PageRenderTime 41ms CodeModel.GetById 2ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 1ms

/sloodle/lib/io.php

http://sloodle.googlecode.com/
PHP | 1192 lines | 541 code | 130 blank | 521 comment | 193 complexity | ce6e1e824f01d7a84fb7fe644bc56d11 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   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/general.php');
  23    
  24          
  25    /** Defines the HTTP parameter name for a Sloodle password. */
  26    define('SLOODLE_PARAM_PASSWORD', 'sloodlepwd');
  27    /** Defines the HTTP parameter name for a course ID. */
  28    define('SLOODLE_PARAM_COURSE_ID', 'sloodlecourseid');
  29    /** Defines the HTTP parameter name for a Sloodle controller ID. */
  30    define('SLOODLE_PARAM_CONTROLLER_ID', 'sloodlecontrollerid');
  31    /** Defines the HTTP parameter name for a module ID. */
  32    define('SLOODLE_PARAM_MODULE_ID', 'sloodlemoduleid');
  33    /** Defines the HTTP parameter name for an avatar UUID. */
  34    define('SLOODLE_PARAM_AVATAR_UUID', 'sloodleuuid');
  35    /** Defines the HTTP parameter name for an avatar name. */
  36    define('SLOODLE_PARAM_AVATAR_NAME', 'sloodleavname');
  37    
  38    /** Defines the HTTP parameter name for a request descriptor. */
  39    define('SLOODLE_PARAM_REQUEST_DESC', 'sloodlerequestdesc');
  40    /** Defines the HTTP parameter name for indicating a request which relates to an object instead of a user. */
  41    define('SLOODLE_PARAM_IS_OBJECT', 'sloodleisobject');
  42    /** Defines the HTTP parameter name for specifying server access level. */
  43    define('SLOODLE_PARAM_SERVER_ACCESS_LEVEL', 'sloodleserveraccesslevel');
  44
  45    
  46    /**
  47    * 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}.
  48    * @package sloodle
  49    */
  50    class SloodleResponse
  51    {
  52      // DATA //
  53      
  54        /**
  55        * The separation string between lines of the response (typically just a newline).
  56        * @var string
  57        * @access private
  58        */
  59        var $line_separator = "\n";
  60        
  61        /**
  62        * The separation string between fields of a response line (by default, a pipe character |).
  63        * @var string
  64        * @access private
  65        */
  66        var $field_separator = "|";
  67      
  68        /**
  69        * Integer status code of the response.
  70        * Refer to the {@link http://slisweb.sjsu.edu/sl/index.php/Sloodle_status_codes status codes} page on the Sloodle wiki for a reference.
  71        * <b>Required.</b>
  72        * @var int
  73        * @access private
  74        */
  75        var $status_code = null;
  76        
  77        /**
  78        * Status descriptor string.
  79        * Should contain a generalised description/category of the status code.
  80        * <b>Optional but recommended. Ignored if null.</b>
  81        * @var string
  82        * @access private
  83        */
  84        var $status_descriptor = null;
  85        
  86        /**
  87        * Integer side effect(s) codes.
  88        * Status code(s) of side effect(s) incurred during the operation.
  89        * Can be a single integer, or an array of integers.
  90        * <b>Optional. Ignored if null.</b>
  91        * @var mixed
  92        * @access private
  93        */
  94        var $side_effects = null;
  95        
  96        /**
  97        * Request descriptor.
  98        * A brief string passed into the request by an LSL script (via HTTP parameter 'sloodlerequestdesc'),
  99        * which is returned so that it can correctly distinguish one request from anotehr.
 100        * <b>Optional. Ignored if null.</b>
 101        * @var string
 102        * @access private
 103        */
 104        var $request_descriptor = null;
 105        
 106        /**
 107        * Timestamp when the request was originally made by the LSL script.
 108        * This is <i>not</i> filled-in automatically. You must do it manually if you need it.
 109        * <b>Optional. Ignored if null.</b>
 110        * @var integer
 111        * @access private
 112        */
 113        var $request_timestamp = null;
 114        
 115        /**
 116        * Timestamp when the response was generated on the Moodle site.
 117        * This is <i>not</i> filled-in automatically. You must do it manually if you need it.
 118        * <b>Optional. Ignored if null.</b>
 119        * @var integer
 120        * @access private
 121        */
 122        var $response_timestamp = null;
 123        
 124        /**
 125        * Avatar UUID.
 126        * Should be a string specifying the UUID key of the agent in-world being handled. (Typically of the user who initiated the request).
 127        * <b>Optional. Ignored if null.</b>
 128        * @var string
 129        * @access private
 130        */
 131        var $avatar_uuid = null;
 132        
 133        /**
 134        * Tracking code of the request.
 135        * Use of this value is undefined. Please do not use it.
 136        * <b>Optional. Ignored if null.</b>
 137        * @var mixed
 138        * @access private
 139        */
 140        var $tracking_code = null;
 141        
 142        /**
 143        * Total number of pages.
 144        * If a response requires multiple pages, this value indicates how many pages there are.
 145        * <b>Optional, unless $page_number is specified. Ignored if null.</b> <i>Not yet supported.</i>
 146        * @var integer
 147        * @access private
 148        */
 149        var $page_total = null;
 150        
 151        /**
 152        * Current page number.
 153        * If a response requires multiple pages, this value indicates which page is being returned in this response.
 154        * <b>Optional, unless $page_total is specified. Ignored if null.</b> <i>Not yet supported.</i>
 155        * @var integer
 156        * @access private
 157        */
 158        var $page_number = null;
 159        
 160        /**
 161        * Data to render following the status line in the response.
 162        * This value can either be a scalar (single value, e.g. int, string, float), or an array.
 163        * If it is a single scalar, it is rendered as a single line.
 164        * If it is an array, then each element becomes one line.
 165        * If an element is a scalar, then it is directly output onto the line.
 166        * If an element is an array, then each child element is output as a separate field on the same line.
 167        * <b>Optional. Ignored if null.</b>
 168        * @see SloodleResponse::set_data()
 169        * @see SloodleResponse::add_data_line()
 170        * @see SloodleResponse::clear_data()
 171        * @var mixed
 172        * @access private
 173        */
 174        var $data = null;
 175        
 176    
 177      // ACCESSORS //
 178    
 179    
 180        /**
 181        * Sets the line separator.
 182        * @param string $sep A string to separate lines
 183        * @return void
 184        */
 185        function set_line_separator($sep)
 186        {
 187            $this->line_separator = $sep;
 188        }
 189        
 190        /**
 191        * Gets the line separator.
 192        * @return string The current line separator string
 193        */
 194        function get_line_separator()
 195        {
 196            return $this->line_separator;
 197        }
 198        
 199        
 200        /**
 201        * Sets the field separator.
 202        * @param string $sep A string to separate fields
 203        * @return void
 204        */
 205        function set_field_separator($sep)
 206        {
 207            $this->field_separator = $sep;
 208        }
 209        
 210        /**
 211        * Gets the field separator.
 212        * @return string The current field separator string
 213        */
 214        function get_field_separator()
 215        {
 216            return $this->field_separator;
 217        }
 218        
 219    
 220        /**
 221        * Accessor function to set member value {@link $status_code}
 222        * @param integer $par A non-zero status code
 223        * @return void
 224        */
 225        function set_status_code($par)
 226        {
 227            // Validate
 228            if (is_int($par) == false || $par == 0) {
 229                $this->_internal_validation_error("Sloodle - LSL response: invalid status code specified; should be non-zero integer", 0);
 230            }
 231            // Store
 232            $this->status_code = $par;
 233        }
 234    
 235        /**
 236        * Accessor function to set member value {@link $status_descriptor}
 237        * @param mixed $par A status descriptor string, or null to clear it
 238        * @return void
 239        */
 240        function set_status_descriptor($par)
 241        {
 242            // Validate
 243            if (is_string($par) == false && is_null($par) == false) {
 244                $this->_internal_validation_error("Sloodle - LSL response: invalid status descriptor specified; should be a string or null", 0);
 245            } else {
 246                $this->status_descriptor = $par;
 247            }
 248        }
 249    
 250        /**
 251        * 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.
 252        * @param mixed $par An integer side effect code, an array of integer side effect codes, or null to clear it
 253        * @return void
 254        */
 255        function set_side_effects($par)
 256        {
 257            // We'll use a variable to store the validity
 258            $valid = true;
 259            if (is_array($par)) {
 260                // Array types are acceptable
 261                // Make sure each array element is valid
 262                foreach ($par as $elem) {
 263                    if (!is_int($elem)) $valid = false;
 264                }
 265                // Were all elements valid?
 266                if ($valid == false) {
 267                    $this->_internal_validation_error("Sloodle - LSL response: invalid element in array of side effect codes; all elements should be integers", 0);
 268                }
 269            } else if (is_int($par) == false && is_null($par) == false) {
 270                // It's not an array, an integer or null
 271                $valid = false;
 272                $this->_internal_validation_error("Sloodle - LSL response: invalid side effect type; should be an integer, an array of integers, or null", 0);
 273            }
 274            // Was it valid?
 275            if ($valid) {
 276                $this->side_effects = $par;
 277            }
 278        }
 279
 280        /**
 281        * Adds one or more integer side effect codes to member {@link $status_code}.
 282        * @param mixed $par An integer side effect code, or an array of them.
 283        * @return void
 284        */
 285        function add_side_effects($par)
 286        {
 287            // We'll use a variable to store the validity
 288            $valid = true;
 289            if (is_array($par)) {
 290                // Array types are acceptable
 291                // Make sure each array element is valid
 292                foreach ($par as $elem) {
 293                    if (!is_int($elem)) $valid = false;
 294                }
 295                // Were all elements valid?
 296                if ($valid == false) {
 297                    $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);
 298                }
 299            } else if (is_int($par) == false) {
 300                // It's not an array or an integer
 301                $valid = false;
 302                $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);
 303            }
 304            // Was it valid?
 305            if ($valid) {
 306                // If we were passed just a single side effect, then convert it to an array
 307                if (is_int($par)) {
 308                    $par = array($par);
 309                }
 310                // Make sure our existing side effect member is an array
 311                if (is_null($this->side_effects)) $this->side_effects = array();
 312                else if (is_int($this->side_effects)) $this->side_effects = array($this->side_effects);
 313                        
 314                // Append our new side effect(s)               
 315                foreach ($par as $cur) {
 316                    $this->side_effects[] = $cur;
 317                }
 318            }
 319        }
 320        
 321        /**
 322        * Adds a single side effect code to member {@link $status_code}
 323        * @param integer $par An integer side-effect code.
 324        * @return void
 325        */
 326        function add_side_effect($par)
 327        {
 328            // Make sure the parameter is valid
 329            if (!is_int($par))
 330                $this->_internal_validation_error("Sloodle - LSL response: cannot add side effect. Invalid side effect type. Should be an integer.", 0);
 331            $this->add_side_effects($par);
 332        }
 333        
 334        /**
 335        * Accessor function to set member value {@link $request_descriptor}
 336        * @param mixed $par A string request descriptor, or null to clear it
 337        * @return void
 338        */
 339        function set_request_descriptor($par)
 340        {
 341            // Validate
 342            if (is_string($par) == false && is_null($par) == false) {
 343                $this->_internal_validation_error("Sloodle - LSL response: invalid request descriptor specified; should be a string or null", 0);
 344            } else {
 345                $this->request_descriptor = $par;
 346            }
 347        }
 348        
 349        /**
 350        * Accessor function to set member value {@link $request_timestamp}
 351        * @param mixed $par An integer timestamp, or null to clear it
 352        * @return void
 353        */
 354        function set_request_timestamp($par)
 355        {
 356            // Validate
 357            if (is_int($par) == false && is_null($par) == false) {
 358                $this->_internal_validation_error("Sloodle - LSL response: invalid request timestamp; should be an integer, or null", 0);
 359            } else {
 360                $this->request_timestamp = $par;
 361            }
 362        }
 363        
 364        /**
 365        * Accessor function to set member value {@link $response_timestamp}
 366        * @param mixed $par An integer timestamp, or null to clear it
 367        * @return void
 368        */
 369        function set_response_timestamp($par)
 370        {
 371            // Validate
 372            if (is_int($par) == false && is_null($par) == false) {
 373                $this->_internal_validation_error("Sloodle - LSL response: invalid response timestamp; should be an integer, or null", 0);
 374            } else {
 375                $this->response_timestamp = $par;
 376            }
 377        }
 378        
 379        /**
 380        * Accessor function to set member value {@link $avatar_uuid}
 381        * @param mixed $par A string containing a UUID, or null to clear it
 382        * @return void
 383        */
 384        function set_avatar_uuid($par)
 385        {
 386            // Validate
 387            if (is_string($par) == false && is_null($par) == false) {
 388                $this->_internal_validation_error("Sloodle - LSL response: invalid avatar UUID specified; should be a string or null", 0);
 389            } else {
 390                $this->avatar_uuid = $par;
 391            }
 392        }
 393        
 394        /**
 395        * Accessor function to set member value {@link $tracking_code}
 396        * @param mixed $par Any scalar value
 397        * @return void
 398        */
 399        function set_tracking_code($par)
 400        {
 401            $this->tracking_code = $par;
 402        }
 403        
 404        /**
 405        * Accessor function to set member value {@link $page_total}
 406        * @param mixed $par A positive page total count, or null to clear it
 407        * @return void
 408        */
 409        function set_page_total($par)
 410        {
 411            // Validate
 412            if ((is_int($par) == false || $par < 0) && is_null($par) == false) {
 413                $this->_internal_validation_error("Sloodle - LSL response: invalid page total; should be a positive integer, or null", 0);
 414            } else {
 415                $this->page_total = $par;
 416            }
 417        }
 418        
 419        /**
 420        * Accessor function to set member value {@link $page_number}
 421        * @param mixed $par A positive page number, or null to clear it
 422        * @return void
 423        */
 424        function set_page_number($par)
 425        {
 426            // Validate
 427            if ((is_int($par) == false || $par < 0) && is_null($par) == false) {
 428                $this->_internal_validation_error("Sloodle - LSL response: invalid page number; should be a positive integer, or null", 0);
 429            } else {
 430                $this->page_number = $par;
 431            }
 432        }
 433        
 434        /**
 435        * 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>
 436        * @param mixed $par Any scalar value, or a mixed array of scalars or scalar arrays, or null to clear it
 437        * @return void
 438        */
 439        function set_data($par)
 440        {
 441            // We'll use a variable to store validity
 442            $valid = true;
 443            if (is_array($par)) {
 444                // Check each element
 445                foreach ($par as $elem) {
 446                    // Is this element another array? Or is it a scalar/null value?
 447                    if (is_array($elem)) {
 448                        // Check each inner element for validity
 449                        foreach ($elem as $innerelem) {
 450                            // Is this element scalar or null? If not, it is invalid
 451                            if (is_scalar($innerelem) == false && is_null($innerelem) == false) {
 452                                $valid = false;
 453                            }
 454                        }
 455                    } else if (is_scalar($elem) == false && is_null($elem) == false) {
 456                        // Not an array, nor a scalar/null value - it is invalid
 457                        $valid = false;
 458                    }
 459                }
 460                if ($valid == false) {
 461                    $this->_internal_validation_error("Sloodle - LSL response: non-scalar element in array of items for a data line");
 462                }
 463            } else if (is_scalar($par) == false && is_null($par) == false) {
 464                $valid = false;
 465                $this->_internal_validation_error("Sloodle - LSL response: each line of data must be a scalar type, or an array of scalars");
 466            }
 467            // Store it if it is valid
 468            if ($valid) {
 469                $this->data = $par;
 470            }
 471        }
 472    
 473        /**
 474        * Adds one line of data to the {@link $data} member
 475        * @param mixed $par A scalar, or an array of scalars
 476        * @return void
 477        */
 478        function add_data_line($par)
 479        {
 480            // We'll use a variable to store validity
 481            $valid = true;
 482            if (is_array($par)) {
 483                // Check each element
 484                foreach ($par as $elem) {
 485                    if (is_scalar($elem) == false && is_null($elem) == false) $valid = false;
 486                }
 487                if ($valid == false) {
 488                    $this->_internal_validation_error("Sloodle - LSL response: non-scalar element in array of items for a data line");
 489                }
 490            } else if (is_scalar($par) == false && is_null($par) == false) {
 491                $valid = false;
 492                $this->_internal_validation_error("Sloodle - LSL response: each line of data must be a scalar type, or an array of scalars");
 493            }
 494            // Store it if it is valid
 495            if ($valid) {
 496                // Remove line separators
 497                $par = str_replace(array($this->line_separator, "\r"), ' ', $par); // We'll remove carriage returns, as they screw everything up... thanks to Microsoft...
 498                $this->data[] = $par;
 499            }
 500        }
 501        
 502        /**
 503        * Clears all data from member {@link $data}
 504        * @return void
 505        */
 506        function clear_data()
 507        {
 508            $this->data = null;
 509        }
 510        
 511        
 512      // OTHER FUNCTIONS //
 513      
 514        /**
 515        * <i>Constructor</i> - can intialise some variables
 516        * @param int $status_code The initial status code for the response (optional - ignore if null)
 517        * @param string $status_descriptor The initial status descriptor for the response (optional - ignore if null)
 518        * @param mixed $data The initial data for the response, which can be a scalar, or a mixed array of scalars/scalar-arrays (see {@link SloodleResponse::$data}) (optional - ignore if null)
 519        * @return void
 520        * @access public
 521        */
 522        function SloodleResponse($status_code = null, $status_descriptor = null, $data = null)
 523        {
 524            // Store the data
 525            if (!is_null($status_code)) $this->status_code = (int)$status_code;
 526            if (!is_null($status_descriptor)) $this->status_descriptor = (string)$status_descriptor;
 527            if (!is_null($data)) $this->data = $data;
 528        }
 529      
 530        /**
 531        * Renders the response to a string.
 532        * Prior to rendering, this function will perform final validation on all the data.
 533        * If anything fails, then the script will terminate with an LSL-friendly error message.
 534        *
 535        * @param string &$str Reference to a string object which the response should be rendered to.
 536        * @return void
 537        * @access public
 538        */
 539        function render_to_string(&$str)
 540        {
 541            // Clear the string
 542            $str = "";
 543            
 544            // We can omit any unnecessary items of data, but the number of field-separators must be correct
 545            // 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.:
 546            // 1|||AVATAR_LIST
 547            // (where the pipe-character | is the field separator)
 548            
 549            // We will step backwards through out list of fields, and as soon as one item is specified, all of them should be
 550            $showall = false;
 551            // Make sure that if the page number is specified, that the total is as well
 552            if (is_null($this->page_number) xor is_null($this->page_total)) {
 553                $this->_internal_validation_error("Sloodle - LSL response: script must specify both \"page_total\" *and* \"page_number\", or specify neither");
 554            } else if ($showall || is_null($this->page_number) == false) {
 555                $showall = true;
 556                $str = $this->field_separator . (string)$this->page_total . $this->field_separator . (string)$this->page_number . $str;
 557            }
 558            
 559            // Do we have a tracking code?
 560            if ($showall || is_null($this->tracking_code) == false) {
 561                $showall = true;
 562                $str = $this->field_separator . (string)$this->tracking_code . $str;
 563            }
 564            
 565            // User key?
 566            if ($showall || is_null($this->avatar_uuid) == false) {
 567                $showall = true;
 568                $str = $this->field_separator . $this->avatar_uuid . $str;
 569            }
 570            
 571            // Response timestamp?
 572            if ($showall || is_null($this->response_timestamp) == false) {
 573                $showall = true;
 574                $str = $this->field_separator . (string)$this->response_timestamp . $str;
 575            }
 576            
 577            // Request timestamp?
 578            if ($showall || is_null($this->request_timestamp) == false) {
 579                $showall = true;
 580                $str = $this->field_separator . (string)$this->request_timestamp . $str;
 581            }
 582            
 583            // Request descriptor?
 584            if ($showall || is_null($this->request_descriptor) == false) {
 585                $showall = true;
 586                $str = $this->field_separator . $this->request_descriptor . $str;
 587            }
 588            
 589            // Side-effects?
 590            if ($showall || is_null($this->side_effects) == false) {
 591                $showall = true;
 592                // Is this an array?
 593                if (is_array($this->side_effects)) {
 594                    // Yes - output each side effect code in a comma-separated list
 595                    $selist = "";
 596                    $isfirst = true;
 597                    foreach ($this->side_effects as $cur_side_effect) {
 598                        if (!$isfirst)  $selist .= ",";
 599                        else $isfirst = false;
 600                        $selist .= (string)$cur_side_effect;
 601                    }
 602                    // Add that list to the output
 603                    $str = $this->field_separator . $selist . $str;
 604                    
 605                } else {
 606                    // Not at an array - output the single item
 607                    $str = $this->field_separator . (string)$this->side_effects . $str;
 608                }
 609            }
 610            
 611            // Status descriptor?
 612            if ($showall || is_null($this->status_descriptor) == false) {
 613                $showall = true;
 614                $str = $this->field_separator . $this->status_descriptor . $str;
 615            }
 616            
 617            // Ensure that a status code has been specified
 618            if (is_null($this->status_code)) {
 619                // Not specified - report an error
 620                $this->_internal_validation_error("Sloodle - LSL response: no status code specified");
 621            } else {
 622                // Output the status code
 623                $str = (string)$this->status_code . $str;
 624            }
 625            
 626            
 627            // Has any data been specified?
 628            if (is_null($this->data) == false) {
 629                
 630                // Do we have an outer array?
 631                if (is_array($this->data)) {
 632                
 633                    // Go through each element in the outer array
 634                    foreach ($this->data as $outer_elem) {
 635                        
 636                        // Do we have an inner array on this element?
 637                        if (is_array($outer_elem)) {
 638                        
 639                            // Construct the line, piece-at-a-time
 640                            $line = "";
 641                            $isfirst = true;
 642                            foreach ($outer_elem as $inner_elem) {
 643                                // Use the standard field separator
 644                                if (!$isfirst) $line .= $this->field_separator;
 645                                else $isfirst = false;
 646                                $line .= (string)$inner_elem;
 647                            }
 648                            // Append the new line of data
 649                            $str .= $this->line_separator . (string)$line;
 650                        
 651                        } else {
 652                            // Output the single item
 653                            $str .= $this->line_separator . (string)$outer_elem;
 654                        }
 655                    }
 656                
 657                } else {
 658                    // Output the single item
 659                    $str .= $this->line_separator . (string)$this->data;
 660                }
 661            }
 662        }
 663        
 664        /**
 665        * Outputs the response directly to the HTTP response.
 666        *
 667        * @access public
 668        * @return void
 669        * @uses SloodleResponse::render_to_string() Outputs the result from this function directly to the HTTP response stream.
 670        */
 671        function render_to_output()
 672        {
 673            // Attempt to render the output to a string, and then copy that string to the HTTP response
 674            $str = "";
 675            $this->render_to_string($str);
 676            SloodleDebugLogger::log('RESPONSE', $str);
 677            echo $str;
 678        }
 679        
 680        
 681        // Quick-output
 682        // Can be called statically to allow simple output of basic data
 683        // The status code is required, but the other parameters are optional
 684        // If an error occurs, the LSL-friendly error message is output to the HTTP response, and the script terminated
 685        // If $static is true (default) then this will be treated as a static call, and a new response object will be used
 686        // If $static is false then this is treated as adding data to an existing response object
 687        /**
 688        * Quick output of data to avoid several accessor calls if the response is very basic.
 689        * Can be called statically to allow simple output of basic data.
 690        * The status code is required, but the other parameters are optional
 691        * If an error occurs, the LSL-friendly error message is output to the HTTP response, and the script terminated
 692        *
 693        * @param int $status_code The status code for the response (required)
 694        * @param string $status_descriptor The status descriptor for the response (optional - ignored if null)
 695        * @param mixed $data The data for the response, which can be a scalar, or a mixed array of scalars/scalar-arrays (see {@link SloodleResponse::$data}) (optional - ignored if null)
 696        * @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.
 697        * @return void
 698        * @access public
 699        */
 700        function quick_output($status_code, $status_descriptor = null, $data = null, $static = true)
 701        {
 702            // Is this s static call?
 703            if ($static) {
 704                // Construct and render the output of a response object
 705                $response = new SloodleResponse($status_code, $status_descriptor, $data);
 706                $response->render_to_output();
 707            } else {
 708                // Set all our data
 709                $this->status_code = $status_code;
 710                if ($status_descriptor != null) $this->status_descriptor = $status_descriptor;
 711                if ($data != null) $this->add_data_line($data);
 712                // Output it
 713                $this->render_to_output();
 714            }
 715        }
 716    
 717        
 718        /**
 719        * Internal function to report a data validation error.
 720        * Outputs an LSL-friendly error message, and terminates the script
 721        *
 722        * @param string $msg The error message to output.
 723        * @return void
 724        * @access private
 725        */
 726        function _internal_validation_error($msg)
 727        {
 728            exit("-104".$this->field_separator."SYSTEM".$this->line_separator.$msg);
 729        }
 730    }
 731    
 732    
 733    /**
 734    * Obtains a named HTTP request parameter, and terminates script with an error message if it was not provided.
 735    * This is a 'Sloodle-friendly' version of the Moodle "required_param" function.
 736    * Instead of terminate the script with an HTML-formatted error message, it will terminate with a message
 737    *  which conforms for the {@link http://slisweb.sjsu.edu/sl/index.php/Sloodle_communications_specification Sloodle communications specification},
 738    *  making it suitable for use in {@link http://slisweb.sjsu.edu/sl/index.php/Linker_Script linker scripts}.
 739    *
 740    * @param string $parname Name of the HTTP request parameter to fetch.
 741    * @param int $type Type of parameter expected, such as "PARAM_RAW". See Moodle documentation for a complete list.
 742    * @return mixed The appropriately parsed and/or cleaned parameter value, if it was found.
 743    * @deprecated
 744    */
 745    function sloodle_required_param($parname, $type)
 746    {
 747        exit('ERROR: deprecated function \'sloodle_required_param()\' called.');
 748        // Attempt to get the parameter
 749        $par = optional_param($parname, null, $type);
 750        // Was it provided?
 751        if (is_null($par)) {
 752            // No - report the error
 753            SloodleResponse::quick_output(-811, "SYSTEM", "Expected request parameter '$parname'.");
 754            exit();
 755        }
 756        
 757        return $par;
 758    }
 759    
 760    
 761    // This class handles an HTTP request
 762    /**
 763    * Handles incoming HTTP requests, typically from LSL if dealing with Second Life.
 764    * This class will perform much of the complex and repetitive processing required for handling HTTP requests.
 765    *
 766    * @uses SloodleResponse Outputs error messages in appropriate format if an error occurs.
 767    * @uses SloodleUser Stores and processes user data incoming from an HTTP request
 768    * 
 769    * @package sloodle
 770    */
 771    class SloodleRequest
 772    {
 773      // DATA //
 774        
 775        /**
 776        * Reference to the containing {@link SloodleSession} object.
 777        * If null, then this module is being used outwith the framework.
 778        * <b>Always check the status of the variable before using it!</b>
 779        * Note: if not provided, then this object will not render any response information.
 780        * @var object
 781        * @access protected
 782        */
 783        var $_session = null;
 784
 785        /**
 786        * Indicates whether or not the basic request data has already been processed.
 787        * This is used to ensure data is processed.
 788        * @var bool
 789        * @access private
 790        */
 791        var $request_data_processed = false;
 792        
 793        
 794    // ACCESSORS //
 795    
 796        /**
 797        * Checks whether or not the request data has already been processed.
 798        * @return bool
 799        */
 800        function is_request_data_processed()
 801        {
 802            return $this->request_data_processed;
 803        }
 804
 805        /**
 806        * Fetches the password request parameter.
 807        * @param bool $required If true (default) then the function will terminate the script with an error message if the HTTP request parameter was not specified.
 808        * @return string|null The password provided in the request parameters, or null if there wasn't one
 809        */
 810        function get_password($required = true)
 811        {
 812            return $this->get_param(SLOODLE_PARAM_PASSWORD, $required);
 813        }
 814        
 815        /**
 816        * Fetches the course ID request parameter.
 817        * @param bool $required If true (default) then the function will terminate the script with an error message if the HTTP request parameter was not specified.
 818        * @return int|null The course ID provided in the request parameters, or null if there wasn't one
 819        */
 820        function get_course_id($required = true)
 821        {
 822            return (int)$this->get_param(SLOODLE_PARAM_COURSE_ID, $required);
 823        }
 824        
 825        /**
 826        * Fetches the controller ID request parameter.
 827        * @param bool $required If true (default) then the function will terminate the script with an error message if the HTTP request parameter was not specified.
 828        * @return int|null The controller ID provided in the request parameters, or null if there wasn't one
 829        */
 830        function get_controller_id($required = true)
 831        {
 832            return (int)$this->get_param(SLOODLE_PARAM_CONTROLLER_ID, $required);
 833        }
 834        
 835        /**
 836        * Fetches the module ID request parameter.
 837        * @param bool $required If true (default) then the function will terminate the script with an error message if the HTTP request parameter was not specified.
 838        * @return int|null The module ID provided in the request parameters, or null if there wasn't one
 839        */
 840        function get_module_id($required = true)
 841        {
 842            return (int)$this->get_param(SLOODLE_PARAM_MODULE_ID, $required);
 843        }
 844        
 845        /**
 846        * Fetches the avatar UUID request parameter.
 847        * @param bool $required If true (default) then the function will terminate the script with an error message if the HTTP request parameter was not specified.
 848        * @return string|null The avatar UUID provided in the request parameters, or null if there wasn't one
 849        */
 850        function get_avatar_uuid($required = true)
 851        {
 852            return $this->get_param(SLOODLE_PARAM_AVATAR_UUID, $required);
 853        }
 854        
 855        /**
 856        * Fetches the avatar name request parameter.
 857        * @param bool $required If true (default) then the function will terminate the script with an error message if the HTTP request parameter was not specified.
 858        * @return string|null The avatar name provided in the request parameters, or null if there wasn't one
 859        */
 860        function get_avatar_name($required = true)
 861        {
 862            return $this->get_param(SLOODLE_PARAM_AVATAR_NAME, $required);
 863        }
 864        
 865        /**
 866        * Fetches the request descriptor request parameter.
 867        * @param bool $required If true (default) then the function will terminate the script with an error message if the HTTP request parameter was not specified.
 868        * @return string|null The request descriptor provided in the request parameters, or null if there wasn't one
 869        */
 870        function get_request_descriptor($required = true)
 871        {
 872            return $this->get_param(SLOODLE_PARAM_REQUEST_DESC, $required);
 873        }
 874        
 875        /**
 876        * Checks the parameters to determine if the request relates to an object rather than a user
 877        * @return bool True if the request seems to have come from an object, or false otherwise.
 878        */
 879        function is_object_request()
 880        {
 881            $par = $this->get_param(SLOODLE_PARAM_IS_OBJECT, false, false);
 882            if (strcasecmp($par, 'true') == 0 || strcasecmp($par, 'yes') == 0 || $par == '1') return true;
 883            return false;
 884        }
 885        
 886        /**
 887        * Fetches the server access level parameter, if specified.
 888        * @param bool $required If true (default) then the function will terminate the script with an error message if the HTTP request parameter was not specified.
 889        * @return string|null The server access level provided in the request parameters, or null if there wasn't one
 890        */
 891        function get_server_access_level($required = true)
 892        {
 893            return (int)$this->get_param(SLOODLE_PARAM_SERVER_ACCESS_LEVEL, $required);
 894        }
 895        
 896        
 897      // FUNCTIONS //
 898      
 899        /**
 900        * <i>Constructor</i> - initialises the {@link SloodleSession} object.
 901        * If the session parameter is null, then this object simply does not render response information.
 902        *
 903        * @param SloodleUser $_session A reference to the {@link SloodleSession} object which this request should use, or null
 904        */
 905        function SloodleRequest(&$_session)
 906        {
 907            // Store our session object
 908            $this->_session = &$_session;
 909        }
 910        
 911        /**
 912        * Process all of the standard data provided by the HTTP request, and write it into our {@link SloodleSession} object.
 913        * Requires that a {@link SloodleSession} object was provided at construction, and is stored in the $_session member.
 914        * NOTE: this does not load the module part of the session. That must be done separately, using the {@link SloodleSession::load_module()} member function.
 915        * @param bool $require_auth If true, then the function will terminate the script with an error message if it cannot authenticate the request through a course, controller and password
 916        * @param bool $require_user If true, then the function will terminate the script with an error message if a legitimate user was not identified or could not be auto-registered
 917        * @return bool True if successful, or false otherwise.
 918        */
 919        function process_request_data($require_auth = true, $require_user = true)
 920        {
 921
 922            SloodleDebugLogger::log('REQUEST', null);
 923
 924            // Do we have a session object?
 925            if (!isset($this->_session)) return false;
 926            
 927            // Store the request descriptor
 928            $this->_session->response->set_request_descriptor($this->get_request_descriptor(false));
 929            // Attempt to load the controller, then the course
 930            // (there is a shortcut, using course->load_by_controller(), 
 931            //  however, that makes it harder to locate problems)
 932            if ($this->_session->course->controller->load( $this->get_controller_id(false) )) {
 933                // Got the controller... now the course
 934                $this->_session->course->load( $this->_session->course->controller->get_course_id() );
 935            } else {
 936                // Perhaps a course was specified in the request instead?
 937                $this->_session->course->load( $this->get_course_id(false) );
 938            }
 939            
 940            // Get the avatar details
 941            $uuid = $this->get_avatar_uuid(false);
 942            $avname = $this->get_avatar_name(false);
 943            
 944            // Attempt to load an avatar
 945            if ($this->_session->user->load_avatar($uuid, $avname)) {
 946                // Success - now attempt to load the linked VLE user
 947                $this->_session->user->load_linked_user();
 948                // If we didn't already have a UUID then get it from the user data
 949                if (empty($uuid)) {
 950                    $uuid = $this->_session->user->get_avatar_uuid();
 951                }
 952                
 953                // Update the user's activity listing
 954                $this->_session->user->set_avatar_last_active();
 955                $this->_session->user->write_avatar();
 956            }
 957            
 958            // If we now have a UUID, then add it to our response data
 959            if (!empty($uuid)) $this->_session->response->set_avatar_uuid($uuid);
 960            
 961            $this->request_data_processed = true;
 962            return true;
 963        }
 964      
 965        
 966        /**
 967        * Gets a database record for the course identified in the request.
 968        * (Note: this function does not check whether or not the user is enrolled in the course)
 969        *
 970        * @param bool $require If true, the function will NOT return failure. Rather, it will terminate the script with an error message.
 971        * @return object A record directly from the database, or null if the course is not found.
 972        */
 973        function get_course_record($require = true)
 974        {
 975            // Make sure the request data is processed
 976            $this->process_request_data();
 977            // Make sure the course ID was specified
 978            if (is_null($this->course_id)) {
 979                if ($require) {
 980                    $this->response->set_status_code(-501);
 981                    $this->response->set_status_descriptor('COURSE');
 982                    $this->response->add_data_line('No course specified in request.');
 983                    $this->response->render_to_output();
 984                    exit();
 985                }
 986                return null;
 987            }
 988            // Attempt to get the course data
 989            $course_record = get_record('course', 'id', $this->course_id);
 990            if ($course_record === false) {
 991                // Course not found
 992                if ($require) {
 993                    $this->response->set_status_code(-512);
 994                    $this->response->set_status_descriptor('COURSE');
 995                    $this->response->add_data_line("Course {$this->course_id} not found.");
 996                    $this->response->render_to_output();
 997                    exit();
 998                }
 999                return null;
1000            }
1001            // Make sure the course is visible
1002            // TODO: any availability other checks here?
1003            if ((int)$course_record->visible == 0) {
1004                // Course not available
1005                if ($require) {
1006                    $this->response->set_status_code(-513);
1007                    $this->response->set_status_descriptor('COURSE');
1008                    $this->response->add_data_line("Course {$this->course_id} is not available.");
1009                    $this->response->render_to_output();
1010                    exit();
1011                }
1012                return null;
1013            }
1014            // TODO: in future, we need to check that the course is Sloodle-enabled
1015            // TODO: in future, make sure we are authenticated for this particular course
1016            
1017            // Seems fine... return the object
1018            return $course_record;
1019        }
1020        
1021        /**
1022        * Get a course module instance for the module specified in the request
1023        * Uses the ID specified in {@link $module_id}.
1024        *
1025        * @param string $type specifies the name of the module type (e.g. 'forum', 'choice' etc.) - ignored if blank (default).
1026        * @param bool $require If true, the function will NOT return failure. Rather, it will terminate the script with an error message.
1027        * @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)
1028        */
1029        function get_course_module_instance( $type = '', $require = true )
1030        {
1031            // Make sure the request data is processed
1032            $this->process_request_data();
1033            
1034            // Make sure the module ID was specified
1035            if ($this->module_id == null) {
1036                if ($require) {
1037                    $this->response->set_status_code(-711);
1038                    $this->response->set_status_descriptor('MODULE_DESCRIPTOR');
1039                    $this->response->add_data_line('Course module instance ID not specified.');
1040                    $this->response->render_to_output();
1041                    exit();
1042                }
1043                return false;
1044            }
1045            
1046            // Attempt to get the instance
1047            if (!($cmi = sloodle_get_course_module_instance($this->module_id))) {
1048                if ($require) {
1049                    $this->response->set_status_code(-712);
1050                    $this->response->set_status_descriptor('MODULE_DESCRIPTOR');
1051                    $this->response->add_data_line('Could not find course module instance.');
1052                    $this->response->render_to_output();
1053                    exit();
1054                }
1055                return false;
1056            }
1057            
1058            // If the type was specified, then verify it
1059            if (!empty($type)) {
1060                if (!sloodle_check_course_module_instance_type($cmi, strtolower($type))) {
1061                    if ($require) {
1062                        $this->response->set_status_code(-712);
1063                        $this->response->set_status_descriptor('MODULE_DESCRIPTOR');
1064                        $this->response->add_data_line("Course module instance not of expected type. (Expected: '$type').");
1065                        $this->response->render_to_output();
1066                        exit();
1067                    }
1068                    return false;
1069                }
1070            }
1071            
1072            // Make sure the instance is visible
1073            if (!sloodle_is_course_module_instance_visible($cmi)) {
1074                if ($require) {
1075                    $this->response->set_status_code(-713);
1076                    $this->response->set_status_descriptor('MODULE_DESCRIPTOR');
1077                    $this->response->add_data_line('Specified course module instance is not available.');
1078                    $this->response->render_to_output();
1079                    exit();
1080                }
1081                return false;
1082            }
1083            
1084            // Everything looks fine
1085            return $cmi;
1086        }
1087        
1088        
1089    // UTILITY FUNCTIONS //
1090    
1091        /**
1092        * Obtains a named HTTP request parameter, or NULL if it has not been provided.
1093        * Return values are always strings.
1094        * @param string $parname The name of the parameter to fetch
1095        * @param mixed $default The value to return if the parameter cannot be found
1096        * @return string|mixed The raw parameter value (will be a string if the parameter was found, or the value of parameter $default otherwise)
1097        */
1098        function optional_param($parname, $default = null)
1099        {
1100            if (isset($_REQUEST[$parname])) return (string)$_REQUEST[$parname];
1101            return $default;
1102        }
1103    
1104        /**
1105        * Obtains a named HTTP request parameter, or terminates with an error message if it has not been provided.
1106        * Note: for linker scripts, this should *always* be used instead of the standard Moodle function, as this will
1107        *  render appropriately formatted error messages, which scripts can understand.
1108        * Also note that this function always returned values in the string type. They must be cast.
1109        *
1110        * @param string $parname The name of the HTTP request parameter to get.
1111        * @return string The raw parameter value
1112        */
1113        function required_param($parname)
1114        {
1115            // Is the parameter provided?
1116            if (!isset($_REQUEST[$parname])) {
1117                // No - report the error
1118                if (isset($this->_session)) {
1119                    $this->_session->response->set_statu…

Large files files are truncated, but you can click here to view the full file