tagging as ATutor 1.5.4-release
[atutor.git] / tools / ims / ims_export.php
1 <?php
2 /****************************************************************/
3 /* ATutor                                                                                                               */
4 /****************************************************************/
5 /* Copyright (c) 2002-2007 by Greg Gay & Joel Kronenberg        */
6 /* Adaptive Technology Resource Centre / University of Toronto  */
7 /* http://atutor.ca                                                                                             */
8 /*                                                              */
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 /****************************************************************/
13 // $Id$
14
15 define('AT_INCLUDE_PATH', '../../include/');
16
17 /* content id of an optional chapter */
18 $cid = intval($_REQUEST['cid']);
19 $c   = intval($_REQUEST['c']);
20
21 if (isset($_REQUEST['to_tile']) && !isset($_POST['cancel'])) {
22         /* for TILE */
23
24         /* redirect to TILE import servlet */
25
26         require(AT_INCLUDE_PATH.'vitals.inc.php');
27         if (!authenticate(AT_PRIV_ADMIN, AT_PRIV_RETURN)) {
28                 /* user can't be authenticated */
29                 header('HTTP/1.1 404 Not Found');
30                 echo 'Document not found.';
31                 exit;
32         }
33
34         $m = md5(DB_PASSWORD . 'x' . ADMIN_PASSWORD . 'x' . $_SERVER['SERVER_ADDR'] . 'x' . $cid . 'x' . $_SESSION['course_id'] . 'x' . date('Ymd'));
35
36         header('Location: '.AT_TILE_IMPORT. '?cp='.urlencode(AT_BASE_HREF. 'tools/ims/ims_export.php?cid='.$cid.'&c='.$_SESSION['course_id'].'&m='.$m));
37         exit;
38 } else if (isset($_GET['m'])) {
39         /* for TILE */
40
41         /* request (hopefully) coming from a TILE server, send the content package */
42
43         $_user_location = 'public';
44         require(AT_INCLUDE_PATH.'vitals.inc.php');
45         $m = md5(DB_PASSWORD . 'x' . ADMIN_PASSWORD . 'x' . $_SERVER['SERVER_ADDR'] . 'x' . $cid . 'x' . $c . 'x' . date('Ymd'));
46         if (($m != $_GET['m']) || !$c) {
47                 header('HTTP/1.1 404 Not Found');
48                 echo 'Document not found.';
49                 exit;
50         }
51         
52         $course_id = $c;
53
54 } else {
55         require(AT_INCLUDE_PATH.'vitals.inc.php');
56         $course_id = $_SESSION['course_id'];
57 }
58
59 $instructor_id   = $system_courses[$course_id]['member_id'];
60 $course_desc     = $system_courses[$course_id]['description'];
61 $course_title    = $system_courses[$course_id]['title'];
62 $course_language = $system_courses[$course_id]['primary_language'];
63
64 $courseLanguage =& $languageManager->getLanguage($course_language);
65
66 $course_language_charset = $courseLanguage->getCharacterSet();
67 $course_language_code = $courseLanguage->getCode();
68
69 require(AT_INCLUDE_PATH.'classes/zipfile.class.php');                           /* for zipfile */
70 require(AT_INCLUDE_PATH.'classes/vcard.php');                                           /* for vcard */
71 require(AT_INCLUDE_PATH.'classes/XML/XML_HTMLSax/XML_HTMLSax.php');     /* for XML_HTMLSax */
72 require(AT_INCLUDE_PATH.'ims/ims_template.inc.php');                            /* for ims templates + print_organizations() */
73
74 if (isset($_POST['cancel'])) {
75         $msg->addFeedback('EXPORT_CANCELLED');
76         header('Location: ../index.php');
77         exit;
78 }
79
80
81 $zipfile = new zipfile(); 
82 $zipfile->create_dir('resources/');
83
84 /*
85         the following resources are to be identified:
86         even if some of these can't be images, they can still be files in the content dir.
87         theoretically the only urls we wouldn't deal with would be for a <!DOCTYPE and <form>
88
89         img             => src
90         a               => href                         // ignore if href doesn't exist (ie. <a name>)
91         object  => data | classid       // probably only want data
92         applet  => classid | archive                    // whatever these two are should double check to see if it's a valid file (not a dir)
93         link    => href
94         script  => src
95         form    => action
96         input   => src
97         iframe  => src
98
99 */
100 class MyHandler {
101     function MyHandler(){}
102     function openHandler(& $parser,$name,$attrs) {
103                 global $my_files;
104
105                 $name = strtolower($name);
106                 $attrs = array_change_key_case($attrs, CASE_LOWER);
107
108                 $elements = array(      'img'           => 'src',
109                                                         'a'                     => 'href',                              
110                                                         'object'        => array('data', 'classid'),
111                                                         'applet'        => array('classid', 'archive'),
112                                                         'link'          => 'href',
113                                                         'script'        => 'src',
114                                                         'form'          => 'action',
115                                                         'input'         => 'src',
116                                                         'iframe'        => 'src',
117                                                         'embed'         => 'src',
118                                                         'param'         => 'value');
119         
120                 /* check if this attribute specifies the files in different ways: (ie. java) */
121                 if (is_array($elements[$name])) {
122                         $items = $elements[$name];
123
124                         foreach ($items as $item) {
125                                 if ($attrs[$item] != '') {
126
127                                         /* some attributes allow a listing of files to include seperated by commas (ie. applet->archive). */
128                                         if (strpos($attrs[$item], ',') !== false) {
129                                                 $files = explode(',', $attrs[$item]);
130                                                 foreach ($files as $file) {
131                                                         $my_files[] = trim($file);
132                                                 }
133                                         } else {
134                                                 $my_files[] = $attrs[$item];
135                                         }
136                                 }
137                         }
138                 } else if (isset($elements[$name]) && ($attrs[$elements[$name]] != '')) {
139                         /* we know exactly which attribute contains the reference to the file. */
140                         $my_files[] = $attrs[$elements[$name]];
141                 }
142     }
143     function closeHandler(& $parser,$name) { }
144 }
145
146 /* get all the content */
147 $content = array();
148 $paths   = array();
149 $top_content_parent_id = 0;
150
151 $handler=new MyHandler();
152 $parser =& new XML_HTMLSax();
153 $parser->set_object($handler);
154 $parser->set_element_handler('openHandler','closeHandler');
155
156 if (authenticate(AT_PRIV_CONTENT, AT_PRIV_RETURN)) {
157         $sql = "SELECT *, UNIX_TIMESTAMP(last_modified) AS u_ts FROM ".TABLE_PREFIX."content WHERE course_id=$course_id ORDER BY content_parent_id, ordering";
158 } else {
159         $sql = "SELECT *, UNIX_TIMESTAMP(last_modified) AS u_ts FROM ".TABLE_PREFIX."content WHERE course_id=$course_id ORDER BY content_parent_id, ordering";
160 }
161 $result = mysql_query($sql, $db);
162 while ($row = mysql_fetch_assoc($result)) {
163         if (authenticate(AT_PRIV_CONTENT, AT_PRIV_RETURN) || $contentManager->isReleased($row['content_id']) === TRUE) {
164                 $content[$row['content_parent_id']][] = $row;
165                 if ($cid == $row['content_id']) {
166                         $top_content = $row;
167                         $top_content_parent_id = $row['content_parent_id'];
168                 }
169         }
170 }
171
172
173 if ($cid) {
174         /* filter out the top level sections that we don't want */
175         $top_level = $content[$top_content_parent_id];
176         foreach($top_level as $page) {
177                 if ($page['content_id'] == $cid) {
178                         $content[$top_content_parent_id] = array($page);
179                 } else {
180                         /* this is a page we don't want, so might as well remove it's children too */
181                         unset($content[$page['content_id']]);
182                 }
183         }
184         $ims_course_title = $course_title . ' - ' . $content[$top_content_parent_id][0]['title'];
185 } else {
186         $ims_course_title = $course_title;
187 }
188
189
190 /* generate the imsmanifest.xml header attributes */
191 $imsmanifest_xml = str_replace(array('{COURSE_TITLE}', '{COURSE_DESCRIPTION}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}', '{COURSE_PRIMARY_LANGUAGE_CODE}'), 
192                                                           array($ims_course_title, $course_desc, $course_language_charset, $course_language_code),
193                                                           $ims_template_xml['header']);
194 //debug($imsmanifest_xml);
195 //exit;
196
197 /* get the first content page to default the body frame to */
198 $first = $content[$top_content_parent_id][0];
199
200 /* generate the resources and save the HTML files */
201
202 $used_glossary_terms = array();
203 ob_start();
204 print_organizations($top_content_parent_id, $content, 0, '', array(), $toc_html);
205 $organizations_str = ob_get_contents();
206 ob_end_clean();
207
208
209 if (count($used_glossary_terms)) {
210         $used_glossary_terms = array_unique($used_glossary_terms);
211         sort($used_glossary_terms);
212         reset($used_glossary_terms);
213
214         $terms_xml = '';
215         foreach ($used_glossary_terms as $term) {
216                 $term_key = urlencode($term);
217                 $glossary[$term_key] = str_replace('&', '&amp;', $glossary[$term_key]);
218                 $escaped_term = str_replace('&', '&amp;', $term);
219                 $terms_xml .= str_replace(      array('{TERM}', '{DEFINITION}'),
220                                                                         array($escaped_term, $glossary[$term_key]),
221                                                                         $glossary_term_xml);
222
223                 $terms_html .= str_replace(     array('{ENCODED_TERM}', '{TERM}', '{DEFINITION}'),
224                                                                         array($term_key, $term, $glossary[$term_key]),
225                                                                         $glossary_term_html);
226         }
227
228         $glossary_body_html = str_replace('{BODY}', $terms_html, $glossary_body_html);
229
230         $glossary_xml = str_replace(array('{GLOSSARY_TERMS}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}'),
231                                                             array($terms_xml, $course_language_charset),
232                                                                 $glossary_xml);
233         $glossary_html = str_replace(   array('{CONTENT}', '{KEYWORDS}', '{TITLE}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}', '{COURSE_PRIMARY_LANGUAGE_CODE}'),
234                                                                         array($glossary_body_html, '', 'Glossary', $course_language_charset, $course_language_code),
235                                                                         $html_template);
236         $toc_html .= '<ul><li><a href="glossary.html" target="body">'._AT('glossary').'</a></li></ul>';
237 } else {
238         unset($glossary_xml);
239 }
240
241 $toc_html = str_replace(array('{TOC}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}', '{COURSE_PRIMARY_LANGUAGE_CODE}'),
242                                             array($toc_html, $course_language_charset, $course_language_code),
243                                                 $html_toc);
244
245 if ($first['content_path']) {
246         $first['content_path'] .= '/';
247 }
248 $frame = str_replace(   array('{COURSE_TITLE}',         '{FIRST_ID}', '{PATH}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}', '{COURSE_PRIMARY_LANGUAGE_CODE}'),
249                                                 array($ims_course_title, $first['content_id'], $first['content_path'], $course_language_charset, $course_language_code),
250                                                 $html_frame);
251
252 $html_mainheader = str_replace(array('{COURSE_TITLE}', '{COURSE_PRIMARY_LANGUAGE_CHARSET}', '{COURSE_PRIMARY_LANGUAGE_CODE}'),
253                                                            array($ims_course_title, $course_language_charset, $course_language_code),
254                                                            $html_mainheader);
255
256
257
258 /* append the Organizations and Resources to the imsmanifest */
259 $imsmanifest_xml .= str_replace(        array('{ORGANIZATIONS}',        '{RESOURCES}', '{COURSE_TITLE}'),
260                                                                         array($organizations_str,       $resources, $ims_course_title),
261                                                                         $ims_template_xml['final']);
262
263
264 /* generate the vcard for the instructor/author */
265 $sql = "SELECT first_name, last_name, email, website, login, phone FROM ".TABLE_PREFIX."members WHERE member_id=$instructor_id";
266 $result = mysql_query($sql, $db);
267 $vcard = new vCard();
268 if ($row = mysql_fetch_assoc($result)) {
269         $vcard->setName($row['last_name'], $row['first_name'], $row['login']);
270         $vcard->setEmail($row['email']);
271         $vcard->setNote('Originated from an ATutor at '.AT_BASE_HREF.'. See ATutor.ca for additional information.');
272         $vcard->setURL($row['website']);
273
274         $imsmanifest_xml = str_replace('{VCARD}', $vcard->getVCard(), $imsmanifest_xml);
275 } else {
276         $imsmanifest_xml = str_replace('{VCARD}', '', $imsmanifest_xml);
277 }
278
279 /* save the imsmanifest.xml file */
280
281 $zipfile->add_file($frame,                       'index.html');
282 $zipfile->add_file($toc_html,            'toc.html');
283 $zipfile->add_file($imsmanifest_xml, 'imsmanifest.xml');
284 $zipfile->add_file($html_mainheader, 'header.html');
285 if ($glossary_xml) {
286         $zipfile->add_file($glossary_xml,  'glossary.xml');
287         $zipfile->add_file($glossary_html, 'glossary.html');
288 }
289 $zipfile->add_file(file_get_contents(AT_INCLUDE_PATH.'ims/adlcp_rootv1p2.xsd'), 'adlcp_rootv1p2.xsd');
290 $zipfile->add_file(file_get_contents(AT_INCLUDE_PATH.'ims/ims_xml.xsd'), 'ims_xml.xsd');
291 $zipfile->add_file(file_get_contents(AT_INCLUDE_PATH.'ims/imscp_rootv1p1p2.xsd'), 'imscp_rootv1p1p2.xsd');
292 $zipfile->add_file(file_get_contents(AT_INCLUDE_PATH.'ims/imsmd_rootv1p2p1.xsd'), 'imsmd_rootv1p2p1.xsd');
293 $zipfile->add_file(file_get_contents(AT_INCLUDE_PATH.'ims/ims.css'), 'ims.css');
294 $zipfile->add_file(file_get_contents(AT_INCLUDE_PATH.'ims/footer.html'), 'footer.html');
295 $zipfile->add_file(file_get_contents('../../images/logo.gif'), 'logo.gif');
296
297 $zipfile->close(); // this is optional, since send_file() closes it anyway
298
299 $ims_course_title = str_replace(array(' ', ':'), '_', $ims_course_title);
300 $ims_course_title = preg_replace("{[^a-zA-Z0-9._-]}","", trim($ims_course_title));
301 $zipfile->send_file($ims_course_title . '_ims');
302
303 exit;
304 ?>