Source for file general.php

Documentation is available at general.php

  1. <?php
  2.     
  3.     /**
  4.     * Sloodle general library.
  5.     *
  6.     * Provides various utility functionality for general Sloodle purposes.
  7.     *
  8.     * @package sloodle
  9.     * @copyright Copyright (c) 2007-8 Sloodle (various contributors)
  10.     * @license http://www.gnu.org/licenses/gpl-3.0.html GNU GPL v3
  11.     *
  12.     * @contributor Edmund Edgar
  13.     * @contributor Peter R. Bloomfield
  14.     *
  15.     */
  16.     
  17.     // This library expects that the Sloodle config file has already been included
  18.     //  (along with the Moodle libraries)
  19.     
  20.     /** Include our email functionality. */
  21.     require_once(SLOODLE_LIBROOT.'/mail.php');
  22.  
  23.  
  24.     /**
  25.     * Force the user to login, but reject guest logins.
  26.     * This function exists to workaround some Moodle 1.8 bugs.
  27.     * @return void 
  28.     */
  29.     function sloodle_require_login_no_guest()
  30.     {
  31.         global $CFG$SESSION$FULLME;
  32.         // Attempt a direct login initially
  33.         require_login(0false);
  34.         // Has the user been logged-in as a guest?
  35.         if (isguestuser()) {
  36.             // Make sure we can come back here after login
  37.             $SESSION->wantsurl $FULLME;
  38.             // Redirect to the appropriate login page
  39.             if (empty($CFG->loginhttps)) {
  40.                 redirect($CFG->wwwroot .'/login/index.php');
  41.             else {
  42.                 $wwwroot str_replace('http:','https:'$CFG->wwwroot);
  43.                 redirect($wwwroot .'/login/index.php');
  44.             }
  45.             exit();
  46.         }
  47.     }    
  48.     
  49.     /**
  50.     * Sets a Sloodle configuration value.
  51.     * This data will be stored in Moodle's "config" table, so it will persist even after Sloodle is uninstalled.
  52.     * After being set, it will be available (read-only) as a named member of Moodle's $CFG variable.
  53.     * <b>NOTE:</b> in Sloodle debug mode, this function will terminate the script with an error if the name is not prefixed with "sloodle_".
  54.     * @param string $name The name of the value to be stored (should be prefixed with "sloodle_")
  55.     * @param string $value The string representation of the value to be stored
  56.     * @return bool True on success, or false on failure (may fail if database query encountered an error)
  57.     * @see sloodle_get_config()
  58.     */
  59.     function sloodle_set_config($name$value)
  60.     {
  61.         // If in debug mode, ensure the name is prefixed appropriately for Sloodle
  62.         if (defined('SLOODLE_DEBUG'&& SLOODLE_DEBUG{
  63.             if (substr_count($name'sloodle_'1{
  64.                 exit ("ERROR: sloodle_set_config(..) called with invalid value name \"$name\". Expected \"sloodle_\" prefix.");
  65.             }
  66.         }
  67.         // Use the standard Moodle config function, ignoring the 3rd parameter ("plugin", which defaults to NULL)
  68.         return set_config(strtolower($name)$value);
  69.     }
  70.  
  71.     /**
  72.     * Gets a Sloodle configuration value from Moodle's "config" table.
  73.     * This function does not necessarily need to be used.
  74.     * All configuration data is available as named members of Moodle's $CFG global variable.
  75.     * <b>NOTE:</b> in Sloodle debug mode, this function will terminate the script with an error if the name is not prefixed with "sloodle_".
  76.     * @param string $name The name of the value to be stored (should be prefixed with "sloodle_")
  77.     * @return mixed A string containing the configuration value, or false if the query failed (e.g. if the named value didn't exist)
  78.     * @see sloodle_set_config()
  79.     */
  80.     function sloodle_get_config($name)
  81.     {
  82.         // If in debug mode, ensure the name is prefixed appropriately for Sloodle
  83.         if (defined('SLOODLE_DEBUG'&& SLOODLE_DEBUG{
  84.             if (substr_count($name'sloodle_'1{
  85.                 exit ("ERROR: sloodle_get_config(..) called with invalid value name \"$name\". Expected \"sloodle_\" prefix.");
  86.             }
  87.         }
  88.         // Use the Moodle config function, ignoring the plugin parameter
  89.         $val get_config(NULLstrtolower($name));
  90.         // Older Moodle versions return a database record object instead of the value itself
  91.         // Workaround:
  92.         if (is_object($val)) return $val->value;
  93.         return $val;
  94.     }
  95.     
  96.     /**
  97.     * Determines whether or not auto-registration is allowed for the site.
  98.     * @return bool True if auto-reg is allowed on the site, or false otherwise.
  99.     */
  100.     function sloodle_autoreg_enabled_site()
  101.     {
  102.         return (bool)sloodle_get_config('sloodle_allow_autoreg');
  103.     }
  104.     
  105.     /**
  106.     * Determines whether or not auto-enrolment is allowed for the site.
  107.     * @return bool True if auto-enrolment is allowed on the site, or false otherwise.
  108.     */
  109.     function sloodle_autoenrol_enabled_site()
  110.     {
  111.         return (bool)sloodle_get_config('sloodle_allow_autoenrol');
  112.     }
  113.  
  114.     /**
  115.     * Sends an XMLRPC message into Second Life.
  116.     * @param string $channel A string containing a UUID identifying the XMLRPC channel in SL to be used
  117.     * @param int $intval An integer value to be sent in the message
  118.     * @param string $strval A string value to be sent in the message
  119.     * @return bool True if successful, or false if an error occurs
  120.     */
  121.     function sloodle_send_xmlrpc_message($channel,$intval,$strval)
  122.     {
  123.         // Include our XMLRPC library
  124.         require_once(SLOODLE_DIRROOT.'/lib/xmlrpc.inc');
  125.         // Instantiate a new client object for communicating with Second Life
  126.         $client new xmlrpc_client("http://xmlrpc.secondlife.com/cgi-bin/xmlrpc.cgi");
  127.         // Construct the content of the RPC
  128.         $content '<?xml version="1.0"?><methodCall><methodName>llRemoteData</methodName><params><param><value><struct><member><name>Channel</name><value><string>'.$channel.'</string></value></member><member><name>IntValue</name><value><int>'.$intval.'</int></value></member><member><name>StringValue</name><value><string>'.$strval.'</string></value></member></struct></value></param></params></methodCall>';
  129.         
  130.         // Attempt to send the data via http
  131.         $response $client->send(
  132.             $content,
  133.             60,
  134.             'http'
  135.         );
  136.         
  137.         //var_dump($response); // Debug output
  138.         // Make sure we got a response value
  139.         if (!isset($response->val|| empty($response->val|| is_null($response->val)) {
  140.             // Report an error if we are in debug mode
  141.             if (defined('SLOODLE_DEBUG'&& SLOODLE_DEBUG{
  142.                 print '<p align="left">Not getting the expected XMLRPC response. Is Second Life broken again?<br/>';
  143.                 if (isset($response->errstr)) print "XMLRPC Error - ".$response->errstr;
  144.                 print '</p>';
  145.             }
  146.             return FALSE;
  147.         }
  148.         
  149.         // Check the contents of the response value
  150.         //if (defined('SLOODLE_DEBUG') && SLOODLE_DEBUG) {
  151.         //    print_r($response->val);
  152.         //}
  153.         
  154.         //TODO: Check the details of the response to see if this was successful or not...
  155.         return TRUE;
  156.     
  157.     }
  158.  
  159.     /**
  160.     * Old logging function
  161.     * @todo <b>May require update?</b>
  162.     */
  163.     function sloodle_add_to_log($courseid null$module null$action null$url null$cmid null$info null)
  164.     {
  165.  
  166.        global $CFG;
  167.  
  168.        // TODO: Make sure we set this in the calling function, then remove this bit
  169.        if ($courseid == null{
  170.           $courseid optional_param('sloodle_courseid',0,PARAM_RAW);
  171.        }
  172.  
  173.        // if no action is specified, use the object name
  174.        if ($action == null{
  175.           $action $_SERVER['X-SecondLife-Object-Name'];
  176.        }
  177.  
  178.        $region $_SERVER['X-SecondLife-Region'];
  179.        if ($info == null{
  180.           $info $region;
  181.        }
  182.  
  183.        $slurl '';
  184.        if (preg_match('/^(.*)\(.*?\)$/',$region,$matches)) // strip the coordinates, eg. Cicero (123,123)
  185.           $region $matches[1];
  186.        }
  187.  
  188.        $xyz $_SERVER['X-SecondLife-Local-Position'];
  189.        if (preg_match('/^\((.*?),(.*?),(.*?)\)$/',$xyz,$matches)) {
  190.           $xyz $matches[1].'/'.$matches[2].'/'.$matches[3];
  191.        }
  192.  
  193.        return add_to_log($courseidnull$action$CFG->wwwroot.'/mod/sloodle/toslurl.php?region='.urlencode($region).'&xyz='.$xyz$userid$info );
  194.        //return add_to_log($courseid, null, "ok", "ok", $userid, "ok");
  195.  
  196.     }
  197.  
  198.     /**
  199.     * Determines whether or not Sloodle is installed.
  200.     * Queries Moodle's modules table for a Sloodle entry.
  201.     * <b>NOTE:</b> does not check for the presence of the Sloodle files.
  202.     * @return bool True if Sloodle is installed, or false otherwise.
  203.     */
  204.     function sloodle_is_installed()
  205.     {
  206.         // Is there a Sloodle entry in the modules table?
  207.         return record_exists('modules''name''sloodle');
  208.     }
  209.     
  210.     /**
  211.     * Generates a random login security token.
  212.     * Uses mixed-case letters and numbers to generate a random 16-character string.
  213.     * @return string 
  214.     * @see sloodle_random_web_password()
  215.     */
  216.     function sloodle_random_security_token()
  217.     {
  218.         // Define the characters we can use in our token, and get the length of it
  219.         $str "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  220.         $strlen strlen($str1;
  221.         // Prepare the token variable
  222.         $token '';
  223.         // Loop once for each output character
  224.         for($length 0$length 16$length++{
  225.             // Shuffle the string, then pick and store a random character
  226.             $str str_shuffle($str);
  227.             $char mt_rand(0$strlen);
  228.             $token .= $str[$char];
  229.         }
  230.         
  231.         return $token;
  232.     }
  233.     
  234.     /**
  235.     * Generates a random web password
  236.     * Uses mixed-case letters and numbers to generate a random 8-character string.
  237.     * @return string 
  238.     * @see sloodle_random_security_token()
  239.     */
  240.     function sloodle_random_web_password()
  241.     {
  242.         // Define the characters we can use in our token, and get the length of it
  243.         $str "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  244.         $strlen strlen($str1;
  245.         // Prepare the password string
  246.         $pwd '';
  247.         // Loop once for each output character
  248.         for($length 0$length 8$length++{
  249.             // Shuffle the string, then pick and store a random character
  250.             $str str_shuffle($str);
  251.             $char mt_rand(0$strlen);
  252.             $pwd .= $str[$char];
  253.         }
  254.         
  255.         return $pwd;
  256.     }
  257.     
  258.     /**
  259.     * Generates a random prim password (7 to 9 digit number).
  260.     * @return string The password as a string
  261.     */
  262.     function sloodle_random_prim_password()
  263.     {
  264.         return (string)mt_rand(1000000999999999);
  265.     }
  266.     
  267.     /**
  268.     * Converts a string vector to an array vector.
  269.     * String vector should be of format "<x,y,z>".
  270.     * Converts to associative array with members 'x', 'y', and 'z'.
  271.     * Returns false if input parameter was not of correct format.
  272.     * @param string $vector A string vector of format "<x,y,z>".
  273.     * @return mixed 
  274.     * @see sloodle_array_to_vector()
  275.     * @see sloodle_round_vector()
  276.     */
  277.     function sloodle_vector_to_array($vector)
  278.     {
  279.         if (preg_match('/<(.*?),(.*?),(.*?)>/',$vector,$vectorbits)) {
  280.             $arr array();
  281.             $arr['x'$vectorbits[1];
  282.             $arr['y'$vectorbits[2];
  283.             $arr['z'$vectorbits[3];
  284.             return $arr;
  285.         }
  286.         return false;
  287.     }
  288.     
  289.     /**
  290.     * Converts an array vector to a string vector.
  291.     * Array vector should be associative, containing elements 'x', 'y', and 'z'.
  292.     * Converts to a string vector of format "<x,y,z>".
  293.     * @return string 
  294.     * @see sloodle_vector_to_array()
  295.     * @see sloodle_round_vector()
  296.     */
  297.     function sloodle_array_to_vector($arr)
  298.     {
  299.         $ret '<'.$arr['x'].','.$arr['y'].','.$arr['z'].'>';
  300.         return $ret;
  301.     }
  302.     
  303.     /**
  304.     * Obtains the identified course module instance database record.
  305.     * @param int $id The integer ID of a course module instance
  306.     * @return mixed  A database record if successful, or false if it could not be found
  307.     */
  308.     function sloodle_get_course_module_instance($id)
  309.     {
  310.         return get_record('course_modules''id'$id);
  311.     }
  312.     
  313.     /**
  314.     * Determines whether or not the specified course module instance is visible.
  315.     * Checks that the instance itself and the course section are both valid.
  316.     * @param int $id The integer ID of a course module instance.
  317.     * @return bool True if visible, or false if invisible or not found
  318.     */
  319.     {
  320.         // Get the course module instance record, whether directly from the parameter, or from the database
  321.         if (is_object($id)) {
  322.             $course_module_instance $id;
  323.         else if (is_int($id)) {
  324.             if (!($course_module_instance get_record('course_modules''id'$id))) return FALSE;
  325.         else return FALSE;
  326.         
  327.         // Make sure the instance itself is visible
  328.         if ((int)$course_module_instance->visible == 0return FALSE;
  329.         // Find out which section it is in, and if that section is valid
  330.         if (!($section get_record('course_sections''id'$course_module_instance->section))) return FALSE;
  331.         if ((int)$section->visible == 0return FALSE;
  332.         
  333.         // Looks like the module is visible
  334.         return TRUE;
  335.     }
  336.     
  337.     /**
  338.     * Determines if the specified course module instance is of the named type.
  339.     * For example, this can check if a particular instance is a "forum" or a "chat".
  340.     * @param int $id The integer ID of a course module instance
  341.     * @param string $module_name Module type to check (must be the exact name of an installed module, e.g. 'sloodle' or 'quiz')
  342.     * @return bool True if the module is of the specified type, or false otherwise
  343.     */
  344.     function sloodle_check_course_module_instance_type($id$module_name)
  345.     {
  346.         // Get the record for the module type
  347.         if (!($module_record get_record('modules''name'$module_name))) return FALSE;
  348.  
  349.         // Get the course module instance record, whether directly from the parameter, or from the database
  350.         if (is_object($id)) {
  351.             $course_module_instance $id;
  352.         else if (is_int($id)) {
  353.             if (!($course_module_instance get_record('course_modules''id'$id))) return FALSE;
  354.         else return FALSE;
  355.         
  356.         // Check the type of the instance
  357.         return ($course_module_instance->module == $module_record->id);
  358.     }
  359.     
  360.     /**
  361.     * Obtains the ID number of the specified module (type not instance).
  362.     * @param string $name The name of the module type to check, e.g. 'sloodle' or 'forum'
  363.     * @return mixed Integer containing module ID, or false if it is not installed
  364.     */
  365.     function sloodle_get_module_id($name)
  366.     {
  367.         // Ensure the name is a non-empty string
  368.         if (!is_string($name|| empty($name)) return FALSE;
  369.         // Obtain the module record
  370.         if (!($module_record get_record('modules''name'$module_name))) return FALSE;
  371.         
  372.         return $module_record->id;
  373.     }
  374.     
  375.     /**
  376.     * Checks if the specified position is in the current (site-wide) loginzone.
  377.     * @param mixed $pos A string vector or an associated array vector
  378.     * @return bool True if position is in LoginZone, or false if not
  379.     * @see sloodle_login_zone_coordinates()
  380.     * @todo Update or remove... no longer valid
  381.     */
  382.     function sloodle_position_is_in_login_zone($pos)
  383.     {
  384.         // Get a position array from the parameter
  385.         $posarr NULL;
  386.         if (is_array($pos&& count($pos== 3{
  387.             $posarr $pos;
  388.         else if (is_string($pos)) {
  389.             $posarr sloodle_vector_to_array($pos);
  390.         else {
  391.             return FALSE;
  392.         }
  393.         // Fetch the loginzone boundaries
  394.         list($maxarr,$minarrsloodle_login_zone_coordinates();
  395.  
  396.         // Make sure the position is not past the maximum bounds
  397.         if ( ($posarr['x'$maxarr['x']|| ($posarr['y'$maxarr['y']|| ($posarr['z'$maxarr['z']) ) {
  398.             return FALSE;
  399.         }
  400.         // Make sure the position is not past the minimum bounds
  401.         if ( ($posarr['x'$minarr['x']|| ($posarr['y'$minarr['y']|| ($posarr['z'$minarr['z']) ) {
  402.             return FALSE;
  403.         }
  404.  
  405.         return TRUE;
  406.     }
  407.     
  408.     /**
  409.     * Generates teleport coordinates for a user who has already finished the LoginZone process.
  410.     * @param string $pos A string vector giving the position of the LoginZone
  411.     * @param string $size A string vector giving the size of the LoginZone
  412.     * @return array, bool An associative array vector containing a teleport location, or false if the operation fails.
  413.     */
  414.     function sloodle_finished_login_coordinates($pos$size)
  415.     {
  416.         // Make sure the parameters are valid types
  417.         if (!is_string($pos|| !is_string($size)) {
  418.             return FALSE;
  419.         }
  420.         // Convert both to arrays
  421.         $posarr sloodle_vector_to_array($pos);
  422.         $sizearr sloodle_vector_to_array($size);
  423.         // Calculate a position just below the loginzone
  424.         $coord array();
  425.         $coord['x'round($posarr['x'],0);
  426.         $coord['y'round($posarr['y'],0);
  427.         $coord['z'round(($posarr['z']-(($sizearr['z'])/2)-2),0);
  428.         return $coord;
  429.     }
  430.     
  431.     /**
  432.     * Generates a random position within a cuboid zone of the specified size.
  433.     * (Note: leaves a 2 metre margin round the outside)
  434.     * @param array $size Associative array giving the size of the zone
  435.     * @return array An associative vector array
  436.     */
  437.     function sloodle_random_position_in_zone($size)
  438.     {
  439.         // Construct the half-size array
  440.         $halfsize array('x'=>($size['x'2.02.0'y'=>($size['y'2.02.0'z'=>($size['z'2.02.0);
  441.     
  442.         $pos array();
  443.         $pos['x'mt_rand(0.0$size['x'4.0$halfsize['x'];
  444.         $pos['y'mt_rand(0.0$size['y'4.0$halfsize['y'];
  445.         $pos['z'mt_rand(0.0$size['z'4.0$halfsize['z'];
  446.         return $pos;
  447.     }
  448.  
  449.     // Round the specified 3d vector to integer values
  450.     // $pos should be a vector string "<x,y,z>" or an associative array {x,y,z}
  451.     // Return is the same as the type passed-in
  452.     // If the input type is unrecognised, it simply returns it back out unchanged
  453.     /**
  454.     * Rounds the specified 3d vector integer values.
  455.     * Can handle/return a string vector, or an array vector.
  456.     * (Output type matches input type).
  457.     * @param mixed $pos Either a string vector or an array vector
  458.     * @return mixed 
  459.     */
  460.     function sloodle_round_vector($pos)
  461.     {
  462.         // We will work with an array, but allow for conversion to/from string
  463.         $arrayvec $pos;
  464.         $returnstring FALSE;
  465.         // Is it a string?
  466.         if (is_string($pos)) {
  467.             $arrayvec sloodle_vector_to_array($pos);
  468.             $returnstring TRUE;
  469.         else if (!is_array($pos)) {
  470.             return $pos;
  471.         }
  472.     
  473.         // Construct an output array
  474.         $output array();
  475.         foreach ($arrayvec as $key => $val{
  476.             $output[$keyround($val0);
  477.         }
  478.         
  479.         // If we need to convert it back to a string, then do so
  480.         if ($returnstring{
  481.             return sloodle_array_to_vector($output);
  482.         }
  483.         
  484.         return $output;
  485.     }
  486.     
  487.     /**
  488.     * Calculates the maximum and minimum bounds of the specified LoginZone
  489.     * Returns the bounds as a numeric array of two associate array vectors: ($max, $min).
  490.     * (Or returns false if no LoginZone position/size could be found in the Moodle configuration table).
  491.     * @param string $pos A string vector giving the position of the LoginZone
  492.     * @param string $size A string vector giving the size of the LoginZone
  493.     * @return array 
  494.     */
  495.     function sloodle_login_zone_bounds($pos$size)
  496.     {
  497.         // Make sure the parameters are valid types
  498.         if (($pos == FALSE|| ($size == FALSE)) {
  499.             return FALSE;
  500.         }
  501.         // Convert both to arrays
  502.         $posarr sloodle_vector_to_array($pos);
  503.         $sizearr sloodle_vector_to_array($size);
  504.         // Calculate the bounds
  505.         $max array();
  506.         $max['x'$posarr['x']+(($sizearr['x'])/2)-2;
  507.         $max['y'$posarr['y']+(($sizearr['y'])/2)-2;
  508.         $max['z'$posarr['z']+(($sizearr['z'])/2)-2;
  509.         $min array();
  510.         $min['x'$posarr['x']-(($sizearr['x'])/2)+2;
  511.         $min['y'$posarr['y']-(($sizearr['y'])/2)+2;
  512.         $min['z'$posarr['z']-(($sizearr['z'])/2)+2;
  513.         
  514.         return array($max,$min);
  515.     }
  516.     
  517.     
  518.     /**
  519.     * Checks if the given prim password is valid.
  520.     * @param string $password The password string to check
  521.     * @return bool True if it is valid, or false otherwise.
  522.     */
  523.     function sloodle_validate_prim_password($password)
  524.     {
  525.         // Check that it's a string
  526.         if (!is_string($password)) return false;
  527.         // Check the length
  528.         $len strlen($password);
  529.         if ($len || $len 9return false;
  530.         // Check that it's all numbers
  531.         if (!ctype_digit($password)) return false;
  532.         // Check that it doesn't start with a 0
  533.         if ($password[0== '0'return false;
  534.         
  535.         // It all seems fine
  536.         return true;
  537.     }
  538.     
  539.     /**
  540.     * Checks if the given prim password is valid, and provides feedback.
  541.     * An array is written to by reference, each element containing error codes.
  542.     * Each error code is a word. The full text of the error message may be obtained
  543.     *  from the string file by looking for "primpass:errorcode".
  544.     *
  545.     * @param string $password The password to validate
  546.     * @param array &$errors An array (passed by reference) which will contain any error messages
  547.     * @return bool True if the prim password is valid, or false otherwise
  548.     */
  549.     function sloodle_validate_prim_password_verbose($password&$errors)
  550.     {
  551.         // Initialise variables
  552.         $errors array();
  553.         $result true;
  554.         
  555.         // Check that it's a string
  556.         if (!is_string($password)) {
  557.             $errors['invalidtype';
  558.             $result false;
  559.         }
  560.         // Check the length
  561.         $len strlen($password);
  562.         if ($len 5{
  563.             $errors['tooshort';
  564.             $result false;
  565.         }
  566.         if ($len 9{
  567.             $errors['toolong';
  568.             $result false;
  569.         }
  570.         
  571.         // Check that it's all numbers
  572.         if (!ctype_digit($password)) {
  573.             $errors['numonly';
  574.             $result false;
  575.         }
  576.         
  577.         // Check that it doesn't start with a 0
  578.         if ($password[0== '0'{
  579.             $errors['leadingzero';
  580.             $result false;
  581.         }
  582.         
  583.         return $result;
  584.     }
  585.     
  586.     
  587.     /**
  588.     * Stores a pending login notification for an auto-registered user.
  589.     * A cron job will process the pending notification queue.
  590.     * @param string $destination Identifies the destination of the notification (for SL, this will be the object UUID. The send function will construct the email address)
  591.     * @param string $avatar Identifier for the avatar being notified
  592.     * @param string $username The username to notify the user of
  593.     * @param string $password The (plaintext) password to notify the user of
  594.     * @return bool True if successful, or false otherwise
  595.     */
  596.     function sloodle_login_notification($destination$avatar$username$password)
  597.     {
  598.         // If another pending notification already exists for the same username, then delete it
  599.         delete_records('sloodle_login_notifications''username'$username);
  600.         
  601.         // Add the new details
  602.         $notification new stdClass();
  603.         $notification->destination $destination;
  604.         $notification->avatar $avatar;
  605.         $notification->username $username;
  606.         $notification->password $password;
  607.  
  608.         return (bool)insert_record('sloodle_login_notifications'$notification);
  609.     }
  610.     
  611.     /**
  612.     * Send a login notification.
  613.     * @param string $destination Identifies the destination of the notification (for SL, this will be the object UUID. The target email address will be constructed)
  614.     * @param string $avatar Identifier for the avatar being notified
  615.     * @param string $username The username to notify the user of
  616.     * @param string $password The (plaintext) password to notify the user of
  617.     * @return bool True if successful, or false otherwise
  618.     */
  619.     function sloodle_send_login_notification($destination$avatar$username$password)
  620.     {
  621.         global $CFG;
  622.         return sloodle_text_email_sl($destination'SLOODLE_LOGIN'"$avatar|{$CFG->wwwroot}|$username|$password");
  623.     }
  624.     
  625.     /**
  626.     * Processes pending login notifications, up to a certain limit.
  627.     * Retrieves the requests one-at-a-time for processing.
  628.     * This is slower, but ensures minimal damage if the process is terminated, e.g. due to server timeout.
  629.     * @param int $limit The maximum number of pending requests to process.
  630.     * @return void 
  631.     */
  632.     function sloodle_process_login_notifications($limit 25)
  633.     {
  634.         global $CFG;
  635.         
  636.         // Validate the limit
  637.         $limit = (int)$limit;
  638.         if ($limit 1return;
  639.         
  640.         // Go through each one
  641.         for ($i 0$i $limit$i++{
  642.             // Obtain the first record
  643.             $recs get_records('sloodle_login_notifications''''''id''*'0$limit);
  644.             if (!$recsreturn false;
  645.             reset($recs);
  646.             $rec current($recs);
  647.             
  648.             // Determine the user ID of the person who requested this
  649.             $userid 0;
  650.             if (!($sloodleuser get_record('sloodle_users''uuid'$rec->avatar))) {
  651.                 // Failed to the user - get the guest user instead
  652.                 $guestdata guest_user();
  653.                 $userid $guestdata->id;
  654.             else {
  655.                 // Got the data - store the user ID
  656.                 $userid $sloodleuser->userid;
  657.             }
  658.             
  659.             // Send the notification
  660.             if (sloodle_send_login_notification($rec->destination$rec->avatar$rec->username$rec->password)) {
  661.                 // Log the notification
  662.                  add_to_log(SITEID'sloodle''view''''Sent login details by email to avatar in-world'0$userid);
  663.             else {
  664.                 // Log the failed notification (but don't keep trying the same one)
  665.                 add_to_log(SITEID'sloodle''view failed''''Failed to send login details by email to avatar in-world'0$userid);
  666.             }
  667.             
  668.             // Delete the record from the data
  669.             delete_records('sloodle_login_notifications''id'$rec->id);
  670.         }
  671.     }
  672.     
  673.     
  674.     /**
  675.     * Extracts a value from a name-value associative array if it is set.
  676.     * (The array should associate name to value).
  677.     * @param array $settings The array of names and values
  678.     * @param string $name The name of the value to retrieve
  679.     * @param mixed $default The default value to return if the specified value was not found
  680.     * @return mixed The value from the input array, or the $default parameter
  681.     */
  682.     function sloodle_get_value($settings$name$default null)
  683.     {
  684.         if (is_array($settings&& isset($settings[$name])) return $settings[$name];
  685.         return $default;
  686.     }
  687.     
  688.     
  689.     /**
  690.     * Outputs the standard form elements for access levels in object configuration.
  691.     * Each part can be optionally hidden, and default values can be provided.
  692.     * (Note: the server access level must be communicated from the object back to Moodle... rubbish implementation, but it works!)
  693.     * @param array $current_config An associative array of setting names to values, containing defaults. (Ignored if null).
  694.     * @param bool $show_use_object Determines whether or not the "Use Object" setting is shown
  695.     * @param bool $show_control_object Determines whether or not the "Control Object" setting is shown
  696.     * @param bool $show_server Determines whether or not the server access setting is shown
  697.     * @return void 
  698.     */
  699.     function sloodle_print_access_level_options($current_config$show_use_object true$show_control_object true$show_server true)
  700.     {
  701.         // Quick-escape: if everything is being suppressed, then do nothing
  702.         if (!($show_use_object || $show_control_object || $show_server)) return;
  703.         
  704.         // Fetch default values from the configuration, if possible
  705.         $sloodleobjectaccessleveluse sloodle_get_value($current_config'sloodleobjectaccessleveluse'SLOODLE_OBJECT_ACCESS_LEVEL_PUBLIC);
  706.         $sloodleobjectaccesslevelctrl sloodle_get_value($current_config'sloodleobjectaccesslevelctrl'SLOODLE_OBJECT_ACCESS_LEVEL_OWNER);
  707.         $sloodleserveraccesslevel sloodle_get_value($current_config'sloodleserveraccesslevel'SLOODLE_SERVER_ACCESS_LEVEL_PUBLIC);
  708.         
  709.         // Define our object access level array
  710.         $object_access_levels array(  SLOODLE_OBJECT_ACCESS_LEVEL_PUBLIC => get_string('accesslevel:public','sloodle'),
  711.                                         SLOODLE_OBJECT_ACCESS_LEVEL_GROUP => get_string('accesslevel:group','sloodle'),
  712.                                         SLOODLE_OBJECT_ACCESS_LEVEL_OWNER => get_string('accesslevel:owner','sloodle') );
  713.         // Define our server access level array
  714.         $server_access_levels array(  SLOODLE_SERVER_ACCESS_LEVEL_PUBLIC => get_string('accesslevel:public','sloodle'),
  715.                                         SLOODLE_SERVER_ACCESS_LEVEL_COURSE => get_string('accesslevel:course','sloodle'),
  716.                                         SLOODLE_SERVER_ACCESS_LEVEL_SITE => get_string('accesslevel:site','sloodle'),
  717.                                         SLOODLE_SERVER_ACCESS_LEVEL_STAFF => get_string('accesslevel:staff','sloodle') );
  718.     
  719.         // Display box and a heading
  720.         print_box_start('generalbox boxaligncenter');
  721.         echo '<h3>'.get_string('accesslevel','sloodle').'</h3>';
  722.     
  723.         // Print the object settings
  724.         if ($show_use_object || $show_control_object{
  725.             
  726.             // Object access
  727.             echo '<b>'.get_string('accesslevelobject','sloodle').'</b><br><i>'.get_string('accesslevelobject:desc','sloodle').'</i><br><br>';
  728.             // Use object
  729.             if ($show_use_object{
  730.                 echo get_string('accesslevelobject:use','sloodle').': ';
  731.                 choose_from_menu($object_access_levels'sloodleobjectaccessleveluse'$sloodleobjectaccessleveluse'');
  732.                 echo '<br><br>';
  733.             }
  734.             // Control object
  735.             if ($show_control_object{
  736.                 echo get_string('accesslevelobject:control','sloodle').': ';
  737.                 choose_from_menu($object_access_levels'sloodleobjectaccesslevelctrl'$sloodleobjectaccesslevelctrl'');
  738.                 echo '<br><br>';
  739.             }
  740.         }
  741.         
  742.         // Print the server settings
  743.         if ($show_server{
  744.             // Server access
  745.             echo '<b>'.get_string('accesslevelserver','sloodle').'</b><br><i>'.get_string('accesslevelserver:desc','sloodle').'</i><br><br>';
  746.             echo get_string('accesslevel','sloodle').': ';
  747.             choose_from_menu($server_access_levels'sloodleserveraccesslevel'$sloodleserveraccesslevel'');
  748.             echo '<br>';
  749.         }        
  750.         
  751.         print_box_end();
  752.     }
  753.  
  754.     function sloodle_access_level_option_choice($option$current_config$show$prefix ''$suffix ''{
  755.  
  756.     $access_levels array();
  757.         if ($option == 'sloodleserveraccesslevel'{
  758.             $access_levels arraySLOODLE_SERVER_ACCESS_LEVEL_PUBLIC => get_string('accesslevel:public','sloodle'),
  759.                                     SLOODLE_SERVER_ACCESS_LEVEL_COURSE => get_string('accesslevel:course','sloodle'),
  760.                                     SLOODLE_SERVER_ACCESS_LEVEL_SITE => get_string('accesslevel:site','sloodle'),
  761.                                     SLOODLE_SERVER_ACCESS_LEVEL_STAFF => get_string('accesslevel:staff','sloodle'
  762.                                   );
  763.         else {
  764.             $access_levels arraySLOODLE_OBJECT_ACCESS_LEVEL_PUBLIC => get_string('accesslevel:public','sloodle'),
  765.                                     SLOODLE_OBJECT_ACCESS_LEVEL_GROUP => get_string('accesslevel:group','sloodle'),
  766.                                     SLOODLE_OBJECT_ACCESS_LEVEL_OWNER => get_string('accesslevel:owner','sloodle'
  767.                                   );
  768.         }
  769.  
  770.         $defaults array(
  771.             'sloodleobjectaccessleveluse' => SLOODLE_OBJECT_ACCESS_LEVEL_PUBLIC,
  772.             'sloodleobjectaccesslevelctrl' => SLOODLE_OBJECT_ACCESS_LEVEL_OWNER,
  773.             'sloodleserveraccesslevel' => SLOODLE_SERVER_ACCESS_LEVEL_PUBLIC
  774.         );
  775.  
  776.         // Fetch default values from the configuration, if possible
  777.         $selected_value sloodle_get_value($current_config$option$defaults[$option]);
  778.         
  779.         if ($show{
  780.             return choose_from_menu($access_levels$prefix.$option.$suffix$selected_value''''0$return true);
  781.         else {
  782.             return '&nbsp;';
  783.         
  784.         
  785.     }
  786.  
  787.  
  788.     /**
  789.     * Returns a very approximate natural language description of a period of time (in minutes, hours, days, or weeks).
  790.     * Can also be used to describe how long ago something happened, in which case anything less than 1 minute is treated as 'now'.
  791.     * @param int $secs Number of seconds in period of time
  792.     * @param bool $ago If true (not default), then the time will be described in past tense, e.g. "3 days ago", as opposed to simply "3 days".
  793.     * @return string 
  794.     */
  795.     function sloodle_describe_approx_time($secs$ago false)
  796.     {
  797.         // Make sure the time is a positive integer
  798.         $secs = (int)$secs;
  799.         if ($secs 0$secs *= -1;
  800.         
  801.         // Less than a minute
  802.         if ($secs 60{
  803.             // If we are describing a past time, then approximate to 'now'
  804.             if ($agoreturn ucwords(get_string('now''sloodle'));
  805.             // Give the number of seconds
  806.             if ($secs == 1return '1 'get_string('second''sloodle');
  807.             return $secs.' 'get_string('seconds''sloodle');
  808.         }
  809.         
  810.         // This variable will hold the time description
  811.         $desc '';
  812.         
  813.         // Roughly 1 minute
  814.         if ($secs 120$desc '1 'get_string('minute''sloodle');
  815.         // Several minutes (up to 1 hour)
  816.         else if ($secs 3600$desc ((string)(int)($secs 60)).' 'get_string('minutes''sloodle');
  817.         // Roughly 1 hour
  818.         else if ($secs 7200$desc '1 'get_string('hour''sloodle');
  819.         // Several hours (up to 1 day)
  820.         else if ($secs 86400$desc ((string)(int)($secs 3600)).' 'get_string('hours''sloodle');
  821.         // Roughly 1 day
  822.         else if ($secs 172800$desc '1 'get_string('day''sloodle');
  823.         // Several days (up to 1 week)
  824.         else if ($secs 604800$desc ((string)(int)($secs 86400)).' 'get_string('days''sloodle');
  825.         // Roughly 1 week
  826.         else if ($secs 1209600$desc '1 'get_string('week''sloodle');
  827.         // Several weeks (up to 2 months)
  828.         else if ($secs 5184000$desc ((string)(int)($secs 604800)).' 'get_string('weeks''sloodle');
  829.         // Several months (up to 11 months)
  830.         else if ($secs 29462400$desc ((string)(int)($secs 2592000)).' 'get_string('months''sloodle');
  831.         // 1 year
  832.         else if ($secs 63072000$desc '1 'get_string('year''sloodle');
  833.         // Several years
  834.         else $desc ((string)(int)($secs 31536000)).' 'get_string('years''sloodle');
  835.         
  836.         // Add 'ago' if necessary
  837.         if ($agoreturn get_string('timeago''sloodle'$desc);
  838.         return $desc;
  839.     }
  840.     
  841.     /**
  842.     * Gets the basic URL of the current web-page being accessed.
  843.     * Includes the protocol, hostname, and script path/name.
  844.     * @return string 
  845.     */
  846.     function sloodle_get_web_path()
  847.     {
  848.         // Check for the protocol
  849.         if (empty($_SERVER['HTTPS']|| $_SERVER['HTTPS'== 'off'$protocol "http";
  850.         else $protocol "https";
  851.         // Get the host name (e.g. domain)
  852.         $host $_SERVER['SERVER_NAME'];
  853.         // Finally, get the script path/name
  854.         $file $_SERVER['SCRIPT_NAME'];
  855.         
  856.         return $protocol.'://'.$host.$file;
  857.     }
  858.     
  859.     /**
  860.     * Gets an array of subdirectories within the given directory.
  861.     * Ignores anything which starts with a .
  862.     * @param string $dir The directory to search WITHOUT a trailing slash. (Note: cannot search the current directory or higher in the file hierarchy)
  863.     * @param bool $relative If TRUE (default) the array of results will be relative to the input directory. Otherwise, they will include the input directory path.
  864.     * @return array|falseA numeric array of subdirectory names sorted alphabetically, or false if an error occurred (such as the input value not being a directory)
  865.     */
  866.     function sloodle_get_subdirectories($dir$relative true)
  867.     {
  868.         // Make sure we have a valid directory
  869.         if (empty($dir)) return false;
  870.         // Open the directory
  871.         if (!is_dir($dir)) return false;
  872.         if (!$dh opendir($dir)) return false;
  873.         
  874.         // Go through each item
  875.         $output array();
  876.         while (($file readdir($dh)) !== false{
  877.             // Ignore anything starting with a . and anything which isn't a directory
  878.             if (strpos($file'.'== 0continue;
  879.             $filetype @filetype($dir.'/'.$file);
  880.             if (empty($filetype|| $filetype != 'dir'continue;
  881.             
  882.             // Store it
  883.             if ($relative$output[$file;
  884.             else $output[$dir.'/'.$file;
  885.         }
  886.         closedir($dh);
  887.         natcasesort($output);
  888.         return $output;
  889.     }
  890.     
  891.     /**
  892.     * Gets an array of files within the given directory.
  893.     * Ignores anything which starts with a .
  894.     * @param string $dir The directory to search WITHOUT a trailing slash. (Note: cannot search the current directory or higher in the file hierarchy)
  895.     * @param bool $relative If TRUE (default) the array of results will be relative to the input directory. Otherwise, they will include the input directory path.
  896.     * @return array|falseA numeric array of file names sorted alphabetically, or false if an error occurred (such as the input value not being a directory)
  897.     */
  898.     function sloodle_get_files($dir$relative true)
  899.     {
  900.         // Make sure we have a valid directory
  901.         if (empty($dir)) return false;
  902.         // Open the directory
  903.         if (!is_dir($dir)) return false;
  904.         if (!$dh opendir($dir)) return false;
  905.         
  906.         // Go through each item
  907.         $output array();
  908.         while (($file readdir($dh)) !== false{
  909.             // Ignore anything starting with a . and anything which isn't a file
  910.             if (strpos($file'.'== 0continue;
  911.             $filetype @filetype($dir.'/'.$file);
  912.             if (empty($filetype|| $filetype != 'file'continue;
  913.             
  914.             // Store it
  915.             if ($relative$output[$file;
  916.             else $output[$dir.'/'.$file;
  917.         }
  918.         closedir($dh);
  919.         natcasesort($output);
  920.         return $output;
  921.     }
  922.     
  923.     /**
  924.     * Extracts the object name and version number from an object identifier.
  925.     * @param string $objid An object identifier, such as "chat-1.0"
  926.     * @return array A numeric array of name then version number.
  927.     */
  928.     function sloodle_parse_object_identifier($objid)
  929.     {
  930.         // Find the last dash character, and split the string around it.
  931.         $lastpos strrpos($objid'-');
  932.         // Check for common problems
  933.         if ($lastpos === falsereturn array($objid'')// No dash
  934.         if ($lastpos == 0return array(''substr($objid1))// Dash at start
  935.         if ($lastpos == (strlen($objid1)) return array(substr($objid0-1)'')// Dash at end
  936.         // Split up the values
  937.         $name substr($objid0$lastpos);
  938.         $version substr($objid$lastpos 1strlen($objid$lastpos 1);
  939.         return array($name$version);
  940.     }
  941.     
  942.     /**
  943.     * Gets all object types and versions available in this installation.
  944.     * Creates a 2-dimensional associative array.
  945.     * The top level is the object name, and the second is the object version (both as strings).
  946.     * The associated value is the path to the configuration form script, or boolean false
  947.     *  if the object has no configuration options.
  948.     * @return array|falseReturns a 2d associative array if successful, or false if an error occurs
  949.     */
  950.     {
  951.         // Fetch all sub-directories of the "mod" directory
  952.         $MODPATH SLOODLE_DIRROOT.'/mod';
  953.         $dirs sloodle_get_subdirectories($MODPATHtrue);
  954.         if (!$dirsreturn false;
  955.         
  956.         // Go through each object to parse names and version numbers.
  957.         // Object names should have format "name-version" (e.g. "chat-1.0").
  958.         // We will skip anything that does not match this format.
  959.         // We will also skip anything with a "noshow" file in the folder.
  960.         $mods array();
  961.         foreach ($dirs as $d{
  962.             if (empty($d)) continue;
  963.             
  964.             // Parse the object identifier
  965.             list($name$versionsloodle_parse_object_identifier($d);
  966.             if (empty($name|| empty($version)) continue;
  967.  
  968.             // Check if there's a noshow file
  969.             if (file_exists("{$MODPATH}/{$d}/noshow")) continue;
  970.             
  971.             // Check if this object has a configuration script
  972.             $cfgscript "$MODPATH/$d/object_config.php";
  973.             if (file_exists($cfgscript)) {
  974.                 $mods[$name][$version$cfgscript;
  975.             else {
  976.                 $mods[$name][$versionfalse;
  977.             }
  978.         }
  979.         
  980.         // Sort the array by name of the object
  981.         ksort($mods);        
  982.         return $mods;
  983.     }
  984.    
  985.  
  986.     /**
  987.     * Render a page viewing a particular feature, or a SLOODLE module.
  988.     * Outputs error text in SLOODLE debug mode.
  989.     * @param string $feature The name of a feature to view ("course", "user", "users"), or "module" to indicate that we are viewing some kind of module. Note: features should contain only alphanumric characters.
  990.     * @return bool True if successful, or false if not.
  991.     */
  992.     function sloodle_view($feature)
  993.     {
  994.         global $CFG$USER;
  995.         // Make sure the parameter is safe -- nothing but alphanumeric characters.
  996.         if (!ctype_alnum($feature)) {
  997.             sloodle_debug('sloodle_view(..): Invalid characters in view feature, "'.$feature.'"');
  998.             return false;
  999.         }
  1000.         if (empty($feature)) {
  1001.             sloodle_debug('sloodle_view(..): No feature name specified.');
  1002.             return false;
  1003.         }
  1004.         $feature trim($feature);
  1005.  
  1006.         // Has a module been requested?
  1007.         if (strcasecmp($feature'module'== 0{
  1008.             // We should have an ID parameter, indicating which module has been requested
  1009.             $id required_param('id'PARAM_INT);
  1010.             // Query the database for the SLOODLE module sub-type
  1011.             $instanceid get_field('course_modules''instance''id'$id);
  1012.             if ($instanceid === falseerror('Course module instance '.$id.' not found.');
  1013.             $type get_field('sloodle''type''id'$instanceid);
  1014.             if ($type === falseerror('SLOODLE module instance '.$instanceid.' not found.');
  1015.             // We will just use the type as a feature name now.
  1016.             // This means the following words are unavailable as module sub-types: course, user, users
  1017.             $feature $type;
  1018.         }
  1019.  
  1020.         // Attempt to include the relevant viewing class
  1021.         $filename SLOODLE_DIRROOT."/view/{$feature}.php";
  1022.         if (!file_exists($filename)) {
  1023.             error("SLOODLE file not found: view/{$feature}.php");
  1024.             exit();
  1025.         }
  1026.         require_once($filename);
  1027.  
  1028.         // Create and execute the viewing instance
  1029.         $classname 'sloodle_view_'.$feature;
  1030.         if (!class_exists($classname)) {
  1031.             error("SLOODLE class missing: {$classname}");
  1032.             exit();
  1033.         }
  1034.         $viewer new $classname();
  1035.         $viewer->view();
  1036.  
  1037.         return true;
  1038.     
  1039.  
  1040.     /**
  1041.     * Returns the given string, 'cleaned' and ready for output to SL as UTF-8.
  1042.     * Removes tags and slash-characters.
  1043.     * @param string str The string to clean.
  1044.     * @return string 
  1045.     */
  1046.     function sloodle_clean_for_output($str)
  1047.     {
  1048.         return strip_tags(stripcslashes(html_entity_decode($strENT_QUOTES'UTF-8')));
  1049.     }
  1050.  
  1051.     /**
  1052.     * Returns the given string, 'cleaned' and ready for storage in the database.
  1053.     * Note: removes tags and slash-characters.
  1054.     * @param string str The string to clean.
  1055.     * @return string 
  1056.     */
  1057.     function sloodle_clean_for_db($str)
  1058.     {
  1059.         return htmlentities($strENT_QUOTES'UTF-8');
  1060.     }
  1061.  
  1062.     /**
  1063.     * Converts a shorthand file size to a number of bytes, if necessary.
  1064.     * This follows PHP shorthand, with K for Kilobytes, M for Megabytes, and G for Gigabytes.
  1065.     * @param string size The shorthand size to conert
  1066.     * @return integer The size specified in bytes
  1067.     */
  1068.     function sloodle_convert_file_size_shorthand($size)
  1069.     {
  1070.         $size trim($size);
  1071.         $num = (int)$size;
  1072.         $char strtolower($size{strlen($size)-1});
  1073.         switch ($char)
  1074.         {
  1075.         case 'g'$num *= 1024;
  1076.         case 'm'$num *= 1024;
  1077.         case 'k'$num *= 1024;
  1078.         }
  1079.  
  1080.         return $num;
  1081.     }
  1082.  
  1083.     /**
  1084.     * Converts a file size to plain text.
  1085.     * For example, will convert "1024" to "1 kilobyte".
  1086.     * @param integer|stringsize If an integer, then it is the number of bytes. If a string, then it can be PHP shorthand, such as "1M" for 1 megabyte.
  1087.     * @return string A text string describing the specified size.
  1088.     */
  1089.     function sloodle_get_size_description($size)
  1090.     {
  1091.         // Make sure we have a number of bytes
  1092.         $bytes 0;
  1093.         if (is_int($size)) $bytes $size;
  1094.         else $bytes sloodle_convert_file_size_shorthand($size);
  1095.         $desc '';
  1096.  
  1097.         // Keep the number small by going with the largest possible units
  1098.         if ($bytes >= 1073741824$desc ($bytes 1073741824)." GB";
  1099.         else if ($bytes >= 1048576$desc ($bytes 1048576)" MB";
  1100.         else if ($bytes >= 1024$desc ($bytes 1024)" KB";
  1101.         else $desc $bytes " bytes";
  1102.  
  1103.         return $desc;
  1104.     }
  1105.  
  1106.     /**
  1107.     * Gets the maximum size of a file (in bytes) that can be uploaded using POST.
  1108.     * @return integer 
  1109.     */
  1110.     function sloodle_get_max_post_upload()
  1111.     {
  1112.         // Get the sizes of the relevant limits
  1113.         $upload_max_filesize sloodle_convert_file_size_shorthand(ini_get('upload_max_filesize'));
  1114.         $post_max_size sloodle_convert_file_size_shorthand(ini_get('post_max_size'));
  1115.  
  1116.         // Use the smaller limit
  1117.         return min($upload_max_filesize$post_max_size);
  1118.     }
  1119.  
  1120.  
  1121. ?>

Documentation generated on Fri, 17 Jul 2009 11:01:18 +0100 by phpDocumentor 1.4.0