Code Search for Developers
 
 
  

contents.php from pointcarre at Krugle


Show contents.php syntax highlighted

<?php //$id: $
/*
----------------------------------------------------------------------
Dokeos - elearning and course management software

Copyright (c) 2004 Dokeos S.A.
Copyright (c) Denes Nagy (darkden@freemail.hu)

For a full list of contributors, see "credits.txt".
The full license can be read in "license.txt".

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

See the GNU General Public License for more details.

Contact: Dokeos, 181 rue Royale, B-1000 Brussels, Belgium, info@dokeos.com
----------------------------------------------------------------------
*/
/**
============================================================================== 
*	Show the table of contents of a scorm-based tutorial
*
* This script is a double-pass script. When called, it initialises stuff
* (generally depending on $menu or $openfirst parameters), then calls
* the opensco.php script which opens the content in another frame and
* calls this script back without any action parameter.
*	@author   Denes Nagy <darkden@freemail.hu>
*	@author   Yannick Warnier <yannick.warnier@dokeos.com>
*	@access   public
*
*	@package dokeos.scorm
*
============================================================================== 
*/

//Initialisation includes
$langFile = "scorm";
require('../inc/claro_init_global.inc.php');
include_once(api_get_library_path().'/database.lib.php');
include('XMLencode.php');
include('scormparsing.lib.php');

//error_log($_SERVER['REQUEST_URI']."---menu=".$_POST['menu'],0);
//error_log("---Script started. s_identifier is now:".$_SESSION['s_identifier']." and old s_identifier is now:".$_SESSION['old_sco_identifier'],0);

//Parameters reception
$edoceo			= $_GET['edoceo'];
$openDir		= $_REQUEST['openDir'];
$menu					= $_REQUEST['menu'];
$openfirst	= $_REQUEST['openfirst'];
//$request_file must be like this : http://localhost/root/Dokeos/Scorm_content1/imsmanifest.xml
//with SERVER_NAME (=127.0.0.1) it does not work
$request_file		= $_REQUEST['file'];
//$s_identifier		= $_SESSION['s_identifier'];
$_uid					= $_SESSION['_uid'];

//Charset settings (very important for imported contents)
$charset = GetXMLEncode($_GET['file']);
header('Content-Type: text/html; charset='. $charset);
//The following charset describes the encoding of most language files
//For further enhancements and in order to ensure internationalisation, we
//should make every language file UTF-8, or adapt get_lang to be able to sort
//out the file encoding and use htmlentities if required.
//If using unicode characters (courses in non-european alphabets), change this
//to $charset_lang = 'UTF-8';
$charset_lang = 'ISO-8859-15';

//Latest language inits
$array_status=array(
					'completed' => get_lang('ScormCompstatus'),
					'passed' => get_lang('ScormPassed'),
					'failed' => get_lang('ScormFailed'),
					'incomplete' => get_lang('ScormIncomplete'),
					'not attempted' => get_lang('ScormNotAttempted')
);


//Database table names init
$TBL_SCORM_MAIN     = Database::get_scorm_main_table();
$TBL_SCORM_SCO_DATA = Database::get_scorm_sco_data_table();

//if the last sco visited hasn't been closed, mark it complete:
if(!empty($_SESSION['last_sco_closed']) && !empty($_SESSION['old_sco_identifier'])){
	if($_SESSION['last_sco_closed'] != $_SESSION['old_sco_identifier']){
		$sql = "SELECT status FROM $TBL_SCORM_SCO_DATA 
			WHERE contentId='".$_SESSION['contentId']."' 
			and scoIdentifier='".$_SESSION['old_sco_identifier']."' 
			and studentId='".$_SESSION['_uid']."'";
		$result = api_sql_query($sql,__FILE__,__LINE__);
		if(mysql_num_rows($result)==1){
			$my_row = mysql_fetch_row($result);
			$my_status=$my_row[0];
			if($my_status == 'not attempted'){
				$sql = "UPDATE $TBL_SCORM_SCO_DATA 
					SET score='0', status='completed', time='00:00' 
					WHERE (studentId='".$__SESSION['_uid']."' 
						and scoIdentifier='".$_SESSION['old_sco_identifier']."' 
						and contentId='".$_SESSION['contentId']."')";
				$result = api_sql_query($sql,__FILE__,__LINE__);
				$_SESSION['last_sco_closed'] = $_SESSION['old_sco_identifier'];
			}
		}
	}
}

//Backup latest SCO-identifier opened (to use as reference to the last element seen in closesco.php) 
//This operation needs only to be done when the user takes an action, not on automatic reloading
//of the script. This is checked with the $menu parameter (set on user actions)

$_SESSION['old_sco_identifier'] = $_SESSION['s_identifier'];

//Special condition to avoid buggy database refresh in case of restart (see closesco.php)
if($_SESSION['just_started']==true){
	//error_log("Content was just started - prevent saving last element",0);
	$_SESSION['dont_save_last']=true;
	$_SESSION['just_started']=false;
}else{
	//error_log("Content was not just started - allow saving last element",0);
	$_SESSION['dont_save_last']=false;
}


//Ensure the items array (TOC) and other session variables are really erased on first visit or on restart
if ($openfirst == 'yes' or $menu == 'restart'){
	//error_log("Openfirst or restart was set (unset session[s_identifier] and session[old_sco_identifier]",0);
	//api_session_unregister('items');
	$_SESSION['items'] = array();
	$items = array();
	$_SESSION['items_dictionary'] = array();
	$items_dictionary = array();
	$_SESSION['defaultorgtitle'] = '';
	$defaultorgtitle = '';
	$_SESSION['contentId'] = '';
	if($menu == 'restart'){
		$_SESSION['just_started']=true;
	}
	unset($_SESSION['s_identifier']);
	unset($_SESSION['sco_identifier']);
	unset($_SESSION['old_sco_identifier']);
}else{
	//error_log("Openfirst or restart was NOT set",0);
	$items = $_SESSION['items'];
	$defaultorgtitle = $_SESSION['defaultorgtitle'];
	if(!empty($menu)){
		$_SESSION['just_started']=false;
	}
}

//HTML start

$output = '<html>
<head>
<link rel="stylesheet" type="text/css" href="../css/scorm.css">
</head>
<body>';

//incoming variables :
//- $request_file
//- $tabledraw -> if true, then the program draws a help table for showing imsmanifest.xml tags (technical)


// More init (display tweaks)
$tabledraw=false;  //if true, then technical information is shown
$wrap=true; //if false then the toc is not in a table, if true, then it is
$tablewidth=255;  //this is the width of the content tables

$defaultorgref='';
$version='0.0';
$inorg=false; //whether we are inside an organisation or not
$intitle=$inmeta=$ingeneral=false;
$inversion=false;
$prereq=false;
$initem=0; //how deep we are in the hieracrchy of itmes
$itemindex=0;
$previouslevel=1;
$clusterinfo=0;

$exit_after_menu = false; //used to disable printing of javascript redirections in output.

/**
 * This function displays a message in the message frame.
 *
 * For some reason (apparently JavaScript reasons), the message shown 
 * cannot be more than 66 characters. Together with the enveloppe, it 
 * gets to something around 250 characters, which apparently is too 
 * big for the "write" method 
 * @param		string	The message to show. Should be smaller than 66 characters.
 * @return void	Doesn't return anything, just writes to the message frame.
 */
function message($text) {
	//ugly little patch for text encoding of accentuated characters - see other comments on 'accentuated' characters
	// and improvements to this patch below in this file
	#global $charset_lang;
	#$text = htmlentities($text,ENT_QUOTES,$charset_lang);
	$string = "<script language='Javascript' type='text/javascript'>".
		"zwindow=open('','message');".
		"s='<html><head><link rel=\"stylesheet\" type=\"text/css\" href=\"../css/scorm.css\"></head><body>".
		"<div class=\"message\">$text</div></body></html>';".
		"z=zwindow.document;".
		"z.write(s);".
		"z.close();".
		"</script>";
	return $string;
}



/****************************************** PROCESSING **********************************/
//Real processing starts here

//1. Check whether we need to build the TOC ($items array) or if it already exists
if($openfirst=='yes' or $menu=='restart'){
	//error_log("Openfirst or restart was set (generate $items)",0);

	/*====================
	  PARSING THE XML FILE
	  ====================*/
	//1.1
	if (!(list($xml_parser, $fp) = new_xml_parser($request_file))) {
	   die("<font color='red'>Error : could not open XML input - $request_file</font>");
	}
	
	//my variables : $xml_parser, new_xml_parser()
	
	if ($tabledraw) {
	  $output .= "<table border='0'>"
			."<tr>"
				."<td>Row</td>"
				."<td>Inorg</td>"
				."<td>Initem</td>"
				."<td>Tag name</td>"
				."<td>Attributes</td>"
			."</tr>";
	}

	while ($data = fread($fp, 4096)) {  //reads the file in 4096 byte amounts
	   if (!xml_parse($xml_parser, $data, feof($fp))) {
		   die(sprintf("XML error: %s at line %d\n",
					   xml_error_string(xml_get_error_code($xml_parser)),
					   xml_get_current_line_number($xml_parser)));
	   }
	}
	if ($tabledraw) {
	  $output .= "</table>";  
	  $output .= "parse complete<br /><hr />";  
	  $output .= "<br />Total lines in xml file : ";
	  $output .= xml_get_current_line_number($xml_parser);  
	  $output .= " (xml_get_current_line_number)";  
	  $output .= "<br /><br />";
	}

	//build an index of items (item identifier => item index in $items). This should improve parsing speed.
	foreach($items as $key => $content){
		$items_dictionary[$content['identifier']] = $key;
	}
	$_SESSION['items_dictionary'] = $items_dictionary;
	
	//As we asked to start from the beginning, set the current identifier to the first elem's
	$i=1;
	for(;$items[$i]['href']=='';$i++){
		/*do nothing (get the index of the first item of href<>'')*/
	}
	$_SESSION['s_identifier'] = $items[$i]['identifier'];
	$href=api_get_path('WEB_COURSE_PATH').$_course['path']."/scorm".$openDir."/".$items[$i]['href'];
	//error_log("New s_identifier calculated: ".$_SESSION['s_identifier']." - Old one is: ".$_SESSION['old_sco_identifier'],0);

}



//2. Compute the maximum depth level ot the TOC.
//		For fixed width : width=$tablewidth (in two tables) and enable nbsp substitution in two places
// 	$items is a result of the imsmanifest.xml parsing
$maxlevel=1;
$i=1;

while ($items[$i]) {
  if (($items[$i]['level'])>$maxlevel) { $maxlevel=$items[$i]['level']; }
  $i++;
}



//3. Check if the content was ever opened or not, 
//			If not, add a line to scorm_main with the title and course code to record its existence
$sql = "SELECT dokeosCourse FROM $TBL_SCORM_MAIN WHERE "
			." (contentTitle='".$openDir."' and dokeosCourse='".$_course['official_code']."')";
$result = api_sql_query($sql,__FILE__,__LINE__);
$numrows = mysql_num_rows($result);

if ($numrows==0) { //this means that this Scorm content was never opened by anyone in this dokeos course
	//$result = api_sql_query("SELECT MAX(contentId) FROM $TBL_SCORM_MAIN");
	//$ar = mysql_fetch_array($result);
	//$maxcontentId = $ar['MAX(contentId)']+1;
	$sql = "INSERT INTO $TBL_SCORM_MAIN (contentTitle, dokeosCourse) VALUES "
			." ('".$openDir."','".$_course['official_code']."')";
	$result = api_sql_query($sql,__FILE__,__LINE__);
}

//4. Get the contentId for this content (whether it has just been inserted or not) to check if the
//			current user ever opened it.
$sql = "SELECT contentId FROM $TBL_SCORM_MAIN "
        ." WHERE (contentTitle='".$openDir."' and dokeosCourse='".$_course['official_code']."')";

$result = api_sql_query($sql,__FILE__,__LINE__);
$ar = mysql_fetch_array($result);
$mycontentId = $ar['contentId']; //it has to exist, because the previous step checked it existed and if not inserted it
$_SESSION['contentId'] = $mycontentId;

$everopened = true;
$numrows2 = 0; 
$result2='';
$sql2 = "SELECT * FROM $TBL_SCORM_SCO_DATA WHERE (studentId='$_uid' and contentId='$mycontentId')";
$result2 = api_sql_query($sql2,__FILE__,__LINE__);
$numrows2 = mysql_num_rows($result2);

if ($numrows2 == 0) { //this means that this Scorm content was not opened by the current student
	$everopened = false;
}


/*if($openfirst=='yes' or $menu='restart'){
	$s_identifier = $items[1]['identifier'];
	$href=api_get_path('WEB_COURSE_PATH').$_course['path']."/scorm".$openDir."/".$items[1]['href'];
	$output .= "<script language='Javascript' type='text/javascript'>",
		"nextwindow=open('opensco.php?sco_href=$href&sco_identifier=$s_identifier&file=$request_file&edoceo=$edoceo&openDir=$openDir','message');",
		"</script>";
}*/



/*=========================
  IF RESTART WAS CLICKED...
  =========================*/
//5 If the user clicked on "restart", the $items array has been cleaned 
// and no element has any special mark whatsoever, except the first one which is highlighted
if ( $menu == 'restart' ) { //Restrart clicked
	//error_log("Restart was set...",0);
	if ( $version == '1.1' ) {
		//5.1.a Ignore if version of SCORM is <1.2 (or that's basically what is intended)
		//display warning message in message frame (side-menu bottom)
		$output .= message(htmlentities(get_lang('ScormNoStatus'),ENT_QUOTE,$charset_lang)); 
	} else {
		//error_log("Update database for restart",0);
		//5.1.b.1 Loads a blank page in the "sco" frame, probably to enable scorm API reinit
		//$output .= "<script language='Javascript' type='text/javascript'>
		//	xwindow=open('about:blank','sco');
		//	</script>";
		
		//5.1.b.2 update the status for the current user and content in the SCORM data table
		$sql = "UPDATE $TBL_SCORM_SCO_DATA SET score='0', status='not attempted', time='00:00' "
							." WHERE (studentId='$_uid' and contentId='$mycontentId')";
		$result = api_sql_query($sql,__FILE__,__LINE__);
		//5.1.b.3 clean session vars about this content
		api_session_unregister('s_href');
		$i=1;
		for(;$items[$i]['href']=='';$i++){/*do nothing, just get the index of first elem with href*/}
		$_SESSION['s_identifier'] = $items[$i]['identifier'];
		//error_log("New s_identifier generated: ".$_SESSION['s_identifier'],0);
		//api_session_unregister('s_identifier');
		//5.1.b.4 display info message in message frame (side-menu bottom)
		//$output .=message("<img src=\'../img/restart.jpg\' alt='restart'/>".get_lang('ScormRestarted'));//the img tag fails because of the htmlentities() call in message()
		//$output .=message(htmlentities(get_lang('ScormRestarted'),ENT_QUOTES,$charset_lang));
	}
 //that's all for the special "restart" treatment, although it includes loading the scorm document - see rest of script

}elseif (($menu=='prev') or ($menu=='next')) {
	//error_log("Menu was 'prev' or 'next'",0);

	/*==============================
	  IF PREV OR NEXT WAS CLICKED...
	  ==============================*/
	//5.2.15 If 'previous' or 'next' were clicked, then we might need to reload this script in order
	// to gain benefits of the database updates before we display the TOC
	
	if ($version=='1.3') { 
		$output .=message('Sequencing for 1.3 not yet available'); 
	}
	else 
	{
		// if the current identifier is empty, set to first item identifier
		if (empty($_SESSION['s_identifier'])) { 
			$i=1;
			for(;$items[$i]['href']=='';$i++){/*get index of first elem with href*/}
			$_SESSION['s_identifier']=$items[$i]['identifier'];	
			//error_log("s_identifier was empty - new one: ".$_SESSION['s_identifier'],0);
			
		}
		
		$i=1; 
		if($openfirst == 'yes'){
		 //do nothing so that we start on first element
		 //$s_identifier = $items[1]['identifier'];
			//error_log("Openfirst was set, found first valid elem: ".$items[$i]['identifier'],0);
			for(;$items[$i]['href']=='';$i++){/*get index of first elem with href*/}
		}else{
			$i = $items_dictionary[$_SESSION['s_identifier']];
			
			if ($menu=='next') {
				//error_log("Menu was 'next'",0);

				do {  // we take the next sco which has a href
					$i++;
				} while (($items[$i]['href'] == '') and ($i <= count($items)));
				if ($i>count($items)) { 
					$output .=message(htmlentities(get_lang('ScormNoNext'),ENT_QUOTES,$charset_lang)); 
					#echo $output; 
					$exit_after_menu=true; 
				}
			}
			if ($menu=='prev') {
				//error_log("Menu was 'prev'",0);
				do {  // we take the previous sco which has href
					$i--;
				} while (($items[$i]['href'] == '') and ($i >= 1));
				if ($i<1) { 
					$output .=message(htmlentities(get_lang('ScormNoPrev'),ENT_QUOTES,$charset_lang)); 
					#echo $output; 
					$exit_after_menu=true; 
				}
			}
		}
		//sco opening begin
		$href=api_get_path('WEB_COURSE_PATH').$_course['path']."/scorm".$openDir."/".$items[$i]['href'];
		$_SESSION['s_identifier'] = $items[$i]['identifier'];
		//error_log("New s_identifier: ".$_SESSION['s_identifier']." - Old one is: ".$_SESSION['old_sco_identifier'],0);
		//$s_identifier = $identifier;	
	}
}elseif ($menu=='my_status') {
	//error_log("Menu was 'my_status'",0);

/*===========================
  IF MY STATUS WAS CLICKED...
  ===========================*/
//6. The user chose to display the status screen. 
// @todo It is a very bad idea to mix status display and the rest of the TOC display.
//  Ideally, this should be fixed by including here two different display scripts depending on what to display.
	
	//allows to not highlight an element if currently displaying status
	$_SESSION['displaying_status']=true;
	
	if ($version=='1.1') { 
		$output .=message(htmlentities(get_lang('ScormNoStatus'),ENT_QUOTES,$charset_lang)); 
	} else {
		$w=$tablewidth-20;
		$output .= "<br />";
	
		//if display in fullscreen required
		if (strcmp($_GET["fs"],"true")==0)
		{ $output .= "<table align='center'>"; }

		else
		{ $output .= "<table class='margin_table'>"; }
		
		$output .="<tr><td><div class='title'>".htmlentities(get_lang('ScormMystatus'),ENT_QUOTES,$charset_lang)."</div></td></tr>"
			."<tr><td>&nbsp;</td></tr>"
			."<tr><td>"
				."<table border='0' class='data_table'><tr>\n"
					."<td><div class='mystatusfirstrow'>".htmlentities(get_lang('ScormLessonTitle'),ENT_QUOTES,$charset_lang)."</div></td>\n"
					."<td><div class='mystatusfirstrow'>".htmlentities(get_lang('ScormStatus'),ENT_QUOTES,$charset_lang)."</div></td>\n"
					."<td><div class='mystatusfirstrow'>".htmlentities(get_lang('ScormScore'),ENT_QUOTES,$charset_lang)."</div></td>\n"
					."<td><div class='mystatusfirstrow'>".htmlentities(get_lang('ScormTime'),ENT_QUOTES,$charset_lang)."</div></td></tr>\n";

		//going through the items using the $items[] array instead of the database order ensures
		// we get them in the same order as in the imsmanifest file, which is rather random when using
		// the database table
		foreach($items as $i => $myitem ) {
			$sql="SELECT * FROM $TBL_SCORM_SCO_DATA 
				WHERE (studentId='$_uid' 
				AND contentId='".$mycontentId."' 
				AND scoIdentifier = '".$myitem['identifier']."')";// order by scoId";
			$result = api_sql_query($sql,__FILE__,__LINE__);
			$ar = mysql_fetch_array($result);

			$counter++;
			if (($counter % 2)==0) { $oddclass="row_odd"; } else { $oddclass="row_even"; }

			$lesson_status=$ar['status'];
			$score=$ar['score'];
			$time=$ar['time'];
			$scoIdentifier=$ar['scoIdentifier'];
			$title=$myitem['title'];
			if (strlen($title)>65) {
				$title=substr($title,0,64);
				$title.="...";
			}
			//$title=str_replace(' ','&nbsp;',$title);
			//Remove "NaN" if any (@todo: locate the source of these NaN)
			$time = str_replace('NaN','00',$time);
			if (($lesson_status=='completed') or ($lesson_status=='passed')) { $color='green'; } else { $color='black'; }
			$output .= "<tr class='$oddclass'>\n"
						."<td><div class='mystatus'>$title</div></td>\n"
						."<td><font color='$color'><div class='mystatus'>".htmlentities($array_status[$lesson_status],ENT_QUOTES,$charset_lang)."</div></font></td>\n"
						."<td><div class='mystatus' align='center'>".($score==0?'-':$score)."</div></td>\n"
						."<td><div class='mystatus'>$time</div></td>\n"
					."</tr>\n";
		}

		$output .= "</table></td></tr></table>";
	}
	$output .= "</body></html>";
	//We just wanted the status, so skip the rest now (we don't need any footer anyway)
	echo $output;
	exit();
}
//echo "<pre>".print_r($items,true)."</pre>";
//if the action requested is any of restart, openfirst, next or prev, open the content in the content frame
//This is done by calling opensco.php in the 'message' frame, which in turn calls the document in the 'sco' frame.
if(($menu=='restart' or $menu=='next' or $menu=='prev' or $openfirst=='yes') and ($exit_after_menu==false)){
	//error_log("Menu was 'prev' or 'next' or restart or openfirst was set and could include javascript for opensco and contents.php.",0);
	//error_log('get_better_anchor_target returned '.$target_identifier,0);
	$output .= "<script language='Javascript' type='text/javascript'>".
		"nextwindow=open('opensco.php?sco_href=".base64_encode($href)."&sco_identifier=".$_SESSION['s_identifier']
				."&file=$request_file&edoceo=$edoceo&openDir=$openDir','message');".
		//this line enables the movement of the menu
				//"thiswindow=open('contents.php?file=$request_file&openDir=$openDir&time=$time&edoceo=$edoceo#$identifier','contents');".
				"thiswindow=open('contents.php?file=$request_file&openDir=$openDir&time=$time&edoceo=$edoceo','contents');".
				"</script>";
			//sco opening end
}


/*=======================
  TABLE OF CONTENTS TITLE
  =======================*/
//6. If we are here, it's only because the user didn't choose the status display 
//   (otherwise we would have exited). SHOW the TOC here... 
//6.1 Deal with the title
$t=$defaultorgtitle;
$t=str_replace(' ','&nbsp;',$t);
if ($wrap) {
	$output .= "<div><b>$defaultorgtitle</b></div><br />";
} else {
	$output .= "<table border='0' cellspacing='0' cellpadding='0' width='$tablewidth'>
		<tr>
			<td>
				<div><b>$t</b></div>
			</td>
		</tr>
	</table>
	<br />
	<table border='0' cellspacing='0' cellpadding='0' width='$tablewidth'>";
}

//remember the title in the session (for later reuse)
$_SESSION['defaultorgtitle'] = $defaultorgtitle;

/*====================================
  TABLE OF CONTENTS LISTING ROW BY ROW
  ====================================*/
//6.2 Displaying TOC

//$output .= "<pre>".print_r($items,true)."</pre>";

//6.2.1 Init vars to compute total items completed
$num_of_completed=0;
$i=1;

while ($items[$i]) {
	//error_log("Now processing item $i: ".$items[$i]['identifier'],0);

	//6.2.2 Set whether to highlight the item or not (don't highlight if displaying status)
	$bold = false;
	if( ( $items[$i]['identifier'] == $_SESSION['s_identifier']) && (!$_SESSION['displaying_status'])){
		//error_log("Item is the current one",0);
		$bold = true;
	}
	
	if (!$wrap) { $output .= "<tr>"; } //do not wrap this item with the previous one }
	
	//6.2.3 if this user never opened this content 
	// make initial entries in the scorm data table for this student
	// the order of insertions is the same as in the file (so it is the one we want to keep for status display)
	// $index comes from outside this script and represents the scoId in the table
	if ($everopened==false) { 
		$sql = "INSERT INTO $TBL_SCORM_SCO_DATA "
					."(contentId, scoId, scoIdentifier, scoTitle, status, studentID, score, time)VALUES "
					."('".$mycontentId."','".$index."','".$items[$i]['identifier']."','"
					.addslashes($items[$i]['title'])."','not attempted','".$_uid."','0','00:00')";
		$result = api_sql_query($sql,__FILE__,__LINE__);
	}
	
	//6.2.4 Display spaces/cells an amount of time that corresponds to the depth of the element in the hierarchy
	if ($wrap) { 
		$output .= str_repeat("&nbsp;&nbsp;",$items[$i]['level']-1); 
	} else { 
		$output .= "<td>".str_repeat("&nbsp;&nbsp;",$items[$i]['level']-1)."</td>"; 
	}
	$col=$maxlevel-$items[$i]['level']+1; //prepare the number of columns to display
	if (!$wrap) { $output .= '<td colspan="'.$col.'"><table border="0" cellspacing="0" cellpadding="0">'; }
	
	//6.2.5 Get the document/content path
	//$href="../../courses/$_course[path]/scorm".$openDir."/".urlencode($items[$i]['href']);
	if(substr($items[$i]['href'],0,4)=='http'){
		$href = $items[$i]['href'];
	}else{
		$href=api_get_path('WEB_COURSE_PATH').$_course['path']."/scorm".$openDir."/".$items[$i]['href'];
	}
	//6.2.6 Get useful values in practical variables
	$identifier=$items[$i]['identifier'];
	$prereq=$items[$i]['prereq'];
	
	//6.2.7 Get the recorded status for this document/content
	$sql3 = "SELECT status FROM $TBL_SCORM_SCO_DATA WHERE "
				." (contentId='$mycontentId' and studentId='$_uid' and scoIdentifier='$identifier')";
	$result3 = api_sql_query($sql3,__FILE__,__LINE__);
	$ar3=mysql_fetch_array($result3);
	$lesson_status=$ar3['status'];
	
	//6.2.8 Count this lesson as completed if applicable
	if (($lesson_status == 'completed') or ($lesson_status == 'passed')) { $num_of_completed++; }
	
	//6.2.9 display this document/content name as a link to the document/content itself
	if ($items[$i]['href']!='') {
		if (!$wrap) { $output .= "<tr><td>"; } //display choice
		
		//6.2.9.1 if the lesson was completed, display a little icon
		if (($lesson_status=='completed') or ($lesson_status=='passed')) { 
			$output .= '<img src="../img/checkbox_on2.gif" border="0" width="13" height="11" alt="on"/>'; 
		} else {
			//insert the image but make it invisible, so that the space taken is identical (no movement when image appears)
			$output .= '<img src="../img/checkbox_on2.gif" border="0" width="13" height="11" alt="on" style="visibility: hidden"/>'; 
			//$output .= "&nbsp;"; 
		}
		
		if (!$wrap) { $output .= "</td><td>"; } //display choice
		
		//6.2.9.2 Add HTML anchor
		$output .= "<a name='$identifier'>";
		//6.2.9.3 Highlight if applicable
		if ($bold) { $output .= "<b>";}
		//6.2.9.4 Display the link
		$output .= "<a href='opensco.php";
		if ($version=='1.3') { //SCORM version 1.3
			if ($items[$i]['parameters']!='') { 
				// there should probably be an additional '?' here... maybe...
				$output .= "{$items[$i]['parameters']}"."&"; //add parameters to the link 
			} else { 
				$output .= "?"; 
			}
		} else { //version is not 1.3 
			$output .= "?"; 
		}
		
		$output .= "sco_href=".base64_encode($href)."&sco_identifier=$identifier&file=$request_file&edoceo=$edoceo&openDir=$openDir' target='message' class='";
		//as you might realise, this links points to the message frame, to opensco.php, which will then open the content
		//in the contents frame
		
		//change CSS class to "completed" if completed or passed
		if (($lesson_status=='completed') or ($lesson_status=='passed')) { $output .= $array_status[$lesson_status]; }
		$output .= "'>"; 
		//error_log("Added link to opensco with sco_identifier=".$items[$i]['identifier'],0);

	}else{
		if (($lesson_status=='completed') or ($lesson_status=='passed')) { 
			$output .= '<img src="../img/checkbox_on2.gif" border="0" width="13" height="11" alt="on"/>'; 
		} else {
			//insert the image but make it invisible, so that the space taken is identical (no movement when image appears)
			$output .= '<img src="../img/checkbox_on2.gif" border="0" width="13" height="11" alt="on" style="visibility: hidden"/>'; 
		}
	}
	
	//6.2.10 Simulate htmlentities() just for spaces
	$t=$items[$i]['title'];
	
	//6.2.11 Display title (unfiltered if wrapped display - which is the default)
	$t=str_replace(' ','&nbsp;',$t);
	$twrap = $items[$i]['title'];
	//cut the title string if too long to fit in typical frame width
	$max_len = 37-(3*$items[$i]['level']);
	if(strlen($twrap)>$max_len){
		$twrap = str_replace(' ','&nbsp;',substr($twrap,0,$max_len-3).'...');
	}

	if (!$wrap) { $output .= $t; } else { $output .= $twrap; }
	
	if ( $items[$i]['href'] != '' ) { $output .= "</a>"; } //see above for opening anchor tag "a name=..."
	if ($bold) { $output .= "</b>";}   
	if (!$wrap) { $output .= "</td></tr></table></td></tr>\n"; } else { $output .= "<br />\n"; }
	$i++;
}

//6.2.12 Display percentage complete
if ( count($items) != 0 ) { 
    $percent=round($num_of_completed/count($items)*100); 
} else { //no item found. Display an error.
    $output .= message(htmlentities(get_lang('ScormNoItems'),ENT_QUOTES,$charset_lang)); echo $output; exit();
}

$npercent=100-$percent;
if (($percent==0) and ($openfirst=='yes') and ($version != '1.3') and ($menu=='')) { $menu="next"; } 
//ie. the first lesson appears if nothing is completed, not if in 1.3 and the user clicked onto Launch just now

if (!$wrap) { $output .= "</table>\n"; } // display-choice

/*=================
  COMPLETION STATUS
  =================*/

//6.2.13 Display the completion status of the whole learning path
//! temporary fix for the accentuated characters bug (due to different encoding
// between the imsmanifest file - which is the source to this frame's encoding - and the language file)
// The fix is temporary because it will most probably fail on any non-european special character
// To really fix this, there should be a function to check the language files' encoding and put it
// in the third argument to htmlentities() here below
$output .= '<br /><a name="statustable"></a><table border="0"><tr><td>'
    .htmlentities(get_lang('ScormCompstatus'),ENT_QUOTES,$charset_lang)."<br />"
    .'<table border="0" cellpadding="0" cellspacing="0"><tr><td>'
    .'<img src="../img/bar_1.gif" width="1" height="12">'
    .'<img src="../img/bar_1u.gif" width="'.$percent.'" height="12">'
    .'<img src="../img/bar_1m.gif" width="1" height="12">'
    .'<img src="../img/bar_1r.gif" width="'.$npercent.'" height="12">'
    .'<img src="../img/bar_1.gif" width="1" height="12"></td></tr></table>'
    ."</td><td valign=\"bottom\"><font align=\"left\"><br />$percent&nbsp;%</td></tr></table>\n";

if ($tabledraw) {
    $output .= "<br /><br /><hr /><br />";
    $i=1;
    while ($items[$i]) {
        $output .= "Index : {$items[$i]['index']} "
            ."Identifierref : {$items[$i]['identifierref']} "
            ."Identifier : {$items[$i]['identifier']} "
            ."Level : {$items[$i]['level']}   "
            ."Title : {$items[$i]['title']} "
            ."Href : {$items[$i]['href']} "
            ."Prereq : {$items[$i]['prereq']} "
            ."Parameters : {$items[$i]['parameters']} "
            ."Clusterinfo : {$items[$i]['clusterinfo']}<br />\n";
        $i++;
    }
    $output .= "<br />\n";  
    $output .= "defaultorg : $defaultorgref<br />defaultorgtitle : $defaultorgtitle";
}

//6.2.14 If the parser was used, close it (and the XML file too)
if($openfirst=='yes' or $menu=='restart'){
	xml_parser_free($xml_parser);
	fclose($fp);
}

//$openfirst='no';

/*===========================
  VERSION INFO
  ===========================*/

//$output .= "<p class=version>[ Scorm&nbsp;".get_lang('ScormVersion')."&nbsp;:&nbsp;$version ]</p>";

//if($menu=='restart'){unset($_SESSION['s_identifier']);}
$_SESSION['contentId'] = $mycontentId;
$_SESSION['items'] = $items;
//if(empty($_SESSION['old_sco_identifier'])){
//	$_SESSION['old_sco_identifier'] = $_SESSION['s_identifier'];
//}
$_SESSION['displaying_status']=false;

//if the user didn't click a menu button, then assume he clicked a SCORM button in the content,
// and that the element that needs to be updated by closesco.php is the latest element we have here,
// namely $_SESSION['s_identifier'], instead of $_SESSION['old_s_identifier']
if(empty($menu)){
	$_SESSION['old_sco_identifier'] = $_SESSION['s_identifier'];
}

//error_log("End of script (before output). s_identifier is now:".$_SESSION['s_identifier']." and old s_identifier is now:".$_SESSION['old_sco_identifier'],0);


echo $output;
//error_log("End of script (after output). s_identifier is now:".$_SESSION['s_identifier']." and old s_identifier is now:".$_SESSION['old_sco_identifier'],0);

?>
</body></html>




See more files for this project here

pointcarre

Pointcarre - a learning management system based on the Dokeos community releases. No fork, but containing locally developed extensions, features not (yet) in the standard release, integrated plugins...

Project homepage: http://sourceforge.net/projects/pointcarre
Programming language(s): PHP
License: other

  export/
    APIWrapper.js
    SCOFunctions.js
    ims_xml.xsd
    imscp_v1p1.xsd
    imsmd_v1p2.xsd
  XMLencode.php
  blank.php
  closesco.php
  contents.php
  headerpage.php
  index.php
  load.php
  opensco.php
  scormbuilder.php
  scormbuilderadditem.php
  scormbuilderbrowse.php
  scormbuilderheader.php
  scormbuilderstarter.php
  scormdocument.php
  scormfunctions.php
  scormparsing.lib.php
  showinframes.php