<?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 ? '&' : '?') . 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 ? '&' : '?') . 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 ? '&' : '?') . 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 . '&' . 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; }