remove old readme
[atutor.git] / docs / mods / _core / imscp / ims_export.php
1 <?php
2 /************************************************************************/
3 /* ATutor                                                               */
4 /************************************************************************/
5 /* Copyright (c) 2002 - 2009                                            */
6 /* Inclusive Design Institute                                           */
7 /*                                                                      */
8 /* This program is free software. You can redistribute it and/or        */
9 /* modify it under the terms of the GNU General Public License          */
10 /* as published by the Free Software Foundation.                        */
11 /************************************************************************/
12 // $Id$
13 define('AT_INCLUDE_PATH', '../../../include/');
14
15 /* content id of an optional chapter */
16 $cid = isset($_REQUEST['cid']) ? intval($_REQUEST['cid']) : 0;
17
18 if (isset($_REQUEST['to_tile']) && !isset($_POST['cancel'])) {
19         /* for TILE */
20         require(AT_INCLUDE_PATH.'vitals.inc.php');
21         if (!authenticate(AT_PRIV_ADMIN, AT_PRIV_RETURN)) {
22                 /* user can't be authenticated */
23                 header('HTTP/1.1 404 Not Found');
24                 echo 'Document not found.';
25                 exit;
26         }
27         /* to avoid timing out on large files */
28         @set_time_limit(0);
29         
30         // oauth authentication. Get oauth access token: $access_token_key
31         $client_callback_url = AT_BASE_HREF.'mods/_core/imscp/ims_export.php?to_tile=1'.SEP.'cid='.$cid;
32         if (isset($_REQUEST['to_a4a'])){
33                 $client_callback_url .= SEP.'to_a4a=1';
34         }
35         include_once('oauth/oauth_authenticate.php');
36
37         $m = md5(DB_PASSWORD . 'x' . ADMIN_PASSWORD . 'x' . $_SERVER['SERVER_ADDR'] . 'x' . $cid . 'x' . $_SESSION['course_id'] . 'x' . date('Ymd'));
38
39         $export_url = AT_BASE_HREF. 'mods/_core/imscp/ims_export.php?cid='.$cid.SEP.'c='.$_SESSION['course_id'].SEP.'m='.$m;
40         if (isset($_REQUEST['to_a4a'])){
41                 $export_url .= SEP.'a4a=1';
42         }
43         
44         $tile_import_url = AT_TILE_IMPORT_URL. '?oauth_token='.$access_token_key.'&url='.urlencode($export_url);
45
46         $oauth_server_response = @file_get_contents($tile_import_url);
47         
48         // handle OAUTH import response
49         foreach (explode('&', $oauth_server_response) as $rtn)
50         {
51                 $rtn_pair = explode('=', $rtn);
52                 
53                 if ($rtn_pair[0] == 'course_id') $tile_course_id = $rtn_pair[1];
54                 if ($rtn_pair[0] == 'error') $error = urldecode($rtn_pair[1]);
55         }
56         
57         if ($tile_course_id > 0)
58                 $msg->addFeedback(array('TILE_IMPORT_SUCCESS', AT_TILE_VIEW_COURSE_URL.$tile_course_id));
59         else
60         {
61                 // No response from transformable, the package file might be too big
62                 if (trim($error) == '') $error = _AT('tile_no_response');
63                 else {
64                         // delete this access token since it cannot import into Transformable
65                         $sql = "DELETE FROM ".TABLE_PREFIX."oauth_client_tokens
66                                  WHERE token = '".$access_token_key."'
67                                    AND token_type='access'";
68                         $result = mysql_query($sql, $db);
69                 }
70                 $msg->addError(array('TILE_IMPORT_FAIL', $error));
71         }
72
73         header('Location: '.AT_BASE_HREF.'mods/_core/imscp/index.php');
74         exit;
75 } else if (isset($_GET['m'])) {
76         /* for TILE */
77
78         /* request (hopefully) coming from a TILE server, send the content package */
79
80         $_user_location = 'public';
81         require(AT_INCLUDE_PATH.'vitals.inc.php');
82         $c = isset($_REQUEST['c'])   ? intval($_REQUEST['c'])   : 0;
83         $m = md5(DB_PASSWORD . 'x' . ADMIN_PASSWORD . 'x' . $_SERVER['SERVER_ADDR'] . 'x' . $cid . 'x' . $c . 'x' . date('Ymd'));
84         if (($m != $_GET['m']) || !$c) {
85                 header('HTTP/1.1 404 Not Found');
86                 echo 'Document not found.';
87                 exit;
88         }
89         
90         $course_id = $c;
91         if (isset($_GET['a4a'])){
92                 $use_a4a = true;
93         }
94 } else {
95         $use_a4a = false;
96         if (isset($_REQUEST['to_a4a'])){
97                 $use_a4a = true;
98         }
99         require(AT_INCLUDE_PATH.'vitals.inc.php');
100         $course_id = $_SESSION['course_id'];
101 }
102 //load the following after vitals is included
103 require(AT_INCLUDE_PATH.'../mods/_standard/tests/classes/testQuestions.class.php');
104 require(AT_INCLUDE_PATH.'../mods/_core/imsafa/classes/A4aExport.class.php');
105
106 $instructor_id   = $system_courses[$course_id]['member_id'];
107 $course_desc     = htmlspecialchars($system_courses[$course_id]['description'], ENT_QUOTES, 'UTF-8');
108 $course_title    = htmlspecialchars($system_courses[$course_id]['title'], ENT_QUOTES, 'UTF-8');
109 $course_language = $system_courses[$course_id]['primary_language'];
110
111 $courseLanguage =& $languageManager->getLanguage($course_language);
112 //If course language cannot be found, use UTF-8 English
113 //@author harris, Oct 30,2008
114 if ($courseLanguage == null){
115         $courseLanguage =& $languageManager->getLanguage('en');
116 }
117
118 $course_language_charset = $courseLanguage->getCharacterSet();
119 $course_language_code = $courseLanguage->getCode();
120
121 require(AT_INCLUDE_PATH.'classes/zipfile.class.php');                           /* for zipfile */
122 require(AT_INCLUDE_PATH.'classes/vcard.php');                                           /* for vcard */
123 require(AT_INCLUDE_PATH.'classes/XML/XML_HTMLSax/XML_HTMLSax.php');     /* for XML_HTMLSax */
124 require(AT_INCLUDE_PATH.'../mods/_core/imscp/include/ims_template.inc.php');                            /* for ims templates + print_organizations() */
125
126 if (isset($_POST['cancel'])) {
127         $msg->addFeedback('EXPORT_CANCELLED');
128         header('Location: ../content/index.php');
129         exit;
130 }
131
132
133 $zipfile = new zipfile(); 
134 $zipfile->create_dir('resources/');
135
136 /*
137         the following resources are to be identified:
138         even if some of these can't be images, they can still be files in the content dir.
139         theoretically the only urls we wouldn't deal with would be for a <!DOCTYPE and <form>
140
141         img             => src
142         a               => href                         // ignore if href doesn't exist (ie. <a name>)
143         object  => data | classid       // probably only want data
144         applet  => classid | archive                    // whatever these two are should double check to see if it's a valid file (not a dir)
145         link    => href
146         script  => src
147         form    => action
148         input   => src
149         iframe  => src
150
151 */
152 class MyHandler {
153     function MyHandler(){}
154     function openHandler(& $parser,$name,$attrs) {
155                 global $my_files;
156
157                 $name = strtolower($name);
158                 $attrs = array_change_key_case($attrs, CASE_LOWER);
159
160                 $elements = array(      'img'           => 'src',
161                                                         'a'                     => 'href',                              
162                                                         'object'        => array('data', 'classid'),
163                                                         'applet'        => array('classid', 'archive'),
164                                                         'link'          => 'href',
165                                                         'script'        => 'src',
166                                                         'form'          => 'action',
167                                                         'input'         => 'src',
168                                                         'iframe'        => 'src',
169                                                         'source'        => 'src',
170                                                         'embed'         => 'src',
171                                                         'param'         => 'value');
172         
173                 /* check if this attribute specifies the files in different ways: (ie. java) */
174                 if (is_array($elements[$name])) {
175                         $items = $elements[$name];
176
177                         foreach ($items as $item) {
178                                 if ($attrs[$item] != '') {
179
180                                         /* some attributes allow a listing of files to include seperated by commas (ie. applet->archive). */
181                                         if (strpos($attrs[$item], ',') !== false) {
182                                                 $files = explode(',', $attrs[$item]);
183                                                 foreach ($files as $file) {
184                                                         $my_files[] = trim($file);
185                                                 }
186                                         } else {
187                                                 $my_files[] = $attrs[$item];
188                                         }
189                                 }
190                         }
191                 } else if (isset($elements[$name]) && ($attrs[$elements[$name]] != '')) {
192                         /* we know exactly which attribute contains the reference to the file. */
193                         $my_files[] = $attrs[$elements[$name]];
194                 }
195     }
196     function closeHandler(& $parser,$name) { }
197 }
198
199 /* get all the content */
200 $content = array();
201 $paths   = array();
202 $top_content_parent_id = 0;
203
204 $handler=new MyHandler();
205 $parser = new XML_HTMLSax();
206 $parser->set_object($handler);
207 $parser->set_element_handler('openHandler','closeHandler');
208
209 if (authenticate(AT_PRIV_CONTENT, AT_PRIV_RETURN)) {
210         $sql = "SELECT *, UNIX_TIMESTAMP(last_modified) AS u_ts FROM ".TABLE_PREFIX."content WHERE course_id=$course_id ORDER BY content_parent_id, ordering";
211 } else {
212         $sql = "SELECT *, UNIX_TIMESTAMP(last_modified) AS u_ts FROM ".TABLE_PREFIX."content WHERE course_id=$course_id ORDER BY content_parent_id, ordering";
213 }
214 $result = mysql_query($sql, $db);
215 while ($row = mysql_fetch_assoc($result)) {
216         if (authenticate(AT_PRIV_CONTENT, AT_PRIV_RETURN) || $contentManager->isReleased($row['content_id']) === TRUE) {
217                 $content[$row['content_parent_id']][] = $row;
218                 if ($cid == $row['content_id']) {
219                         $top_content = $row;
220                         $top_content_parent_id = $row['content_parent_id'];
221                 }
222         }
223 }
224
225 if ($cid) {
226         /* filter out the top level sections that we don't want */
227         $top_level = $content[$top_content_parent_id];
228         foreach($top_level as $page) {
229                 if ($page['content_id'] == $cid) {
230                         $content[$top_content_parent_id] = array($page);
231                 } else {
232                         /* this is a page we don't want, so might as well remove it's children too */
233                         unset($content[$page['content_id']]);
234                 }
235         }
236         $ims_course_title = $course_title . ' - ' . $content[$top_content_parent_id][0]['title'];
237 } else {
238         $ims_course_title = $course_title;
239 }
240
241
242 /* generate the imsmanifest.xml header attributes */
243 $imsmanifest_xml = str_replace(array('{COURSE_TITLE}', '{COURSE_DESCRIPTION}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}', '{COURSE_PRIMARY_LANGUAGE_CODE}'), 
244                                                           array($ims_course_title, $course_desc, $course_language_charset, $course_language_code),
245                                                           $ims_template_xml['header']);
246 //debug($imsmanifest_xml);
247 //exit;
248
249 /* get the first content page to default the body frame to */
250 $first = $content[$top_content_parent_id][0];
251
252 $test_ids = array();    //global array to store all the test ids
253 //if ($my_files == null) 
254 //$my_files = array();
255
256 /* generate the IMS QTI resource and files */
257 /*
258 /* in print_organizations
259 foreach ($content[0] as $content_box){
260         $content_test_rs = $contentManager->getContentTestsAssoc($content_box['content_id']);   
261         while ($content_test_row = mysql_fetch_assoc($content_test_rs)){
262                 //export
263                 $test_ids[] = $content_test_row['test_id'];
264                 //the 'added_files' is for adding into the manifest file in this zip
265                 $added_files = test_qti_export($content_test_row['test_id'], '', $zipfile);
266
267                 //Save all the xml files in this array, and then print_organizations will add it to the manifest file.
268                 foreach($added_files as $filename=>$file_array){
269                         $my_files[] = $filename;
270                         foreach ($file_array as $garbage=>$filename2){
271                                 $my_files[] = $filename2;
272                         }
273                 }
274         }
275 }
276 */
277
278 /* generate the resources and save the HTML files */
279 $used_glossary_terms = array();
280 ob_start();
281 print_organizations($top_content_parent_id, $content, 0, '', array(), $toc_html);
282 $organizations_str = ob_get_contents();
283 ob_end_clean();
284
285 if (count($used_glossary_terms)) {
286         $used_glossary_terms = array_unique($used_glossary_terms);
287         sort($used_glossary_terms);
288         reset($used_glossary_terms);
289
290         $terms_xml = '';
291         foreach ($used_glossary_terms as $term) {
292                 $term_key = urlencode($term);
293                 $glossary[$term_key] = htmlentities($glossary[$term_key], ENT_QUOTES, 'UTF-8');
294                 $glossary[$term_key] = str_replace('&', '&amp;', $glossary[$term_key]);
295                 $escaped_term = str_replace('&', '&amp;', $term);
296                 $terms_xml .= str_replace(      array('{TERM}', '{DEFINITION}'),
297                                                                         array($escaped_term, $glossary[$term_key]),
298                                                                         $glossary_term_xml);
299
300                 $terms_html .= str_replace(     array('{ENCODED_TERM}', '{TERM}', '{DEFINITION}'),
301                                                                         array($term_key, $term, $glossary[$term_key]),
302                                                                         $glossary_term_html);
303         }
304
305         $glossary_body_html = str_replace('{BODY}', $terms_html, $glossary_body_html);
306
307         $glossary_xml = str_replace(array('{GLOSSARY_TERMS}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}'),
308                                                             array($terms_xml, $course_language_charset),
309                                                                 $glossary_xml);
310         $glossary_html = str_replace(   array('{CONTENT}', '{KEYWORDS}', '{TITLE}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}', '{COURSE_PRIMARY_LANGUAGE_CODE}'),
311                                                                         array($glossary_body_html, '', 'Glossary', $course_language_charset, $course_language_code),
312                                                                         $html_template);
313         $toc_html .= '<ul><li><a href="glossary.html" target="body">'._AT('glossary').'</a></li></ul>';
314 } else {
315         unset($glossary_xml);
316 }
317
318 $toc_html = str_replace(array('{TOC}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}', '{COURSE_PRIMARY_LANGUAGE_CODE}'),
319                                             array($toc_html, $course_language_charset, $course_language_code),
320                                                 $html_toc);
321
322 if ($first['content_path']) {
323         $first['content_path'] .= '/';
324 }
325 $frame = str_replace(   array('{COURSE_TITLE}',         '{FIRST_ID}', '{PATH}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}', '{COURSE_PRIMARY_LANGUAGE_CODE}'),
326                                                 array($ims_course_title, $first['content_id'], $first['content_path'], $course_language_charset, $course_language_code),
327                                                 $html_frame);
328
329 $html_mainheader = str_replace(array('{COURSE_TITLE}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}', '{COURSE_PRIMARY_LANGUAGE_CODE}'),
330                                                            array($ims_course_title, $course_language_charset, $course_language_code),
331                                                            $html_mainheader);
332
333 $footer = str_replace(  
334     array(
335         '{COURSE_PRIMARY_LANGUAGE_CODE}',       
336         '{CONTENT_PACKAGE_TITLE}', 
337         '{COURSE_PRIMARY_LANGUAGE_CHARSET}', 
338         '{CONTENT_PACKAGE_HOW_TO}'
339     ), 
340     array(
341         $course_language_code, 
342         _AT('content_package') . ' - ' . $ims_course_title,
343         $course_language_charset,
344          _AT('general_help', AT_GUIDES_PATH.'index_list.php?lang='.$_SESSION['lang'])
345     ),
346     $footer_html
347 );
348
349 /* append the Organizations and Resources to the imsmanifest */
350 $imsmanifest_xml .= str_replace(        array('{ORGANIZATIONS}',        '{RESOURCES}', '{COURSE_TITLE}'),
351                                                                         array($organizations_str,       $resources, $ims_course_title),
352                                                                         $ims_template_xml['final']);
353
354 /* generate the vcard for the instructor/author */
355 $sql = "SELECT first_name, last_name, email, website, login, phone FROM ".TABLE_PREFIX."members WHERE member_id=$instructor_id";
356 $result = mysql_query($sql, $db);
357 $vcard = new vCard();
358 if ($row = mysql_fetch_assoc($result)) {
359         $vcard->setName($row['last_name'], $row['first_name'], $row['login']);
360         $vcard->setEmail($row['email']);
361         $vcard->setNote('Originated from an ATutor at '.AT_BASE_HREF.'. See ATutor.ca for additional information.');
362         $vcard->setURL($row['website']);
363
364         $imsmanifest_xml = str_replace('{VCARD}', $vcard->getVCard(), $imsmanifest_xml);
365 } else {
366         $imsmanifest_xml = str_replace('{VCARD}', '', $imsmanifest_xml);
367 }
368
369 /* save the imsmanifest.xml file */
370
371 $zipfile->add_file($frame,                       'index.html');
372 $zipfile->add_file($toc_html,            'toc.html');
373 $zipfile->add_file($imsmanifest_xml, 'imsmanifest.xml');
374 $zipfile->add_file($html_mainheader, 'header.html');
375 $zipfile->add_file($footer,          'footer.html');
376 if ($glossary_xml) {
377         $zipfile->add_file($glossary_xml,  'glossary.xml');
378         $zipfile->add_file($glossary_html, 'glossary.html');
379 }
380 $zipfile->add_file(file_get_contents(AT_INCLUDE_PATH.'../mods/_core/imscp/include/adlcp_rootv1p2.xsd'), 'adlcp_rootv1p2.xsd');
381 $zipfile->add_file(file_get_contents(AT_INCLUDE_PATH.'../mods/_core/imscp/include/ims_xml.xsd'), 'ims_xml.xsd');
382 $zipfile->add_file(file_get_contents(AT_INCLUDE_PATH.'../mods/_core/imscp/include/imscp_rootv1p1p2.xsd'), 'imscp_rootv1p1p2.xsd');
383 $zipfile->add_file(file_get_contents(AT_INCLUDE_PATH.'../mods/_core/imscp/include/imsmd_rootv1p2p1.xsd'), 'imsmd_rootv1p2p1.xsd');
384 $zipfile->add_file(file_get_contents(AT_INCLUDE_PATH.'../mods/_core/imscp/include/ims.css'), 'ims.css');
385 $zipfile->add_file(file_get_contents('../../../images/logo.gif'), 'logo.gif');
386
387 $zipfile->close(); // this is optional, since send_file() closes it anyway
388
389 $ims_course_title = str_replace(array(' ', ':'), '_', $ims_course_title);
390 /**
391  * A problem here with the preg_replace below.
392  * Originally was designed to remove all werid symbols to avoid file corruptions.
393  * In UTF-8, all non-english chars are considered to be 'werid symbols'
394  * We can still replace it as is, or add fileid to the filename to avoid these problems
395  * Well then again people won't be able to tell what this file is about
396  * If we are going to take out the preg_replace, some OS might not be able to understand
397  * these characters and will have problems importing.
398  */
399 $ims_course_title = preg_replace("{[^a-zA-Z0-9._-]}","", trim($ims_course_title));
400 $zipfile->send_file($ims_course_title . '_ims');
401
402 exit;
403 ?>