/** hack to Just Get A Question from current dmid, using Excercise class
	 * to do our factorying for us. 
	 * Obviously the factory code needs to be refactored to ElseWhere, but not on Sunday 
	 * :-P
	 * (Sun 15 Jun 2008)
	 */
	function getQuestion( $dmid, $questionLanguages, $answerLanguages ) {
		if ( !$questionLanguages )
			throw new Exception( "Vocview: no question (original) languages provided!" );

		if ( !$answerLanguages )
			throw new Exception( "Vocview: no answer (translation) languages provided!" );
		/* 3 men walked into a bar^wExercise
		 * fullset, fetcher, and subset
		 */

		/* our regular fetcher is provided by functions.php 
		 * I suppose if I were tidier, I could use fetchers for
		 * persistence
		 */
		$fetcher = new OWFetcher();

		/* fullset is a domdocument containing a <collection> of
		 * empty <defined-meanings/> (just their defined-meaning-id
		 * attribute is set)
		 * This format makes sense on some days, it's just
		 * massive nukular overkill today, specially since
		 * we only have 1 element :-P
		 * Still, if Exercise wants this as a dom, we can oblige.
		 */
		$xmlString = "
			<collection>
				<defined-meaning defined-meaning-id=\"$dmid\" />
			</collection>
		";
		$xml = simplexml_load_string( $xmlString );
		$fullset = dom_import_simplexml( $xml )->ownerDocument;
		# et voila. 

		/* subset is a selection of stuff we are actually
		 * interested in, from the above, as an array of 
		 * dmid's .... Oh look! We have just one!
		 */
		$subset = array( $dmid ); # :-P
		# (ok, to be honest, it does also get auto-generated
		# from the fullset, if we say nothing... but
		# then where would the joke be? )

		# and we already had the fetcher.
		# So the fullset said to the fetcher: let's do this! 

		$exercise = new Exercise( $fetcher, $fullset, $subset );
		$exercise->setQuestionLanguages( $questionLanguages );
		$exercise->setAnswerLanguages( $answerLanguages );
		
		# Ok, now let's see. which question did we need?
		# (and setting selfcheck to false)
		$question = $exercise->getQuestion( $dmid, false );
		# Oh REALLY! And we needed to go through all that?

		# well, let's return it, before people start asking
		# more difficult questions.

		return $question;
		
	}
Exemple #2
0
 /**
  * constructor of the class
  *
  * @author 	Olivier Brouckaert
  * @param int $questionId that answers belong to
  * @param int $course_id
  */
 public function __construct($questionId, $course_id = null)
 {
     $this->questionId = intval($questionId);
     $this->answer = array();
     $this->correct = array();
     $this->comment = array();
     $this->weighting = array();
     $this->position = array();
     $this->hotspot_coordinates = array();
     $this->hotspot_type = array();
     $this->destination = array();
     // clears $new_* arrays
     $this->cancel();
     if (!empty($course_id)) {
         $courseInfo = api_get_course_info_by_id($course_id);
     } else {
         $courseInfo = api_get_course_info();
     }
     $this->course = $courseInfo;
     $this->course_id = $courseInfo['real_id'];
     // fills arrays
     $objExercise = new Exercise($this->course_id);
     $exerciseId = isset($_REQUEST['exerciseId']) ? $_REQUEST['exerciseId'] : null;
     $objExercise->read($exerciseId);
     if ($objExercise->random_answers == '1') {
         $this->readOrderedBy('rand()', '');
         // randomize answers
     } else {
         $this->read();
         // natural order
     }
 }
Exemple #3
0
 public function exercise_get($id = null)
 {
     $user = new User($this->user_id);
     $exercise = new Exercise();
     $exercise->where('id', $id);
     $exercise->get();
     $logs = $exercise->exerciselog;
     $logs->get();
     $response = array();
     foreach ($logs as $log) {
         array_push($response, $log->getData());
     }
     $this->response($response);
 }
 protected function getContent()
 {
     $content = '<ol class="breadcrumb">
               <li><a href="' . ROOT_DIR . 'admin/courseadmin">' . I18n::t('courseoverview.title') . '</a></li>
               <li><a href="' . ROOT_DIR . 'admin/lessonadmin/' . $this->course->getId() . '">' . $this->course->getName(I18n::getLang()) . '</a></li>
               <li class="active">' . $this->lesson->getName(I18n::getLang()) . '</li>
             </ol>';
     $content .= '<form method="post"><input type="hidden" name="action" value="saveExercises" />
 <table id="exercise-admin-table" class="table table-hover">
 <thead>
 <tr>
 <th>' . I18n::t('admin.exerciseadmin.question') . '</th>
 <th>' . I18n::t('admin.exerciseadmin.answer') . ' (EN)</th>
 <th>' . I18n::t('admin.exerciseadmin.answer') . ' (DE)</th>
 <th>&nbsp;</th>
 </tr>
 </thead>
 <tbody>';
     foreach ((array) Exercise::getMultipleExercises($this->lesson->getId(), 50, 0) as $exercise) {
         $content .= '<tr><input type="hidden" name="exercise_id[]" value="' . $exercise->getId() . '" />
   <td><input type="text" name="question[]" value="' . $exercise->getQuestion() . '" /></td>
   <td><input type="text" name="answer_en[]" value="' . $exercise->getAnswer('en') . '" /></td>
   <td><input type="text" name="answer_de[]" value="' . $exercise->getAnswer('de') . '" /></td>
   </tr>';
     }
     $content .= '</tbody>
 </table>
 <table width="100%">
 <tr><td width="50%" align="left"><button id="exercise-add-btn" class="btn btn-default" type="button">' . I18n::t('button.add') . '</button></td>
 <td width="50%" align="right"><input type="submit" class="btn btn-default" value="' . I18n::t('button.save') . '" /></td></tr>
 </table>
 </form>';
     return $content;
 }
 public function checkCode()
 {
     Helpers::normalizeCode($this->code);
     if (!($this->exercise = Exercise::model()->findByAttributes(array('code' => trim($this->code))))) {
         $this->addError('code', Yii::t('swu', 'The code you entered does not exist.'));
     }
 }
function main() {
	$collection_id = 376317; # olpc dictionary.... WAY too big

	$fetcher = new OWFetcher();
	echo "fullset...\n";
	$fullSetXML = $fetcher->getFullSetXML_asString( $collection_id );

	$fullSet = new DOMDocument();
	$success = $fullSet->loadXML( $fullSetXML );
	if ( !$success ) {
		throw new Exception( "Failed to load category XML from server" );
	}

	$maxSubSet = dom2set( $fullSet );
	# sort($maxSubSet); foreach ($maxSubSet as $dmid) {print "$dmid,";}


	# var_dump($fullSet->saveXML());
	$exercise = new Exercise( $fetcher, $fullSet, $maxSubSet ); # pwease, not the max!
	# $exercise->setLanguages(array("eng","fra","deu"));
	$exercise->setQuestionLanguages( array( "deu" ) );
	$exercise->setAnswerLanguages( array( "eng" ) );

	# $question_dmid=$maxSubSet[array_rand($maxSubSet)];
	echo "question...\n";
	# $questionNode=$exercise->getQuestionNode($question_dmid);

	# dumpNode($questionNode);
	$runex = $exercise->randSubExercise( 10 );
	dumpExercise( $runex, 5 );

	echo "\n\n=== presistence test ===\n\n";
	saveExercise( $runex );
	$exid = mysql_insert_id();
	$loadex = loadExercise( $exid );
	$loadex->setFetcher( $fetcher );
	dumpExercise( $loadex, 10 );

}
Exemple #7
0
 public function sendCodes($controller)
 {
     if (!($student = Student::model()->findByAttributes(array('email' => $this->email)))) {
         return false;
     }
     $exercises = Exercise::model()->with('assignment')->sortByDuedate()->findAllByAttributes(array('student_id' => $student->id));
     foreach ($exercises as $exercise) {
         $exercise->link = Yii::app()->controller->createAbsoluteSslUrl('exercise/info', array('k' => $exercise->generateAckKey()));
     }
     $options = array();
     if (Helpers::getYiiParam('addOriginatingIP')) {
         $options['originating_IP'] = sprintf('[%s]', Yii::app()->request->userHostAddress);
     }
     return MailTemplate::model()->mailFromTemplate('send_codes', array($student->email => $student->name), array('student' => $student, 'exercises' => $exercises), $options);
 }
Exemple #8
0
 public function checkCode()
 {
     if ($this->getError('verifyCode')) {
         return;
         // we don't provide any information about the code if the captcha is not valid
     }
     Helpers::normalizeCode($this->code);
     if ($this->exercise = Exercise::model()->findByAttributes(array('code' => trim($this->code)))) {
         if (!$this->byteacher and $this->exercise->duedate < date('Y-m-d H:m:s', time() - $this->exercise->assignment->grace * 24 * 60 * 60)) {
             $this->addError('code', Yii::t('swu', 'The code provided is not valid anymore (time expired on %date%).', array('%date%' => $this->exercise->duedate)));
             return;
         }
     } elseif ($this->code) {
         $this->addError('code', Yii::t('swu', 'The code provided is not valid.'));
         return;
     }
 }
Exemple #9
0
 public function get($functionName, $linkName, $params = array(), $checkSession = true)
 {
     $positive = function ($input) {
         //$input = $input[count($input)-1];
         $result = Model::isEmpty();
         $result['content'] = array();
         foreach ($input as $inp) {
             if ($inp->getNumRows() > 0) {
                 // extract exercise data from db answer
                 $res = Exercise::ExtractExercise($inp->getResponse(), false);
                 $result['content'] = array_merge($result['content'], is_array($res) ? $res : array($res));
                 $result['status'] = 200;
             }
         }
         return $result;
     };
     $params = DBJson::mysql_real_escape_string($params);
     return $this->_component->call($linkName, $params, '', 200, $positive, array(), 'Model::isProblem', array(), 'Query');
 }
 public function saveExercises()
 {
     $successful = true;
     $updateAmount = isset($_POST['exercise_id']) && !empty($_POST['exercise_id']) ? count($_POST['exercise_id']) : 0;
     $i = 0;
     // update exercises that were present in DB already
     while ($i < $updateAmount) {
         $id = $this->secureString($_POST['exercise_id'][$i]);
         $question = $this->secureString($_POST['question'][$i]);
         $answerEN = $this->secureString($_POST['answer_en'][$i]);
         $answerDE = $this->secureString($_POST['answer_de'][$i]);
         // do not update exercises with empty fields
         if (empty($id) || empty($question) || empty($answerEN) || empty($answerDE)) {
             $i++;
             continue;
         }
         if (!Exercise::update($id, $question, $answerEN, $answerDE)) {
             $successful = false;
         }
         $i++;
     }
     // add new exercises to DB
     while ($i < count($_POST['question'])) {
         $question = $this->secureString($_POST['question'][$i]);
         $answerEN = $this->secureString($_POST['answer_en'][$i]);
         $answerDE = $this->secureString($_POST['answer_de'][$i]);
         // do not add exercises with empty fields
         if (empty($question) || empty($answerEN) || empty($answerDE)) {
             $i++;
             continue;
         }
         if (!Exercise::createExercise($this->lesson->getId(), $question, $answerEN, $answerDE)) {
             $successful = false;
         }
         $i++;
     }
     if ($successful) {
         $this->getView()->addSuccessMessage('Exercises were successfully saved!');
     } else {
         $this->getView()->addErrorMessage('There was a problem saving one or more exercises..');
     }
     $this->defaultAction();
 }
function loadExercise( $exercise_id ) {
	if ( !is_int( $exercise_id ) )
		throw new Exception( "persist; loadExercise exercise_id is not an integer" );


	global $mysql_info;
	DBTools::connect( $mysql_info );
	$exercise_id = mysql_real_escape_string( $exercise_id );
	$row = DBTools::doQuery( "select * from exercises where id=\"$exercise_id\"" );
	$exercise = new Exercise();
	$exercise->setId( $exercise_id );
	$exercise->loadXML( $row["exercise"] );
	$exercise->setQuestionLanguages( explode( ",", $row["questionLanguages"] ) );
	$exercise->setAnswerLanguages( explode( ",", $row["answerLanguages"] ) );
	return $exercise;
}
 public function evaluate()
 {
     if (isset($_POST['answer']) && !empty($_POST['answer'])) {
         $input = $this->secureString($_POST['answer']);
         $correct = $_SESSION['currentExercise']->getAnswer(I18n::getLang());
         // trim whitespaces, remove not relevant characters in order to be more flexible with user input
         $removedChars = '/(\\W+)|[0-9]|_/';
         $input = trim($input);
         $input = preg_replace($removedChars, '', $input);
         $correct = trim($correct);
         $correct = preg_replace($removedChars, '', $correct);
         if (strtolower($input) === strtolower($correct)) {
             $updated = Exercise::addCorrectAnswer($_SESSION['user']->getEmail(), $_SESSION['currentExercise']->getId());
             if (!$updated) {
                 $this->getView()->addErrorMessage('Could not update DB.');
             }
             $this->getView()->addSuccessMessage(I18n::t('exercise.correct'));
         } else {
             $this->getView()->addErrorMessage(I18n::t('exercise.wrong'));
         }
     }
     $this->defaultAction();
 }
// general parameters passed via POST/GET
if (empty($origin)) {
    $origin = Security::remove_XSS($_REQUEST['origin']);
}
/** @var Exercise $objExercise */
if (empty($objExercise)) {
    $objExercise = Session::read('objExercise');
}
if (empty($remind_list)) {
    $remind_list = isset($_REQUEST['remind_list']) ? $_REQUEST['remind_list'] : null;
}
$exe_id = isset($_REQUEST['exe_id']) ? intval($_REQUEST['exe_id']) : 0;
if (empty($objExercise)) {
    // Redirect to the exercise overview
    // Check if the exe_id exists
    $objExercise = new Exercise();
    $exercise_stat_info = $objExercise->get_stat_track_exercise_info_by_exe_id($exe_id);
    if (!empty($exercise_stat_info) && isset($exercise_stat_info['exe_exo_id'])) {
        header("Location: overview.php?exerciseId=" . $exercise_stat_info['exe_exo_id']);
        exit;
    }
    api_not_allowed();
}
if (api_is_in_gradebook()) {
    $interbreadcrumb[] = array('url' => api_get_path(WEB_CODE_PATH) . 'gradebook/index.php?' . api_get_cidreq(), 'name' => get_lang('ToolGradebook'));
}
$nameTools = get_lang('Exercises');
$interbreadcrumb[] = array("url" => "exercise.php?" . api_get_cidreq(), "name" => get_lang('Exercises'));
$htmlHeadXtra[] = '<script src="' . api_get_path(WEB_LIBRARY_JS_PATH) . 'hotspot/js/hotspot.js"></script>';
$htmlHeadXtra[] = '<link rel="stylesheet" href="' . api_get_path(WEB_LIBRARY_JS_PATH) . 'hotspot/css/hotspot.css">';
if ($origin != 'learnpath') {
Exemple #14
0
}
if (isset($_REQUEST['quId']) && is_numeric($_REQUEST['quId'])) {
    $quId = (int) $_REQUEST['quId'];
} else {
    $quId = null;
}
if (isset($_REQUEST['filter'])) {
    $filter = $_REQUEST['filter'];
} else {
    $filter = 'all';
}
$categoryId = substr($filter, 0, 10) == 'categoryId' && is_numeric(substr($filter, 10)) ? substr($filter, 10) : null;
/*
 * Init other vars
 */
$exercise = new Exercise();
if (!is_null($exId)) {
    $exercise->load($exId);
}
$dialogBox = new DialogBox();
/*
 * Execute commands
 */
// use question in exercise
if ($cmd == 'rqUse' && !is_null($quId) && !is_null($exId)) {
    if ($exercise->addQuestion($quId)) {
        // TODO show confirmation and back link
        header('Location: ' . Url::Contextualize('edit_exercise.php?exId=' . $exId));
    }
}
// delete question
<?php

/* See license terms in /license.txt */
//require_once '../inc/global.inc.php';
$this_section = SECTION_COURSES;
$exercise_id = isset($_GET['exerciseId']) && !empty($_GET['exerciseId']) ? intval($_GET['exerciseId']) : 0;
// Access control
api_protect_course_script(true);
if (!api_is_allowed_to_edit()) {
    api_not_allowed();
}
$objExercise = new Exercise();
$result = $objExercise->read($exercise_id);
if (!$result) {
    api_not_allowed(true);
}
$interbreadcrumb[] = array("url" => "exercise.php?" . api_get_cidreq(), "name" => get_lang('Exercises'));
$interbreadcrumb[] = array("url" => "admin.php?exerciseId={$exercise_id}&" . api_get_cidreq(), "name" => $objExercise->name);
//Add the JS needed to use the jqgrid
$htmlHeadXtra[] = api_get_jqgrid_js();
// The header.
Display::display_header(get_lang('StudentsWhoAreTakingTheExerciseRightNow'));
//jqgrid will use this URL to do the selects
$minutes = 60;
$url = api_get_path(WEB_AJAX_PATH) . 'exercise.ajax.php?a=get_live_stats&exercise_id=' . $objExercise->id . '&minutes=' . $minutes;
//The order is important you need to check the the $column variable in the model.ajax.php file
$columns = array(get_lang('FirstName'), get_lang('LastName'), get_lang('Time'), get_lang('QuestionsAlreadyAnswered'), get_lang('Score'));
//Column config
$column_model = array(array('name' => 'firstname', 'index' => 'firstname', 'width' => '100', 'align' => 'left'), array('name' => 'lastname', 'index' => 'lastname', 'width' => '100', 'align' => 'left'), array('name' => 'start_date', 'index' => 'start_date', 'width' => '100', 'align' => 'left'), array('name' => 'question', 'index' => 'count_questions', 'width' => '60', 'align' => 'left', 'sortable' => 'false'), array('name' => 'score', 'index' => 'score', 'width' => '50', 'align' => 'left', 'sortable' => 'false'));
//Autowidth
$extra_params['autowidth'] = 'true';
Exemple #16
0
    /**
     * Exports the learning path as a SCORM package. This is the main function that
     * gathers the content, transforms it, writes the imsmanifest.xml file, zips the
     * whole thing and returns the zip.
     *
     * This method needs to be called in PHP5, as it will fail with non-adequate
     * XML package (like the ones for PHP4), and it is *not* a static method, so
     * you need to call it on a learnpath object.
     * @TODO The method might be redefined later on in the scorm class itself to avoid
     * creating a SCORM structure if there is one already. However, if the initial SCORM
     * path has been modified, it should use the generic method here below.
     * @TODO link this function with the export_lp() function in the same class
     * @param	string	Optional name of zip file. If none, title of learnpath is
     * 					domesticated and trailed with ".zip"
     * @return	string	Returns the zip package string, or null if error
     */
    function scorm_export()
    {
        global $_course;
        global $charset;
        if (!class_exists('DomDocument')) {
            error_log('DOM functions not supported for PHP version below 5.0', 0);
            $this->error = 'PHP DOM functions not supported for PHP versions below 5.0';
            return null;
        }
        //remove memory and time limits as much as possible as this might be a long process...
        if (function_exists('ini_set')) {
            $mem = ini_get('memory_limit');
            if (substr($mem, -1, 1) == 'M') {
                $mem_num = substr($mem, 0, -1);
                if ($mem_num < 128) {
                    ini_set('memory_limit', '128M');
                }
            } else {
                ini_set('memory_limit', '128M');
            }
            ini_set('max_execution_time', 600);
            //}else{
            //error_log('Scorm export: could not change memory and time limits',0);
        }
        //Create the zip handler (this will remain available throughout the method)
        $archive_path = api_get_path(SYS_ARCHIVE_PATH);
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
        $temp_dir_short = uniqid();
        $temp_zip_dir = $archive_path . "/" . $temp_dir_short;
        $temp_zip_file = $temp_zip_dir . "/" . md5(time()) . ".zip";
        $zip_folder = new PclZip($temp_zip_file);
        $current_course_path = api_get_path(SYS_COURSE_PATH) . api_get_course_path();
        $root_path = $main_path = api_get_path(SYS_PATH);
        $files_cleanup = array();
        //place to temporarily stash the zipfiles
        //create the temp dir if it doesn't exist
        //or do a cleanup befor creating the zipfile
        if (!is_dir($temp_zip_dir)) {
            mkdir($temp_zip_dir);
        } else {
            //cleanup: check the temp dir for old files and delete them
            $handle = opendir($temp_zip_dir);
            while (false !== ($file = readdir($handle))) {
                if ($file != "." && $file != "..") {
                    unlink("{$temp_zip_dir}/{$file}");
                }
            }
            closedir($handle);
        }
        $zip_files = $zip_files_abs = $zip_files_dist = array();
        if (is_dir($current_course_path . '/scorm/' . $this->path) && is_file($current_course_path . '/scorm/' . $this->path . '/imsmanifest.xml')) {
            // remove the possible . at the end of the path
            $dest_path_to_lp = substr($this->path, -1) == '.' ? substr($this->path, 0, -1) : $this->path;
            $dest_path_to_scorm_folder = str_replace('//', '/', $temp_zip_dir . '/scorm/' . $dest_path_to_lp);
            $perm = api_get_setting('permissions_for_new_directories');
            $perm = octdec(!empty($perm) ? $perm : '0770');
            mkdir($dest_path_to_scorm_folder, $perm, true);
            $zip_files_dist = copyr($current_course_path . '/scorm/' . $this->path, $dest_path_to_scorm_folder, array('imsmanifest'), $zip_files);
        }
        //Build a dummy imsmanifest structure. Do not add to the zip yet (we still need it)
        //This structure is developed following regulations for SCORM 1.2 packaging in the SCORM 1.2 Content
        //Aggregation Model official document, secion "2.3 Content Packaging"
        $xmldoc = new DOMDocument('1.0', $this->encoding);
        $root = $xmldoc->createElement('manifest');
        $root->setAttribute('identifier', 'SingleCourseManifest');
        $root->setAttribute('version', '1.1');
        $root->setAttribute('xmlns', 'http://www.imsproject.org/xsd/imscp_rootv1p1p2');
        $root->setAttribute('xmlns:adlcp', 'http://www.adlnet.org/xsd/adlcp_rootv1p2');
        $root->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
        $root->setAttribute('xsi:schemaLocation', 'http://www.imsproject.org/xsd/imscp_rootv1p1p2 imscp_rootv1p1p2.xsd http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 imsmd_rootv1p2p1.xsd http://www.adlnet.org/xsd/adlcp_rootv1p2 adlcp_rootv1p2.xsd');
        //Build mandatory sub-root container elements
        $metadata = $xmldoc->createElement('metadata');
        $md_schema = $xmldoc->createElement('schema', 'ADL SCORM');
        $metadata->appendChild($md_schema);
        $md_schemaversion = $xmldoc->createElement('schemaversion', '1.2');
        $metadata->appendChild($md_schemaversion);
        $root->appendChild($metadata);
        $organizations = $xmldoc->createElement('organizations');
        $resources = $xmldoc->createElement('resources');
        //Build the only organization we will use in building our learnpaths
        $organizations->setAttribute('default', 'dokeos_scorm_export');
        $organization = $xmldoc->createElement('organization');
        $organization->setAttribute('identifier', 'dokeos_scorm_export');
        //to set the title of the SCORM entity (=organization), we take the name given
        //in Dokeos and convert it to HTML entities using the Dokeos charset (not the
        //learning path charset) as it is the encoding that defines how it is stored
        //in the database. Then we convert it to HTML entities again as the "&" character
        //alone is not authorized in XML (must be &amp;)
        //The title is then decoded twice when extracting (see scorm::parse_manifest)
        $org_title = $xmldoc->createElement('title', htmlentities(api_htmlentities($this->get_name(), ENT_QUOTES, $charset)));
        $organization->appendChild($org_title);
        //For each element, add it to the imsmanifest structure, then add it to the zip.
        //Always call the learnpathItem->scorm_export() method to change it to the SCORM
        //format
        $link_updates = array();
        foreach ($this->items as $index => $item) {
            if (!in_array($item->type, array(TOOL_QUIZ, TOOL_FORUM, TOOL_THREAD, TOOL_LINK, TOOL_STUDENTPUBLICATION))) {
                //get included documents from this item
                if ($item->type == 'sco') {
                    $inc_docs = $item->get_resources_from_source(null, api_get_path(SYS_COURSE_PATH) . api_get_course_path() . '/' . 'scorm/' . $this->path . '/' . $item->get_path());
                } else {
                    $inc_docs = $item->get_resources_from_source();
                }
                //give a child element <item> to the <organization> element
                $my_item_id = $item->get_id();
                $my_item = $xmldoc->createElement('item');
                $my_item->setAttribute('identifier', 'ITEM_' . $my_item_id);
                $my_item->setAttribute('identifierref', 'RESOURCE_' . $my_item_id);
                $my_item->setAttribute('isvisible', 'true');
                //give a child element <title> to the <item> element
                $my_title = $xmldoc->createElement('title', htmlspecialchars($item->get_title(), ENT_QUOTES, $this->encoding));
                $my_item->appendChild($my_title);
                //give a child element <adlcp:prerequisites> to the <item> element
                $my_prereqs = $xmldoc->createElement('adlcp:prerequisites', $this->get_scorm_prereq_string($my_item_id));
                $my_prereqs->setAttribute('type', 'aicc_script');
                $my_item->appendChild($my_prereqs);
                //give a child element <adlcp:maxtimeallowed> to the <item> element - not yet supported
                //$xmldoc->createElement('adlcp:maxtimeallowed','');
                //give a child element <adlcp:timelimitaction> to the <item> element - not yet supported
                //$xmldoc->createElement('adlcp:timelimitaction','');
                //give a child element <adlcp:datafromlms> to the <item> element - not yet supported
                //$xmldoc->createElement('adlcp:datafromlms','');
                //give a child element <adlcp:masteryscore> to the <item> element
                $my_masteryscore = $xmldoc->createElement('adlcp:masteryscore', $item->get_mastery_score());
                $my_item->appendChild($my_masteryscore);
                //attach this item to the organization element or hits parent if there is one
                if (!empty($item->parent) && $item->parent != 0) {
                    $children = $organization->childNodes;
                    $possible_parent =& $this->get_scorm_xml_node($children, 'ITEM_' . $item->parent);
                    if (is_object($possible_parent)) {
                        $possible_parent->appendChild($my_item);
                    } else {
                        if ($this->debug > 0) {
                            error_log('Parent ITEM_' . $item->parent . ' of item ITEM_' . $my_item_id . ' not found');
                        }
                    }
                } else {
                    if ($this->debug > 0) {
                        error_log('No parent');
                    }
                    $organization->appendChild($my_item);
                }
                //get the path of the file(s) from the course directory root
                $my_file_path = $item->get_file_path('scorm/' . $this->path . '/');
                $my_xml_file_path = api_htmlentities($my_file_path, ENT_QUOTES, $this->encoding);
                $my_sub_dir = dirname($my_file_path);
                $my_xml_sub_dir = api_htmlentities($my_sub_dir, ENT_QUOTES, $this->encoding);
                //give a <resource> child to the <resources> element
                $my_resource = $xmldoc->createElement('resource');
                $my_resource->setAttribute('identifier', 'RESOURCE_' . $item->get_id());
                $my_resource->setAttribute('type', 'webcontent');
                $my_resource->setAttribute('href', $my_xml_file_path);
                //adlcp:scormtype can be either 'sco' or 'asset'
                if ($item->type == 'sco') {
                    $my_resource->setAttribute('adlcp:scormtype', 'sco');
                } else {
                    $my_resource->setAttribute('adlcp:scormtype', 'asset');
                }
                //xml:base is the base directory to find the files declared in this resource
                $my_resource->setAttribute('xml:base', '');
                //give a <file> child to the <resource> element
                $my_file = $xmldoc->createElement('file');
                $my_file->setAttribute('href', $my_xml_file_path);
                $my_resource->appendChild($my_file);
                //dependency to other files - not yet supported
                $i = 1;
                foreach ($inc_docs as $doc_info) {
                    if (count($doc_info) < 1 or empty($doc_info[0])) {
                        continue;
                    }
                    $my_dep = $xmldoc->createElement('resource');
                    $res_id = 'RESOURCE_' . $item->get_id() . '_' . $i;
                    $my_dep->setAttribute('identifier', $res_id);
                    $my_dep->setAttribute('type', 'webcontent');
                    $my_dep->setAttribute('adlcp:scormtype', 'asset');
                    $my_dep_file = $xmldoc->createElement('file');
                    //check type of URL
                    //error_log(__LINE__.'Now dealing with '.$doc_info[0].' of type '.$doc_info[1].'-'.$doc_info[2],0);
                    if ($doc_info[1] == 'remote') {
                        //remote file. Save url as is
                        $my_dep_file->setAttribute('href', $doc_info[0]);
                        $my_dep->setAttribute('xml:base', '');
                    } elseif ($doc_info[1] == 'local') {
                        switch ($doc_info[2]) {
                            case 'url':
                                //local URL - save path as url for now, don't zip file
                                $abs_path = api_get_path(SYS_PATH) . str_replace(api_get_path(WEB_PATH), '', $doc_info[0]);
                                $current_dir = dirname($abs_path);
                                $file_path = realpath($abs_path);
                                $my_dep_file->setAttribute('href', $file_path);
                                $my_dep->setAttribute('xml:base', '');
                                if (strstr($file_path, $main_path) !== false) {
                                    //the calculated real path is really inside the dokeos root path
                                    //reduce file path to what's under the DocumentRoot
                                    $file_path = substr($file_path, strlen($root_path) - 1);
                                    //echo $file_path;echo '<br><br>';
                                    //error_log(__LINE__.'Reduced url path: '.$file_path,0);
                                    $zip_files_abs[] = $file_path;
                                    $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path);
                                    $my_dep_file->setAttribute('href', $file_path);
                                    $my_dep->setAttribute('xml:base', '');
                                } else {
                                    if (empty($file_path)) {
                                        /* $document_root = substr(api_get_path(SYS_PATH), 0, strpos(api_get_path(SYS_PATH),api_get_path(REL_PATH)));
                                           if(strpos($document_root,-1)=='/')
                                           {
                                           $document_root = substr(0, -1, $document_root);
                                           } */
                                        $file_path = $_SERVER['DOCUMENT_ROOT'] . $abs_path;
                                        $file_path = str_replace('//', '/', $file_path);
                                        if (file_exists($file_path)) {
                                            $file_path = substr($file_path, strlen($current_dir));
                                            // we get the relative path
                                            $zip_files[] = $my_sub_dir . '/' . $file_path;
                                            $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path);
                                            $my_dep_file->setAttribute('href', $file_path);
                                            $my_dep->setAttribute('xml:base', '');
                                        }
                                    }
                                }
                                break;
                            case 'abs':
                                //absolute path from DocumentRoot. Save file and leave path as is in the zip
                                $my_dep_file->setAttribute('href', $doc_info[0]);
                                $my_dep->setAttribute('xml:base', '');
                                //$current_dir = dirname($current_course_path.'/'.$item->get_file_path()).'/';
                                //the next lines fix a bug when using the "subdir" mode of Dokeos, whereas
                                //an image path would be constructed as /var/www/subdir/subdir/img/foo.bar
                                $abs_img_path_without_subdir = $doc_info[0];
                                $relp = api_get_path(REL_PATH);
                                //the url-append config param
                                $pos = strpos($abs_img_path_without_subdir, $relp);
                                if ($pos === 0) {
                                    $abs_img_path_without_subdir = '/' . substr($abs_img_path_without_subdir, strlen($relp));
                                }
                                //$file_path = realpath(api_get_path(SYS_PATH).$doc_info[0]);
                                $file_path = realpath(api_get_path(SYS_PATH) . $abs_img_path_without_subdir);
                                $file_path = str_replace('\\', '/', $file_path);
                                $file_path = str_replace('//', '/', $file_path);
                                //error_log(__LINE__.'Abs path: '.$file_path,0);
                                //prepare the current directory path (until just under 'document') with a trailing slash
                                $cur_path = substr($current_course_path, -1) == '/' ? $current_course_path : $current_course_path . '/';
                                //check if the current document is in that path
                                if (strstr($file_path, $cur_path) !== false) {
                                    //the document is in that path, now get the relative path
                                    //to the containing document
                                    $orig_file_path = dirname($cur_path . $my_file_path) . '/';
                                    $relative_path = '';
                                    if (strstr($file_path, $cur_path) !== false) {
                                        $relative_path = substr($file_path, strlen($orig_file_path));
                                        $file_path = substr($file_path, strlen($cur_path));
                                    } else {
                                        //this case is still a problem as it's difficult to calculate a relative path easily
                                        //might still generate wrong links
                                        //$file_path = substr($file_path,strlen($cur_path));
                                        //calculate the directory path to the current file (without trailing slash)
                                        $my_relative_path = dirname($file_path);
                                        $my_relative_file = basename($file_path);
                                        //calculate the directory path to the containing file (without trailing slash)
                                        $my_orig_file_path = substr($orig_file_path, 0, -1);
                                        $dotdot = '';
                                        $subdir = '';
                                        while (strstr($my_relative_path, $my_orig_file_path) === false && strlen($my_orig_file_path) > 1 && strlen($my_relative_path) > 1) {
                                            $my_relative_path2 = dirname($my_relative_path);
                                            $my_orig_file_path = dirname($my_orig_file_path);
                                            $subdir = substr($my_relative_path, strlen($my_relative_path2) + 1) . "/" . $subdir;
                                            $dotdot += '../';
                                            $my_relative_path = $my_relative_path2;
                                        }
                                        $relative_path = $dotdot . $subdir . $my_relative_file;
                                    }
                                    //put the current document in the zip (this array is the array
                                    //that will manage documents already in the course folder - relative)
                                    $zip_files[] = $file_path;
                                    //update the links to the current document in the containing document (make them relative)
                                    $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $relative_path);
                                    $my_dep_file->setAttribute('href', $file_path);
                                    $my_dep->setAttribute('xml:base', '');
                                } elseif (strstr($file_path, $main_path) !== false) {
                                    //the calculated real path is really inside the dokeos root path
                                    //reduce file path to what's under the DocumentRoot
                                    $file_path = substr($file_path, strlen($root_path));
                                    //echo $file_path;echo '<br><br>';
                                    //error_log('Reduced path: '.$file_path,0);
                                    $zip_files_abs[] = $file_path;
                                    $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path);
                                    $my_dep_file->setAttribute('href', 'document/' . $file_path);
                                    $my_dep->setAttribute('xml:base', '');
                                } else {
                                    if (empty($file_path)) {
                                        /* $document_root = substr(api_get_path(SYS_PATH), 0, strpos(api_get_path(SYS_PATH),api_get_path(REL_PATH)));
                                           if(strpos($document_root,-1)=='/')
                                           {
                                           $document_root = substr(0, -1, $document_root);
                                           } */
                                        $file_path = $_SERVER['DOCUMENT_ROOT'] . $doc_info[0];
                                        $file_path = str_replace('//', '/', $file_path);
                                        if (file_exists($file_path)) {
                                            $file_path = substr($file_path, strlen($current_dir));
                                            // we get the relative path
                                            $zip_files[] = $my_sub_dir . '/' . $file_path;
                                            $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path);
                                            $my_dep_file->setAttribute('href', 'document/' . $file_path);
                                            $my_dep->setAttribute('xml:base', '');
                                        }
                                    }
                                }
                                break;
                            case 'rel':
                                //path relative to the current document. Save xml:base as current document's directory and save file in zip as subdir.file_path
                                if (substr($doc_info[0], 0, 2) == '..') {
                                    //relative path going up
                                    $current_dir = dirname($current_course_path . '/' . $item->get_file_path()) . '/';
                                    $file_path = realpath($current_dir . $doc_info[0]);
                                    //error_log($file_path.' <-> '.$main_path,0);
                                    if (strstr($file_path, $main_path) !== false) {
                                        //the calculated real path is really inside the dokeos root path
                                        //reduce file path to what's under the DocumentRoot
                                        $file_path = substr($file_path, strlen($root_path));
                                        //error_log('Reduced path: '.$file_path,0);
                                        $zip_files_abs[] = $file_path;
                                        $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path);
                                        $my_dep_file->setAttribute('href', 'document/' . $file_path);
                                        $my_dep->setAttribute('xml:base', '');
                                    }
                                } else {
                                    $zip_files[] = $my_sub_dir . '/' . $doc_info[0];
                                    $my_dep_file->setAttribute('href', $doc_info[0]);
                                    $my_dep->setAttribute('xml:base', $my_xml_sub_dir);
                                }
                                break;
                            default:
                                $my_dep_file->setAttribute('href', $doc_info[0]);
                                $my_dep->setAttribute('xml:base', '');
                                break;
                        }
                    }
                    $my_dep->appendChild($my_dep_file);
                    $resources->appendChild($my_dep);
                    $dependency = $xmldoc->createElement('dependency');
                    $dependency->setAttribute('identifierref', $res_id);
                    $my_resource->appendChild($dependency);
                    $i++;
                }
                //$my_dependency = $xmldoc->createElement('dependency');
                //$my_dependency->setAttribute('identifierref','');
                $resources->appendChild($my_resource);
                $zip_files[] = $my_file_path;
                //error_log('File '.$my_file_path. ' added to $zip_files',0);
            } else {
                // if the item is a quiz or a link or whatever non-exportable, we include a step indicating it
                if ($item->type == TOOL_LINK) {
                    $my_item = $xmldoc->createElement('item');
                    $my_item->setAttribute('identifier', 'ITEM_' . $item->get_id());
                    $my_item->setAttribute('identifierref', 'RESOURCE_' . $item->get_id());
                    $my_item->setAttribute('isvisible', 'true');
                    //give a child element <title> to the <item> element
                    $my_title = $xmldoc->createElement('title', htmlspecialchars($item->get_title(), ENT_QUOTES));
                    $my_item->appendChild($my_title);
                    //give a child element <adlcp:prerequisites> to the <item> element
                    $my_prereqs = $xmldoc->createElement('adlcp:prerequisites', $item->get_prereq_string());
                    $my_prereqs->setAttribute('type', 'aicc_script');
                    $my_item->appendChild($my_prereqs);
                    //give a child element <adlcp:maxtimeallowed> to the <item> element - not yet supported
                    //$xmldoc->createElement('adlcp:maxtimeallowed','');
                    //give a child element <adlcp:timelimitaction> to the <item> element - not yet supported
                    //$xmldoc->createElement('adlcp:timelimitaction','');
                    //give a child element <adlcp:datafromlms> to the <item> element - not yet supported
                    //$xmldoc->createElement('adlcp:datafromlms','');
                    //give a child element <adlcp:masteryscore> to the <item> element
                    $my_masteryscore = $xmldoc->createElement('adlcp:masteryscore', $item->get_mastery_score());
                    $my_item->appendChild($my_masteryscore);
                    //attach this item to the organization element or its parent if there is one
                    if (!empty($item->parent) && $item->parent != 0) {
                        $children = $organization->childNodes;
                        for ($i = 0; $i < $children->length; $i++) {
                            $item_temp = $children->item($i);
                            if ($item_temp->nodeName == 'item') {
                                if ($item_temp->getAttribute('identifier') == 'ITEM_' . $item->parent) {
                                    $item_temp->appendChild($my_item);
                                }
                            }
                        }
                    } else {
                        $organization->appendChild($my_item);
                    }
                    $my_file_path = 'link_' . $item->get_id() . '.html';
                    $sql = 'SELECT url, title FROM ' . Database::get_course_table(TABLE_LINK) . ' WHERE id=' . $item->path;
                    $rs = Database::query($sql, __FILE__, __LINE__);
                    if ($link = Database::fetch_array($rs)) {
                        $url = $link['url'];
                        $title = stripslashes($link['title']);
                        $links_to_create[$my_file_path] = array('title' => $title, 'url' => $url);
                        $my_xml_file_path = api_htmlentities($my_file_path, ENT_QUOTES, $this->encoding);
                        $my_sub_dir = dirname($my_file_path);
                        $my_xml_sub_dir = api_htmlentities($my_sub_dir, ENT_QUOTES, $this->encoding);
                        //give a <resource> child to the <resources> element
                        $my_resource = $xmldoc->createElement('resource');
                        $my_resource->setAttribute('identifier', 'RESOURCE_' . $item->get_id());
                        $my_resource->setAttribute('type', 'webcontent');
                        $my_resource->setAttribute('href', $my_xml_file_path);
                        //adlcp:scormtype can be either 'sco' or 'asset'
                        $my_resource->setAttribute('adlcp:scormtype', 'asset');
                        //xml:base is the base directory to find the files declared in this resource
                        $my_resource->setAttribute('xml:base', '');
                        //give a <file> child to the <resource> element
                        $my_file = $xmldoc->createElement('file');
                        $my_file->setAttribute('href', $my_xml_file_path);
                        $my_resource->appendChild($my_file);
                        $resources->appendChild($my_resource);
                    }
                } elseif ($item->type == TOOL_QUIZ) {
                    require_once api_get_path(SYS_CODE_PATH) . 'exercice/exercise.class.php';
                    $exe_id = $item->path;
                    //should be using ref when everything will be cleaned up in this regard
                    $exe = new Exercise();
                    $exe->read($exe_id);
                    $my_item = $xmldoc->createElement('item');
                    $my_item->setAttribute('identifier', 'ITEM_' . $item->get_id());
                    $my_item->setAttribute('identifierref', 'RESOURCE_' . $item->get_id());
                    $my_item->setAttribute('isvisible', 'true');
                    //give a child element <title> to the <item> element
                    $my_title = $xmldoc->createElement('title', htmlspecialchars($item->get_title(), ENT_QUOTES, $this->encoding));
                    $my_item->appendChild($my_title);
                    $my_max_score = $xmldoc->createElement('max_score', $item->get_max());
                    //$my_item->appendChild($my_max_score);
                    //give a child element <adlcp:prerequisites> to the <item> element
                    $my_prereqs = $xmldoc->createElement('adlcp:prerequisites', $item->get_prereq_string());
                    $my_prereqs->setAttribute('type', 'aicc_script');
                    $my_item->appendChild($my_prereqs);
                    //give a child element <adlcp:masteryscore> to the <item> element
                    $my_masteryscore = $xmldoc->createElement('adlcp:masteryscore', $item->get_mastery_score());
                    $my_item->appendChild($my_masteryscore);
                    //attach this item to the organization element or hits parent if there is one
                    if (!empty($item->parent) && $item->parent != 0) {
                        $children = $organization->childNodes;
                        for ($i = 0; $i < $children->length; $i++) {
                            $item_temp = $children->item($i);
                            if ($item_temp->nodeName == 'item') {
                                if ($item_temp->getAttribute('identifier') == 'ITEM_' . $item->parent) {
                                    $item_temp->appendChild($my_item);
                                }
                            }
                        }
                    } else {
                        $organization->appendChild($my_item);
                    }
                    //include export scripts
                    require_once api_get_path(SYS_CODE_PATH) . 'exercice/export/scorm/scorm_export.php';
                    //get the path of the file(s) from the course directory root
                    //$my_file_path = $item->get_file_path('scorm/'.$this->path.'/');
                    $my_file_path = 'quiz_' . $item->get_id() . '.html';
                    //write the contents of the exported exercise into a (big) html file
                    //to later pack it into the exported SCORM. The file will be removed afterwards
                    $contents = export_exercise($exe_id, true);
                    $tmp_file_path = $archive_path . $temp_dir_short . '/' . $my_file_path;
                    $res = file_put_contents($tmp_file_path, $contents);
                    if ($res === false) {
                        error_log('Could not write into file ' . $tmp_file_path . ' ' . __FILE__ . ' ' . __LINE__, 0);
                    }
                    $files_cleanup[] = $tmp_file_path;
                    //error_log($tmp_path);die();
                    $my_xml_file_path = api_htmlentities($my_file_path, ENT_QUOTES, $this->encoding);
                    $my_sub_dir = dirname($my_file_path);
                    $my_xml_sub_dir = api_htmlentities($my_sub_dir, ENT_QUOTES, $this->encoding);
                    //give a <resource> child to the <resources> element
                    $my_resource = $xmldoc->createElement('resource');
                    $my_resource->setAttribute('identifier', 'RESOURCE_' . $item->get_id());
                    $my_resource->setAttribute('type', 'webcontent');
                    $my_resource->setAttribute('href', $my_xml_file_path);
                    //adlcp:scormtype can be either 'sco' or 'asset'
                    $my_resource->setAttribute('adlcp:scormtype', 'sco');
                    //xml:base is the base directory to find the files declared in this resource
                    $my_resource->setAttribute('xml:base', '');
                    //give a <file> child to the <resource> element
                    $my_file = $xmldoc->createElement('file');
                    $my_file->setAttribute('href', $my_xml_file_path);
                    $my_resource->appendChild($my_file);
                    //get included docs
                    $inc_docs = $item->get_resources_from_source(null, $tmp_file_path);
                    //dependency to other files - not yet supported
                    $i = 1;
                    foreach ($inc_docs as $doc_info) {
                        if (count($doc_info) < 1 or empty($doc_info[0])) {
                            continue;
                        }
                        $my_dep = $xmldoc->createElement('resource');
                        $res_id = 'RESOURCE_' . $item->get_id() . '_' . $i;
                        $my_dep->setAttribute('identifier', $res_id);
                        $my_dep->setAttribute('type', 'webcontent');
                        $my_dep->setAttribute('adlcp:scormtype', 'asset');
                        $my_dep_file = $xmldoc->createElement('file');
                        //check type of URL
                        //error_log(__LINE__.'Now dealing with '.$doc_info[0].' of type '.$doc_info[1].'-'.$doc_info[2],0);
                        if ($doc_info[1] == 'remote') {
                            //remote file. Save url as is
                            $my_dep_file->setAttribute('href', $doc_info[0]);
                            $my_dep->setAttribute('xml:base', '');
                        } elseif ($doc_info[1] == 'local') {
                            switch ($doc_info[2]) {
                                case 'url':
                                    //local URL - save path as url for now, don't zip file
                                    //save file but as local file (retrieve from URL)
                                    $abs_path = api_get_path(SYS_PATH) . str_replace(api_get_path(WEB_PATH), '', $doc_info[0]);
                                    $current_dir = dirname($abs_path);
                                    $file_path = realpath($abs_path);
                                    $my_dep_file->setAttribute('href', 'document/' . $file_path);
                                    $my_dep->setAttribute('xml:base', '');
                                    if (strstr($file_path, $main_path) !== false) {
                                        //the calculated real path is really inside the dokeos root path
                                        //reduce file path to what's under the DocumentRoot
                                        $file_path = substr($file_path, strlen($root_path));
                                        //echo $file_path;echo '<br><br>';
                                        //error_log('Reduced path: '.$file_path,0);
                                        $zip_files_abs[] = $file_path;
                                        $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => 'document/' . $file_path);
                                        $my_dep_file->setAttribute('href', 'document/' . $file_path);
                                        $my_dep->setAttribute('xml:base', '');
                                    } else {
                                        if (empty($file_path)) {
                                            /* $document_root = substr(api_get_path(SYS_PATH), 0, strpos(api_get_path(SYS_PATH),api_get_path(REL_PATH)));
                                               if(strpos($document_root,-1)=='/')
                                               {
                                               $document_root = substr(0, -1, $document_root);
                                               } */
                                            $file_path = $_SERVER['DOCUMENT_ROOT'] . $abs_path;
                                            $file_path = str_replace('//', '/', $file_path);
                                            if (file_exists($file_path)) {
                                                $file_path = substr($file_path, strlen($current_dir));
                                                // we get the relative path
                                                $zip_files[] = $my_sub_dir . '/' . $file_path;
                                                $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => 'document/' . $file_path);
                                                $my_dep_file->setAttribute('href', 'document/' . $file_path);
                                                $my_dep->setAttribute('xml:base', '');
                                            }
                                        }
                                    }
                                    break;
                                case 'abs':
                                    //absolute path from DocumentRoot. Save file and leave path as is in the zip
                                    $current_dir = dirname($current_course_path . '/' . $item->get_file_path()) . '/';
                                    $file_path = realpath($doc_info[0]);
                                    $my_dep_file->setAttribute('href', $file_path);
                                    $my_dep->setAttribute('xml:base', '');
                                    if (strstr($file_path, $main_path) !== false) {
                                        //the calculated real path is really inside the dokeos root path
                                        //reduce file path to what's under the DocumentRoot
                                        $file_path = substr($file_path, strlen($root_path));
                                        //echo $file_path;echo '<br><br>';
                                        //error_log('Reduced path: '.$file_path,0);
                                        $zip_files_abs[] = $file_path;
                                        $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path);
                                        $my_dep_file->setAttribute('href', 'document/' . $file_path);
                                        $my_dep->setAttribute('xml:base', '');
                                    } else {
                                        if (empty($file_path)) {
                                            /* $document_root = substr(api_get_path(SYS_PATH), 0, strpos(api_get_path(SYS_PATH),api_get_path(REL_PATH)));
                                               if(strpos($document_root,-1)=='/')
                                               {
                                               $document_root = substr(0, -1, $document_root);
                                               } */
                                            $file_path = $_SERVER['DOCUMENT_ROOT'] . $doc_info[0];
                                            $file_path = str_replace('//', '/', $file_path);
                                            if (file_exists($file_path)) {
                                                $file_path = substr($file_path, strlen($current_dir));
                                                // we get the relative path
                                                $zip_files[] = $my_sub_dir . '/' . $file_path;
                                                $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path);
                                                $my_dep_file->setAttribute('href', 'document/' . $file_path);
                                                $my_dep->setAttribute('xml:base', '');
                                            }
                                        }
                                    }
                                    break;
                                case 'rel':
                                    //path relative to the current document. Save xml:base as current document's directory and save file in zip as subdir.file_path
                                    if (substr($doc_info[0], 0, 2) == '..') {
                                        //relative path going up
                                        $current_dir = dirname($current_course_path . '/' . $item->get_file_path()) . '/';
                                        $file_path = realpath($current_dir . $doc_info[0]);
                                        //error_log($file_path.' <-> '.$main_path,0);
                                        if (strstr($file_path, $main_path) !== false) {
                                            //the calculated real path is really inside the dokeos root path
                                            //reduce file path to what's under the DocumentRoot
                                            $file_path = substr($file_path, strlen($root_path));
                                            $file_path_dest = $file_path;
                                            //file path is courses/DOKEOS/document/....
                                            $info_file_path = explode('/', $file_path);
                                            if ($info_file_path[0] == 'courses') {
                                                //add character "/" in file path
                                                $file_path_dest = '/' . $file_path;
                                            }
                                            //error_log('Reduced path: '.$file_path,0);
                                            $zip_files_abs[] = $file_path;
                                            $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path_dest);
                                            $my_dep_file->setAttribute('href', 'document/' . $file_path);
                                            $my_dep->setAttribute('xml:base', '');
                                        }
                                    } else {
                                        $zip_files[] = $my_sub_dir . '/' . $doc_info[0];
                                        $my_dep_file->setAttribute('href', $doc_info[0]);
                                        $my_dep->setAttribute('xml:base', $my_xml_sub_dir);
                                    }
                                    break;
                                default:
                                    $my_dep_file->setAttribute('href', $doc_info[0]);
                                    // ../../courses/
                                    $my_dep->setAttribute('xml:base', '');
                                    break;
                            }
                        }
                        $my_dep->appendChild($my_dep_file);
                        $resources->appendChild($my_dep);
                        $dependency = $xmldoc->createElement('dependency');
                        $dependency->setAttribute('identifierref', $res_id);
                        $my_resource->appendChild($dependency);
                        $i++;
                    }
                    $resources->appendChild($my_resource);
                    $zip_files[] = $my_file_path;
                } else {
                    //get the path of the file(s) from the course directory root
                    $my_file_path = 'non_exportable.html';
                    $my_xml_file_path = api_htmlentities($my_file_path, ENT_COMPAT, $this->encoding);
                    $my_sub_dir = dirname($my_file_path);
                    $my_xml_sub_dir = api_htmlentities($my_sub_dir, ENT_COMPAT, $this->encoding);
                    //give a <resource> child to the <resources> element
                    $my_resource = $xmldoc->createElement('resource');
                    $my_resource->setAttribute('identifier', 'RESOURCE_' . $item->get_id());
                    $my_resource->setAttribute('type', 'webcontent');
                    $my_resource->setAttribute('href', 'document/' . $my_xml_file_path);
                    //adlcp:scormtype can be either 'sco' or 'asset'
                    $my_resource->setAttribute('adlcp:scormtype', 'asset');
                    //xml:base is the base directory to find the files declared in this resource
                    $my_resource->setAttribute('xml:base', '');
                    //give a <file> child to the <resource> element
                    $my_file = $xmldoc->createElement('file');
                    $my_file->setAttribute('href', 'document/' . $my_xml_file_path);
                    $my_resource->appendChild($my_file);
                    $resources->appendChild($my_resource);
                }
            }
        }
        $organizations->appendChild($organization);
        $root->appendChild($organizations);
        $root->appendChild($resources);
        $xmldoc->appendChild($root);
        //todo: add a readme file here, with a short description and a link to the Reload player
        //then add the file to the zip, then destroy the file (this is done automatically)
        // http://www.reload.ac.uk/scormplayer.html - once done, don't forget to close FS#138
        //error_log(print_r($zip_files,true),0);
        foreach ($zip_files as $file_path) {
            if (empty($file_path)) {
                continue;
            }
            //error_log(__LINE__.'getting document from '.$sys_course_path.$_course['path'].'/'.$file_path.' removing '.$sys_course_path.$_course['path'].'/',0);
            $dest_file = $archive_path . $temp_dir_short . '/' . $file_path;
            $this->create_path($dest_file);
            //error_log('copy '.api_get_path('SYS_COURSE_PATH').$_course['path'].'/'.$file_path.' to '.api_get_path('SYS_ARCHIVE_PATH').$temp_dir_short.'/'.$file_path,0);
            //echo $main_path.$file_path.'<br>';
            @copy($sys_course_path . $_course['path'] . '/' . $file_path, $dest_file);
            //check if the file needs a link update
            if (in_array($file_path, array_keys($link_updates))) {
                $string = file_get_contents($dest_file);
                unlink($dest_file);
                foreach ($link_updates[$file_path] as $old_new) {
                    //error_log('Replacing '.$old_new['orig'].' by '.$old_new['dest'].' in '.$file_path,0);
                    //this is an ugly hack that allows .flv files to be found by the flv player that
                    // will be added in document/main/inc/lib/flv_player/flv_player.swf and that needs
                    // to find the flv to play in document/main/, so we replace main/ in the flv path by
                    // ../../.. to return from inc/lib/flv_player to the document/main path
                    if (substr($old_new['dest'], -3) == 'flv' && substr($old_new['dest'], 0, 5) == 'main/') {
                        $old_new['dest'] = str_replace('main/', '../../../', $old_new['dest']);
                    } elseif (substr($old_new['dest'], -3) == 'flv' && substr($old_new['dest'], 0, 6) == 'video/') {
                        $old_new['dest'] = str_replace('video/', '../../../../video/', $old_new['dest']);
                    }
                    if (substr($old_new['dest'], 0, 1) == '/') {
                        $old_new['dest'] = substr($old_new['dest'], 1);
                    }
                    $string = str_replace($old_new['orig'], $old_new['dest'], $string);
                    $string = str_replace(str_replace('https', 'http', $old_new['orig']), $old_new['dest'], $string);
                }
                file_put_contents($dest_file, $string);
            }
        }
        foreach ($zip_files_abs as $file_path) {
            if (empty($file_path)) {
                continue;
            }
            //error_log(__LINE__.'checking existence of '.$main_path.$file_path.'',0);
            if (!is_file($main_path . $file_path) || !is_readable($main_path . $file_path)) {
                continue;
            }
            //error_log(__LINE__.'getting document from '.$main_path.$file_path.' removing '.api_get_path('SYS_COURSE_PATH').$_course['path'].'/',0);
            $dest_file = $archive_path . $temp_dir_short . '/document/' . $file_path;
            $this->create_path($dest_file);
            //error_log('Created path '.api_get_path(SYS_ARCHIVE_PATH).$temp_dir_short.'/document/'.$file_path,0);
            //error_log('copy '.api_get_path(SYS_COURSE_PATH).$_course['path'].'/'.$file_path.' to '.api_get_path(SYS_ARCHIVE_PATH).$temp_dir_short.'/'.$file_path,0);
            //echo $main_path.$file_path.' - '.$dest_file.'<br>';
            copy($main_path . $file_path, $dest_file);
            //check if the file needs a link update
            if (in_array($file_path, array_keys($link_updates))) {
                $string = file_get_contents($dest_file);
                unlink($dest_file);
                foreach ($link_updates[$file_path] as $old_new) {
                    //error_log('Replacing '.$old_new['orig'].' by '.$old_new['dest'].' in '.$file_path,0);
                    //this is an ugly hack that allows .flv files to be found by the flv player that
                    // will be added in document/main/inc/lib/flv_player/flv_player.swf and that needs
                    // to find the flv to play in document/main/, so we replace main/ in the flv path by
                    // ../../.. to return from inc/lib/flv_player to the document/main path
                    if (substr($old_new['dest'], -3) == 'flv' && substr($old_new['dest'], 0, 5) == 'main/') {
                        $old_new['dest'] = str_replace('main/', '../../../', $old_new['dest']);
                    }
                    if (substr($old_new['dest'], 0, 1) == '/') {
                        $old_new['dest'] = substr($old_new['dest'], 1);
                    }
                    $string = str_replace($old_new['orig'], $old_new['dest'], $string);
                    $string = str_replace(str_replace('https', 'http', $old_new['orig']), $old_new['dest'], $string);
                }
                file_put_contents($dest_file, $string);
            }
        }
        if (is_array($links_to_create)) {
            foreach ($links_to_create as $file => $link) {
                $file_content = '<html><body><div style="text-align:center"><a href="' . $link['url'] . '">' . $link['title'] . '</a></div></body></html>';
                file_put_contents($archive_path . $temp_dir_short . '/' . $file, $file_content);
            }
        }
        // add non exportable message explanation
        $lang_not_exportable = get_lang('ThisItemIsNotExportable');
        $file_content = <<<EOD
<html>
\t<head>
\t\t<style>
\t\t\t.error-message {
\t\t\t\tfont-family: arial, verdana, helvetica, sans-serif;
\t\t\t\tborder-width: 1px;
\t\t\t\tborder-style: solid;
\t\t\t\tleft: 50%;
\t\t\t\tmargin: 10px auto;
\t\t\t\tmin-height: 30px;
\t\t\t\tpadding: 5px;
\t\t\t\tright: 50%;
\t\t\t\twidth: 500px;
\t\t\t\tbackground-color: #FFD1D1;
\t\t\t\tborder-color: #FF0000;
\t\t\t\tcolor: #000;
\t\t\t}
\t\t</style>
\t<body>
\t\t<div class="error-message">
\t\t\t{$lang_not_exportable}
\t\t</div>
\t</body>
</html>
EOD;
        if (!is_dir($archive_path . $temp_dir_short . '/document')) {
            @mkdir($archive_path . $temp_dir_short . '/document');
        }
        file_put_contents($archive_path . $temp_dir_short . '/document/non_exportable.html', $file_content);
        //Add the extra files that go along with a SCORM package
        $main_code_path = api_get_path(SYS_CODE_PATH) . 'newscorm/packaging/';
        $extra_files = scandir($main_code_path);
        foreach ($extra_files as $extra_file) {
            if (strpos($extra_file, '.') === 0) {
                continue;
            } else {
                $dest_file = $archive_path . $temp_dir_short . '/' . $extra_file;
                $this->create_path($dest_file);
                copy($main_code_path . $extra_file, $dest_file);
            }
        }
        //Finalize the imsmanifest structure, add to the zip, then return the zip
        $xmldoc->save($archive_path . '/' . $temp_dir_short . '/imsmanifest.xml');
        $zip_folder->add($archive_path . '/' . $temp_dir_short, PCLZIP_OPT_REMOVE_PATH, $archive_path . '/' . $temp_dir_short . '/');
        //clean possible temporary files
        foreach ($files_cleanup as $file) {
            $res = unlink($file);
            if ($res === false) {
                error_log('Could not delete temp file ' . $file . ' ' . __FILE__ . ' ' . __LINE__, 0);
            }
        }
        //Send file to client
        //$name = 'scorm_export_'.$this->lp_id.'.zip';
        require_once api_get_path(LIBRARY_PATH) . 'fileUpload.lib.php';
        $name = preg_replace('([^a-zA-Z0-9_\\.])', '-', html_entity_decode($this->get_name(), ENT_QUOTES)) . '.zip';
        DocumentManager::file_send_for_download($temp_zip_file, true, $name);
    }
        $interbreadcrumb[] = array("url" => "admin.php?exerciseId=" . $exercise_id . "&" . api_get_cidreq(), "name" => $objExerciseTmp->name);
    }
} else {
    $interbreadcrumb[] = array("url" => "exercise.php?" . api_get_cidreq(), "name" => get_lang('Exercises'));
    $objExerciseTmp = new Exercise();
    if ($objExerciseTmp->read($exercise_id)) {
        $nameTools = get_lang('Results') . ': ' . $objExerciseTmp->name;
    }
}
Display::display_header($nameTools);
// Clean all results for this test before the selected date
if (($is_allowedToEdit || $is_tutor || api_is_coach()) && isset($_GET['delete_before_date']) && $locked == false) {
    // ask for the date
    $check = Security::check_token('get');
    if ($check) {
        $objExerciseTmp = new Exercise();
        if ($objExerciseTmp->read($exercise_id)) {
            $count = $objExerciseTmp->clean_results(true, $_GET['delete_before_date'] . ' 23:59:59');
            Display::display_confirmation_message(sprintf(get_lang('XResultsCleaned'), $count));
        }
    }
}
// Security token to protect deletion
$token = Security::get_token();
$actions = Display::div($actions, array('class' => 'actions'));
$extra = '<script>
    $(document).ready(function() {
        $( "#dialog:ui-dialog" ).dialog( "destroy" );
        $( "#dialog-confirm" ).dialog({
                autoOpen: false,
                show: "blind",
 /**
  * Shows the user detail progress (when clicking in the details link)
  * @param   int     $user_id
  * @param   string  $course_code
  * @param   int     $session_id
  * @return  string  html code
  */
 public static function show_course_detail($user_id, $course_code, $session_id)
 {
     $html = '';
     if (isset($course_code)) {
         $user_id = intval($user_id);
         $session_id = intval($session_id);
         $course = Database::escape_string($course_code);
         $course_info = CourseManager::get_course_information($course);
         $html .= Display::page_subheader($course_info['title']);
         $html .= '<table class="data_table" width="100%">';
         //Course details
         $html .= '
             <tr>
             <th class="head" style="color:#000">' . get_lang('Exercises') . '</th>
             <th class="head" style="color:#000">' . get_lang('Attempts') . '</th>
             <th class="head" style="color:#000">' . get_lang('BestAttempt') . '</th>
             <th class="head" style="color:#000">' . get_lang('Ranking') . '</th>
             <th class="head" style="color:#000">' . get_lang('BestResultInCourse') . '</th>
             <th class="head" style="color:#000">' . get_lang('Statistics') . ' ' . Display::return_icon('info3.gif', get_lang('OnlyBestResultsPerStudent'), array('align' => 'absmiddle', 'hspace' => '3px')) . '</th>
             </tr>';
         if (empty($session_id)) {
             $user_list = CourseManager::get_user_list_from_course_code($course, $session_id, null, null, STUDENT);
         } else {
             $user_list = CourseManager::get_user_list_from_course_code($course, $session_id, null, null, 0);
         }
         // Show exercise results of invisible exercises? see BT#4091
         $exercise_list = ExerciseLib::get_all_exercises($course_info, $session_id, false, null, false, 2);
         $to_graph_exercise_result = array();
         if (!empty($exercise_list)) {
             $score = $weighting = $exe_id = 0;
             foreach ($exercise_list as $exercices) {
                 $exercise_obj = new Exercise($course_info['real_id']);
                 $exercise_obj->read($exercices['id']);
                 $visible_return = $exercise_obj->is_visible();
                 $score = $weighting = $attempts = 0;
                 // Getting count of attempts by user
                 $attempts = Event::count_exercise_attempts_by_user(api_get_user_id(), $exercices['id'], $course_info['real_id'], $session_id);
                 $html .= '<tr class="row_even">';
                 $url = api_get_path(WEB_CODE_PATH) . "exercice/overview.php?cidReq={$course_info['code']}&id_session={$session_id}&exerciseId={$exercices['id']}";
                 if ($visible_return['value'] == true) {
                     $exercices['title'] = Display::url($exercices['title'], $url, array('target' => SESSION_LINK_TARGET));
                 }
                 $html .= Display::tag('td', $exercices['title']);
                 // Exercise configuration show results or show only score
                 if ($exercices['results_disabled'] == 0 || $exercices['results_disabled'] == 2) {
                     //For graphics
                     $best_exercise_stats = Event::get_best_exercise_results_by_user($exercices['id'], $course_info['real_id'], $session_id);
                     $to_graph_exercise_result[$exercices['id']] = array('title' => $exercices['title'], 'data' => $best_exercise_stats);
                     $latest_attempt_url = '';
                     $best_score = $position = $percentage_score_result = '-';
                     $graph = $normal_graph = null;
                     // Getting best results
                     $best_score_data = ExerciseLib::get_best_attempt_in_course($exercices['id'], $course_info['real_id'], $session_id);
                     $best_score = '';
                     if (!empty($best_score_data)) {
                         $best_score = ExerciseLib::show_score($best_score_data['exe_result'], $best_score_data['exe_weighting']);
                     }
                     if ($attempts > 0) {
                         $exercise_stat = ExerciseLib::get_best_attempt_by_user(api_get_user_id(), $exercices['id'], $course_info['real_id'], $session_id);
                         if (!empty($exercise_stat)) {
                             //Always getting the BEST attempt
                             $score = $exercise_stat['exe_result'];
                             $weighting = $exercise_stat['exe_weighting'];
                             $exe_id = $exercise_stat['exe_id'];
                             $latest_attempt_url .= api_get_path(WEB_CODE_PATH) . 'exercice/result.php?id=' . $exe_id . '&cidReq=' . $course_info['code'] . '&show_headers=1&id_session=' . $session_id;
                             $percentage_score_result = Display::url(ExerciseLib::show_score($score, $weighting), $latest_attempt_url);
                             $my_score = 0;
                             if (!empty($weighting) && intval($weighting) != 0) {
                                 $my_score = $score / $weighting;
                             }
                             //@todo this function slows the page
                             $position = ExerciseLib::get_exercise_result_ranking($my_score, $exe_id, $exercices['id'], $course_info['code'], $session_id, $user_list);
                             $graph = self::generate_exercise_result_thumbnail_graph($to_graph_exercise_result[$exercices['id']]);
                             $normal_graph = self::generate_exercise_result_graph($to_graph_exercise_result[$exercices['id']]);
                         }
                     }
                     $html .= Display::div($normal_graph, array('id' => 'main_graph_' . $exercices['id'], 'class' => 'dialog', 'style' => 'display:none'));
                     if (empty($graph)) {
                         $graph = '-';
                     } else {
                         $graph = Display::url('<img src="' . $graph . '" >', $normal_graph, array('id' => $exercices['id'], 'class' => 'expand-image'));
                     }
                     $html .= Display::tag('td', $attempts, array('align' => 'center'));
                     $html .= Display::tag('td', $percentage_score_result, array('align' => 'center'));
                     $html .= Display::tag('td', $position, array('align' => 'center'));
                     $html .= Display::tag('td', $best_score, array('align' => 'center'));
                     $html .= Display::tag('td', $graph, array('align' => 'center'));
                     //$html .= Display::tag('td', $latest_attempt_url,       array('align'=>'center', 'width'=>'25'));
                 } else {
                     // Exercise configuration NO results
                     $html .= Display::tag('td', $attempts, array('align' => 'center'));
                     $html .= Display::tag('td', '-', array('align' => 'center'));
                     $html .= Display::tag('td', '-', array('align' => 'center'));
                     $html .= Display::tag('td', '-', array('align' => 'center'));
                     $html .= Display::tag('td', '-', array('align' => 'center'));
                 }
                 $html .= '</tr>';
             }
         } else {
             $html .= '<tr><td colspan="5" align="center">' . get_lang('NoEx') . '</td></tr>';
         }
         $html .= '</table>';
         // LP table results
         $html .= '<table class="data_table">';
         $html .= Display::tag('th', get_lang('Learnpaths'), array('class' => 'head', 'style' => 'color:#000'));
         $html .= Display::tag('th', get_lang('LatencyTimeSpent'), array('class' => 'head', 'style' => 'color:#000'));
         $html .= Display::tag('th', get_lang('Progress'), array('class' => 'head', 'style' => 'color:#000'));
         $html .= Display::tag('th', get_lang('Score'), array('class' => 'head', 'style' => 'color:#000'));
         $html .= Display::tag('th', get_lang('LastConnexion'), array('class' => 'head', 'style' => 'color:#000'));
         $html .= '</tr>';
         $list = new LearnpathList(api_get_user_id(), $course_info['code'], $session_id, 'publicated_on ASC', true);
         $lp_list = $list->get_flat_list();
         if (!empty($lp_list) > 0) {
             foreach ($lp_list as $lp_id => $learnpath) {
                 $progress = Tracking::get_avg_student_progress($user_id, $course, array($lp_id), $session_id);
                 $last_connection_in_lp = Tracking::get_last_connection_time_in_lp($user_id, $course, $lp_id, $session_id);
                 $time_spent_in_lp = Tracking::get_time_spent_in_lp($user_id, $course, array($lp_id), $session_id);
                 $percentage_score = Tracking::get_avg_student_score($user_id, $course, array($lp_id), $session_id);
                 if (is_numeric($percentage_score)) {
                     $percentage_score = $percentage_score . '%';
                 } else {
                     $percentage_score = '0%';
                 }
                 $time_spent_in_lp = api_time_to_hms($time_spent_in_lp);
                 $html .= '<tr class="row_even">';
                 $url = api_get_path(WEB_CODE_PATH) . "newscorm/lp_controller.php?cidReq={$course_code}&id_session={$session_id}&lp_id={$lp_id}&action=view";
                 if ($learnpath['lp_visibility'] == 0) {
                     $html .= Display::tag('td', $learnpath['lp_name']);
                 } else {
                     $html .= Display::tag('td', Display::url($learnpath['lp_name'], $url, array('target' => SESSION_LINK_TARGET)));
                 }
                 $html .= Display::tag('td', $time_spent_in_lp, array('align' => 'center'));
                 if (is_numeric($progress)) {
                     $progress = $progress . '%';
                 }
                 $html .= Display::tag('td', $progress, array('align' => 'center'));
                 $html .= Display::tag('td', $percentage_score);
                 $last_connection = '-';
                 if (!empty($last_connection_in_lp)) {
                     $last_connection = api_convert_and_format_date($last_connection_in_lp, DATE_TIME_FORMAT_LONG);
                 }
                 $html .= Display::tag('td', $last_connection, array('align' => 'center', 'width' => '180px'));
                 $html .= "</tr>";
             }
         } else {
             $html .= '<tr>
                     <td colspan="4" align="center">
                         ' . get_lang('NoLearnpath') . '
                     </td>
                   </tr>';
         }
         $html .= '</table>';
     }
     return $html;
 }
 /**
  * Get all questions
  * @param Application $app
  * @param int $categoryId
  * @param int $exerciseId
  * @param int $courseId
  * @param array $options
  * @param bool $get_count
  * @return array
  */
 public static function getQuestions($app, $categoryId, $exerciseId, $courseId, $options, $get_count = false)
 {
     $questionTable = Database::get_course_table(TABLE_QUIZ_QUESTION);
     $questionPoolFields = array('question_session_id' => array('innerjoin' => " INNER JOIN " . Database::get_course_table(TABLE_QUIZ_TEST_QUESTION) . " as quiz_rel_question_session ON (quiz_rel_question_session.question_id = s.iid)\n                                 INNER JOIN " . Database::get_course_table(TABLE_QUIZ_TEST) . " as quizsession ON (quizsession.iid = quiz_rel_question_session.exercice_id)\n                                 INNER JOIN " . Database::get_main_table(TABLE_MAIN_SESSION) . " session ON (session.id = quizsession.session_id)", 'where' => 'session_id', 'inject_fields' => 'session.name as question_session_id, '), 'question_category_id' => array('innerjoin' => " INNER JOIN " . Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY) . " as quiz_rel_cat ON (quiz_rel_cat.question_id = s.iid)\n                                 INNER JOIN " . Database::get_course_table(TABLE_QUIZ_CATEGORY) . " as cat ON (cat.iid = quiz_rel_cat.category_id)", 'where' => 'quiz_rel_cat.category_id', 'inject_fields' => 'cat.title as question_category_id, '), 'question_exercise_id' => array('innerjoin' => " INNER JOIN " . Database::get_course_table(TABLE_QUIZ_TEST_QUESTION) . " as quiz_rel_question ON (quiz_rel_question.question_id = s.iid)\n                                 INNER JOIN " . Database::get_course_table(TABLE_QUIZ_TEST) . " as quizexercise ON (quizexercise.iid = quiz_rel_question.exercice_id) ", 'where' => 'quiz_rel_question.exercice_id', 'inject_fields' => 'quizexercise.title as question_exercise_id, '), 'question_c_id' => array('where' => 's.c_id', 'innerjoin' => " INNER JOIN " . Database::get_main_table(TABLE_MAIN_COURSE) . " as course ON (course.id = s.c_id) ", 'inject_fields' => 'course.title as question_c_id, '), 'question_question_type' => array('where' => 's.type ', 'inject_fields' => 's.type as question_question_type,'), 'question_difficulty' => array('where' => 's.level', 'inject_fields' => 's.level as question_difficulty, '));
     // Checking if you're looking for orphan questions.
     $isOrphanQuestion = false;
     if (isset($options['question'])) {
         foreach ($options['question'] as $option) {
             if (isset($option['field']) && $option['field'] == 'question_exercise_id') {
                 if ($option['data'] == 0) {
                     $isOrphanQuestion = true;
                     break;
                 }
             }
         }
     }
     // Special case for orphan questions.
     if ($isOrphanQuestion) {
         $questionPoolFields['question_exercise_id'] = array('innerjoin' => " LEFT JOIN " . Database::get_course_table(TABLE_QUIZ_TEST_QUESTION) . " as quiz_rel_question ON (quiz_rel_question.question_id = s.iid)\n                                 LEFT JOIN " . Database::get_course_table(TABLE_QUIZ_TEST) . " as quizexercise ON (quizexercise.iid = quiz_rel_question.exercice_id) ", 'where' => 'quiz_rel_question.exercice_id', 'inject_fields' => 'quizexercise.title as question_exercise_id, ');
     }
     $inject_extra_fields = null;
     $inject_joins = null;
     $where = $options['where'];
     $newQuestionPoolField = array();
     if (isset($options['question'])) {
         foreach ($options['question'] as $question) {
             if (isset($questionPoolFields[$question['field']])) {
                 $newQuestionPoolField[$question['field']] = $questionPoolFields[$question['field']];
             }
         }
     }
     $inject_question_fields = null;
     $questionPoolFields = $newQuestionPoolField;
     // Injecting inner joins.
     foreach ($questionPoolFields as $field => $option) {
         $where = str_replace($field, $option['where'], $where);
         if (isset($option['innerjoin']) && !empty($option['innerjoin'])) {
             $inject_joins .= $option['innerjoin'];
         }
         if (isset($option['inject_fields']) && !empty($option['inject_fields'])) {
             $inject_question_fields .= $option['inject_fields'];
         }
     }
     $options['where'] = $where;
     $extra_field = new ExtraField('question');
     $conditions = $extra_field->parseConditions($options);
     $inject_joins .= $conditions['inject_joins'];
     $where = $conditions['where'];
     $inject_where = $conditions['inject_where'];
     $inject_extra_fields = $conditions['inject_extra_fields'];
     $order = $conditions['order'];
     $limit = $conditions['limit'];
     if ($get_count == true) {
         $select = " SELECT count(*) as total_rows";
     } else {
         $select = " SELECT s.*, {$inject_extra_fields} {$inject_question_fields} 1 ";
     }
     $extraCondition = null;
     // Used by the question manager
     if (!empty($categoryId)) {
         $categoryRelQuestionTable = Database::get_course_table(TABLE_QUIZ_QUESTION_REL_CATEGORY);
         $extraCondition = " INNER JOIN {$categoryRelQuestionTable} c ON (s.iid = c.question_id)";
         $categoryId = intval($categoryId);
         $where .= " AND category_id = {$categoryId} ";
     }
     /*if (!empty($exerciseId)) {
           $exerciseRelQuestionTable = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
           $extraCondition .= " INNER JOIN $exerciseRelQuestionTable e ON (s.iid = e.question_id)";
           $exerciseId = intval($exerciseId);
           $where .= " AND exercice_id = $exerciseId ";
       }*/
     // Orphan questions
     if ($isOrphanQuestion) {
         //$exerciseRelQuestionTable = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
         //$extraCondition .= " INNER JOIN $exerciseRelQuestionTable e ON (s.iid = e.question_id)";
         $where .= " OR quizexercise.active = -1 OR quiz_rel_question.exercice_id IS NULL";
     }
     if (!empty($courseId)) {
         $courseId = intval($courseId);
         $where .= " AND s.c_id = {$courseId} ";
     }
     if (isset($options['question'])) {
         $courseList = CourseManager::get_course_list_of_user_as_course_admin(api_get_user_id());
         foreach ($options['question'] as $questionOption) {
             if ($questionOption['field'] == 'question_c_id') {
                 if (isset($questionOption['data'])) {
                     if (!isset($courseList[$questionOption['data']])) {
                         return array();
                     }
                 }
             }
         }
     }
     //var_dump(CourseManager::get_teacher_list_from_course_code())
     //var_dump($inject_joins);
     $query = " {$select} FROM {$questionTable} s {$inject_joins} {$extraCondition} WHERE 1=1 {$where} {$inject_where} {$order} {$limit}";
     //echo $query.'<br />';
     //var_dump($extraCondition);
     //var_dump($where);
     $result = Database::query($query);
     $questions = array();
     $exerciseList = null;
     if (!empty($exerciseId)) {
         $exercise = new Exercise();
         $exercise->read($exerciseId);
         $exerciseList = $exercise->questionList;
     }
     if (Database::num_rows($result)) {
         $questions = Database::store_result($result, 'ASSOC');
         if ($get_count) {
             return $questions[0]['total_rows'];
         }
         $previewIcon = Display::return_icon('preview.gif', get_lang('View'), array(), ICON_SIZE_SMALL);
         $copyIcon = Display::return_icon('copy.png', get_lang('Copy'), array(), ICON_SIZE_SMALL);
         $reuseIcon = Display::return_icon('view_more_stats.gif', get_lang('InsertALinkToThisQuestionInTheExercise'), array(), ICON_SIZE_SMALL);
         $editIcon = Display::return_icon('edit.png', get_lang('Edit'), array(), ICON_SIZE_SMALL);
         //$deleteIcon = Display::return_icon('delete.png', get_lang('Delete'), array(), ICON_SIZE_SMALL);
         //var_dump($exerciseId);
         // Including actions
         foreach ($questions as &$question) {
             $type = self::get_question_type($question['type']);
             $question['type'] = get_lang($type[1]);
             $question['question_question_type'] = get_lang($type[1]);
             if (empty($exerciseId)) {
                 // View.
                 $actions = Display::url($previewIcon, $app['url_generator']->generate('admin_questions_show', array('id' => $question['iid'])));
                 // Edit.
                 $actions .= Display::url($editIcon, $app['url_generator']->generate('admin_questions_edit', array('id' => $question['iid'])));
             } else {
                 // View.
                 $actions = Display::url($previewIcon, $app['url_generator']->generate('question_show', array('cidReq' => api_get_course_id(), 'id_session' => api_get_session_id(), 'exerciseId' => $exerciseId, 'id' => $question['iid'])));
                 if (isset($exerciseList) && !empty($exerciseList) && in_array($question['iid'], $exerciseList)) {
                     // Copy.
                     //$actions .= $copyIconDisabled;
                 } else {
                     // Copy.
                     $actions .= Display::url($copyIcon, 'javascript:void(0);', array('onclick' => 'ajaxAction(this);', 'data-url' => $app['url_generator']->generate('exercise_copy_question', array('cidReq' => api_get_course_id(), 'id_session' => api_get_session_id(), 'questionId' => $question['iid'], 'exerciseId' => $exerciseId))));
                     // Reuse.
                     $actions .= Display::url($reuseIcon, 'javascript:void(0);', array('onclick' => 'ajaxAction(this);', 'data-url' => $app['url_generator']->generate('exercise_reuse_question', array('cidReq' => api_get_course_id(), 'id_session' => api_get_session_id(), 'questionId' => $question['iid'], 'exerciseId' => $exerciseId))));
                 }
                 // Edit.
                 $actions .= Display::url($editIcon, $app['url_generator']->generate('exercise_question_edit', array('cidReq' => api_get_course_id(), 'id_session' => api_get_session_id(), 'id' => $question['iid'])));
             }
             $question['actions'] = $actions;
         }
     }
     return $questions;
 }
    if ($is_allowed_to_edit) {
        if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'view' && !isset($_REQUEST['exeId'])) {
            $_REQUEST['action'] = 'build';
        }
        //$_SESSION['studentview'] = null;
    }
}

$action = (!empty($_REQUEST['action']) ? $_REQUEST['action'] : '');

// format title to be displayed correctly if QUIZ
$post_title = "";
if (isset($_POST['title'])) {
    $post_title = Security::remove_XSS($_POST['title']);
    if (isset($_POST['type']) && isset($_POST['title']) && $_POST['type'] == TOOL_QUIZ && !empty($_POST['title'])) {
        $post_title = Exercise::format_title_variable($_POST['title']);
    }
}

switch ($action) {
    case 'add_item':
        if (!$is_allowed_to_edit) {
            api_not_allowed(true);
        }
        if ($debug > 0) error_log('New LP - add item action triggered', 0);

        if (!$lp_found) {
            //check if the learnpath ID was defined, otherwise send back to list
            if ($debug > 0) error_log('New LP - No learnpath given for add item', 0);
            require 'lp_list.php';
        } else {
Exemple #21
0
} else {
    $cmd = null;
}
if (isset($item_list['1']) && is_numeric($item_list['1'])) {
    $quId = (int) $item_list['1'];
} else {
    $quId = null;
}
if (isset($item_list['2']) && is_numeric($item_list['2'])) {
    $exId = (int) $item_list['2'];
} else {
    $exId = null;
}
if ($cmd == 'download') {
    // find exercise informations
    $exercise = new Exercise();
    if ($exercise->load($exId) || $is_allowedToEdit) {
        if ($exercise->getVisibility() == 'VISIBLE' || $is_allowedToEdit) {
            $question = new Question();
            if ($question->load($quId)) {
                $attachmentFile = $question->getQuestionDirSys() . $question->getAttachment();
                if (claro_send_file($attachmentFile)) {
                    die;
                } else {
                    $dialogBox->error(get_lang('Not found'));
                }
            } else {
                $dialogBox->error(get_lang('Not found'));
            }
        } else {
            $dialogBox->error(get_lang('Not allowed'));
}
// general parameters passed via POST/GET
if (empty($origin)) {
    $origin = Security::remove_XSS($_REQUEST['origin']);
}
if (empty($objExercise)) {
    $objExercise = $_SESSION['objExercise'];
}
if (empty($remind_list)) {
    $remind_list = isset($_REQUEST['remind_list']) ? $_REQUEST['remind_list'] : null;
}
$exe_id = isset($_REQUEST['exe_id']) ? intval($_REQUEST['exe_id']) : 0;
if (empty($objExercise)) {
    // Redirect to the exercise overview
    // Check if the exe_id exists
    $objExercise = new Exercise();
    $exercise_stat_info = $objExercise->getStatTrackExerciseInfoByExeId($exe_id);
    if (!empty($exercise_stat_info) && isset($exercise_stat_info['exe_exo_id'])) {
        if ($exercise_stat_info['status'] == 'incomplete') {
            $objExercise->read($exercise_stat_info['exe_exo_id']);
        } else {
            header("Location: overview.php?exerciseId=" . $exercise_stat_info['exe_exo_id']);
            exit;
        }
    } else {
        api_not_allowed(true);
    }
}
$gradebook = '';
if (isset($_SESSION['gradebook'])) {
    $gradebook = $_SESSION['gradebook'];
 /**
  * return the number of question of a category id in a test
  * @param int $exerciseId
  * @param int $categoryId
  *
  * @return integer
  *
  * @author hubert.borderiou 07-04-2011
  */
 public static function getNumberOfQuestionsInCategoryForTest($exerciseId, $categoryId)
 {
     $nbCatResult = 0;
     $quiz = new Exercise();
     $quiz->read($exerciseId);
     $tabQuestionList = $quiz->selectQuestionList();
     // the array given by selectQuestionList start at indice 1 and not at indice 0 !!! ? ? ?
     for ($i = 1; $i <= count($tabQuestionList); $i++) {
         if (TestCategory::getCategoryForQuestion($tabQuestionList[$i]) == $categoryId) {
             $nbCatResult++;
         }
     }
     return $nbCatResult;
 }
Exemple #24
0
       );*/
     $new_result = array();
     if (!empty($result)) {
         foreach ($result as $item) {
             $item['display_text'] = $item['displayText'];
             $item['field_type'] = $obj->get_field_type_by_id($item['fieldType']);
             $item['changeable'] = $item['changeable'] ? Display::return_icon('check-circle.png', get_lang('Invisible')) : Display::return_icon('closed-circle.png', get_lang('Visible'), null, ICON_SIZE_SMALL);
             $item['visible'] = $item['visible'] ? Display::return_icon('check-circle.png', get_lang('Invisible')) : Display::return_icon('closed-circle.png', get_lang('Visible'), null, ICON_SIZE_SMALL);
             $item['filter'] = $item['filter'] ? Display::return_icon('check-circle.png', get_lang('Invisible')) : Display::return_icon('closed-circle.png', get_lang('Visible'), null, ICON_SIZE_SMALL);
             $new_result[] = $item;
         }
         $result = $new_result;
     }
     break;
 case 'get_exercise_grade':
     $objExercise = new Exercise();
     $exercises = $objExercise->getExercisesByCouseSession($_GET['course_id'], $_GET['session_id']);
     $cntExer = 4;
     if (!empty($exercises)) {
         $cntExer += count($exercises);
     }
     $columns = array();
     //Get dynamic column names
     $i = 1;
     $column_names = array();
     foreach (range(1, $cntExer) as $cnt) {
         switch ($cnt) {
             case 1:
                 $columns[] = 'session';
                 $column_names[] = get_lang('Section');
                 break;
 /**
  * Restore Quiz
  */
 function restore_quizzes($session_id = 0, $respect_base_content = false)
 {
     if ($this->course->has_resources(RESOURCE_QUIZ)) {
         $table_qui = Database::get_course_table(TABLE_QUIZ_TEST);
         $table_rel = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
         $table_doc = Database::get_course_table(TABLE_DOCUMENT);
         $resources = $this->course->resources;
         foreach ($resources[RESOURCE_QUIZ] as $id => $quiz) {
             if (isset($quiz->obj)) {
                 //For new imports
                 $quiz = $quiz->obj;
             } else {
                 //For backward compatibility
                 $quiz->obj = $quiz;
             }
             $doc = '';
             if (!empty($quiz->sound)) {
                 if (isset($this->course->resources[RESOURCE_DOCUMENT][$quiz->sound]) && $this->course->resources[RESOURCE_DOCUMENT][$quiz->sound]->is_restored()) {
                     $sql = "SELECT path FROM " . $table_doc . " WHERE c_id = " . $this->destination_course_id . "  AND id = " . $resources[RESOURCE_DOCUMENT][$quiz->sound]->destination_id;
                     $doc = Database::query($sql);
                     $doc = Database::fetch_object($doc);
                     $doc = str_replace('/audio/', '', $doc->path);
                 }
             }
             if ($id != -1) {
                 // check resources inside html from fckeditor tool and copy correct urls into recipient course
                 $quiz->description = DocumentManager::replace_urls_inside_content_html_from_copy_course($quiz->description, $this->course->code, $this->course->destination_path, $this->course->backup_path, $this->course->info['path']);
                 global $_custom;
                 if (isset($_custom['exercises_clean_dates_when_restoring']) && $_custom['exercises_clean_dates_when_restoring']) {
                     $quiz->start_time = null;
                     $quiz->end_time = null;
                 }
                 $params = array('c_id' => $this->destination_course_id, 'title' => self::DBUTF8($quiz->title), 'description' => self::DBUTF8($quiz->description), 'type' => isset($quiz->quiz_type) ? $quiz->quiz_type : $quiz->type, 'random' => $quiz->random, 'active' => $quiz->active, 'sound' => self::DBUTF8($doc), 'max_attempt' => (int) $quiz->max_attempt, 'results_disabled' => (int) $quiz->results_disabled, 'access_condition' => $quiz->access_condition, 'start_time' => $quiz->start_time, 'pass_percentage' => $quiz->pass_percentage, 'end_time' => $quiz->end_time, 'feedback_type' => (int) $quiz->feedback_type, 'random_answers' => (int) $quiz->random_answers, 'random_by_category' => $quiz->random_by_category, 'review_answers' => $quiz->review_answers, 'propagate_neg' => $quiz->propagate_neg, 'text_when_finished' => $quiz->text_when_finished, 'expired_time' => (int) $quiz->expired_time, 'end_button' => (int) $quiz->end_button);
                 if ($respect_base_content) {
                     $my_session_id = $quiz->session_id;
                     if (!empty($quiz->session_id)) {
                         $my_session_id = $session_id;
                     }
                     $params['session_id'] = $my_session_id;
                 } else {
                     if (!empty($session_id)) {
                         $session_id = intval($session_id);
                         $params['session_id'] = $session_id;
                     }
                 }
                 $new_id = Database::insert($table_qui, $params);
             } else {
                 // $id = -1 identifies the fictionary test for collecting orphan questions. We do not store it in the database.
                 $new_id = -1;
             }
             if ($new_id && $new_id != -1) {
                 // Updates the question position
                 $exercise = new Exercise($this->destination_course_id);
                 $exercise->read($new_id);
                 $exercise->addExerciseToOrderTable();
                 $this->course->resources[RESOURCE_QUIZ][$id]->obj->destination_id = $new_id;
                 $order = 0;
                 if (!empty($quiz->question_ids)) {
                     foreach ($quiz->question_ids as $index => $question_id) {
                         $qid = $this->restore_quiz_question($question_id);
                         $question_order = $quiz->question_orders[$index] ? $quiz->question_orders[$index] : ++$order;
                         $sql = "INSERT IGNORE INTO " . $table_rel . " SET c_id = " . $this->destination_course_id . ", question_id = " . $qid . ", exercice_id = " . $new_id . ", question_order = " . $question_order;
                         Database::query($sql);
                     }
                 }
                 if (isset($quiz->categorie) && $quiz->categories) {
                     $exercise_obj = new Exercise($this->destination_course_id);
                     $exercise_obj->read($new_id);
                     $cats = array();
                     foreach ($quiz->categories as $cat) {
                         $cat_from_db = new Testcategory($cat['category_id']);
                         /*$cat_from_db = new Testcategory($cat['category_id']);
                           if ($cat_from_db && $cat_from_db->title == $cat['title']) {
                               echo '1';
                               //use the same id
                               $cats[$cat_from_db->id] = $cat['count_questions'];
                           } else {*/
                         $cat_from_db = $cat_from_db->get_category_by_title($cat['title'], $this->destination_course_id);
                         if (empty($cat_from_db)) {
                             //Create a new category in this portal
                             if ($cat['category_id'] == 0) {
                                 $category_c_id = 0;
                             } else {
                                 $category_c_id = $this->destination_course_id;
                             }
                             $new_cat = new Testcategory(null, $cat['title'], $cat['description'], null, 'simple', $category_c_id);
                             $new_cat_id = $new_cat->addCategoryInBDD();
                             $cats[$new_cat_id] = $cat['count_questions'];
                         } else {
                             $cats[$cat_from_db['iid']] = $cat['count_questions'];
                         }
                         //}
                     }
                     $exercise_obj->save_categories_in_exercise($cats);
                 }
             }
         }
     }
 }
 /**
  * return the number of question of a category id in a test
  * input : test_id, category_id
  * return : integer
  * hubert.borderiou 07-04-2011
  */
 public static function getNumberOfQuestionsInCategoryForTest($exercise_id, $category_id)
 {
     $number_questions_in_category = 0;
     $exercise = new Exercise();
     $exercise->read($exercise_id);
     $question_list = $exercise->getQuestionList();
     // the array given by selectQuestionList start at indice 1 and not at indice 0 !!! ? ? ?
     foreach ($question_list as $question_id) {
         $category_in_question = Testcategory::getCategoryForQuestion($question_id);
         if (in_array($category_id, $category_in_question)) {
             $number_questions_in_category++;
         }
     }
     return $number_questions_in_category;
 }
/**
 * Handles a given Excel spreadsheets as in the template provided
 */
function lp_upload_quiz_action_handling()
{
    global $debug;
    $_course = api_get_course_info();
    $courseId = $_course['real_id'];
    if (!isset($_POST['submit_upload_quiz'])) {
        return;
    }
    // Get the extension of the document.
    $path_info = pathinfo($_FILES['user_upload_quiz']['name']);
    // Check if the document is an Excel document
    if ($path_info['extension'] != 'xls') {
        return;
    }
    // Read the Excel document
    $data = new Spreadsheet_Excel_Reader();
    // Set output Encoding.
    $data->setOutputEncoding(api_get_system_encoding());
    // Reading the xls document.
    $data->read($_FILES['user_upload_quiz']['tmp_name']);
    $correctScore = isset($_POST['correct_score']) ? $_POST['correct_score'] : null;
    $incorrectScore = isset($_POST['incorrect_score']) ? $_POST['incorrect_score'] : null;
    $useCustomScore = isset($_POST['user_custom_score']) ? true : false;
    $propagateNegative = 0;
    if ($useCustomScore && !empty($incorrectScore)) {
        if ($incorrectScore < 0) {
            $propagateNegative = 1;
        }
    }
    // Variables
    $quiz_index = 0;
    $question_title_index = array();
    $question_name_index_init = array();
    $question_name_index_end = array();
    $score_index = array();
    $feedback_true_index = array();
    $feedback_false_index = array();
    $number_questions = 0;
    $question_description_index = array();
    // Reading all the first column items sequentially to create breakpoints
    for ($i = 1; $i <= $data->sheets[0]['numRows']; $i++) {
        if ($data->sheets[0]['cells'][$i][1] == 'Quiz' && $i == 1) {
            $quiz_index = $i;
            // Quiz title position, only occurs once
        } elseif ($data->sheets[0]['cells'][$i][1] == 'Question') {
            $question_title_index[] = $i;
            // Question title position line
            $question_name_index_init[] = $i + 1;
            // Questions name 1st position line
            $number_questions++;
        } elseif ($data->sheets[0]['cells'][$i][1] == 'Score') {
            $question_name_index_end[] = $i - 1;
            // Question name position
            $score_index[] = $i;
            // Question score position
        } elseif ($data->sheets[0]['cells'][$i][1] == 'FeedbackTrue') {
            $feedback_true_index[] = $i;
            // FeedbackTrue position (line)
        } elseif ($data->sheets[0]['cells'][$i][1] == 'FeedbackFalse') {
            $feedback_false_index[] = $i;
            // FeedbackFalse position (line)
        } elseif ($data->sheets[0]['cells'][$i][1] == 'EnrichQuestion') {
            $question_description_index[] = $i;
        }
    }
    // Variables
    $quiz = array();
    $question = array();
    $new_answer = array();
    $score_list = array();
    $feedback_true_list = array();
    $feedback_false_list = array();
    $question_description = array();
    // Getting questions.
    $k = $z = $q = $l = $m = 0;
    for ($i = 1; $i <= $data->sheets[0]['numRows']; $i++) {
        if (is_array($data->sheets[0]['cells'][$i])) {
            $column_data = $data->sheets[0]['cells'][$i];
            // Fill all column with data to have a full array
            for ($x = 1; $x <= $data->sheets[0]['numCols']; $x++) {
                if (empty($column_data[$x])) {
                    $data->sheets[0]['cells'][$i][$x] = '';
                }
            }
            // Array filled with data
            $column_data = $data->sheets[0]['cells'][$i];
        } else {
            $column_data = '';
        }
        // Fill quiz data
        if ($quiz_index == $i) {
            // The title always in the first position
            $quiz = $column_data;
        } elseif (in_array($i, $question_title_index)) {
            //a complete line where 1st column is 'Question'
            $question[$k] = $column_data;
            $k++;
        } elseif (in_array($i, $score_index)) {
            //a complete line where 1st column is 'Score'
            $score_list[$z] = $column_data;
            $z++;
        } elseif (in_array($i, $feedback_true_index)) {
            //a complete line where 1st column is 'FeedbackTrue'
            $feedback_true_list[$q] = $column_data;
            $q++;
        } elseif (in_array($i, $feedback_false_index)) {
            //a complete line where 1st column is 'FeedbackFalse' for wrong answers
            $feedback_false_list[$l] = $column_data;
            $l++;
        } elseif (in_array($i, $question_description_index)) {
            //a complete line where 1st column is 'EnrichQuestion'
            $question_description[$m] = $column_data;
            $m++;
        }
    }
    // Get answers
    for ($i = 0; $i < count($question_name_index_init); $i++) {
        for ($j = $question_name_index_init[$i]; $j <= $question_name_index_end[$i]; $j++) {
            if (is_array($data->sheets[0]['cells'][$j])) {
                $column_data = $data->sheets[0]['cells'][$j];
                // Fill all column with data
                for ($x = 1; $x <= $data->sheets[0]['numCols']; $x++) {
                    if (empty($column_data[$x])) {
                        $data->sheets[0]['cells'][$j][$x] = '';
                    }
                }
                $column_data = $data->sheets[0]['cells'][$j];
                // Array filled of data
                if (is_array($data->sheets[0]['cells'][$j]) && count($data->sheets[0]['cells'][$j]) > 0) {
                    $new_answer[$i][$j] = $data->sheets[0]['cells'][$j];
                }
            }
        }
    }
    // Quiz title.
    $quiz_title = $quiz[2];
    if ($quiz_title != '') {
        // Variables
        $type = 2;
        $random = $active = $results = $max_attempt = $expired_time = 0;
        // Make sure feedback is enabled (3 to disable), otherwise the fields
        // added to the XLS are not shown, which is confusing
        $feedback = 0;
        // Quiz object
        $exercise = new Exercise();
        //
        $quiz_id = $exercise->createExercise($quiz_title, $expired_time, $type, $random, $active, $results, $max_attempt, $feedback, $propagateNegative);
        if ($quiz_id) {
            // insert into the item_property table
            api_item_property_update($_course, TOOL_QUIZ, $quiz_id, 'QuizAdded', api_get_user_id());
            // Import questions.
            for ($i = 0; $i < $number_questions; $i++) {
                // Question name
                $question_title = $question[$i][2];
                $question_description_text = "<p></p>";
                if (isset($question_description[$i][2])) {
                    // Question description.
                    $question_description_text = "<p>" . $question_description[$i][2] . "</p>";
                }
                // Unique answers are the only question types available for now
                // through xls-format import
                $question_id = null;
                $detectQuestionType = detectQuestionType($new_answer[$i], $score_list);
                /** @var Question $answer */
                switch ($detectQuestionType) {
                    case FREE_ANSWER:
                        $answer = new FreeAnswer();
                        break;
                    case GLOBAL_MULTIPLE_ANSWER:
                        $answer = new GlobalMultipleAnswer();
                        break;
                    case MULTIPLE_ANSWER:
                        $answer = new MultipleAnswer();
                        break;
                    case UNIQUE_ANSWER:
                    default:
                        $answer = new UniqueAnswer();
                        break;
                }
                if ($question_title != '') {
                    $question_id = $answer->create_question($quiz_id, $question_title, $question_description_text, 0, $answer->type);
                }
                $total = 0;
                if (is_array($new_answer[$i]) && !empty($question_id)) {
                    $id = 1;
                    $answers_data = $new_answer[$i];
                    $globalScore = null;
                    $objAnswer = new Answer($question_id, $courseId);
                    $globalScore = $score_list[$i][3];
                    // Calculate the number of correct answers to divide the
                    // score between them when importing from CSV
                    $numberRightAnswers = 0;
                    foreach ($answers_data as $answer_data) {
                        if (strtolower($answer_data[3]) == 'x') {
                            $numberRightAnswers++;
                        }
                    }
                    foreach ($answers_data as $answer_data) {
                        $answerValue = $answer_data[2];
                        $correct = 0;
                        $score = 0;
                        if (strtolower($answer_data[3]) == 'x') {
                            $correct = 1;
                            $score = $score_list[$i][3];
                            $comment = $feedback_true_list[$i][2];
                        } else {
                            $comment = $feedback_false_list[$i][2];
                            $floatVal = (double) $answer_data[3];
                            if (is_numeric($floatVal)) {
                                $score = $answer_data[3];
                            }
                        }
                        if ($useCustomScore) {
                            if ($correct) {
                                $score = $correctScore;
                            } else {
                                $score = $incorrectScore;
                            }
                        }
                        // Fixing scores:
                        switch ($detectQuestionType) {
                            case GLOBAL_MULTIPLE_ANSWER:
                                $score /= $numberRightAnswers;
                                break;
                            case UNIQUE_ANSWER:
                                break;
                            case MULTIPLE_ANSWER:
                                if (!$correct) {
                                    //$total = $total - $score;
                                }
                                break;
                        }
                        $objAnswer->createAnswer($answerValue, $correct, $comment, $score, $id);
                        $total += $score;
                        $id++;
                    }
                    $objAnswer->save();
                    $questionObj = Question::read($question_id, $courseId);
                    switch ($detectQuestionType) {
                        case GLOBAL_MULTIPLE_ANSWER:
                            $questionObj->updateWeighting($globalScore);
                            break;
                        case UNIQUE_ANSWER:
                        case MULTIPLE_ANSWER:
                        default:
                            $questionObj->updateWeighting($total);
                            break;
                    }
                    $questionObj->save();
                } else {
                    if ($detectQuestionType === FREE_ANSWER) {
                        $questionObj = Question::read($question_id, $courseId);
                        $globalScore = $score_list[$i][3];
                        $questionObj->updateWeighting($globalScore);
                        $questionObj->save();
                    }
                }
            }
        }
        if (isset($_SESSION['lpobject'])) {
            if ($debug > 0) {
                error_log('New LP - SESSION[lpobject] is defined', 0);
            }
            $oLP = unserialize($_SESSION['lpobject']);
            if (is_object($oLP)) {
                if ($debug > 0) {
                    error_log('New LP - oLP is object', 0);
                }
                if (empty($oLP->cc) or $oLP->cc != api_get_course_id()) {
                    if ($debug > 0) {
                        error_log('New LP - Course has changed, discard lp object', 0);
                    }
                    $oLP = null;
                    Session::erase('oLP');
                    Session::erase('lpobject');
                } else {
                    $_SESSION['oLP'] = $oLP;
                }
            }
        }
        if (isset($_SESSION['oLP']) && isset($_GET['lp_id'])) {
            $previous = $_SESSION['oLP']->select_previous_item_id();
            $parent = 0;
            // Add a Quiz as Lp Item
            $_SESSION['oLP']->add_item($parent, $previous, TOOL_QUIZ, $quiz_id, $quiz_title, '');
            // Redirect to home page for add more content
            header('location: ../newscorm/lp_controller.php?' . api_get_cidreq() . '&action=add_item&type=step&lp_id=' . Security::remove_XSS($_GET['lp_id']));
            exit;
        } else {
            //  header('location: exercise.php?' . api_get_cidreq());
            echo '<script>window.location.href = "' . api_get_path(WEB_CODE_PATH) . 'exercice/admin.php?' . api_get_cidReq() . '&exerciseId=' . $quiz_id . '&session_id=' . api_get_session_id() . '"</script>';
        }
    }
}
/**
   Return the <a> html code for delete, add, clone, edit a question
   in_action = the code of the action triggered by the button
   from_exercice = the id of the current exercice from which we click on question pool
   in_questionid = the id of the current question
   in_questiontype = the code of the type of the current question
   in_questionname = the name of the question
   in_selected_course = the if of the course chosen in the FILTERING MENU
   in_courseCategoryId = the id of the category chosen in the FILTERING MENU
   in_exerciseLevel = the level of the exercice chosen in the FILTERING MENU
   in_answerType = the code of the type of the question chosen in the FILTERING MENU
   in_session_id = the id of the session_id chosen in the FILTERING MENU
   in_exercice_id = the id of the exercice chosen in the FILTERING MENU
*/
function get_action_icon_for_question($in_action, $from_exercice, $in_questionid, $in_questiontype, $in_questionname, $in_selected_course, $in_courseCategoryId, $in_exerciseLevel, $in_answerType, $in_session_id, $in_exercice_id)
{
    $res = "";
    $getParams = "&selected_course={$in_selected_course}&courseCategoryId={$in_courseCategoryId}&exerciseId={$in_exercice_id}&exerciseLevel={$in_exerciseLevel}&answerType={$in_answerType}&session_id={$in_session_id}";
    switch ($in_action) {
        case "delete":
            $res = "<a href='" . api_get_self() . "?" . api_get_cidreq() . $getParams . "&delete={$in_questionid}' onclick='return confirm_your_choice()'>";
            $res .= Display::return_icon("delete.png", get_lang('Delete'));
            $res .= "</a>";
            break;
        case "edit":
            $res = get_a_tag_for_question(1, $from_exercice, $in_questionid, $in_questiontype, Display::return_icon("edit.png", get_lang('Modify')), $in_session_id);
            break;
        case "add":
            // add if question is not already in test
            $myObjEx = new Exercise();
            $myObjEx->read($from_exercice);
            if (!$myObjEx->isInList($in_questionid)) {
                $res = "<a href='" . api_get_self() . "?" . api_get_cidreq() . $getParams . "&recup={$in_questionid}&fromExercise={$from_exercice}'>";
                $res .= Display::return_icon("view_more_stats.gif", get_lang('InsertALinkToThisQuestionInTheExercise'));
                $res .= "</a>";
            } else {
                $res = "-";
            }
            unset($myObjEx);
            break;
        case "clone":
            $url = api_get_self() . "?" . api_get_cidreq() . $getParams . "&amp;copy_question={$in_questionid}&amp;course_id={$in_selected_course}&amp;fromExercise={$from_exercice}";
            $res = Display::url(Display::return_icon('cd.gif', get_lang('ReUseACopyInCurrentTest')), $url);
            break;
        default:
            $res = $in_action;
            break;
    }
    return $res;
}
/**
 * Send a complete exercise in IMS/QTI format, from its ID
 *
 * @param int $exerciseId The exercise to export
 * @param boolean $standalone Wether it should include XML tag and DTD line.
 * @return The XML as a string, or an empty string if there's no exercise with given ID.
 */
function export_exercise_to_qti($exerciseId, $standalone = true)
{
    $exercise = new Exercise();
    if (!$exercise->read($exerciseId)) {
        return '';
    }
    $ims = new ImsSection($exercise);
    $xml = $ims->export($standalone);
    return $xml;
}
    $course_code = '';
}
if (empty($course_code)) {
    $course_code = 0;
}
$form->setDefaults(array('course_code' => (string) $course_code));
$course_info = api_get_course_info($course_code);
if (!empty($course_info)) {
    $list = new LearnpathList('', $course_code);
    $lp_list = $list->get_flat_list();
    $_course = $course_info;
    $main_question_list = array();
    foreach ($lp_list as $lp_id => $lp) {
        $exercise_list = ExerciseLib::get_all_exercises_from_lp($lp_id, $course_info['real_id']);
        foreach ($exercise_list as $exercise) {
            $my_exercise = new Exercise();
            $my_exercise->read($exercise['path']);
            $question_list = $my_exercise->selectQuestionList();
            $exercise_stats = get_all_exercise_event_from_lp($exercise['path'], $course_info['real_id'], $session_id);
            foreach ($question_list as $question_id) {
                $question_data = Question::read($question_id);
                $main_question_list[$question_id] = $question_data;
                $quantity_exercises = 0;
                $question_result = 0;
                foreach ($exercise_stats as $stats) {
                    if (!empty($stats['question_list'])) {
                        foreach ($stats['question_list'] as $my_question_stat) {
                            if ($question_id == $my_question_stat['question_id']) {
                                $question_result = $question_result + $my_question_stat['marks'];
                                $quantity_exercises++;
                            }