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