Example #1
0
 * Init request vars
 */
if (!empty($_REQUEST['relativePath']) && $_REQUEST['relativePath'] != '/' && $_REQUEST['relativePath'] != '.') {
    $relativePath = str_replace('..', '', $_REQUEST['relativePath']) . '/';
} else {
    $relativePath = '/';
}
/*
 * Handle upload
 */
if ($is_allowedToEdit && isset($_FILES['sentFile']['tmp_name']) && is_uploaded_file($_FILES['sentFile']['tmp_name'])) {
    $imgFile = $_FILES['sentFile'];
    $imgFile['name'] = replace_dangerous_char($imgFile['name'], 'strict');
    $imgFile['name'] = get_secure_file_name($imgFile['name']);
    if (claro_is_in_a_course()) {
        $enoughSize = enough_size($_FILES['sentFile']['size'], $pathSys, $maxFilledSpace);
    } else {
        $enoughSize = true;
    }
    if (is_image($imgFile['name']) && $enoughSize) {
        // rename if file already exists
        if (file_exists($pathSys . $relativePath . $imgFile['name'])) {
            $pieceList = explode('.', $imgFile['name']);
            $base = $pieceList[0];
            $ext = $pieceList[1];
            $i = 1;
            while (file_exists($pathSys . $relativePath . $base . '_' . $i . '.' . $ext)) {
                $i++;
            }
            $imgFile['name'] = $base . '_' . $i . '.' . $ext;
            $alertMessage = get_lang('A file with this name already exists.') . "\n" . get_lang('Your file has been renamed to %filename', array('%filename' => $imgFile['name']));
 // this line will be removed if an error occurs
 $rankMax = 1 + intval(Database::get()->querySingle("SELECT MAX(`rank`) AS max\n            FROM `lp_learnPath` WHERE `course_id` = ?d", $course_id)->max);
 $tempPathId = Database::get()->query("INSERT INTO `lp_learnPath`\n            (`course_id`, `name`,`visible`,`rank`,`comment`)\n            VALUES (?d, ?s, 0, ?d,'')", $course_id, $lpName, $rankMax)->lastInsertID;
 $baseWorkDir .= "path_" . $tempPathId;
 if (!is_dir($baseWorkDir)) {
     claro_mkdir($baseWorkDir, CLARO_FILE_PERMISSIONS);
 }
 // unzip package
 require_once "include/pclzip/pclzip.lib.php";
 /*
  * Check if the file is valid (not to big and exists)
  */
 if (!isset($_FILES['uploadedPackage']) || !is_uploaded_file($_FILES['uploadedPackage']['tmp_name'])) {
     $errorFound = true;
     array_push($errorMsgs, $langFileScormError);
 } elseif (!enough_size($_FILES['uploadedPackage']['size'], $baseWorkDir, $maxFilledSpace)) {
     $errorFound = true;
     array_push($errorMsgs, $langNoSpace);
 } elseif (preg_match("/.zip\$/i", $_FILES['uploadedPackage']['name'])) {
     array_push($okMsgs, $langOkFileReceived . basename($_FILES['uploadedPackage']['name']));
     if (!function_exists('gzopen')) {
         $errorFound = true;
         array_push($errorMsgs, $langErrorNoZlibExtension);
     } else {
         $zipFile = new pclZip($_FILES['uploadedPackage']['tmp_name']);
         $is_allowedToUnzip = true;
         // default initialisation
         // Check the zip content (real size and file extension)
         $zipContentArray = $zipFile->listContent();
         if ($zipContentArray == 0) {
             $errorFound = true;
Example #3
0
 /**
  * Imports a zip file (presumably AICC) into the Dokeos structure
  * @param	string	Zip file info as given by $_FILES['userFile']
  * @return	string	Absolute path to the AICC config files directory or empty string on error
  */
 function import_package($zip_file_info, $current_dir = '')
 {
     if ($this->debug > 0) {
         error_log('In aicc::import_package(' . print_r($zip_file_info, true) . ',"' . $current_dir . '") method', 0);
     }
     //ini_set('error_log','E_ALL');
     $maxFilledSpace = 1000000000;
     $zip_file_path = $zip_file_info['tmp_name'];
     $zip_file_name = $zip_file_info['name'];
     if ($this->debug > 0) {
         error_log('New LP - aicc::import_package() - Zip file path = ' . $zip_file_path . ', zip file name = ' . $zip_file_name, 0);
     }
     $course_rel_dir = api_get_course_path() . '/scorm';
     //scorm dir web path starting from /courses
     $course_sys_dir = api_get_path(SYS_COURSE_PATH) . $course_rel_dir;
     //absolute system path for this course
     $current_dir = replace_dangerous_char(trim($current_dir), 'strict');
     //current dir we are in, inside scorm/
     if ($this->debug > 0) {
         error_log('New LP - aicc::import_package() - Current_dir = ' . $current_dir, 0);
     }
     //$uploaded_filename = $_FILES['userFile']['name'];
     //get name of the zip file without the extension
     if ($this->debug > 0) {
         error_log('New LP - aicc::import_package() - Received zip file name: ' . $zip_file_path, 0);
     }
     $file_info = pathinfo($zip_file_name);
     $filename = $file_info['basename'];
     $extension = $file_info['extension'];
     $file_base_name = str_replace('.' . $extension, '', $filename);
     //filename without its extension
     $this->zipname = $file_base_name;
     //save for later in case we don't have a title
     if ($this->debug > 0) {
         error_log('New LP - aicc::import_package() - Base file name is : ' . $file_base_name, 0);
     }
     $new_dir = replace_dangerous_char(trim($file_base_name), 'strict');
     $this->subdir = $new_dir;
     if ($this->debug > 0) {
         error_log('New LP - aicc::import_package() - Subdir is first set to : ' . $this->subdir, 0);
     }
     /*
     		if( check_name_exist($course_sys_dir.$current_dir."/".$new_dir) )
     		{
     			$dialogBox = get_lang('FileExists');
     			$stopping_error = true;
     		}
     */
     $zipFile = new pclZip($zip_file_path);
     // Check the zip content (real size and file extension)
     $zipContentArray = $zipFile->listContent();
     $package_type = '';
     //the type of the package. Should be 'aicc' after the next few lines
     $package = '';
     //the basename of the config files (if 'courses.crs' => 'courses')
     $at_root = false;
     //check if the config files are at zip root
     $config_dir = '';
     //the directory in which the config files are. May remain empty
     $files_found = array();
     $subdir_isset = false;
     //the following loop should be stopped as soon as we found the right config files (.crs, .au, .des and .cst)
     foreach ($zipContentArray as $thisContent) {
         if (preg_match('~.(php.*|phtml)$~i', $thisContent['filename'])) {
             //if a php file is found, do not authorize (security risk)
             if ($this->debug > 1) {
                 error_log('New LP - aicc::import_package() - Found unauthorized file: ' . $thisContent['filename'], 0);
             }
             return api_failure::set_failure('php_file_in_zip_file');
         } elseif (preg_match('?.*/aicc/$?', $thisContent['filename'])) {
             //if a directory named 'aicc' is found, package type = aicc, but continue
             //because we need to find the right AICC files
             if ($this->debug > 1) {
                 error_log('New LP - aicc::import_package() - Found aicc directory: ' . $thisContent['filename'], 0);
             }
             $package_type = 'aicc';
         } else {
             //else, look for one of the files we're searching for (something.crs case insensitive)
             $res = array();
             if (preg_match('?^(.*)\\.(crs|au|des|cst|ore|pre|cmp)$?i', $thisContent['filename'], $res)) {
                 if ($this->debug > 1) {
                     error_log('New LP - aicc::import_package() - Found AICC config file: ' . $thisContent['filename'] . '. Now splitting: ' . $res[1] . ' and ' . $res[2], 0);
                 }
                 if ($thisContent['filename'] == basename($thisContent['filename'])) {
                     if ($this->debug > 2) {
                         error_log('New LP - aicc::import_package() - ' . $thisContent['filename'] . ' is at root level', 0);
                     }
                     $at_root = true;
                     if (!is_array($files_found[$res[1]])) {
                         $files_found[$res[1]] = $this->config_exts;
                         //initialise list of expected extensions (defined in class definition)
                     }
                     $files_found[$res[1]][strtolower($res[2])] = $thisContent['filename'];
                     $subdir_isset = true;
                 } else {
                     if (!$subdir_isset) {
                         if (preg_match('?^.*/aicc$?i', dirname($thisContent['filename']))) {
                             //echo "Cutting subdir<br/>";
                             $this->subdir .= '/' . substr(dirname($thisContent['filename']), 0, -5);
                         } else {
                             //echo "Not cutting subdir<br/>";
                             $this->subdir .= '/' . dirname($thisContent['filename']);
                         }
                         $subdir_isset = true;
                     }
                     if ($this->debug > 2) {
                         error_log('New LP - aicc::import_package() - ' . $thisContent['filename'] . ' is not at root level - recording subdir ' . $this->subdir, 0);
                     }
                     $config_dir = dirname($thisContent['filename']);
                     //just the relative directory inside scorm/
                     if (!is_array($files_found[basename($res[1])])) {
                         $files_found[basename($res[1])] = $this->config_exts;
                     }
                     $files_found[basename($res[1])][strtolower($res[2])] = basename($thisContent['filename']);
                 }
                 $package_type = 'aicc';
             } else {
                 if ($this->debug > 3) {
                     error_log('New LP - aicc::import_package() - File ' . $thisContent['filename'] . ' didnt match any check', 0);
                 }
             }
         }
         $realFileSize += $thisContent['size'];
     }
     if ($this->debug > 2) {
         error_log('New LP - aicc::import_package() - $files_found: ' . print_r($files_found, true), 0);
     }
     if ($this->debug > 1) {
         error_log('New LP - aicc::import_package() - Package type is now ' . $package_type, 0);
     }
     $mandatory = false;
     foreach ($files_found as $file_name => $file_exts) {
         $temp = (!empty($files_found[$file_name]['crs']) and !empty($files_found[$file_name]['au']) and !empty($files_found[$file_name]['des']) and !empty($files_found[$file_name]['cst']));
         if ($temp) {
             if ($this->debug > 1) {
                 error_log('New LP - aicc::import_package() - Found all config files for ' . $file_name, 0);
             }
             $mandatory = true;
             $package = $file_name;
             //store base config file name for reuse in parse_config_files()
             $this->config_basename = $file_name;
             //store filenames for reuse in parse_config_files()
             $this->config_files = $files_found[$file_name];
             //get out, we only want one config files set
             break;
         }
     }
     if ($package_type == '' or $mandatory != true) {
         return api_failure::set_failure('not_aicc_content');
     }
     if (!enough_size($realFileSize, $course_sys_dir, $maxFilledSpace)) {
         return api_failure::set_failure('not_enough_space');
     }
     // it happens on Linux that $new_dir sometimes doesn't start with '/'
     if ($new_dir[0] != '/') {
         $new_dir = '/' . $new_dir;
     }
     //cut trailing slash
     if ($new_dir[strlen($new_dir) - 1] == '/') {
         $new_dir = substr($new_dir, 0, -1);
     }
     /*
     --------------------------------------
     	Uncompressing phase
     --------------------------------------
     */
     /*
     	We need to process each individual file in the zip archive to
     	- add it to the database
     	- parse & change relative html links
     	- make sure the filenames are secure (filter funny characters or php extensions)
     */
     if (is_dir($course_sys_dir . $new_dir) or @mkdir($course_sys_dir . $new_dir)) {
         // PHP method - slower...
         if ($this->debug >= 1) {
             error_log('New LP - Changing dir to ' . $course_sys_dir . $new_dir, 0);
         }
         $saved_dir = getcwd();
         chdir($course_sys_dir . $new_dir);
         $unzippingState = $zipFile->extract();
         for ($j = 0; $j < count($unzippingState); $j++) {
             $state = $unzippingState[$j];
             //TODO fix relative links in html files (?)
             $extension = strrchr($state["stored_filename"], ".");
             //if($this->debug>1){error_log('New LP - found extension '.$extension.' in '.$state['stored_filename'],0);}
         }
         if (!empty($new_dir)) {
             $new_dir = $new_dir . '/';
         }
         //rename files, for example with \\ in it
         if ($dir = @opendir($course_sys_dir . $new_dir)) {
             if ($this->debug == 1) {
                 error_log('New LP - Opened dir ' . $course_sys_dir . $new_dir, 0);
             }
             while ($file = readdir($dir)) {
                 if ($file != '.' && $file != '..') {
                     $filetype = "file";
                     if (is_dir($course_sys_dir . $new_dir . $file)) {
                         $filetype = "folder";
                     }
                     //TODO RENAMING FILES CAN BE VERY DANGEROUS AICC-WISE, avoid that as much as possible!
                     //$safe_file=replace_dangerous_char($file,'strict');
                     $find_str = array('\\', '.php', '.phtml');
                     $repl_str = array('/', '.txt', '.txt');
                     $safe_file = str_replace($find_str, $repl_str, $file);
                     if ($safe_file != $file) {
                         //@rename($course_sys_dir.$new_dir,$course_sys_dir.'/'.$safe_file);
                         $mydir = dirname($course_sys_dir . $new_dir . $safe_file);
                         if (!is_dir($mydir)) {
                             $mysubdirs = split('/', $mydir);
                             $mybasedir = '/';
                             foreach ($mysubdirs as $mysubdir) {
                                 if (!empty($mysubdir)) {
                                     $mybasedir = $mybasedir . $mysubdir . '/';
                                     if (!is_dir($mybasedir)) {
                                         @mkdir($mybasedir);
                                         if ($this->debug == 1) {
                                             error_log('New LP - Dir ' . $mybasedir . ' doesnt exist. Creating.', 0);
                                         }
                                     }
                                 }
                             }
                         }
                         @rename($course_sys_dir . $new_dir . $file, $course_sys_dir . $new_dir . $safe_file);
                         if ($this->debug == 1) {
                             error_log('New LP - Renaming ' . $course_sys_dir . $new_dir . $file . ' to ' . $course_sys_dir . $new_dir . $safe_file, 0);
                         }
                     }
                     //set_default_settings($course_sys_dir,$safe_file,$filetype);
                 }
             }
             closedir($dir);
             chdir($saved_dir);
         }
     } else {
         return '';
     }
     return $course_sys_dir . $new_dir . $config_dir;
 }
Example #4
0
 /**
  * Imports a zip file into the Chamilo structure
  * @param	string	$zip_file_info Zip file info as given by $_FILES['userFile']
  * @return	string	$current_dir Absolute path to the imsmanifest.xml file or empty string on error
  */
 public function import_package($zip_file_info, $current_dir = '')
 {
     if ($this->debug > 0) {
         error_log('In scorm::import_package(' . print_r($zip_file_info, true) . ',"' . $current_dir . '") method', 0);
     }
     $maxFilledSpace = DocumentManager::get_course_quota();
     $zip_file_path = $zip_file_info['tmp_name'];
     $zip_file_name = $zip_file_info['name'];
     if ($this->debug > 1) {
         error_log('New LP - import_package() - zip file path = ' . $zip_file_path . ', zip file name = ' . $zip_file_name, 0);
     }
     $course_rel_dir = api_get_course_path() . '/scorm';
     // scorm dir web path starting from /courses
     $course_sys_dir = api_get_path(SYS_COURSE_PATH) . $course_rel_dir;
     // Absolute system path for this course.
     $current_dir = api_replace_dangerous_char(trim($current_dir));
     // Current dir we are in, inside scorm/
     if ($this->debug > 1) {
         error_log('New LP - import_package() - current_dir = ' . $current_dir, 0);
     }
     // Get name of the zip file without the extension.
     if ($this->debug > 1) {
         error_log('New LP - Received zip file name: ' . $zip_file_path, 0);
     }
     $file_info = pathinfo($zip_file_name);
     $filename = $file_info['basename'];
     $extension = $file_info['extension'];
     $file_base_name = str_replace('.' . $extension, '', $filename);
     // Filename without its extension.
     $this->zipname = $file_base_name;
     // Save for later in case we don't have a title.
     if ($this->debug > 1) {
         error_log("New LP - base file name is : " . $file_base_name, 0);
     }
     $new_dir = api_replace_dangerous_char(trim($file_base_name));
     $this->subdir = $new_dir;
     if ($this->debug > 1) {
         error_log("New LP - subdir is first set to : " . $this->subdir, 0);
     }
     $zipFile = new PclZip($zip_file_path);
     // Check the zip content (real size and file extension).
     $zipContentArray = $zipFile->listContent();
     $package_type = '';
     $at_root = false;
     $manifest = '';
     $manifest_list = array();
     // The following loop should be stopped as soon as we found the right imsmanifest.xml (how to recognize it?).
     $realFileSize = 0;
     foreach ($zipContentArray as $thisContent) {
         $thisContent['filename'];
         if (preg_match('~.(php.*|phtml)$~i', $thisContent['filename'])) {
             $file = $thisContent['filename'];
             $this->set_error_msg("File {$file} contains a PHP script");
         } elseif (stristr($thisContent['filename'], 'imsmanifest.xml')) {
             //error_log('Found imsmanifest at '.$thisContent['filename'], 0);
             if ($thisContent['filename'] == basename($thisContent['filename'])) {
                 $at_root = true;
             } else {
                 if ($this->debug > 2) {
                     error_log("New LP - subdir is now " . $this->subdir, 0);
                 }
             }
             $package_type = 'scorm';
             $manifest_list[] = $thisContent['filename'];
             $manifest = $thisContent['filename'];
             //just the relative directory inside scorm/
         } else {
             // Do nothing, if it has not been set as scorm somewhere else, it stays as '' default.
         }
         $realFileSize += $thisContent['size'];
     }
     // Now get the shortest path (basically, the imsmanifest that is the closest to the root).
     $shortest_path = $manifest_list[0];
     $slash_count = substr_count($shortest_path, '/');
     foreach ($manifest_list as $manifest_path) {
         $tmp_slash_count = substr_count($manifest_path, '/');
         if ($tmp_slash_count < $slash_count) {
             $shortest_path = $manifest_path;
             $slash_count = $tmp_slash_count;
         }
     }
     $this->subdir .= '/' . dirname($shortest_path);
     // Do not concatenate because already done above.
     $manifest = $shortest_path;
     if ($this->debug > 1) {
         error_log('New LP - Package type is now ' . $package_type, 0);
     }
     if ($package_type == '') {
         // && defined('CHECK_FOR_SCORM') && CHECK_FOR_SCORM)
         if ($this->debug > 1) {
             error_log('New LP - Package type is empty', 0);
         }
         return api_failure::set_failure('not_scorm_content');
     }
     if (!enough_size($realFileSize, $course_sys_dir, $maxFilledSpace)) {
         if ($this->debug > 1) {
             error_log('New LP - Not enough space to store package', 0);
         }
         return api_failure::set_failure('not_enough_space');
     }
     // It happens on Linux that $new_dir sometimes doesn't start with '/'
     if ($new_dir[0] != '/') {
         $new_dir = '/' . $new_dir;
     }
     if ($new_dir[strlen($new_dir) - 1] == '/') {
         $new_dir = substr($new_dir, 0, -1);
     }
     /* Uncompressing phase */
     /*
         We need to process each individual file in the zip archive to
         - add it to the database
         - parse & change relative html links
         - make sure the filenames are secure (filter funny characters or php extensions)
     */
     if (is_dir($course_sys_dir . $new_dir) or @mkdir($course_sys_dir . $new_dir, api_get_permissions_for_new_directories())) {
         // PHP method - slower...
         if ($this->debug >= 1) {
             error_log('New LP - Changing dir to ' . $course_sys_dir . $new_dir, 0);
         }
         $saved_dir = getcwd();
         chdir($course_sys_dir . $new_dir);
         $unzippingState = $zipFile->extract();
         for ($j = 0; $j < count($unzippingState); $j++) {
             $state = $unzippingState[$j];
             // TODO: Fix relative links in html files (?)
             $extension = strrchr($state['stored_filename'], '.');
             if ($this->debug >= 1) {
                 error_log('New LP - found extension ' . $extension . ' in ' . $state['stored_filename'], 0);
             }
         }
         if (!empty($new_dir)) {
             $new_dir = $new_dir . '/';
         }
         // Rename files, for example with \\ in it.
         if ($this->debug >= 1) {
             error_log('New LP - try to open: ' . $course_sys_dir . $new_dir, 0);
         }
         if ($dir = @opendir($course_sys_dir . $new_dir)) {
             if ($this->debug >= 1) {
                 error_log('New LP - Opened dir ' . $course_sys_dir . $new_dir, 0);
             }
             while ($file = readdir($dir)) {
                 if ($file != '.' && $file != '..') {
                     $filetype = 'file';
                     if (is_dir($course_sys_dir . $new_dir . $file)) {
                         $filetype = 'folder';
                     }
                     // TODO: RENAMING FILES CAN BE VERY DANGEROUS SCORM-WISE, avoid that as much as possible!
                     //$safe_file = api_replace_dangerous_char($file, 'strict');
                     $find_str = array('\\', '.php', '.phtml');
                     $repl_str = array('/', '.txt', '.txt');
                     $safe_file = str_replace($find_str, $repl_str, $file);
                     if ($this->debug >= 1) {
                         error_log('Comparing:  ' . $safe_file, 0);
                     }
                     if ($this->debug >= 1) {
                         error_log('and:  ' . $file, 0);
                     }
                     if ($safe_file != $file) {
                         $mydir = dirname($course_sys_dir . $new_dir . $safe_file);
                         if (!is_dir($mydir)) {
                             $mysubdirs = explode('/', $mydir);
                             $mybasedir = '/';
                             foreach ($mysubdirs as $mysubdir) {
                                 if (!empty($mysubdir)) {
                                     $mybasedir = $mybasedir . $mysubdir . '/';
                                     if (!is_dir($mybasedir)) {
                                         @mkdir($mybasedir, api_get_permissions_for_new_directories());
                                         if ($this->debug >= 1) {
                                             error_log('New LP - Dir ' . $mybasedir . ' doesnt exist. Creating.', 0);
                                         }
                                     }
                                 }
                             }
                         }
                         @rename($course_sys_dir . $new_dir . $file, $course_sys_dir . $new_dir . $safe_file);
                         if ($this->debug >= 1) {
                             error_log('New LP - Renaming ' . $course_sys_dir . $new_dir . $file . ' to ' . $course_sys_dir . $new_dir . $safe_file, 0);
                         }
                     }
                 }
             }
             closedir($dir);
             chdir($saved_dir);
             api_chmod_R($course_sys_dir . $new_dir, api_get_permissions_for_new_directories());
             if ($this->debug > 1) {
                 error_log('New LP - changed back to init dir: ' . $course_sys_dir . $new_dir, 0);
             }
         }
     } else {
         return '';
     }
     return $course_sys_dir . $new_dir . $manifest;
 }
Example #5
0
/**
 * unzip safly a zipfile
 *
 * @author Hugues Peeters <*****@*****.**>
 *
 * @param string $fileName file name of zip
 * @param string $filePath file path of zip
 * @param string $extractPath
 * @param integer $maxFilledSpace (byte) count  of byte size aivailable
 * @param boolean $allowPHP whether True the file can't contain php or phtml files
 * @return true
 * @throws claro_failure on error
 */
function treat_secure_file_unzip($fileName, $filePath, $extractPath, $maxFilledSpace, $allowPHP = false)
{
    $zipFile = new pclZip($fileName);
    // Check the zip content (real size and file extension)
    $zipContentArray = $zipFile->listContent();
    if (!is_array($zipContentArray)) {
        return false;
    }
    foreach ($zipContentArray as $thisContent) {
        if (!$allowPHP) {
            if (preg_match('~.(php.?|phtml)$~i', $thisContent['filename'])) {
                return claro_failure::set_failure(get_lang('The zip file can not contain .PHP files'));
            }
        }
        if (!isset($realFileSize)) {
            $realFileSize = 0;
        }
        $realFileSize += $thisContent['size'];
    }
    if (!enough_size($realFileSize, $extractPath, $maxFilledSpace)) {
        return claro_failure::set_failure(get_lang('The upload has failed. There is not enough space in your directory'));
    }
    $extractedFileNameList = $zipFile->extract(PCLZIP_OPT_PATH, $extractPath . $filePath, PCLZIP_OPT_SET_CHMOD, CLARO_FILE_PERMISSIONS);
    if (is_array($extractedFileNameList)) {
        return $extractedFileNameList;
    } else {
        return false;
    }
}
Example #6
0
/**
 * Manages all the unzipping process of an uploaded file
 *
 * @author Hugues Peeters <*****@*****.**>
 *
 * @param  array  $uploaded_file - follows the $_FILES Structure
 * @param  string $upload_path   - destination of the upload.
 *                                This path is to append to $base_work_dir
 * @param  string $base_work_dir  - base working directory of the module
 * @param  int $max_filled_space  - amount of bytes to not exceed in the base
 *                                working directory
 *
 * @return boolean true if it succeeds false otherwise
 */
function unzip_uploaded_file($uploaded_file, $upload_path, $base_work_dir, $max_filled_space)
{
    $zip_file = new PclZip($uploaded_file['tmp_name']);
    // Check the zip content (real size and file extension)
    if (file_exists($uploaded_file['tmp_name'])) {
        $zip_content_array = $zip_file->listContent();
        $ok_scorm = false;
        $realFileSize = 0;
        foreach ($zip_content_array as &$this_content) {
            if (preg_match('~.(php.*|phtml)$~i', $this_content['filename'])) {
                return api_failure::set_failure('php_file_in_zip_file');
            } elseif (stristr($this_content['filename'], 'imsmanifest.xml')) {
                $ok_scorm = true;
            } elseif (stristr($this_content['filename'], 'LMS')) {
                $ok_plantyn_scorm1 = true;
            } elseif (stristr($this_content['filename'], 'REF')) {
                $ok_plantyn_scorm2 = true;
            } elseif (stristr($this_content['filename'], 'SCO')) {
                $ok_plantyn_scorm3 = true;
            } elseif (stristr($this_content['filename'], 'AICC')) {
                $ok_aicc_scorm = true;
            }
            $realFileSize += $this_content['size'];
        }
        if ($ok_plantyn_scorm1 && $ok_plantyn_scorm2 && $ok_plantyn_scorm3 || $ok_aicc_scorm) {
            $ok_scorm = true;
        }
        if (!$ok_scorm && defined('CHECK_FOR_SCORM') && CHECK_FOR_SCORM) {
            return api_failure::set_failure('not_scorm_content');
        }
        if (!enough_size($realFileSize, $base_work_dir, $max_filled_space)) {
            return api_failure::set_failure('not_enough_space');
        }
        // It happens on Linux that $upload_path sometimes doesn't start with '/'
        if ($upload_path[0] != '/' && substr($base_work_dir, -1, 1) != '/') {
            $upload_path = '/' . $upload_path;
        }
        if ($upload_path[strlen($upload_path) - 1] == '/') {
            $upload_path = substr($upload_path, 0, -1);
        }
        /*	Uncompressing phase */
        /*
            The first version, using OS unzip, is not used anymore
            because it does not return enough information.
            We need to process each individual file in the zip archive to
            - add it to the database
            - parse & change relative html links
        */
        if (PHP_OS == 'Linux' && !get_cfg_var('safe_mode') && false) {
            // *** UGent, changed by OC ***
            // Shell Method - if this is possible, it gains some speed
            exec("unzip -d \"" . $base_work_dir . $upload_path . "/\"" . $uploaded_file['name'] . " " . $uploaded_file['tmp_name']);
        } else {
            // PHP method - slower...
            $save_dir = getcwd();
            chdir($base_work_dir . $upload_path);
            $unzippingState = $zip_file->extract();
            for ($j = 0; $j < count($unzippingState); $j++) {
                $state = $unzippingState[$j];
                // Fix relative links in html files
                $extension = strrchr($state['stored_filename'], '.');
            }
            if ($dir = @opendir($base_work_dir . $upload_path)) {
                while ($file = readdir($dir)) {
                    if ($file != '.' && $file != '..') {
                        $filetype = 'file';
                        if (is_dir($base_work_dir . $upload_path . '/' . $file)) {
                            $filetype = 'folder';
                        }
                        $safe_file = api_replace_dangerous_char($file, 'strict');
                        @rename($base_work_dir . $upload_path . '/' . $file, $base_work_dir . $upload_path . '/' . $safe_file);
                        set_default_settings($upload_path, $safe_file, $filetype);
                    }
                }
                closedir($dir);
            } else {
                error_log('Could not create directory ' . $base_work_dir . $upload_path . ' to unzip files');
            }
            chdir($save_dir);
            // Back to previous dir position
        }
    }
    return true;
}
function doImport($course_code, $webDir, $scoFileSize, $scoFileName, $displayExtraMessages = false) {
    global $langUnamedPath;
    global $langFileScormError;
    global $langNotice;
    global $langMaxFileSize;
    global $langNoSpace;
    global $langOkFileReceived;
    global $langErrorNoZlibExtension;
    global $langErrorReadingZipFile;
    global $langZipNoPhp;
    global $langErrortExtractingManifest;
    global $langErrorFileMustBeZip;
    global $langErrorOpeningManifest;
    global $langOkManifestFound;
    global $langErrorReadingManifest;
    global $langOkManifestRead;
    global $langErrorAssetNotFound;
    global $langErrorNoModuleInPackage;
    global $langErrorSql;
    global $langOkChapterHeadAdded;
    global $langUnamedModule;
    global $langDefaultModuleComment;
    global $langDefaultModuleAddedComment;
    global $langOkModuleAdded;
    global $langOkDefaultTitleUsed;
    global $langDefaultLearningPathComment;
    global $langOkDefaultCommentUsed;
    global $langSuccessOk;
    global $langError;
    global $langInstalled;
    global $langNotInstalled;
    global $langBack;
    global $errorFound;
    global $elementsPile;
    global $itemsPile;
    global $manifestData;
    global $iterator;
    global $course_code;
    global $course_id;
    global $langErrorValidatingManifest;
    global $urlServer;

    $pwd = getcwd();

    // init msg arays
    $okMsgs = array();
    $errorMsgs = array();

    $maxFilledSpace = 100000000;

    $courseDir = "/courses/" . $course_code . "/scormPackages/";
    $tempDir = "/courses/" . $course_code . "/temp/";
    $baseWorkDir = $webDir . $courseDir; // path_id
    $tempWorkDir = $webDir . $tempDir;

    if (!is_dir($baseWorkDir)) {
        claro_mkdir($baseWorkDir, CLARO_FILE_PERMISSIONS);
    }

    // arrays used to store inserted ids
    $insertedModule_id = array();
    $insertedAsset_id = array();

    $lpName = $langUnamedPath;

    // we need a new path_id for this learning path so we prepare a line in DB
    // this line will be removed if an error occurs
    $rankMax = 1 + intval(Database::get()->querySingle("SELECT MAX(`rank`) AS max
            FROM `lp_learnPath` WHERE `course_id` = ?d", $course_id)->max);

    $tempPathId = Database::get()->query("INSERT INTO `lp_learnPath`
            (`course_id`, `name`,`visible`,`rank`,`comment`)
            VALUES (?d, ?s, 0, ?d,'')", $course_id, $lpName, $rankMax)->lastInsertID;
    $baseWorkDir .= "path_" . $tempPathId;

    if (!is_dir($baseWorkDir)) {
        claro_mkdir($baseWorkDir, CLARO_FILE_PERMISSIONS);
    }

    // unzip package
    require_once("include/pclzip/pclzip.lib.php");

    /*
     * Check the file size doesn't exceed
     * the maximum file size authorized in the directory
     */

    if (!enough_size($scoFileSize, $baseWorkDir, $maxFilledSpace)) {
        $errorFound = true;
        array_push($errorMsgs, $langNoSpace);
    }

    /*
     * Unzipping stage
     */ elseif (preg_match("/.zip$/i", $scoFileName)) {
        array_push($okMsgs, $langOkFileReceived . basename($scoFileName));

        if (!function_exists('gzopen')) {
            $errorFound = true;
            array_push($errorMsgs, $langErrorNoZlibExtension);
        } else {
            $zipFile = new pclZip($tempWorkDir . $scoFileName);
            $is_allowedToUnzip = true; // default initialisation
            // Check the zip content (real size and file extension)

            $zipContentArray = $zipFile->listContent();

            if ($zipContentArray == 0) {
                $errorFound = true;
                array_push($errorMsgs, $langErrorReadingZipFile);
            }

            $pathToManifest = ""; // empty by default because we can expect that the manifest.xml is in the root of zip file
            $pathToManifestFound = false;
            $realFileSize = 0;

            foreach ($zipContentArray as $thisContent) {
                if (preg_match('/.(php[[:digit:]]?|phtml)$/i', $thisContent['filename'])) {
                    $errorFound = true;
                    array_push($errorMsgs, $langZipNoPhp);
                    $is_allowedToUnzip = false;
                    break;
                }

                if (strtolower(substr($thisContent['filename'], -15)) == "imsmanifest.xml") {
                    // this check exists to find the less deep imsmanifest.xml in the zip if there are several imsmanifest.xml
                    // if this is the first imsmanifest.xml we found OR path to the new manifest found is shorter (less deep)
                    if (!$pathToManifestFound || ( count(explode('/', $thisContent['filename'])) < count(explode('/', $pathToManifest . "imsmanifest.xml")) )
                    ) {
                        $pathToManifest = substr($thisContent['filename'], 0, -15);
                        $pathToManifestFound = true;
                    }
                }
                $realFileSize += $thisContent['size'];
            }

            if (!isset($alreadyFilledSpace)) {
                $alreadyFilledSpace = 0;
            }

            if (($realFileSize + $alreadyFilledSpace) > $maxFilledSpace) { // check the real size.
                $errorFound = true;
                array_push($errorMsgs, $langNoSpace);
                $is_allowedToUnzip = false;
            }

            if ($is_allowedToUnzip && !$errorFound) {
                // PHP extraction of zip file using zlib

                chdir($baseWorkDir);
                $unzippingState = $zipFile->extract(PCLZIP_OPT_BY_NAME, $pathToManifest . "imsmanifest.xml", PCLZIP_OPT_PATH, '', PCLZIP_OPT_REMOVE_PATH, $pathToManifest);
                if ($unzippingState == 0) {
                    $errorFound = true;
                    array_push($errorMsgs, $langErrortExtractingManifest);
                }
            } //end of if ($is_allowedToUnzip)
        } // end of if (!function_exists...
    } else {
        $errorFound = true;
        array_push($errorMsgs, $langErrorFileMustBeZip . ": " . basename($scoFileName));
    }
    // find xmlmanifest (must be in root else ==> cancel operation, delete files)
    // parse xml manifest to find :
    // package name - learning path name
    // SCO list
    // start asset path

    if (!$errorFound) {
        $elementsPile = array(); // array used to remember where we are in the arborescence of the XML file
        $itemsPile = array(); // array used to remember parents items
        // declaration of global arrays used for extracting needed info from manifest for the new modules/SCO
        $manifestData = array();   // for global data  of the learning path
        $manifestData['items'] = array(); // item tags content (attributes + some child elements data (title for an example)
        $manifestData['scos'] = array();  // for path of start asset id of each new module to create

        $iterator = 0; // will be used to increment position of paths in manifestData['scosPaths"]
        // and to have the names at the same pos if found
        //$xml_parser = xml_parser_create();
        $xml_parser = xml_parser_create('utf-8');
        xml_set_element_handler($xml_parser, "startElement", "endElement");
        xml_set_character_data_handler($xml_parser, "elementData");

        // this file has to exist in a SCORM conformant package
        // this file must be in the root the sent zip
        $file = "imsmanifest.xml";

        if (!($fp = @fopen($file, "r"))) {
            $errorFound = true;
            array_push($errorMsgs, $langErrorOpeningManifest);
        } else {
            if (!isset($manifestPath)) {
                $manifestPath = "";
            }

            array_push($okMsgs, $langOkManifestFound . $manifestPath . "imsmanifest.xml");

            while ($data = str_replace("\n", "", fread($fp, 4096))) {
                // fix for fread breaking thing
                // msg from "ml at csite dot com" 02-Jul-2003 02:29 on http://www.php.net/xml
                // preg expression has been modified to match tag with inner attributes

                if (!isset($cache)) {
                    $cache = "";
                }

                $data = $cache . $data;
                if (!feof($fp)) {
                    // search fo opening, closing, empty tags (with or without attributes)
                    if (preg_match_all("/<[^\>]*.>/", $data, $regs)) {
                        $lastTagname = $regs[0][count($regs[0]) - 1];
                        $split = false;
                        for ($i = strlen($data) - strlen($lastTagname); $i >= strlen($lastTagname); $i--) {
                            if ($lastTagname == substr($data, $i, strlen($lastTagname))) {
                                $cache = substr($data, $i, strlen($data));
                                $data = substr($data, 0, $i);
                                $split = true;
                                break;
                            }
                        }
                    }

                    if (!$split) {
                        $cache = $data;
                    }
                }
                // end of fix

                if (!xml_parse($xml_parser, $data, feof($fp))) {
                    // if reading of the xml file in not successfull :
                    // set errorFound, set error msg, break while statement

                    $errorFound = true;
                    array_push($errorMsgs, $langErrorReadingManifest);
                    // Since manifest.xml cannot be parsed, test versus IMS CP 1.4.4 XSD (compatible with all SCORM packages as well)
                    require_once 'include/validateXML.php';
                    libxml_use_internal_errors(true);
                    
                    $xml = new DOMDocument();
                    $xml->load($manifestPath."imsmanifest.xml");
                    
                    if (!$xml->schemaValidate($urlServer . 'modules/learnPath/export/imscp_v1p2.xsd')) {
                        $messages = libxml_display_errors();
                        
                        array_push($errorMsgs, $langErrorValidatingManifest . $messages);
                    }
                    break;
                }
            }
            // close file
            fclose($fp);
        }

        // liberate parser ressources
        xml_parser_free($xml_parser);
    } //if (!$errorFound)
    // check if all starts assets files exist in the zip file
    if (!$errorFound) {
        array_push($okMsgs, $langOkManifestRead);
        if (sizeof($manifestData['items']) > 0) {
            // if there is items in manifest we look for sco type resources referenced in idientifierref
            foreach ($manifestData['items'] as $item) {
                if (!isset($item['identifierref']) || $item['identifierref'] == '') {
                    break; // skip if no ressource reference in item (item is probably a chapter head)
                }

                    
// find the file in the zip file
                $scoPathFound = false;

                for ($i = 0; $i < sizeof($zipContentArray); $i++) {
                    if (isset($manifestData['scos'][$item['identifierref']]['xml:base'])) {
                        $extraPath = $manifestData['scos'][$item['identifierref']]['xml:base'];
                    } else if (isset($manifestData['assets'][$item['identifierref']]['xml:base'])) {
                        $extraPath = $manifestData['assets'][$item['identifierref']]['xml:base'];
                    } else {
                        $extraPath = "";
                    }

                    if (isset($zipContentArray[$i]["filename"]) &&
                            ( ( isset($manifestData['scos'][$item['identifierref']]['href']) && $zipContentArray[$i]["filename"] == $pathToManifest . $extraPath . $manifestData['scos'][$item['identifierref']]['href']) || (isset($manifestData['assets'][$item['identifierref']]['href']) && $zipContentArray[$i]["filename"] == $pathToManifest . $extraPath . $manifestData['assets'][$item['identifierref']]['href'])
                            )
                    ) {
                        $scoPathFound = true;
                        break;
                    }
                }

                if (!$scoPathFound) {
                    $errorFound = true;
                    array_push($errorMsgs, $langErrorAssetNotFound . $manifestData['scos'][$item['identifierref']]['href']);
                    break;
                }
            }
        } //if (sizeof ...)
        elseif (sizeof($manifestData['scos']) > 0) {
            // if there ie no items in the manifest file
            // check for scos in resources

            foreach ($manifestData['scos'] as $sco) {
                // find the file in the zip file
                // create a fake item so that the rest of the procedure (add infos of in db) can remains the same
                $manifestData['items'][$sco['href']]['identifierref'] = $sco['href'];
                $manifestData['items'][$sco['href']]['parameters'] = '';
                $manifestData['items'][$sco['href']]['isvisible'] = "true";
                $manifestData['items'][$sco['href']]['title'] = $sco['title'];
                $manifestData['items'][$sco['href']]['description'] = $sco['description'];
                $manifestData['items'][$attributes['IDENTIFIER']]['parent'] = 0;

                $scoPathFound = false;

                for ($i = 0; $i < sizeof($zipContentArray); $i++) {
                    if ($zipContentArray[$i]["filename"] == $sco['href']) {
                        $scoPathFound = true;
                        break;
                    }
                }
                if (!$scoPathFound) {
                    $errorFound = true;
                    array_push($errorMsgs, $langErrorAssetNotFound . $sco['href']);
                    break;
                }
            }
        } // if sizeof (...ΰ
        else {
            $errorFound = true;
            array_push($errorMsgs, $langErrorNoModuleInPackage);
        }
    }// if errorFound
    // unzip all files
    // &&
    // insert corresponding entries in database

    if (!$errorFound) {
        // PHP extraction of zip file using zlib
        chdir($baseWorkDir);

        // PCLZIP_OPT_PATH is the path where files will be extracted ( '' )
        // PLZIP_OPT_REMOVE_PATH suppress a part of the path of the file ( $pathToManifest )
        // the result is that the manifest is in th eroot of the path_# directory and all files will have a path related to the root
        $unzippingState = $zipFile->extract(PCLZIP_OPT_PATH, '', PCLZIP_OPT_REMOVE_PATH, $pathToManifest);

        // insert informations in DB :
        //        - 1 learning path ( already added because we needed its id to create the package directory )
        //        - n modules
        //        - n asset as start asset of modules

        if (sizeof($manifestData['items']) == 0) {
            $errorFound = true;
            array_push($errorMsgs, $langErrorNoModuleInPackage);
        } else {
            $i = 0;
            $insertedLPMid = array(); // array of learnPath_module_id && order of related group
            $inRootRank = 1; // default rank for root module (parent == 0)

            foreach ($manifestData['items'] as $item) {
                if (isset($item['parent']) && isset($insertedLPMid[$item['parent']])) {
                    $parent = $insertedLPMid[$item['parent']]['LPMid'];
                    $rank = $insertedLPMid[$item['parent']]['rank'] ++;
                } else {
                    $parent = 0;
                    $rank = $inRootRank++;
                }

                //-------------------------------------------------------------------------------
                // add chapter head
                //-------------------------------------------------------------------------------

                if ((!isset($item['identifierref']) || $item['identifierref'] == '') && isset($item['title']) && $item['title'] != '') {
                    // add title as a module
                    $chapterTitle = $item['title'];

                    // array of all inserted module ids
                    $insertedModule_id[$i] = Database::get()->query("INSERT INTO `lp_module`
                            (`course_id`, `name`, `comment`, `contentType`, `launch_data`)
                            VALUES (?d, ?s, '', ?s,'')", $course_id, $chapterTitle, CTLABEL_)->lastInsertID;
                    if (!$insertedModule_id[$i]) {
                        $errorFound = true;
                        array_push($errorMsgs, $langErrorSql);
                        break;
                    }
                    // visibility
                    if (isset($item['isvisible']) && $item['isvisible'] != '') {
                        $visibility = ($item['isvisible'] == "true") ? 1 : 0;
                    } else {
                        $visibility = 1; // IMS consider that the default value of 'isvisible' is true
                    }

                    // add title module in the learning path
                    // finally : insert in learning path
                    // get the inserted id of the learnPath_module rel to allow 'parent' link in next inserts
                    $insertedLPMid[$item['itemIdentifier']]['LPMid'] = Database::get()->query("INSERT INTO `lp_rel_learnPath_module`
                            (`learnPath_id`, `module_id`,`rank`, `visible`, `parent`)
                            VALUES (?d, ?d, ?d, ?d, ?d)", $tempPathId, $insertedModule_id[$i], $rank, $visibility, $parent)->lastInsertID;
                    $insertedLPMid[$item['itemIdentifier']]['rank'] = 1;

                    if (!$insertedLPMid[$item['itemIdentifier']]['LPMid']) {
                        $errorFound = true;
                        array_push($errorMsgs, $langErrorSql);
                        break;
                    }
                    if (!$errorFound) {
                        array_push($okMsgs, $langOkChapterHeadAdded . "<i>" . $chapterTitle . "</i>");
                    }
                    $i++;
                    continue;
                }

                // use found title of module or use default title
                if (!isset($item['title']) || $item['title'] == '') {
                    $moduleName = $langUnamedModule;
                } else {
                    $moduleName = $item['title'];
                }

                // set description as comment or default comment
                // look fo description in item description or in sco (resource) description
                // don't remember why I checked for parameters string ... so comment it
                if ((!isset($item['description']) || $item['description'] == '' ) &&
                        (!isset($manifestData['scos'][$item['identifierref']]['description']) /* || $manifestData['scos'][$item['identifierref']]['parameters'] == '' */ )
                ) {
                    $description = $langDefaultModuleComment;
                } else {
                    if (isset($item['description']) && $item['description'] != '') {
                        $description = $item['description'];
                    } else {
                        $description = $manifestData['scos'][$item['identifierref']]['description'];
                    }
                }

                // insert modules and their start asset
                // create new module

                if (!isset($item['datafromlms'])) {
                    $item['datafromlms'] = "";
                }

                // elegxoume an to contentType prepei na einai scorm h asset
                if (isset($manifestData['scos'][$item['identifierref']]['contentTypeFlag']) && $manifestData['scos'][$item['identifierref']]['contentTypeFlag'] == CTSCORMASSET_) {
                    $contentType = CTSCORMASSET_;
                } else {
                    $contentType = CTSCORM_;
                }

                // array of all inserted module ids
                $insertedModule_id[$i] = Database::get()->query("INSERT INTO `lp_module`
                        (`course_id`, `name`, `comment`, `contentType`, `launch_data`)
                        VALUES (?d, ?s, ?s, ?s, ?s)", $course_id, $moduleName, $description, $contentType, $item['datafromlms'])->lastInsertID;
                
                if (!$insertedModule_id[$i]) {
                    $errorFound = true;
                    array_push($errorMsgs, $langErrorSql);
                    break;
                }
                // build asset path
                // a $manifestData['scos'][$item['identifierref']] __SHOULD__ not exist if a $manifestData['assets'][$item['identifierref']] exists
                // so according to IMS we can say that one is empty if the other is filled, so we concat them without more verification than if the var exists.

                // suppress notices
                if (!isset($manifestData['xml:base']['manifest'])) {
                    $manifestData['xml:base']['manifest'] = "";
                }
                if (!isset($manifestData['xml:base']['ressources'])) {
                    $manifestData['xml:base']['ressources'] = "";
                }
                if (!isset($manifestData['scos'][$item['identifierref']]['href'])) {
                    $manifestData['scos'][$item['identifierref']]['href'] = "";
                }
                if (!isset($manifestData['assets'][$item['identifierref']]['href'])) {
                    $manifestData['assets'][$item['identifierref']]['href'] = "";
                }
                if (!isset($manifestData['scos'][$item['identifierref']]['parameters'])) {
                    $manifestData['scos'][$item['identifierref']]['parameters'] = "";
                }
                if (!isset($manifestData['assets'][$item['identifierref']]['parameters'])) {
                    $manifestData['assets'][$item['identifierref']]['parameters'] = "";
                }
                if (!isset($manifestData['items'][$item['itemIdentifier']]['parameters'])) {
                    $manifestData['items'][$item['itemIdentifier']]['parameters'] = "";
                }

                if (isset($manifestData['scos'][$item['identifierref']]['xml:base'])) {
                    $extraPath = $manifestData['scos'][$item['identifierref']]['xml:base'];
                } else if (isset($manifestData['assets'][$item['identifierref']]['xml:base'])) {
                    $extraPath = $manifestData['assets'][$item['identifierref']]['xml:base'];
                } else {
                    $extraPath = "";
                }

                $assetPath = "/"
                        . $manifestData['xml:base']['manifest']
                        . $manifestData['xml:base']['ressources']
                        . $extraPath
                        . $manifestData['scos'][$item['identifierref']]['href']
                        . $manifestData['assets'][$item['identifierref']]['href']
                        . $manifestData['scos'][$item['identifierref']]['parameters']
                        . $manifestData['assets'][$item['identifierref']]['parameters']
                        . $manifestData['items'][$item['itemIdentifier']]['parameters'];

                // create new asset
                // array of all inserted asset ids
                $insertedAsset_id[$i] = Database::get()->query("INSERT INTO `lp_asset`
                        (`path` , `module_id` , `comment`)
                        VALUES (?s, ?d, '')", $assetPath, $insertedModule_id[$i])->lastInsertID;
                
                if (!$insertedAsset_id[$i]) {
                    $errorFound = true;
                    array_push($errorMsgs, $langErrorSql);
                    break;
                }
                // update of module with correct start asset id
                Database::get()->query("UPDATE `lp_module`
                        SET `startAsset_id` = ?d
                        WHERE `module_id` = ?d
                        AND `course_id` = ?d", $insertedAsset_id[$i], $insertedModule_id[$i], $course_id);

                // visibility
                if (isset($item['isvisible']) && $item['isvisible'] != '') {
                    ( $item['isvisible'] == "true" ) ? $visibility = 1 : $visibility = 0;
                } else {
                    $visibility = 1; // IMS consider that the default value of 'isvisible' is true
                }

                // finally : insert in learning path
                // get the inserted id of the learnPath_module rel to allow 'parent' link in next inserts
                $insertedLPMid[$item['itemIdentifier']]['LPMid'] = Database::get()->query("INSERT INTO `lp_rel_learnPath_module`
                        (`learnPath_id`, `module_id`, `specificComment`, `rank`, `visible`, `lock`, `parent`)
                        VALUES (?d, ?d, ?s, ?d, ?d, 'OPEN', ?d)", $tempPathId, $insertedModule_id[$i], $langDefaultModuleAddedComment, $rank, $visibility, $parent)->lastInsertID;
                $insertedLPMid[$item['itemIdentifier']]['rank'] = 1;

                if (!$insertedLPMid[$item['itemIdentifier']]['LPMid']) {
                    $errorFound = true;
                    array_push($errorMsgs, $langErrorSql);
                    break;
                }

                if (!$errorFound) {
                    array_push($okMsgs, $langOkModuleAdded . "<i>" . $moduleName . "</i>");
                }
                $i++;
            }//foreach
        } // if sizeof($manifestData['items'] == 0 )
    } // if errorFound
    // last step
    // - delete all added files/directories/records in db
    // or
    // - update the learning path record

    if ($errorFound) {
        // delete all database entries of this "module"
        // delete modules and assets (build query)
        // delete assets
        $sqlDelAssets = "DELETE FROM `lp_asset` WHERE 1 = 0";
        foreach ($insertedAsset_id as $insertedAsset) {
            $sqlDelAssets .= " OR `asset_id` = " . intval($insertedAsset);
        }
        Database::get()->query($sqlDelAssets);

        // delete modules
        $sqlDelModules = "DELETE FROM `lp_module` WHERE 1 = 0";
        foreach ($insertedModule_id as $insertedModule) {
            $sqlDelModules .= " OR ( `module_id` = " . intval($insertedModule) . " AND `course_id` = " . intval($course_id) . " )";
        }
        Database::get()->query($sqlDelModules);

        // delete learningPath_module
        Database::get()->query("DELETE FROM `lp_rel_learnPath_module` WHERE `learnPath_id` = ?d", $tempPathId);

        // delete learning path
        Database::get()->query("DELETE FROM `lp_learnPath`
                     WHERE `learnPath_id` = ?d
                     AND `course_id` = ?d", $tempPathId, $course_id);

        // delete the directory (and files) of this learning path and all its content
        claro_delete_file($baseWorkDir);
    } else {
        // finalize insertion : update the empty learning path insert that was made to find its id
        $rankMax = 1 + intval(Database::get()->querySingle("SELECT MAX(`rank`) AS max
                FROM `lp_learnPath`
                WHERE `course_id` = ?d", $course_id)->max);

        if (isset($manifestData['packageTitle'])) {
            $lpName = $manifestData['packageTitle'];
        } else {
            array_push($okMsgs, $langOkDefaultTitleUsed);
        }

        if (isset($manifestData['packageDesc'])) {
            $lpComment = $manifestData['packageDesc'];
        } else {
            $lpComment = $langDefaultLearningPathComment;
            array_push($okMsgs, $langOkDefaultCommentUsed);
        }

        Database::get()->query("UPDATE `lp_learnPath`
                SET `rank` = ?d,
                    `name` = ?s,
                    `comment` = ?s,
                    `visible` = 1
                WHERE `learnPath_id` = ?d
                AND `course_id` = ?d", $rankMax, $lpName, $lpComment, $tempPathId, $course_id);
    }

    /* --------------------------------------
      status messages
      -------------------------------------- */
    $importMessages = "\n<p>\n";
    //$importMessages .= "<!-- Messages -->";
    foreach ($okMsgs as $msg) {
        $importMessages .= "\n<b>[</b><span class=\"correct\">$langSuccessOk</span><b>]</b>&nbsp;&nbsp;&nbsp;" . $msg . "<br />";
    }

    foreach ($errorMsgs as $msg) {
        $importMessages .= "\n<b>[</b><span class=\"error\">$langError</span><b>]</b>&nbsp;&nbsp;&nbsp;" . $msg . "<br />";
    }

    $importMessages .= "\n\n";
    //$importMessages .= "<!-- End messages -->";
    // installation completed or not message
    if (!$errorFound) {
        $importMessages .= "\n<br /><center><b>" . $langInstalled . "</b></center>";
        if ($displayExtraMessages == true) {
            $importMessages .= "\n<br /><br ><center><a href=\"learningPathAdmin.php?course=$course_code&amp;path_id=" . $tempPathId . "\">" . $lpName . "</a></center>";
        }        
        $importMessages .= "\n<br /><br >";
    }
    else {
        $importMessages .= "\n<br /><center><b>" . $langNotInstalled . "</b></center>";
    }
    //$importMessages .= "\n<br /><a href=\"index.php?course=$course_code\">$langBack</a></p>";
    $importMessages .= "\n<br /></p>";

    chdir($pwd);

    return array($importMessages, $tempPathId);
}