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