/** * Export hierarchical tabular data to XML-file * @param array Hierarchical array of data to put in XML, each element presenting a 'name' and a 'value' property * @param string Name of file to be given to the user * @param string Name of common tag to place each line in * @param string Name of the root element. A root element should always be given. * @param string Encoding in which the data is provided * @return void Prompts the user for a file download */ public static function export_complex_table_xml($data, $filename = 'export', $wrapper_tagname, $encoding = 'ISO-8859-1') { $file = api_get_path(SYS_ARCHIVE_PATH) . '/' . uniqid('') . '.xml'; $handle = fopen($file, 'a+'); fwrite($handle, '<?xml version="1.0" encoding="' . $encoding . '"?>' . "\n"); if (!is_null($wrapper_tagname)) { fwrite($handle, '<' . $wrapper_tagname . '>'); } $s = self::_export_complex_table_xml_helper($data); fwrite($handle, $s); if (!is_null($wrapper_tagname)) { fwrite($handle, '</' . $wrapper_tagname . '>' . "\n"); } fclose($handle); DocumentManager::file_send_for_download($file, true, $filename . '.xml'); return false; }
if ($not_deleted_file['contains_file'] == 0) { $filename = trim($filename) . ".html"; $work_temp = api_get_path(SYS_ARCHIVE_PATH) . api_get_unique_id() . '_' . $filename; file_put_contents($work_temp, $not_deleted_file['description']); $files[basename($work_temp)] = $filename; $zip_folder->add($work_temp, PCLZIP_OPT_REMOVE_PATH, api_get_path(SYS_ARCHIVE_PATH), PCLZIP_CB_PRE_ADD, 'my_pre_add_callback'); @unlink($work_temp); } } if (!empty($files)) { //logging event_download(basename($work_data['title']) . '.zip (folder)'); //start download of created file $name = basename($work_data['title']) . '.zip'; if (Security::check_abs_path($temp_zip_file, api_get_path(SYS_ARCHIVE_PATH))) { DocumentManager::file_send_for_download($temp_zip_file, true, $name); @unlink($temp_zip_file); exit; } } else { exit; } /* Extra function (only used here) */ function my_pre_add_callback($p_event, &$p_header) { global $files; if (isset($files[basename($p_header['stored_filename'])])) { $p_header['stored_filename'] = $files[basename($p_header['stored_filename'])]; return 1; } return 0;
/** * Export HTML content in a ODF document * @param string $html * @param string $name * @param string $format * * @return bool */ public static function htmlToOdt($html, $name, $format = 'odt') { $unoconv = api_get_configuration_value('unoconv.binaries'); if (empty($unoconv)) { return false; } if (!empty($html)) { $fs = new Filesystem(); $paths = ['root_sys' => api_get_path(SYS_PATH), 'path.temp' => api_get_path(SYS_ARCHIVE_PATH)]; $connector = new Connector(); $drivers = new DriversContainer(); $drivers['configuration'] = array('unoconv.binaries' => $unoconv, 'unoconv.timeout' => 60); $tempFilesystem = TemporaryFilesystem::create(); $manager = new Manager($tempFilesystem, $fs); $alchemyst = new Alchemyst($drivers, $manager); $dataFileSystem = new Data($paths, $fs, $connector, $alchemyst); $content = $dataFileSystem->convertRelativeToAbsoluteUrl($html); $filePath = $dataFileSystem->putContentInTempFile($content, api_replace_dangerous_char($name), 'html'); $try = true; while ($try) { try { $convertedFile = $dataFileSystem->transcode($filePath, $format); $try = false; DocumentManager::file_send_for_download($convertedFile, false, $name . '.' . $format); } catch (Exception $e) { // error_log($e->getMessage()); } } } }
/** * Exports the learning path as a SCORM package. This is the main function that * gathers the content, transforms it, writes the imsmanifest.xml file, zips the * whole thing and returns the zip. * * This method needs to be called in PHP5, as it will fail with non-adequate * XML package (like the ones for PHP4), and it is *not* a static method, so * you need to call it on a learnpath object. * @TODO The method might be redefined later on in the scorm class itself to avoid * creating a SCORM structure if there is one already. However, if the initial SCORM * path has been modified, it should use the generic method here below. * @TODO link this function with the export_lp() function in the same class * @param string Optional name of zip file. If none, title of learnpath is * domesticated and trailed with ".zip" * @return string Returns the zip package string, or null if error */ function scorm_export() { global $_course; global $charset; if (!class_exists('DomDocument')) { error_log('DOM functions not supported for PHP version below 5.0', 0); $this->error = 'PHP DOM functions not supported for PHP versions below 5.0'; return null; } //remove memory and time limits as much as possible as this might be a long process... if (function_exists('ini_set')) { $mem = ini_get('memory_limit'); if (substr($mem, -1, 1) == 'M') { $mem_num = substr($mem, 0, -1); if ($mem_num < 128) { ini_set('memory_limit', '128M'); } } else { ini_set('memory_limit', '128M'); } ini_set('max_execution_time', 600); //}else{ //error_log('Scorm export: could not change memory and time limits',0); } //Create the zip handler (this will remain available throughout the method) $archive_path = api_get_path(SYS_ARCHIVE_PATH); $sys_course_path = api_get_path(SYS_COURSE_PATH); $temp_dir_short = uniqid(); $temp_zip_dir = $archive_path . "/" . $temp_dir_short; $temp_zip_file = $temp_zip_dir . "/" . md5(time()) . ".zip"; $zip_folder = new PclZip($temp_zip_file); $current_course_path = api_get_path(SYS_COURSE_PATH) . api_get_course_path(); $root_path = $main_path = api_get_path(SYS_PATH); $files_cleanup = array(); //place to temporarily stash the zipfiles //create the temp dir if it doesn't exist //or do a cleanup befor creating the zipfile if (!is_dir($temp_zip_dir)) { mkdir($temp_zip_dir); } else { //cleanup: check the temp dir for old files and delete them $handle = opendir($temp_zip_dir); while (false !== ($file = readdir($handle))) { if ($file != "." && $file != "..") { unlink("{$temp_zip_dir}/{$file}"); } } closedir($handle); } $zip_files = $zip_files_abs = $zip_files_dist = array(); if (is_dir($current_course_path . '/scorm/' . $this->path) && is_file($current_course_path . '/scorm/' . $this->path . '/imsmanifest.xml')) { // remove the possible . at the end of the path $dest_path_to_lp = substr($this->path, -1) == '.' ? substr($this->path, 0, -1) : $this->path; $dest_path_to_scorm_folder = str_replace('//', '/', $temp_zip_dir . '/scorm/' . $dest_path_to_lp); $perm = api_get_setting('permissions_for_new_directories'); $perm = octdec(!empty($perm) ? $perm : '0770'); mkdir($dest_path_to_scorm_folder, $perm, true); $zip_files_dist = copyr($current_course_path . '/scorm/' . $this->path, $dest_path_to_scorm_folder, array('imsmanifest'), $zip_files); } //Build a dummy imsmanifest structure. Do not add to the zip yet (we still need it) //This structure is developed following regulations for SCORM 1.2 packaging in the SCORM 1.2 Content //Aggregation Model official document, secion "2.3 Content Packaging" $xmldoc = new DOMDocument('1.0', $this->encoding); $root = $xmldoc->createElement('manifest'); $root->setAttribute('identifier', 'SingleCourseManifest'); $root->setAttribute('version', '1.1'); $root->setAttribute('xmlns', 'http://www.imsproject.org/xsd/imscp_rootv1p1p2'); $root->setAttribute('xmlns:adlcp', 'http://www.adlnet.org/xsd/adlcp_rootv1p2'); $root->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); $root->setAttribute('xsi:schemaLocation', 'http://www.imsproject.org/xsd/imscp_rootv1p1p2 imscp_rootv1p1p2.xsd http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 imsmd_rootv1p2p1.xsd http://www.adlnet.org/xsd/adlcp_rootv1p2 adlcp_rootv1p2.xsd'); //Build mandatory sub-root container elements $metadata = $xmldoc->createElement('metadata'); $md_schema = $xmldoc->createElement('schema', 'ADL SCORM'); $metadata->appendChild($md_schema); $md_schemaversion = $xmldoc->createElement('schemaversion', '1.2'); $metadata->appendChild($md_schemaversion); $root->appendChild($metadata); $organizations = $xmldoc->createElement('organizations'); $resources = $xmldoc->createElement('resources'); //Build the only organization we will use in building our learnpaths $organizations->setAttribute('default', 'dokeos_scorm_export'); $organization = $xmldoc->createElement('organization'); $organization->setAttribute('identifier', 'dokeos_scorm_export'); //to set the title of the SCORM entity (=organization), we take the name given //in Dokeos and convert it to HTML entities using the Dokeos charset (not the //learning path charset) as it is the encoding that defines how it is stored //in the database. Then we convert it to HTML entities again as the "&" character //alone is not authorized in XML (must be &) //The title is then decoded twice when extracting (see scorm::parse_manifest) $org_title = $xmldoc->createElement('title', htmlentities(api_htmlentities($this->get_name(), ENT_QUOTES, $charset))); $organization->appendChild($org_title); //For each element, add it to the imsmanifest structure, then add it to the zip. //Always call the learnpathItem->scorm_export() method to change it to the SCORM //format $link_updates = array(); foreach ($this->items as $index => $item) { if (!in_array($item->type, array(TOOL_QUIZ, TOOL_FORUM, TOOL_THREAD, TOOL_LINK, TOOL_STUDENTPUBLICATION))) { //get included documents from this item if ($item->type == 'sco') { $inc_docs = $item->get_resources_from_source(null, api_get_path(SYS_COURSE_PATH) . api_get_course_path() . '/' . 'scorm/' . $this->path . '/' . $item->get_path()); } else { $inc_docs = $item->get_resources_from_source(); } //give a child element <item> to the <organization> element $my_item_id = $item->get_id(); $my_item = $xmldoc->createElement('item'); $my_item->setAttribute('identifier', 'ITEM_' . $my_item_id); $my_item->setAttribute('identifierref', 'RESOURCE_' . $my_item_id); $my_item->setAttribute('isvisible', 'true'); //give a child element <title> to the <item> element $my_title = $xmldoc->createElement('title', htmlspecialchars($item->get_title(), ENT_QUOTES, $this->encoding)); $my_item->appendChild($my_title); //give a child element <adlcp:prerequisites> to the <item> element $my_prereqs = $xmldoc->createElement('adlcp:prerequisites', $this->get_scorm_prereq_string($my_item_id)); $my_prereqs->setAttribute('type', 'aicc_script'); $my_item->appendChild($my_prereqs); //give a child element <adlcp:maxtimeallowed> to the <item> element - not yet supported //$xmldoc->createElement('adlcp:maxtimeallowed',''); //give a child element <adlcp:timelimitaction> to the <item> element - not yet supported //$xmldoc->createElement('adlcp:timelimitaction',''); //give a child element <adlcp:datafromlms> to the <item> element - not yet supported //$xmldoc->createElement('adlcp:datafromlms',''); //give a child element <adlcp:masteryscore> to the <item> element $my_masteryscore = $xmldoc->createElement('adlcp:masteryscore', $item->get_mastery_score()); $my_item->appendChild($my_masteryscore); //attach this item to the organization element or hits parent if there is one if (!empty($item->parent) && $item->parent != 0) { $children = $organization->childNodes; $possible_parent =& $this->get_scorm_xml_node($children, 'ITEM_' . $item->parent); if (is_object($possible_parent)) { $possible_parent->appendChild($my_item); } else { if ($this->debug > 0) { error_log('Parent ITEM_' . $item->parent . ' of item ITEM_' . $my_item_id . ' not found'); } } } else { if ($this->debug > 0) { error_log('No parent'); } $organization->appendChild($my_item); } //get the path of the file(s) from the course directory root $my_file_path = $item->get_file_path('scorm/' . $this->path . '/'); $my_xml_file_path = api_htmlentities($my_file_path, ENT_QUOTES, $this->encoding); $my_sub_dir = dirname($my_file_path); $my_xml_sub_dir = api_htmlentities($my_sub_dir, ENT_QUOTES, $this->encoding); //give a <resource> child to the <resources> element $my_resource = $xmldoc->createElement('resource'); $my_resource->setAttribute('identifier', 'RESOURCE_' . $item->get_id()); $my_resource->setAttribute('type', 'webcontent'); $my_resource->setAttribute('href', $my_xml_file_path); //adlcp:scormtype can be either 'sco' or 'asset' if ($item->type == 'sco') { $my_resource->setAttribute('adlcp:scormtype', 'sco'); } else { $my_resource->setAttribute('adlcp:scormtype', 'asset'); } //xml:base is the base directory to find the files declared in this resource $my_resource->setAttribute('xml:base', ''); //give a <file> child to the <resource> element $my_file = $xmldoc->createElement('file'); $my_file->setAttribute('href', $my_xml_file_path); $my_resource->appendChild($my_file); //dependency to other files - not yet supported $i = 1; foreach ($inc_docs as $doc_info) { if (count($doc_info) < 1 or empty($doc_info[0])) { continue; } $my_dep = $xmldoc->createElement('resource'); $res_id = 'RESOURCE_' . $item->get_id() . '_' . $i; $my_dep->setAttribute('identifier', $res_id); $my_dep->setAttribute('type', 'webcontent'); $my_dep->setAttribute('adlcp:scormtype', 'asset'); $my_dep_file = $xmldoc->createElement('file'); //check type of URL //error_log(__LINE__.'Now dealing with '.$doc_info[0].' of type '.$doc_info[1].'-'.$doc_info[2],0); if ($doc_info[1] == 'remote') { //remote file. Save url as is $my_dep_file->setAttribute('href', $doc_info[0]); $my_dep->setAttribute('xml:base', ''); } elseif ($doc_info[1] == 'local') { switch ($doc_info[2]) { case 'url': //local URL - save path as url for now, don't zip file $abs_path = api_get_path(SYS_PATH) . str_replace(api_get_path(WEB_PATH), '', $doc_info[0]); $current_dir = dirname($abs_path); $file_path = realpath($abs_path); $my_dep_file->setAttribute('href', $file_path); $my_dep->setAttribute('xml:base', ''); if (strstr($file_path, $main_path) !== false) { //the calculated real path is really inside the dokeos root path //reduce file path to what's under the DocumentRoot $file_path = substr($file_path, strlen($root_path) - 1); //echo $file_path;echo '<br><br>'; //error_log(__LINE__.'Reduced url path: '.$file_path,0); $zip_files_abs[] = $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path); $my_dep_file->setAttribute('href', $file_path); $my_dep->setAttribute('xml:base', ''); } else { if (empty($file_path)) { /* $document_root = substr(api_get_path(SYS_PATH), 0, strpos(api_get_path(SYS_PATH),api_get_path(REL_PATH))); if(strpos($document_root,-1)=='/') { $document_root = substr(0, -1, $document_root); } */ $file_path = $_SERVER['DOCUMENT_ROOT'] . $abs_path; $file_path = str_replace('//', '/', $file_path); if (file_exists($file_path)) { $file_path = substr($file_path, strlen($current_dir)); // we get the relative path $zip_files[] = $my_sub_dir . '/' . $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path); $my_dep_file->setAttribute('href', $file_path); $my_dep->setAttribute('xml:base', ''); } } } break; case 'abs': //absolute path from DocumentRoot. Save file and leave path as is in the zip $my_dep_file->setAttribute('href', $doc_info[0]); $my_dep->setAttribute('xml:base', ''); //$current_dir = dirname($current_course_path.'/'.$item->get_file_path()).'/'; //the next lines fix a bug when using the "subdir" mode of Dokeos, whereas //an image path would be constructed as /var/www/subdir/subdir/img/foo.bar $abs_img_path_without_subdir = $doc_info[0]; $relp = api_get_path(REL_PATH); //the url-append config param $pos = strpos($abs_img_path_without_subdir, $relp); if ($pos === 0) { $abs_img_path_without_subdir = '/' . substr($abs_img_path_without_subdir, strlen($relp)); } //$file_path = realpath(api_get_path(SYS_PATH).$doc_info[0]); $file_path = realpath(api_get_path(SYS_PATH) . $abs_img_path_without_subdir); $file_path = str_replace('\\', '/', $file_path); $file_path = str_replace('//', '/', $file_path); //error_log(__LINE__.'Abs path: '.$file_path,0); //prepare the current directory path (until just under 'document') with a trailing slash $cur_path = substr($current_course_path, -1) == '/' ? $current_course_path : $current_course_path . '/'; //check if the current document is in that path if (strstr($file_path, $cur_path) !== false) { //the document is in that path, now get the relative path //to the containing document $orig_file_path = dirname($cur_path . $my_file_path) . '/'; $relative_path = ''; if (strstr($file_path, $cur_path) !== false) { $relative_path = substr($file_path, strlen($orig_file_path)); $file_path = substr($file_path, strlen($cur_path)); } else { //this case is still a problem as it's difficult to calculate a relative path easily //might still generate wrong links //$file_path = substr($file_path,strlen($cur_path)); //calculate the directory path to the current file (without trailing slash) $my_relative_path = dirname($file_path); $my_relative_file = basename($file_path); //calculate the directory path to the containing file (without trailing slash) $my_orig_file_path = substr($orig_file_path, 0, -1); $dotdot = ''; $subdir = ''; while (strstr($my_relative_path, $my_orig_file_path) === false && strlen($my_orig_file_path) > 1 && strlen($my_relative_path) > 1) { $my_relative_path2 = dirname($my_relative_path); $my_orig_file_path = dirname($my_orig_file_path); $subdir = substr($my_relative_path, strlen($my_relative_path2) + 1) . "/" . $subdir; $dotdot += '../'; $my_relative_path = $my_relative_path2; } $relative_path = $dotdot . $subdir . $my_relative_file; } //put the current document in the zip (this array is the array //that will manage documents already in the course folder - relative) $zip_files[] = $file_path; //update the links to the current document in the containing document (make them relative) $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $relative_path); $my_dep_file->setAttribute('href', $file_path); $my_dep->setAttribute('xml:base', ''); } elseif (strstr($file_path, $main_path) !== false) { //the calculated real path is really inside the dokeos root path //reduce file path to what's under the DocumentRoot $file_path = substr($file_path, strlen($root_path)); //echo $file_path;echo '<br><br>'; //error_log('Reduced path: '.$file_path,0); $zip_files_abs[] = $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); } else { if (empty($file_path)) { /* $document_root = substr(api_get_path(SYS_PATH), 0, strpos(api_get_path(SYS_PATH),api_get_path(REL_PATH))); if(strpos($document_root,-1)=='/') { $document_root = substr(0, -1, $document_root); } */ $file_path = $_SERVER['DOCUMENT_ROOT'] . $doc_info[0]; $file_path = str_replace('//', '/', $file_path); if (file_exists($file_path)) { $file_path = substr($file_path, strlen($current_dir)); // we get the relative path $zip_files[] = $my_sub_dir . '/' . $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); } } } break; case 'rel': //path relative to the current document. Save xml:base as current document's directory and save file in zip as subdir.file_path if (substr($doc_info[0], 0, 2) == '..') { //relative path going up $current_dir = dirname($current_course_path . '/' . $item->get_file_path()) . '/'; $file_path = realpath($current_dir . $doc_info[0]); //error_log($file_path.' <-> '.$main_path,0); if (strstr($file_path, $main_path) !== false) { //the calculated real path is really inside the dokeos root path //reduce file path to what's under the DocumentRoot $file_path = substr($file_path, strlen($root_path)); //error_log('Reduced path: '.$file_path,0); $zip_files_abs[] = $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); } } else { $zip_files[] = $my_sub_dir . '/' . $doc_info[0]; $my_dep_file->setAttribute('href', $doc_info[0]); $my_dep->setAttribute('xml:base', $my_xml_sub_dir); } break; default: $my_dep_file->setAttribute('href', $doc_info[0]); $my_dep->setAttribute('xml:base', ''); break; } } $my_dep->appendChild($my_dep_file); $resources->appendChild($my_dep); $dependency = $xmldoc->createElement('dependency'); $dependency->setAttribute('identifierref', $res_id); $my_resource->appendChild($dependency); $i++; } //$my_dependency = $xmldoc->createElement('dependency'); //$my_dependency->setAttribute('identifierref',''); $resources->appendChild($my_resource); $zip_files[] = $my_file_path; //error_log('File '.$my_file_path. ' added to $zip_files',0); } else { // if the item is a quiz or a link or whatever non-exportable, we include a step indicating it if ($item->type == TOOL_LINK) { $my_item = $xmldoc->createElement('item'); $my_item->setAttribute('identifier', 'ITEM_' . $item->get_id()); $my_item->setAttribute('identifierref', 'RESOURCE_' . $item->get_id()); $my_item->setAttribute('isvisible', 'true'); //give a child element <title> to the <item> element $my_title = $xmldoc->createElement('title', htmlspecialchars($item->get_title(), ENT_QUOTES)); $my_item->appendChild($my_title); //give a child element <adlcp:prerequisites> to the <item> element $my_prereqs = $xmldoc->createElement('adlcp:prerequisites', $item->get_prereq_string()); $my_prereqs->setAttribute('type', 'aicc_script'); $my_item->appendChild($my_prereqs); //give a child element <adlcp:maxtimeallowed> to the <item> element - not yet supported //$xmldoc->createElement('adlcp:maxtimeallowed',''); //give a child element <adlcp:timelimitaction> to the <item> element - not yet supported //$xmldoc->createElement('adlcp:timelimitaction',''); //give a child element <adlcp:datafromlms> to the <item> element - not yet supported //$xmldoc->createElement('adlcp:datafromlms',''); //give a child element <adlcp:masteryscore> to the <item> element $my_masteryscore = $xmldoc->createElement('adlcp:masteryscore', $item->get_mastery_score()); $my_item->appendChild($my_masteryscore); //attach this item to the organization element or its parent if there is one if (!empty($item->parent) && $item->parent != 0) { $children = $organization->childNodes; for ($i = 0; $i < $children->length; $i++) { $item_temp = $children->item($i); if ($item_temp->nodeName == 'item') { if ($item_temp->getAttribute('identifier') == 'ITEM_' . $item->parent) { $item_temp->appendChild($my_item); } } } } else { $organization->appendChild($my_item); } $my_file_path = 'link_' . $item->get_id() . '.html'; $sql = 'SELECT url, title FROM ' . Database::get_course_table(TABLE_LINK) . ' WHERE id=' . $item->path; $rs = Database::query($sql, __FILE__, __LINE__); if ($link = Database::fetch_array($rs)) { $url = $link['url']; $title = stripslashes($link['title']); $links_to_create[$my_file_path] = array('title' => $title, 'url' => $url); $my_xml_file_path = api_htmlentities($my_file_path, ENT_QUOTES, $this->encoding); $my_sub_dir = dirname($my_file_path); $my_xml_sub_dir = api_htmlentities($my_sub_dir, ENT_QUOTES, $this->encoding); //give a <resource> child to the <resources> element $my_resource = $xmldoc->createElement('resource'); $my_resource->setAttribute('identifier', 'RESOURCE_' . $item->get_id()); $my_resource->setAttribute('type', 'webcontent'); $my_resource->setAttribute('href', $my_xml_file_path); //adlcp:scormtype can be either 'sco' or 'asset' $my_resource->setAttribute('adlcp:scormtype', 'asset'); //xml:base is the base directory to find the files declared in this resource $my_resource->setAttribute('xml:base', ''); //give a <file> child to the <resource> element $my_file = $xmldoc->createElement('file'); $my_file->setAttribute('href', $my_xml_file_path); $my_resource->appendChild($my_file); $resources->appendChild($my_resource); } } elseif ($item->type == TOOL_QUIZ) { require_once api_get_path(SYS_CODE_PATH) . 'exercice/exercise.class.php'; $exe_id = $item->path; //should be using ref when everything will be cleaned up in this regard $exe = new Exercise(); $exe->read($exe_id); $my_item = $xmldoc->createElement('item'); $my_item->setAttribute('identifier', 'ITEM_' . $item->get_id()); $my_item->setAttribute('identifierref', 'RESOURCE_' . $item->get_id()); $my_item->setAttribute('isvisible', 'true'); //give a child element <title> to the <item> element $my_title = $xmldoc->createElement('title', htmlspecialchars($item->get_title(), ENT_QUOTES, $this->encoding)); $my_item->appendChild($my_title); $my_max_score = $xmldoc->createElement('max_score', $item->get_max()); //$my_item->appendChild($my_max_score); //give a child element <adlcp:prerequisites> to the <item> element $my_prereqs = $xmldoc->createElement('adlcp:prerequisites', $item->get_prereq_string()); $my_prereqs->setAttribute('type', 'aicc_script'); $my_item->appendChild($my_prereqs); //give a child element <adlcp:masteryscore> to the <item> element $my_masteryscore = $xmldoc->createElement('adlcp:masteryscore', $item->get_mastery_score()); $my_item->appendChild($my_masteryscore); //attach this item to the organization element or hits parent if there is one if (!empty($item->parent) && $item->parent != 0) { $children = $organization->childNodes; for ($i = 0; $i < $children->length; $i++) { $item_temp = $children->item($i); if ($item_temp->nodeName == 'item') { if ($item_temp->getAttribute('identifier') == 'ITEM_' . $item->parent) { $item_temp->appendChild($my_item); } } } } else { $organization->appendChild($my_item); } //include export scripts require_once api_get_path(SYS_CODE_PATH) . 'exercice/export/scorm/scorm_export.php'; //get the path of the file(s) from the course directory root //$my_file_path = $item->get_file_path('scorm/'.$this->path.'/'); $my_file_path = 'quiz_' . $item->get_id() . '.html'; //write the contents of the exported exercise into a (big) html file //to later pack it into the exported SCORM. The file will be removed afterwards $contents = export_exercise($exe_id, true); $tmp_file_path = $archive_path . $temp_dir_short . '/' . $my_file_path; $res = file_put_contents($tmp_file_path, $contents); if ($res === false) { error_log('Could not write into file ' . $tmp_file_path . ' ' . __FILE__ . ' ' . __LINE__, 0); } $files_cleanup[] = $tmp_file_path; //error_log($tmp_path);die(); $my_xml_file_path = api_htmlentities($my_file_path, ENT_QUOTES, $this->encoding); $my_sub_dir = dirname($my_file_path); $my_xml_sub_dir = api_htmlentities($my_sub_dir, ENT_QUOTES, $this->encoding); //give a <resource> child to the <resources> element $my_resource = $xmldoc->createElement('resource'); $my_resource->setAttribute('identifier', 'RESOURCE_' . $item->get_id()); $my_resource->setAttribute('type', 'webcontent'); $my_resource->setAttribute('href', $my_xml_file_path); //adlcp:scormtype can be either 'sco' or 'asset' $my_resource->setAttribute('adlcp:scormtype', 'sco'); //xml:base is the base directory to find the files declared in this resource $my_resource->setAttribute('xml:base', ''); //give a <file> child to the <resource> element $my_file = $xmldoc->createElement('file'); $my_file->setAttribute('href', $my_xml_file_path); $my_resource->appendChild($my_file); //get included docs $inc_docs = $item->get_resources_from_source(null, $tmp_file_path); //dependency to other files - not yet supported $i = 1; foreach ($inc_docs as $doc_info) { if (count($doc_info) < 1 or empty($doc_info[0])) { continue; } $my_dep = $xmldoc->createElement('resource'); $res_id = 'RESOURCE_' . $item->get_id() . '_' . $i; $my_dep->setAttribute('identifier', $res_id); $my_dep->setAttribute('type', 'webcontent'); $my_dep->setAttribute('adlcp:scormtype', 'asset'); $my_dep_file = $xmldoc->createElement('file'); //check type of URL //error_log(__LINE__.'Now dealing with '.$doc_info[0].' of type '.$doc_info[1].'-'.$doc_info[2],0); if ($doc_info[1] == 'remote') { //remote file. Save url as is $my_dep_file->setAttribute('href', $doc_info[0]); $my_dep->setAttribute('xml:base', ''); } elseif ($doc_info[1] == 'local') { switch ($doc_info[2]) { case 'url': //local URL - save path as url for now, don't zip file //save file but as local file (retrieve from URL) $abs_path = api_get_path(SYS_PATH) . str_replace(api_get_path(WEB_PATH), '', $doc_info[0]); $current_dir = dirname($abs_path); $file_path = realpath($abs_path); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); if (strstr($file_path, $main_path) !== false) { //the calculated real path is really inside the dokeos root path //reduce file path to what's under the DocumentRoot $file_path = substr($file_path, strlen($root_path)); //echo $file_path;echo '<br><br>'; //error_log('Reduced path: '.$file_path,0); $zip_files_abs[] = $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => 'document/' . $file_path); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); } else { if (empty($file_path)) { /* $document_root = substr(api_get_path(SYS_PATH), 0, strpos(api_get_path(SYS_PATH),api_get_path(REL_PATH))); if(strpos($document_root,-1)=='/') { $document_root = substr(0, -1, $document_root); } */ $file_path = $_SERVER['DOCUMENT_ROOT'] . $abs_path; $file_path = str_replace('//', '/', $file_path); if (file_exists($file_path)) { $file_path = substr($file_path, strlen($current_dir)); // we get the relative path $zip_files[] = $my_sub_dir . '/' . $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => 'document/' . $file_path); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); } } } break; case 'abs': //absolute path from DocumentRoot. Save file and leave path as is in the zip $current_dir = dirname($current_course_path . '/' . $item->get_file_path()) . '/'; $file_path = realpath($doc_info[0]); $my_dep_file->setAttribute('href', $file_path); $my_dep->setAttribute('xml:base', ''); if (strstr($file_path, $main_path) !== false) { //the calculated real path is really inside the dokeos root path //reduce file path to what's under the DocumentRoot $file_path = substr($file_path, strlen($root_path)); //echo $file_path;echo '<br><br>'; //error_log('Reduced path: '.$file_path,0); $zip_files_abs[] = $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); } else { if (empty($file_path)) { /* $document_root = substr(api_get_path(SYS_PATH), 0, strpos(api_get_path(SYS_PATH),api_get_path(REL_PATH))); if(strpos($document_root,-1)=='/') { $document_root = substr(0, -1, $document_root); } */ $file_path = $_SERVER['DOCUMENT_ROOT'] . $doc_info[0]; $file_path = str_replace('//', '/', $file_path); if (file_exists($file_path)) { $file_path = substr($file_path, strlen($current_dir)); // we get the relative path $zip_files[] = $my_sub_dir . '/' . $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); } } } break; case 'rel': //path relative to the current document. Save xml:base as current document's directory and save file in zip as subdir.file_path if (substr($doc_info[0], 0, 2) == '..') { //relative path going up $current_dir = dirname($current_course_path . '/' . $item->get_file_path()) . '/'; $file_path = realpath($current_dir . $doc_info[0]); //error_log($file_path.' <-> '.$main_path,0); if (strstr($file_path, $main_path) !== false) { //the calculated real path is really inside the dokeos root path //reduce file path to what's under the DocumentRoot $file_path = substr($file_path, strlen($root_path)); $file_path_dest = $file_path; //file path is courses/DOKEOS/document/.... $info_file_path = explode('/', $file_path); if ($info_file_path[0] == 'courses') { //add character "/" in file path $file_path_dest = '/' . $file_path; } //error_log('Reduced path: '.$file_path,0); $zip_files_abs[] = $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path_dest); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); } } else { $zip_files[] = $my_sub_dir . '/' . $doc_info[0]; $my_dep_file->setAttribute('href', $doc_info[0]); $my_dep->setAttribute('xml:base', $my_xml_sub_dir); } break; default: $my_dep_file->setAttribute('href', $doc_info[0]); // ../../courses/ $my_dep->setAttribute('xml:base', ''); break; } } $my_dep->appendChild($my_dep_file); $resources->appendChild($my_dep); $dependency = $xmldoc->createElement('dependency'); $dependency->setAttribute('identifierref', $res_id); $my_resource->appendChild($dependency); $i++; } $resources->appendChild($my_resource); $zip_files[] = $my_file_path; } else { //get the path of the file(s) from the course directory root $my_file_path = 'non_exportable.html'; $my_xml_file_path = api_htmlentities($my_file_path, ENT_COMPAT, $this->encoding); $my_sub_dir = dirname($my_file_path); $my_xml_sub_dir = api_htmlentities($my_sub_dir, ENT_COMPAT, $this->encoding); //give a <resource> child to the <resources> element $my_resource = $xmldoc->createElement('resource'); $my_resource->setAttribute('identifier', 'RESOURCE_' . $item->get_id()); $my_resource->setAttribute('type', 'webcontent'); $my_resource->setAttribute('href', 'document/' . $my_xml_file_path); //adlcp:scormtype can be either 'sco' or 'asset' $my_resource->setAttribute('adlcp:scormtype', 'asset'); //xml:base is the base directory to find the files declared in this resource $my_resource->setAttribute('xml:base', ''); //give a <file> child to the <resource> element $my_file = $xmldoc->createElement('file'); $my_file->setAttribute('href', 'document/' . $my_xml_file_path); $my_resource->appendChild($my_file); $resources->appendChild($my_resource); } } } $organizations->appendChild($organization); $root->appendChild($organizations); $root->appendChild($resources); $xmldoc->appendChild($root); //todo: add a readme file here, with a short description and a link to the Reload player //then add the file to the zip, then destroy the file (this is done automatically) // http://www.reload.ac.uk/scormplayer.html - once done, don't forget to close FS#138 //error_log(print_r($zip_files,true),0); foreach ($zip_files as $file_path) { if (empty($file_path)) { continue; } //error_log(__LINE__.'getting document from '.$sys_course_path.$_course['path'].'/'.$file_path.' removing '.$sys_course_path.$_course['path'].'/',0); $dest_file = $archive_path . $temp_dir_short . '/' . $file_path; $this->create_path($dest_file); //error_log('copy '.api_get_path('SYS_COURSE_PATH').$_course['path'].'/'.$file_path.' to '.api_get_path('SYS_ARCHIVE_PATH').$temp_dir_short.'/'.$file_path,0); //echo $main_path.$file_path.'<br>'; @copy($sys_course_path . $_course['path'] . '/' . $file_path, $dest_file); //check if the file needs a link update if (in_array($file_path, array_keys($link_updates))) { $string = file_get_contents($dest_file); unlink($dest_file); foreach ($link_updates[$file_path] as $old_new) { //error_log('Replacing '.$old_new['orig'].' by '.$old_new['dest'].' in '.$file_path,0); //this is an ugly hack that allows .flv files to be found by the flv player that // will be added in document/main/inc/lib/flv_player/flv_player.swf and that needs // to find the flv to play in document/main/, so we replace main/ in the flv path by // ../../.. to return from inc/lib/flv_player to the document/main path if (substr($old_new['dest'], -3) == 'flv' && substr($old_new['dest'], 0, 5) == 'main/') { $old_new['dest'] = str_replace('main/', '../../../', $old_new['dest']); } elseif (substr($old_new['dest'], -3) == 'flv' && substr($old_new['dest'], 0, 6) == 'video/') { $old_new['dest'] = str_replace('video/', '../../../../video/', $old_new['dest']); } if (substr($old_new['dest'], 0, 1) == '/') { $old_new['dest'] = substr($old_new['dest'], 1); } $string = str_replace($old_new['orig'], $old_new['dest'], $string); $string = str_replace(str_replace('https', 'http', $old_new['orig']), $old_new['dest'], $string); } file_put_contents($dest_file, $string); } } foreach ($zip_files_abs as $file_path) { if (empty($file_path)) { continue; } //error_log(__LINE__.'checking existence of '.$main_path.$file_path.'',0); if (!is_file($main_path . $file_path) || !is_readable($main_path . $file_path)) { continue; } //error_log(__LINE__.'getting document from '.$main_path.$file_path.' removing '.api_get_path('SYS_COURSE_PATH').$_course['path'].'/',0); $dest_file = $archive_path . $temp_dir_short . '/document/' . $file_path; $this->create_path($dest_file); //error_log('Created path '.api_get_path(SYS_ARCHIVE_PATH).$temp_dir_short.'/document/'.$file_path,0); //error_log('copy '.api_get_path(SYS_COURSE_PATH).$_course['path'].'/'.$file_path.' to '.api_get_path(SYS_ARCHIVE_PATH).$temp_dir_short.'/'.$file_path,0); //echo $main_path.$file_path.' - '.$dest_file.'<br>'; copy($main_path . $file_path, $dest_file); //check if the file needs a link update if (in_array($file_path, array_keys($link_updates))) { $string = file_get_contents($dest_file); unlink($dest_file); foreach ($link_updates[$file_path] as $old_new) { //error_log('Replacing '.$old_new['orig'].' by '.$old_new['dest'].' in '.$file_path,0); //this is an ugly hack that allows .flv files to be found by the flv player that // will be added in document/main/inc/lib/flv_player/flv_player.swf and that needs // to find the flv to play in document/main/, so we replace main/ in the flv path by // ../../.. to return from inc/lib/flv_player to the document/main path if (substr($old_new['dest'], -3) == 'flv' && substr($old_new['dest'], 0, 5) == 'main/') { $old_new['dest'] = str_replace('main/', '../../../', $old_new['dest']); } if (substr($old_new['dest'], 0, 1) == '/') { $old_new['dest'] = substr($old_new['dest'], 1); } $string = str_replace($old_new['orig'], $old_new['dest'], $string); $string = str_replace(str_replace('https', 'http', $old_new['orig']), $old_new['dest'], $string); } file_put_contents($dest_file, $string); } } if (is_array($links_to_create)) { foreach ($links_to_create as $file => $link) { $file_content = '<html><body><div style="text-align:center"><a href="' . $link['url'] . '">' . $link['title'] . '</a></div></body></html>'; file_put_contents($archive_path . $temp_dir_short . '/' . $file, $file_content); } } // add non exportable message explanation $lang_not_exportable = get_lang('ThisItemIsNotExportable'); $file_content = <<<EOD <html> \t<head> \t\t<style> \t\t\t.error-message { \t\t\t\tfont-family: arial, verdana, helvetica, sans-serif; \t\t\t\tborder-width: 1px; \t\t\t\tborder-style: solid; \t\t\t\tleft: 50%; \t\t\t\tmargin: 10px auto; \t\t\t\tmin-height: 30px; \t\t\t\tpadding: 5px; \t\t\t\tright: 50%; \t\t\t\twidth: 500px; \t\t\t\tbackground-color: #FFD1D1; \t\t\t\tborder-color: #FF0000; \t\t\t\tcolor: #000; \t\t\t} \t\t</style> \t<body> \t\t<div class="error-message"> \t\t\t{$lang_not_exportable} \t\t</div> \t</body> </html> EOD; if (!is_dir($archive_path . $temp_dir_short . '/document')) { @mkdir($archive_path . $temp_dir_short . '/document'); } file_put_contents($archive_path . $temp_dir_short . '/document/non_exportable.html', $file_content); //Add the extra files that go along with a SCORM package $main_code_path = api_get_path(SYS_CODE_PATH) . 'newscorm/packaging/'; $extra_files = scandir($main_code_path); foreach ($extra_files as $extra_file) { if (strpos($extra_file, '.') === 0) { continue; } else { $dest_file = $archive_path . $temp_dir_short . '/' . $extra_file; $this->create_path($dest_file); copy($main_code_path . $extra_file, $dest_file); } } //Finalize the imsmanifest structure, add to the zip, then return the zip $xmldoc->save($archive_path . '/' . $temp_dir_short . '/imsmanifest.xml'); $zip_folder->add($archive_path . '/' . $temp_dir_short, PCLZIP_OPT_REMOVE_PATH, $archive_path . '/' . $temp_dir_short . '/'); //clean possible temporary files foreach ($files_cleanup as $file) { $res = unlink($file); if ($res === false) { error_log('Could not delete temp file ' . $file . ' ' . __FILE__ . ' ' . __LINE__, 0); } } //Send file to client //$name = 'scorm_export_'.$this->lp_id.'.zip'; require_once api_get_path(LIBRARY_PATH) . 'fileUpload.lib.php'; $name = preg_replace('([^a-zA-Z0-9_\\.])', '-', html_entity_decode($this->get_name(), ENT_QUOTES)) . '.zip'; DocumentManager::file_send_for_download($temp_zip_file, true, $name); }
* but this code will hopefully be replaced soon by an Apache URL * rewrite mechanism. * * @package chamilo.work */ //require_once '../inc/global.inc.php'; require_once 'work.lib.php'; // Course protection api_protect_course_script(true); $commentId = isset($_GET['comment_id']) ? intval($_GET['comment_id']) : null; if (empty($commentId)) { api_not_allowed(true); } $workData = getWorkComment($commentId); $courseInfo = api_get_course_info(); if (!empty($workData)) { if (empty($workData['file_path']) || isset($workData['file_path']) && !file_exists($workData['file_path'])) { api_not_allowed(true); } $work = get_work_data_by_id($workData['work_id']); protectWork($courseInfo, $work['parent_id']); if (user_is_author($workData['work_id']) || $courseInfo['show_score'] == 0 && $work['active'] == 1 && $work['accepted'] == 1) { if (Security::check_abs_path($workData['file_path'], api_get_path(SYS_COURSE_PATH) . api_get_course_path() . '/')) { DocumentManager::file_send_for_download($workData['file_path'], true, $workData['file_name_to_show']); } } else { api_not_allowed(true); } } else { api_not_allowed(true); }
/** * Exports the current SCORM object's files as a zip. Excerpts taken from learnpath_functions.inc.php::exportpath() * @param integer Learnpath ID (optional, taken from object context if not defined) */ function export_zip($lp_id = null) { if ($this->debug > 0) { error_log('In scorm::export_zip method(' . $lp_id . ')', 0); } if (empty($lp_id)) { if (!is_object($this)) { return false; } else { $id = $this->get_id(); if (empty($id)) { return false; } else { $lp_id = $this->get_id(); } } } //error_log('New LP - in export_zip()',0); //zip everything that is in the corresponding scorm dir //write the zip file somewhere (might be too big to return) require_once 'learnpath_functions.inc.php'; $course_id = api_get_course_int_id(); $tbl_lp = Database::get_course_table(TABLE_LP_MAIN); $_course = api_get_course_info(api_get_course_id()); $sql = "SELECT * FROM {$tbl_lp} WHERE c_id = " . $course_id . " AND id=" . $lp_id; $result = Database::query($sql); $row = Database::fetch_array($result); $LPname = $row['path']; $list = split('/', $LPname); $LPnamesafe = $list[0]; //$zipfoldername = '/tmp'; //$zipfoldername = '../../courses/'.$_course['directory'].'/temp/'.$LPnamesafe; $zipfoldername = api_get_path(SYS_COURSE_PATH) . $_course['directory'] . '/temp/' . $LPnamesafe; $scormfoldername = api_get_path(SYS_COURSE_PATH) . $_course['directory'] . '/scorm/' . $LPnamesafe; $zipfilename = $zipfoldername . '/' . $LPnamesafe . '.zip'; // Get a temporary dir for creating the zip file. //error_log('New LP - cleaning dir '.$zipfoldername, 0); deldir($zipfoldername); // Make sure the temp dir is cleared. $res = mkdir($zipfoldername, api_get_permissions_for_new_directories()); //error_log('New LP - made dir '.$zipfoldername, 0); // Create zipfile of given directory. $zip_folder = new PclZip($zipfilename); $zip_folder->create($scormfoldername . '/', PCLZIP_OPT_REMOVE_PATH, $scormfoldername . '/'); //$zipfilename = '/var/www/chamilo/courses/TEST2/scorm/example_document.html'; //This file sending implies removing the default mime-type from php.ini //DocumentManager :: file_send_for_download($zipfilename, true, $LPnamesafe.'.zip'); DocumentManager::file_send_for_download($zipfilename, true); // Delete the temporary zip file and directory in fileManager.lib.php FileManager::my_delete($zipfilename); FileManager::my_delete($zipfoldername); return true; }
/** * Exports the current AICC object's files as a zip. Excerpts taken from learnpath_functions.inc.php::exportpath() * @param integer Learnpath ID (optional, taken from object context if not defined) */ function export_zip($lp_id = null) { if ($this->debug > 0) { error_log('In aicc::export_zip method(' . $lp_id . ')', 0); } if (empty($lp_id)) { if (!is_object($this)) { return false; } else { $id = $this->get_id(); if (empty($id)) { return false; } else { $lp_id = $this->get_id(); } } } //error_log('New LP - in export_zip()',0); //zip everything that is in the corresponding scorm dir //write the zip file somewhere (might be too big to return) require_once api_get_path(LIBRARY_PATH) . "fileUpload.lib.php"; require_once api_get_path(LIBRARY_PATH) . "fileManage.lib.php"; require_once api_get_path(LIBRARY_PATH) . "document.lib.php"; require_once api_get_path(LIBRARY_PATH) . "pclzip/pclzip.lib.php"; require_once "learnpath_functions.inc.php"; $tbl_lp = Database::get_course_table(TABLE_LP_MAIN); $_course = Database::get_course_info(api_get_course_id()); $sql = "SELECT * FROM {$tbl_lp} WHERE id=" . $lp_id; $result = Database::query($sql, __FILE__, __LINE__); $row = Database::fetch_array($result); $LPname = $row['path']; $list = split('/', $LPname); $LPnamesafe = $list[0]; //$zipfoldername = '/tmp'; //$zipfoldername = '../../courses/'.$_course['directory']."/temp/".$LPnamesafe; $zipfoldername = api_get_path('SYS_COURSE_PATH') . $_course['directory'] . "/temp/" . $LPnamesafe; $scormfoldername = api_get_path('SYS_COURSE_PATH') . $_course['directory'] . "/scorm/" . $LPnamesafe; $zipfilename = $zipfoldername . "/" . $LPnamesafe . ".zip"; //Get a temporary dir for creating the zip file //error_log('New LP - cleaning dir '.$zipfoldername,0); deldir($zipfoldername); //make sure the temp dir is cleared $res = mkdir($zipfoldername); //error_log('New LP - made dir '.$zipfoldername,0); //create zipfile of given directory $zip_folder = new PclZip($zipfilename); $zip_folder->create($scormfoldername . '/', PCLZIP_OPT_REMOVE_PATH, $scormfoldername . '/'); //$zipfilename = '/var/www/dokeos-comp/courses/TEST2/scorm/example_document.html'; //this file sending implies removing the default mime-type from php.ini //DocumentManager :: file_send_for_download($zipfilename, true, $LPnamesafe.".zip"); DocumentManager::file_send_for_download($zipfilename, true); // Delete the temporary zip file and directory in fileManage.lib.php my_delete($zipfilename); my_delete($zipfoldername); return true; }
$language_file = array('courses', 'index', 'admin'); $user_id = api_get_user_id(); if (!isset($_GET['file']) || !isset($_GET['title']) || !isset($_GET['ticket_id'])) { api_not_allowed(); } if (!api_is_platform_admin()) { $ticket_id = $_GET['ticket_id']; $table_support_messages = Database::get_main_table(TABLE_SUPPORT_MESSAGE); $table_support_tickets = Database::get_main_table(TABLE_SUPPORT_TICKET); $table_support_message_attachments = Database::get_main_table(TABLE_SUPPORT_MESSAGE_ATTACHMENTS); $sql = "SELECT DISTINCT ticket.request_user FROM {$table_support_tickets} ticket, {$table_support_messages} message, {$table_support_message_attachments} attch \n\t\t\tWHERE ticket.ticket_id = message.ticket_id AND attch.message_id = message.message_id AND ticket.ticket_id = {$ticket_id}"; $rs = Database::query($sql); $row_users = Database::fetch_array($rs, 'ASSOC'); $user_request_id = $row_users['request_user']; if (intval($user_request_id) != $user_id) { api_not_allowed(); } } $file_url = $_GET['file']; $file_url = str_replace('///', '&', $file_url); $file_url = str_replace(' ', '+', $file_url); $file_url = str_replace('/..', '', $file_url); $file_url = Database::escape_string($file_url); $title = $_GET['title']; $path_attachment = api_get_path(SYS_PATH); $path_message_attach = $path_attachment . 'tck_messageattch/'; $full_file_name = $path_message_attach . $file_url; if (Security::check_abs_path($full_file_name, $path_message_attach)) { DocumentManager::file_send_for_download($full_file_name, TRUE, $title); } exit;
/** * Quite similar to display_complete_report(), returns an HTML string * that can be used in a csv file * @todo consider merging this function with display_complete_report * @return string The contents of a csv file * @author Patrick Cool <*****@*****.**>, Ghent University * @version February 2007 */ static function export_complete_report_xls($survey_data, $filename, $user_id = 0) { $spreadsheet = new PHPExcel(); $spreadsheet->setActiveSheetIndex(0); $worksheet = $spreadsheet->getActiveSheet(); $line = 0; $column = 1; // Skip the first column (row titles) // Show extra fields blank space (enough for extra fields on next line) //if (!empty($_REQUEST['fields_filter'])) { // Show user fields section with a big th colspan that spans over all fields $extra_user_fields = UserManager::get_extra_fields(0, 0, 5, 'ASC', false, true); $num = count($extra_user_fields); for ($i = 0; $i < $num; $i++) { $worksheet->SetCellValueByColumnAndRow($line, $column, ''); $column++; } $display_extra_user_fields = true; //} // Database table definitions $table_survey_question = Database::get_course_table(TABLE_SURVEY_QUESTION); $table_survey_question_option = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION); $table_survey_answer = Database::get_course_table(TABLE_SURVEY_ANSWER); $course_id = api_get_course_int_id(); // First line (questions) $sql = "SELECT\n questions.question_id,\n questions.type,\n questions.survey_question,\n count(options.question_option_id) as number_of_options\n\t\t\t\tFROM {$table_survey_question} questions\n\t\t\t\tLEFT JOIN {$table_survey_question_option} options\n ON questions.question_id = options.question_id AND options.c_id = {$course_id}\n\t\t\t\tWHERE\n\t\t\t\t questions.survey_id = '" . intval($_GET['survey_id']) . "' AND\n\t\t\t\t questions.c_id = {$course_id}\n\t\t\t\tGROUP BY questions.question_id\n\t\t\t\tORDER BY questions.sort ASC"; $result = Database::query($sql); while ($row = Database::fetch_array($result)) { // We show the questions if // 1. there is no question filter and the export button has not been clicked // 2. there is a quesiton filter but the question is selected for display if (!$_POST['submit_question_filter'] || is_array($_POST['questions_filter']) && in_array($row['question_id'], $_POST['questions_filter'])) { // We do not show comment and pagebreak question types if ($row['type'] != 'comment' && $row['type'] != 'pagebreak') { if ($row['number_of_options'] == 0 && $row['type'] == 'open') { $worksheet->SetCellValueByColumnAndRow($line, $column, api_html_entity_decode(strip_tags($row['survey_question']), ENT_QUOTES)); $column++; } else { for ($ii = 0; $ii < $row['number_of_options']; $ii++) { $worksheet->SetCellValueByColumnAndRow($line, $column, api_html_entity_decode(strip_tags($row['survey_question']), ENT_QUOTES)); $column++; } } } } } $line++; $column = 1; // Show extra field values if ($display_extra_user_fields) { // Show the fields names for user fields foreach ($extra_user_fields as &$field) { $worksheet->SetCellValueByColumnAndRow($line, $column, api_html_entity_decode(strip_tags($field[3]), ENT_QUOTES)); $column++; } } // Getting all the questions and options (second line) $sql = "SELECT\n survey_question.question_id, survey_question.survey_id, survey_question.survey_question, survey_question.display, survey_question.sort, survey_question.type,\n survey_question_option.question_option_id, survey_question_option.option_text, survey_question_option.sort as option_sort\n\t\t\t\tFROM {$table_survey_question} survey_question\n\t\t\t\tLEFT JOIN {$table_survey_question_option} survey_question_option\n\t\t\t\tON survey_question.question_id = survey_question_option.question_id AND survey_question_option.c_id = {$course_id}\n\t\t\t\tWHERE survey_question.survey_id = '" . intval($_GET['survey_id']) . "' AND\n\t\t\t\tsurvey_question.c_id = {$course_id}\n\t\t\t\tORDER BY survey_question.sort ASC, survey_question_option.sort ASC"; $result = Database::query($sql); $possible_answers = array(); $possible_answers_type = array(); while ($row = Database::fetch_array($result)) { // We show the options if // 1. there is no question filter and the export button has not been clicked // 2. there is a quesiton filter but the question is selected for display if (!$_POST['submit_question_filter'] || is_array($_POST['questions_filter']) && in_array($row['question_id'], $_POST['questions_filter'])) { // We do not show comment and pagebreak question types if ($row['type'] != 'comment' && $row['type'] != 'pagebreak') { $worksheet->SetCellValueByColumnAndRow($line, $column, api_html_entity_decode(strip_tags($row['option_text']), ENT_QUOTES)); $possible_answers[$row['question_id']][$row['question_option_id']] = $row['question_option_id']; $possible_answers_type[$row['question_id']] = $row['type']; $column++; } } } // Getting all the answers of the users $line++; $column = 0; $old_user = ''; $answers_of_user = array(); $sql = "SELECT * FROM {$table_survey_answer}\n WHERE c_id = {$course_id} AND survey_id='" . intval($_GET['survey_id']) . "' "; if ($user_id != 0) { $sql .= "AND user='******' "; } $sql .= "ORDER BY user ASC"; $open_question_iterator = 1; $result = Database::query($sql); while ($row = Database::fetch_array($result)) { if ($old_user != $row['user'] && $old_user != '') { $return = SurveyUtil::export_complete_report_row_xls($survey_data, $possible_answers, $answers_of_user, $old_user, true); foreach ($return as $elem) { $worksheet->SetCellValueByColumnAndRow($line, $column, $elem); $column++; } $answers_of_user = array(); $line++; $column = 0; } if ($possible_answers_type[$row['question_id']] == 'open') { $temp_id = 'open' . $open_question_iterator; $answers_of_user[$row['question_id']][$temp_id] = $row; $open_question_iterator++; } else { $answers_of_user[$row['question_id']][$row['option_id']] = $row; } $old_user = $row['user']; } $return = SurveyUtil::export_complete_report_row_xls($survey_data, $possible_answers, $answers_of_user, $old_user, true); // this is to display the last user foreach ($return as $elem) { $worksheet->SetCellValueByColumnAndRow($line, $column, $elem); $column++; } $file = api_get_path(SYS_ARCHIVE_PATH) . api_replace_dangerous_char($filename); $writer = new PHPExcel_Writer_Excel2007($spreadsheet); $writer->save($file); DocumentManager::file_send_for_download($file, true, $filename); return null; }
public function export_csv() { $course = Request::get_course_key(); $items = Notebook::repository()->find_by_course($course); $writer = CsvWriter::create(); $writer->add($items); $path = $writer->get_path(); \DocumentManager::file_send_for_download($path, true, get_lang('Notebook') . '.csv'); }
/** * This function downloads all the files of the input array into one zip * @param array $fileList containing all the ids of the files that have to be downloaded. * @author Patrick Cool <*****@*****.**>, Ghent University * @todo consider removing the check if the user has received or sent this file (zip download of a folder already sufficiently checks for this). * @todo integrate some cleanup function that removes zip files that are older than 2 days * * @author Patrick Cool <*****@*****.**>, Ghent University * @author Julio Montoya Addin c_id support * @version march 2006 */ function zip_download($fileList) { $_course = api_get_course_info(); $dropbox_cnf = getDropboxConf(); $course_id = api_get_course_int_id(); $fileList = array_map('intval', $fileList); // note: we also have to add the check if the user has received or sent this file. $sql = "SELECT DISTINCT file.filename, file.title, file.author, file.description\n FROM " . $dropbox_cnf['tbl_file'] . " file\n INNER JOIN " . $dropbox_cnf['tbl_person'] . " person\n ON (person.file_id=file.id AND file.c_id = {$course_id} AND person.c_id = {$course_id})\n INNER JOIN " . $dropbox_cnf['tbl_post'] . " post\n ON (post.file_id = file.id AND post.c_id = {$course_id} AND file.c_id = {$course_id})\n WHERE\n file.id IN (" . implode(', ', $fileList) . ") AND\n file.id = person.file_id AND\n (\n person.user_id = '" . api_get_user_id() . "' OR\n post.dest_user_id = '" . api_get_user_id() . "'\n ) "; $result = Database::query($sql); $files = array(); while ($row = Database::fetch_array($result)) { $files[$row['filename']] = array('filename' => $row['filename'], 'title' => $row['title'], 'author' => $row['author'], 'description' => $row['description']); } // Step 3: create the zip file and add all the files to it $temp_zip_file = api_get_path(SYS_ARCHIVE_PATH) . api_get_unique_id() . ".zip"; Session::write('dropbox_files_to_download', $files); $zip = new PclZip($temp_zip_file); foreach ($files as $value) { $zip->add(api_get_path(SYS_COURSE_PATH) . $_course['path'] . '/dropbox/' . $value['filename'], PCLZIP_OPT_REMOVE_ALL_PATH, PCLZIP_CB_PRE_ADD, 'my_pre_add_callback'); } Session::erase('dropbox_files_to_download'); $name = 'dropbox-' . api_get_utc_datetime() . '.zip'; DocumentManager::file_send_for_download($temp_zip_file, true, $name); @unlink($temp_zip_file); exit; }
public function export_csv() { $c_id = Request::get_c_id(); $session_id = Request::get_session_id(); $course = (object) array(); $course->c_id = $c_id; $course->session_id = $session_id; $descriptions = CourseDescription::repository()->find_by_course($course); $writer = new CsvWriter(); $writer->add($descriptions); $path = $writer->get_path(); \DocumentManager::file_send_for_download($path, true, get_lang('CourseDescriptions') . '.csv'); }
<?php /* For licensing terms, see /license.txt */ /** * Download script for course info * @package chamilo.course_info */ ////require_once '../inc/global.inc.php'; $this_section = SECTION_COURSES; $_cid = false; if (isset($_GET['session']) && $_GET['session']) { $archive_path = api_get_path(SYS_ARCHIVE_PATH) . 'temp/'; $_cid = true; $is_courseAdmin = true; } else { $archive_path = api_get_path(SYS_ARCHIVE_PATH); } $archive_file = isset($_GET['archive']) ? $_GET['archive'] : null; $archive_file = str_replace(array('..', '/', '\\'), '', $archive_file); list($extension) = getextension($archive_file); if (empty($extension) || !file_exists($archive_path . $archive_file)) { api_not_allowed(true); } if (Security::check_abs_path($archive_path . $archive_file, $archive_path)) { DocumentManager::file_send_for_download($archive_path . $archive_file, true, $archive_file); exit; } else { api_not_allowed(true); }
/** * // TODO: The output encoding should be equal to the system encoding. * * Exports the learning path as a SCORM package. This is the main function that * gathers the content, transforms it, writes the imsmanifest.xml file, zips the * whole thing and returns the zip. * * This method needs to be called in PHP5, as it will fail with non-adequate * XML package (like the ones for PHP4), and it is *not* a static method, so * you need to call it on a learnpath object. * @TODO The method might be redefined later on in the scorm class itself to avoid * creating a SCORM structure if there is one already. However, if the initial SCORM * path has been modified, it should use the generic method here below. * @TODO link this function with the export_lp() function in the same class * @param string Optional name of zip file. If none, title of learnpath is * domesticated and trailed with ".zip" * @return string Returns the zip package string, or null if error */ public function scorm_export() { $_course = api_get_course_info(); $course_id = $_course['real_id']; // Remove memory and time limits as much as possible as this might be a long process... if (function_exists('ini_set')) { api_set_memory_limit('128M'); ini_set('max_execution_time', 600); } // Create the zip handler (this will remain available throughout the method). $archive_path = api_get_path(SYS_ARCHIVE_PATH); $sys_course_path = api_get_path(SYS_COURSE_PATH); $temp_dir_short = uniqid(); $temp_zip_dir = $archive_path . '/' . $temp_dir_short; $temp_zip_file = $temp_zip_dir . '/' . md5(time()) . '.zip'; $zip_folder = new PclZip($temp_zip_file); $current_course_path = api_get_path(SYS_COURSE_PATH) . api_get_course_path(); $root_path = $main_path = api_get_path(SYS_PATH); $files_cleanup = array(); // Place to temporarily stash the zip file. // create the temp dir if it doesn't exist // or do a cleanup before creating the zip file. if (!is_dir($temp_zip_dir)) { mkdir($temp_zip_dir, api_get_permissions_for_new_directories()); } else { // Cleanup: Check the temp dir for old files and delete them. $handle = opendir($temp_zip_dir); while (false !== ($file = readdir($handle))) { if ($file != '.' && $file != '..') { unlink("{$temp_zip_dir}/{$file}"); } } closedir($handle); } $zip_files = $zip_files_abs = $zip_files_dist = array(); if (is_dir($current_course_path . '/scorm/' . $this->path) && is_file($current_course_path . '/scorm/' . $this->path . '/imsmanifest.xml')) { // Remove the possible . at the end of the path. $dest_path_to_lp = substr($this->path, -1) == '.' ? substr($this->path, 0, -1) : $this->path; $dest_path_to_scorm_folder = str_replace('//', '/', $temp_zip_dir . '/scorm/' . $dest_path_to_lp); mkdir($dest_path_to_scorm_folder, api_get_permissions_for_new_directories(), true); $zip_files_dist = copyr($current_course_path . '/scorm/' . $this->path, $dest_path_to_scorm_folder, array('imsmanifest'), $zip_files); } // Build a dummy imsmanifest structure. // Do not add to the zip yet (we still need it). // This structure is developed following regulations for SCORM 1.2 packaging in the SCORM 1.2 Content // Aggregation Model official document, section "2.3 Content Packaging". // We are going to build a UTF-8 encoded manifest. Later we will recode it to the desired (and supported) encoding. $xmldoc = new DOMDocument('1.0'); $root = $xmldoc->createElement('manifest'); $root->setAttribute('identifier', 'SingleCourseManifest'); $root->setAttribute('version', '1.1'); $root->setAttribute('xmlns', 'http://www.imsproject.org/xsd/imscp_rootv1p1p2'); $root->setAttribute('xmlns:adlcp', 'http://www.adlnet.org/xsd/adlcp_rootv1p2'); $root->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); $root->setAttribute('xsi:schemaLocation', 'http://www.imsproject.org/xsd/imscp_rootv1p1p2 imscp_rootv1p1p2.xsd http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 imsmd_rootv1p2p1.xsd http://www.adlnet.org/xsd/adlcp_rootv1p2 adlcp_rootv1p2.xsd'); // Build mandatory sub-root container elements. $metadata = $xmldoc->createElement('metadata'); $md_schema = $xmldoc->createElement('schema', 'ADL SCORM'); $metadata->appendChild($md_schema); $md_schemaversion = $xmldoc->createElement('schemaversion', '1.2'); $metadata->appendChild($md_schemaversion); $root->appendChild($metadata); $organizations = $xmldoc->createElement('organizations'); $resources = $xmldoc->createElement('resources'); // Build the only organization we will use in building our learnpaths. $organizations->setAttribute('default', 'chamilo_scorm_export'); $organization = $xmldoc->createElement('organization'); $organization->setAttribute('identifier', 'chamilo_scorm_export'); // To set the title of the SCORM entity (=organization), we take the name given // in Chamilo and convert it to HTML entities using the Chamilo charset (not the // learning path charset) as it is the encoding that defines how it is stored // in the database. Then we convert it to HTML entities again as the "&" character // alone is not authorized in XML (must be &). // The title is then decoded twice when extracting (see scorm::parse_manifest). $org_title = $xmldoc->createElement('title', api_utf8_encode($this->get_name())); $organization->appendChild($org_title); $folder_name = 'document'; // Removes the learning_path/scorm_folder path when exporting see #4841 $path_to_remove = null; $result = $this->generate_lp_folder($_course); if (isset($result['dir']) && strpos($result['dir'], 'learning_path')) { $path_to_remove = 'document' . $result['dir']; $path_to_replace = $folder_name . '/'; } //Fixes chamilo scorm exports if ($this->ref == 'chamilo_scorm_export') { $path_to_remove = 'scorm/' . $this->path . '/document/'; } // For each element, add it to the imsmanifest structure, then add it to the zip. // Always call the learnpathItem->scorm_export() method to change it to the SCORM format. $link_updates = array(); $links_to_create = array(); foreach ($this->items as $index => $item) { if (!in_array($item->type, array(TOOL_QUIZ, TOOL_FORUM, TOOL_THREAD, TOOL_LINK, TOOL_STUDENTPUBLICATION))) { // Get included documents from this item. if ($item->type == 'sco') { $inc_docs = $item->get_resources_from_source(null, api_get_path(SYS_COURSE_PATH) . api_get_course_path() . '/' . 'scorm/' . $this->path . '/' . $item->get_path()); } else { $inc_docs = $item->get_resources_from_source(); } // Give a child element <item> to the <organization> element. $my_item_id = $item->get_id(); $my_item = $xmldoc->createElement('item'); $my_item->setAttribute('identifier', 'ITEM_' . $my_item_id); $my_item->setAttribute('identifierref', 'RESOURCE_' . $my_item_id); $my_item->setAttribute('isvisible', 'true'); // Give a child element <title> to the <item> element. $my_title = $xmldoc->createElement('title', htmlspecialchars(api_utf8_encode($item->get_title()), ENT_QUOTES, 'UTF-8')); $my_item->appendChild($my_title); // Give a child element <adlcp:prerequisites> to the <item> element. $my_prereqs = $xmldoc->createElement('adlcp:prerequisites', $this->get_scorm_prereq_string($my_item_id)); $my_prereqs->setAttribute('type', 'aicc_script'); $my_item->appendChild($my_prereqs); // Give a child element <adlcp:maxtimeallowed> to the <item> element - not yet supported. //$xmldoc->createElement('adlcp:maxtimeallowed',''); // Give a child element <adlcp:timelimitaction> to the <item> element - not yet supported. //$xmldoc->createElement('adlcp:timelimitaction',''); // Give a child element <adlcp:datafromlms> to the <item> element - not yet supported. //$xmldoc->createElement('adlcp:datafromlms',''); // Give a child element <adlcp:masteryscore> to the <item> element. $my_masteryscore = $xmldoc->createElement('adlcp:masteryscore', $item->get_mastery_score()); $my_item->appendChild($my_masteryscore); // Attach this item to the organization element or hits parent if there is one. if (!empty($item->parent) && $item->parent != 0) { $children = $organization->childNodes; $possible_parent =& $this->get_scorm_xml_node($children, 'ITEM_' . $item->parent); if (is_object($possible_parent)) { $possible_parent->appendChild($my_item); } else { if ($this->debug > 0) { error_log('Parent ITEM_' . $item->parent . ' of item ITEM_' . $my_item_id . ' not found'); } } } else { if ($this->debug > 0) { error_log('No parent'); } $organization->appendChild($my_item); } // Get the path of the file(s) from the course directory root. $my_file_path = $item->get_file_path('scorm/' . $this->path . '/'); if (!empty($path_to_remove)) { //From docs $my_xml_file_path = str_replace($path_to_remove, $path_to_replace, $my_file_path); //From quiz if ($this->ref == 'chamilo_scorm_export') { $path_to_remove = 'scorm/' . $this->path . '/'; $my_xml_file_path = str_replace($path_to_remove, '', $my_file_path); } } else { $my_xml_file_path = $my_file_path; } $my_sub_dir = dirname($my_file_path); $my_sub_dir = str_replace('\\', '/', $my_sub_dir); $my_xml_sub_dir = $my_sub_dir; // Give a <resource> child to the <resources> element $my_resource = $xmldoc->createElement('resource'); $my_resource->setAttribute('identifier', 'RESOURCE_' . $item->get_id()); $my_resource->setAttribute('type', 'webcontent'); $my_resource->setAttribute('href', $my_xml_file_path); // adlcp:scormtype can be either 'sco' or 'asset'. if ($item->type == 'sco') { $my_resource->setAttribute('adlcp:scormtype', 'sco'); } else { $my_resource->setAttribute('adlcp:scormtype', 'asset'); } // xml:base is the base directory to find the files declared in this resource. $my_resource->setAttribute('xml:base', ''); // Give a <file> child to the <resource> element. $my_file = $xmldoc->createElement('file'); $my_file->setAttribute('href', $my_xml_file_path); $my_resource->appendChild($my_file); // Dependency to other files - not yet supported. $i = 1; foreach ($inc_docs as $doc_info) { if (count($doc_info) < 1 || empty($doc_info[0])) { continue; } $my_dep = $xmldoc->createElement('resource'); $res_id = 'RESOURCE_' . $item->get_id() . '_' . $i; $my_dep->setAttribute('identifier', $res_id); $my_dep->setAttribute('type', 'webcontent'); $my_dep->setAttribute('adlcp:scormtype', 'asset'); $my_dep_file = $xmldoc->createElement('file'); // Check type of URL. //error_log(__LINE__.'Now dealing with '.$doc_info[0].' of type '.$doc_info[1].'-'.$doc_info[2], 0); if ($doc_info[1] == 'remote') { // Remote file. Save url as is. $my_dep_file->setAttribute('href', $doc_info[0]); $my_dep->setAttribute('xml:base', ''); } elseif ($doc_info[1] == 'local') { switch ($doc_info[2]) { case 'url': // Local URL - save path as url for now, don't zip file. $abs_path = api_get_path(SYS_PATH) . str_replace(api_get_path(WEB_PATH), '', $doc_info[0]); $current_dir = dirname($abs_path); $current_dir = str_replace('\\', '/', $current_dir); $file_path = realpath($abs_path); $file_path = str_replace('\\', '/', $file_path); $my_dep_file->setAttribute('href', $file_path); $my_dep->setAttribute('xml:base', ''); if (strstr($file_path, $main_path) !== false) { // The calculated real path is really inside Chamilo's root path. // Reduce file path to what's under the DocumentRoot. $file_path = substr($file_path, strlen($root_path) - 1); //echo $file_path;echo '<br /><br />'; //error_log(__LINE__.'Reduced url path: '.$file_path, 0); $zip_files_abs[] = $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path); $my_dep_file->setAttribute('href', $file_path); $my_dep->setAttribute('xml:base', ''); } elseif (empty($file_path)) { /*$document_root = substr(api_get_path(SYS_PATH), 0, strpos(api_get_path(SYS_PATH), api_get_path(REL_PATH))); if (strpos($document_root, -1) == '/') { $document_root = substr(0, -1, $document_root); }*/ $file_path = $_SERVER['DOCUMENT_ROOT'] . $abs_path; $file_path = str_replace('//', '/', $file_path); if (file_exists($file_path)) { $file_path = substr($file_path, strlen($current_dir)); // We get the relative path. $zip_files[] = $my_sub_dir . '/' . $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path); $my_dep_file->setAttribute('href', $file_path); $my_dep->setAttribute('xml:base', ''); } } break; case 'abs': // Absolute path from DocumentRoot. Save file and leave path as is in the zip. $my_dep_file->setAttribute('href', $doc_info[0]); $my_dep->setAttribute('xml:base', ''); // The next lines fix a bug when using the "subdir" mode of Chamilo, whereas // an image path would be constructed as /var/www/subdir/subdir/img/foo.bar $abs_img_path_without_subdir = $doc_info[0]; $relp = api_get_path(REL_PATH); // The url-append config param. $pos = strpos($abs_img_path_without_subdir, $relp); if ($pos === 0) { $abs_img_path_without_subdir = '/' . substr($abs_img_path_without_subdir, strlen($relp)); } $file_path = realpath(api_get_path(SYS_PATH) . $abs_img_path_without_subdir); $file_path = str_replace('\\', '/', $file_path); $file_path = str_replace('//', '/', $file_path); // Prepare the current directory path (until just under 'document') with a trailing slash. $cur_path = substr($current_course_path, -1) == '/' ? $current_course_path : $current_course_path . '/'; // Check if the current document is in that path. if (strstr($file_path, $cur_path) !== false) { // The document is in that path, now get the relative path // to the containing document. $orig_file_path = dirname($cur_path . $my_file_path) . '/'; $orig_file_path = str_replace('\\', '/', $orig_file_path); $relative_path = ''; if (strstr($file_path, $cur_path) !== false) { //$relative_path = substr($file_path, strlen($orig_file_path)); $relative_path = str_replace($cur_path, '', $file_path); $file_path = substr($file_path, strlen($cur_path)); } else { // This case is still a problem as it's difficult to calculate a relative path easily // might still generate wrong links. //$file_path = substr($file_path,strlen($cur_path)); // Calculate the directory path to the current file (without trailing slash). $my_relative_path = dirname($file_path); $my_relative_path = str_replace('\\', '/', $my_relative_path); $my_relative_file = basename($file_path); // Calculate the directory path to the containing file (without trailing slash). $my_orig_file_path = substr($orig_file_path, 0, -1); $dotdot = ''; $subdir = ''; while (strstr($my_relative_path, $my_orig_file_path) === false && strlen($my_orig_file_path) > 1 && strlen($my_relative_path) > 1) { $my_relative_path2 = dirname($my_relative_path); $my_relative_path2 = str_replace('\\', '/', $my_relative_path2); $my_orig_file_path = dirname($my_orig_file_path); $my_orig_file_path = str_replace('\\', '/', $my_orig_file_path); $subdir = substr($my_relative_path, strlen($my_relative_path2) + 1) . '/' . $subdir; $dotdot += '../'; $my_relative_path = $my_relative_path2; } $relative_path = $dotdot . $subdir . $my_relative_file; } // Put the current document in the zip (this array is the array // that will manage documents already in the course folder - relative). $zip_files[] = $file_path; // Update the links to the current document in the containing document (make them relative). $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $relative_path); $my_dep_file->setAttribute('href', $file_path); $my_dep->setAttribute('xml:base', ''); } elseif (strstr($file_path, $main_path) !== false) { // The calculated real path is really inside Chamilo's root path. // Reduce file path to what's under the DocumentRoot. $file_path = substr($file_path, strlen($root_path)); //echo $file_path;echo '<br /><br />'; //error_log('Reduced path: '.$file_path, 0); $zip_files_abs[] = $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); } elseif (empty($file_path)) { /*$document_root = substr(api_get_path(SYS_PATH), 0, strpos(api_get_path(SYS_PATH), api_get_path(REL_PATH))); if(strpos($document_root,-1) == '/') { $document_root = substr(0, -1, $document_root); }*/ $file_path = $_SERVER['DOCUMENT_ROOT'] . $doc_info[0]; $file_path = str_replace('//', '/', $file_path); $abs_path = api_get_path(SYS_PATH) . str_replace(api_get_path(WEB_PATH), '', $doc_info[0]); $current_dir = dirname($abs_path); $current_dir = str_replace('\\', '/', $current_dir); if (file_exists($file_path)) { $file_path = substr($file_path, strlen($current_dir)); // We get the relative path. $zip_files[] = $my_sub_dir . '/' . $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); } } break; case 'rel': // Path relative to the current document. // Save xml:base as current document's directory and save file in zip as subdir.file_path if (substr($doc_info[0], 0, 2) == '..') { // Relative path going up. $current_dir = dirname($current_course_path . '/' . $item->get_file_path()) . '/'; $current_dir = str_replace('\\', '/', $current_dir); $file_path = realpath($current_dir . $doc_info[0]); $file_path = str_replace('\\', '/', $file_path); //error_log($file_path.' <-> '.$main_path,0); if (strstr($file_path, $main_path) !== false) { // The calculated real path is really inside Chamilo's root path. // Reduce file path to what's under the DocumentRoot. $file_path = substr($file_path, strlen($root_path)); //error_log('Reduced path: '.$file_path, 0); $zip_files_abs[] = $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); } } else { $zip_files[] = $my_sub_dir . '/' . $doc_info[0]; $my_dep_file->setAttribute('href', $doc_info[0]); $my_dep->setAttribute('xml:base', $my_xml_sub_dir); } break; default: $my_dep_file->setAttribute('href', $doc_info[0]); $my_dep->setAttribute('xml:base', ''); break; } } $my_dep->appendChild($my_dep_file); $resources->appendChild($my_dep); $dependency = $xmldoc->createElement('dependency'); $dependency->setAttribute('identifierref', $res_id); $my_resource->appendChild($dependency); $i++; } $resources->appendChild($my_resource); $zip_files[] = $my_file_path; } else { // If the item is a quiz or a link or whatever non-exportable, we include a step indicating it. switch ($item->type) { case TOOL_LINK: $my_item = $xmldoc->createElement('item'); $my_item->setAttribute('identifier', 'ITEM_' . $item->get_id()); $my_item->setAttribute('identifierref', 'RESOURCE_' . $item->get_id()); $my_item->setAttribute('isvisible', 'true'); // Give a child element <title> to the <item> element. $my_title = $xmldoc->createElement('title', htmlspecialchars(api_utf8_encode($item->get_title()), ENT_QUOTES, 'UTF-8')); $my_item->appendChild($my_title); // Give a child element <adlcp:prerequisites> to the <item> element. $my_prereqs = $xmldoc->createElement('adlcp:prerequisites', $item->get_prereq_string()); $my_prereqs->setAttribute('type', 'aicc_script'); $my_item->appendChild($my_prereqs); // Give a child element <adlcp:maxtimeallowed> to the <item> element - not yet supported. //$xmldoc->createElement('adlcp:maxtimeallowed', ''); // Give a child element <adlcp:timelimitaction> to the <item> element - not yet supported. //$xmldoc->createElement('adlcp:timelimitaction', ''); // Give a child element <adlcp:datafromlms> to the <item> element - not yet supported. //$xmldoc->createElement('adlcp:datafromlms', ''); // Give a child element <adlcp:masteryscore> to the <item> element. $my_masteryscore = $xmldoc->createElement('adlcp:masteryscore', $item->get_mastery_score()); $my_item->appendChild($my_masteryscore); // Attach this item to the organization element or its parent if there is one. if (!empty($item->parent) && $item->parent != 0) { $children = $organization->childNodes; for ($i = 0; $i < $children->length; $i++) { $item_temp = $children->item($i); if ($item_temp->nodeName == 'item') { if ($item_temp->getAttribute('identifier') == 'ITEM_' . $item->parent) { $item_temp->appendChild($my_item); } } } } else { $organization->appendChild($my_item); } $my_file_path = 'link_' . $item->get_id() . '.html'; $sql = 'SELECT url, title FROM ' . Database::get_course_table(TABLE_LINK) . ' WHERE c_id = ' . $course_id . ' AND id=' . $item->path; $rs = Database::query($sql); if ($link = Database::fetch_array($rs)) { $url = $link['url']; $title = stripslashes($link['title']); $links_to_create[$my_file_path] = array('title' => $title, 'url' => $url); $my_xml_file_path = $my_file_path; $my_sub_dir = dirname($my_file_path); $my_sub_dir = str_replace('\\', '/', $my_sub_dir); $my_xml_sub_dir = $my_sub_dir; // Give a <resource> child to the <resources> element. $my_resource = $xmldoc->createElement('resource'); $my_resource->setAttribute('identifier', 'RESOURCE_' . $item->get_id()); $my_resource->setAttribute('type', 'webcontent'); $my_resource->setAttribute('href', $my_xml_file_path); // adlcp:scormtype can be either 'sco' or 'asset'. $my_resource->setAttribute('adlcp:scormtype', 'asset'); // xml:base is the base directory to find the files declared in this resource. $my_resource->setAttribute('xml:base', ''); // give a <file> child to the <resource> element. $my_file = $xmldoc->createElement('file'); $my_file->setAttribute('href', $my_xml_file_path); $my_resource->appendChild($my_file); $resources->appendChild($my_resource); } break; case TOOL_QUIZ: $exe_id = $item->path; // Should be using ref when everything will be cleaned up in this regard. $exe = new Exercise(); $exe->read($exe_id); $my_item = $xmldoc->createElement('item'); $my_item->setAttribute('identifier', 'ITEM_' . $item->get_id()); $my_item->setAttribute('identifierref', 'RESOURCE_' . $item->get_id()); $my_item->setAttribute('isvisible', 'true'); // Give a child element <title> to the <item> element. $my_title = $xmldoc->createElement('title', htmlspecialchars(api_utf8_encode($item->get_title()), ENT_QUOTES, 'UTF-8')); $my_item->appendChild($my_title); $my_max_score = $xmldoc->createElement('max_score', $item->get_max()); //$my_item->appendChild($my_max_score); // Give a child element <adlcp:prerequisites> to the <item> element. $my_prereqs = $xmldoc->createElement('adlcp:prerequisites', $item->get_prereq_string()); $my_prereqs->setAttribute('type', 'aicc_script'); $my_item->appendChild($my_prereqs); // Give a child element <adlcp:masteryscore> to the <item> element. $my_masteryscore = $xmldoc->createElement('adlcp:masteryscore', $item->get_mastery_score()); $my_item->appendChild($my_masteryscore); // Attach this item to the organization element or hits parent if there is one. if (!empty($item->parent) && $item->parent != 0) { $children = $organization->childNodes; for ($i = 0; $i < $children->length; $i++) { $item_temp = $children->item($i); if ($item_temp->nodeName == 'item') { if ($item_temp->getAttribute('identifier') == 'ITEM_' . $item->parent) { $item_temp->appendChild($my_item); } } } } else { $organization->appendChild($my_item); } // Get the path of the file(s) from the course directory root //$my_file_path = $item->get_file_path('scorm/'.$this->path.'/'); $my_file_path = 'quiz_' . $item->get_id() . '.html'; // Write the contents of the exported exercise into a (big) html file // to later pack it into the exported SCORM. The file will be removed afterwards. $contents = ScormSection::export_exercise_to_scorm($exe_id, true); $tmp_file_path = $archive_path . $temp_dir_short . '/' . $my_file_path; $res = file_put_contents($tmp_file_path, $contents); if ($res === false) { error_log('Could not write into file ' . $tmp_file_path . ' ' . __FILE__ . ' ' . __LINE__, 0); } $files_cleanup[] = $tmp_file_path; //error_log($tmp_path); die(); //$my_xml_file_path = api_htmlentities(api_utf8_encode($my_file_path), ENT_QUOTES, 'UTF-8'); $my_xml_file_path = $my_file_path; $my_sub_dir = dirname($my_file_path); $my_sub_dir = str_replace('\\', '/', $my_sub_dir); //$my_xml_sub_dir = api_htmlentities(api_utf8_encode($my_sub_dir), ENT_QUOTES, 'UTF-8'); $my_xml_sub_dir = $my_sub_dir; // Give a <resource> child to the <resources> element. $my_resource = $xmldoc->createElement('resource'); $my_resource->setAttribute('identifier', 'RESOURCE_' . $item->get_id()); $my_resource->setAttribute('type', 'webcontent'); $my_resource->setAttribute('href', $my_xml_file_path); // adlcp:scormtype can be either 'sco' or 'asset'. $my_resource->setAttribute('adlcp:scormtype', 'sco'); // xml:base is the base directory to find the files declared in this resource. $my_resource->setAttribute('xml:base', ''); // Give a <file> child to the <resource> element. $my_file = $xmldoc->createElement('file'); $my_file->setAttribute('href', $my_xml_file_path); $my_resource->appendChild($my_file); // Get included docs. $inc_docs = $item->get_resources_from_source(null, $tmp_file_path); // Dependency to other files - not yet supported. $i = 1; foreach ($inc_docs as $doc_info) { if (count($doc_info) < 1 || empty($doc_info[0])) { continue; } $my_dep = $xmldoc->createElement('resource'); $res_id = 'RESOURCE_' . $item->get_id() . '_' . $i; $my_dep->setAttribute('identifier', $res_id); $my_dep->setAttribute('type', 'webcontent'); $my_dep->setAttribute('adlcp:scormtype', 'asset'); $my_dep_file = $xmldoc->createElement('file'); // Check type of URL. if ($doc_info[1] == 'remote') { // Remote file. Save url as is. $my_dep_file->setAttribute('href', $doc_info[0]); $my_dep->setAttribute('xml:base', ''); } elseif ($doc_info[1] == 'local') { switch ($doc_info[2]) { case 'url': // Local URL - save path as url for now, don't zip file. // Save file but as local file (retrieve from URL). $abs_path = api_get_path(SYS_PATH) . str_replace(api_get_path(WEB_PATH), '', $doc_info[0]); $current_dir = dirname($abs_path); $current_dir = str_replace('\\', '/', $current_dir); $file_path = realpath($abs_path); $file_path = str_replace('\\', '/', $file_path); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); if (strstr($file_path, $main_path) !== false) { // The calculated real path is really inside the chamilo root path. // Reduce file path to what's under the DocumentRoot. $file_path = substr($file_path, strlen($root_path)); //echo $file_path;echo '<br /><br />'; //error_log('Reduced path: '.$file_path, 0); $zip_files_abs[] = $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => 'document/' . $file_path); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); } elseif (empty($file_path)) { /*$document_root = substr(api_get_path(SYS_PATH), 0, strpos(api_get_path(SYS_PATH),api_get_path(REL_PATH))); if (strpos($document_root,-1) == '/') { $document_root = substr(0, -1, $document_root); }*/ $file_path = $_SERVER['DOCUMENT_ROOT'] . $abs_path; $file_path = str_replace('//', '/', $file_path); if (file_exists($file_path)) { $file_path = substr($file_path, strlen($current_dir)); // We get the relative path. $zip_files[] = $my_sub_dir . '/' . $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => 'document/' . $file_path); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); } } break; case 'abs': // Absolute path from DocumentRoot. Save file and leave path as is in the zip. $current_dir = dirname($current_course_path . '/' . $item->get_file_path()) . '/'; $current_dir = str_replace('\\', '/', $current_dir); $file_path = realpath($doc_info[0]); $file_path = str_replace('\\', '/', $file_path); $my_dep_file->setAttribute('href', $file_path); $my_dep->setAttribute('xml:base', ''); if (strstr($file_path, $main_path) !== false) { // The calculated real path is really inside the chamilo root path. // Reduce file path to what's under the DocumentRoot. $file_path = substr($file_path, strlen($root_path)); //echo $file_path;echo '<br /><br />'; //error_log('Reduced path: '.$file_path, 0); $zip_files_abs[] = $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); } elseif (empty($file_path)) { /*$document_root = substr(api_get_path(SYS_PATH), 0, strpos(api_get_path(SYS_PATH), api_get_path(REL_PATH))); if (strpos($document_root,-1) == '/') { $document_root = substr(0, -1, $document_root); }*/ $file_path = $_SERVER['DOCUMENT_ROOT'] . $doc_info[0]; $file_path = str_replace('//', '/', $file_path); if (file_exists($file_path)) { $file_path = substr($file_path, strlen($current_dir)); // We get the relative path. $zip_files[] = $my_sub_dir . '/' . $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); } } break; case 'rel': // Path relative to the current document. Save xml:base as current document's directory and save file in zip as subdir.file_path if (substr($doc_info[0], 0, 2) == '..') { // Relative path going up. $current_dir = dirname($current_course_path . '/' . $item->get_file_path()) . '/'; $current_dir = str_replace('\\', '/', $current_dir); $file_path = realpath($current_dir . $doc_info[0]); $file_path = str_replace('\\', '/', $file_path); //error_log($file_path.' <-> '.$main_path, 0); if (strstr($file_path, $main_path) !== false) { // The calculated real path is really inside Chamilo's root path. // Reduce file path to what's under the DocumentRoot. $file_path = substr($file_path, strlen($root_path)); $file_path_dest = $file_path; // File path is courses/CHAMILO/document/.... $info_file_path = explode('/', $file_path); if ($info_file_path[0] == 'courses') { // Add character "/" in file path. $file_path_dest = 'document/' . $file_path; } //error_log('Reduced path: '.$file_path, 0); $zip_files_abs[] = $file_path; $link_updates[$my_file_path][] = array('orig' => $doc_info[0], 'dest' => $file_path_dest); $my_dep_file->setAttribute('href', 'document/' . $file_path); $my_dep->setAttribute('xml:base', ''); } } else { $zip_files[] = $my_sub_dir . '/' . $doc_info[0]; $my_dep_file->setAttribute('href', $doc_info[0]); $my_dep->setAttribute('xml:base', $my_xml_sub_dir); } break; default: $my_dep_file->setAttribute('href', $doc_info[0]); // ../../courses/ $my_dep->setAttribute('xml:base', ''); break; } } $my_dep->appendChild($my_dep_file); $resources->appendChild($my_dep); $dependency = $xmldoc->createElement('dependency'); $dependency->setAttribute('identifierref', $res_id); $my_resource->appendChild($dependency); $i++; } $resources->appendChild($my_resource); $zip_files[] = $my_file_path; break; default: // Get the path of the file(s) from the course directory root $my_file_path = 'non_exportable.html'; //$my_xml_file_path = api_htmlentities(api_utf8_encode($my_file_path), ENT_COMPAT, 'UTF-8'); $my_xml_file_path = $my_file_path; $my_sub_dir = dirname($my_file_path); $my_sub_dir = str_replace('\\', '/', $my_sub_dir); //$my_xml_sub_dir = api_htmlentities(api_utf8_encode($my_sub_dir), ENT_COMPAT, 'UTF-8'); $my_xml_sub_dir = $my_sub_dir; // Give a <resource> child to the <resources> element. $my_resource = $xmldoc->createElement('resource'); $my_resource->setAttribute('identifier', 'RESOURCE_' . $item->get_id()); $my_resource->setAttribute('type', 'webcontent'); $my_resource->setAttribute('href', $folder_name . '/' . $my_xml_file_path); // adlcp:scormtype can be either 'sco' or 'asset'. $my_resource->setAttribute('adlcp:scormtype', 'asset'); // xml:base is the base directory to find the files declared in this resource. $my_resource->setAttribute('xml:base', ''); // Give a <file> child to the <resource> element. $my_file = $xmldoc->createElement('file'); $my_file->setAttribute('href', 'document/' . $my_xml_file_path); $my_resource->appendChild($my_file); $resources->appendChild($my_resource); break; } } } $organizations->appendChild($organization); $root->appendChild($organizations); $root->appendChild($resources); $xmldoc->appendChild($root); // TODO: Add a readme file here, with a short description and a link to the Reload player // then add the file to the zip, then destroy the file (this is done automatically). // http://www.reload.ac.uk/scormplayer.html - once done, don't forget to close FS#138 foreach ($zip_files as $file_path) { if (empty($file_path)) { continue; } $dest_file = $archive_path . $temp_dir_short . '/' . $file_path; if (!empty($path_to_remove) && !empty($path_to_replace)) { $dest_file = str_replace($path_to_remove, $path_to_replace, $dest_file); } $this->create_path($dest_file); @copy($sys_course_path . $_course['path'] . '/' . $file_path, $dest_file); // Check if the file needs a link update. if (in_array($file_path, array_keys($link_updates))) { $string = file_get_contents($dest_file); unlink($dest_file); foreach ($link_updates[$file_path] as $old_new) { // This is an ugly hack that allows .flv files to be found by the flv player that // will be added in document/main/inc/lib/flv_player/flv_player.swf and that needs // to find the flv to play in document/main/, so we replace main/ in the flv path by // ../../.. to return from inc/lib/flv_player to the document/main path. if (substr($old_new['dest'], -3) == 'flv' && substr($old_new['dest'], 0, 5) == 'main/') { $old_new['dest'] = str_replace('main/', '../../../', $old_new['dest']); } elseif (substr($old_new['dest'], -3) == 'flv' && substr($old_new['dest'], 0, 6) == 'video/') { $old_new['dest'] = str_replace('video/', '../../../../video/', $old_new['dest']); } //Fix to avoid problems with default_course_document if (strpos("main/default_course_document", $old_new['dest'] === false)) { //$newDestination = str_replace('document/', $mult.'document/', $old_new['dest']); $newDestination = $old_new['dest']; } else { $newDestination = str_replace('document/', '', $old_new['dest']); } $string = str_replace($old_new['orig'], $newDestination, $string); //Add files inside the HTMLs $new_path = str_replace('/courses/', '', $old_new['orig']); $destinationFile = $archive_path . $temp_dir_short . '/' . $old_new['dest']; if (file_exists($sys_course_path . $new_path)) { copy($sys_course_path . $new_path, $destinationFile); } } file_put_contents($dest_file, $string); } } foreach ($zip_files_abs as $file_path) { if (empty($file_path)) { continue; } if (!is_file($main_path . $file_path) || !is_readable($main_path . $file_path)) { continue; } $dest_file = $archive_path . $temp_dir_short . '/document/' . $file_path; $this->create_path($dest_file); copy($main_path . $file_path, $dest_file); // Check if the file needs a link update. if (in_array($file_path, array_keys($link_updates))) { $string = file_get_contents($dest_file); unlink($dest_file); foreach ($link_updates[$file_path] as $old_new) { // This is an ugly hack that allows .flv files to be found by the flv player that // will be added in document/main/inc/lib/flv_player/flv_player.swf and that needs // to find the flv to play in document/main/, so we replace main/ in the flv path by // ../../.. to return from inc/lib/flv_player to the document/main path. if (substr($old_new['dest'], -3) == 'flv' && substr($old_new['dest'], 0, 5) == 'main/') { $old_new['dest'] = str_replace('main/', '../../../', $old_new['dest']); } $string = str_replace($old_new['orig'], $old_new['dest'], $string); } file_put_contents($dest_file, $string); } } if (is_array($links_to_create)) { foreach ($links_to_create as $file => $link) { $file_content = '<!DOCTYPE html><head> <meta charset="' . api_get_language_isocode() . '" /> <title>' . $link['title'] . '</title> </head> <body dir="' . api_get_text_direction() . '"> <div style="text-align:center"> <a href="' . $link['url'] . '">' . $link['title'] . '</a></div> </body> </html>'; file_put_contents($archive_path . $temp_dir_short . '/' . $file, $file_content); } } // Add non exportable message explanation. $lang_not_exportable = get_lang('ThisItemIsNotExportable'); $file_content = '<!DOCTYPE html><head> <meta charset="' . api_get_language_isocode() . '" /> <title>' . $lang_not_exportable . '</title> <meta http-equiv="Content-Type" content="text/html; charset=' . api_get_system_encoding() . '" /> </head> <body dir="' . api_get_text_direction() . '">'; $file_content .= <<<EOD <style> .error-message { font-family: arial, verdana, helvetica, sans-serif; border-width: 1px; border-style: solid; left: 50%; margin: 10px auto; min-height: 30px; padding: 5px; right: 50%; width: 500px; background-color: #FFD1D1; border-color: #FF0000; color: #000; } </style> <body> <div class="error-message"> {$lang_not_exportable} </div> </body> </html> EOD; if (!is_dir($archive_path . $temp_dir_short . '/document')) { @mkdir($archive_path . $temp_dir_short . '/document', api_get_permissions_for_new_directories()); } file_put_contents($archive_path . $temp_dir_short . '/document/non_exportable.html', $file_content); // Add the extra files that go along with a SCORM package. $main_code_path = api_get_path(SYS_CODE_PATH) . 'newscorm/packaging/'; $extra_files = scandir($main_code_path); foreach ($extra_files as $extra_file) { if (strpos($extra_file, '.') === 0) { continue; } else { $dest_file = $archive_path . $temp_dir_short . '/' . $extra_file; $this->create_path($dest_file); copy($main_code_path . $extra_file, $dest_file); } } // Finalize the imsmanifest structure, add to the zip, then return the zip. $manifest = @$xmldoc->saveXML(); $manifest = api_utf8_decode_xml($manifest); // The manifest gets the system encoding now. file_put_contents($archive_path . '/' . $temp_dir_short . '/imsmanifest.xml', $manifest); $zip_folder->add($archive_path . '/' . $temp_dir_short, PCLZIP_OPT_REMOVE_PATH, $archive_path . '/' . $temp_dir_short . '/'); // Clean possible temporary files. foreach ($files_cleanup as $file) { $res = unlink($file); if ($res === false) { error_log('Could not delete temp file ' . $file . ' ' . __FILE__ . ' ' . __LINE__, 0); } } $name = api_replace_dangerous_char($this->get_name()) . '.zip'; DocumentManager::file_send_for_download($temp_zip_file, true, $name); }
if (!$pub->is_accessible()) { break; } if ($pub->is_file()) { $items[] = $pub; } /** * We ignore folders */ } /** * Requested files may not be accessible. */ if (count($items) == 0) { Response::not_found(); } /** * Zip files together. */ $zip = Chamilo::temp_zip(); foreach ($items as $item) { $path = $item->get_absolute_path(); $title = $item->get_title(); $zip->add($path, $title); } /** * Send file for download */ event_download(Uri::here()); DocumentManager::file_send_for_download($zip->get_path(), false, get_lang('StudentPublications') . '.zip');
/** * @param string $filename * @param array $array */ function export_complete_report_xls($filename, $array) { global $global, $filter_score; $spreadsheet = new PHPExcel(); $spreadsheet->setActiveSheetIndex(0); $worksheet = $spreadsheet->getActiveSheet(); $line = 0; $column = 0; //skip the first column (row titles) if ($global) { $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('Courses')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('Exercises')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('ExamTaken')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('ExamNotTaken')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, sprintf(get_lang('ExamPassX'), $filter_score) . '%'); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('ExamFail')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('TotalStudents')); $column++; $line++; foreach ($array as $row) { $column = 0; foreach ($row as $item) { $worksheet->SetCellValueByColumnAndRow($line, $column, html_entity_decode(strip_tags($item))); $column++; } $line++; } $line++; } else { $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('Exercises')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('User')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('Percentage')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('Status')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('Attempts')); $column++; $line++; foreach ($array as $row) { $column = 0; $worksheet->SetCellValueByColumnAndRow($line, $column, html_entity_decode(strip_tags($row['exercise']))); $column++; foreach ($row['users'] as $key => $user) { $column = 1; $worksheet->SetCellValueByColumnAndRow($line, $column, html_entity_decode(strip_tags($user))); $column++; foreach ($row['results'][$key] as $result_item) { $worksheet->SetCellValueByColumnAndRow($line, $column, html_entity_decode(strip_tags($result_item))); $column++; } $line++; } } $line++; } $file = api_get_path(SYS_ARCHIVE_PATH) . api_replace_dangerous_char($filename); $writer = new PHPExcel_Writer_Excel2007($spreadsheet); $writer->save($file); DocumentManager::file_send_for_download($file, true, $filename); exit; }
$is_nano = true; } switch ($action) { case 'get_file': if ($nano->get_param_value('user_id') == api_get_user_id() || api_is_allowed_to_edit()) { $file_path = $nano->load_filename_if_exists(); //$file_path = '/var/www/rocio/courses/GREAT123/exercises/0/2/5/1/1-0-1-2-5-38.mp3'; if ($file_path) { $info = pathinfo($file_path); $user_info = api_get_user_info($nano->params['user_id']); $name = get_lang('Quiz') . '-' . $user_info['firstname'] . '-' . $user_info['lastname'] . '.' . $info['extension']; $download = true; if (isset($_REQUEST['download']) && $_REQUEST['download'] == 0) { $download = false; } DocumentManager::file_send_for_download($file_path, $download); exit; } } break; case 'show_audio': if (!$is_nano) { echo $nano->return_js($_REQUEST); } echo $nano->show_audio_file($is_nano); break; case 'delete': $return = $nano->delete_files(); if ($return == 1) { //cant' do this because the post that nano send doesnt take into account the session Display::display_confirmation_message(get_lang('FileDeleted'));
$column++; } $line++; foreach ($array as $row) { $column = 0; foreach ($row as $item) { $worksheet->SetCellValueByColumnAndRow($line, $column, html_entity_decode(strip_tags($item))); $column++; } $line++; } $line++; $file = api_get_path(SYS_ARCHIVE_PATH) . api_replace_dangerous_char($filename); $writer = new PHPExcel_Writer_Excel2007($spreadsheet); $writer->save($file); DocumentManager::file_send_for_download($file, true, $filename); exit; } $interbreadcrumb[] = array('url' => 'index.php', 'name' => get_lang('MySpace')); Display::display_header(get_lang('CurrentCourses')); $table = new HTML_Table(array('class' => 'data_table')); $row = 0; $column = 0; foreach ($headers as $header) { $table->setHeaderContents($row, $column, $header); $column++; } $row++; foreach ($array as $row_table) { $column = 0; foreach ($row_table as $cell) {
/* AUTHORIZATION */ // Check if the id makes sense if (!isset($_GET['id']) || !is_numeric($_GET['id'])) { api_not_allowed(true); exit; } // Check if the user is allowed to download the file $allowed_to_download = false; if (user_can_download_file($_GET['id'], api_get_user_id())) { $allowed_to_download = true; } /* ERROR IF NOT ALLOWED TO DOWNLOAD */ if (!$allowed_to_download) { api_not_allowed(true, Display::return_message(get_lang('YouAreNotAllowedToDownloadThisFile'), 'error')); exit; } else { /* DOWNLOAD THE FILE */ // the user is allowed to download the file $_SESSION['_seen'][$_course['id']][TOOL_DROPBOX][] = intval($_GET['id']); $work = new Dropbox_Work($_GET['id']); $path = dropbox_cnf('sysPath') . '/' . $work->filename; //path to file as stored on server if (!Security::check_abs_path($path, dropbox_cnf('sysPath') . '/')) { exit; } $file = $work->title; DocumentManager::file_send_for_download($path, true, $file); exit; } //@todo clean this file the code below is useless there are 2 exits in previous conditions ... maybe a bad copy/paste/merge? exit;
//echo $doc_url; if (!isset($_course)) { api_not_allowed(true); } $full_file_name = api_get_path(SYS_COURSE_PATH) . api_get_course_path() . '/upload/blog/' . $doc_url; //if the rewrite rule asks for a directory, we redirect to the course view if (is_dir($full_file_name)) { //remove last slash if present while ($doc_url[$dul = strlen($doc_url) - 1] == '/') { $doc_url = substr($doc_url, 0, $dul); } //create the path $document_explorer = api_get_path(WEB_COURSE_PATH) . api_get_course_path(); // home course path //redirect header('Location: ' . $document_explorer); } $tbl_blogs_attachment = Database::get_course_table(TABLE_BLOGS_ATTACHMENT); $course_id = api_get_course_int_id(); // launch event Event::event_download($doc_url); $sql = 'SELECT filename FROM ' . $tbl_blogs_attachment . ' WHERE c_id = ' . $course_id . ' AND path LIKE BINARY "' . Database::escape_string($doc_url) . '"'; $result = Database::query($sql); if (Database::num_rows($result) > 0) { $row = Database::fetch_array($result); if (Security::check_abs_path($full_file_name, api_get_path(SYS_COURSE_PATH) . api_get_course_path() . '/upload/blog/')) { DocumentManager::file_send_for_download($full_file_name, TRUE, $row['filename']); } } exit;
public function export_csv() { $c_id = Request::get_c_id(); $session_id = Request::get_session_id(); $root = (object) array(); $root->c_id = $c_id; $root->id = 0; $root->session_id = $session_id; $links = LinkRepository::instance()->find_by_category($root); $repo = LinkCategory::repository(); $categories = $repo->find_by_course($c_id, $session_id); $temp = Chamilo::temp_file(); $writer = \CsvWriter::create(new \FileWriter($temp)); $headers = array(); $headers[] = 'url'; $headers[] = 'title'; $headers[] = 'description'; $headers[] = 'target'; $headers[] = 'category_title'; $headers[] = 'category_description'; $writer->put($headers); foreach ($links as $link) { $data = array(); $data[] = $link->url; $data[] = $link->title; $data[] = $link->description; $data[] = $link->target; $data[] = ''; $data[] = ''; $writer->put($data); } foreach ($categories as $category) { foreach ($category->links as $link) { $data = array(); $data[] = $link->url; $data[] = $link->title; $data[] = $link->description; $data[] = $link->target; $data[] = $category->category_title; $data[] = $category->description; $writer->put($data); } } \DocumentManager::file_send_for_download($temp, true, get_lang('Links') . '.csv'); }
/** * Downloads all user files per user * @param int $userId * @param array $courseInfo * @return bool */ function downloadAllFilesPerUser($userId, $courseInfo) { $userInfo = api_get_user_info($userId); if (empty($userInfo) || empty($courseInfo)) { return false; } require_once api_get_path(LIBRARY_PATH).'pclzip/pclzip.lib.php'; $tempZipFile = api_get_path(SYS_ARCHIVE_PATH).api_get_unique_id().".zip"; $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/work/'; $zip = new PclZip($tempZipFile); $workPerUser = getWorkPerUser($userId); if (!empty($workPerUser)) { $files = array(); foreach ($workPerUser as $work) { $work = $work['work']; foreach ($work->user_results as $userResult) { if (empty($userResult['url']) || empty($userResult['contains_file'])) { continue; } $data = getFileContents($userResult['id'], $courseInfo); if (!empty($data) && isset($data['path'])) { $files[basename($data['path'])] = array( 'title' => $data['title'], 'path' => $data['path'] ); } } } if (!empty($files)) { Session::write('files', $files); foreach ($files as $data) { $zip->add( $data['path'], PCLZIP_OPT_REMOVE_PATH, $coursePath, PCLZIP_CB_PRE_ADD, 'preAddAllWorkStudentCallback' ); } } // Start download of created file $name = basename(replace_dangerous_char($userInfo['complete_name'])).'.zip'; event_download($name.'.zip (folder)'); if (Security::check_abs_path($tempZipFile, api_get_path(SYS_ARCHIVE_PATH))) { DocumentManager::file_send_for_download($tempZipFile, true, $name); @unlink($tempZipFile); exit; } } exit; }
// No invisible folders found, so all visible files can be added to the zipfile $files_for_zipfile = $all_visible_files_path; } Session::write('doc_files_to_download', $files); // Add all files in our final array to the zipfile for ($i = 0; $i < count($files_for_zipfile); $i++) { $zip->add($sysCoursePath . $courseInfo['path'] . '/document' . $files_for_zipfile[$i], PCLZIP_OPT_REMOVE_PATH, $sysCoursePath . $courseInfo['path'] . '/document' . $remove_dir, PCLZIP_CB_PRE_ADD, 'fixDocumentNameCallback'); } Session::erase('doc_files_to_download'); } // Launch event Event::event_download($path == '/' ? 'documents.zip (folder)' : basename($path) . '.zip (folder)'); // Start download of created file $name = $path == '/' ? 'documents.zip' : $documentInfo['title'] . '.zip'; if (Security::check_abs_path($tempZipFile, api_get_path(SYS_ARCHIVE_PATH))) { $result = DocumentManager::file_send_for_download($tempZipFile, true, $name); @unlink($tempZipFile); exit; } else { api_not_allowed(true); } /** * Returns the difference between two arrays, as an array of those key/values * Use this as array_diff doesn't give the * * @param array $arr1 first array * @param array $arr2 second array * * @return array difference between the two arrays */ function diff($arr1, $arr2)
if (count($files) == 0) { Response::not_found(); } $root_dir = ''; $items = array_merge($folders, $files); foreach ($items as $item) { $path = $item->get_absolute_path(); $path = realpath($path); $dir = dirname($path); if (empty($root_dir) || strlen($root_dir) > strlen($dir)) { $root_dir = $dir; } } /** * Zip files together. */ $temp_zip_path = Chamilo::temp_file('zip'); $zip_folder = new PclZip($temp_zip_path); foreach ($files as $file) { if (empty($root_dir)) { $root_dir = dirname($file); } $file = (string) $file; $zip_folder->add($file, PCLZIP_OPT_REMOVE_PATH, $root_dir); } /** * Send file for download */ event_download(Uri::here()); DocumentManager::file_send_for_download($temp_zip_path, false, get_lang('Documents') . '.zip');
/** * @param array $courseInfo * @param int $sessionId * * @return bool */ public static function downloadAllDeletedDocument($courseInfo, $sessionId) { // Zip library for creation of the zip file. require api_get_path(LIBRARY_PATH) . 'pclzip/pclzip.lib.php'; $files = self::getDeletedDocuments($courseInfo, $sessionId); if (empty($files)) { return false; } $coursePath = api_get_path(SYS_COURSE_PATH) . $courseInfo['path'] . '/document'; // Creating a ZIP file. $tempZipFile = api_get_path(SYS_ARCHIVE_PATH) . api_get_unique_id() . ".zip"; $zip = new PclZip($tempZipFile); foreach ($files as $file) { $zip->add($coursePath . $file['path'], PCLZIP_OPT_REMOVE_PATH, $coursePath); } if (Security::check_abs_path($tempZipFile, api_get_path(SYS_ARCHIVE_PATH))) { DocumentManager::file_send_for_download($tempZipFile, true); @unlink($tempZipFile); exit; } }
if (isset($_SESSION['oLP'])) { $obj = $_SESSION['oLP']; } else { api_not_allowed(); } //If is visible for the current user if (!learnpath::is_lp_visible_for_student($obj->get_id(), api_get_user_id())) { api_not_allowed(); } $doc_url = isset($_GET['doc_url']) ? $_GET['doc_url'] : null; // Change the '&' that got rewritten to '///' by mod_rewrite back to '&' $doc_url = str_replace('///', '&', $doc_url); // Still a space present? it must be a '+' (that got replaced by mod_rewrite) $doc_url = str_replace(' ', '+', $doc_url); $doc_url = str_replace(array('../', '\\..', '\\0', '..\\'), array('', '', '', ''), $doc_url); //echo $doc_url; if (strpos($doc_url, '../') or strpos($doc_url, '/..')) { $doc_url = ''; } $sys_course_path = api_get_path(SYS_COURSE_PATH) . $_course['path'] . '/scorm'; if (is_dir($sys_course_path . $doc_url)) { api_not_allowed(); } if (Security::check_abs_path($sys_course_path . $doc_url, $sys_course_path . '/')) { $full_file_name = $sys_course_path . $doc_url; // Launch event Event::event_download($doc_url); $fixLinks = api_get_configuration_value('lp_replace_http_to_https'); DocumentManager::file_send_for_download($full_file_name, false, '', $fixLinks); } exit;
//check if the document is in the database if (!DocumentManager::get_document_id($_course, $_REQUEST['file'])) { //file not found! if ($debug > 0) { error_log("404 " . $_REQUEST["file"]); } header("HTTP/1.0 404 Not Found"); $error404 = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">'; $error404 .= '<html><head>'; $error404 .= '<title>404 Not Found</title>'; $error404 .= '</head><body>'; $error404 .= '<h1>Not Found</h1>'; $error404 .= '<p>The requested URL was not found on this server.</p>'; $error404 .= '<hr>'; $error404 .= '</body></html>'; echo $error404; exit; } $doc_url = str_replace('../', '', $_REQUEST['file']); if ($debug > 0) { error_log($doc_url); } $full_file_name = $coursePath . $doc_url; if (Security::check_abs_path($full_file_name, $coursePath . '/')) { DocumentManager::file_send_for_download($full_file_name, false); } exit; } } } }
/** * Export SCORM content into a zip file * * Basically, all this function does is put the scorm directory back into a zip file (like the one * that was most probably used to import the course at first) * @deprecated this function is only called in the newscorm/scorm_admin.php which is deprecated * * @param string Name of the SCORM path (or the directory under which it resides) * @param array Not used right now. Should replace the use of global $_course * @return void * @author imandak80 */ function exportSCORM($scormname, $course) { $_course = api_get_course_info(); // Initialize. $tmpname = api_get_path(SYS_COURSE_PATH) . $_course['path'] . '/scorm'; $zipfoldername = $tmpname . $scormname; $zipfilename = $zipfoldername . '.zip'; // Create zipfile of given directory. include_once api_get_path(LIBRARY_PATH) . 'pclzip/pclzip.lib.php'; $zip_folder = new PclZip($zipfilename); $list = 1; //$list = $zip_folder->create($zipfoldername.'/',PCLZIP_OPT_REMOVE_PATH,$tmpname.$scormname."/"); // whitout folder $list = $zip_folder->create($zipfoldername . '/', PCLZIP_OPT_REMOVE_PATH, $tmpname); if ($list == 0) { //echo "Error : ".$zip_folder->errorInfo(true); } // Send to client. DocumentManager::file_send_for_download($zipfilename, false, basename($scormname . '.zip')); FileManager::my_delete($zipfilename); }
/** * Exports the complete report as an XLS file * @return boolean False on error */ public function exportCompleteReportXLS($document_path = '', $user_id = null, $export_user_fields = false, $export_filter = 0, $exercise_id = 0, $hotpotato_name = null) { global $charset; $this->getExercisesReporting($document_path, $user_id, $export_filter, $exercise_id, $hotpotato_name); $filename = 'exercise_results_' . api_get_local_time() . '.xls'; if (!empty($user_id)) { $filename = 'exercise_results_user_' . $user_id . '_' . api_get_local_time() . '.xls'; } $spreadsheet = new PHPExcel(); $spreadsheet->setActiveSheetIndex(0); $worksheet = $spreadsheet->getActiveSheet(); $line = 0; $column = 0; //skip the first column (row titles) // check if exists column 'user' $with_column_user = false; foreach ($this->results as $result) { if (!empty($result['last_name']) && !empty($result['first_name'])) { $with_column_user = true; break; } } $officialCodeInList = api_get_setting('exercise.show_official_code_exercise_result_list'); if ($with_column_user) { if (api_is_western_name_order()) { $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('FirstName')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('LastName')); $column++; } else { $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('LastName')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('FirstName')); $column++; } if ($officialCodeInList === 'true') { $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('OfficialCode')); $column++; } $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('Email')); $column++; } $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('Groups')); $column++; if ($export_user_fields) { //show user fields section with a big th colspan that spans over all fields $extra_user_fields = UserManager::get_extra_fields(0, 1000, 5, 'ASC', false, 1); //show the fields names for user fields foreach ($extra_user_fields as $field) { $worksheet->SetCellValueByColumnAndRow($line, $column, api_html_entity_decode(strip_tags($field[3]), ENT_QUOTES, $charset)); $column++; } } $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('Title')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('StartDate')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('EndDate')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('Duration') . ' (' . get_lang('MinMinutes') . ')'); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('Score')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('Total')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('Status')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('ToolLearnpath')); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, get_lang('UserIsCurrentlySubscribed')); $line++; foreach ($this->results as $row) { $column = 0; if ($with_column_user) { if (api_is_western_name_order()) { $worksheet->SetCellValueByColumnAndRow($line, $column, api_html_entity_decode(strip_tags($row['first_name']), ENT_QUOTES, $charset)); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, api_html_entity_decode(strip_tags($row['last_name']), ENT_QUOTES, $charset)); $column++; } else { $worksheet->SetCellValueByColumnAndRow($line, $column, api_html_entity_decode(strip_tags($row['last_name']), ENT_QUOTES, $charset)); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, api_html_entity_decode(strip_tags($row['first_name']), ENT_QUOTES, $charset)); $column++; } if ($officialCodeInList === 'true') { $worksheet->SetCellValueByColumnAndRow($line, $column, api_html_entity_decode(strip_tags($row['official_code']), ENT_QUOTES, $charset)); $column++; } $worksheet->SetCellValueByColumnAndRow($line, $column, api_html_entity_decode(strip_tags($row['email']), ENT_QUOTES, $charset)); $column++; } $worksheet->SetCellValueByColumnAndRow($line, $column, api_html_entity_decode(strip_tags(implode(", ", GroupManager::get_user_group_name($row['user_id']))), ENT_QUOTES, $charset)); $column++; if ($export_user_fields) { //show user fields data, if any, for this user $user_fields_values = UserManager::get_extra_user_data($row['user_id'], false, false, false, true); foreach ($user_fields_values as $value) { $worksheet->SetCellValueByColumnAndRow($line, $column, api_html_entity_decode(strip_tags($value), ENT_QUOTES, $charset)); $column++; } } $worksheet->SetCellValueByColumnAndRow($line, $column, api_html_entity_decode(strip_tags($row['title']), ENT_QUOTES, $charset)); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, $row['start_date']); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, $row['end_date']); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, $row['duration']); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, $row['result']); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, $row['max']); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, $row['status']); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, $row['lp_name']); $column++; $worksheet->SetCellValueByColumnAndRow($line, $column, $row['is_user_subscribed']); $line++; } $file = api_get_path(SYS_ARCHIVE_PATH) . api_replace_dangerous_char($filename); $writer = new PHPExcel_Writer_Excel2007($spreadsheet); $writer->save($file); DocumentManager::file_send_for_download($file, true, $filename); return true; }
/** * Exports the complete report as an XLS file * @return boolean False on error */ public function exportCompleteReportXLS($data) { $filename = 'gradebook-results-' . api_get_local_time() . '.xls'; $spreadsheet = new PHPExcel(); $spreadsheet->setActiveSheetIndex(0); $worksheet = $spreadsheet->getActiveSheet(); $line = 0; $column = 0; //skip the first column (row titles) //headers foreach ($data[0] as $header_col) { $worksheet->SetCellValueByColumnAndRow($line, $column, $header_col); $column++; } $line++; $cant_students = count($data[1]); for ($i = 0; $i < $cant_students; $i++) { $column = 0; foreach ($data[1][$i] as $col_name) { $worksheet->SetCellValueByColumnAndRow($line, $column, html_entity_decode(strip_tags($col_name))); $column++; } $line++; } $file = api_get_path(SYS_ARCHIVE_PATH) . api_replace_dangerous_char($filename); $writer = new PHPExcel_Writer_Excel2007($spreadsheet); $writer->save($file); DocumentManager::file_send_for_download($file, true, $filename); exit; }