Source for file sl_iolib.php

Documentation is available at sl_iolib.php

  1. <?php
  2.     // This file is part of the Sloodle project (www.sloodle.org) and is released under the GNU GPL v3.
  3.     
  4.     /**
  5.     * Sloodle input/output library.
  6.     *
  7.     * Provides general request and response functionality for interacting with in-world LSL scripts.
  8.     *
  9.     * @package sloodle
  10.     * @copyright Copyright (c) 2007-8 Sloodle (various contributors)
  11.     * @license http://www.gnu.org/licenses/gpl-3.0.html GNU GPL v3
  12.     * @since Sloodle 0.2
  13.     *
  14.     * @contributor Peter R. Bloomfield
  15.     *
  16.     */
  17.             
  18.  
  19.     // NOTE: this file requires that the Sloodle "config.php" file already be included
  20.     
  21.     /** Include our general library. */
  22.     require_once(SLOODLE_DIRROOT '/lib/sl_generallib.php');
  23.     
  24.     /** Defines what character(s) will be used to separate lines in the Sloodle communications specification. */
  25.     define("SLOODLE_LINE_SEPARATOR""\n");
  26.     /** Defines what character(s) will be used to separate individual fields in the Sloodle communications specification. */
  27.     define("SLOODLE_FIELD_SEPARATOR""|");
  28.     
  29.     /** Used to indicate that authentication has been successful. */
  30.     define("SLOODLE_AUTH_OK"1);
  31.     /** Used to indicate that authentication has not yet been attempted. */
  32.     define("SLOODLE_AUTH_UNKNOWN"0);
  33.     /** Used to indicate that authentication has failed. */
  34.     define("SLOODLE_AUTH_FAILED"-1);
  35.  
  36.     
  37.     /**
  38.     * A helper class to validate and structure data for output according to the {@link http://slisweb.sjsu.edu/sl/index.php/Sloodle_communications_specification Sloodle communications specification}.
  39.     * @package sloodle
  40.     */
  41.     class SloodleLSLResponse
  42.     {
  43.       ///// DATA /////
  44.       
  45.         /**
  46.         * Integer status code of the response.
  47.         * Refer to the {@link http://slisweb.sjsu.edu/sl/index.php/Sloodle_status_codes status codes} page on the Sloodle wiki for a reference.
  48.         * <b>Required.</b>
  49.         * @var int 
  50.         * @access private
  51.         */
  52.         var $status_code = NULL;
  53.         
  54.         /**
  55.         * Status descriptor string.
  56.         * Should contain a generalised description/category of the status code.
  57.         * <b>Optional but recommended. Ignored if NULL.</b>
  58.         * @var string 
  59.         * @access private
  60.         */
  61.         var $status_descriptor = NULL;
  62.         
  63.         /**
  64.         * Integer side effect(s) codes.
  65.         * Status code(s) of side effect(s) incurred during the operation.
  66.         * Can be a single integer, or an array of integers.
  67.         * <b>Optional. Ignored if NULL.</b>
  68.         * @var mixed 
  69.         * @access private
  70.         */
  71.         var $side_effects = NULL;
  72.         
  73.         /**
  74.         * Request descriptor.
  75.         * A brief string passed into the request by an LSL script (via HTTP parameter 'sloodlerequestdesc'),
  76.         * which is returned so that it can correctly distinguish one request from anotehr.
  77.         * <b>Optional. Ignored if NULL.</b>
  78.         * @var string 
  79.         * @access private
  80.         */
  81.         var $request_descriptor = NULL;
  82.         
  83.         /**
  84.         * Timestamp when the request was originally made by the LSL script.
  85.         * This is <i>not</i> filled-in automatically. You must do it manually if you need it.
  86.         * <b>Optional. Ignored if NULL.</b>
  87.         * @var integer 
  88.         * @access private
  89.         */
  90.         var $request_timestamp = NULL;
  91.         
  92.         /**
  93.         * Timestamp when the response was generated on the Moodle site.
  94.         * This is <i>not</i> filled-in automatically. You must do it manually if you need it.
  95.         * <b>Optional. Ignored if NULL.</b>
  96.         * @var integer 
  97.         * @access private
  98.         */
  99.         var $response_timestamp = NULL;
  100.         
  101.         // User key
  102.         // Should be a string specifying the UUID key of the avatar/agent in-world being handled
  103.         // Optional
  104.         /**
  105.         * SL agent key.
  106.         * Should be a string specifying the UUID key of the agent in-world being handled. (Typically of the user who initiated the request).
  107.         * <b>Optional. Ignored if NULL.</b>
  108.         * @var string 
  109.         * @access private
  110.         */
  111.         var $user_key = NULL;
  112.         
  113.         /**
  114.         * Tracking code of the request.
  115.         * Use of this value is undefined. Please do not use it.
  116.         * <b>Optional. Ignored if NULL.</b>
  117.         * @var mixed 
  118.         * @access private
  119.         */
  120.         var $tracking_code = NULL;
  121.         
  122.         /**
  123.         * Total number of pages.
  124.         * If a response requires multiple pages, this value indicates how many pages there are.
  125.         * <b>Optional, unless $page_number is specified. Ignored if NULL.</b> <i>Not yet supported.</i>
  126.         * @var integer 
  127.         * @access private
  128.         */
  129.         var $page_total = NULL;
  130.         
  131.         /**
  132.         * Current page number.
  133.         * If a response requires multiple pages, this value indicates which page is being returned in this response.
  134.         * <b>Optional, unless $page_total is specified. Ignored if NULL.</b> <i>Not yet supported.</i>
  135.         * @var integer 
  136.         * @access private
  137.         */
  138.         var $page_number = NULL;
  139.         
  140.         /**
  141.         * Data to render following the status line in the response.
  142.         * This value can either be a scalar (single value, e.g. int, string, float), or an array.
  143.         * If it is a single scalar, it is rendered as a single line.
  144.         * If it is an array, then each element becomes one line.
  145.         * If an element is a scalar, then it is directly output onto the line.
  146.         * If an element is an array, then each child element is output as a separate field on the same line.
  147.         * <b>Optional. Ignored if NULL.</b>
  148.         * @see SLOODLE_LINE_SEPARATOR
  149.         * @see SLOODLE_FIELD_SEPARATOR
  150.         * @see SloodleLSLResponse::set_data()
  151.         * @see SloodleLSLResponse::add_data_line()
  152.         * @see SloodleLSLResponse::clear_data()
  153.         * @var mixed 
  154.         * @access private
  155.         */
  156.         var $data = NULL;
  157.         
  158.     
  159.       ///// ACCESSORS /////
  160.     
  161.         // If invalid data is submitted to the functions, then the script is terminated with an LSL-friendly error message
  162.     
  163.         /**
  164.         * Accessor function to set member value {@link $status_code}
  165.         * @param integer $par A non-zero status code
  166.         * @return void 
  167.         */
  168.         function set_status_code($par)
  169.         {
  170.             // Validate
  171.             if (is_int($par== FALSE || $par == 0{
  172.                 $this->_internal_validation_error("Sloodle - LSL response: invalid status code specified; should be non-zero integer"0);
  173.             }
  174.             // Store
  175.             $this->status_code = $par;
  176.         }
  177.     
  178.         /**
  179.         * Accessor function to set member value {@link $status_descriptor}
  180.         * @param mixed $par A status descriptor string, or NULL to clear it
  181.         * @return void 
  182.         */
  183.         function set_status_descriptor($par)
  184.         {
  185.             // Validate
  186.             if (is_string($par== FALSE && is_null($par== FALSE{
  187.                 $this->_internal_validation_error("Sloodle - LSL response: invalid status descriptor specified; should be a string or null"0);
  188.             else {
  189.                 $this->status_descriptor = $par;
  190.             }
  191.         }
  192.     
  193.         /**
  194.         * Accessor function to set member value {@link $side_effects}. <b>Note:</b> it is recommended that you use {@link add_side_effect()} or {@link add_side_effects()} instead.
  195.         * @param mixed $par An integer side effect code, an array of integer side effect codes, or null to clear it
  196.         * @return void 
  197.         */
  198.         function set_side_effects($par)
  199.         {
  200.             // We'll use a variable to store the validity
  201.             $valid TRUE;
  202.             if (is_array($par)) {
  203.                 // Array types are acceptable
  204.                 // Make sure each array element is valid
  205.                 foreach ($par as $elem{
  206.                     if (!is_int($elem)) $valid FALSE;
  207.                 }
  208.                 // Were all elements valid?
  209.                 if ($valid == FALSE{
  210.                     $this->_internal_validation_error("Sloodle - LSL response: invalid element in array of side effect codes; all elements should be integers"0);
  211.                 }
  212.             else if (is_int($par== FALSE && is_null($par== FALSE{
  213.                 // It's not an array, an integer or null
  214.                 $valid FALSE;
  215.                 $this->_internal_validation_error("Sloodle - LSL response: invalid side effect type; should be an integer, an array of integers, or null"0);
  216.             }
  217.             // Was it valid?
  218.             if ($valid{
  219.                 $this->side_effects = $par;
  220.             }
  221.         }
  222.  
  223.         /**
  224.         * Adds one or more integer side effect codes to member {@link $status_code}.
  225.         * @param mixed $par An integer side effect code, or an array of them.
  226.         * @return void 
  227.         */
  228.         function add_side_effects($par)
  229.         {
  230.             // We'll use a variable to store the validity
  231.             $valid TRUE;
  232.             if (is_array($par)) {
  233.                 // Array types are acceptable
  234.                 // Make sure each array element is valid
  235.                 foreach ($par as $elem{
  236.                     if (!is_int($elem)) $valid FALSE;
  237.                 }
  238.                 // Were all elements valid?
  239.                 if ($valid == FALSE{
  240.                     $this->_internal_validation_error("Sloodle - LSL response: cannot add side effects. Invalid element in array of side effect codes. All elements should be integers"0);
  241.                 }
  242.             else if (is_int($par== FALSE{
  243.                 // It's not an array or an integer
  244.                 $valid FALSE;
  245.                 $this->_internal_validation_error("Sloodle - LSL response: cannot add side effect. Invalid side effect type. should be an integer or an array of integers"0);
  246.             }
  247.             // Was it valid?
  248.             if ($valid{
  249.                 // If we were passed just a single side effect, then convert it to an array
  250.                 if (is_int($par)) {
  251.                     $par array($par);
  252.                 }
  253.                 // Make sure our existing side effect member is an array
  254.                 if (is_null($this->side_effects)) $this->side_effects = array();
  255.                 else if (is_int($this->side_effects)) $this->side_effects = array($this->side_effects);
  256.                         
  257.                 // Append our new side effect(s)               
  258.                 foreach ($par as $cur{
  259.                     $this->side_effects[$cur;
  260.                 }
  261.             }
  262.         }
  263.         
  264.         /**
  265.         * Adds a single side effect code to member {@link $status_code}
  266.         * @param integer $par An integer side-effect code.
  267.         * @return void 
  268.         */
  269.         function add_side_effect($par)
  270.         {
  271.             // Make sure the parameter is valid
  272.             if (!is_int($par))
  273.                 $this->_internal_validation_error("Sloodle - LSL response: cannot add side effect. Invalid side effect type. Should be an integer."0);
  274.             $this->add_side_effects($par);
  275.         }
  276.         
  277.         /**
  278.         * Accessor function to set member value {@link $request_descriptor}
  279.         * @param mixed $par A string request descriptor, or NULL to clear it
  280.         * @return void 
  281.         */
  282.         function set_request_descriptor($par)
  283.         {
  284.             // Validate
  285.             if (is_string($par== FALSE && is_null($par== FALSE{
  286.                 $this->_internal_validation_error("Sloodle - LSL response: invalid request descriptor specified; should be a string or null"0);
  287.             else {
  288.                 $this->request_descriptor = $par;
  289.             }
  290.         }
  291.         
  292.         /**
  293.         * Accessor function to set member value {@link $request_timestamp}
  294.         * @param mixed $par An integer timestamp, or NULL to clear it
  295.         * @return void 
  296.         */
  297.         function set_request_timestamp($par)
  298.         {
  299.             // Validate
  300.             if (is_int($par== FALSE && is_null($par== FALSE{
  301.                 $this->_internal_validation_error("Sloodle - LSL response: invalid request timestamp; should be an integer, or null"0);
  302.             else {
  303.                 $this->request_timestamp = $par;
  304.             }
  305.         }
  306.         
  307.         /**
  308.         * Accessor function to set member value {@link $response_timestamp}
  309.         * @param mixed $par An integer timestamp, or NULL to clear it
  310.         * @return void 
  311.         */
  312.         function set_response_timestamp($par)
  313.         {
  314.             // Validate
  315.             if (is_int($par== FALSE && is_null($par== FALSE{
  316.                 $this->_internal_validation_error("Sloodle - LSL response: invalid response timestamp; should be an integer, or null"0);
  317.             else {
  318.                 $this->response_timestamp = $par;
  319.             }
  320.         }
  321.         
  322.         /**
  323.         * Accessor function to set member value {@link $user_key}
  324.         * @param mixed $par A string containing a UUID, or NULL to clear it
  325.         * @return void 
  326.         */
  327.         function set_user_key($par)
  328.         {
  329.             // Validate
  330.             if (is_string($par== FALSE && is_null($par== FALSE{
  331.                 $this->_internal_validation_error("Sloodle - LSL response: invalid user key specified; should be a string or null"0);
  332.             else {
  333.                 $this->user_key = $par;
  334.             }
  335.         }
  336.         
  337.         /**
  338.         * Accessor function to set member value {@link $tracking_code}
  339.         * @param mixed $par Any scalar value
  340.         * @return void 
  341.         */
  342.         function set_tracking_code($par)
  343.         {
  344.             $this->tracking_code = $par;
  345.         }
  346.         
  347.         /**
  348.         * Accessor function to set member value {@link $page_total}
  349.         * @param mixed $par A positive page total count, or NULL to clear it
  350.         * @return void 
  351.         */
  352.         function set_page_total($par)
  353.         {
  354.             // Validate
  355.             if ((is_int($par== FALSE || $par 0&& is_null($par== FALSE{
  356.                 $this->_internal_validation_error("Sloodle - LSL response: invalid page total; should be a positive integer, or null"0);
  357.             else {
  358.                 $this->page_total = $par;
  359.             }
  360.         }
  361.         
  362.         /**
  363.         * Accessor function to set member value {@link $page_number}
  364.         * @param mixed $par A positive page number, or NULL to clear it
  365.         * @return void 
  366.         */
  367.         function set_page_number($par)
  368.         {
  369.             // Validate
  370.             if ((is_int($par== FALSE || $par 0&& is_null($par== FALSE{
  371.                 $this->_internal_validation_error("Sloodle - LSL response: invalid page number; should be a positive integer, or null"0);
  372.             else {
  373.                 $this->page_number = $par;
  374.             }
  375.         }
  376.         
  377.         /**
  378.         * Accessor function to set member value {@link $data}. <b>Note: it is recommended that you use the {@link add_data_line()} and {@link clear_data()} functions instead of this.</b>
  379.         * @param mixed $par Any scalar value, or a mixed array of scalars or scalar arrays, or NULL to clear it
  380.         * @return void 
  381.         */
  382.         function set_data($par)
  383.         {
  384.             // We'll use a variable to store validity
  385.             $valid TRUE;
  386.             if (is_array($par)) {
  387.                 // Check each element
  388.                 foreach ($par as $elem{
  389.                     // Is this element another array? Or is it a scalar/null value?
  390.                     if (is_array($elem)) {
  391.                         // Check each inner element for validity
  392.                         foreach ($elem as $innerelem{
  393.                             // Is this element scalar or null? If not, it is invalid
  394.                             if (is_scalar($innerelem== FALSE && is_null($innerelem== FALSE{
  395.                                 $valid FALSE;
  396.                             }
  397.                         }
  398.                     else if (is_scalar($elem== FALSE && is_null($elem== FALSE{
  399.                         // Not an array, nor a scalar/null value - it is invalid
  400.                         $valid FALSE;
  401.                     }
  402.                 }
  403.                 if ($valid == FALSE{
  404.                     $this->_internal_validation_error("Sloodle - LSL response: non-scalar element in array of items for a data line");
  405.                 }
  406.             else if (is_scalar($par== FALSE && is_null($par== FALSE{
  407.                 $valid FALSE;
  408.                 $this->_internal_validation_error("Sloodle - LSL response: each line of data must be a scalar type, or an array of scalars");
  409.             }
  410.             // Store it if it is valid
  411.             if ($valid{
  412.                 $this->data = $par;
  413.             }
  414.         }
  415.     
  416.         /**
  417.         * Adds one line of data to the {@link $data} member
  418.         * @param mixed $par A scalar, or an array of scalars
  419.         * @return void 
  420.         */
  421.         function add_data_line($par)
  422.         {
  423.             // We'll use a variable to store validity
  424.             $valid TRUE;
  425.             if (is_array($par)) {
  426.                 // Check each element
  427.                 foreach ($par as $elem{
  428.                     if (is_scalar($elem== FALSE && is_null($elem== FALSE$valid FALSE;
  429.                 }
  430.                 if ($valid == FALSE{
  431.                     $this->_internal_validation_error("Sloodle - LSL response: non-scalar element in array of items for a data line");
  432.                 }
  433.             else if (is_scalar($par== FALSE && is_null($par== FALSE{
  434.                 $valid FALSE;
  435.                 $this->_internal_validation_error("Sloodle - LSL response: each line of data must be a scalar type, or an array of scalars");
  436.             }
  437.             // Store it if it is valid
  438.             if ($valid{
  439.                 $this->data[$par;
  440.             }
  441.         }
  442.         
  443.         /**
  444.         * Clears all data from member {@link $data}
  445.         * @return void 
  446.         */
  447.         function clear_data()
  448.         {
  449.             $this->data = NULL;
  450.         }
  451.         
  452.         
  453.       ///// OTHER FUNCTIONS /////
  454.       
  455.         /**
  456.         * <i>Constructor</i> - can intialise some variables
  457.         * @param int $status_code The initial status code for the response (optional - ignore if NULL)
  458.         * @param string $status_descriptor The initial status descriptor for the response (optional - ignore if NULL)
  459.         * @param mixed $data The initial data for the response, which can be a scalar, or a mixed array of scalars/scalar-arrays (see {@link SloodleLSLResponse::$data}) (optional - ignore if NULL)
  460.         * @return void 
  461.         * @access public
  462.         */
  463.         function SloodleLSLResponse($status_code NULL$status_descriptor NULL$data NULL)
  464.         {
  465.             // Store the data
  466.             if (!is_null($status_code)) $this->status_code = (int)$status_code;
  467.             if (!is_null($status_descriptor)) $this->status_descriptor = (string)$status_descriptor;
  468.             if (!is_null($data)) $this->data = $data;
  469.         }
  470.       
  471.         /**
  472.         * Renders the response to a string.
  473.         * Prior to rendering, this function will perform final validation on all the data.
  474.         * If anything fails, then the script will terminate with an LSL-friendly error message.
  475.         *
  476.         * @param string &$str Reference to a string object which the response should be rendered to.
  477.         * @return void 
  478.         * @access public
  479.         */
  480.         function render_to_string(&$str)
  481.         {
  482.             // Clear the string
  483.             $str "";
  484.             
  485.             // We can omit any unnecessary items of data, but the number of field-separators must be correct
  486.             // E.g. if item 4 is specified, but items 2 and 3 are not, then empty field-separators must be output as if items 2 and 3 were present, e.g.:
  487.             // 1|||AVATAR_LIST
  488.             // (where the pipe-character | is the field separator)
  489.             
  490.             // We will step backwards through out list of fields, and as soon as one item is specified, all of them should be
  491.             $showall FALSE;
  492.             // Make sure that if the page number is specified, that the total is as well
  493.             if (is_null($this->page_numberxor is_null($this->page_total)) {
  494.                 $this->_internal_validation_error("Sloodle - LSL response: script must specify both \"page_total\" *and* \"page_number\", or specify neither");
  495.             else if ($showall || is_null($this->page_number== FALSE{
  496.                 $showall TRUE;
  497.                 $str SLOODLE_FIELD_SEPARATOR . (string)$this->page_total . SLOODLE_FIELD_SEPARATOR . (string)$this->page_number . $str;
  498.             }
  499.             
  500.             // Do we have a tracking code?
  501.             if ($showall || is_null($this->tracking_code== FALSE{
  502.                 $showall TRUE;
  503.                 $str SLOODLE_FIELD_SEPARATOR . (string)$this->tracking_code . $str;
  504.             }
  505.             
  506.             // User key?
  507.             if ($showall || is_null($this->user_key== FALSE{
  508.                 $showall TRUE;
  509.                 $str SLOODLE_FIELD_SEPARATOR $this->user_key . $str;
  510.             }
  511.             
  512.             // Response timestamp?
  513.             if ($showall || is_null($this->response_timestamp== FALSE{
  514.                 $showall TRUE;
  515.                 $str SLOODLE_FIELD_SEPARATOR . (string)$this->response_timestamp . $str;
  516.             }
  517.             
  518.             // Request timestamp?
  519.             if ($showall || is_null($this->request_timestamp== FALSE{
  520.                 $showall TRUE;
  521.                 $str SLOODLE_FIELD_SEPARATOR . (string)$this->request_timestamp . $str;
  522.             }
  523.             
  524.             // Request descriptor?
  525.             if ($showall || is_null($this->request_descriptor== FALSE{
  526.                 $showall TRUE;
  527.                 $str SLOODLE_FIELD_SEPARATOR $this->request_descriptor . $str;
  528.             }
  529.             
  530.             // Side-effects?
  531.             if ($showall || is_null($this->side_effects== FALSE{
  532.                 $showall TRUE;
  533.                 // Is this an array?
  534.                 if (is_array($this->side_effects)) {
  535.                     // Yes - output each side effect code in a comma-separated list
  536.                     $selist "";
  537.                     $isfirst TRUE;
  538.                     foreach ($this->side_effects as $cur_side_effect{
  539.                         if (!$isfirst)  $selist .= ",";
  540.                         else $isfirst FALSE;
  541.                         $selist .= (string)$cur_side_effect;
  542.                     }
  543.                     // Add that list to the output
  544.                     $str SLOODLE_FIELD_SEPARATOR $selist $str;
  545.                     
  546.                 else {
  547.                     // Not at an array - output the single item
  548.                     $str SLOODLE_FIELD_SEPARATOR . (string)$this->side_effects . $str;
  549.                 }
  550.             }
  551.             
  552.             // Status descriptor?
  553.             if ($showall || is_null($this->status_descriptor== FALSE{
  554.                 $showall TRUE;
  555.                 $str SLOODLE_FIELD_SEPARATOR $this->status_descriptor . $str;
  556.             }
  557.             
  558.             // Ensure that a status code has been specified
  559.             if (is_null($this->status_code)) {
  560.                 // Not specified - report an error
  561.                 $this->_internal_validation_error("Sloodle - LSL response: no status code specified");
  562.             else {
  563.                 // Output the status code
  564.                 $str = (string)$this->status_code . $str;
  565.             }
  566.             
  567.             
  568.             // Has any data been specified?
  569.             if (is_null($this->data== FALSE{
  570.                 
  571.                 // Do we have an outer array?
  572.                 if (is_array($this->data)) {
  573.                 
  574.                     // Go through each element in the outer array
  575.                     foreach ($this->data as $outer_elem{
  576.                         
  577.                         // Do we have an inner array on this element?
  578.                         if (is_array($outer_elem)) {
  579.                         
  580.                             // Construct the line, piece-at-a-time
  581.                             $line "";
  582.                             $isfirst TRUE;
  583.                             foreach ($outer_elem as $inner_elem{
  584.                                 // Use the standard field separator
  585.                                 if (!$isfirst$line .= SLOODLE_FIELD_SEPARATOR;
  586.                                 else $isfirst FALSE;
  587.                                 $line .= (string)$inner_elem;
  588.                             }
  589.                             // Append the new line of data
  590.                             $str .= SLOODLE_LINE_SEPARATOR . (string)$line;
  591.                         
  592.                         else {
  593.                             // Output the single item
  594.                             $str .= SLOODLE_LINE_SEPARATOR . (string)$outer_elem;
  595.                         }
  596.                     }
  597.                 
  598.                 else {
  599.                     // Output the single item
  600.                     $str .= SLOODLE_LINE_SEPARATOR . (string)$this->data;
  601.                 }
  602.             }
  603.         }
  604.         
  605.         /**
  606.         * Outputs the response directly to the HTTP response.
  607.         *
  608.         * @access public
  609.         * @return void 
  610.         * @uses SloodleLSLResponse::render_to_string() Outputs the result from this function directly to the HTTP response stream.
  611.         */
  612.         function render_to_output()
  613.         {
  614.             // Attempt to render the output to a string, and then copy that string to the HTTP response
  615.             $str "";
  616.             $this->render_to_string($str);
  617.             echo $str;
  618.         }
  619.         
  620.         
  621.         // Quick-output
  622.         // Can be called statically to allow simple output of basic data
  623.         // The status code is required, but the other parameters are optional
  624.         // If an error occurs, the LSL-friendly error message is output to the HTTP response, and the script terminated
  625.         // If $static is TRUE (default) then this will be treated as a static call, and a new response object will be used
  626.         // If $static is FALSE then this is treated as adding data to an existing response object
  627.         /**
  628.         * Quick output of data to avoid several accessor calls if the response is very basic.
  629.         * Can be called statically to allow simple output of basic data.
  630.         * The status code is required, but the other parameters are optional
  631.         * If an error occurs, the LSL-friendly error message is output to the HTTP response, and the script terminated
  632.         *
  633.         * @param int $status_code The status code for the response (required)
  634.         * @param string $status_descriptor The status descriptor for the response (optional - ignored if NULL)
  635.         * @param mixed $data The data for the response, which can be a scalar, or a mixed array of scalars/scalar-arrays (see {@link SloodleLSLResponse::$data}) (optional - ignored if NULL)
  636.         * @param bool $static If TRUE (default), then this function will assume it is being call statically, and construct its own response object. Otherwise, it will all the existing member data to render the output.
  637.         * @return void 
  638.         * @access public
  639.         */
  640.         function quick_output($status_code$status_descriptor NULL$data NULL$static TRUE)
  641.         {
  642.             // Is this s static call?
  643.             if ($static{
  644.                 // Construct and render the output of a response object
  645.                 $response new SloodleLSLResponse($status_code$status_descriptor$data);
  646.                 $response->render_to_output();
  647.             else {
  648.                 // Set all our data
  649.                 $this->status_code = $status_code;
  650.                 if ($status_descriptor != NULL$this->status_descriptor = $status_descriptor;
  651.                 if ($data != NULL$this->add_data_line($data);
  652.                 // Output it
  653.                 $this->render_to_output();
  654.             }
  655.         }
  656.     
  657.         
  658.         /**
  659.         * Internal function to report a data validation error.
  660.         * Outputs an LSL-friendly error message, and terminates the script
  661.         *
  662.         * @param string $msg The error message to output.
  663.         * @return void 
  664.         * @access private
  665.         */
  666.         function _internal_validation_error($msg)
  667.         {
  668.             exit("-104".SLOODLE_FIELD_SEPARATOR."SYSTEM".SLOODLE_LINE_SEPARATOR.$msg);
  669.         }
  670.     }
  671.     
  672.     
  673.     /**
  674.     * Obtains a named HTTP request parameter, and terminates script with an error message if it was not provided.
  675.     * This is a 'Sloodle-friendly' version of the Moodle "required_param" function.
  676.     * Instead of terminate the script with an HTML-formatted error message, it will terminate with a message
  677.     *  which conforms for the {@link http://slisweb.sjsu.edu/sl/index.php/Sloodle_communications_specification Sloodle communications specification},
  678.     *  making it suitable for use in {@link http://slisweb.sjsu.edu/sl/index.php/Linker_Script linker scripts}.
  679.     *
  680.     * @param string $parname Name of the HTTP request parameter to fetch.
  681.     * @param int $type Type of parameter expected, such as "PARAM_RAW". See Moodle documentation for a complete list.
  682.     * @return mixed The appropriately parsed and/or cleaned parameter value, if it was found.
  683.     */
  684.     function sloodle_required_param($parname$type)
  685.     {
  686.         // Attempt to get the parameter
  687.         $par optional_param($parnameNULL$type);
  688.         // Was it provided?
  689.         if (is_null($par)) {
  690.             // No - report the error
  691.             SloodleLSLResponse::quick_output(-811"SYSTEM""Expected request parameter '$parname'.");
  692.             exit();
  693.         }
  694.         
  695.         return $par;
  696.     }
  697.     
  698.     
  699.     // This class handles a request from an LSL script
  700.     /**
  701.     * Handles incoming HTTP requests, typically from LSL scripts.
  702.     * This class will perform much of the complex and repetitive processing required for handling HTTP requests.
  703.     *
  704.     * @uses SloodleLSLResponse Outputs error messages in appropriate format if an error occurs.
  705.     * @uses SloodleUser Stores and processes user data incoming from an HTTP request
  706.     * @package sloodle
  707.     */
  708.     class SloodleLSLRequest
  709.     {
  710.       ///// DATA /////
  711.       // WARNING: all data should be treated as PRIVATE (even though PHP4 does not recognise this concept)
  712.       
  713.         /**
  714.         * Indicates whether or not the request data has been processed by the {@link process_request_data()} function.
  715.         * @var bool 
  716.         * @see SloodleLSLRequest::process_request_data()
  717.         * @access private
  718.         */
  719.         var $request_data_processed = FALSE;
  720.         
  721.         /**
  722.         * Contains the password specified in HTTP request parameters (or NULL if not specified).
  723.         * @see SloodleLSLRequest::authenticate_request()
  724.         * @access private
  725.         */
  726.         var $password = NULL;
  727.         
  728.         /**
  729.         * Indicates the status of request authentication.
  730.         * @see SloodleLSLRequest::authenticate_request()
  731.         * @see SLOODLE_AUTH_OK
  732.         * @see SLOODLE_AUTH_UNKNOWN
  733.         * @see SLOODLE_AUTH_FAILED
  734.         * @var int 
  735.         * @access private
  736.         */
  737.         var $auth_status = SLOODLE_AUTH_UNKNOWN;
  738.         
  739.         /**
  740.         * A 3-element array containing the LoginZone position vector specified in HTTP request parameters (or NULL if not specified).
  741.         * @access private
  742.         */
  743.         var $login_zone_pos = NULL;
  744.         
  745.         /**
  746.         * Integer ID of the course specified in the request (or NULL if not specified).
  747.         * @access private
  748.         */
  749.         var $course_id = NULL;
  750.         
  751.         /**
  752.         * Integer ID of the course module instance specified in the request (or NULL if not specified).
  753.         * @access private
  754.         */
  755.         var $module_id = NULL;
  756.  
  757.         /**
  758.         * String UUID of the SL user agent specified in the request (or NULL if not specified).
  759.         * @access private
  760.         */
  761.         var $avatar_uuid = NULL;
  762.         
  763.         /**
  764.         * String name of the SL agent specified in the request (or NULL if not specified).
  765.         * @access private
  766.         */
  767.         var $avatar_name = NULL;
  768.         
  769.         /**
  770.         * String containing the login security token specified in the request (or NULL if not specified).
  771.         * @access private
  772.         */
  773.         var $login_security_token = NULL;
  774.         
  775.         
  776.     /// References to potentially external objects ///
  777.         
  778.         /**
  779.         * The object used to output response data.
  780.         * The object reference may be provided externally in the parameters of the constructor ({@link SloodleLSLRequest()}) or via the ({@link set_response()}) accessor.
  781.         * Otherwise, it will have been instantiated by this object itself.
  782.         * @var SloodleLSLResponse 
  783.         * @see SloodleLSLRequest::set_response()
  784.         * @see SloodleLSLRequest::get_response()
  785.         * @access private
  786.         */
  787.         var $response = NULL;
  788.  
  789.         /**
  790.         * The object used to store and process incoming user data.
  791.         * The object reference may be provided externally in the parameters of the constructor ({@link SloodleLSLRequest()}) or via the ({@link set_user()}) accessor.
  792.         * Otherwise, it will have been instantiated by this object itself.
  793.         * @var SloodleUser 
  794.         * @see SloodleLSLRequest::set_user()
  795.         * @see SloodleLSLRequest::get_user()
  796.         * @access private
  797.         */
  798.         var $user = NULL;
  799.                 
  800.         
  801.       ///// ACCESSORS /////
  802.     
  803.         /**
  804.         * Returns member variable {@link $request_data_processed}.
  805.         * @return bool TRUE if the request data has been processed, or FALSE if not
  806.         * @see SloodleLSLRequest::process_request_data()
  807.         */
  808.         function is_request_data_processed()
  809.         {
  810.             return $this->request_data_processed;
  811.         }
  812.         
  813.         /**
  814.         * Returns member variable {@link $auth_status}.
  815.         * @return int One of: {@link SLOODLE_AUTH_OK}{@link SLOODLE_AUTH_UNKNOWN}, or {@link SLOODLE_AUTH_FAILED}.
  816.         * @see SloodleLSLRequest::authenticate_request()
  817.         */
  818.         function get_auth_status()
  819.         {
  820.             return $this->auth_status;
  821.         }
  822.  
  823.         /**
  824.         * Indicates whether or not request authentication has succeeded.
  825.         * @return bool TRUE if the request data has been authenticated, or FALSE if it failed or has not been attempted yet
  826.         * @see SloodleLSLRequest::authenticate_request()
  827.         * @see SloodleLSLRequest::$auth_status
  828.         */
  829.         function is_authenticated()
  830.         {
  831.             return ($this->auth_status == SLOODLE_AUTH_OK);
  832.         }
  833.         
  834.         /**
  835.         * Indicates whether or not request authentication has failed.
  836.         * @return bool TRUE if the request data has failed authentication, or FALSE if it passed or has not been attempted yet
  837.         * @see SloodleLSLRequest::authenticate_request()
  838.         * @see SloodleLSLRequest::$auth_status
  839.         */
  840.         function is_auth_failed()
  841.         {
  842.             return ($this->auth_status == SLOODLE_AUTH_FAILED);
  843.         }
  844.         
  845.         /**
  846.         * Sets the {@link SloodleLSLRequest::$response} member.
  847.         * @param SloodleLSLResponse $response Reference to a {@link SloodleLSLResponse} object
  848.         */
  849.         function set_response(&$response)
  850.         {
  851.             $this->response = &$response;
  852.         }
  853.  
  854.         /**
  855.         * Sets the {@link SloodleLSLRequest::$user} member.
  856.         * @param SloodleUser $user Reference to a {@link SloodleUser} object
  857.         */
  858.         function set_user(&$user)
  859.         {
  860.             $this->user = &$user;
  861.         }
  862.     
  863.         
  864.       // NOTE: These accessors will force the request data to be processed if it hasn't already been processed
  865.  
  866.         /**
  867.         * Returns member value {@link $password}.
  868.         * Note: this function will ensure that {@link process_request_data()} has already been called prior to execution.
  869.         * @return string|nullThe password provided in the request parameters, or NULL if there wasn't one
  870.         */
  871.         function get_password()
  872.         {
  873.             // Ensure the request data has been processed
  874.             $this->process_request_data();
  875.             return $this->password;
  876.         }
  877.         
  878.         /**
  879.         * Returns member value {@link $course_id}.
  880.         * Note: this function will ensure that {@link process_request_data()} has already been called prior to execution.
  881.         * @return integer|nullThe course ID provided in the request parameters, or NULL if there wasn't one
  882.         */
  883.         function get_course_id()
  884.         {
  885.             // Ensure the request data has been processed
  886.             $this->process_request_data();
  887.             return $this->course_id;
  888.         }
  889.         
  890.         /**
  891.         * Returns member value {@link $module_id}.
  892.         * Note: this function will ensure that {@link process_request_data()} has already been called prior to execution.
  893.         * @return integer|nullThe course module instance ID provided in the request parameters, or NULL if there wasn't one
  894.         */
  895.         function get_module_id()
  896.         {
  897.             // Ensure the request data has been processed
  898.             $this->process_request_data();
  899.             return $this->module_id;
  900.         }
  901.         
  902.         /**
  903.         * Returns member value {@link $avatar_uuid}.
  904.         * Note: this function will ensure that {@link process_request_data()} has already been called prior to execution.
  905.         * @return string|nullThe avatar UUID provided in the request parameters, or NULL if there wasn't one
  906.         */
  907.         function get_avatar_uuid()
  908.         {
  909.             // Ensure the request data has been processed
  910.             $this->process_request_data();
  911.             return $this->avatar_uuid;
  912.         }
  913.         
  914.         /**
  915.         * Returns member value {@link $avatar_name}.
  916.         * Note: this function will ensure that {@link process_request_data()} has already been called prior to execution.
  917.         * @return string|nullThe avatar name provided in the request parameters, or NULL if there wasn't one
  918.         */
  919.         function get_avatar_name()
  920.         {
  921.             // Ensure the request data has been processed
  922.             $this->process_request_data();
  923.             return $this->avatar_name;
  924.         }
  925.         
  926.         /**
  927.         * Returns member value {@link $login_security_token}.
  928.         * Note: this function will ensure that {@link process_request_data()} has already been called prior to execution.
  929.         * @return string|nullThe login security token provided in the request parameters, or NULL if there wasn't one
  930.         */
  931.         function get_login_security_token()
  932.         {
  933.             // Ensure the request data has been processed
  934.             $this->process_request_data();
  935.             return $this->login_security_token;
  936.         }
  937.         
  938.         /**
  939.         * Returns member value {@link $response}.
  940.         * Note: this function will ensure that {@link process_request_data()} has already been called prior to execution.
  941.         * @return &SloodleLSLResponse A reference to the response object used by this object
  942.         */
  943.         function get_response()
  944.         {
  945.             // Ensure the request data has been processed
  946.             $this->process_request_data();
  947.             return $this->response;
  948.         }
  949.         
  950.         /**
  951.         * Returns member value {@link $user}.
  952.         * Note: this function will ensure that {@link process_request_data()} has already been called prior to execution.
  953.         * @return &SloodleUser A reference to the user object used by this object
  954.         */
  955.         function get_user()
  956.         {
  957.             // Ensure the request data has been processed
  958.             $this->process_request_data();
  959.             return $this->user;
  960.         }
  961.         
  962.         
  963.       ///// FUNCTIONS /////
  964.       
  965.         /**
  966.         * <i>Constructor</i> - initialises the user and response objects.
  967.         * If the parameters provide references to appropriate objects, then the constructor will store them.
  968.         * However, if the parameters are NULL, then the constructor will create its own instances.
  969.         *
  970.         * @param SloodleLSLResponse $response Reference to the response object which this object should use, or NULL
  971.         * @param SloodleUser $user Refernce to the user object which this object should use, or NULL
  972.         */
  973.         function SloodleLSLRequest(&$response&$user)
  974.         {
  975.             // Store or instantiate our response object
  976.             if (is_object($response)) $this->response = &$response;
  977.             else $this->response = new SloodleLSLResponse();
  978.             
  979.             // Store or instantiate our user object
  980.             if (is_object($user)) $this->user = &$user;
  981.             else $this->user = new SloodleUser();
  982.         }
  983.         
  984.         // Process all of the data provided by the request
  985.         // This function will usually be called automatically when needed
  986.         // Normally, it will not process the request data if it already has done
  987.         // However, if parameter $force is TRUE then it will force re-processing
  988.         // Note that, if avatar_uuid and/or avatar_name are specified in the request,
  989.         //  then this function will attempt to retreive data for them.
  990.         //  However, it will *not* login the user or auto-register them - that should be done manually on the $user object.
  991.         // This will also attempt to fetch a course record if a course ID is requested
  992.         // No return value
  993.         /**
  994.         * Process all of the standard data provided by the HTTP request.
  995.         *
  996.         * This function should normally be called very shortly after the start of a script, as it will
  997.         *  check all the expected HTTP request parameters, perform basic processing, and store the data.
  998.         * It will also send data to the appropriate {@link SloodleLSLResposne} and {@link SloodleUser} objects.
  999.         * When called, it will check the {@link $request_data_processed} member to see if it has already been called.
  1000.         * If so, it will not execute again, unless the $force parameter is TRUE.
  1001.         * <b>Note:</b> most functions in this class will automatically call this function if needed to ensure data is available.
  1002.         *
  1003.         * @param bool $force If TRUE, then the function is forced to execute again, even if it has already been executed. (Default: FALSE).
  1004.         */
  1005.         function process_request_data$force FALSE )
  1006.         {
  1007.             // Process the request data if it has not yet been procesed, or if re-processing is being forced
  1008.             if ($this->request_data_processed == FALSE || $force == TRUE{
  1009.                 // Fetch the parameters from the request
  1010.                 $this->password = optional_param('sloodlepwd'NULLPARAM_RAW);
  1011.                 $this->course_id = optional_param('sloodlecourseid'NULLPARAM_INT);
  1012.                 $this->module_id = optional_param('sloodlemoduleid'NULLPARAM_INT);
  1013.                 $this->avatar_uuid = optional_param('sloodleuuid'NULLPARAM_RAW);
  1014.                 $this->avatar_name = optional_param('sloodleavname'NULLPARAM_RAW);
  1015.                 $this->login_security_token = optional_param('sloodlelst'NULLPARAM_RAW);
  1016.                 
  1017.                 $this->response->set_request_descriptor(optional_param('sloodlerequestdesc'NULLPARAM_RAW));
  1018.                 
  1019.                 // Fetch the login zone position string
  1020.                 $temp_pos optional_param('sloodleloginzonepos'NULLPARAM_RAW);
  1021.                 // If it was specified then convert it to an array
  1022.                 if (!is_null($temp_pos&& !empty($temp_pos)) $this->login_zone_pos = vector_to_array($temp_pos);
  1023.                 else $this->login_zone_pos = NULL;
  1024.                 
  1025.                 // Some values ought to be NULL if they are empty
  1026.                 if (empty($this->avatar_uuid)) $this->avatar_uuid = NULL;
  1027.                 if (empty($this->avatar_name)) $this->avatar_name = NULL;
  1028.                 
  1029.                 // Attempt to find a Sloodle user by UUID/name
  1030.                 $found_sloodle_user $this->user->find_sloodle_user($this->avatar_uuid$this->avatar_nameTRUE);
  1031.                 if ($found_sloodle_user === TRUE{
  1032.                     // We found a user
  1033.                     // If the UUID or name had been previously unspecified, then attempt to get them from the database data
  1034.                     if (is_null($this->avatar_uuid)) $this->avatar_uuid = $this->user->sloodle_user_cache->uuid;
  1035.                     if (is_null($this->avatar_name)) $this->avatar_name = $this->user->sloodle_user_cache->avname;
  1036.                     
  1037.                     // Attempt to find an associated Moodle user (from the data cached above), and cache the results
  1038.                     $this->user->find_linked_moodle_user(TRUETRUE);                
  1039.                 }
  1040.                 
  1041.                 // Store the avatar UUID in the response object
  1042.                 $this->response->user_key = $this->avatar_uuid;
  1043.             }
  1044.             
  1045.             $this->request_data_processed = TRUE;
  1046.         }
  1047.       
  1048.         /**
  1049.         * Authenticates the request against the site using the password parameter.
  1050.         * This function can use both site-wide or object-specific prim passwords (the latter of which
  1051.         *  uses the 'sloodle_active_object' table in the database).
  1052.         * It will also set the content of member {$link $auth_status} as appropriate.
  1053.         *
  1054.         * @param bool $require If TRUE, the function will NOT return on authentication failure. Rather, it will terminate the script with an error message.
  1055.         * @return bool TRUE if successful in authenticating the request, or FALSE if not.
  1056.         */
  1057.         function authenticate_request$require TRUE )
  1058.         {
  1059.             // If the request is already authenticated, then there is nothing else to do
  1060.             if ($this->auth_status == SLOODLE_AUTH_OK)
  1061.                 return TRUE;
  1062.         
  1063.             // Make sure the request data is processed
  1064.             $this->process_request_data();
  1065.             // We are not initially authenticated
  1066.             $this->auth_status = SLOODLE_AUTH_UNKNOWN;
  1067.             
  1068.             // Ensure that a password was provided
  1069.             if (is_null($this->password)) {
  1070.                 $this->auth_status = SLOODLE_AUTH_FAILED;
  1071.                 // Should we terminate the script with an error message?
  1072.                 if ($require{
  1073.                     $this->response->set_status_code(-212);
  1074.                     $this->response->set_status_descriptor('OBJECT_AUTH');
  1075.                     $this->response->add_data_line('Prim Password not passed in request');
  1076.                     $this->response->render_to_output();
  1077.                     exit();
  1078.                 else {
  1079.                     return FALSE;
  1080.                 }
  1081.             }
  1082.             
  1083.             // Does the password contain an object UUID?
  1084.             $objpwd NULL;
  1085.             if (preg_match('/^(.*?)\|(\d\d*)$/',$this->password$matches)) {
  1086.                 $objuuid $matches[1]// Object UUID
  1087.                 $objpwd $matches[2]// Object-specific password
  1088.                 // Get an appropriate entry from the table of active objects
  1089.                 $entry get_record('sloodle_active_object','uuid',$objuuid);            
  1090.                 if ($entry !== FALSE && $entry->pwd != NULL && $entry->pwd == $objpwd{
  1091.                     // Authentication was successful
  1092.                     $this->auth_status = SLOODLE_AUTH_OK;
  1093.                     return TRUE;
  1094.                 }
  1095.             }
  1096.            
  1097.             // Check the password value as a whole, and check the object-password (if one was given)
  1098.             $_prim_password sloodle_get_prim_password();
  1099.             if ($this->password !== $_prim_password && $objpwd !== $_prim_password{
  1100.                 $this->auth_status = SLOODLE_AUTH_FAILED;
  1101.                 // Should we terminate the script with an error message?
  1102.                 if ($require{
  1103.                     $this->response->set_status_code(-213);
  1104.                     $this->response->set_status_descriptor('OBJECT_AUTH');
  1105.                     $this->response->add_data_line('Password provided was invalid');
  1106.                     $this->response->render_to_output();
  1107.                     exit();
  1108.                 else {
  1109.                     return FALSE;
  1110.                 }
  1111.             }
  1112.             unset($_prim_password)// For security
  1113.             
  1114.             // Authentication appears to be OK
  1115.             $this->auth_status = SLOODLE_AUTH_OK;
  1116.             return TRUE;
  1117.         }
  1118.         
  1119.         /**
  1120.         * Gets a database record for the course identified in the request.
  1121.         * (Note: this function does not check whether or not the user is enrolled in the course)
  1122.         *
  1123.         * @param bool $require If TRUE, the function will NOT return failure. Rather, it will terminate the script with an error message.
  1124.         * @return object record directly from the database, or NULL if the course is not found.
  1125.         */
  1126.         function get_course_record($require TRUE)
  1127.         {
  1128.             // Make sure the request data is processed
  1129.             $this->process_request_data();
  1130.             // Make sure the course ID was specified
  1131.             if (is_null($this->course_id)) {
  1132.                 if ($require{
  1133.                     $this->response->set_status_code(-501);
  1134.                     $this->response->set_status_descriptor('COURSE');
  1135.                     $this->response->add_data_line('No course specified in request.');
  1136.                     $this->response->render_to_output();
  1137.                     exit();
  1138.                 }
  1139.                 return NULL;
  1140.             }
  1141.             // Attempt to get the course data
  1142.             $course_record get_record('course''id'$this->course_id);
  1143.             if ($course_record === FALSE{
  1144.                 // Course not found
  1145.                 if ($require{
  1146.                     $this->response->set_status_code(-512);
  1147.                     $this->response->set_status_descriptor('COURSE');
  1148.                     $this->response->add_data_line("Course {$this->course_id} not found.");
  1149.                     $this->response->render_to_output();
  1150.                     exit();
  1151.                 }
  1152.                 return NULL;
  1153.             }
  1154.             // Make sure the course is visible
  1155.             // TODO: any availability other checks here?
  1156.             if ((int)$course_record->visible == 0) {
  1157.                 // Course not available
  1158.                 if ($require) {
  1159.                     $this->response->set_status_code(-513);
  1160.                     $this->response->set_status_descriptor('COURSE');
  1161.                     $this->response->add_data_line("Course {$this->course_id} is not available.");
  1162.                     $this->response->render_to_output();
  1163.                     exit();
  1164.                 }
  1165.                 return NULL;
  1166.             }
  1167.             // TODO: in future, we need to check that the course is Sloodle-enabled
  1168.             // TODO: in future, make sure we are authenticated for this particular course
  1169.             
  1170.             // Seems fine... return the object
  1171.             return $course_record;
  1172.         }
  1173.         
  1174.         /**
  1175.         * Get a course module instance for the module specified in the request
  1176.         * Uses the ID specified in {@link $module_id}.
  1177.         *
  1178.         * @param string $type specifies the name of the module type (e.g. 'forum', 'choice' etc.) - ignored if blank (default).
  1179.         * @param bool $require If TRUE, the function will NOT return failure. Rather, it will terminate the script with an error message.
  1180.         * @return object A database record if successful, or FALSE if not (e.g. if instance is not found, is not visible, or is not of the correct type)
  1181.         */
  1182.         function get_course_module_instance( $type = '', $require = TRUE )
  1183.         {
  1184.             // Make sure the request data is processed
  1185.             $this->process_request_data();
  1186.             
  1187.             // Make sure the module ID was specified
  1188.             if ($this->module_id == NULL) {
  1189.                 if ($require) {
  1190.                     $this->response->set_status_code(-711);
  1191.                     $this->response->set_status_descriptor('MODULE_DESCRIPTOR');
  1192.                     $this->response->add_data_line('Course module instance ID not specified.');
  1193.                     $this->response->render_to_output();
  1194.                     exit();
  1195.                 }
  1196.                 return FALSE;
  1197.             }
  1198.             
  1199.             // Attempt to get the instance
  1200.             if (!($cmi = sloodle_get_course_module_instance($this->module_id))) {
  1201.                 if ($require) {
  1202.                     $this->response->set_status_code(-712);
  1203.                     $this->response->set_status_descriptor('MODULE_DESCRIPTOR');
  1204.                     $this->response->add_data_line('Could not find course module instance.');
  1205.                     $this->response->render_to_output();
  1206.                     exit();
  1207.                 }
  1208.                 return FALSE;
  1209.             }
  1210.             
  1211.             // If the type was specified, then verify it
  1212.             if (!empty($type)) {
  1213.                 if (!sloodle_check_course_module_instance_type($cmi, strtolower($type))) {
  1214.                     if ($require) {
  1215.                         $this->response->set_status_code(-712);
  1216.                         $this->response->set_status_descriptor('MODULE_DESCRIPTOR');
  1217.                         $this->response->add_data_line("Course module instance not of expected type. (Expected: '$type').");
  1218.                         $this->response->render_to_output();
  1219.                         exit();
  1220.                     }
  1221.                     return FALSE;
  1222.                 }
  1223.             }
  1224.             
  1225.             // Make sure the instance is visible
  1226.             if (!sloodle_is_course_module_instance_visible($cmi)) {
  1227.                 if ($require) {
  1228.                     $this->response->set_status_code(-713);
  1229.                     $this->response->set_status_descriptor('MODULE_DESCRIPTOR');
  1230.                     $this->response->add_data_line('Specified course module instance is not available.');
  1231.                     $this->response->render_to_output();
  1232.                     exit();
  1233.                 }
  1234.                 return FALSE;
  1235.             }
  1236.             
  1237.             // Everything looks fine
  1238.             return $cmi;
  1239.         }
  1240.         
  1241.         
  1242.     ///// UTILITY FUNCTIONS /////
  1243.     
  1244.         /**
  1245.         * Obtains a named HTTP request parameter, and terminate with an error message if it has not been provided.
  1246.         * Note: for LSL linker scripts, this should *always* be used instead of the Moodle function, as this will
  1247.         *  render appropraitely formatted error messages, which LSL scripts can understand.
  1248.         *
  1249.         * @param string $parname The name of the HTTP request parameter to get.
  1250.         * @param int $type Specifies the expected type of parameter, as according to the Moodle documentation.
  1251.         * @return mixed The converted and cleaned parameter if it is found
  1252.         */
  1253.         function required_param($parname, $type=PARAM_RAW)
  1254.         {
  1255.             // Attempt to get the parameter
  1256.             $par = optional_param($parname, NULL, $type);
  1257.             // Was it provided?
  1258.             if (is_null($par)) {
  1259.                 // No - report the error
  1260.                 $this->response->set_status_code(-811);
  1261.                 $this->response->set_status_descriptor('SYSTEM');
  1262.                 $this->response->add_data_line("Required parameter not provided: '$parname'.");
  1263.                 $this->response->render_to_output();
  1264.                 exit();
  1265.             }
  1266.             
  1267.             return $par;
  1268.         }
  1269.         
  1270.     }

Documentation generated on Tue, 04 Mar 2008 15:08:45 +0000 by phpDocumentor 1.4.0