You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
526 lines
14 KiB
526 lines
14 KiB
<?php
|
|
/* For licensing terms, see /license.txt */
|
|
|
|
/**
|
|
* Code library for HotPotatoes integration.
|
|
*
|
|
* @package chamilo.exercise
|
|
*
|
|
* @author Istvan Mandak (original author)
|
|
*/
|
|
|
|
/* TODO: This is a global variable with too simple name, conflicts are possible.
|
|
Better eliminate it. Correct the test unit too. */
|
|
$dbTable = Database::get_course_table(TABLE_DOCUMENT);
|
|
|
|
/**
|
|
* Creates a hotpotato directory.
|
|
*
|
|
* If a directory of that name already exists, don't create any.
|
|
* If a file of that name exists, remove it and create a directory.
|
|
*
|
|
* @param string $base_work_dir Wanted path
|
|
*
|
|
* @return bool Always true so far
|
|
*/
|
|
function hotpotatoes_init($base_work_dir)
|
|
{
|
|
//global $_course, $_user;
|
|
$document_path = $base_work_dir.'/';
|
|
if (!is_dir($document_path)) {
|
|
if (is_file($document_path)) {
|
|
@unlink($document_path);
|
|
}
|
|
@mkdir($document_path, api_get_permissions_for_new_directories());
|
|
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
//why create a .htaccess here?
|
|
//if (!is_file($document_path.".htacces"))
|
|
//{
|
|
// if (!($fp = fopen($document_path.".htaccess", "w"))) {
|
|
// }
|
|
// $str = "order deny,allow\nallow from all";
|
|
// if (!fwrite($fp,$str)) { }
|
|
//}
|
|
}
|
|
|
|
/**
|
|
* Gets the title of the quiz file given as parameter.
|
|
*
|
|
* @param string $fname File name
|
|
* @param string $fpath File path
|
|
*
|
|
* @return string The exercise title
|
|
*/
|
|
function GetQuizName($fname, $fpath)
|
|
{
|
|
$title = GetComment($fname);
|
|
if (trim($title) == '') {
|
|
if (file_exists($fpath.$fname)) {
|
|
if (!($fp = @fopen($fpath.$fname, 'r'))) {
|
|
//die('Could not open Quiz input.');
|
|
return basename($fname);
|
|
}
|
|
|
|
$contents = @fread($fp, filesize($fpath.$fname));
|
|
@fclose($fp);
|
|
|
|
$title = api_get_title_html($contents);
|
|
}
|
|
}
|
|
if ($title == '') {
|
|
$title = basename($fname);
|
|
}
|
|
|
|
return (string) $title;
|
|
}
|
|
|
|
/**
|
|
* Gets the comment about a file from the corresponding database record.
|
|
*
|
|
* @param string $path File path
|
|
* @param string $courseCode (if not given, the course will be taken from the context)
|
|
*
|
|
* @return string comment from the database record
|
|
* Added conditional to the table if is empty
|
|
*/
|
|
function GetComment($path, $courseCode = '')
|
|
{
|
|
$dbTable = Database::get_course_table(TABLE_DOCUMENT);
|
|
$course_info = api_get_course_info($courseCode);
|
|
$path = Database::escape_string($path);
|
|
if (!empty($course_info) && !empty($path)) {
|
|
$query = "SELECT comment FROM $dbTable WHERE c_id = {$course_info['real_id']}";
|
|
$result = Database::query($query);
|
|
while ($row = Database::fetch_array($result)) {
|
|
return $row[0];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Sets the comment in the database for a particular path.
|
|
*
|
|
* @param string $path File path
|
|
* @param string $comment Comment to set
|
|
*
|
|
* @return Doctrine\DBAL\Driver\Statement|null
|
|
* Result of the database operation
|
|
* (Database::query will output some message directly on error anyway)
|
|
*/
|
|
function SetComment($path, $comment)
|
|
{
|
|
$dbTable = Database::get_course_table(TABLE_DOCUMENT);
|
|
$path = Database::escape_string($path);
|
|
$comment = Database::escape_string($comment);
|
|
$course_id = api_get_course_int_id();
|
|
$query = "UPDATE $dbTable SET comment = '$comment'
|
|
WHERE $course_id AND path = '$path'";
|
|
$result = Database::query($query);
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Reads the file contents into a string.
|
|
*
|
|
* @param string $full_file_path Urlencoded path
|
|
*
|
|
* @return string The file contents or false on security error
|
|
*/
|
|
function ReadFileCont($full_file_path)
|
|
{
|
|
if (empty($full_file_path)) {
|
|
return false;
|
|
}
|
|
if (Security::check_abs_path(dirname($full_file_path).'/', api_get_path(SYS_COURSE_PATH))) {
|
|
if (is_file($full_file_path)) {
|
|
if (!($fp = fopen(urldecode($full_file_path), 'r'))) {
|
|
return '';
|
|
}
|
|
$contents = fread($fp, filesize($full_file_path));
|
|
fclose($fp);
|
|
|
|
return $contents;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Writes the file contents into the given file path.
|
|
*
|
|
* @param string $full_file_path Urlencoded path
|
|
* @param string $content The file contents
|
|
*
|
|
* @return bool True on success, false on security error
|
|
*/
|
|
function WriteFileCont($full_file_path, $content)
|
|
{
|
|
// Check if this is not an attack, trying to get into other directories or something like that.
|
|
$_course = api_get_course_info();
|
|
if (Security::check_abs_path(
|
|
dirname($full_file_path).'/',
|
|
api_get_path(SYS_COURSE_PATH).$_course['path'].'/'
|
|
)) {
|
|
// Check if this is not an attack, trying to upload a php file or something like that.
|
|
if (basename($full_file_path) != Security::filter_filename(basename($full_file_path))) {
|
|
return false;
|
|
}
|
|
//if (!($fp = fopen(urldecode($full_file_path), 'w'))) {
|
|
//die('Could not open Quiz input.');
|
|
//}
|
|
$fp = fopen(urldecode($full_file_path), 'w');
|
|
if ($fp !== false) {
|
|
fwrite($fp, $content);
|
|
fclose($fp);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Gets the name of an img whose path is given (without directories or extensions).
|
|
*
|
|
* @param string $imageTag An image tag (<img src="...." ...>)
|
|
*
|
|
* @return string The image file name or an empty string
|
|
*/
|
|
function GetImgName($imageTag)
|
|
{
|
|
// Select src tag from img tag.
|
|
$match = [];
|
|
//preg_match('/(src=(["\'])1.*(["\'])1)/i', $imageTag, $match); //src
|
|
preg_match('/src(\s)*=(\s)*[\'"]([^\'"]*)[\'"]/i', $imageTag, $match); //get the img src as contained between " or '
|
|
//list($key, $srctag) = each($match);
|
|
$src = $match[3];
|
|
//$src = substr($srctag, 5, (strlen($srctag) - 7));
|
|
if (stristr($src, 'http') === false) {
|
|
// Valid or invalid image name.
|
|
if ($src == '') {
|
|
return '';
|
|
} else {
|
|
$tmp_src = basename($src);
|
|
if ($tmp_src == '') {
|
|
return $src;
|
|
} else {
|
|
return $tmp_src;
|
|
}
|
|
}
|
|
} else {
|
|
// The img tag contained "http", which means it is probably external. Ignore it.
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the source path of an image tag.
|
|
*
|
|
* @param string $imageTag An image tag
|
|
*
|
|
* @return string The image source or ""
|
|
*/
|
|
function GetSrcName($imageTag)
|
|
{
|
|
// Select src tag from img tag.
|
|
$match = [];
|
|
preg_match("|(src=\".*\" )|U", $imageTag, $match); //src
|
|
list(, $srctag) = each($match);
|
|
$src = substr($srctag, 5, (strlen($srctag) - 7));
|
|
if (stristr($src, 'http') === false) {
|
|
// valid or invalid image name
|
|
return $src;
|
|
} else {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the image parameters from an image path.
|
|
*
|
|
* @param string $fname File name
|
|
* @param string $fpath File path
|
|
* @param array $imgparams Reference to a list of image parameters (emptied, then used to return results)
|
|
* @param int $imgcount Reference to a counter of images (emptied, then used to return results)
|
|
*/
|
|
function GetImgParams($fname, $fpath, &$imgparams, &$imgcount)
|
|
{
|
|
// Select img tags from context.
|
|
$imgparams = [];
|
|
//phpinfo();
|
|
$contents = ReadFileCont("$fpath"."$fname");
|
|
$matches = [];
|
|
preg_match_all('(<img .*>)', $contents, $matches);
|
|
$imgcount = 0;
|
|
while (list(, $match) = each($matches)) {
|
|
// Each match consists of a key and a value.
|
|
while (list(, $imageTag) = each($match)) {
|
|
$imgname = GetImgName($imageTag);
|
|
if ($imgname != '' && !in_array($imgname, $imgparams)) {
|
|
array_push($imgparams, $imgname); // name (+ type) of the images in the html test
|
|
$imgcount = $imgcount + 1; // number of images in the html test
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generates a list of hidden fields with the image params given as parameter to this function.
|
|
*
|
|
* @param array $imgparams List of image parameters
|
|
*
|
|
* @return string String containing the hidden parameters built from the list given
|
|
*/
|
|
function GenerateHiddenList($imgparams)
|
|
{
|
|
$list = '';
|
|
if (is_array($imgparams)) {
|
|
while (list(, $string) = each($imgparams)) {
|
|
$list .= "<input type=\"hidden\" name=\"imgparams[]\" value=\"$string\" />\n";
|
|
}
|
|
}
|
|
|
|
return $list;
|
|
}
|
|
|
|
/**
|
|
* Searches for a node in the given array.
|
|
*
|
|
* @param array $array Reference to the array to search
|
|
* @param string $node Node we are looking for in the array
|
|
*
|
|
* @return mixed Node name or false if not found
|
|
*/
|
|
function myarraysearch(&$array, $node)
|
|
{
|
|
$match = false;
|
|
$tmp_array = [];
|
|
for ($i = 0; $i < count($array); $i++) {
|
|
if (!strcmp($array[$i], $node)) {
|
|
$match = $node;
|
|
} else {
|
|
array_push($tmp_array, $array[$i]);
|
|
}
|
|
}
|
|
$array = $tmp_array;
|
|
|
|
return $match;
|
|
}
|
|
|
|
/**
|
|
* Searches an image name into an array.
|
|
*
|
|
* @param array $imgparams Reference to an array to search
|
|
* @param string $string String to look for
|
|
*
|
|
* @return mixed String given if found, false otherwise
|
|
*
|
|
* @uses \myarraysearch This function is just an additional layer on the myarraysearch() function
|
|
*/
|
|
function CheckImageName(&$imgparams, $string)
|
|
{
|
|
$checked = myarraysearch($imgparams, $string);
|
|
|
|
return $checked;
|
|
}
|
|
|
|
/**
|
|
* Replaces an image tag by ???
|
|
*
|
|
* @param string $content The content to replace
|
|
*
|
|
* @return string The modified content
|
|
*/
|
|
function ReplaceImgTag($content)
|
|
{
|
|
$newcontent = $content;
|
|
$matches = [];
|
|
preg_match_all('(<img .*>)', $content, $matches);
|
|
while (list(, $match) = each($matches)) {
|
|
while (list(, $imageTag) = each($match)) {
|
|
$imgname = GetSrcName($imageTag);
|
|
if ($imgname != '') {
|
|
$prehref = $imgname;
|
|
$posthref = basename($imgname);
|
|
$newcontent = str_replace($prehref, $posthref, $newcontent);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $newcontent;
|
|
}
|
|
|
|
/**
|
|
* Fills the folder name up to a certain length with "0".
|
|
*
|
|
* @param string $name Original folder name
|
|
* @param int $nsize Length to reach
|
|
*
|
|
* @return string Modified folder name
|
|
*/
|
|
function FillFolderName($name, $nsize)
|
|
{
|
|
$str = '';
|
|
for ($i = 0; $i < $nsize - strlen($name); $i++) {
|
|
$str .= '0';
|
|
}
|
|
$str .= $name;
|
|
|
|
return $str;
|
|
}
|
|
|
|
/**
|
|
* Generates the HotPotato folder tree.
|
|
*
|
|
* @param string $folder Folder path
|
|
*
|
|
* @return string Folder name (modified)
|
|
*/
|
|
function GenerateHpFolder($folder)
|
|
{
|
|
$filelist = [];
|
|
if ($dir = @opendir($folder)) {
|
|
while (($file = readdir($dir)) !== false) {
|
|
if ($file != '.') {
|
|
if ($file != '..') {
|
|
$full_name = $folder.'/'.$file;
|
|
if (is_dir($full_name)) {
|
|
$filelist[] = $file;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
$name = '';
|
|
$w = true;
|
|
while ($w == true) {
|
|
$name = FillFolderName(mt_rand(1, 99999), 6);
|
|
$checked = myarraysearch($filelist, $name);
|
|
// As long as we find the name in the array, continue looping. As soon as we have a new element, quit.
|
|
if (!$checked) {
|
|
$w = false;
|
|
}
|
|
}
|
|
|
|
return $name;
|
|
}
|
|
|
|
/**
|
|
* Gets the folder name (strips down path).
|
|
*
|
|
* @param string $fname Path
|
|
*
|
|
* @return string Folder name stripped down
|
|
*/
|
|
function GetFolderName($fname)
|
|
{
|
|
$name = explode('/', $fname);
|
|
$name = $name[sizeof($name) - 2];
|
|
|
|
return $name;
|
|
}
|
|
|
|
/**
|
|
* Gets the folder path (with out the name of the folder itself) ?
|
|
*
|
|
* @param string $fname Path
|
|
*
|
|
* @return string Path stripped down
|
|
*/
|
|
function GetFolderPath($fname)
|
|
{
|
|
$str = '';
|
|
$name = explode('/', $fname);
|
|
for ($i = 0; $i < sizeof($name) - 1; $i++) {
|
|
$str = $str.$name[$i].'/';
|
|
}
|
|
|
|
return $str;
|
|
}
|
|
|
|
/**
|
|
* Checks if there are subfolders.
|
|
*
|
|
* @param string $path Path
|
|
*
|
|
* @return int 1 if a subfolder was found, 0 otherwise
|
|
*/
|
|
function CheckSubFolder($path)
|
|
{
|
|
$folder = GetFolderPath($path);
|
|
$dflag = 0;
|
|
if ($dir = @opendir($folder)) {
|
|
while (($file = readdir($dir)) !== false) {
|
|
if ($file != '.') {
|
|
if ($file != '..') {
|
|
$full_name = $folder.'/'.$file;
|
|
if (is_dir($full_name)) {
|
|
$dflag = 1; // first directory
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $dflag;
|
|
}
|
|
|
|
/**
|
|
* Hotpotato Garbage Collector.
|
|
*
|
|
* @param string $folder Path
|
|
* @param int $flag Flag
|
|
* @param int $user_id User id
|
|
*/
|
|
function HotPotGCt($folder, $flag, $user_id)
|
|
{
|
|
// Garbage Collector
|
|
$filelist = [];
|
|
if ($dir = @opendir($folder)) {
|
|
while (($file = readdir($dir)) !== false) {
|
|
if ($file != '.') {
|
|
if ($file != '..') {
|
|
$full_name = $folder.'/'.$file;
|
|
if (is_dir($full_name)) {
|
|
HotPotGCt($folder.'/'.$file, $flag, $user_id);
|
|
} else {
|
|
$filelist[] = $file;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
closedir($dir);
|
|
}
|
|
|
|
foreach ($filelist as $val) {
|
|
if (stristr($val, $user_id.'.t.html')) {
|
|
if ($flag == 1) {
|
|
my_delete($folder.'/'.$val);
|
|
} else {
|
|
echo $folder.'/'.$val.'<br />';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Deletes an attempt from TABLE_STATISTIC_TRACK_E_HOTPOTATOES.
|
|
*
|
|
* @param int $id
|
|
*/
|
|
function deleteAttempt($id)
|
|
{
|
|
$table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTPOTATOES);
|
|
$id = intval($id);
|
|
$sql = "DELETE FROM $table WHERE id = $id";
|
|
Database::query($sql);
|
|
}
|
|
|