2 /************************************************************************/
4 /************************************************************************/
5 /* Copyright (c) 2002 - 2009 */
6 /* Inclusive Design Institute */
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: ims_import.php 9081 2010-01-13 20:26:03Z cindy $
13 define('AT_INCLUDE_PATH', '../../../include/');
14 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.'classes/pclzip.lib.php');
18 require(AT_INCLUDE_PATH.'../mods/_core/imsqti/lib/qti.inc.php');
19 require(AT_INCLUDE_PATH.'../mods/_core/imsqti/classes/QTIImport.class.php');
20 require(AT_INCLUDE_PATH.'../mods/_core/imsafa/classes/A4aImport.class.php');
21 require(AT_INCLUDE_PATH.'../mods/_core/imscp/ns.inc.php'); //namespace, no longer needs, delete it after it's stable.
22 require(AT_INCLUDE_PATH.'../mods/_core/imscc/classes/WeblinksParser.class.php');
23 require(AT_INCLUDE_PATH.'../mods/_core/imscc/classes/DiscussionToolsParser.class.php');
24 require(AT_INCLUDE_PATH.'../mods/_core/imscc/classes/DiscussionToolsImport.class.php');
27 /* make sure we own this course that we're exporting */
28 authenticate(AT_PRIV_CONTENT);
30 /* to avoid timing out on large files */
32 $_SESSION['done'] = 1;
34 $html_head_tags = array("style", "script", "link");
36 $package_base_path = '';
37 $package_real_base_path = ''; //the path to save the contents
38 $all_package_base_path = array();
40 $element_path = array();
41 $imported_glossary = array();
46 $skip_ims_validation = false;
47 $added_dt = array(); //the mapping of discussion tools that are added
48 $avail_dt = array(); //list of discussion tools that have not been handled
51 * return the error messages represented by the given array
53 * @ref http://ca3.php.net/manual/en/domdocument.schemavalidate.php
55 function libxml_display_error($error)
58 switch ($error->level) {
59 case LIBXML_ERR_WARNING:
60 $return .= "<b>Warning $error->code</b>: ";
62 case LIBXML_ERR_ERROR:
63 $return .= "<b>Error $error->code</b>: ";
65 case LIBXML_ERR_FATAL:
66 $return .= "<b>Fatal Error $error->code</b>: ";
69 $return .= trim($error->message);
71 $return .= " in <b>$error->file</b>";
73 $return .= " on line <b>$error->line</b>\n";
79 * Validate all the XML in the package, including checking XSDs, missing data.
80 * @param string the path of the directory that contains all the package files
81 * @return boolean true if every file exists in the manifest, false if any is missing.
83 function checkResources($import_path){
84 global $items, $msg, $skip_ims_validation, $avail_dt;
86 if (!is_dir($import_path)){
90 //if the package has access for all content, skip validation for now.
91 //todo: import the XSD into our validator
92 if ($skip_ims_validation){
96 //generate a file tree
97 $data = rscandir($import_path);
99 //check if every file is presented in the manifest
100 foreach($data as $filepath){
101 $filepath = substr($filepath, strlen($import_path));
103 //validate xml via its xsd/dtds
104 if (preg_match('/(.*)\.xml/', $filepath)){
105 libxml_use_internal_errors(true);
106 $dom = new DOMDocument();
107 $dom->load(realpath($import_path.$filepath));
108 if (!@$dom->schemaValidate('main.xsd')){
109 $errors = libxml_get_errors();
110 foreach ($errors as $error) {
112 if ($error->level==LIBXML_ERR_WARNING){
115 $msg->addError(array('IMPORT_CARTRIDGE_FAILED', libxml_display_error($error)));
117 libxml_clear_errors();
119 //if this is the manifest file, we do not have to check for its existance.
120 // if (preg_match('/(.*)imsmanifest\.xml/', $filepath)){
126 //Create an array that mimics the structure of the data array, based on the xml items
127 $filearray = array();
128 foreach($items as $name=>$fileinfo){
129 if(isset($fileinfo['file']) && is_array($fileinfo['file']) && !empty($fileinfo['file'])){
130 foreach($fileinfo['file'] as $fn){
131 if (!in_array(realpath($import_path.$fn), $filearray)){
132 $filearray[] = realpath($import_path. $fn);
137 //validate the xml by its schema
138 if (preg_match('/imsqti\_(.*)/', $fileinfo['type'])){
139 $qti = new QTIParser($fileinfo['type']);
140 $xml_content = @file_get_contents($import_path . $fileinfo['href']);
141 $qti->parse($xml_content); //will add error to $msg if failed
144 //add all dependent discussion tools to a list
145 if(isset($fileinfo['dependency']) && !empty($fileinfo['dependency'])){
146 $avail_dt = array_merge($avail_dt, $fileinfo['dependency']);
150 //check if all files in the xml is presented in the archieve
151 $result = array_diff($filearray, $data);
152 //using sizeof because array_diff only
153 //returns an array containing all the entries from array1 that are not present in any of the
155 //Using sizeof make sure it's not a subset of array2.
156 //-1 on data because it always contain the imsmanifest.xml file
157 if (!$skip_ims_validation){
158 if (!empty($result) || sizeof($data)-1>sizeof($filearray)){
159 $msg->addError(array('IMPORT_CARTRIDGE_FAILED', _AT('ims_missing_references')));
166 * @example rscandir(dirname(__FILE__).'/'));
167 * @param string $base
172 function rscandir($base='', &$data=array()) {
173 $array = array_diff(scandir($base), array('.', '..')); # remove ' and .. from the array */
174 foreach($array as $value) : /* loop through the array at the level of the supplied $base */
176 if (is_dir($base.$value)) : /* if this is a directory */
177 // don't save the directory name
178 // $data[] = $base.$value.'/'; /* add it to the $data array */
179 $data = rscandir($base.$value.'/', $data); /* then make a recursive call with the
180 current $value as the $base supplying the $data array to carry into the recursion */
182 elseif (is_file($base.$value)) : /* else if the current $value is a file */
183 $data[] = realpath($base.$value); /* just add the current $value to the $data array */
188 return $data; // return the $data array
193 * Function to restructure the $items. So that old import will merge the top page into its children, and
194 * create a new folder on top of it
196 function rehash($items){
198 $parent_page_maps = array(); //old=>new
199 $temp_popped_items = array();
200 $rehashed_items = array(); //the reconstructed array
201 foreach($items as $id => $content){
202 $parent_obj = $items[$content['parent_content_id']];
203 $rehashed_items[$id] = $content; //copy
204 //first check if this is the top folder of the archieve, we don't want the top folder, remove it.
205 /* if (isset($content['parent_content_id']) && !isset($parent_obj) && !isset($content['type'])){
206 //if we can get into here, it means the parent_content_id of this is empty
207 //implying this is the first folder.
208 //note: it checks content[type] cause it could be a webcontent. In that case,
209 // we do want to keep it.
210 debug($content, 'hit');
211 unset($rehashed_items[$id]);
214 //then check if there exists a mapping for this item, if so, simply replace is and next.
216 */ if (isset($parent_page_maps[$content['parent_content_id']])){
217 $rehashed_items [$id]['parent_content_id'] = $parent_page_maps[$content['parent_content_id']];
218 $rehashed_items [$id]['ordering']++;
220 //If its parent page is a top page and have an identiferref
221 elseif (isset($parent_obj) && isset($parent_obj['href'])){
222 if (!isset($parent_obj['href'])){
223 //check if this top page is already a folder, if so, next.
226 //else, make its parent page to a folder
227 $new_item['title'] = $parent_obj['title'];
228 //check if this parent has been modified, if so, chnage it
229 if (isset($parent_page_maps[$parent_obj['parent_content_id']])){
230 $new_item['parent_content_id'] = $parent_page_maps[$parent_obj['parent_content_id']];
232 $new_item['parent_content_id'] = $parent_obj['parent_content_id'];
234 //all ordering needs to be +1 because we are creating a new folder on top of
235 //everything, except the first page.
236 $new_item['ordering'] = $parent_obj['ordering'];
237 if ($new_item['parent_content_id']!='0'){
238 $new_item['ordering']++;
241 //assign this new parent folder to the pending items array
242 $new_item_name = $content['parent_content_id'].'_FOLDER';
243 //a not so brilliant way to append the folder in its appropriate position
244 $reordered_hashed_items = array(); //use to store the new rehashed item with the correct item order
245 foreach($rehashed_items as $rh_id=>$rh_content){
246 if ($rh_id == $content['parent_content_id']){
247 //add the folder in before the parent subpage.
248 $reordered_hashed_items[$new_item_name] = $new_item;
250 $reordered_hashed_items[$rh_id] = $rh_content; //clone
252 $rehashed_items = $reordered_hashed_items; //replace it back
253 unset($reordered_hashed_items);
254 $parent_page_maps[$content['parent_content_id']] = $new_item_name; //save this page on the hash map
256 //reconstruct the parent
257 $rehashed_items[$content['parent_content_id']]['parent_content_id'] = $parent_page_maps[$content['parent_content_id']];
258 $rehashed_items[$content['parent_content_id']]['ordering'] = 0; //always the first one.
261 $rehashed_items[$id]['parent_content_id'] = $parent_page_maps[$content['parent_content_id']];
262 $rehashed_items[$id]['ordering']++;
266 return $rehashed_items;
271 * This function will take the test accessment XML and add these to the database.
272 * @param string The path of the XML, without the import_path.
273 * @param mixed An item singleton. Contains the info of this item, namely, the accessment details.
274 * The item must be an object created by the ims class.
275 * @param string the import path
276 * @return mixed An Array that contains all the question IDs that have been imported.
278 function addQuestions($xml, $item, $import_path){
280 $qti_import = new QTIImport($import_path);
281 $tests_xml = $import_path.$xml;
283 //Mimic the array for now.
284 $test_attributes['resource']['href'] = $item['href'];
285 $test_attributes['resource']['type'] = preg_match('/imsqti_xmlv1p2/', $item['type'])==1?'imsqti_xmlv1p2':'imsqti_xmlv1p1';
286 $test_attributes['resource']['file'] = $item['file'];
288 //Get the XML file out and start importing them into our database.
289 //TODO: See question_import.php 287-289.
290 $qids = $qti_import->importQuestions($test_attributes);
291 $test_title = $qti_import->title;
297 /* called at the start of en element */
298 /* builds the $path array which is the path from the root to the current element */
299 function startElement($parser, $name, $attrs) {
300 global $items, $path, $package_base_path, $all_package_base_path, $package_real_base_path;
301 global $element_path, $import_path, $skip_ims_validation;
302 global $xml_base_path, $test_message, $content_type;
303 global $current_identifier, $msg, $ns, $ns_cp;
305 //check if the xml is valid
307 if(isset($attrs['xsi:schemaLocation']) && $name == 'manifest'){
308 //run the loop and check it thru the ns.inc.php
309 } elseif ($name == 'manifest' && !isset($attrs['xsi:schemaLocation'])) {
310 //$msg->addError('MANIFEST_NOT_WELLFORM: NO NAMESPACE');
311 $msg->addError('IMPORT_CARTRIDGE_FAILED');
315 //error if the tag names are wrong
316 if (preg_match('/^xsi\:/', $name) >= 1){
317 //$msg->addError('MANIFEST_NOT_WELLFORM');
318 $msg->addError('IMPORT_CARTRIDGE_FAILED');
322 //validate namespaces
323 if(!$skip_ims_validation && isset($attrs['xsi:schemaLocation']) && $name=='manifest'){
324 $schema_location = array();
325 $split_location = preg_split('/[\r\n\s]+/', trim($attrs['xsi:schemaLocation']));
327 //check if the namespace is actually right, have an array or some sort in IMS class
328 if(sizeof($split_location)%2==1){
329 //schema is not in the form of "The first URI reference in each pair is a namespace name,
330 //and the second is the location of a schema that describes that namespace."
331 //$msg->addError('MANIFEST_NOT_WELLFORM');
332 $msg->addError(array('IMPORT_CARTRIDGE_FAILED', _AT('schema_error')));
335 //turn the xsi:schemaLocation URI into a schema that describe namespace.
337 //http://msdn.microsoft.com/en-us/library/ms256100(VS.85).aspx
338 //http://www.w3.org/TR/xmlschema-1/
339 for($i=0; $i < sizeof($split_location);$i=$i+2){
341 if (isset($ns[$split_location[$i]]) && $ns[$split_location[$i]] != $split_location[$i+1]){
342 //$msg->addError('MANIFEST_NOT_WELLFORM: SCHEMA');
343 $msg->addError('IMPORT_CARTRIDGE_FAILED');
346 //if the key of the namespace is not defined. Throw error.
347 if(!isset($ns[$split_location[$i]]) && !isset($ns_cp[$split_location[$i]])){
348 $msg->addError(array('IMPORT_CARTRIDGE_FAILED', _AT('schema_error')));
355 if ($name == 'manifest' && isset($attrs['xml:base']) && $attrs['xml:base']) {
356 $xml_base_path = $attrs['xml:base'];
357 } else if ($name == 'file') {
358 // check if it misses file references
359 if(!$skip_ims_validation && (!isset($attrs['href']) || $attrs['href']=='')){
360 //$msg->addError('MANIFEST_NOT_WELLFORM');
361 $msg->addError(array('IMPORT_CARTRIDGE_FAILED', _AT('ims_missing_references')));
364 // special case for webCT content packages that don't specify the `href` attribute
365 // with the `<resource>` element.
366 // we take the `href` from the first `<file>` element.
367 if (isset($items[$current_identifier]) && ($items[$current_identifier]['href'] == '')) {
368 $attrs['href'] = urldecode($attrs['href']);
369 $items[$current_identifier]['href'] = $attrs['href'];
372 $temp_path = pathinfo($attrs['href']);
373 $temp_path = explode('/', $temp_path['dirname']);
374 if (empty($package_base_path)){
375 $package_base_path = $temp_path;
377 if ($all_package_base_path!='' && empty($all_package_base_path)){
378 $all_package_base_path = $temp_path;
380 $package_base_path = array_intersect_assoc($package_base_path, $temp_path);
382 //calculate the depths of relative paths
383 if ($all_package_base_path!=''){
384 $no_relative_temp_path = $temp_path;
385 foreach($no_relative_temp_path as $path_node){
386 if ($path_node=='..'){
387 array_pop($no_relative_temp_path);
388 array_pop($no_relative_temp_path); //not a typo, have to pop twice, both itself('..'), and the one before.
391 $all_package_base_path = array_intersect_assoc($all_package_base_path, $no_relative_temp_path);
392 if (empty($all_package_base_path)){
393 $all_package_base_path = ''; //unset it, there is no intersection.
397 //save the actual content base path
398 if (in_array('..', $temp_path)){
399 $sizeofrp = array_count_values($temp_path);
402 //for IMSCC, assume that all resources lies in the same folder, except styles.css
403 if ($items[$current_identifier]['type']=='webcontent' || $items[$current_identifier]['type']=='imsdt_xmlv1p0'){
404 //find the intersection of each item's related files, then that intersection is the content_path
405 if (isset($items[$current_identifier]['file'])){
406 foreach ($items[$current_identifier]['file'] as $resource_path){
407 $temp_path = pathinfo($resource_path);
408 $temp_path = explode('/', $temp_path['dirname']);
409 $package_base_path = array_intersect_assoc($package_base_path, $temp_path);
415 if($sizeofrp['..'] > 0 && !empty($all_package_base_path)){
416 for ($i=0; $i<$sizeofrp['..']; $i++){
417 array_pop($all_package_base_path);
421 if (count($package_base_path) > 0) {
422 $items[$current_identifier]['new_path'] = implode('/', $package_base_path);
426 * @harris, reworked the package_base_path
427 if ($package_base_path=="") {
428 $package_base_path = $temp_path;
430 elseif (is_array($package_base_path) && $content_type != 'IMS Common Cartridge') {
431 //if this is a content package, we want only intersection
432 $package_base_path = array_intersect($package_base_path, $temp_path);
433 $temp_path = $package_base_path;
435 //added these 2 lines in so that pictures would load. making the elseif above redundant.
436 //if there is a bug for pictures not load, then it's the next 2 lines.
437 $package_base_path = array_intersect($package_base_path, $temp_path);
438 $temp_path = $package_base_path;
440 $items[$current_identifier]['new_path'] = implode('/', $temp_path);
442 if ( isset($_POST['allow_test_import']) && isset($items[$current_identifier])
443 && preg_match('/((.*)\/)*tests\_[0-9]+\.xml$/', $attrs['href'])) {
444 $items[$current_identifier]['tests'][] = $attrs['href'];
446 if ( isset($_POST['allow_a4a_import']) && isset($items[$current_identifier])) {
447 $items[$current_identifier]['a4a_import_enabled'] = true;
449 } else if (($name == 'item') && ($attrs['identifierref'] != '')) {
450 $path[] = $attrs['identifierref'];
451 } else if (($name == 'item') && ($attrs['identifier'])) {
452 $path[] = $attrs['identifier'];
453 // } else if (($name == 'resource') && is_array($items[$attrs['identifier']])) {
454 } else if (($name == 'resource')) {
455 $current_identifier = $attrs['identifier'];
456 $items[$current_identifier]['type'] = $attrs['type'];
457 if ($attrs['href']) {
458 $attrs['href'] = urldecode($attrs['href']);
460 $items[$attrs['identifier']]['href'] = $attrs['href'];
462 // href points to a remote url
463 if (preg_match('/^http.*:\/\//', trim($attrs['href']))) {
464 $items[$attrs['identifier']]['new_path'] = '';
465 } else // href points to local file
467 $temp_path = pathinfo($attrs['href']);
468 $temp_path = explode('/', $temp_path['dirname']);
469 // if (empty($package_base_path)) {
470 $package_base_path = $temp_path;
473 // $package_base_path = array_intersect($package_base_path, $temp_path);
475 $items[$attrs['identifier']]['new_path'] = implode('/', $temp_path);
479 //if test custom message has not been saved
480 // if (!isset($items[$current_identifier]['test_message'])){
481 // $items[$current_identifier]['test_message'] = $test_message;
483 } else if ($name=='dependency' && $attrs['identifierref']!='') {
484 //if there is a dependency, attach it to the item array['file']
485 $items[$current_identifier]['dependency'][] = $attrs['identifierref'];
487 if (($name == 'item') && ($attrs['parameters'] != '')) {
488 $items[$attrs['identifierref']]['test_message'] = $attrs['parameters'];
491 if(!isset($items[$current_identifier]) && $attrs['href']!=''){
492 $items[$current_identifier]['href'] = $attrs['href'];
494 if (substr($attrs['href'], 0, 7) == 'http://' || substr($attrs['href'], 0, 8) == 'https://' || file_exists($import_path.$attrs['href']) || $skip_ims_validation){
495 $items[$current_identifier]['file'][] = $attrs['href'];
497 $msg->addError(array('IMPORT_CARTRIDGE_FAILED', _AT(array('ims_files_missing', $attrs['href']))));
500 if ($name=='cc:authorizations'){
501 //don't have authorization setup.
502 //$msg->addError('');
503 $msg->addError('IMS_AUTHORIZATION_NOT_SUPPORT');
505 array_push($element_path, $name);
508 /* called when an element ends */
509 /* removed the current element from the $path */
510 function endElement($parser, $name) {
511 global $path, $element_path, $my_data, $items;
512 global $current_identifier, $skip_ims_validation;
513 global $msg, $content_type;
514 static $resource_num = 0;
516 if ($name == 'item') {
520 //check if this is a test import
521 if ($name == 'schema'){
522 if (trim($my_data)=='IMS Question and Test Interoperability'){
523 $msg->addError('IMPORT_FAILED');
525 $content_type = trim($my_data);
529 if ($current_identifier != ''){
530 $my_data = trim($my_data);
531 $last_file_name = $items[$current_identifier]['file'][(sizeof($items[$current_identifier]['file']))-1];
533 if ($name=='originalAccessMode'){
534 if (in_array('accessModeStatement', $element_path)){
535 $items[$current_identifier]['a4a'][$last_file_name][$resource_num]['access_stmt_originalAccessMode'] = $my_data;
536 } elseif (in_array('adaptationStatement', $element_path)){
537 $items[$current_identifier]['a4a'][$last_file_name][$resource_num]['adapt_stmt_originalAccessMode'] = $my_data;
539 } elseif (($name=='language') && in_array('accessModeStatement', $element_path)){
540 $items[$current_identifier]['a4a'][$last_file_name][$resource_num]['language'][] = $my_data;
541 } elseif ($name=='hasAdaptation') {
542 $items[$current_identifier]['a4a'][$last_file_name][$resource_num]['hasAdaptation'][] = $my_data;
543 } elseif ($name=='isAdaptationOf'){
544 $items[$current_identifier]['a4a'][$last_file_name][$resource_num]['isAdaptationOf'][] = $my_data;
545 } elseif ($name=='accessForAllResource'){
546 /* the head node of accessForAll Metadata, if this exists in the manifest. Skip XSD validation,
547 * because A4a doesn't have a xsd yet. Our access for all is based on ISO which will not pass
548 * the current IMS validation.
549 * Also, since ATutor is the only one (as of Oct 21, 2009) that exports IMS with access for all
550 * content, we can almost assume that any ims access for all content is by us, and is valid.
552 $skip_ims_validation = true;
554 } elseif($name=='file'){
555 $resource_num = 0; //reset resournce number to 0 when the file tags ends
559 if ($element_path === array('manifest', 'metadata', 'imsmd:lom', 'imsmd:general', 'imsmd:title', 'imsmd:langstring')) {
560 global $package_base_name;
561 $package_base_name = trim($my_data);
564 array_pop($element_path);
568 /* called when there is character data within elements */
569 /* constructs the $items array using the last entry in $path as the parent element */
570 function characterData($parser, $data){
571 global $path, $items, $order, $my_data, $element_path;
572 global $current_identifier;
574 $str_trimmed_data = trim($data);
576 if (!empty($str_trimmed_data)) {
577 $size = count($path);
579 $current_item_id = $path[$size-1];
581 $parent_item_id = $path[$size-2];
586 if (isset($items[$current_item_id]['parent_content_id']) && is_array($items[$current_item_id])) {
588 /* this item already exists, append the title */
589 /* this fixes {\n, \t, `, &} characters in elements */
591 /* horible kludge to fix the <ns2:objectiveDesc xmlns:ns2="http://www.utoronto.ca/atrc/tile/xsd/tile_objective"> */
593 if (in_array('accessForAllResource', $element_path)){
595 } elseif ($element_path[count($element_path)-1] != 'ns1:objectiveDesc') {
596 $items[$current_item_id]['title'] .= $data;
600 $order[$parent_item_id] ++;
601 $item_tmpl = array( 'title' => $data,
602 'parent_content_id' => $parent_item_id,
603 'ordering' => $order[$parent_item_id]-1);
604 //append other array values if it exists
605 if (is_array($items[$current_item_id])){
606 $items[$current_item_id] = array_merge($items[$current_item_id], $item_tmpl);
608 $items[$current_item_id] = $item_tmpl;
617 /* glossary parser: */
618 function glossaryStartElement($parser, $name, $attrs) {
619 global $element_path;
621 array_push($element_path, $name);
624 /* called when an element ends */
625 /* removed the current element from the $path */
626 function glossaryEndElement($parser, $name) {
627 global $element_path, $my_data, $imported_glossary;
628 static $current_term;
630 if ($element_path === array('glossary', 'item', 'term') ||
631 $element_path === array('glossary:glossary', 'item', 'term')) {
632 $current_term = $my_data;
634 } else if ($element_path === array('glossary', 'item', 'definition') ||
635 $element_path === array('glossary:glossary', 'item', 'definition')) {
636 $imported_glossary[trim($current_term)] = trim($my_data);
639 array_pop($element_path);
643 function glossaryCharacterData($parser, $data){
649 if (!isset($_POST['submit']) && !isset($_POST['cancel'])) {
650 /* just a catch all */
652 $errors = array('FILE_MAX_SIZE', ini_get('post_max_size'));
653 $msg->addError($errors);
655 header('Location: ./index.php');
657 } else if (isset($_POST['cancel'])) {
658 $msg->addFeedback('IMPORT_CANCELLED');
660 header('Location: ../content/index.php');
664 $cid = intval($_POST['cid']);
666 //If user chooses to ignore validation.
667 if(isset($_POST['ignore_validation']) && $_POST['ignore_validation']==1) {
668 $skip_ims_validation = true;
671 if (isset($_POST['url']) && ($_POST['url'] != 'http://') ) {
672 if ($content = @file_get_contents($_POST['url'])) {
673 // save file to /content/
674 $filename = substr(time(), -6). '.zip';
675 $full_filename = AT_CONTENT_DIR . $filename;
677 if (!$fp = fopen($full_filename, 'w+b')) {
678 echo "Cannot open file ($filename)";
682 if (fwrite($fp, $content, strlen($content) ) === FALSE) {
683 echo "Cannot write to file ($filename)";
688 $_FILES['file']['name'] = $filename;
689 $_FILES['file']['tmp_name'] = $full_filename;
690 $_FILES['file']['size'] = strlen($content);
692 $url_parts = pathinfo($_POST['url']);
693 $package_base_name_url = $url_parts['basename'];
695 $ext = pathinfo($_FILES['file']['name']);
696 $ext = $ext['extension'];
699 $msg->addError('IMPORTDIR_IMS_NOTVALID');
700 } else if ($_FILES['file']['error'] == 1) {
701 $errors = array('FILE_MAX_SIZE', ini_get('upload_max_filesize'));
702 $msg->addError($errors);
703 } else if ( !$_FILES['file']['name'] || (!is_uploaded_file($_FILES['file']['tmp_name']) && !$_POST['url'])) {
704 $msg->addError('FILE_NOT_SELECTED');
705 } else if ($_FILES['file']['size'] == 0) {
706 $msg->addError('IMPORTFILE_EMPTY');
709 if ($msg->containsErrors()) {
710 if (isset($_GET['tile'])) {
711 header('Location: '.$_base_path.'mods/_standard/tile_search/index.php');
713 header('Location: index.php');
718 /* check if ../content/import/ exists */
719 $import_path = AT_CONTENT_DIR . 'import/';
720 $content_path = AT_CONTENT_DIR;
722 if (!is_dir($import_path)) {
723 if (!@mkdir($import_path, 0700)) {
724 $msg->addError('IMPORTDIR_FAILED');
728 $import_path .= $_SESSION['course_id'].'/';
729 if (is_dir($import_path)) {
730 clr_dir($import_path);
733 if (!@mkdir($import_path, 0700)) {
734 $msg->addError('IMPORTDIR_FAILED');
737 if ($msg->containsErrors()) {
738 if (isset($_GET['tile'])) {
739 header('Location: '.$_base_path.'mods/_standard/tile_search/index.php');
741 header('Location: index.php');
746 /* extract the entire archive into AT_COURSE_CONTENT . import/$course using the call back function to filter out php files */
748 $archive = new PclZip($_FILES['file']['tmp_name']);
749 if ($archive->extract( PCLZIP_OPT_PATH, $import_path,
750 PCLZIP_CB_PRE_EXTRACT, 'preImportCallBack') == 0) {
751 $msg->addError('IMPORT_FAILED');
752 echo 'Error : '.$archive->errorInfo(true);
753 clr_dir($import_path);
754 header('Location: index.php');
757 error_reporting(AT_ERROR_REPORTING);
759 /* get the course's max_quota */
760 $sql = "SELECT max_quota FROM ".TABLE_PREFIX."courses WHERE course_id=$_SESSION[course_id]";
761 $result = mysql_query($sql, $db);
762 $q_row = mysql_fetch_assoc($result);
764 if ($q_row['max_quota'] != AT_COURSESIZE_UNLIMITED) {
766 if ($q_row['max_quota'] == AT_COURSESIZE_DEFAULT) {
767 $q_row['max_quota'] = $MaxCourseSize;
769 $totalBytes = dirsize($import_path);
770 $course_total = dirsize(AT_CONTENT_DIR . $_SESSION['course_id'].'/');
771 $total_after = $q_row['max_quota'] - $course_total - $totalBytes + $MaxCourseFloat;
773 if ($total_after < 0) {
774 /* remove the content dir, since there's no space for it */
775 $errors = array('NO_CONTENT_SPACE', number_format(-1*($total_after/AT_KBYTE_SIZE), 2 ) );
776 $msg->addError($errors);
778 clr_dir($import_path);
780 if (isset($_GET['tile'])) {
781 header('Location: '.$_base_path.'mods/_standard/tile_search/index.php');
783 header('Location: index.php');
790 $items = array(); /* all the content pages */
791 $order = array(); /* keeps track of the ordering for each content page */
792 $path = array(); /* the hierarchy path taken in the menu to get to the current item in the manifest */
793 $dependency_files = array(); /* the file path for the dependency files */
796 $items[content_id/resource_id] = array(
798 'real_content_id' // calculated after being inserted
804 $ims_manifest_xml = @file_get_contents($import_path.'imsmanifest.xml');
805 //scan for manifest xml if it's not on the top level.
806 if ($ims_manifest_xml === false){
807 $data = rscandir($import_path);
808 $manifest_array = array();
809 foreach($data as $scanned_file){
810 $scanned_file = realpath($scanned_file);
811 //change the file string to an array
812 $this_file_array = explode(DIRECTORY_SEPARATOR, $scanned_file);
813 if(empty($manifest_array)){
814 $manifest_array = $this_file_array;
816 $manifest_array = array_intersect_assoc($this_file_array, $manifest_array);
818 if (strpos($scanned_file, 'imsmanifest')!==false){
819 $ims_manifest_xml = @file_get_contents($scanned_file);
822 if ($ims_manifest_xml !== false){
823 $import_path = implode(DIRECTORY_SEPARATOR, $manifest_array) . DIRECTORY_SEPARATOR;
827 //if no imsmanifest.xml found in the entire package, throw error.
828 if ($ims_manifest_xml === false) {
829 $msg->addError('NO_IMSMANIFEST');
831 if (file_exists($import_path . 'atutor_backup_version')) {
832 $msg->addError('NO_IMS_BACKUP');
834 clr_dir($import_path);
836 if (isset($_GET['tile'])) {
837 header('Location: '.$_base_path.'mods/_standard/tile_search/index.php');
839 header('Location: index.php');
844 $xml_parser = xml_parser_create();
846 xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, false); /* conform to W3C specs */
847 xml_set_element_handler($xml_parser, 'startElement', 'endElement');
848 xml_set_character_data_handler($xml_parser, 'characterData');
850 if (!xml_parse($xml_parser, $ims_manifest_xml, true)) {
851 die(sprintf("XML error: %s at line %d",
852 xml_error_string(xml_get_error_code($xml_parser)),
853 xml_get_current_line_number($xml_parser)));
855 xml_parser_free($xml_parser);
856 /* check if the glossary terms exist */
858 if ($content_type == 'IMS Common Cartridge'){
859 $glossary_path = 'resources/GlossaryItem/';
860 // $package_base_path = '';
862 if (file_exists($import_path . $glossary_path . 'glossary.xml')){
863 $glossary_xml = @file_get_contents($import_path.$glossary_path.'glossary.xml');
864 $element_path = array();
865 $xml_parser = xml_parser_create();
867 /* insert the glossary terms into the database (if they're not in there already) */
868 /* parse the glossary.xml file and insert the terms */
869 xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, false); /* conform to W3C specs */
870 xml_set_element_handler($xml_parser, 'glossaryStartElement', 'glossaryEndElement');
871 xml_set_character_data_handler($xml_parser, 'glossaryCharacterData');
873 if (!xml_parse($xml_parser, $glossary_xml, true)) {
874 die(sprintf("XML error: %s at line %d",
875 xml_error_string(xml_get_error_code($xml_parser)),
876 xml_get_current_line_number($xml_parser)));
878 xml_parser_free($xml_parser);
879 $contains_glossary_terms = true;
880 foreach ($imported_glossary as $term => $defn) {
881 if (!$glossary[$term]) {
882 $sql = "INSERT INTO ".TABLE_PREFIX."glossary VALUES (NULL, $_SESSION[course_id], '$term', '$defn', 0)";
883 mysql_query($sql, $db);
888 // Check if all the files exists in the manifest, iff it's a IMS CC package.
889 if ($content_type == 'IMS Common Cartridge') {
890 checkResources($import_path);
893 // Check if there are any errors during parsing.
894 if ($msg->containsErrors()) {
895 if (isset($_GET['tile'])) {
896 header('Location: '.$_base_path.'mods/_standard/tile_search/index.php');
898 header('Location: index.php');
903 /* generate a unique new package base path based on the package file name and date as needed. */
904 /* the package name will be the dir where the content for this package will be put, as a result */
905 /* the 'content_path' field in the content table will be set to this path. */
906 /* $package_base_name_url comes from the URL file name (NOT the file name of the actual file we open)*/
907 if (!$package_base_name && $package_base_name_url) {
908 $package_base_name = substr($package_base_name_url, 0, -4);
909 } else if (!$package_base_name) {
910 $package_base_name = substr($_FILES['file']['name'], 0, -4);
913 $package_base_name = strtolower($package_base_name);
914 $package_base_name = str_replace(array('\'', '"', ' ', '|', '\\', '/', '<', '>', ':'), '_' , $package_base_name);
915 $package_base_name = preg_replace("/[^A-Za-z0-9._\-]/", '', $package_base_name);
917 if (is_dir(AT_CONTENT_DIR . $_SESSION['course_id'].'/'.$package_base_name)) {
918 $package_base_name .= '_'.date('ymdHis');
921 if ($package_base_path) {
922 $package_base_path = implode('/', $package_base_path);
923 } elseif (empty($package_base_path)){
924 $package_base_path = '';
927 if ($xml_base_path) {
928 $package_base_path = $xml_base_path . $package_base_path;
930 mkdir(AT_CONTENT_DIR .$_SESSION['course_id'].'/'.$xml_base_path);
931 $package_base_name = $xml_base_path . $package_base_name;
934 /* get the top level content ordering offset */
935 $sql = "SELECT MAX(ordering) AS ordering FROM ".TABLE_PREFIX."content WHERE course_id=$_SESSION[course_id] AND content_parent_id=$cid";
936 $result = mysql_query($sql, $db);
937 $row = mysql_fetch_assoc($result);
938 $order_offset = intval($row['ordering']); /* it's nice to have a real number to deal with */
939 $lti_offset = array(); //since we don't need lti tools, the ordering needs to be subtracted
940 //reorder the items stack
941 $items = rehash($items);
942 //debug($items);exit;
943 foreach ($items as $item_id => $content_info)
945 //formatting field, default 1
946 $content_formatting = 1; //CONTENT_TYPE_CONTENT
948 //don't want to display glossary as a page
949 if ($content_info['href']== $glossary_path . 'glossary.xml'){
953 //if discussion tools, add it to the list of unhandled dts
954 if ($content_info['type']=='imsdt_xmlv1p0'){
955 //if it will be taken care after (has dependency), then move along.
956 if (in_array($item_id, $avail_dt)){
957 $lti_offset[$content_info['parent_content_id']]++;
962 //handle the special case of cc import, where there is no content association. The resource should
964 if(!isset($content_info['parent_content_id'])){
965 //if this is a question bank
966 if ($content_info['type']=="imsqti_xmlv1p2/imscc_xmlv1p0/question-bank"){
967 addQuestions($content_info['href'], $content_info, $import_path);
971 //if it has no title, most likely it is not a page but just a normal item, skip it
972 if (!isset($content_info['title'])){
976 //check dependency immediately, then handles it
978 if (is_array($content_info['dependency']) && !empty($content_info['dependency'])){
979 foreach($content_info['dependency'] as $dependency_ref){
981 /** handled by get_html_head in vitals.inc.php
982 if (preg_match('/(.*)\.css$/', $items[$dependency_ref]['href'])){
983 //calculate where this is based on our current base_href.
984 //assuming the dependency folders are siblings of the item
985 $head = '<link rel="stylesheet" type="text/css" href="../'.$items[$dependency_ref]['href'].'" />';
988 //check if this is a discussion tool dependency
989 if ($items[$dependency_ref]['type']=='imsdt_xmlv1p0'){
990 $items[$item_id]['forum'][$dependency_ref] = $items[$dependency_ref]['href'];
992 //check if this is a QTI dependency
993 if (strpos($items[$dependency_ref]['type'], 'imsqti_xmlv1p2/imscc_xmlv1p0') !== false){
994 $items[$item_id]['tests'][$dependency_ref] = $items[$dependency_ref]['href'];
999 //check file array, see if there are css.
1000 //edited nov 26, harris
1001 //removed cuz i added link to the html_tags
1003 if (is_array($content_info['file']) && !empty($content_info['file'])){
1004 foreach($content_info['file'] as $dependency_ref){
1006 if (preg_match('/(.*)\.css$/', $dependency_ref)){
1007 //calculate where this is based on our current base_href.
1008 //assuming the dependency folders are siblings of the item
1009 $head = '<link rel="stylesheet" type="text/css" href="'.$dependency_ref.'" />';
1016 if (preg_match('/^http.*:\/\//', trim($content_info['href'])) )
1018 $content = '<a href="'.$content_info['href'].'" target="_blank">'.$content_info['title'].'</a>';
1022 if ($content_type == 'IMS Common Cartridge'){
1023 //to handle import with purely images but nothing else
1024 //don't need a content base path for it.
1025 $content_new_path = $content_info['new_path'];
1026 $content_info['new_path'] = '';
1028 if (isset($content_info['href'], $xml_base_path)) {
1029 $content_info['href'] = $xml_base_path . $content_info['href'];
1031 if (!isset($content_info['href'])) {
1032 // this item doesn't have an identifierref. so create an empty page.
1033 // what we called a folder according to v1.2 Content Packaging spec
1037 $last_modified = date('Y-m-d H:i:s');
1039 //$file_info = @stat(AT_CONTENT_DIR . 'import/'.$_SESSION['course_id'].'/'.$content_info['href']);
1040 $file_info = @stat($import_path.$content_info['href']);
1041 if ($file_info === false) {
1045 //$path_parts = pathinfo(AT_CONTENT_DIR . 'import/'.$_SESSION['course_id'].'/'.$content_info['href']);
1046 $path_parts = pathinfo($import_path.$content_info['href']);
1047 $ext = strtolower($path_parts['extension']);
1049 $last_modified = date('Y-m-d H:i:s', $file_info['mtime']);
1051 if (in_array($ext, array('gif', 'jpg', 'bmp', 'png', 'jpeg'))) {
1052 /* this is an image */
1053 $content = '<img src="'.$content_info['href'].'" alt="'.$content_info['title'].'" />';
1054 } else if ($ext == 'swf') {
1056 /* Using default size of 550 x 400 */
1058 $content = '<object type="application/x-shockwave-flash" data="' . $content_info['href'] . '" width="550" height="400"><param name="movie" value="'. $content_info['href'] .'" /></object>';
1060 } else if ($ext == 'mov') {
1061 /* this is a quicktime movie */
1062 /* Using default size of 550 x 400 */
1064 $content = '<object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" width="550" height="400" codebase="http://www.apple.com/qtactivex/qtplugin.cab"><param name="src" value="'. $content_info['href'] . '" /><param name="autoplay" value="true" /><param name="controller" value="true" /><embed src="' . $content_info['href'] .'" width="550" height="400" controller="true" pluginspage="http://www.apple.com/quicktime/download/"></embed></object>';
1067 * commenting this whole chunk out. It's part of my test import codes, not sure why it's here,
1068 * and I don't think it should be here. Remove this whole comment after further testing and confirmation.
1071 //Mimic the array for now.
1072 $test_attributes['resource']['href'] = $test_xml_file;
1073 $test_attributes['resource']['type'] = isset($items[$item_id]['type'])?'imsqti_xmlv1p2':'imsqti_xmlv1p1';
1074 $test_attributes['resource']['file'] = $items[$item_id]['file'];
1075 // $test_attributes['resource']['file'] = array($test_xml_file);
1077 //Get the XML file out and start importing them into our database.
1078 //TODO: See question_import.php 287-289.
1079 $qids = $qti_import->importQuestions($test_attributes);
1082 } else if ($ext == 'mp3') {
1083 $content = '<object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" width="200" height="15" codebase="http://www.apple.com/qtactivex/qtplugin.cab"><param name="src" value="'. $content_info['href'] . '" /><param name="autoplay" value="false" /><embed src="' . $content_info['href'] .'" width="200" height="15" autoplay="false" pluginspage="http://www.apple.com/quicktime/download/"></embed></object>';
1084 } else if (in_array($ext, array('wav', 'au'))) {
1085 $content = '<embed SRC="'.$content_info['href'].'" autostart="false" width="145" height="60"><noembed><bgsound src="'.$content_info['href'].'"></noembed></embed>';
1087 } else if (in_array($ext, array('txt', 'css', 'html', 'htm', 'csv', 'asc', 'tsv', 'xml', 'xsl'))) {
1088 if ($content_type == 'IMS Common Cartridge'){
1089 $content_info['new_path'] = $content_new_path;
1092 /* this is a plain text file */
1093 //$content = file_get_contents(AT_CONTENT_DIR . 'import/'.$_SESSION['course_id'].'/'.$content_info['href']);
1094 $content = file_get_contents($import_path.$content_info['href']);
1095 if ($content === false) {
1096 /* if we can't stat() it then we're unlikely to be able to read it */
1097 /* so we'll never get here. */
1101 // get the contents of the 'head' element
1102 $head .= get_html_head_by_tag($content, $html_head_tags);
1104 // Specifically handle eXe package
1105 // NOTE: THIS NEEDS WORK! TO FIND A WAY APPLY EXE .CSS FILES ONLY ON COURSE CONTENT PART.
1106 // NOW USE OUR OWN .CSS CREATED SOLELY FOR EXE
1107 $isExeContent = false;
1109 // check xml file in eXe package
1110 if (preg_match("/<organization[ ]*identifier=\"eXe*>*/", $ims_manifest_xml))
1112 $isExeContent = true;
1115 // use ATutor's eXe style sheet as the ones from eXe conflicts with ATutor's style sheets
1118 $head = preg_replace ('/(<style.*>)(.*)(<\/style>)/ms', '\\1@import url(/docs/exestyles.css);\\3', $head);
1121 // end of specifically handle eXe package
1123 $content = get_html_body($content);
1124 if ($contains_glossary_terms)
1126 // replace glossary content package links to real glossary mark-up using [?] [/?]
1127 // refer to bug 3641, edited by Harris
1128 $content = preg_replace('/<a href="([.\w\d\s]+[^"]+)" target="body" class="at-term">([.\w\d\s&;"]+|.*)<\/a>/i', '[?]\\2[/?]', $content);
1131 /* potential security risk? */
1132 if ( strpos($content_info['href'], '..') === false && !preg_match('/((.*)\/)*tests\_[0-9]+\.xml$/', $content_info['href'])) {
1133 // @unlink(AT_CONTENT_DIR . 'import/'.$_SESSION['course_id'].'/'.$content_info['href']);
1136 /* overwrite content if this is discussion tool. */
1137 if ($content_info['type']=='imsdt_xmlv1p0'){
1138 $dt_parser = new DiscussionToolsParser();
1139 $xml_content = @file_get_contents($import_path . $content_info['href']);
1140 $dt_parser->parse($xml_content);
1141 $forum_obj = $dt_parser->getDt();
1142 $content = $forum_obj->getText();
1144 $dt_parser->close();
1147 /* non text file, and can't embed (example: PDF files) */
1148 $content = '<a href="'.$content_info['href'].'">'.$content_info['title'].'</a>';
1151 $content_parent_id = $cid;
1152 if ($content_info['parent_content_id'] !== 0) {
1153 $content_parent_id = $items[$content_info['parent_content_id']]['real_content_id'];
1154 //if it's not there, use $cid
1155 if (!$content_parent_id){
1156 $content_parent_id = $cid;
1161 if ($content_parent_id == $cid) {
1162 $my_offset = $order_offset;
1165 /* replace the old path greatest common denomiator with the new package path. */
1166 /* we don't use str_replace, b/c there's no knowing what the paths may be */
1167 /* we only want to replace the first part of the path.
1169 if(is_array($all_package_base_path)){
1170 $all_package_base_path = implode('/', $all_package_base_path);
1173 if ($all_package_base_path != '') {
1174 $content_info['new_path'] = $package_base_name . substr($content_info['new_path'], strlen($all_package_base_path));
1176 $content_info['new_path'] = $package_base_name . '/' . $content_info['new_path'];
1180 if ($content_info['type']=='imswl_xmlv1p0'){
1181 $weblinks_parser = new WeblinksParser();
1182 $xml_content = @file_get_contents($import_path . $content_info['href']);
1183 $weblinks_parser->parse($xml_content);
1184 $content_info['title'] = $weblinks_parser->getTitle();
1185 $content = $weblinks_parser->getUrl();
1186 $content_folder_type = CONTENT_TYPE_WEBLINK;
1187 $content_formatting = 2;
1189 $head = addslashes($head);
1190 $content_info['title'] = addslashes($content_info['title']);
1191 $content_info['test_message'] = addslashes($content_info['test_message']);
1193 //if this file is a test_xml, create a blank page instead, for imscc.
1194 if (preg_match('/((.*)\/)*tests\_[0-9]+\.xml$/', $content_info['href'])
1195 || preg_match('/imsqti\_(.*)/', $content_info['type'])) {
1198 $content = addslashes($content);
1201 //check for content_type
1202 if ($content_formatting!=CONTENT_TYPE_WEBLINK){
1203 $content_folder_type = (!isset($content_info['type'])?CONTENT_TYPE_FOLDER:CONTENT_TYPE_CONTENT);
1206 $sql= 'INSERT INTO '.TABLE_PREFIX.'content'
1215 use_customized_head,
1223 ('.$_SESSION['course_id'].','
1224 .intval($content_parent_id).','
1225 .($content_info['ordering'] + $my_offset - $lti_offset[$content_info['parent_content_id']] + 1).','
1226 .'"'.$last_modified.'",
1228 .$content_formatting.' ,
1233 .'"'.$content_info['new_path'].'",'
1234 .'"'.$content_info['title'].'",'
1236 .'"'.$content_info['test_message'].'",'
1237 .$content_folder_type.')';
1239 $result = mysql_query($sql, $db) or die(mysql_error());
1241 /* get the content id and update $items */
1242 $items[$item_id]['real_content_id'] = mysql_insert_id($db);
1244 /* get the tests associated with this content */
1245 if (!empty($items[$item_id]['tests']) || strpos($items[$item_id]['type'], 'imsqti_xmlv1p2/imscc_xmlv1p0') !== false){
1246 $qti_import = new QTIImport($import_path);
1247 if (isset($items[$item_id]['tests'])){
1248 $loop_var = $items[$item_id]['tests'];
1250 $loop_var = $items[$item_id]['file'];
1253 foreach ($loop_var as $array_id => $test_xml_file){
1254 //check if this item is the qti item object, or it is the content item obj
1255 //switch it to qti obj if it's content item obj
1256 if ($items[$item_id]['type'] == 'webcontent'){
1257 $item_qti = $items[$array_id];
1259 $item_qti = $items[$item_id];
1261 //call subrountine to add the questions.
1262 $qids = addQuestions($test_xml_file, $item_qti, $import_path);
1265 if ($test_title==''){
1266 $test_title = $content_info['title'];
1269 $tid = $qti_import->importTest($test_title);
1271 //associate question and tests
1272 foreach ($qids as $order=>$qid){
1273 if (isset($qti_import->weights[$order])){
1274 $weight = round($qti_import->weights[$order]);
1278 $new_order = $order + 1;
1279 $sql = "INSERT INTO " . TABLE_PREFIX . "tests_questions_assoc" .
1280 "(test_id, question_id, weight, ordering, required) " .
1281 "VALUES ($tid, $qid, $weight, $new_order, 0)";
1282 $result = mysql_query($sql, $db);
1285 //associate content and test
1286 $sql = 'INSERT INTO ' . TABLE_PREFIX . 'content_tests_assoc' .
1287 '(content_id, test_id) ' .
1288 'VALUES (' . $items[$item_id]['real_content_id'] . ", $tid)";
1289 $result = mysql_query($sql, $db);
1291 // if (!$msg->containsErrors()) {
1292 // $msg->addFeedback('IMPORT_SUCCEEDED');
1297 /* get the a4a related xml */
1298 if (isset($items[$item_id]['a4a_import_enabled']) && isset($items[$item_id]['a4a']) && !empty($items[$item_id]['a4a'])) {
1299 $a4a_import = new A4aImport($items[$item_id]['real_content_id']);
1300 $a4a_import->setRelativePath($items[$item_id]['new_path']);
1301 $a4a_import->importA4a($items[$item_id]['a4a']);
1304 /* get the discussion tools (dependent to content)*/
1305 if (isset($items[$item_id]['forum']) && !empty($items[$item_id]['forum'])){
1306 foreach($items[$item_id]['forum'] as $forum_ref => $forum_link){
1307 $dt_parser = new DiscussionToolsParser();
1308 $dt_import = new DiscussionToolsImport();
1310 //if this forum has not been added, parse it and add it.
1311 if (!isset($added_dt[$forum_ref])){
1312 $xml_content = @file_get_contents($import_path . $forum_link);
1313 $dt_parser->parse($xml_content);
1314 $forum_obj = $dt_parser->getDt();
1315 $dt_import->import($forum_obj, $items[$item_id]['real_content_id']);
1316 $added_dt[$forum_ref] = $dt_import->getFid();
1318 //associate the fid and content id
1319 $dt_import->associateForum($items[$item_id]['real_content_id'], $added_dt[$forum_ref]);
1321 } elseif ($items[$item_id]['type']=='imsdt_xmlv1p0'){
1322 //optimize this, repeated codes as above
1323 $dt_parser = new DiscussionToolsParser();
1324 $dt_import = new DiscussionToolsImport();
1325 $xml_content = @file_get_contents($import_path . $content_info['href']);
1326 $dt_parser->parse($xml_content);
1327 $forum_obj = $dt_parser->getDt();
1328 $dt_import->import($forum_obj, $items[$item_id]['real_content_id']);
1329 $added_dt[$item_id] = $dt_import->getFid();
1331 //associate the fid and content id
1332 $dt_import->associateForum($items[$item_id]['real_content_id'], $added_dt[$item_id]);
1336 if ($package_base_path == '.') {
1337 $package_base_path = '';
1340 // loop through the files outside the package folder, and copy them to its relative path
1341 if (is_dir(AT_CONTENT_DIR . 'import/'.$_SESSION['course_id'].'/resources')) {
1342 $handler = opendir(AT_CONTENT_DIR . 'import/'.$_SESSION['course_id'].'/resources');
1343 while ($file = readdir($handler)){
1344 $filename = AT_CONTENT_DIR . 'import/'.$_SESSION['course_id'].'/resources/'.$file;
1345 if(is_file($filename)){
1346 @rename($filename, AT_CONTENT_DIR .$_SESSION['course_id'].'/'.$package_base_name.'/'.$file);
1351 //takes care of the condition where the whole package doesn't have any contents but question banks
1352 if(is_array($all_package_base_path)){
1353 $all_package_base_path = implode('/', $all_package_base_path);
1356 if (@rename($import_path.$all_package_base_path, AT_CONTENT_DIR .$_SESSION['course_id'].'/'.$package_base_name) === false) {
1357 if (!$msg->containsErrors()) {
1358 $msg->addError('IMPORT_FAILED');
1361 //check if there are still resources missing
1362 foreach($items as $idetails){
1363 $temp_path = pathinfo($idetails['href']);
1364 @rename(AT_CONTENT_DIR . 'import/'.$_SESSION['course_id'].'/'.$temp_path['dirname'], AT_CONTENT_DIR .$_SESSION['course_id'].'/'.$package_base_name . '/' . $temp_path['dirname']);
1366 clr_dir(AT_CONTENT_DIR . 'import/'.$_SESSION['course_id']);
1368 if (file_exists($full_filename)) {
1369 @unlink($full_filename);
1373 if ($_POST['s_cid']){
1374 if (!$msg->containsErrors()) {
1375 $msg->addFeedback('ACTION_COMPLETED_SUCCESSFULLY');
1377 header('Location: ../editor/edit_content.php?cid='.intval($_POST['cid']));
1380 if (!$msg->containsErrors()) {
1381 $msg->addFeedback('ACTION_COMPLETED_SUCCESSFULLY');
1383 if ($_GET['tile']) {
1384 header('Location: '.AT_BASE_HREF.'mods/_standard/tile_search/index.php');
1386 header('Location: ./index.php?cid='.intval($_POST['cid']));