PageRenderTime 24ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/mods/_standard/tests/import_test.php

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