2 /****************************************************************/
4 /****************************************************************/
5 /* Copyright (c) 2002-2008 by Greg Gay & Joel Kronenberg */
6 /* Adaptive Technology Resource Centre / University of Toronto */
9 /* This program is free software. You can redistribute it and/or*/
10 /* modify it under the terms of the GNU General Public License */
11 /* as published by the Free Software Foundation. */
12 /****************************************************************/
14 define('AT_INCLUDE_PATH', '../../include/');
15 require(AT_INCLUDE_PATH.'classes/testQuestions.class.php');
16 require(AT_INCLUDE_PATH.'classes/A4a/A4aExport.class.php');
18 /* content id of an optional chapter */
19 $cid = isset($_REQUEST['cid']) ? intval($_REQUEST['cid']) : 0;
20 $c = isset($_REQUEST['c']) ? intval($_REQUEST['c']) : 0;
22 if (isset($_REQUEST['to_tile']) && !isset($_POST['cancel'])) {
25 /* redirect to TILE import servlet */
27 require(AT_INCLUDE_PATH.'vitals.inc.php');
28 if (!authenticate(AT_PRIV_ADMIN, AT_PRIV_RETURN)) {
29 /* user can't be authenticated */
30 header('HTTP/1.1 404 Not Found');
31 echo 'Document not found.';
35 $m = md5(DB_PASSWORD . 'x' . ADMIN_PASSWORD . 'x' . $_SERVER['SERVER_ADDR'] . 'x' . $cid . 'x' . $_SESSION['course_id'] . 'x' . date('Ymd'));
37 header('Location: '.AT_TILE_IMPORT. '?cp='.urlencode(AT_BASE_HREF. 'tools/ims/ims_export.php?cid='.$cid.'&c='.$_SESSION['course_id'].'&m='.$m));
39 } else if (isset($_GET['m'])) {
42 /* request (hopefully) coming from a TILE server, send the content package */
44 $_user_location = 'public';
45 require(AT_INCLUDE_PATH.'vitals.inc.php');
46 $m = md5(DB_PASSWORD . 'x' . ADMIN_PASSWORD . 'x' . $_SERVER['SERVER_ADDR'] . 'x' . $cid . 'x' . $c . 'x' . date('Ymd'));
47 if (($m != $_GET['m']) || !$c) {
48 header('HTTP/1.1 404 Not Found');
49 echo 'Document not found.';
57 if (isset($_REQUEST['to_a4a'])){
60 require(AT_INCLUDE_PATH.'vitals.inc.php');
61 $course_id = $_SESSION['course_id'];
64 $instructor_id = $system_courses[$course_id]['member_id'];
65 $course_desc = $system_courses[$course_id]['description'];
66 $course_title = $system_courses[$course_id]['title'];
67 $course_language = $system_courses[$course_id]['primary_language'];
69 $courseLanguage =& $languageManager->getLanguage($course_language);
70 //If course language cannot be found, use UTF-8 English
71 //@author harris, Oct 30,2008
72 if ($courseLanguage == null){
73 $courseLanguage =& $languageManager->getLanguage('en');
76 $course_language_charset = $courseLanguage->getCharacterSet();
77 $course_language_code = $courseLanguage->getCode();
79 require(AT_INCLUDE_PATH.'classes/zipfile.class.php'); /* for zipfile */
80 require(AT_INCLUDE_PATH.'classes/vcard.php'); /* for vcard */
81 require(AT_INCLUDE_PATH.'classes/XML/XML_HTMLSax/XML_HTMLSax.php'); /* for XML_HTMLSax */
82 require(AT_INCLUDE_PATH.'ims/ims_template.inc.php'); /* for ims templates + print_organizations() */
84 if (isset($_POST['cancel'])) {
85 $msg->addFeedback('EXPORT_CANCELLED');
86 header('Location: ../index.php');
91 $zipfile = new zipfile();
92 $zipfile->create_dir('resources/');
95 the following resources are to be identified:
96 even if some of these can't be images, they can still be files in the content dir.
97 theoretically the only urls we wouldn't deal with would be for a <!DOCTYPE and <form>
100 a => href // ignore if href doesn't exist (ie. <a name>)
101 object => data | classid // probably only want data
102 applet => classid | archive // whatever these two are should double check to see if it's a valid file (not a dir)
111 function MyHandler(){}
112 function openHandler(& $parser,$name,$attrs) {
115 $name = strtolower($name);
116 $attrs = array_change_key_case($attrs, CASE_LOWER);
118 $elements = array( 'img' => 'src',
120 'object' => array('data', 'classid'),
121 'applet' => array('classid', 'archive'),
130 /* check if this attribute specifies the files in different ways: (ie. java) */
131 if (is_array($elements[$name])) {
132 $items = $elements[$name];
134 foreach ($items as $item) {
135 if ($attrs[$item] != '') {
137 /* some attributes allow a listing of files to include seperated by commas (ie. applet->archive). */
138 if (strpos($attrs[$item], ',') !== false) {
139 $files = explode(',', $attrs[$item]);
140 foreach ($files as $file) {
141 $my_files[] = trim($file);
144 $my_files[] = $attrs[$item];
148 } else if (isset($elements[$name]) && ($attrs[$elements[$name]] != '')) {
149 /* we know exactly which attribute contains the reference to the file. */
150 $my_files[] = $attrs[$elements[$name]];
153 function closeHandler(& $parser,$name) { }
156 /* get all the content */
159 $top_content_parent_id = 0;
161 $handler=new MyHandler();
162 $parser =& new XML_HTMLSax();
163 $parser->set_object($handler);
164 $parser->set_element_handler('openHandler','closeHandler');
166 if (authenticate(AT_PRIV_CONTENT, AT_PRIV_RETURN)) {
167 $sql = "SELECT *, UNIX_TIMESTAMP(last_modified) AS u_ts FROM ".TABLE_PREFIX."content WHERE course_id=$course_id ORDER BY content_parent_id, ordering";
169 $sql = "SELECT *, UNIX_TIMESTAMP(last_modified) AS u_ts FROM ".TABLE_PREFIX."content WHERE course_id=$course_id ORDER BY content_parent_id, ordering";
171 $result = mysql_query($sql, $db);
172 while ($row = mysql_fetch_assoc($result)) {
173 if (authenticate(AT_PRIV_CONTENT, AT_PRIV_RETURN) || $contentManager->isReleased($row['content_id']) === TRUE) {
174 $content[$row['content_parent_id']][] = $row;
175 if ($cid == $row['content_id']) {
177 $top_content_parent_id = $row['content_parent_id'];
183 /* filter out the top level sections that we don't want */
184 $top_level = $content[$top_content_parent_id];
185 foreach($top_level as $page) {
186 if ($page['content_id'] == $cid) {
187 $content[$top_content_parent_id] = array($page);
189 /* this is a page we don't want, so might as well remove it's children too */
190 unset($content[$page['content_id']]);
193 $ims_course_title = $course_title . ' - ' . $content[$top_content_parent_id][0]['title'];
195 $ims_course_title = $course_title;
199 /* generate the imsmanifest.xml header attributes */
200 $imsmanifest_xml = str_replace(array('{COURSE_TITLE}', '{COURSE_DESCRIPTION}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}', '{COURSE_PRIMARY_LANGUAGE_CODE}'),
201 array($ims_course_title, $course_desc, $course_language_charset, $course_language_code),
202 $ims_template_xml['header']);
203 //debug($imsmanifest_xml);
206 /* get the first content page to default the body frame to */
207 $first = $content[$top_content_parent_id][0];
209 $test_ids = array(); //global array to store all the test ids
210 //if ($my_files == null)
211 //$my_files = array();
213 /* generate the IMS QTI resource and files */
215 /* in print_organizations
216 foreach ($content[0] as $content_box){
217 $content_test_rs = $contentManager->getContentTestsAssoc($content_box['content_id']);
218 while ($content_test_row = mysql_fetch_assoc($content_test_rs)){
220 $test_ids[] = $content_test_row['test_id'];
221 //the 'added_files' is for adding into the manifest file in this zip
222 $added_files = test_qti_export($content_test_row['test_id'], '', $zipfile);
224 //Save all the xml files in this array, and then print_organizations will add it to the manifest file.
225 foreach($added_files as $filename=>$file_array){
226 $my_files[] = $filename;
227 foreach ($file_array as $garbage=>$filename2){
228 $my_files[] = $filename2;
235 /* generate the resources and save the HTML files */
236 $used_glossary_terms = array();
238 print_organizations($top_content_parent_id, $content, 0, '', array(), $toc_html);
239 $organizations_str = ob_get_contents();
242 if (count($used_glossary_terms)) {
243 $used_glossary_terms = array_unique($used_glossary_terms);
244 sort($used_glossary_terms);
245 reset($used_glossary_terms);
248 foreach ($used_glossary_terms as $term) {
249 $term_key = urlencode($term);
250 $glossary[$term_key] = htmlentities($glossary[$term_key], ENT_QUOTES, 'UTF-8');
251 $glossary[$term_key] = str_replace('&', '&', $glossary[$term_key]);
252 $escaped_term = str_replace('&', '&', $term);
253 $terms_xml .= str_replace( array('{TERM}', '{DEFINITION}'),
254 array($escaped_term, $glossary[$term_key]),
257 $terms_html .= str_replace( array('{ENCODED_TERM}', '{TERM}', '{DEFINITION}'),
258 array($term_key, $term, $glossary[$term_key]),
259 $glossary_term_html);
262 $glossary_body_html = str_replace('{BODY}', $terms_html, $glossary_body_html);
264 $glossary_xml = str_replace(array('{GLOSSARY_TERMS}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}'),
265 array($terms_xml, $course_language_charset),
267 $glossary_html = str_replace( array('{CONTENT}', '{KEYWORDS}', '{TITLE}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}', '{COURSE_PRIMARY_LANGUAGE_CODE}'),
268 array($glossary_body_html, '', 'Glossary', $course_language_charset, $course_language_code),
270 $toc_html .= '<ul><li><a href="glossary.html" target="body">'._AT('glossary').'</a></li></ul>';
272 unset($glossary_xml);
275 $toc_html = str_replace(array('{TOC}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}', '{COURSE_PRIMARY_LANGUAGE_CODE}'),
276 array($toc_html, $course_language_charset, $course_language_code),
279 if ($first['content_path']) {
280 $first['content_path'] .= '/';
282 $frame = str_replace( array('{COURSE_TITLE}', '{FIRST_ID}', '{PATH}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}', '{COURSE_PRIMARY_LANGUAGE_CODE}'),
283 array($ims_course_title, $first['content_id'], $first['content_path'], $course_language_charset, $course_language_code),
286 $html_mainheader = str_replace(array('{COURSE_TITLE}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}', '{COURSE_PRIMARY_LANGUAGE_CODE}'),
287 array($ims_course_title, $course_language_charset, $course_language_code),
292 /* append the Organizations and Resources to the imsmanifest */
293 $imsmanifest_xml .= str_replace( array('{ORGANIZATIONS}', '{RESOURCES}', '{COURSE_TITLE}'),
294 array($organizations_str, $resources, $ims_course_title),
295 $ims_template_xml['final']);
297 /* generate the vcard for the instructor/author */
298 $sql = "SELECT first_name, last_name, email, website, login, phone FROM ".TABLE_PREFIX."members WHERE member_id=$instructor_id";
299 $result = mysql_query($sql, $db);
300 $vcard = new vCard();
301 if ($row = mysql_fetch_assoc($result)) {
302 $vcard->setName($row['last_name'], $row['first_name'], $row['login']);
303 $vcard->setEmail($row['email']);
304 $vcard->setNote('Originated from an ATutor at '.AT_BASE_HREF.'. See ATutor.ca for additional information.');
305 $vcard->setURL($row['website']);
307 $imsmanifest_xml = str_replace('{VCARD}', $vcard->getVCard(), $imsmanifest_xml);
309 $imsmanifest_xml = str_replace('{VCARD}', '', $imsmanifest_xml);
312 /* save the imsmanifest.xml file */
314 $zipfile->add_file($frame, 'index.html');
315 $zipfile->add_file($toc_html, 'toc.html');
316 $zipfile->add_file($imsmanifest_xml, 'imsmanifest.xml');
317 $zipfile->add_file($html_mainheader, 'header.html');
319 $zipfile->add_file($glossary_xml, 'glossary.xml');
320 $zipfile->add_file($glossary_html, 'glossary.html');
322 $zipfile->add_file(file_get_contents(AT_INCLUDE_PATH.'ims/adlcp_rootv1p2.xsd'), 'adlcp_rootv1p2.xsd');
323 $zipfile->add_file(file_get_contents(AT_INCLUDE_PATH.'ims/ims_xml.xsd'), 'ims_xml.xsd');
324 $zipfile->add_file(file_get_contents(AT_INCLUDE_PATH.'ims/imscp_rootv1p1p2.xsd'), 'imscp_rootv1p1p2.xsd');
325 $zipfile->add_file(file_get_contents(AT_INCLUDE_PATH.'ims/imsmd_rootv1p2p1.xsd'), 'imsmd_rootv1p2p1.xsd');
326 $zipfile->add_file(file_get_contents(AT_INCLUDE_PATH.'ims/ims.css'), 'ims.css');
327 $zipfile->add_file(file_get_contents(AT_INCLUDE_PATH.'ims/footer.html'), 'footer.html');
328 $zipfile->add_file(file_get_contents('../../images/logo.gif'), 'logo.gif');
330 $zipfile->close(); // this is optional, since send_file() closes it anyway
332 $ims_course_title = str_replace(array(' ', ':'), '_', $ims_course_title);
334 * A problem here with the preg_replace below.
335 * Originally was designed to remove all werid symbols to avoid file corruptions.
336 * In UTF-8, all non-english chars are considered to be 'werid symbols'
337 * We can still replace it as is, or add fileid to the filename to avoid these problems
338 * Well then again people won't be able to tell what this file is about
339 * If we are going to take out the preg_replace, some OS might not be able to understand
340 * these characters and will have problems importing.
342 $ims_course_title = preg_replace("{[^a-zA-Z0-9._-]}","", trim($ims_course_title));
343 $zipfile->send_file($ims_course_title . '_ims');