/** * transform all entities of $string to their hexadecimal representation * * @param $string string original string to entify * @param $quote_style string Constant choosen among ENT_COMPAT, ENT_QUOTES OR ENT_NOQUOTES (see claro_htmlentities doc for more info) * * @return string entified string */ function xmlentities($string, $quote_style = ENT_QUOTES) { static $trans; // remove all html entities before xml encoding // must convert all quotes to avoid remaining html entity in code $string = claro_html_entity_decode($string, ENT_QUOTES); // xml encoding if (!isset($trans)) { $trans = get_html_translation_table(HTML_ENTITIES, $quote_style); foreach (array_keys($trans) as $key) { $trans[$key] = '&#' . ord($key) . ';'; } // dont translate the '&' in case it is part of &xxx; $trans[chr(38)] = '&'; } // after the initial translation, _do_ map standalone '&' into '&' return preg_replace("/&(?![A-Za-z]{0,4}\\w{2,3};|#[0-9]{2,3};)/", "&", strtr($string, $trans)); }
function _entityDecode($text) { return claro_html_entity_decode(strtr($text, array(''' => '\'')), ENT_QUOTES, 'UTF-8'); }
/** * Returns decoded utf-8 $str. No changes are made if it was not utf-8 * */ function claro_utf8_decode($str, $toCharset = '') { if ($toCharset != '') { $charset = $toCharset; } else { $charset = $GLOBALS['charset']; } if (strtoupper($charset) == 'UTF-8' || !seems_utf8($str)) { return $str; } elseif (strtoupper($charset) == 'ISO-8859-1') { return utf8_decode($str); } elseif (function_exists('mb_convert_encoding')) { return mb_convert_encoding($str, 'UTF-8', $charset); } elseif (function_exists('iconv')) { return iconv('UTF-8', $charset . '//TRANSLIT', $str); } else { $converted = claro_htmlentities($str, ENT_NOQUOTES, 'UTF-8'); return claro_html_entity_decode($converted, ENT_NOQUOTES, $charset); } }
/** * Reverse function for claro_htmlentities. * Convert entities in UTF-8. * @param $text_to_convert Text to convert. * @return string converted * @access public */ public function unhtmlentities($text_to_convert) { return claro_html_entity_decode($text_to_convert, ENT_QUOTES, $this->encoding); }
/** * Create files (quiz) needed in the export of this module * * @copyright (c) 2001-2011, Universite catholique de Louvain (UCL) * @param int $quizId id of the Quiz * @param object $item item of the path * @param string $destDir path when the files need to be copied * @param int $deepness deepness of the destinationd directory * @return boolean */ public function prepareFiles($quizId, &$item, $destDir, $deepness) { $completionThresold = $item->getCompletionThreshold(); if (empty($completionThresold)) { $completionThresold = 50; } $quizId = (int) $quizId; $quiz = new Exercise(); if (!$quiz->load($quizId)) { $this->error[] = get_lang('Unable to load the exercise'); return false; } $deep = ''; if ($deepness) { for ($i = $deepness; $i > 0; $i--) { $deep .= ' ../'; } } // Generate standard page header $pageHeader = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>' . $quiz->getTitle() . '</title> <meta http-equiv="expires" content="Tue, 05 DEC 2000 07:00:00 GMT"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Content-Type" content="text/HTML; charset=' . get_locale('charset') . '" /> <link rel="stylesheet" type="text/css" href="' . $deep . get_conf('claro_stylesheet') . '/main.css" media="screen, projection, tv" /> <script language="javascript" type="text/javascript" src="' . $deep . 'js/jquery.js"></script> <script language="javascript" type="text/javascript" src="' . $deep . 'js/claroline.js"></script> <script language="javascript" type="text/javascript" src="' . $deep . 'js/claroline.ui.js"></script> <script language="javascript" type="text/javascript" src="' . $deep . 'js/APIWrapper.js"></script> <script language="javascript" type="text/javascript" src="' . $deep . 'js/connector13.js"></script> <script language="javascript" type="text/javascript" src="' . $deep . 'js/scores.js"></script> </head> ' . "\n"; $pageBody = '<body onload="loadPage()"> <div id="claroBody"><form id="quiz"> <table width="100%" border="0" cellpadding="1" cellspacing="0" class="claroTable">' . "\n"; // Get the question list $questionList = $quiz->getQuestionList(); $questionCount = count($questionList); // Keep track of raw scores (ponderation) for each question $questionPonderationList = array(); // Keep track of correct texts for fill-in type questions // TODO La variable $fillAnswerList n'apparaît qu'une fois $fillAnswerList = array(); // Display each question $questionCount = 0; foreach ($questionList as $question) { // Update question number $questionCount++; // read the question, abort on error $scormQuestion = new ScormQuestion(); if (!$scormQuestion->load($question['id'])) { $this->error[] = get_lang('Unable to load exercise\'s question'); return false; } $questionPonderationList[] = $scormQuestion->getGrade(); $pageBody .= '<thead>' . "\n" . '<tr>' . "\n" . '<th>' . get_lang('Question') . ' ' . $questionCount . '</th>' . "\n" . '</tr>' . "\n" . '</thead>' . "\n"; $pageBody .= '<tr>' . "\n" . '<td>' . "\n" . $scormQuestion->export() . "\n" . '</td>' . "\n" . '</tr>' . "\n"; } $pageEnd = ' <tr> <td align="center"><br /><input type="button" value="' . get_lang('Ok') . '" onclick="calcScore()" /></td> </tr> </table> </form> </div></body></html>' . "\n"; /* Generate the javascript that'll calculate the score * We have the following variables to help us : * $idCounter : number of elements to check. their id are "scorm_XY" * $raw_to_pass : score (on 100) needed to pass the quiz * $fillAnswerList : a list of arrays (text, score) indexed on <input>'s names * */ $pageHeader .= ' <script type="text/javascript" language="javascript"> var raw_to_pass = '******'; var weighting = ' . array_sum($questionPonderationList) . '; var rawScore; var scoreCommited = false; var showScore = true; var fillAnswerList = new Array();' . "\n"; // This is the actual code present in every exported exercise. // use claro_html_entity_decode in output to prevent double encoding errors with some languages... $pageHeader .= ' function calcScore() { if( !scoreCommited ) { rawScore = CalculateRawScore(document, ' . getIdCounter() . ', fillAnswerList); var score = Math.max(Math.round(rawScore * 100 / weighting), 0); var oldScore = doLMSGetValue("cmi.score.raw"); doLMSSetValue("cmi.score.max", weighting); doLMSSetValue("cmi.score.min", 0); computeTime(); if (score > oldScore) // Update only if score is better than the previous time. { doLMSSetValue("cmi.raw", rawScore); } var oldStatus = doLMSGetValue( "cmi.completion_status" ) if (score >= raw_to_pass) { doLMSSetValue("cmi.completion_status", "completed"); } else if (oldStatus != "completed" ) // If passed once, never mark it as failed. { doLMSSetValue("cmi.completion_status", "failed"); } doLMSCommit(); doLMSFinish(); scoreCommited = true; if(showScore) alert(\'' . clean_str_for_javascript(claro_html_entity_decode(get_lang('Score'))) . ' :\\n\' + rawScore + \'/\' + weighting ); } } </script> '; // Construct the HTML file and save it. $filename = "quiz_" . $quizId . ".html"; $pageContent = $pageHeader . $pageBody . $pageEnd; if (!($f = fopen($destDir . '/' . $filename, 'w'))) { $this->error = get_lang('Unable to create file : ') . $filename; return false; } fwrite($f, $pageContent); fclose($f); return true; }
/** * Parse and execute wiki2xhtml macros * * enabled macros are : * - """start_html""" : start of html block, the block begins on the next line * - """end_html""" : end of html block * - """home""" or """main""" : link to Main page * - default : the surrounded string is interpreted as embedded html * @access private * @see class.wiki2xhtml.php * @return string macro execution result */ protected function parseMacro($str, &$tag, &$attr, &$type) { $tag = ''; $attr = ''; $trimmedStr = trim($str, '"'); $matches = array(); if (preg_match('/^color([0-9])/', $trimmedStr, $matches)) { $colorCodeList = array(0 => '#DD0000', 1 => '#006600', 2 => '#0000DD', 3 => '#660099', 4 => '#008888', 5 => '#55AA22', 6 => '#888800', 7 => '#DE8822', 8 => '#804020', 9 => '#990022'); $colorCode = isset($colorCodeList[(int) $matches[1]]) ? $colorCodeList[(int) $matches[1]] : '#000000'; $trimmedStr = 'color'; } elseif (preg_match('/^color\\(([a-zA-Z]+|#[a-fA-F0-9]{3}|#[a-fA-F0-9]{6})\\)/', $trimmedStr, $matches)) { $colorCode = $matches[1]; $trimmedStr = 'color'; } switch ($trimmedStr) { // start of html block case 'start_html': $this->setOpt('inline_html_allowed', 1); $str = "<!-- start of embedded html -->\n"; break; // end of html block // end of html block case 'end_html': $this->setOpt('inline_html_allowed', 0); $str = "<!-- start of embedded html -->\n"; break; // link to main page // link to main page case 'home': case 'main': $str = "<a href=\"" . $_SERVER['PHP_SELF'] . "?action=show&title=" . rawurlencode('__MainPage__') . "&wikiId=" . $this->wiki->getWikiId() . "\" class=\"wikiShow\">" . get_lang('Main page') . "</a>"; break; // toc // toc case 'toc': $str = ''; $this->addAtEnd[] = '<script type="text/javascript" src="./js/toc.js"></script>'; $this->addAtEnd[] = '<script type="text/javascript">createTOC();</script>'; break; case 'color': $str = '<span style="color: ' . $colorCode . ';">'; break; case '/color': $str = '</span>'; break; // embedded html // embedded html default: // FIXME secure embedded html !!! // - remove dangerous tags and attributes // - protect against XSS $str = trim($str, '"'); $str = claro_html_entity_decode($str); $str = $this->san->sanitize($str); } return $str; }
/** * Parse the manifest file given in argument * @param string manifestPath, path to the manifest file * @return bool false on failure, array moduleInfo on success */ public function parse($manifestPath) { // reset state $this->elementPile = array(); $this->moduleInfo = array(); $this->backlog->info('Parsing manifest file ' . $manifestPath); if (!file_exists($manifestPath)) { $this->backlog->failure(get_lang('Manifest missing : %filename', array('%filename' => $manifestPath))); return false; } $xmlParser = xml_parser_create(); xml_set_element_handler($xmlParser, array(&$this, 'startElement'), array(&$this, 'endElement')); xml_set_character_data_handler($xmlParser, array(&$this, 'elementData')); // read manifest file if (false === ($data = @file_get_contents($manifestPath))) { $this->backlog->failure(get_lang('Cannot open manifest file')); return false; } else { $this->backlog->debug('Manifest open : ' . $manifestPath); $data = claro_html_entity_decode(urldecode($data)); } if (!xml_parse($xmlParser, $data)) { // if reading of the xml file in not successfull : // set errorFound, set error msg, break while statement $this->backlog->failure(get_lang('Error while parsing manifest')); return false; } // liberate parser ressources xml_parser_free($xmlParser); // complete module info for missing optional elements if (!array_key_exists('ENTRY', $this->moduleInfo)) { $this->moduleInfo['ENTRY'] = 'entry.php'; } // Module License if (!array_key_exists('LICENSE', $this->moduleInfo)) { $this->moduleInfo['LICENSE'] = ''; } // Module version if (!array_key_exists('VERSION', $this->moduleInfo)) { $this->moduleInfo['VERSION'] = ''; } // Module description if (!array_key_exists('DESCRIPTION', $this->moduleInfo)) { $this->moduleInfo['DESCRIPTION'] = ''; } // Author informations if (!array_key_exists('AUTHOR', $this->moduleInfo)) { $this->moduleInfo['AUTHOR'] = array(); } // Author name if (!array_key_exists('NAME', $this->moduleInfo['AUTHOR'])) { $this->moduleInfo['AUTHOR']['NAME'] = ''; } // Author email if (!array_key_exists('EMAIL', $this->moduleInfo['AUTHOR'])) { $this->moduleInfo['AUTHOR']['EMAIL'] = ''; } // Author website if (!array_key_exists('WEB', $this->moduleInfo['AUTHOR'])) { $this->moduleInfo['AUTHOR']['WEB'] = ''; } // Module website if (!array_key_exists('WEB', $this->moduleInfo)) { $this->moduleInfo['WEB'] = ''; } // Set default module context if (!array_key_exists('CONTEXTS', $this->moduleInfo) || empty($this->moduleInfo['CONTEXTS'])) { if (strtoupper($this->moduleInfo['TYPE']) == 'TOOL') { $this->moduleInfo['CONTEXTS'] = array('course'); } else { $this->moduleInfo['CONTEXTS'] = array('platform'); } } return $this->moduleInfo; }
$manifestData['scos'] = array(); // for path of start asset id of each new module to create $xml_parser = xml_parser_create(); xml_set_element_handler($xml_parser, "startElement", "endElement"); xml_set_character_data_handler($xml_parser, "elementData"); // this file has to exist in a SCORM conformant package // this file must be in the root the sent zip $file = "imsmanifest.xml"; if (file_exists($file)) { if (!isset($manifestPath)) { $manifestPath = ""; } array_push($okMsgs, get_lang('Manifest found in zip file : ') . $manifestPath . "imsmanifest.xml"); $fileContent = file_get_contents($manifestPath . $file); $charset = get_xml_charset($fileContent); $data = claro_html_entity_decode(urldecode($fileContent), ENT_COMPAT, $charset); if (!xml_parse($xml_parser, $data)) { // if reading of the xml file in not successfull : // set errorFound, set error msg, break while statement $errorFound = true; array_push($errorMsgs, get_lang('Error reading <i>manifest</i> file')); if (claro_debug_mode()) { $debugMessage = strtr('Debug : %message (error code %code) on line %line and column %column', array('%message' => xml_error_string(xml_get_error_code($xml_parser)), '%code' => xml_get_error_code($xml_parser), '%line' => xml_get_current_line_number($xml_parser), '%column' => xml_get_current_column_number($xml_parser))); array_push($errorMsgs, $debugMessage); } } } else { $errorFound = true; array_push($errorMsgs, get_lang('Cannot find <i>manifest</i> file in the package.<br /> File not found : imsmanifest.xml')); } // liberate parser ressources
/** * Evaluates the message and returns modifications for inline images and backgrounds * @access public * @return $message */ public function MsgHTML($message, $basedir = '') { preg_match_all("/(src|background)=\"(.*)\"/Ui", $message, $images); if (isset($images[2])) { foreach ($images[2] as $i => $url) { // do not change urls for absolute images (thanks to corvuscorax) if (!preg_match('#^[A-z]+://#', $url)) { $filename = basename($url); $directory = dirname($url); $directory == '.' ? $directory = '' : ''; $cid = 'cid:' . md5($filename); $ext = pathinfo($filename, PATHINFO_EXTENSION); $mimeType = self::_mime_types($ext); if (strlen($basedir) > 1 && substr($basedir, -1) != '/') { $basedir .= '/'; } if (strlen($directory) > 1 && substr($directory, -1) != '/') { $directory .= '/'; } if ($this->AddEmbeddedImage($basedir . $directory . $filename, md5($filename), $filename, 'base64', $mimeType)) { $message = preg_replace("/" . $images[1][$i] . "=\"" . preg_quote($url, '/') . "\"/Ui", $images[1][$i] . "=\"" . $cid . "\"", $message); } } } } $this->IsHTML(true); $this->Body = $message; $textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\\/\\1>/s', '', $message))); if (!empty($textMsg) && empty($this->AltBody)) { $this->AltBody = claro_html_entity_decode($textMsg); } if (empty($this->AltBody)) { $this->AltBody = 'To view this email message, open it in a program that understands HTML!' . "\n\n"; } }
/** * Exports an exercise as a SCO. * This method is intended to be called from the prepare method. * *@note There's a lot of nearly cut-and-paste from exercise.lib.php here * because of some little differences... * Perhaps something that could be refactorised ? * * @see prepare * @param $quizId The quiz * @param $raw_to_pass The needed score to attain * @return False on error, True if everything went well. * @author Amand Tihon <*****@*****.**> */ public function prepareQuiz($quizId, $raw_to_pass = 50) { global $claro_stylesheet; // those two variables are needed by display_attached_file() global $attachedFilePathWeb; global $attachedFilePathSys; $attachedFilePathWeb = 'Exercises'; $attachedFilePathSys = $this->destDir . '/Exercises'; // read the exercise $quiz = new Exercise(); if (!$quiz->load($quizId)) { $this->error[] = get_lang('Unable to load the exercise'); return false; } // Generate standard page header $pageHeader = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>' . $quiz->getTitle() . '</title> <meta http-equiv="expires" content="Tue, 05 DEC 2000 07:00:00 GMT"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Content-Type" content="text/HTML; charset=' . get_locale('charset') . '" /> <link rel="stylesheet" type="text/css" href="' . get_conf('claro_stylesheet') . '/main.css" media="screen, projection, tv" /> <script language="javascript" type="text/javascript" src="jquery.js"></script> <script language="javascript" type="text/javascript" src="claroline.js"></script> <script language="javascript" type="text/javascript" src="claroline.ui.js"></script> <script language="javascript" type="text/javascript" src="APIWrapper.js"></script> <script language="javascript" type="text/javascript" src="scores.js"></script> ' . "\n"; $pageBody = '<body onload="loadPage()"> <div id="claroBody"><form id="quiz"> <table width="100%" border="0" cellpadding="1" cellspacing="0" class="claroTable">' . "\n"; // Get the question list $questionList = $quiz->getQuestionList(); $questionCount = count($questionList); // Keep track of raw scores (ponderation) for each question $questionPonderationList = array(); // Keep track of correct texts for fill-in type questions // TODO La variable $fillAnswerList n'appara�t qu'une fois $fillAnswerList = array(); // Display each question $questionCount = 0; foreach ($questionList as $question) { // Update question number $questionCount++; // read the question, abort on error $scormQuestion = new ScormQuestion(); if (!$scormQuestion->load($question['id'])) { $this->error[] = get_lang('Unable to load exercise\'s question'); return false; } $questionPonderationList[] = $scormQuestion->getGrade(); $pageBody .= '<tr class="headerX">' . "\n" . '<th>' . get_lang('Question') . ' ' . $questionCount . '</th>' . "\n" . '</tr>' . "\n"; $pageBody .= '<tr>' . "\n" . '<td>' . "\n" . $scormQuestion->export() . "\n" . '</td>' . "\n" . '</tr>' . "\n"; /* if( !empty($scormQuestion->getAttachment()) ) { // copy the attached file if ( !claro_copy_file($this->srcDirExercise . '/' . $attachedFile, $this->destDir . '/Exercises') ) { $this->error[] = get_lang('Unable to copy file : %filename', array ( '%filename' => $attachedFile )); return false; } // Ok, if it was an mp3, we need to copy the flash mp3-player too. $extension=substr(strrchr($attachedFile, '.'), 1); if ( $extension == 'mp3') $this->mp3Found = true; $pageBody .= '<tr><td colspan="2">' . display_attached_file($attachedFile) . '</td></tr>' . "\n"; } */ /* * Display the possible answers */ // End of the question } // foreach($questionList as $questionId) // No more questions, add the button. $pageEnd = ' <tr> <td align="center"><br /><input type="button" value="' . get_lang('Ok') . '" onclick="calcScore()" /></td> </tr> </table> </form> </div></body></html>' . "\n"; /* Generate the javascript that'll calculate the score * We have the following variables to help us : * $idCounter : number of elements to check. their id are "scorm_XY" * $raw_to_pass : score (on 100) needed to pass the quiz * $fillAnswerList : a list of arrays (text, score) indexed on <input>'s names * */ $pageHeader .= ' <script type="text/javascript" language="javascript"> var raw_to_pass = '******'; var weighting = ' . array_sum($questionPonderationList) . '; var rawScore; var scoreCommited = false; var showScore = true; var fillAnswerList = new Array();' . "\n"; // This is the actual code present in every exported exercise. // use claro_html_entity_decode in output to prevent double encoding errors with some languages... $pageHeader .= ' function calcScore() { if( !scoreCommited ) { rawScore = CalculateRawScore(document, ' . getIdCounter() . ', fillAnswerList); var score = Math.max(Math.round(rawScore * 100 / weighting), 0); var oldScore = doLMSGetValue("cmi.core.score.raw"); doLMSSetValue("cmi.core.score.max", weighting); doLMSSetValue("cmi.core.score.min", 0); computeTime(); if (score > oldScore) // Update only if score is better than the previous time. { doLMSSetValue("cmi.core.score.raw", rawScore); } var mode = doLMSGetValue( "cmi.core.lesson_mode" ); if ( mode != "review" && mode != "browse" ) { var oldStatus = doLMSGetValue( "cmi.core.lesson_status" ) if (score >= raw_to_pass) { doLMSSetValue("cmi.core.lesson_status", "passed"); } else if (oldStatus != "passed" ) // If passed once, never mark it as failed. { doLMSSetValue("cmi.core.lesson_status", "failed"); } } doLMSCommit(); doLMSFinish(); scoreCommited = true; if(showScore) alert(\'' . clean_str_for_javascript(claro_html_entity_decode(get_lang('Score'))) . ' :\\n\' + rawScore + \'/\' + weighting ); } } </script> '; // Construct the HTML file and save it. $filename = "quiz_" . $quizId . ".html"; $pageContent = $pageHeader . $pageBody . $pageEnd; if (!($f = fopen($this->destDir . '/' . $filename, 'w'))) { $this->error[] = get_lang('Unable to create file : ') . $filename; return false; } fwrite($f, $pageContent); fclose($f); // Went well. return True; }