remove old readme
[atutor.git] / mods / _standard / tests / import_test.php
1 <?php
2 /************************************************************************/
3 /* ATutor                                                                                                                               */
4 /************************************************************************/
5 /* Copyright (c) 2002-2010                                              */
6 /* Inclusive Design Institute                                           */
7 /* http://atutor.ca                                                     */
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 require(AT_INCLUDE_PATH.'vitals.inc.php');
15 require_once(AT_INCLUDE_PATH.'../mods/_core/file_manager/filemanager.inc.php'); /* for clr_dir() and preImportCallBack and dirsize() */
16 require(AT_INCLUDE_PATH.'../mods/_core/imsqti/lib/qti.inc.php'); 
17 require(AT_INCLUDE_PATH.'classes/pclzip.lib.php');
18 //require(AT_INCLUDE_PATH.'classes/QTI/QTIParser.class.php');   
19 require(AT_INCLUDE_PATH.'../mods/_core/imsqti/classes/QTIImport.class.php');
20
21 /* to avoid timing out on large files */
22 @set_time_limit(0);
23 $_SESSION['done'] = 1;
24
25 $element_path = array();
26 $character_data = '';
27 $test_title = '';
28 $resource_num = 0;
29 $qids = array();        //store all the question ids that's being inserted into the db by this import
30 $overwrite = false;     //files will not be overwrite and prompt
31
32 /* handle get */
33 if (isset($_POST['submit_yes'])){
34         $overwrite = true;
35 } elseif (isset($_POST['submit_no'])){
36         $msg->addFeedback('IMPORT_CANCELLED');
37         header('Location: index.php');
38         exit;
39 }
40
41 /* functions */
42 /* called at the start of en element */
43 /* builds the $path array which is the path from the root to the current element */
44 function startElement($parser, $name, $attrs) {
45         global $attributes, $element_path, $resource_num;
46         //save attributes.
47         switch($name) {
48                 case 'resource':
49                         $attributes[$name.$resource_num]['identifier'] = $attrs['identifier'];
50                         $attributes[$name.$resource_num]['href'] = $attrs['href'];
51                         $attributes[$name.$resource_num]['type'] = $attrs['type'];
52                         $resource_num++;
53                         break;
54                 case 'file':
55                         if(in_array('resource', $element_path)){
56                                 $attributes['resource'.($resource_num-1)]['file'][] = $attrs['href'];
57                         }
58                         break;
59                 case 'dependency':
60                         if(in_array('resource', $element_path)){
61                                 $attributes['resource'.($resource_num-1)]['dependency'][] = $attrs['identifierref'];
62                         }
63                         break;
64
65         }
66         array_push($element_path, $name);               
67 }
68
69 /* called when an element ends */
70 /* removed the current element from the $path */
71 function endElement($parser, $name) {
72         global $element_path, $test_title, $character_data;
73         switch($name) {
74                 case 'title':
75                         if (in_array('organization', $element_path)){
76                                 $test_title = $character_data;
77                         }
78         }
79         $character_data = '';
80         array_pop($element_path);
81 }
82
83 /* called when there is character data within elements */
84 /* constructs the $items array using the last entry in $path as the parent element */
85 function characterData($parser, $data){
86         global $character_data;
87         if (trim($data)!=''){
88                 $character_data .= preg_replace('/[\t\0\x0B]*/', '', $data);
89         }
90 }
91
92 //If overwrite hasn't been set to true, then the file has not been exported and still in the cache.
93 //otherwise, the zip file is extracted but has not been deleted (due to the confirmation).
94 if (!$overwrite){
95         if (!isset($_POST['submit_import'])) {
96                 /* just a catch all */
97                 
98                 $errors = array('FILE_MAX_SIZE', ini_get('post_max_size'));
99                 $msg->addError($errors);
100
101                 header('Location: ./index.php');
102                 exit;
103         } 
104
105
106         //Handles import
107         /*
108         if (isset($_POST['url']) && ($_POST['url'] != 'http://') ) {
109                 if ($content = @file_get_contents($_POST['url'])) {
110
111                         // save file to /content/
112                         $filename = substr(time(), -6). '.zip';
113                         $full_filename = AT_CONTENT_DIR . $filename;
114
115                         if (!$fp = fopen($full_filename, 'w+b')) {
116                                 echo "Cannot open file ($filename)";
117                                 exit;
118                         }
119
120                         if (fwrite($fp, $content, strlen($content) ) === FALSE) {
121                                 echo "Cannot write to file ($filename)";
122                                 exit;
123                         }
124                         fclose($fp);
125                 }       
126                 $_FILES['file']['name']     = $filename;
127                 $_FILES['file']['tmp_name'] = $full_filename;
128                 $_FILES['file']['size']     = strlen($content);
129                 unset($content);
130                 $url_parts = pathinfo($_POST['url']);
131                 $package_base_name_url = $url_parts['basename'];
132         }
133         */
134         $ext = pathinfo($_FILES['file']['name']);
135         $ext = $ext['extension'];
136
137         if ($ext != 'zip') {
138                 $msg->addError('IMPORTDIR_IMS_NOTVALID');
139         } else if ($_FILES['file']['error'] == 1) {
140                 $errors = array('FILE_MAX_SIZE', ini_get('upload_max_filesize'));
141                 $msg->addError($errors);
142         } else if ( !$_FILES['file']['name'] || (!is_uploaded_file($_FILES['file']['tmp_name']) && !$_POST['url'])) {
143                 $msg->addError('FILE_NOT_SELECTED');
144         } else if ($_FILES['file']['size'] == 0) {
145                 $msg->addError('IMPORTFILE_EMPTY');
146         } 
147 }
148
149 if ($msg->containsErrors()) {
150         if (isset($_GET['tile'])) {
151                 header('Location: '.$_base_path.'mods/_standard/tile/index.php');
152         } else {
153                 header('Location: index.php');
154         }
155         exit;
156 }
157
158 /* check if ../content/import/ exists */
159 $import_path = AT_CONTENT_DIR . 'import/';
160 $content_path = AT_CONTENT_DIR;
161
162 if (!is_dir($import_path)) {
163         if (!@mkdir($import_path, 0700)) {
164                 $msg->addError('IMPORTDIR_FAILED');
165         }
166 }
167
168 $import_path .= $_SESSION['course_id'].'/';
169 if (!$overwrite){
170         if (is_dir($import_path)) {
171                 clr_dir($import_path);
172         }
173
174         if (!@mkdir($import_path, 0700)) {
175                 $msg->addError('IMPORTDIR_FAILED');
176         }
177
178         /* extract the entire archive into AT_COURSE_CONTENT . import/$course using the call back function to filter out php files */
179         error_reporting(0);
180         $archive = new PclZip($_FILES['file']['tmp_name']);
181         if ($archive->extract(  PCLZIP_OPT_PATH,        $import_path,
182                                                         PCLZIP_CB_PRE_EXTRACT,  'preImportCallBack') == 0) {
183                 $msg->addError('IMPORT_FAILED');
184                 echo 'Error : '.$archive->errorInfo(true);
185                 clr_dir($import_path);
186                 header('Location: questin_db.php');
187                 exit;
188         }
189         error_reporting(AT_ERROR_REPORTING);
190 }
191 /* get the course's max_quota */
192 $sql    = "SELECT max_quota FROM ".TABLE_PREFIX."courses WHERE course_id=$_SESSION[course_id]";
193 $result = mysql_query($sql, $db);
194 $q_row  = mysql_fetch_assoc($result);
195
196 if ($q_row['max_quota'] != AT_COURSESIZE_UNLIMITED) {
197
198         if ($q_row['max_quota'] == AT_COURSESIZE_DEFAULT) {
199                 $q_row['max_quota'] = $MaxCourseSize;
200         }
201         $totalBytes   = dirsize($import_path);
202         $course_total = dirsize(AT_CONTENT_DIR . $_SESSION['course_id'].'/');
203         $total_after  = $q_row['max_quota'] - $course_total - $totalBytes + $MaxCourseFloat;
204
205         if ($total_after < 0) {
206                 /* remove the content dir, since there's no space for it */
207                 $errors = array('NO_CONTENT_SPACE', number_format(-1*($total_after/AT_KBYTE_SIZE), 2 ) );
208                 $msg->addError($errors);
209                 
210                 clr_dir($import_path);
211
212                 if (isset($_GET['tile'])) {
213                         header('Location: '.$_base_path.'mods/_standard/tile/index.php');
214                 } else {
215                         header('Location: index.php');
216                 }
217                 exit;
218         }
219 }
220
221 $ims_manifest_xml = @file_get_contents($import_path.'imsmanifest.xml');
222
223 if ($ims_manifest_xml === false) {
224         $msg->addError('NO_IMSMANIFEST');
225
226         if (file_exists($import_path . 'atutor_backup_version')) {
227                 $msg->addError('NO_IMS_BACKUP');
228         }
229
230         clr_dir($import_path);
231
232         if (isset($_GET['tile'])) {
233                 header('Location: '.$_base_path.'mods/_standard/tile/index.php');
234         } else {
235                 header('Location: index.php');
236         }
237         exit;
238 }
239
240 $xml_parser = xml_parser_create();
241
242 xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, false); /* conform to W3C specs */
243 xml_set_element_handler($xml_parser, 'startElement', 'endElement');
244 xml_set_character_data_handler($xml_parser, 'characterData');
245
246 if (!xml_parse($xml_parser, $ims_manifest_xml, true)) {
247         die(sprintf("XML error: %s at line %d",
248                                 xml_error_string(xml_get_error_code($xml_parser)),
249                                 xml_get_current_line_number($xml_parser)));
250 }
251
252 xml_parser_free($xml_parser);
253
254 //assign folder names
255 //if (!$package_base_name){
256 //      $package_base_name = substr($_FILES['file']['name'], 0, -4);
257 //}
258
259 //$package_base_name = strtolower($package_base_name);
260 //$package_base_name = str_replace(array('\'', '"', ' ', '|', '\\', '/', '<', '>', ':'), '_' , $package_base_name);
261 //$package_base_name = preg_replace("/[^A-Za-z0-9._\-]/", '', $package_base_name);
262
263 //if (is_dir(AT_CONTENT_DIR . $_SESSION['course_id'].'/'.$package_base_name)) {
264 //      echo 'Already exist: Quitting.  (Need better msg here)';
265 //      exit;
266 //      $package_base_name .= '_'.date('ymdHis');
267 //}
268
269 if ($package_base_path) {
270         $package_base_path = implode('/', $package_base_path);
271 }
272
273 //debug($attributes);
274 //Dependency handling
275 //$media_items = array();
276 $xml_items = array();
277 //foreach($attributes as $resource=>$attrs){
278 //      if ($attrs['type'] != 'webcontent'){
279 //              $media_items[$attrs['identifier']] = $attrs['file'];
280 //      }
281 //}
282
283 //Check if the files exist, if so, warn the user.
284 $existing_files = isQTIFileExist($attributes);
285 //debug($existing_files);
286 if (!$overwrite && !empty($existing_files)){
287         $existing_files = implode('<br/>', $existing_files);
288         require(AT_INCLUDE_PATH.'header.inc.php');
289 //      $msg->addConfirm(array('MEDIA_FILE_EXISTED', $existing_files));
290 //      $msg->printConfirm();
291         echo '<form action="" method="POST">';
292         echo '<div class="input-form">';
293         echo '<div class="row">';
294         $msg->printInfos(array('MEDIA_FILE_EXISTED', $existing_files));
295         echo '</div>';
296         echo '<div class="row buttons">';
297         echo '<input type="submit" class="" name="submit_yes" value="'._AT('yes').'"/>';
298         echo '<input type="submit" class="" name="submit_no" value="'._AT('no').'"/>';
299         echo '<input type="hidden" name="submit_import" value="submit_import" />';
300         ECHO '<input type="hidden" name="url" value="'.$_POST['url'].'" />';
301         echo '</div></div>';
302         echo '</form>';
303         require (AT_INCLUDE_PATH.'footer.inc.php');
304
305         exit;
306 }
307
308 //Get the XML file out and start importing them into our database.
309 //TODO: See question_import.php 287-289.
310 $qti_import = new QTIImport($import_path);
311 $qids = $qti_import->importQuestions($attributes);
312
313 //import test
314 $tid = $qti_import->importTest();
315
316 //associate question and tests
317 foreach ($qids as $order=>$qid){
318         if (isset($qti_import->weights[$order])){
319                 $weight = round($qti_import->weights[$order]);
320         } else {
321                 $weight = 0;
322         }
323         $new_order = $order + 1;
324         $sql = "INSERT INTO " . TABLE_PREFIX . "tests_questions_assoc" . 
325                         "(test_id, question_id, weight, ordering, required) " .
326                         "VALUES ($tid, $qid, $weight, $new_order, 0)";
327         $result = mysql_query($sql, $db);
328 }
329 //debug('imported test');
330 if (!$msg->containsErrors()) {
331         $msg->addFeedback('IMPORT_SUCCEEDED');
332 }
333
334 //clear directory
335 clr_dir(AT_CONTENT_DIR . 'import/'.$_SESSION['course_id']);
336
337 header('Location: index.php');
338 exit;
339 ?>