Skip to content
Snippets Groups Projects
locallib.php 24.62 KiB
<?php
// This file is part of VPL for Moodle - http://vpl.dis.ulpgc.es/
//
// VPL for Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// VPL for Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with VPL for Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Common functions of VPL
 *
 * @package mod_vpl
 * @copyright 2012 Juan Carlos Rodríguez-del-Pino
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 * @author Juan Carlos Rodríguez-del-Pino <jcrodriguez@dis.ulpgc.es>
 */
defined('MOODLE_INTERNAL') || die();

define( 'VPL', 'vpl' );
define( 'VPL_SUBMISSIONS', 'vpl_submissions' );
define( 'VPL_JAILSERVERS', 'vpl_jailservers' );
define( 'VPL_RUNNING_PROCESSES', 'vpl_running_processes' );
define( 'VPL_VARIATIONS', 'vpl_variations' );
define( 'VPL_ASSIGNED_VARIATIONS', 'vpl_assigned_variations' );
define( 'VPL_GRADE_CAPABILITY', 'mod/vpl:grade' );
define( 'VPL_VIEW_CAPABILITY', 'mod/vpl:view' );
define( 'VPL_SUBMIT_CAPABILITY', 'mod/vpl:submit' );
define( 'VPL_SIMILARITY_CAPABILITY', 'mod/vpl:similarity' );
define( 'VPL_ADDINSTANCE_CAPABILITY', 'mod/vpl:addinstance' );
define( 'VPL_SETJAILS_CAPABILITY', 'mod/vpl:setjails' );
define( 'VPL_MANAGE_CAPABILITY', 'mod/vpl:manage' );

require_once(dirname(__FILE__).'/vpl.class.php');

/**
 * Set get vpl session var
 *
 * @param string $varname
 *            name of the session var without 'vpl_'
 * @param string $default
 *            default value
 * @param string $parname
 *            optional parameter name
 * @return $varname/param value
 */
function vpl_get_set_session_var($varname, $default, $parname = null) {
    global $SESSION;
    if ($parname == null) {
        $parname = $varname;
    }
    $res = $default;
    $fullname = 'vpl_' . $varname;
    if (isset( $SESSION->$fullname )) { // Exists var?
        $res = $SESSION->$fullname;
    }
    $res = optional_param( $parname, $res, PARAM_ALPHA );
    $SESSION->$fullname = $res;
    return $res;
}

/**
 * Open/create a file and its dir
 *
 * @param string $filename. Path to the file to open
 * @return resource file descriptor
 */
function vpl_fopen($filename) {
    global $CFG;

    if (! file_exists( $filename )) { // Exists file?
        $dir = dirname( $filename );
        if (! file_exists( $dir )) { // Create dir?
            mkdir( $dir, $CFG->directorypermissions, true );
        }
    }
    $fp = fopen( $filename, 'wb+' );
    return $fp;
}

/**
 * Recursively delete a directory
 *
 * @return bool All delete
 */
function vpl_delete_dir($dirname) {
    $ret = false;
    if (file_exists( $dirname )) {
        $ret = true;
        if (is_dir( $dirname )) {
            $dd = opendir( $dirname );
            if (! $dd) {
                return false;
            }
            $list = array ();
            while ( $name = readdir( $dd ) ) {
                if ($name != '.' && $name != '..') {
                    $list [] = $name;
                }
            }
            closedir( $dd );
            $ret = true;
            foreach ($list as $name) {
                $ret = vpl_delete_dir( $dirname . '/' . $name ) and $ret;
            }
            $ret = rmdir( $dirname ) and $ret;
        } else {
            $ret = unlink( $dirname );
        }
    }
    return $ret;
}

/**
 * Outputs a zip file and removes it. Must be called before any other output
 *
 * @param string $zipfilename. Name of the ZIP file with the data
 * @param string $name of file to be shown, without '.zip'
 *
 */
function vpl_output_zip($zipfilename, $name) {
    if (! file_exists($zipfilename)) {
        print_error("Zip file not found");
        die;
    }
    // Send zipdata.
    $blocksize = 1000 * 1024;
    $size = filesize( $zipfilename );
    $cname = rawurlencode( $name . '.zip' );
    $contentdisposition = 'Content-Disposition: attachment;';
    $contentdisposition .= ' filename="' . $name . '.zip";';
    $contentdisposition .= ' filename*=utf-8\'\'' . $cname;
    @header( 'Content-Length: ' . $size );
    @header( 'Content-Type: application/zip; charset=utf-8' );
    @header( $contentdisposition );
    @header( 'Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0' );
    @header( 'Content-Transfer-Encoding: binary' );
    @header( 'Expires: 0' );
    @header( 'Pragma: no-cache' );
    @header( 'Accept-Ranges: none' );
    // Get zip data.
    $offset = 0;
    while ($offset < $size) {
        echo file_get_contents( $zipfilename, false,  null, $offset, $blocksize);
        $offset += $blocksize;
    }
    // Remove zip file.
    unlink( $zipfilename );
}

/**
 * Get lang code @parm $bashadapt true adapt lang to bash LANG (default false)
 *
 * @return string
 */
function vpl_get_lang($bashadapt = false) {
    global $SESSION, $USER, $CFG;
    $commonlangs = array (
            'aa' => 'DJ',
            'af' => 'ZA',
            'am' => 'ET',
            'an' => 'ES',
            'az' => 'AZ',
            'ber' => 'DZ',
            'bg' => 'BG',
            'ca' => 'ES',
            'cs' => 'CZ',
            'da' => 'DK',
            'de' => 'DE',
            'dz' => 'BT',
            'en' => 'US',
            'es' => 'ES',
            'et' => 'EE',
            'fa' => 'IR',
            'fi' => 'FI',
            'fr' => 'FR',
            'hu' => 'HU',
            'ig' => 'NG',
            'it' => 'IT',
            'is' => 'IS',
            'ja' => 'JP',
            'km' => 'KH',
            'ko' => 'KR',
            'lo' => 'LA',
            'lv' => 'LV',
            'pt' => 'PT',
            'ro' => 'RO',
            'ru' => 'RU',
            'se' => 'NO',
            'sk' => 'sk',
            'so' => 'SO',
            'sv' => 'SE',
            'or' => 'IN',
            'th' => 'th',
            'ti' => 'ET',
            'tk' => 'TM',
            'tr' => 'TR',
            'uk' => 'UA',
            'yo' => 'NG'
    );
    if (isset( $SESSION->lang )) {
        $lang = $SESSION->lang;
    } else if (isset( $USER->lang )) {
        $lang = $USER->lang;
    } else if (isset( $CFG->lang )) {
        $lang = $CFG->lang;
    } else {
        $lang = 'en';
    }
    if ($bashadapt) {
        $parts = explode( '_', $lang );
        if (count( $parts ) == 2) {
            $lang = $parts [0];
        }
        if (isset( $commonlangs [$lang] )) {
            $lang = $lang . '_' . $commonlangs [$lang];
        }
        $lang .= '.UTF-8';
    }
    return $lang;
}

/**
 * generate URL to page with params
 *
 * @param $page string
 *            page from wwwroot
 * @param $var1 string
 *            var1 name optional
 * @param $value1 string
 *            value of var1 optional
 * @param $var2 string
 *            var2 name optional
 * @param $value2 string
 *            value of var2 optional
 * @param
 *            ...
 */
function vpl_abs_href() {
    global $CFG;
    $parms = func_get_args();
    $l = count( $parms );
    $href = $CFG->wwwroot . $parms [0];
    for ($p = 1; $p < $l - 1; $p += 2) {
        $href .= ($p > 1 ? '&amp;' : '?') . urlencode( $parms [$p] ) . '=' . urlencode( $parms [$p + 1] );
    }
    return $href;
}

/**
 * generate URL to page with params
 *
 * @param $page string
 *            page from wwwroot/mod/vpl/
 * @param $var1 string
 *            var1 name optional
 * @param $value1 string
 *            value of var1 optional
 * @param $var2 string
 *            var2 name optional
 * @param $value2 string
 *            value of var2 optional
 * @param
 *            ...
 */
function vpl_mod_href() {
    global $CFG;
    $parms = func_get_args();
    $l = count( $parms );
    $href = $CFG->wwwroot . '/mod/vpl/' . $parms [0];
    for ($p = 1; $p < $l - 1; $p += 2) {
        $href .= ($p > 1 ? '&amp;' : '?') . urlencode( $parms [$p] ) . '=' . urlencode( $parms [$p + 1] );
    }
    return $href;
}

/**
 * generate URL relative page with params
 *
 * @param $page string
 *            page relative
 * @param $var1 string
 *            var1 name optional
 * @param $value1 string
 *            value of var1 optional
 * @param $var2 string
 *            var2 name optional
 * @param $value2 string
 *            value of var2 optional
 * @param
 *            ...
 */
function vpl_rel_url() {
    $parms = func_get_args();
    $l = count( $parms );
    $url = $parms [0];
    for ($p = 1; $p < $l - 1; $p += 2) {
        $url .= ($p > 1 ? '&amp;' : '?') . urlencode( $parms [$p] ) . '=' . urlencode( $parms [$p + 1] );
    }
    return $url;
}
/**
 * Add a parm to a url
 *
 * @param $url string
 * @param $parm string
 *            name
 * @param $value string
 *            value of parm
 */
function vpl_url_add_param($url, $parm, $value) {
    if (strpos( $url, '?' )) {
        return $url . '&amp;' . urlencode( $parm ) . '=' . urlencode( $value );
    } else {
        return $url . '?' . urlencode( $parm ) . '=' . urlencode( $value );
    }
}

/**
 * Print a message and redirect
 *
 * @param string $link. The URL to redirect to
 * @param string $message to be print
 * @param string $type of message (success, info, warning, error). Default = info
 * @return void
 */
function vpl_redirect($link, $message, $type = 'info', $errorcode='') {
    global $OUTPUT;
    if (!$OUTPUT->has_started()) {
        echo $OUTPUT->header();
    }
    echo $OUTPUT->notification($message, $type);
    echo $OUTPUT->continue_button($link);
    echo $OUTPUT->footer();
    die();
}

/**
 * Inmediate redirect
 *
 * @param string $url URL to redirect to
 * @return void
 */
function vpl_inmediate_redirect($url) {
    echo vpl_include_js( 'window.location.replace("' . html_entity_decode(urldecode($url)) . '");' );
    die();
}
/**
 * Set JavaScript file from subdir jscript to be load
 *
 * @param $file string
 *            name of file to load
 * @param $defer boolean
 *            optional set if the load is inmediate or deffered
 * @return void
 */
function vpl_include_jsfile($file, $defer = true) {
    global $PAGE;
    $PAGE->requires->js( new moodle_url( '/mod/vpl/jscript/' . $file ), ! $defer );
}

/**
 * Set JavaScript code to be included
 *
 * @param $jscript string
 *            JavaScript code
 * @return void
 */
function vpl_include_js($jscript) {
    if ($jscript == '') {
        return '';
    }
    $ret = '<script type="text/javascript">';
    $ret .= "\n//<![CDATA[\n";
    $ret .= $jscript;
    $ret .= "\n//]]>\n</script>\n";
    return $ret;
}

/**
 * Popup message box to show text
 *
 * @param string $text to show. It use s() to sanitize text
 * @param boolean $print or not
 * @return void
 */
function vpl_js_alert($text, $print = true) {
    $aux = addslashes( $text ); // Sanitize text.
    $aux = str_replace( "\n", "\\n", $aux ); // Add \n to show multiline text.
    $aux = str_replace( "\r", "", $aux ); // Remove \r.
    $ret = vpl_include_js( 'alert("' . $aux . '");' );
    if ($print) {
        echo $ret;
        @ob_flush();
        flush();
    } else {
        return $ret;
    }
}
function vpl_get_select_time($maximum = null) {
    $minute = 60;
    if ($maximum === null) { // Default value.
        $maximum = 35 * $minute;
    }
    $ret = array (
            0 => get_string( 'select' )
    );
    if ($maximum <= 0) {
        return $ret;
    }
    $value = 4;
    if ($maximum < $value) {
        $value = $maximum;
    }
    while ( $value <= $maximum ) {
        if ($value < $minute) {
            $ret [$value] = get_string( 'numseconds', '', $value );
        } else {
            $num = ( int ) ($value / $minute);
            $ret [$num * $minute] = get_string( 'numminutes', '', $num );
            $value = $num * $minute;
        }
        $value *= 2;
    }
    return $ret;
}

/**
 * Return the post_max_size PHP config option in bytes
 *
 * @return int max size in bytes
 */
function vpl_get_max_post_size() {
    $maxs = trim( ini_get( 'post_max_size' ) );
    $len = strlen( $maxs );
    $last = strtolower( $maxs [$len - 1] );
    $max = ( int ) substr( $maxs, 0, $len - 1 );
    if ($last == 'k') {
        $max *= 1024;
    } else if ($last == 'm') {
        $max *= 1024 * 1024;
    } else if ($last == 'g') {
        $max *= 1024 * 1024 * 1000;
    }
    return $max;
}

/**
 * Convert a size in byte to string in Kb, Mb, Gb and Tb Following IEC "Prefixes for binary multiples"
 *
 * @param $size int
 *            size in bytes
 * @return string
 */
function vpl_conv_size_to_string($size) {
    static $measure = array (
            1024,
            1048576,
            1073741824,
            1099511627776,
            PHP_INT_MAX
    );
    static $measurename = array (
            'KiB',
            'MiB',
            'GiB',
            'TiB'
    );
    for ($i = 0; $i < count( $measure ) - 1; $i ++) {
        if ($measure [$i] <= 0) { // Check for int overflow.
            $num = $size / $measure [$i - 1];
            return sprintf( '%.2f %s', $num, $measurename [$i - 1] );
        }
        if ($size < $measure [$i + 1]) {
            $num = $size / $measure [$i];
            if ($num >= 3 || $size % $measure [$i] == 0) {
                return sprintf( '%4d %s', $num, $measurename [$i] );
            } else {
                return sprintf( '%.2f %s', $num, $measurename [$i] );
            }
        }
    }
}

/**
 * Return the array key after or equal to value
 *
 * @param $array
 * @param string $value of key to search >=
 * @return string key found
 */
function vpl_get_array_key($array, $value) {
    foreach ($array as $key => $nothing) {
        if ($key >= $value) {
            return $key;
        }
    }
    return $key;
}

/**
 * Return un array with the format [size in bytes]=> size in text The first element is [0] => select
 *
 * @param int $minimum the initial value
 * @param int $maximum the limit of values generates
 * @return array
 */
function vpl_get_select_sizes($minimum = 0, $maximum = PHP_INT_MAX) {
    $maximum = ( int ) $maximum;
    if ($maximum < 0) {
        $maximum = PHP_INT_MAX;
    }
    if ($maximum > 17.0e9) {
        $maximum = 16 * 1073741824;
    }
    $ret = array (
            0 => get_string( 'select' )
    );
    if ($minimum > 0) {
        $value = $minimum;
    } else {
        $value = 256 * 1024;
    }
    $pre = 0;
    $increment = $value / 4;
    while ( $value <= $maximum && $value > 0 ) { // Avoid int overflow.
        $ret [$value] = vpl_conv_size_to_string( $value );
        $pre = $value;
        $value += $increment;
        $value = ( int ) $value;
        if ($pre >= $value) { // Check for loop end.
            break;
        }
        if ($value >= 8 * $increment) {
            $increment = $value / 4;
        }
    }
    if ($pre < $maximum) { // Show limit value.
        $ret [$maximum] = vpl_conv_size_to_string( $maximum );
    }
    return $ret;
}

/**
 *
 * @param string $data
 * @return string newline separator "\r\n", "\n", "\r"
 */
function vpl_detect_newline(&$data) {
    // Detect text newline chars.
    if (strrpos( $data, "\r\n" ) !== false) {
        return "\r\n"; // Windows.
    } else if (strrpos( $data, "\n" ) !== false) {
        return "\n"; // UNIX.
    } else if (strrpos( $data, "\r" ) !== false) {
        return "\r"; // Mac.
    } else {
        return "\n"; // Default Unix.
    }
}

function vpl_notice($text, $type = 'success') {
    global $OUTPUT;
    echo $OUTPUT->notification( $text, $type );
}

/**
 * Remove trailing zeros from a float as string
 *
 * @param
 *            $value
 * @return string
 */
function vpl_rtzeros($value) {
    if (strpos( $value, '.' ) || strpos( $value, ',' )) {
        return rtrim( rtrim( $value, '0' ), '.,' );
    }
    return $value;
}

/**
 * Generate an array with index an values $url.index
 *
 * @param string $url base
 * @param $array array of index
 * @return array with index as key and url as value
 */
function vpl_select_index($url, $array) {
    $ret = array ();
    foreach ($array as $value) {
        $ret [$value] = $url . $value;
    }
    return $ret;
}

/**
 * Generate an array ready to be use in $OUTPUT->select_url
 *
 * @param string $url base
 * @param array $array of values
 * @return array with url as key and text as value
 */
function vpl_select_array($url, $array) {
    $ret = array ();
    foreach ($array as $value) {
        $ret [$url . $value] = get_string( $value, VPL );
    }
    return $ret;
}
function vpl_fileextension($filename) {
    return pathinfo( $filename, PATHINFO_EXTENSION );
}


/**
 * Get if filename has image extension
 * @param string $filename
 * @return boolean
 */
function vpl_is_image($filename) {
    return preg_match( '/^(gif|jpg|jpeg|png|ico)$/i', vpl_fileextension( $filename ) ) == 1;
}

/**
 * Get if filename has binary extension or binary data
 * @param string $filename
 * @param string &$data file contents
 * @return boolean
 */
function vpl_is_binary($filename, &$data = false) {
    if ( vpl_is_image( $filename ) ) {
        return true;
    }
    $fileext = 'zip|jar|pdf|tar|bin|7z|arj|deb|gzip|';
    $fileext .= 'rar|rpm|db|rtf|doc|docx|odt|xls|xlsx';
    if ( preg_match( '/^(' . $fileext . ')$/i', vpl_fileextension( $filename ) ) == 1 ) {
        return true;
    }
    if ($data === false) {
        return false;
    }
    return mb_detect_encoding( $data, 'UTF-8', true ) != 'UTF-8';
}

/**
 * Return data encoded to base64
 * @param string $filename
 * @param string &$data file contents
 * @return string
 */
function vpl_encode_binary($filename, &$data) {
    return base64_encode( $data );
}

/**
 * Return data decoded from base64
 * @param string $filename
 * @param string &$data file contents
 * @return string
 */
function vpl_decode_binary($filename, $data) {
    return base64_decode( $data );
}

/**
 * Return if path is valid
 * @param string $path
 * @return boolean
 */
function vpl_is_valid_path_name($path) {
    if (strlen( $path ) > 256) {
        return false;
    }
    $dirs = explode( '/', $path );
    for ($i = 0; $i < count( $dirs ); $i ++) {
        if (! vpl_is_valid_file_name( $dirs [$i] )) {
            return false;
        }
    }
    return true;
}

/**
 * Return if file or directory name is valid
 * @param string $name
 * @return boolean
 */
function vpl_is_valid_file_name($name) {
    $backtick = chr( 96 ); // Avoid warnning in codecheck.
    $regexp = '/[\x00-\x1f]|[:-@]|[{-~]|\\\\|\[|\]|[\/\^';
    $regexp .= $backtick . '´]|^\-|^ | $|^\.$|^\.\.$/';
    if (strlen( $name ) < 1) {
        return false;
    }
    if (strlen( $name ) > 128) {
        return false;
    }
    return preg_match( $regexp, $name ) === 0;
}

/**
 * Truncate string to the limit passed
 * @param string &$string
 * @param int $limit
 */
function vpl_truncate_string(&$string, $limit) {
    if (strlen( $string ) <= $limit) {
        return;
    }
    $string = substr( $string, 0, $limit - 3 ) . '...';
}

function vpl_bash_export($var, $value) {
    if ( is_int($value) ) {
        return 'export ' . $var . '=' . $value . "\n";
    } else {
        return 'export ' . $var . "='" . str_replace( "'", "'\"'\"'", $value ) . "'\n";
    }
}

/**
 * For debug purpose
 * Return content of vars ready to HTML
 */
function vpl_s() {
    $var = func_get_args();
    ob_start();
    call_user_func_array('var_dump', $var);
    $content = ob_get_contents();
    ob_end_clean();
    return htmlspecialchars($content, ENT_QUOTES);
}

/**
 * Truncate string fields of the VPL table
 * @param $instance object with the record
 * @return void
 */
function vpl_truncate_vpl($instance) {
    vpl_truncate_string( $instance->name, 255 );
    vpl_truncate_string( $instance->requirednet, 255 );
    vpl_truncate_string( $instance->password, 255 );
    vpl_truncate_string( $instance->variationtitle, 255 );
}

/**
 * Truncate string fields of the variations table
 * @param $instance object with the record
 * @return void
 */
function vpl_truncate_variations($instance) {
    vpl_truncate_string( $instance->identification, 40 );
}

/**
 * Truncate string fields of the running_processes table
 * @param $instance object with the record
 * @return void
 */
function vpl_truncate_running_processes($instance) {
    vpl_truncate_string( $instance->server, 255 );
}

/**
 * Truncate string fields of the jailservers table
 * @param $instance object with the record
 * @return void
 */
function vpl_truncate_jailservers($instance) {
    vpl_truncate_string( $instance->laststrerror, 255 );
    vpl_truncate_string( $instance->server, 255 );
}

/**
 * Check if IP is within networks
 *
 * @param $networks string with conma separate networks
 * @param $ip string optional with the IP to check, if omited then remote IP
 *
 * @return boolean true found
 */
function vpl_check_network($networks, $ip = false) {
    $networks = trim($networks);
    if ($networks == '') {
        return true;
    }
    if ($ip === false) {
        $ip = getremoteaddr();
    }
    return address_in_subnet( $ip, $networks );
}

/**
 * Get awesome icon for action
 * @param String $id
 * @return string
 */
function vpl_get_awesome_icon($str, $classes = '') {
    $icon = 'mod_vpl:' . $str;
    $imap = mod_vpl_get_fontawesome_icon_map();
    if ( isset( $imap[$icon]) ) {
        $ficon = $imap[$icon];
        return '<i class="fa ' . $ficon . $classes . '"></i> ';
    }
    return '';
}


/**
 * Create a new tabobject for navigation
 * @param String $id
 * @param string|moodle_url $href
 * @param string $str to be i18n
 * @param string $comp component
 * @return tabobject
 */
function vpl_create_tabobject($id, $href, $str, $comp = 'mod_vpl') {
    $stri18n = get_string( $str, $comp);
    $strdescription = vpl_get_awesome_icon($str) . $stri18n;
    return new tabobject( $id, $href, $strdescription, $stri18n );
}

/**
 * Get version string
 * @return string
 */
function vpl_get_version() {
    static $version;
    if (! isset( $version )) {
        $plugin = new stdClass();
        require(dirname( __FILE__ ) . '/version.php');
        $version = $plugin->release;
    }
    return $version;
}

function vpl_get_webservice_available() {
    global $DB, $USER, $CFG;
    if ($USER->id <= 2) {
        return false;
    }
    if (! $CFG->enablewebservices) {
        return false;
    }
    $service = $DB->get_record( 'external_services', array (
            'shortname' => 'mod_vpl_edit',
            'enabled' => 1
    ) );
    return ! empty( $service );
}
function vpl_get_webservice_token($vpl) {
    global $DB, $SESSION, $USER, $CFG;
    $now = time();
    if ($USER->id <= 2) {
        return '';
    }
    if (! $CFG->enablewebservices) {
        return '';
    }
    $service = $DB->get_record( 'external_services', array (
            'shortname' => 'mod_vpl_edit',
            'enabled' => 1
    ) );
    if (empty( $service )) {
        return '';
    }
    $tokenrecord = $DB->get_record( 'external_tokens', array (
            'userid' => $USER->id,
            'externalserviceid' => $service->id
    ) );
    if (! empty( $tokenrecord ) and $tokenrecord->validuntil > 0 and $tokenrecord->validuntil < $now) {
        unset( $tokenrecord ); // Will be delete before creating a new one.
    }
    if (empty( $tokenrecord )) {
        // Remove old tokens from DB.
        $select = 'validuntil > 0 AND  validuntil < ?';
        $DB->delete_records_select( 'external_tokens', $select, array (
                $now
        ) );
        // Select unique token.
        for ($i = 0; $i < 100; $i ++) {
            $token = md5( uniqid( mt_rand(), true ) );
            $tokenrecord = $DB->get_record( 'external_tokens', array (
                    'token' => $token
            ) );
            if (empty( $tokenrecord )) {
                break;
            }
        }
        if ($i >= 100) {
            return '';
        }
        $tokenrecord = new stdClass();
        $tokenrecord->token = $token;
        $tokenrecord->sid = session_id();
        $tokenrecord->userid = $USER->id;
        $tokenrecord->creatorid = $USER->id;
        $tokenrecord->tokentype = EXTERNAL_TOKEN_EMBEDDED;
        $tokenrecord->timecreated = $now;
        $tokenrecord->validuntil = $now + DAYSECS;
        $tokenrecord->iprestriction = getremoteaddr();
        $tokenrecord->contextid = $vpl->get_context()->id;
        $tokenrecord->externalserviceid = $service->id;
        $DB->insert_record( 'external_tokens', $tokenrecord );
    }
    return $tokenrecord->token;
}
function vpl_get_webservice_urlbase($vpl) {
    global $CFG;
    $token = vpl_get_webservice_token( $vpl );
    if ($token == '') {
        return '';
    }
    return $CFG->wwwroot . '/webservice/rest/server.php?moodlewsrestformat=json'
           . '&wstoken=' . $token . '&id=' . $vpl->get_course_module()->id . '&wsfunction=';
}

function vpl_timestamp_to_midnight($timestamp) {
    return $timestamp - ($timestamp + date('Z')) % 86400;
}