function search_users($needle, $type) { global $_configuration, $tbl_access_url_rel_user, $tbl_user, $user_anonymous, $current_user_id, $user_id; $xajax_response = new XajaxResponse(); $return = ''; if (!empty($needle) && !empty($type)) { // xajax send utf8 datas... datas in db can be non-utf8 datas $charset = api_get_system_encoding(); $needle = api_convert_encoding($needle, $charset, 'utf-8'); $assigned_users_to_hrm = UserManager::get_users_followed_by_drh($user_id); $assigned_users_id = array_keys($assigned_users_to_hrm); $without_assigned_users = ''; if (count($assigned_users_id) > 0) { $without_assigned_users = " AND user.user_id NOT IN(" . implode(',', $assigned_users_id) . ")"; } if ($_configuration['multiple_access_urls']) { $sql = "SELECT user.user_id, username, lastname, firstname FROM {$tbl_user} user LEFT JOIN {$tbl_access_url_rel_user} au ON (au.user_id = user.user_id)\n\t\t\tWHERE " . (api_sort_by_first_name() ? 'firstname' : 'lastname') . " LIKE '{$needle}%' AND status NOT IN(" . DRH . ", " . SESSIONADMIN . ") AND user.user_id NOT IN ({$user_anonymous}, {$current_user_id}, {$user_id}) {$without_assigned_users} AND access_url_id = " . api_get_current_access_url_id() . ""; } else { $sql = "SELECT user_id, username, lastname, firstname FROM {$tbl_user} user\n\t\t\tWHERE " . (api_sort_by_first_name() ? 'firstname' : 'lastname') . " LIKE '{$needle}%' AND status NOT IN(" . DRH . ", " . SESSIONADMIN . ") AND user_id NOT IN ({$user_anonymous}, {$current_user_id}, {$user_id}) {$without_assigned_users}"; } $rs = Database::query($sql); $return .= '<select id="origin" name="NoAssignedUsersList[]" multiple="multiple" size="20" style="width:340px;">'; while ($user = Database::fetch_array($rs)) { $person_name = api_get_person_name($user['firstname'], $user['lastname']); $return .= '<option value="' . $user['user_id'] . '" title="' . htmlspecialchars($person_name, ENT_QUOTES) . '">' . $person_name . ' (' . $user['username'] . ')</option>'; } $return .= '</select>'; $xajax_response->addAssign('ajax_list_users_multiple', 'innerHTML', api_utf8_encode($return)); } return $xajax_response; }
function search_sessions($needle, $type) { global $tbl_session_rel_access_url, $tbl_session, $user_id; $xajax_response = new xajaxResponse(); $return = ''; if (!empty($needle) && !empty($type)) { $needle = Database::escape_string($needle); $assigned_sessions_to_hrm = SessionManager::get_sessions_followed_by_drh($user_id); $assigned_sessions_id = array_keys($assigned_sessions_to_hrm); $without_assigned_sessions = ''; if (count($assigned_sessions_id) > 0) { $without_assigned_sessions = " AND s.id NOT IN(" . implode(',', $assigned_sessions_id) . ")"; } if (api_is_multiple_url_enabled()) { $sql = " SELECT s.id, s.name FROM {$tbl_session} s\n LEFT JOIN {$tbl_session_rel_access_url} a ON (s.id = a.session_id)\n WHERE s.name LIKE '{$needle}%' {$without_assigned_sessions} AND access_url_id = " . api_get_current_access_url_id() . ""; } else { $sql = "SELECT s.id, s.name FROM {$tbl_session} s\n WHERE s.name LIKE '{$needle}%' {$without_assigned_sessions} "; } $rs = Database::query($sql); $return .= '<select class="form-control" id="origin" name="NoAssignedSessionsList[]" multiple="multiple" size="20">'; while ($session = Database::fetch_array($rs)) { $return .= '<option value="' . $session['id'] . '" title="' . htmlspecialchars($session['name'], ENT_QUOTES) . '">' . $session['name'] . '</option>'; } $return .= '</select>'; $xajax_response->addAssign('ajax_list_sessions_multiple', 'innerHTML', api_utf8_encode($return)); } return $xajax_response; }
/** * Search users by username, firstname or lastname, based on the given * search string * @param string Search string * @param int Deprecated param * @return string Xajax response block * @assert () === false */ public static function search_users($needle, $id) { global $tbl_user, $tbl_access_url_rel_user; $xajax_response = new XajaxResponse(); $return = ''; if (!empty($needle)) { // xajax send utf8 datas... datas in db can be non-utf8 datas $charset = api_get_system_encoding(); $needle = api_convert_encoding($needle, $charset, 'utf-8'); $needle = Database::escape_string($needle); // search users where username or firstname or lastname begins likes $needle $order_clause = api_sort_by_first_name() ? ' ORDER BY firstname, lastname, username' : ' ORDER BY lastname, firstname, username'; $sql = 'SELECT u.user_id, username, lastname, firstname FROM ' . $tbl_user . ' u ' . ' WHERE (username LIKE "' . $needle . '%" ' . ' OR firstname LIKE "' . $needle . '%" ' . ' OR lastname LIKE "' . $needle . '%") ' . $order_clause . ' LIMIT 11'; $rs = Database::query($sql); $i = 0; while ($user = Database::fetch_array($rs)) { $i++; if ($i <= 10) { $return .= '<a href="javascript: void(0);" onclick="javascript: add_user_to_url(\'' . addslashes($user['user_id']) . '\',\'' . api_get_person_name(addslashes($user['firstname']), addslashes($user['lastname'])) . ' (' . addslashes($user['username']) . ')' . '\')">' . api_get_person_name($user['firstname'], $user['lastname']) . ' (' . $user['username'] . ')</a><br />'; } else { $return .= '...<br />'; } } } $xajax_response->addAssign('ajax_list_users', 'innerHTML', api_utf8_encode($return)); return $xajax_response; }
/** * Get a list of courses (code, url, title, teacher, language) and return to caller * Function registered as service. Returns strings in UTF-8. * @param string Security key (the Dokeos install's API key) * @param mixed Array or string. Type of visibility of course (public, public-registered, private, closed) * @return array Courses list (code=>[title=>'title',url='http://...',teacher=>'...',language=>''],code=>[...],...) */ function courses_list($security_key, $visibilities = 'public') { global $_configuration; // Check if this script is launch by server and if security key is ok. if ($security_key != $_configuration['security_key']) { return array('error_msg' => 'Security check failed'); } $vis = array('public' => '3', 'public-registered' => '2', 'private' => '1', 'closed' => '0'); $courses_list = array(); if (!is_array($visibilities)) { $tmp = $visibilities; $visibilities = array($tmp); } foreach ($visibilities as $visibility) { if (!in_array($visibility, array_keys($vis))) { return array('error_msg' => 'Security check failed'); } $courses_list_tmp = CourseManager::get_courses_list(null, null, null, null, $vis[$visibility]); foreach ($courses_list_tmp as $index => $course) { $course_info = CourseManager::get_course_information($course['code']); $courses_list[$course['code']] = array('title' => api_utf8_encode($course_info['title']), 'url' => api_get_path(WEB_COURSE_PATH) . $course_info['directory'] . '/', 'teacher' => api_utf8_encode($course_info['tutor_name']), 'language' => $course_info['course_language']); } } return $courses_list; }
/** * Search sessions by name, based on a search string * @param string Search string * @param int Deprecated param * @return string Xajax response block * @assert () === false */ function search_sessions($needle, $id) { global $tbl_session; $xajax_response = new XajaxResponse(); $return = ''; if (!empty($needle)) { // xajax send utf8 datas... datas in db can be non-utf8 datas $charset = api_get_system_encoding(); $needle = api_convert_encoding($needle, $charset, 'utf-8'); $needle = Database::escape_string($needle); // search sessiones where username or firstname or lastname begins likes $needle $sql = 'SELECT id, name FROM ' . $tbl_session . ' u WHERE (name LIKE "' . $needle . '%") ORDER BY name, id LIMIT 11'; $rs = Database::query($sql); $i = 0; while ($session = Database::fetch_array($rs)) { $i++; if ($i <= 10) { $return .= '<a href="#" onclick="add_user_to_url(\'' . addslashes($session['id']) . '\',\'' . addslashes($session['name']) . ' (' . addslashes($session['id']) . ')' . '\')">' . $session['name'] . ' </a><br />'; } else { $return .= '...<br />'; } } } $xajax_response->addAssign('ajax_list_courses', 'innerHTML', api_utf8_encode($return)); return $xajax_response; }
/** * Search for a list of available courses by title or code, based on * a given string * @param string String to search for * @param int Deprecated param * @return string A formatted, xajax answer block * @assert () === false */ function search_courses($needle, $id) { global $tbl_course; $xajax_response = new XajaxResponse(); $return = ''; if (!empty($needle)) { // xajax send utf8 datas... datas in db can be non-utf8 datas $charset = api_get_system_encoding(); $needle = api_convert_encoding($needle, $charset, 'utf-8'); $needle = Database::escape_string($needle); // search courses where username or firstname or lastname begins likes $needle $sql = 'SELECT code, title FROM ' . $tbl_course . ' u ' . ' WHERE (title LIKE "' . $needle . '%" ' . ' OR code LIKE "' . $needle . '%" ' . ' ) ' . ' ORDER BY title, code ' . ' LIMIT 11'; $rs = Database::query($sql); $i = 0; while ($course = Database::fetch_array($rs)) { $i++; if ($i <= 10) { $return .= '<a href="javascript: void(0);" onclick="javascript: add_user_to_url(\'' . addslashes($course['code']) . '\',\'' . addslashes($course['title']) . ' (' . addslashes($course['code']) . ')' . '\')">' . $course['title'] . ' (' . $course['code'] . ')</a><br />'; } else { $return .= '...<br />'; } } } $xajax_response->addAssign('ajax_list_courses', 'innerHTML', api_utf8_encode($return)); return $xajax_response; }
function search_sessions($needle, $type) { global $_configuration, $tbl_session_rel_access_url, $tbl_session, $user_id; $xajax_response = new XajaxResponse(); $return = ''; if (!empty($needle) && !empty($type)) { // xajax send utf8 datas... datas in db can be non-utf8 datas $charset = api_get_system_encoding(); $needle = api_convert_encoding($needle, $charset, 'utf-8'); $assigned_sessions_to_hrm = SessionManager::get_sessions_followed_by_drh($user_id); $assigned_sessions_id = array_keys($assigned_sessions_to_hrm); $without_assigned_sessions = ''; if (count($assigned_sessions_id) > 0) { $without_assigned_sessions = " AND s.id NOT IN(" . implode(',', $assigned_sessions_id) . ")"; } if ($_configuration['multiple_access_urls']) { $sql = " SELECT s.id, s.name FROM {$tbl_session} s LEFT JOIN {$tbl_session_rel_access_url} a ON (s.id = a.session_id)\n\t\t\t\t\t\tWHERE s.name LIKE '{$needle}%' {$without_assigned_sessions} AND access_url_id = " . api_get_current_access_url_id() . ""; } else { $sql = "SELECT s.id, s.name FROM {$tbl_session} s\n\t\t\t\tWHERE s.name LIKE '{$needle}%' {$without_assigned_sessions} "; } $rs = Database::query($sql); $return .= '<select id="origin" name="NoAssignedSessionsList[]" multiple="multiple" size="20" style="width:340px;">'; while ($session = Database::fetch_array($rs)) { $return .= '<option value="' . $session['id'] . '" title="' . htmlspecialchars($session['name'], ENT_QUOTES) . '">' . $session['name'] . '</option>'; } $return .= '</select>'; $xajax_response->addAssign('ajax_list_sessions_multiple', 'innerHTML', api_utf8_encode($return)); } return $xajax_response; }
function search_courses($needle, $type) { global $tbl_course, $tbl_course_rel_access_url, $user_id; $xajax_response = new xajaxResponse(); $return = ''; if (!empty($needle) && !empty($type)) { // xajax send utf8 datas... datas in db can be non-utf8 datas $needle = Database::escape_string($needle); $assigned_courses_to_hrm = CourseManager::get_courses_followed_by_drh($user_id); $assigned_courses_code = array_keys($assigned_courses_to_hrm); foreach ($assigned_courses_code as &$value) { $value = "'" . $value . "'"; } $without_assigned_courses = ''; if (count($assigned_courses_code) > 0) { $without_assigned_courses = " AND c.code NOT IN(" . implode(',', $assigned_courses_code) . ")"; } if (api_is_multiple_url_enabled()) { $sql = "SELECT c.code, c.title\n FROM {$tbl_course} c\n\t\t\t\t\tLEFT JOIN {$tbl_course_rel_access_url} a\n ON (a.c_id = c.id)\n \tWHERE\n \t\tc.code LIKE '{$needle}%' {$without_assigned_courses} AND\n \t\taccess_url_id = " . api_get_current_access_url_id(); } else { $sql = "SELECT c.code, c.title\n \t\tFROM {$tbl_course} c\n \tWHERE\n \t\tc.code LIKE '{$needle}%'\n \t\t{$without_assigned_courses} "; } $rs = Database::query($sql); $return .= '<select id="origin" name="NoAssignedCoursesList[]" multiple="multiple" size="20" style="width:340px;">'; while ($course = Database::fetch_array($rs)) { $return .= '<option value="' . $course['code'] . '" title="' . htmlspecialchars($course['title'], ENT_QUOTES) . '">' . $course['title'] . ' (' . $course['code'] . ')</option>'; } $return .= '</select>'; $xajax_response->addAssign('ajax_list_courses_multiple', 'innerHTML', api_utf8_encode($return)); } return $xajax_response; }
/** * Get a list of courses (code, url, title, teacher, language) for a specific * user and return to caller * Function registered as service. Returns strings in UTF-8. * @param string User name in Chamilo * @param string Signature (composed of the sha1(username+apikey) * @return array Courses list (code=>[title=>'title',url='http://...',teacher=>'...',language=>''],code=>[...],...) */ function WSCourseListOfUser($username, $signature) { if (empty($username) or empty($signature)) { return -1; } global $_configuration; $info = api_get_user_info_from_username($username); $user_id = $info['user_id']; $list = UserManager::get_api_keys($user_id, 'dokeos'); $key = ''; foreach ($list as $key) { break; } $local_key = $username . $key; if (!api_is_valid_secret_key($signature, $local_key)) { return -1; // The secret key is incorrect. } $courses_list = array(); $courses_list_tmp = CourseManager::get_courses_list_by_user_id($user_id); foreach ($courses_list_tmp as $index => $course) { $course_info = CourseManager::get_course_information($course['code']); $courses_list[] = array('code' => $course['code'], 'title' => api_utf8_encode($course_info['title']), 'url' => api_get_path(WEB_COURSE_PATH) . $course_info['directory'] . '/', 'teacher' => api_utf8_encode($course_info['tutor_name']), 'language' => $course_info['course_language']); } return $courses_list; }
function ConvertToXmlAttribute($value) { if (IS_WINDOWS_OS || FindBadUtf8($value)) { return api_utf8_encode(htmlspecialchars($value)); } else { return htmlspecialchars($value); } }
function search_coachs($needle) { $tbl_user = Database::get_main_table(TABLE_MAIN_USER); $xajax_response = new xajaxResponse(); $return = ''; if (!empty($needle)) { $order_clause = api_sort_by_first_name() ? ' ORDER BY firstname, lastname, username' : ' ORDER BY lastname, firstname, username'; // search users where username or firstname or lastname begins likes $needle $sql = 'SELECT username, lastname, firstname FROM ' . $tbl_user . ' user WHERE (username LIKE "' . $needle . '%" OR firstname LIKE "' . $needle . '%" OR lastname LIKE "' . $needle . '%") AND status=1' . $order_clause . ' LIMIT 10'; if (api_is_multiple_url_enabled()) { $tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); $access_url_id = api_get_current_access_url_id(); if ($access_url_id != -1) { $sql = 'SELECT username, lastname, firstname FROM ' . $tbl_user . ' user INNER JOIN ' . $tbl_user_rel_access_url . ' url_user ON (url_user.user_id=user.user_id) WHERE access_url_id = ' . $access_url_id . ' AND ( username LIKE "' . $needle . '%" OR firstname LIKE "' . $needle . '%" OR lastname LIKE "' . $needle . '%" ) AND status=1' . $order_clause . ' LIMIT 10'; } } $rs = Database::query($sql); while ($user = Database::fetch_array($rs)) { $return .= '<a href="javascript: void(0);" onclick="javascript: fill_coach_field(\'' . $user['username'] . '\')">' . api_get_person_name($user['firstname'], $user['lastname']) . ' (' . $user['username'] . ')</a><br />'; } } $xajax_response->addAssign('ajax_list_coachs', 'innerHTML', api_utf8_encode($return)); return $xajax_response; }
/** * Get a list of courses (code, url, title, teacher, language) and return to caller * Function registered as service. Returns strings in UTF-8. * @param string User name in Chamilo * @param string Signature (composed of the sha1(username+apikey) * @param mixed Array or string. Type of visibility of course (public, public-registered, private, closed) * @return array Courses list (code=>[title=>'title',url='http://...',teacher=>'...',language=>''],code=>[...],...) */ function WSCourseList($username, $signature, $visibilities = 'public') { if (empty($username) or empty($signature)) { return -1; } global $_configuration; $info = api_get_user_info_from_username($username); $user_id = $info['user_id']; if (!UserManager::is_admin($user_id)) { return -1; } $list = UserManager::get_api_keys($user_id, 'dokeos'); $key = ''; foreach ($list as $key) { break; } $local_key = $username . $key; if (!api_is_valid_secret_key($signature, $local_key) && !api_is_valid_secret_key($signature, $username . $_configuration['security_key'])) { return -1; // The secret key is incorrect. } //public-registered = open $vis = array('public' => '3', 'public-registered' => '2', 'private' => '1', 'closed' => '0'); $courses_list = array(); if (!is_array($visibilities)) { $visibilities = split(',', $visibilities); } foreach ($visibilities as $visibility) { if (!in_array($visibility, array_keys($vis))) { return array('error_msg' => 'Security check failed'); } $courses_list_tmp = CourseManager::get_courses_list(null, null, null, null, $vis[$visibility]); foreach ($courses_list_tmp as $index => $course) { $course_info = CourseManager::get_course_information($course['code']); $courses_list[] = array('code' => $course['code'], 'title' => api_utf8_encode($course_info['title']), 'url' => api_get_path(WEB_COURSE_PATH) . $course_info['directory'] . '/', 'teacher' => api_utf8_encode($course_info['tutor_name']), 'language' => $course_info['course_language']); } } return $courses_list; }
/** * Export the given HTML to PDF, using a global template * @param string the HTML content * @uses export/table_pdf.tpl */ function html_to_pdf_with_template($content) { Display::display_no_header(); //Assignments Display::$global_template->assign('pdf_content', $content); $organization = api_get_setting('Institution'); $img = api_get_path(SYS_CODE_PATH) . 'css/' . api_get_visual_theme() . '/images/header-logo.png'; if (file_exists($img)) { $img = api_get_path(WEB_CODE_PATH) . 'css/' . api_get_visual_theme() . '/images/header-logo.png'; $organization = "<img src='{$img}'>"; } else { if (!empty($organization)) { $organization = '<h2 align="left">' . $organization . '</h2>'; } } Display::$global_template->assign('organization', $organization); //Showing only the current teacher/admin instead the all teacherlist name see BT#4080 $user_info = api_get_user_info(); $teacher_list = $user_info['complete_name']; $session_name = api_get_session_name(api_get_session_id()); if (!empty($session_name)) { Display::$global_template->assign('pdf_session', $session_name); } Display::$global_template->assign('pdf_course', $this->params['course_code']); Display::$global_template->assign('pdf_date', api_format_date(api_get_utc_datetime(), DATE_TIME_FORMAT_LONG)); Display::$global_template->assign('pdf_teachers', $teacher_list); Display::$global_template->assign('pdf_title', $this->params['pdf_title']); Display::$global_template->assign('add_signatures', $this->params['add_signatures']); //Getting template $tpl = Display::$global_template->get_template('export/table_pdf.tpl'); $html = Display::$global_template->fetch($tpl); $html = api_utf8_encode($html); $css_file = api_get_path(TO_SYS, WEB_CSS_PATH) . '/print.css'; $css = file_exists($css_file) ? @file_get_contents($css_file) : ''; self::content_to_pdf($html, $css, $this->params['filename'], $this->params['course_code']); }
/** * Search for a session based on a given search string * @param string A search string * @param string A search box type (single or anything else) * @return string XajaxResponse * @assert ('abc','single') !== '' */ function search_courses($needle, $type) { global $tbl_session; $xajax_response = new XajaxResponse(); $return = ''; if (!empty($needle) && !empty($type)) { // xajax send utf8 datas... datas in db can be non-utf8 datas $charset = api_get_system_encoding(); $needle = api_convert_encoding($needle, $charset, 'utf-8'); $needle = Database::escape_string($needle); $sql = 'SELECT * FROM ' . $tbl_session . ' WHERE name LIKE "' . $needle . '%" ORDER BY id'; $rs = Database::query($sql); $course_list = array(); $return .= '<select id="origin" name="NoSessionCategoryList[]" multiple="multiple" size="20" style="width:340px;">'; while ($course = Database::fetch_array($rs)) { $course_list[] = $course['id']; $return .= '<option value="' . $course['id'] . '" title="' . htmlspecialchars($course['name'], ENT_QUOTES) . '">' . $course['name'] . '</option>'; } $return .= '</select>'; $xajax_response->addAssign('ajax_list_courses_multiple', 'innerHTML', api_utf8_encode($return)); } $_SESSION['course_list'] = $course_list; return $xajax_response; }
function search($needle, $type) { global $elements_in; $xajax_response = new xajaxResponse(); $return = ''; if (!empty($needle) && !empty($type)) { if ($type == 'single') { } else { $list = CourseManager::get_courses_list(0, 0, 2, 'ASC', -1, $needle); } if ($type == 'single') { } else { $return .= '<select id="elements_not_in" name="elements_not_in_name[]" multiple="multiple" size="15" style="width:360px;">'; foreach ($list as $row) { if (!in_array($row['id'], array_keys($elements_in))) { $return .= '<option value="' . $row['id'] . '">' . $row['title'] . ' (' . $row['visual_code'] . ')</option>'; } } $return .= '</select>'; $xajax_response->addAssign('ajax_list_multiple', 'innerHTML', api_utf8_encode($return)); } } return $xajax_response; }
function search_users($needle, $type) { global $tbl_access_url_rel_user, $tbl_user, $user_anonymous, $current_user_id, $user_id, $userStatus; $xajax_response = new xajaxResponse(); $return = ''; if (!empty($needle) && !empty($type)) { $assigned_users_to_hrm = array(); switch ($userStatus) { case DRH: //no break; //no break; case PLATFORM_ADMIN: $assigned_users_to_hrm = UserManager::get_users_followed_by_drh($user_id); break; case STUDENT_BOSS: $assigned_users_to_hrm = UserManager::getUsersFollowedByStudentBoss($user_id); break; } $assigned_users_id = array_keys($assigned_users_to_hrm); $without_assigned_users = ''; $westernOrder = api_is_western_name_order(); if ($westernOrder) { $order_clause = " ORDER BY firstname, lastname"; } else { $order_clause = " ORDER BY lastname, firstname"; } if (count($assigned_users_id) > 0) { $without_assigned_users = " AND user.user_id NOT IN(" . implode(',', $assigned_users_id) . ")"; } if (api_is_multiple_url_enabled()) { $sql = "SELECT user.user_id, username, lastname, firstname\n FROM {$tbl_user} user\n LEFT JOIN {$tbl_access_url_rel_user} au ON (au.user_id = user.user_id)\n WHERE\n " . (api_sort_by_first_name() ? 'firstname' : 'lastname') . " LIKE '{$needle}%' AND\n status NOT IN(" . DRH . ", " . SESSIONADMIN . ", " . STUDENT_BOSS . ") AND\n user.user_id NOT IN ({$user_anonymous}, {$current_user_id}, {$user_id})\n {$without_assigned_users} AND\n access_url_id = " . api_get_current_access_url_id() . "\n {$order_clause}\n "; } else { $sql = "SELECT user_id, username, lastname, firstname\n FROM {$tbl_user} user\n WHERE\n " . (api_sort_by_first_name() ? 'firstname' : 'lastname') . " LIKE '{$needle}%' AND\n status NOT IN(" . DRH . ", " . SESSIONADMIN . ", " . STUDENT_BOSS . ") AND\n user_id NOT IN ({$user_anonymous}, {$current_user_id}, {$user_id})\n {$without_assigned_users}\n {$order_clause}\n "; } $rs = Database::query($sql); $xajax_response->addAssign('ajax_list_users_multiple', 'innerHTML', api_utf8_encode($return)); if ($type == 'single') { $tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); $access_url_id = api_get_current_access_url_id(); $sql = 'SELECT user.user_id, username, lastname, firstname FROM ' . $tbl_user . ' user INNER JOIN ' . $tbl_user_rel_access_url . ' url_user ON (url_user.user_id=user.user_id) WHERE access_url_id = ' . $access_url_id . ' AND ( username LIKE "' . $needle . '%" OR firstname LIKE "' . $needle . '%" OR lastname LIKE "' . $needle . '%" ) AND '; switch ($userStatus) { case DRH: $sql .= " user.status <> 6 AND user.status <> " . DRH; break; case STUDENT_BOSS: $sql .= " user.status <> 6 AND user.status <> " . STUDENT_BOSS; break; } $sql .= " {$order_clause} LIMIT 11"; $rs = Database::query($sql); $i = 0; while ($user = Database::fetch_array($rs)) { $i++; if ($i <= 10) { $person_name = api_get_person_name($user['firstname'], $user['lastname']); $return .= '<a href="javascript: void(0);" onclick="javascript: add_user_to_user(\'' . $user['user_id'] . '\',\'' . $person_name . ' (' . $user['username'] . ')' . '\')">' . $person_name . ' (' . $user['username'] . ')</a><br />'; } else { $return .= '...<br />'; } } $xajax_response->addAssign('ajax_list_users_single', 'innerHTML', api_utf8_encode($return)); } else { $return .= '<select id="origin" class="form-control" name="NoAssignedUsersList[]" multiple="multiple" size="15" ">'; while ($user = Database::fetch_array($rs)) { $person_name = api_get_person_name($user['firstname'], $user['lastname']); $return .= '<option value="' . $user['user_id'] . '" title="' . htmlspecialchars($person_name, ENT_QUOTES) . '">' . $person_name . ' (' . $user['username'] . ')</option>'; } $return .= '</select>'; $xajax_response->addAssign('ajax_list_users_multiple', 'innerHTML', api_utf8_encode($return)); } } return $xajax_response; }
function search($needle, $type) { global $tbl_user, $elements_in; $xajax_response = new XajaxResponse(); $return = ''; if (!empty($needle) && !empty($type)) { // xajax send utf8 datas... datas in db can be non-utf8 datas $charset = api_get_system_encoding(); $needle = Database::escape_string($needle); $needle = api_convert_encoding($needle, $charset, 'utf-8'); if ($type == 'single') { // search users where username or firstname or lastname begins likes $needle /* $sql = 'SELECT user.user_id, username, lastname, firstname FROM '.$tbl_user.' user WHERE (username LIKE "'.$needle.'%" OR firstname LIKE "'.$needle.'%" OR lastname LIKE "'.$needle.'%") AND user.user_id<>"'.$user_anonymous.'" AND user.status<>'.DRH.''. $order_clause. ' LIMIT 11';*/ } else { $list = CourseManager::get_courses_list(0, 0, 2, 'ASC', -1, $needle); } $i = 0; if ($type == 'single') { /* while ($user = Database :: fetch_array($rs)) { $i++; if ($i<=10) { $person_name = api_get_person_name($user['firstname'], $user['lastname']); $return .= '<a href="javascript: void(0);" onclick="javascript: add_user_to_session(\''.$user['user_id'].'\',\''.$person_name.' ('.$user['username'].')'.'\')">'.$person_name.' ('.$user['username'].')</a><br />'; } else { $return .= '...<br />'; } } $xajax_response -> addAssign('ajax_list_users_single','innerHTML',api_utf8_encode($return));*/ } else { $return .= '<select id="elements_not_in" name="elements_not_in_name[]" multiple="multiple" size="15" style="width:360px;">'; foreach ($list as $row) { if (!in_array($row['id'], array_keys($elements_in))) { $return .= '<option value="' . $row['id'] . '">' . $row['title'] . ' (' . $row['visual_code'] . ')</option>'; } } $return .= '</select>'; $xajax_response->addAssign('ajax_list_multiple', 'innerHTML', api_utf8_encode($return)); } } return $xajax_response; }
/** * Takes the first character in a string and returns its Unicode codepoint. * @param string $character The input string. * @param string $encoding (optional) The encoding of the input string. If it is omitted, the platform character set will be used by default. * @return int Returns: the codepoint of the first character; or 0xFFFD (unknown character) when the input string is empty. * This is a multibyte aware version of the function ord(). * @link http://php.net/manual/en/function.ord.php * Note the difference with the original funtion ord(): ord('') returns 0, api_ord('') returns 0xFFFD (unknown character). */ function api_ord($character, $encoding) { return Patchwork\Utf8::ord(api_utf8_encode($character, $encoding)); }
function search_users($needle, $type) { global $tbl_user, $tbl_session_rel_user, $id_session; $xajax_response = new XajaxResponse(); $return = ''; if (!empty($needle) && !empty($type)) { //normal behaviour if ($type == 'any_session' && $needle == 'false') { $type = 'multiple'; $needle = ''; } // xajax send utf8 datas... datas in db can be non-utf8 datas $charset = api_get_system_encoding(); $needle = Database::escape_string($needle); $needle = api_convert_encoding($needle, $charset, 'utf-8'); $order_clause = api_sort_by_first_name() ? ' ORDER BY firstname, lastname, username' : ' ORDER BY lastname, firstname, username'; $cond_user_id = ''; //Only for single & multiple if (in_array($type, array('single', 'multiple'))) { if (!empty($id_session)) { $id_session = intval($id_session); // check id_user from session_rel_user table $sql = 'SELECT id_user FROM ' . $tbl_session_rel_user . ' WHERE id_session ="' . $id_session . '" AND relation_type<>' . SESSION_RELATION_TYPE_RRHH . ' '; $res = Database::query($sql); $user_ids = array(); if (Database::num_rows($res) > 0) { while ($row = Database::fetch_row($res)) { $user_ids[] = (int) $row[0]; } } if (count($user_ids) > 0) { $cond_user_id = ' AND user.user_id NOT IN(' . implode(",", $user_ids) . ')'; } } } switch ($type) { case 'single': // search users where username or firstname or lastname begins likes $needle $sql = 'SELECT user.user_id, username, lastname, firstname, official_code FROM ' . $tbl_user . ' user WHERE (username LIKE "' . $needle . '%" OR firstname LIKE "' . $needle . '%" OR lastname LIKE "' . $needle . '%") AND user.status<>6 AND user.status<>' . DRH . '' . $order_clause . ' LIMIT 11'; break; case 'multiple': $sql = 'SELECT user.user_id, username, lastname, firstname, official_code FROM ' . $tbl_user . ' user WHERE ' . (api_sort_by_first_name() ? 'firstname' : 'lastname') . ' LIKE "' . $needle . '%" AND user.status<>' . DRH . ' AND user.status<>6 ' . $cond_user_id . $order_clause; break; case 'any_session': $sql = 'SELECT DISTINCT user.user_id, username, lastname, firstname, official_code FROM ' . $tbl_user . ' user LEFT OUTER JOIN ' . $tbl_session_rel_user . ' s ON (s.id_user = user.user_id) WHERE s.id_user IS null AND user.status<>' . DRH . ' AND user.status<>6 ' . $cond_user_id . $order_clause; break; } if (api_is_multiple_url_enabled()) { $tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); $access_url_id = api_get_current_access_url_id(); if ($access_url_id != -1) { switch ($type) { case 'single': $sql = 'SELECT user.user_id, username, lastname, firstname, official_code FROM ' . $tbl_user . ' user INNER JOIN ' . $tbl_user_rel_access_url . ' url_user ON (url_user.user_id=user.user_id) WHERE access_url_id = ' . $access_url_id . ' AND (username LIKE "' . $needle . '%" OR firstname LIKE "' . $needle . '%" OR lastname LIKE "' . $needle . '%") AND user.status<>6 AND user.status<>' . DRH . ' ' . $order_clause . ' LIMIT 11'; break; case 'multiple': $sql = 'SELECT user.user_id, username, lastname, firstname , official_code FROM ' . $tbl_user . ' user INNER JOIN ' . $tbl_user_rel_access_url . ' url_user ON (url_user.user_id=user.user_id) WHERE access_url_id = ' . $access_url_id . ' AND ' . (api_sort_by_first_name() ? 'firstname' : 'lastname') . ' LIKE "' . $needle . '%" AND user.status<>' . DRH . ' AND user.status<>6 ' . $cond_user_id . $order_clause; break; case 'any_session': $sql = 'SELECT DISTINCT user.user_id, username, lastname, firstname, official_code FROM ' . $tbl_user . ' user LEFT OUTER JOIN ' . $tbl_session_rel_user . ' s ON (s.id_user = user.user_id) INNER JOIN ' . $tbl_user_rel_access_url . ' url_user ON (url_user.user_id=user.user_id) WHERE access_url_id = ' . $access_url_id . ' AND s.id_user IS null AND user.status<>' . DRH . ' AND user.status<>6 ' . $cond_user_id . $order_clause; break; } } } $rs = Database::query($sql); $i = 0; if ($type == 'single') { while ($user = Database::fetch_array($rs)) { $i++; if ($i <= 10) { $person_name = api_get_person_name($user['firstname'], $user['lastname']) . ' (' . $user['username'] . ') ' . $user['official_code']; $return .= '<a href="javascript: void(0);" onclick="javascript: add_user_to_session(\'' . $user['user_id'] . '\',\'' . $person_name . ' ' . '\')">' . $person_name . ' </a><br />'; } else { $return .= '...<br />'; } } $xajax_response->addAssign('ajax_list_users_single', 'innerHTML', api_utf8_encode($return)); } else { global $nosessionUsersList; $return .= '<select id="origin_users" name="nosessionUsersList[]" multiple="multiple" size="15" style="width:360px;">'; while ($user = Database::fetch_array($rs)) { $person_name = api_get_person_name($user['firstname'], $user['lastname']) . ' (' . $user['username'] . ') ' . $user['official_code']; $return .= '<option value="' . $user['user_id'] . '">' . $person_name . ' </option>'; } $return .= '</select>'; $xajax_response->addAssign('ajax_list_users_multiple', 'innerHTML', api_utf8_encode($return)); } } return $xajax_response; }
/** * A reverse case-insensitive string comparison callback function for sorting. * @param string $string1 The first string. * @param string $string2 The second string. * @return int Returns 0 if $string1 = $string2 or if there is an error; 1 if $string1 < $string2; -1 if $string1 > $string2. */ function _api_casercmp($string1, $string2) { global $_api_collator, $_api_encoding; $result = collator_compare($_api_collator, api_strtolower(api_utf8_encode($string2, $_api_encoding), 'UTF-8'), api_strtolower(api_utf8_encode($string1, $_api_encoding), 'UTF-8')); return $result === false ? 0 : $result; }
/** * // 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 = api_get_course_int_id(); $links_to_create = null; // 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 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, 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 = api_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'); // We are going to build a UTF-8 encoded manifest. Later we will recode it to the desired (and supported) 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', '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(); 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 = 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'. 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', ''); //$current_dir = str_replace('\\', '/', dirname($current_course_path.'/'.$item->get_file_path())).'/'; // 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).$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) . '/'; $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)); $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); 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++; } //$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. 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 = 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', '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: 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(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); } // 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(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. //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); $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 //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']); } //Fix to avoid problems with default_course_document if (strpos("main/default_course_document", $old_new['dest'] === false)) { $new_dest = str_replace('document/', $mult . 'document/', $old_new['dest']); } else { //$new_dest = str_replace('main/default_course_document', $mult.'document/main/default_course_document', $old_new['dest']); $new_dest = $old_new['dest']; } //$string = str_replace($old_new['orig'], $old_new['dest'], $string); $string = str_replace($old_new['orig'], $new_dest, $string); //Add files inside the HTMLs $new_path = str_replace('/courses/', '', $old_new['orig']); //var_dump($sys_course_path.$new_path); var_dump($archive_path.$temp_dir_short.'/'.$old_new['dest']); echo '---'; if (file_exists($sys_course_path . $new_path)) { copy($sys_course_path . $new_path, $archive_path . $temp_dir_short . '/' . $old_new['dest']); } } 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']); } $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 = Text::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); } } // Send file to client $name = api_replace_dangerous_char($this->get_name()) . '.zip'; DocumentManager::file_send_for_download($temp_zip_file, true, $name); }
/** * This function was originally found in the exercise_show.php * @param int $exeId * @param int $questionId * @param int $choice the user selected * @param string $from function is called from 'exercise_show' or 'exercise_result' * @param array $exerciseResultCoordinates the hotspot coordinates $hotspot[$question_id] = coordinates * @param bool $saved_results save results in the DB or just show the reponse * @param bool $from_database gets information from DB or from the current selection * @param bool $show_result show results or not * @param int $propagate_neg * @param array $hotspot_delineation_result * * @todo reduce parameters of this function * @return string html code */ public function manage_answer($exeId, $questionId, $choice, $from = 'exercise_show', $exerciseResultCoordinates = array(), $saved_results = true, $from_database = false, $show_result = true, $propagate_neg = 0, $hotspot_delineation_result = array()) { global $debug; //needed in order to use in the exercise_attempt() for the time global $learnpath_id, $learnpath_item_id; require_once api_get_path(LIBRARY_PATH) . 'geometry.lib.php'; $feedback_type = $this->selectFeedbackType(); $results_disabled = $this->selectResultsDisabled(); if ($debug) { error_log("<------ manage_answer ------> "); error_log('exe_id: ' . $exeId); error_log('$from: ' . $from); error_log('$saved_results: ' . intval($saved_results)); error_log('$from_database: ' . intval($from_database)); error_log('$show_result: ' . $show_result); error_log('$propagate_neg: ' . $propagate_neg); error_log('$exerciseResultCoordinates: ' . print_r($exerciseResultCoordinates, 1)); error_log('$hotspot_delineation_result: ' . print_r($hotspot_delineation_result, 1)); error_log('$learnpath_id: ' . $learnpath_id); error_log('$learnpath_item_id: ' . $learnpath_item_id); error_log('$choice: ' . print_r($choice, 1)); } $extra_data = array(); $final_overlap = 0; $final_missing = 0; $final_excess = 0; $overlap_color = 0; $missing_color = 0; $excess_color = 0; $threadhold1 = 0; $threadhold2 = 0; $threadhold3 = 0; $arrques = null; $arrans = null; $questionId = intval($questionId); $exeId = intval($exeId); $TBL_TRACK_ATTEMPT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); $table_ans = Database::get_course_table(TABLE_QUIZ_ANSWER); // Creates a temporary Question object $course_id = $this->course_id; $objQuestionTmp = Question::read($questionId, $course_id); if ($objQuestionTmp === false) { return false; } $questionName = $objQuestionTmp->selectTitle(); $questionWeighting = $objQuestionTmp->selectWeighting(); $answerType = $objQuestionTmp->selectType(); $quesId = $objQuestionTmp->selectId(); $extra = $objQuestionTmp->extra; $next = 1; //not for now // Extra information of the question if (!empty($extra)) { $extra = explode(':', $extra); if ($debug) { error_log(print_r($extra, 1)); } // Fixes problems with negatives values using intval $true_score = floatval(trim($extra[0])); $false_score = floatval(trim($extra[1])); $doubt_score = floatval(trim($extra[2])); } $totalWeighting = 0; $totalScore = 0; // Destruction of the Question object unset($objQuestionTmp); // Construction of the Answer object $objAnswerTmp = new Answer($questionId); $nbrAnswers = $objAnswerTmp->selectNbrAnswers(); if ($debug) { error_log('Count of answers: ' . $nbrAnswers); error_log('$answerType: ' . $answerType); } if ($answerType == FREE_ANSWER || $answerType == ORAL_EXPRESSION || $answerType == CALCULATED_ANSWER) { $nbrAnswers = 1; } $nano = null; if ($answerType == ORAL_EXPRESSION) { $exe_info = Event::get_exercise_results_by_attempt($exeId); $exe_info = isset($exe_info[$exeId]) ? $exe_info[$exeId] : null; $params = array(); $params['course_id'] = $course_id; $params['session_id'] = api_get_session_id(); $params['user_id'] = isset($exe_info['exe_user_id']) ? $exe_info['exe_user_id'] : api_get_user_id(); $params['exercise_id'] = isset($exe_info['exe_exo_id']) ? $exe_info['exe_exo_id'] : $this->id; $params['question_id'] = $questionId; $params['exe_id'] = isset($exe_info['exe_id']) ? $exe_info['exe_id'] : $exeId; $nano = new Nanogong($params); //probably this attempt came in an exercise all question by page if ($feedback_type == 0) { $nano->replace_with_real_exe($exeId); } } $user_answer = ''; // Get answer list for matching $sql = "SELECT id_auto, id, answer\n FROM {$table_ans}\n WHERE c_id = {$course_id} AND question_id = {$questionId}"; $res_answer = Database::query($sql); $answerMatching = array(); while ($real_answer = Database::fetch_array($res_answer)) { $answerMatching[$real_answer['id_auto']] = $real_answer['answer']; } $real_answers = array(); $quiz_question_options = Question::readQuestionOption($questionId, $course_id); $organs_at_risk_hit = 0; $questionScore = 0; if ($debug) { error_log('Start answer loop '); } $answer_correct_array = array(); for ($answerId = 1; $answerId <= $nbrAnswers; $answerId++) { $answer = $objAnswerTmp->selectAnswer($answerId); $answerComment = $objAnswerTmp->selectComment($answerId); $answerCorrect = $objAnswerTmp->isCorrect($answerId); $answerWeighting = (double) $objAnswerTmp->selectWeighting($answerId); $answerAutoId = $objAnswerTmp->selectAutoId($answerId); $answer_correct_array[$answerId] = (bool) $answerCorrect; if ($debug) { error_log("answer auto id: {$answerAutoId} "); error_log("answer correct: {$answerCorrect} "); } // Delineation $delineation_cord = $objAnswerTmp->selectHotspotCoordinates(1); $answer_delineation_destination = $objAnswerTmp->selectDestination(1); switch ($answerType) { // for unique answer case UNIQUE_ANSWER: case UNIQUE_ANSWER_IMAGE: case UNIQUE_ANSWER_NO_OPTION: if ($from_database) { $sql = "SELECT answer FROM {$TBL_TRACK_ATTEMPT}\n WHERE\n exe_id = '" . $exeId . "' AND\n question_id= '" . $questionId . "'"; $result = Database::query($sql); $choice = Database::result($result, 0, "answer"); $studentChoice = $choice == $answerAutoId ? 1 : 0; if ($studentChoice) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; } } else { $studentChoice = $choice == $answerAutoId ? 1 : 0; if ($studentChoice) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; } } break; // for multiple answers // for multiple answers case MULTIPLE_ANSWER_TRUE_FALSE: if ($from_database) { $choice = array(); $sql = "SELECT answer FROM {$TBL_TRACK_ATTEMPT}\n WHERE\n exe_id = {$exeId} AND\n question_id = " . $questionId; $result = Database::query($sql); while ($row = Database::fetch_array($result)) { $ind = $row['answer']; $values = explode(':', $ind); $my_answer_id = isset($values[0]) ? $values[0] : ''; $option = isset($values[1]) ? $values[1] : ''; $choice[$my_answer_id] = $option; } } $studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : null; if (!empty($studentChoice)) { if ($studentChoice == $answerCorrect) { $questionScore += $true_score; } else { if ($quiz_question_options[$studentChoice]['name'] == "Don't know" || $quiz_question_options[$studentChoice]['name'] == "DoubtScore") { $questionScore += $doubt_score; } else { $questionScore += $false_score; } } } else { // If no result then the user just hit don't know $studentChoice = 3; $questionScore += $doubt_score; } $totalScore = $questionScore; break; case MULTIPLE_ANSWER: //2 if ($from_database) { $choice = array(); $sql = "SELECT answer FROM " . $TBL_TRACK_ATTEMPT . "\n WHERE exe_id = '" . $exeId . "' AND question_id= '" . $questionId . "'"; $resultans = Database::query($sql); while ($row = Database::fetch_array($resultans)) { $ind = $row['answer']; $choice[$ind] = 1; } $studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : null; $real_answers[$answerId] = (bool) $studentChoice; if ($studentChoice) { $questionScore += $answerWeighting; } } else { $studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : null; $real_answers[$answerId] = (bool) $studentChoice; if (isset($studentChoice)) { $questionScore += $answerWeighting; } } $totalScore += $answerWeighting; if ($debug) { error_log("studentChoice: {$studentChoice}"); } break; case GLOBAL_MULTIPLE_ANSWER: if ($from_database) { $choice = array(); $sql = "SELECT answer FROM {$TBL_TRACK_ATTEMPT}\n WHERE exe_id = '" . $exeId . "' AND question_id= '" . $questionId . "'"; $resultans = Database::query($sql); while ($row = Database::fetch_array($resultans)) { $ind = $row['answer']; $choice[$ind] = 1; } $studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : null; $real_answers[$answerId] = (bool) $studentChoice; if ($studentChoice) { $questionScore += $answerWeighting; } } else { $studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : null; if (isset($studentChoice)) { $questionScore += $answerWeighting; } $real_answers[$answerId] = (bool) $studentChoice; } $totalScore += $answerWeighting; if ($debug) { error_log("studentChoice: {$studentChoice}"); } break; case MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE: if ($from_database) { $sql = "SELECT answer FROM " . $TBL_TRACK_ATTEMPT . "\n WHERE exe_id = {$exeId} AND question_id= " . $questionId; $resultans = Database::query($sql); while ($row = Database::fetch_array($resultans)) { $ind = $row['answer']; $result = explode(':', $ind); if (isset($result[0])) { $my_answer_id = isset($result[0]) ? $result[0] : ''; $option = isset($result[1]) ? $result[1] : ''; $choice[$my_answer_id] = $option; } } $studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : ''; if ($answerCorrect == $studentChoice) { //$answerCorrect = 1; $real_answers[$answerId] = true; } else { //$answerCorrect = 0; $real_answers[$answerId] = false; } } else { $studentChoice = $choice[$answerAutoId]; if ($answerCorrect == $studentChoice) { //$answerCorrect = 1; $real_answers[$answerId] = true; } else { //$answerCorrect = 0; $real_answers[$answerId] = false; } } break; case MULTIPLE_ANSWER_COMBINATION: if ($from_database) { $sql = "SELECT answer FROM {$TBL_TRACK_ATTEMPT}\n WHERE exe_id = {$exeId} AND question_id= {$questionId}"; $resultans = Database::query($sql); while ($row = Database::fetch_array($resultans)) { $ind = $row['answer']; $choice[$ind] = 1; } $studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : null; if ($answerCorrect == 1) { if ($studentChoice) { $real_answers[$answerId] = true; } else { $real_answers[$answerId] = false; } } else { if ($studentChoice) { $real_answers[$answerId] = false; } else { $real_answers[$answerId] = true; } } } else { $studentChoice = isset($choice[$answerAutoId]) ? $choice[$answerAutoId] : null; if ($answerCorrect == 1) { if ($studentChoice) { $real_answers[$answerId] = true; } else { $real_answers[$answerId] = false; } } else { if ($studentChoice) { $real_answers[$answerId] = false; } else { $real_answers[$answerId] = true; } } } break; case FILL_IN_BLANKS: $str = ''; if ($from_database) { $sql = "SELECT answer\n FROM {$TBL_TRACK_ATTEMPT}\n WHERE\n exe_id = {$exeId} AND\n question_id= " . intval($questionId); $result = Database::query($sql); $str = Database::result($result, 0, 'answer'); } if ($saved_results == false && strpos($str, 'font color') !== false) { // the question is encoded like this // [A] B [C] D [E] F::10,10,10@1 // number 1 before the "@" means that is a switchable fill in blank question // [A] B [C] D [E] F::10,10,10@ or [A] B [C] D [E] F::10,10,10 // means that is a normal fill blank question // first we explode the "::" $pre_array = explode('::', $answer); // is switchable fill blank or not $last = count($pre_array) - 1; $is_set_switchable = explode('@', $pre_array[$last]); $switchable_answer_set = false; if (isset($is_set_switchable[1]) && $is_set_switchable[1] == 1) { $switchable_answer_set = true; } $answer = ''; for ($k = 0; $k < $last; $k++) { $answer .= $pre_array[$k]; } // splits weightings that are joined with a comma $answerWeighting = explode(',', $is_set_switchable[0]); // we save the answer because it will be modified $temp = $answer; $answer = ''; $j = 0; //initialise answer tags $user_tags = $correct_tags = $real_text = array(); // the loop will stop at the end of the text while (1) { // quits the loop if there are no more blanks (detect '[') if (($pos = api_strpos($temp, '[')) === false) { // adds the end of the text $answer = $temp; $real_text[] = $answer; break; //no more "blanks", quit the loop } // adds the piece of text that is before the blank //and ends with '[' into a general storage array $real_text[] = api_substr($temp, 0, $pos + 1); $answer .= api_substr($temp, 0, $pos + 1); //take the string remaining (after the last "[" we found) $temp = api_substr($temp, $pos + 1); // quit the loop if there are no more blanks, and update $pos to the position of next ']' if (($pos = api_strpos($temp, ']')) === false) { // adds the end of the text $answer .= $temp; break; } if ($from_database) { $queryfill = "SELECT answer FROM " . $TBL_TRACK_ATTEMPT . "\n WHERE\n exe_id = '" . $exeId . "' AND\n question_id= " . intval($questionId) . ""; $resfill = Database::query($queryfill); $str = Database::result($resfill, 0, 'answer'); api_preg_match_all('#\\[([^[]*)\\]#', $str, $arr); $str = str_replace('\\r\\n', '', $str); $choice = $arr[1]; if (isset($choice[$j])) { $tmp = api_strrpos($choice[$j], ' / '); $choice[$j] = api_substr($choice[$j], 0, $tmp); $choice[$j] = trim($choice[$j]); // Needed to let characters ' and " to work as part of an answer $choice[$j] = stripslashes($choice[$j]); } else { $choice[$j] = null; } } else { // This value is the user input, not escaped while correct answer is escaped by fckeditor $choice[$j] = api_htmlentities(trim($choice[$j])); } $user_tags[] = $choice[$j]; //put the contents of the [] answer tag into correct_tags[] $correct_tags[] = api_substr($temp, 0, $pos); $j++; $temp = api_substr($temp, $pos + 1); } $answer = ''; $real_correct_tags = $correct_tags; $chosen_list = array(); for ($i = 0; $i < count($real_correct_tags); $i++) { if ($i == 0) { $answer .= $real_text[0]; } if (!$switchable_answer_set) { // Needed to parse ' and " characters $user_tags[$i] = stripslashes($user_tags[$i]); if ($correct_tags[$i] == $user_tags[$i]) { // gives the related weighting to the student $questionScore += $answerWeighting[$i]; // increments total score $totalScore += $answerWeighting[$i]; // adds the word in green at the end of the string $answer .= $correct_tags[$i]; } elseif (!empty($user_tags[$i])) { // else if the word entered by the student IS NOT the same as the one defined by the professor // adds the word in red at the end of the string, and strikes it $answer .= '<font color="red"><s>' . $user_tags[$i] . '</s></font>'; } else { // adds a tabulation if no word has been typed by the student $answer .= ''; // remove that causes issue } } else { // switchable fill in the blanks if (in_array($user_tags[$i], $correct_tags)) { $chosen_list[] = $user_tags[$i]; $correct_tags = array_diff($correct_tags, $chosen_list); // gives the related weighting to the student $questionScore += $answerWeighting[$i]; // increments total score $totalScore += $answerWeighting[$i]; // adds the word in green at the end of the string $answer .= $user_tags[$i]; } elseif (!empty($user_tags[$i])) { // else if the word entered by the student IS NOT the same as the one defined by the professor // adds the word in red at the end of the string, and strikes it $answer .= '<font color="red"><s>' . $user_tags[$i] . '</s></font>'; } else { // adds a tabulation if no word has been typed by the student $answer .= ''; // remove that causes issue } } // adds the correct word, followed by ] to close the blank $answer .= ' / <font color="green"><b>' . $real_correct_tags[$i] . '</b></font>]'; if (isset($real_text[$i + 1])) { $answer .= $real_text[$i + 1]; } } } else { // insert the student result in the track_e_attempt table, field answer // $answer is the answer like in the c_quiz_answer table for the question // student data are choice[] $listCorrectAnswers = FillBlanks::getAnswerInfo($answer); $switchableAnswerSet = $listCorrectAnswers["switchable"]; $answerWeighting = $listCorrectAnswers["tabweighting"]; // user choices is an array $choice // get existing user data in n the BDD if ($from_database) { $sql = "SELECT answer\n FROM {$TBL_TRACK_ATTEMPT}\n WHERE\n exe_id = {$exeId} AND\n question_id= " . intval($questionId); $result = Database::query($sql); $str = Database::result($result, 0, 'answer'); $listStudentResults = FillBlanks::getAnswerInfo($str, true); $choice = $listStudentResults['studentanswer']; } // loop other all blanks words if (!$switchableAnswerSet) { // not switchable answer, must be in the same place than teacher order for ($i = 0; $i < count($listCorrectAnswers['tabwords']); $i++) { $studentAnswer = isset($choice[$i]) ? trim($choice[$i]) : ''; // This value is the user input, not escaped while correct answer is escaped by fckeditor // Works with cyrillic alphabet and when using ">" chars see #7718 #7610 #7618 if (!$from_database) { $studentAnswer = htmlentities(api_utf8_encode($studentAnswer)); } $correctAnswer = $listCorrectAnswers['tabwords'][$i]; $isAnswerCorrect = 0; if (FillBlanks::isGoodStudentAnswer($studentAnswer, $correctAnswer)) { // gives the related weighting to the student $questionScore += $answerWeighting[$i]; // increments total score $totalScore += $answerWeighting[$i]; $isAnswerCorrect = 1; } $listCorrectAnswers['studentanswer'][$i] = $studentAnswer; $listCorrectAnswers['studentscore'][$i] = $isAnswerCorrect; } } else { // switchable answer $listStudentAnswerTemp = $choice; $listTeacherAnswerTemp = $listCorrectAnswers['tabwords']; // for every teacher answer, check if there is a student answer for ($i = 0; $i < count($listStudentAnswerTemp); $i++) { $studentAnswer = trim($listStudentAnswerTemp[$i]); $found = false; for ($j = 0; $j < count($listTeacherAnswerTemp); $j++) { $correctAnswer = $listTeacherAnswerTemp[$j]; if (!$found) { if (FillBlanks::isGoodStudentAnswer($studentAnswer, $correctAnswer)) { $questionScore += $answerWeighting[$i]; $totalScore += $answerWeighting[$i]; $listTeacherAnswerTemp[$j] = ""; $found = true; } } } $listCorrectAnswers['studentanswer'][$i] = $studentAnswer; if (!$found) { $listCorrectAnswers['studentscore'][$i] = 0; } else { $listCorrectAnswers['studentscore'][$i] = 1; } } } $answer = FillBlanks::getAnswerInStudentAttempt($listCorrectAnswers); } break; // for calculated answer // for calculated answer case CALCULATED_ANSWER: $calculatedAnswer = Session::read('calculatedAnswerId'); $answer = $objAnswerTmp->selectAnswer($calculatedAnswer[$questionId]); $preArray = explode('@@', $answer); $last = count($preArray) - 1; $answer = ''; for ($k = 0; $k < $last; $k++) { $answer .= $preArray[$k]; } $answerWeighting = array($answerWeighting); // we save the answer because it will be modified $temp = $answer; $answer = ''; $j = 0; //initialise answer tags $userTags = $correctTags = $realText = array(); // the loop will stop at the end of the text while (1) { // quits the loop if there are no more blanks (detect '[') if (($pos = api_strpos($temp, '[')) === false) { // adds the end of the text $answer = $temp; $realText[] = $answer; break; //no more "blanks", quit the loop } // adds the piece of text that is before the blank //and ends with '[' into a general storage array $realText[] = api_substr($temp, 0, $pos + 1); $answer .= api_substr($temp, 0, $pos + 1); //take the string remaining (after the last "[" we found) $temp = api_substr($temp, $pos + 1); // quit the loop if there are no more blanks, and update $pos to the position of next ']' if (($pos = api_strpos($temp, ']')) === false) { // adds the end of the text $answer .= $temp; break; } if ($from_database) { $queryfill = "SELECT answer FROM " . $TBL_TRACK_ATTEMPT . "\n WHERE\n exe_id = '" . $exeId . "' AND\n question_id= " . intval($questionId) . ""; $resfill = Database::query($queryfill); $str = Database::result($resfill, 0, 'answer'); api_preg_match_all('#\\[([^[]*)\\]#', $str, $arr); $str = str_replace('\\r\\n', '', $str); $choice = $arr[1]; if (isset($choice[$j])) { $tmp = api_strrpos($choice[$j], ' / '); $choice[$j] = api_substr($choice[$j], 0, $tmp); $choice[$j] = trim($choice[$j]); // Needed to let characters ' and " to work as part of an answer $choice[$j] = stripslashes($choice[$j]); } else { $choice[$j] = null; } } else { // This value is the user input, not escaped while correct answer is escaped by fckeditor $choice[$j] = api_htmlentities(trim($choice[$j])); } $userTags[] = $choice[$j]; //put the contents of the [] answer tag into correct_tags[] $correctTags[] = api_substr($temp, 0, $pos); $j++; $temp = api_substr($temp, $pos + 1); } $answer = ''; $realCorrectTags = $correctTags; for ($i = 0; $i < count($realCorrectTags); $i++) { if ($i == 0) { $answer .= $realText[0]; } // Needed to parse ' and " characters $userTags[$i] = stripslashes($userTags[$i]); if ($correctTags[$i] == $userTags[$i]) { // gives the related weighting to the student $questionScore += $answerWeighting[$i]; // increments total score $totalScore += $answerWeighting[$i]; // adds the word in green at the end of the string $answer .= $correctTags[$i]; } elseif (!empty($userTags[$i])) { // else if the word entered by the student IS NOT the same as the one defined by the professor // adds the word in red at the end of the string, and strikes it $answer .= '<font color="red"><s>' . $userTags[$i] . '</s></font>'; } else { // adds a tabulation if no word has been typed by the student $answer .= ''; // remove that causes issue } // adds the correct word, followed by ] to close the blank $answer .= ' / <font color="green"><b>' . $realCorrectTags[$i] . '</b></font>]'; if (isset($realText[$i + 1])) { $answer .= $realText[$i + 1]; } } break; // for free answer // for free answer case FREE_ANSWER: if ($from_database) { $query = "SELECT answer, marks FROM " . $TBL_TRACK_ATTEMPT . "\n WHERE exe_id = '" . $exeId . "' AND question_id= '" . $questionId . "'"; $resq = Database::query($query); $data = Database::fetch_array($resq); $choice = $data['answer']; $choice = str_replace('\\r\\n', '', $choice); $choice = stripslashes($choice); $questionScore = $data['marks']; if ($questionScore == -1) { $totalScore += 0; } else { $totalScore += $questionScore; } if ($questionScore == '') { $questionScore = 0; } $arrques = $questionName; $arrans = $choice; } else { $studentChoice = $choice; if ($studentChoice) { //Fixing negative puntation see #2193 $questionScore = 0; $totalScore += 0; } } break; case ORAL_EXPRESSION: if ($from_database) { $query = "SELECT answer, marks FROM " . $TBL_TRACK_ATTEMPT . "\n WHERE exe_id = '" . $exeId . "' AND question_id= '" . $questionId . "'"; $resq = Database::query($query); $choice = Database::result($resq, 0, 'answer'); $choice = str_replace('\\r\\n', '', $choice); $choice = stripslashes($choice); $questionScore = Database::result($resq, 0, "marks"); if ($questionScore == -1) { $totalScore += 0; } else { $totalScore += $questionScore; } $arrques = $questionName; $arrans = $choice; } else { $studentChoice = $choice; if ($studentChoice) { //Fixing negative puntation see #2193 $questionScore = 0; $totalScore += 0; } } break; case DRAGGABLE: //no break //no break case MATCHING_DRAGGABLE: //no break //no break case MATCHING: if ($from_database) { $sql = 'SELECT id, answer, id_auto FROM ' . $table_ans . ' WHERE c_id = ' . $course_id . ' AND question_id = "' . $questionId . '" AND correct = 0'; $res_answer = Database::query($sql); // Getting the real answer $real_list = array(); while ($real_answer = Database::fetch_array($res_answer)) { $real_list[$real_answer['id_auto']] = $real_answer['answer']; } $sql = 'SELECT id, answer, correct, id_auto, ponderation FROM ' . $table_ans . ' WHERE c_id = ' . $course_id . ' AND question_id="' . $questionId . '" AND correct <> 0 ORDER BY id_auto'; $res_answers = Database::query($sql); $questionScore = 0; while ($a_answers = Database::fetch_array($res_answers)) { $i_answer_id = $a_answers['id']; //3 $s_answer_label = $a_answers['answer']; // your daddy - your mother $i_answer_correct_answer = $a_answers['correct']; //1 - 2 $i_answer_id_auto = $a_answers['id_auto']; // 3 - 4 $sql = "SELECT answer FROM {$TBL_TRACK_ATTEMPT}\n WHERE\n exe_id = '{$exeId}' AND\n question_id = '{$questionId}' AND\n position = '{$i_answer_id_auto}'"; $res_user_answer = Database::query($sql); if (Database::num_rows($res_user_answer) > 0) { // rich - good looking $s_user_answer = Database::result($res_user_answer, 0, 0); } else { $s_user_answer = 0; } $i_answerWeighting = $a_answers['ponderation']; $user_answer = ''; if (!empty($s_user_answer)) { if ($answerType == DRAGGABLE) { if ($s_user_answer == $i_answer_correct_answer) { $questionScore += $i_answerWeighting; $totalScore += $i_answerWeighting; $user_answer = Display::label(get_lang('Correct'), 'success'); } else { $user_answer = Display::label(get_lang('Incorrect'), 'danger'); } } else { if ($s_user_answer == $i_answer_correct_answer) { $questionScore += $i_answerWeighting; $totalScore += $i_answerWeighting; if (isset($real_list[$i_answer_id])) { $user_answer = Display::span($real_list[$i_answer_id]); } } else { $user_answer = Display::span($real_list[$s_user_answer], ['style' => 'color: #FF0000; text-decoration: line-through;']); } } } elseif ($answerType == DRAGGABLE) { $user_answer = Display::label(get_lang('Incorrect'), 'danger'); } if ($show_result) { echo '<tr>'; echo '<td>' . $s_answer_label . '</td>'; echo '<td>' . $user_answer; if (in_array($answerType, [MATCHING, MATCHING_DRAGGABLE])) { if (isset($real_list[$i_answer_correct_answer])) { echo Display::span($real_list[$i_answer_correct_answer], ['style' => 'color: #008000; font-weight: bold;']); } } echo '</td>'; echo '</tr>'; } } break 2; // break the switch and the "for" condition } else { if ($answerCorrect) { if (isset($choice[$answerAutoId]) && $answerCorrect == $choice[$answerAutoId]) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; $user_answer = Display::span($answerMatching[$choice[$answerAutoId]]); } else { if (isset($answerMatching[$choice[$answerAutoId]])) { $user_answer = Display::span($answerMatching[$choice[$answerAutoId]], ['style' => 'color: #FF0000; text-decoration: line-through;']); } } $matching[$answerAutoId] = $choice[$answerAutoId]; } break; } case HOT_SPOT: if ($from_database) { $TBL_TRACK_HOTSPOT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT); $sql = "SELECT hotspot_correct\n FROM {$TBL_TRACK_HOTSPOT}\n WHERE\n hotspot_exe_id = '" . $exeId . "' AND\n hotspot_question_id= '" . $questionId . "' AND\n hotspot_answer_id = " . intval($answerAutoId) . ""; $result = Database::query($sql); $studentChoice = Database::result($result, 0, "hotspot_correct"); if ($studentChoice) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; } } else { if (!isset($choice[$answerAutoId])) { $choice[$answerAutoId] = 0; } else { $studentChoice = $choice[$answerAutoId]; $choiceIsValid = false; if (!empty($studentChoice)) { $hotspotType = $objAnswerTmp->selectHotspotType($answerId); $hotspotCoordinates = $objAnswerTmp->selectHotspotCoordinates($answerId); $choicePoint = Geometry::decodePoint($studentChoice); switch ($hotspotType) { case 'square': $hotspotProperties = Geometry::decodeSquare($hotspotCoordinates); $choiceIsValid = Geometry::pointIsInSquare($hotspotProperties, $choicePoint); break; case 'circle': $hotspotProperties = Geometry::decodeEllipse($hotspotCoordinates); $choiceIsValid = Geometry::pointIsInEllipse($hotspotProperties, $choicePoint); break; case 'poly': $hotspotProperties = Geometry::decodePolygon($hotspotCoordinates); $choiceIsValid = Geometry::pointIsInPolygon($hotspotProperties, $choicePoint); break; } } $choice[$answerAutoId] = 0; if ($choiceIsValid) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; $choice[$answerAutoId] = 1; } } } break; // @todo never added to chamilo //for hotspot with fixed order // @todo never added to chamilo //for hotspot with fixed order case HOT_SPOT_ORDER: $studentChoice = $choice['order'][$answerId]; if ($studentChoice == $answerId) { $questionScore += $answerWeighting; $totalScore += $answerWeighting; $studentChoice = true; } else { $studentChoice = false; } break; // for hotspot with delineation // for hotspot with delineation case HOT_SPOT_DELINEATION: if ($from_database) { // getting the user answer $TBL_TRACK_HOTSPOT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT); $query = "SELECT hotspot_correct, hotspot_coordinate\n FROM {$TBL_TRACK_HOTSPOT}\n WHERE\n hotspot_exe_id = '" . $exeId . "' AND\n hotspot_question_id= '" . $questionId . "' AND\n hotspot_answer_id='1'"; //by default we take 1 because it's a delineation $resq = Database::query($query); $row = Database::fetch_array($resq, 'ASSOC'); $choice = $row['hotspot_correct']; $user_answer = $row['hotspot_coordinate']; // THIS is very important otherwise the poly_compile will throw an error!! // round-up the coordinates $coords = explode('/', $user_answer); $user_array = ''; foreach ($coords as $coord) { list($x, $y) = explode(';', $coord); $user_array .= round($x) . ';' . round($y) . '/'; } $user_array = substr($user_array, 0, -1); } else { if (!empty($studentChoice)) { $newquestionList[] = $questionId; } if ($answerId === 1) { $studentChoice = $choice[$answerId]; $questionScore += $answerWeighting; if ($hotspot_delineation_result[1] == 1) { $totalScore += $answerWeighting; //adding the total } } } $_SESSION['hotspot_coord'][1] = $delineation_cord; $_SESSION['hotspot_dest'][1] = $answer_delineation_destination; break; } // end switch Answertype if ($show_result) { if ($debug) { error_log('show result ' . $show_result); } if ($from == 'exercise_result') { if ($debug) { error_log('Showing questions $from ' . $from); } //display answers (if not matching type, or if the answer is correct) if (!in_array($answerType, [MATCHING, DRAGGABLE, MATCHING_DRAGGABLE]) || $answerCorrect) { if (in_array($answerType, array(UNIQUE_ANSWER, UNIQUE_ANSWER_IMAGE, UNIQUE_ANSWER_NO_OPTION, MULTIPLE_ANSWER, MULTIPLE_ANSWER_COMBINATION, GLOBAL_MULTIPLE_ANSWER))) { //if ($origin != 'learnpath') { ExerciseShowFunctions::display_unique_or_multiple_answer($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, 0, 0, 0, $results_disabled); //} } elseif ($answerType == MULTIPLE_ANSWER_TRUE_FALSE) { //if ($origin!='learnpath') { ExerciseShowFunctions::display_multiple_answer_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, 0, $questionId, 0, $results_disabled); //} } elseif ($answerType == MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE) { // if ($origin!='learnpath') { ExerciseShowFunctions::display_multiple_answer_combination_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, 0, 0, 0, $results_disabled); //} } elseif ($answerType == FILL_IN_BLANKS) { //if ($origin!='learnpath') { ExerciseShowFunctions::display_fill_in_blanks_answer($feedback_type, $answer, 0, 0, $results_disabled); // } } elseif ($answerType == CALCULATED_ANSWER) { //if ($origin!='learnpath') { ExerciseShowFunctions::display_calculated_answer($feedback_type, $answer, 0, 0); // } } elseif ($answerType == FREE_ANSWER) { //if($origin != 'learnpath') { ExerciseShowFunctions::display_free_answer($feedback_type, $choice, $exeId, $questionId, $questionScore); //} } elseif ($answerType == ORAL_EXPRESSION) { // to store the details of open questions in an array to be used in mail //if ($origin != 'learnpath') { ExerciseShowFunctions::display_oral_expression_answer($feedback_type, $choice, 0, 0, $nano); //} } elseif ($answerType == HOT_SPOT) { //if ($origin != 'learnpath') { ExerciseShowFunctions::display_hotspot_answer($feedback_type, $answerId, $answer, $studentChoice, $answerComment, $results_disabled); // } } elseif ($answerType == HOT_SPOT_ORDER) { //if ($origin != 'learnpath') { ExerciseShowFunctions::display_hotspot_order_answer($feedback_type, $answerId, $answer, $studentChoice, $answerComment); //} } elseif ($answerType == HOT_SPOT_DELINEATION) { $user_answer = $_SESSION['exerciseResultCoordinates'][$questionId]; //round-up the coordinates $coords = explode('/', $user_answer); $user_array = ''; foreach ($coords as $coord) { list($x, $y) = explode(';', $coord); $user_array .= round($x) . ';' . round($y) . '/'; } $user_array = substr($user_array, 0, -1); if ($next) { $user_answer = $user_array; // we compare only the delineation not the other points $answer_question = $_SESSION['hotspot_coord'][1]; $answerDestination = $_SESSION['hotspot_dest'][1]; //calculating the area $poly_user = convert_coordinates($user_answer, '/'); $poly_answer = convert_coordinates($answer_question, '|'); $max_coord = poly_get_max($poly_user, $poly_answer); $poly_user_compiled = poly_compile($poly_user, $max_coord); $poly_answer_compiled = poly_compile($poly_answer, $max_coord); $poly_results = poly_result($poly_answer_compiled, $poly_user_compiled, $max_coord); $overlap = $poly_results['both']; $poly_answer_area = $poly_results['s1']; $poly_user_area = $poly_results['s2']; $missing = $poly_results['s1Only']; $excess = $poly_results['s2Only']; //$overlap = round(polygons_overlap($poly_answer,$poly_user)); // //this is an area in pixels if ($debug > 0) { error_log(__LINE__ . ' - Polygons results are ' . print_r($poly_results, 1), 0); } if ($overlap < 1) { //shortcut to avoid complicated calculations $final_overlap = 0; $final_missing = 100; $final_excess = 100; } else { // the final overlap is the percentage of the initial polygon // that is overlapped by the user's polygon $final_overlap = round((double) $overlap / (double) $poly_answer_area * 100); if ($debug > 1) { error_log(__LINE__ . ' - Final overlap is ' . $final_overlap, 0); } // the final missing area is the percentage of the initial polygon // that is not overlapped by the user's polygon $final_missing = 100 - $final_overlap; if ($debug > 1) { error_log(__LINE__ . ' - Final missing is ' . $final_missing, 0); } // the final excess area is the percentage of the initial polygon's size // that is covered by the user's polygon outside of the initial polygon $final_excess = round(((double) $poly_user_area - (double) $overlap) / (double) $poly_answer_area * 100); if ($debug > 1) { error_log(__LINE__ . ' - Final excess is ' . $final_excess, 0); } } //checking the destination parameters parsing the "@@" $destination_items = explode('@@', $answerDestination); $threadhold_total = $destination_items[0]; $threadhold_items = explode(';', $threadhold_total); $threadhold1 = $threadhold_items[0]; // overlap $threadhold2 = $threadhold_items[1]; // excess $threadhold3 = $threadhold_items[2]; //missing // if is delineation if ($answerId === 1) { //setting colors if ($final_overlap >= $threadhold1) { $overlap_color = true; //echo 'a'; } //echo $excess.'-'.$threadhold2; if ($final_excess <= $threadhold2) { $excess_color = true; //echo 'b'; } //echo '--------'.$missing.'-'.$threadhold3; if ($final_missing <= $threadhold3) { $missing_color = true; //echo 'c'; } // if pass if ($final_overlap >= $threadhold1 && $final_missing <= $threadhold3 && $final_excess <= $threadhold2) { $next = 1; //go to the oars $result_comment = get_lang('Acceptable'); $final_answer = 1; // do not update with update_exercise_attempt } else { $next = 0; $result_comment = get_lang('Unacceptable'); $comment = $answerDestination = $objAnswerTmp->selectComment(1); $answerDestination = $objAnswerTmp->selectDestination(1); //checking the destination parameters parsing the "@@" $destination_items = explode('@@', $answerDestination); } } elseif ($answerId > 1) { if ($objAnswerTmp->selectHotspotType($answerId) == 'noerror') { if ($debug > 0) { error_log(__LINE__ . ' - answerId is of type noerror', 0); } //type no error shouldn't be treated $next = 1; continue; } if ($debug > 0) { error_log(__LINE__ . ' - answerId is >1 so we\'re probably in OAR', 0); } //check the intersection between the oar and the user //echo 'user'; print_r($x_user_list); print_r($y_user_list); //echo 'official';print_r($x_list);print_r($y_list); //$result = get_intersection_data($x_list,$y_list,$x_user_list,$y_user_list); $inter = $result['success']; //$delineation_cord=$objAnswerTmp->selectHotspotCoordinates($answerId); $delineation_cord = $objAnswerTmp->selectHotspotCoordinates($answerId); $poly_answer = convert_coordinates($delineation_cord, '|'); $max_coord = poly_get_max($poly_user, $poly_answer); $poly_answer_compiled = poly_compile($poly_answer, $max_coord); $overlap = poly_touch($poly_user_compiled, $poly_answer_compiled, $max_coord); if ($overlap == false) { //all good, no overlap $next = 1; continue; } else { if ($debug > 0) { error_log(__LINE__ . ' - Overlap is ' . $overlap . ': OAR hit', 0); } $organs_at_risk_hit++; //show the feedback $next = 0; $comment = $answerDestination = $objAnswerTmp->selectComment($answerId); $answerDestination = $objAnswerTmp->selectDestination($answerId); $destination_items = explode('@@', $answerDestination); $try_hotspot = $destination_items[1]; $lp_hotspot = $destination_items[2]; $select_question_hotspot = $destination_items[3]; $url_hotspot = $destination_items[4]; } } } else { // the first delineation feedback if ($debug > 0) { error_log(__LINE__ . ' first', 0); } } } elseif (in_array($answerType, [MATCHING, MATCHING_DRAGGABLE])) { echo '<tr>'; echo Display::tag('td', $answerMatching[$answerId]); echo Display::tag('td', "{$user_answer} / " . Display::tag('strong', $answerMatching[$answerCorrect], ['style' => 'color: #008000; font-weight: bold;'])); echo '</tr>'; } } } else { if ($debug) { error_log('Showing questions $from ' . $from); } switch ($answerType) { case UNIQUE_ANSWER: case UNIQUE_ANSWER_IMAGE: case UNIQUE_ANSWER_NO_OPTION: case MULTIPLE_ANSWER: case GLOBAL_MULTIPLE_ANSWER: case MULTIPLE_ANSWER_COMBINATION: if ($answerId == 1) { ExerciseShowFunctions::display_unique_or_multiple_answer($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, $answerId, $results_disabled); } else { ExerciseShowFunctions::display_unique_or_multiple_answer($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, "", $results_disabled); } break; case MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE: if ($answerId == 1) { ExerciseShowFunctions::display_multiple_answer_combination_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, $answerId, $results_disabled); } else { ExerciseShowFunctions::display_multiple_answer_combination_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, "", $results_disabled); } break; case MULTIPLE_ANSWER_TRUE_FALSE: if ($answerId == 1) { ExerciseShowFunctions::display_multiple_answer_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, $answerId, $results_disabled); } else { ExerciseShowFunctions::display_multiple_answer_true_false($feedback_type, $answerType, $studentChoice, $answer, $answerComment, $answerCorrect, $exeId, $questionId, "", $results_disabled); } break; case FILL_IN_BLANKS: ExerciseShowFunctions::display_fill_in_blanks_answer($feedback_type, $answer, $exeId, $questionId, $results_disabled, $str); break; case CALCULATED_ANSWER: ExerciseShowFunctions::display_calculated_answer($feedback_type, $answer, $exeId, $questionId); break; case FREE_ANSWER: echo ExerciseShowFunctions::display_free_answer($feedback_type, $choice, $exeId, $questionId, $questionScore); break; case ORAL_EXPRESSION: echo '<tr> <td valign="top">' . ExerciseShowFunctions::display_oral_expression_answer($feedback_type, $choice, $exeId, $questionId, $nano) . '</td> </tr> </table>'; break; case HOT_SPOT: ExerciseShowFunctions::display_hotspot_answer($feedback_type, $answerId, $answer, $studentChoice, $answerComment, $results_disabled); break; case HOT_SPOT_DELINEATION: $user_answer = $user_array; if ($next) { //$tbl_track_e_hotspot = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT); // Save into db /* $sql = "INSERT INTO $tbl_track_e_hotspot ( * hotspot_user_id, * hotspot_course_code, * hotspot_exe_id, * hotspot_question_id, * hotspot_answer_id, * hotspot_correct, * hotspot_coordinate * ) VALUES ( * '".Database::escape_string($_user['user_id'])."', * '".Database::escape_string($_course['id'])."', * '".Database::escape_string($exeId)."', '".Database::escape_string($questionId)."', * '".Database::escape_string($answerId)."', * '".Database::escape_string($studentChoice)."', * '".Database::escape_string($user_array)."')"; $result = Database::query($sql,__FILE__,__LINE__); */ $user_answer = $user_array; // we compare only the delineation not the other points $answer_question = $_SESSION['hotspot_coord'][1]; $answerDestination = $_SESSION['hotspot_dest'][1]; //calculating the area $poly_user = convert_coordinates($user_answer, '/'); $poly_answer = convert_coordinates($answer_question, '|'); $max_coord = poly_get_max($poly_user, $poly_answer); $poly_user_compiled = poly_compile($poly_user, $max_coord); $poly_answer_compiled = poly_compile($poly_answer, $max_coord); $poly_results = poly_result($poly_answer_compiled, $poly_user_compiled, $max_coord); $overlap = $poly_results['both']; $poly_answer_area = $poly_results['s1']; $poly_user_area = $poly_results['s2']; $missing = $poly_results['s1Only']; $excess = $poly_results['s2Only']; //$overlap = round(polygons_overlap($poly_answer,$poly_user)); //this is an area in pixels if ($debug > 0) { error_log(__LINE__ . ' - Polygons results are ' . print_r($poly_results, 1), 0); } if ($overlap < 1) { //shortcut to avoid complicated calculations $final_overlap = 0; $final_missing = 100; $final_excess = 100; } else { // the final overlap is the percentage of the initial polygon that is overlapped by the user's polygon $final_overlap = round((double) $overlap / (double) $poly_answer_area * 100); if ($debug > 1) { error_log(__LINE__ . ' - Final overlap is ' . $final_overlap, 0); } // the final missing area is the percentage of the initial polygon that is not overlapped by the user's polygon $final_missing = 100 - $final_overlap; if ($debug > 1) { error_log(__LINE__ . ' - Final missing is ' . $final_missing, 0); } // the final excess area is the percentage of the initial polygon's size that is covered by the user's polygon outside of the initial polygon $final_excess = round(((double) $poly_user_area - (double) $overlap) / (double) $poly_answer_area * 100); if ($debug > 1) { error_log(__LINE__ . ' - Final excess is ' . $final_excess, 0); } } //checking the destination parameters parsing the "@@" $destination_items = explode('@@', $answerDestination); $threadhold_total = $destination_items[0]; $threadhold_items = explode(';', $threadhold_total); $threadhold1 = $threadhold_items[0]; // overlap $threadhold2 = $threadhold_items[1]; // excess $threadhold3 = $threadhold_items[2]; //missing // if is delineation if ($answerId === 1) { //setting colors if ($final_overlap >= $threadhold1) { $overlap_color = true; //echo 'a'; } //echo $excess.'-'.$threadhold2; if ($final_excess <= $threadhold2) { $excess_color = true; //echo 'b'; } //echo '--------'.$missing.'-'.$threadhold3; if ($final_missing <= $threadhold3) { $missing_color = true; //echo 'c'; } // if pass if ($final_overlap >= $threadhold1 && $final_missing <= $threadhold3 && $final_excess <= $threadhold2) { $next = 1; //go to the oars $result_comment = get_lang('Acceptable'); $final_answer = 1; // do not update with update_exercise_attempt } else { $next = 0; $result_comment = get_lang('Unacceptable'); $comment = $answerDestination = $objAnswerTmp->selectComment(1); $answerDestination = $objAnswerTmp->selectDestination(1); //checking the destination parameters parsing the "@@" $destination_items = explode('@@', $answerDestination); } } elseif ($answerId > 1) { if ($objAnswerTmp->selectHotspotType($answerId) == 'noerror') { if ($debug > 0) { error_log(__LINE__ . ' - answerId is of type noerror', 0); } //type no error shouldn't be treated $next = 1; continue; } if ($debug > 0) { error_log(__LINE__ . ' - answerId is >1 so we\'re probably in OAR', 0); } //check the intersection between the oar and the user //echo 'user'; print_r($x_user_list); print_r($y_user_list); //echo 'official';print_r($x_list);print_r($y_list); //$result = get_intersection_data($x_list,$y_list,$x_user_list,$y_user_list); $inter = $result['success']; //$delineation_cord=$objAnswerTmp->selectHotspotCoordinates($answerId); $delineation_cord = $objAnswerTmp->selectHotspotCoordinates($answerId); $poly_answer = convert_coordinates($delineation_cord, '|'); $max_coord = poly_get_max($poly_user, $poly_answer); $poly_answer_compiled = poly_compile($poly_answer, $max_coord); $overlap = poly_touch($poly_user_compiled, $poly_answer_compiled, $max_coord); if ($overlap == false) { //all good, no overlap $next = 1; continue; } else { if ($debug > 0) { error_log(__LINE__ . ' - Overlap is ' . $overlap . ': OAR hit', 0); } $organs_at_risk_hit++; //show the feedback $next = 0; $comment = $answerDestination = $objAnswerTmp->selectComment($answerId); $answerDestination = $objAnswerTmp->selectDestination($answerId); $destination_items = explode('@@', $answerDestination); $try_hotspot = $destination_items[1]; $lp_hotspot = $destination_items[2]; $select_question_hotspot = $destination_items[3]; $url_hotspot = $destination_items[4]; } } } else { // the first delineation feedback if ($debug > 0) { error_log(__LINE__ . ' first', 0); } } break; case HOT_SPOT_ORDER: ExerciseShowFunctions::display_hotspot_order_answer($feedback_type, $answerId, $answer, $studentChoice, $answerComment); break; case DRAGGABLE: //no break //no break case MATCHING_DRAGGABLE: //no break //no break case MATCHING: echo '<tr>'; echo Display::tag('td', $answerMatching[$answerId]); echo Display::tag('td', "{$user_answer} / " . Display::tag('strong', $answerMatching[$answerCorrect], ['style' => 'color: #008000; font-weight: bold;'])); echo '</tr>'; break; } } } if ($debug) { error_log(' ------ '); } } // end for that loops over all answers of the current question if ($debug) { error_log('-- end answer loop --'); } $final_answer = true; foreach ($real_answers as $my_answer) { if (!$my_answer) { $final_answer = false; } } //we add the total score after dealing with the answers if ($answerType == MULTIPLE_ANSWER_COMBINATION || $answerType == MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE) { if ($final_answer) { //getting only the first score where we save the weight of all the question $answerWeighting = $objAnswerTmp->selectWeighting(1); $questionScore += $answerWeighting; $totalScore += $answerWeighting; } } //Fixes multiple answer question in order to be exact //if ($answerType == MULTIPLE_ANSWER || $answerType == GLOBAL_MULTIPLE_ANSWER) { /* if ($answerType == GLOBAL_MULTIPLE_ANSWER) { $diff = @array_diff($answer_correct_array, $real_answers); // All good answers or nothing works like exact $counter = 1; $correct_answer = true; foreach ($real_answers as $my_answer) { if ($debug) error_log(" my_answer: $my_answer answer_correct_array[counter]: ".$answer_correct_array[$counter]); if ($my_answer != $answer_correct_array[$counter]) { $correct_answer = false; break; } $counter++; } if ($debug) error_log(" answer_correct_array: ".print_r($answer_correct_array, 1).""); if ($debug) error_log(" real_answers: ".print_r($real_answers, 1).""); if ($debug) error_log(" correct_answer: ".$correct_answer); if ($correct_answer == false) { $questionScore = 0; } // This makes the result non exact if (!empty($diff)) { $questionScore = 0; } }*/ $extra_data = array('final_overlap' => $final_overlap, 'final_missing' => $final_missing, 'final_excess' => $final_excess, 'overlap_color' => $overlap_color, 'missing_color' => $missing_color, 'excess_color' => $excess_color, 'threadhold1' => $threadhold1, 'threadhold2' => $threadhold2, 'threadhold3' => $threadhold3); if ($from == 'exercise_result') { // if answer is hotspot. To the difference of exercise_show.php, // we use the results from the session (from_db=0) // TODO Change this, because it is wrong to show the user // some results that haven't been stored in the database yet if ($answerType == HOT_SPOT || $answerType == HOT_SPOT_ORDER || $answerType == HOT_SPOT_DELINEATION) { if ($debug) { error_log('$from AND this is a hotspot kind of question '); } $my_exe_id = 0; $from_database = 0; if ($answerType == HOT_SPOT_DELINEATION) { if (0) { if ($overlap_color) { $overlap_color = 'green'; } else { $overlap_color = 'red'; } if ($missing_color) { $missing_color = 'green'; } else { $missing_color = 'red'; } if ($excess_color) { $excess_color = 'green'; } else { $excess_color = 'red'; } if (!is_numeric($final_overlap)) { $final_overlap = 0; } if (!is_numeric($final_missing)) { $final_missing = 0; } if (!is_numeric($final_excess)) { $final_excess = 0; } if ($final_overlap > 100) { $final_overlap = 100; } $table_resume = '<table class="data_table"> <tr class="row_odd" > <td></td> <td ><b>' . get_lang('Requirements') . '</b></td> <td><b>' . get_lang('YourAnswer') . '</b></td> </tr> <tr class="row_even"> <td><b>' . get_lang('Overlap') . '</b></td> <td>' . get_lang('Min') . ' ' . $threadhold1 . '</td> <td><div style="color:' . $overlap_color . '">' . ($final_overlap < 0 ? 0 : intval($final_overlap)) . '</div></td> </tr> <tr> <td><b>' . get_lang('Excess') . '</b></td> <td>' . get_lang('Max') . ' ' . $threadhold2 . '</td> <td><div style="color:' . $excess_color . '">' . ($final_excess < 0 ? 0 : intval($final_excess)) . '</div></td> </tr> <tr class="row_even"> <td><b>' . get_lang('Missing') . '</b></td> <td>' . get_lang('Max') . ' ' . $threadhold3 . '</td> <td><div style="color:' . $missing_color . '">' . ($final_missing < 0 ? 0 : intval($final_missing)) . '</div></td> </tr> </table>'; if ($next == 0) { $try = $try_hotspot; $lp = $lp_hotspot; $destinationid = $select_question_hotspot; $url = $url_hotspot; } else { //show if no error //echo 'no error'; $comment = $answerComment = $objAnswerTmp->selectComment($nbrAnswers); $answerDestination = $objAnswerTmp->selectDestination($nbrAnswers); } echo '<h1><div style="color:#333;">' . get_lang('Feedback') . '</div></h1> <p style="text-align:center">'; $message = '<p>' . get_lang('YourDelineation') . '</p>'; $message .= $table_resume; $message .= '<br />' . get_lang('ResultIs') . ' ' . $result_comment . '<br />'; if ($organs_at_risk_hit > 0) { $message .= '<p><b>' . get_lang('OARHit') . '</b></p>'; } $message .= '<p>' . $comment . '</p>'; echo $message; } else { echo $hotspot_delineation_result[0]; //prints message $from_database = 1; // the hotspot_solution.swf needs this variable } //save the score attempts if (1) { //getting the answer 1 or 0 comes from exercise_submit_modal.php $final_answer = $hotspot_delineation_result[1]; if ($final_answer == 0) { $questionScore = 0; } // we always insert the answer_id 1 = delineation Event::saveQuestionAttempt($questionScore, 1, $quesId, $exeId, 0); //in delineation mode, get the answer from $hotspot_delineation_result[1] Event::saveExerciseAttemptHotspot($exeId, $quesId, 1, $hotspot_delineation_result[1], $exerciseResultCoordinates[$quesId]); } else { if ($final_answer == 0) { $questionScore = 0; $answer = 0; Event::saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0); if (is_array($exerciseResultCoordinates[$quesId])) { foreach ($exerciseResultCoordinates[$quesId] as $idx => $val) { Event::saveExerciseAttemptHotspot($exeId, $quesId, $idx, 0, $val); } } } else { Event::saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0); if (is_array($exerciseResultCoordinates[$quesId])) { foreach ($exerciseResultCoordinates[$quesId] as $idx => $val) { Event::saveExerciseAttemptHotspot($exeId, $quesId, $idx, $choice[$idx], $val); } } } } $my_exe_id = $exeId; } } if ($answerType == HOT_SPOT || $answerType == HOT_SPOT_ORDER) { // We made an extra table for the answers if ($show_result) { // if ($origin != 'learnpath') { echo '</table></td></tr>'; echo "\n <tr>\n <td colspan=\"2\">\n <p><em>" . get_lang('HotSpot') . "</em></p>\n <div id=\"hotspot-solution-{$questionId}\"></div>\n\n <script>\n \$(document).on('ready', function () {\n new HotspotQuestion({\n questionId: {$questionId},\n exerciseId: {$exeId},\n selector: '#hotspot-solution-{$questionId}',\n for: 'solution'\n });\n });\n </script>\n </td>\n </tr>\n "; // } } } //if ($origin != 'learnpath') { if ($show_result) { echo '</table>'; } // } } unset($objAnswerTmp); $totalWeighting += $questionWeighting; // Store results directly in the database // For all in one page exercises, the results will be // stored by exercise_results.php (using the session) if ($saved_results) { if ($debug) { error_log("Save question results {$saved_results}"); } if ($debug) { error_log(print_r($choice, 1)); } if (empty($choice)) { $choice = 0; } if ($answerType == MULTIPLE_ANSWER_TRUE_FALSE || $answerType == MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE) { if ($choice != 0) { $reply = array_keys($choice); for ($i = 0; $i < sizeof($reply); $i++) { $ans = $reply[$i]; Event::saveQuestionAttempt($questionScore, $ans . ':' . $choice[$ans], $quesId, $exeId, $i, $this->id); if ($debug) { error_log('result =>' . $questionScore . ' ' . $ans . ':' . $choice[$ans]); } } } else { Event::saveQuestionAttempt($questionScore, 0, $quesId, $exeId, 0, $this->id); } } elseif ($answerType == MULTIPLE_ANSWER || $answerType == GLOBAL_MULTIPLE_ANSWER) { if ($choice != 0) { $reply = array_keys($choice); if ($debug) { error_log("reply " . print_r($reply, 1) . ""); } for ($i = 0; $i < sizeof($reply); $i++) { $ans = $reply[$i]; Event::saveQuestionAttempt($questionScore, $ans, $quesId, $exeId, $i, $this->id); } } else { Event::saveQuestionAttempt($questionScore, 0, $quesId, $exeId, 0, $this->id); } } elseif ($answerType == MULTIPLE_ANSWER_COMBINATION) { if ($choice != 0) { $reply = array_keys($choice); for ($i = 0; $i < sizeof($reply); $i++) { $ans = $reply[$i]; Event::saveQuestionAttempt($questionScore, $ans, $quesId, $exeId, $i, $this->id); } } else { Event::saveQuestionAttempt($questionScore, 0, $quesId, $exeId, 0, $this->id); } } elseif (in_array($answerType, [MATCHING, DRAGGABLE, MATCHING_DRAGGABLE])) { if (isset($matching)) { foreach ($matching as $j => $val) { Event::saveQuestionAttempt($questionScore, $val, $quesId, $exeId, $j, $this->id); } } } elseif ($answerType == FREE_ANSWER) { $answer = $choice; Event::saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, $this->id); } elseif ($answerType == ORAL_EXPRESSION) { $answer = $choice; Event::saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, $this->id, $nano); } elseif (in_array($answerType, [UNIQUE_ANSWER, UNIQUE_ANSWER_IMAGE, UNIQUE_ANSWER_NO_OPTION])) { $answer = $choice; Event::saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, $this->id); // } elseif ($answerType == HOT_SPOT || $answerType == HOT_SPOT_DELINEATION) { } elseif ($answerType == HOT_SPOT) { $answer = []; if (isset($exerciseResultCoordinates[$questionId]) && !empty($exerciseResultCoordinates[$questionId])) { Database::delete(Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT), ['hotspot_exe_id = ? AND hotspot_question_id = ? AND c_id = ?' => [$exeId, $questionId, api_get_course_int_id()]]); foreach ($exerciseResultCoordinates[$questionId] as $idx => $val) { $answer[] = $val; Event::saveExerciseAttemptHotspot($exeId, $quesId, $idx, $choice[$idx], $val, false, $this->id); } } Event::saveQuestionAttempt($questionScore, implode('|', $answer), $quesId, $exeId, 0, $this->id); } else { Event::saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, $this->id); } } if ($propagate_neg == 0 && $questionScore < 0) { $questionScore = 0; } if ($saved_results) { $stat_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); $sql = 'UPDATE ' . $stat_table . ' SET exe_result = exe_result + ' . floatval($questionScore) . ' WHERE exe_id = ' . $exeId; if ($debug) { error_log($sql); } Database::query($sql); } $return_array = array('score' => $questionScore, 'weight' => $questionWeighting, 'extra' => $extra_data, 'open_question' => $arrques, 'open_answer' => $arrans, 'answer_type' => $answerType); return $return_array; }
/** * Searches a course, given a search string and a type of search box * @param string $needle Search string * @param string $type Type of search box ('single' or anything else) * @return string XajaxResponse * @assert ('abc', 'single') !== null * @assert ('abc', 'multiple') !== null */ public static function search_courses($needle, $type) { global $tbl_course, $tbl_session_rel_course, $id_session; $course_title = null; $xajax_response = new xajaxResponse(); $return = ''; if (!empty($needle) && !empty($type)) { // xajax send utf8 datas... datas in db can be non-utf8 datas $charset = api_get_system_encoding(); $needle = api_convert_encoding($needle, $charset, 'utf-8'); $cond_course_code = ''; if (!empty($id_session)) { $id_session = intval($id_session); // check course_code from session_rel_course table $sql = 'SELECT c_id FROM ' . $tbl_session_rel_course . ' WHERE session_id = ' . $id_session; $res = Database::query($sql); $course_codes = ''; if (Database::num_rows($res) > 0) { while ($row = Database::fetch_row($res)) { $course_codes .= '\'' . $row[0] . '\','; } $course_codes = substr($course_codes, 0, strlen($course_codes) - 1); $cond_course_code = ' AND course.id NOT IN(' . $course_codes . ') '; } } if ($type == 'single') { // search users where username or firstname or lastname begins likes $needle $sql = 'SELECT course.code, course.visual_code, course.title, session_rel_course.session_id FROM ' . $tbl_course . ' course LEFT JOIN ' . $tbl_session_rel_course . ' session_rel_course ON course.id = session_rel_course.c_id AND session_rel_course.session_id = ' . intval($id_session) . ' WHERE course.visual_code LIKE "' . $needle . '%" OR course.title LIKE "' . $needle . '%"'; } else { $sql = 'SELECT course.code, course.visual_code, course.title FROM ' . $tbl_course . ' course WHERE course.visual_code LIKE "' . $needle . '%" ' . $cond_course_code . ' ORDER BY course.code '; } if (api_is_multiple_url_enabled()) { $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); $access_url_id = api_get_current_access_url_id(); if ($access_url_id != -1) { if ($type == 'single') { $sql = 'SELECT course.code, course.visual_code, course.title, session_rel_course.session_id FROM ' . $tbl_course . ' course LEFT JOIN ' . $tbl_session_rel_course . ' session_rel_course ON course.id = session_rel_course.c_id AND session_rel_course.session_id = ' . intval($id_session) . ' INNER JOIN ' . $tbl_course_rel_access_url . ' url_course ON (url_course.c_id = course.id) WHERE access_url_id = ' . $access_url_id . ' AND (course.visual_code LIKE "' . $needle . '%" OR course.title LIKE "' . $needle . '%" )'; } else { $sql = 'SELECT course.code, course.visual_code, course.title FROM ' . $tbl_course . ' course, ' . $tbl_course_rel_access_url . ' url_course WHERE url_course.c_id = course.id AND access_url_id = ' . $access_url_id . ' AND course.visual_code LIKE "' . $needle . '%" ' . $cond_course_code . ' ORDER BY course.code '; } } } $rs = Database::query($sql); $course_list = array(); if ($type == 'single') { while ($course = Database::fetch_array($rs)) { $course_list[] = $course['code']; $course_title = str_replace("'", "\\'", $course_title); $return .= '<a href="javascript: void(0);" onclick="javascript: add_course_to_session(\'' . $course['code'] . '\',\'' . $course_title . ' (' . $course['visual_code'] . ')' . '\')">' . $course['title'] . ' (' . $course['visual_code'] . ')</a><br />'; } $xajax_response->addAssign('ajax_list_courses_single', 'innerHTML', api_utf8_encode($return)); } else { $return .= '<select id="origin" name="NoSessionCoursesList[]" multiple="multiple" size="20" style="width:340px;">'; while ($course = Database::fetch_array($rs)) { $course_list[] = $course['code']; $course_title = str_replace("'", "\\'", $course_title); $return .= '<option value="' . $course['code'] . '" title="' . htmlspecialchars($course['title'] . ' (' . $course['visual_code'] . ')', ENT_QUOTES) . '">' . $course['title'] . ' (' . $course['visual_code'] . ')</option>'; } $return .= '</select>'; $xajax_response->addAssign('ajax_list_courses_multiple', 'innerHTML', api_utf8_encode($return)); } } $_SESSION['course_list'] = $course_list; return $xajax_response; }
/** * Export the given HTML to PDF, using a global template * * @uses export/table_pdf.tpl * @param $content * @param bool|false $saveToFile * @param bool|false $returnHtml * * @return string */ public function html_to_pdf_with_template($content, $saveToFile = false, $returnHtml = false) { if (empty($this->template)) { $tpl = new Template('', false, false, false); } else { $tpl = $this->template; } // Assignments // Assignments $tpl->assign('pdf_content', $content); $organization = api_get_setting('Institution'); $img = api_get_path(SYS_CSS_PATH) . 'themes/' . api_get_visual_theme() . '/images/header-logo.png'; // Search for classic logo if (file_exists($img)) { $img = api_get_path(WEB_CSS_PATH) . 'themes/' . api_get_visual_theme() . '/images/header-logo.png'; $organization = "<img src='{$img}'>"; } else { // Just use the platform title. if (!empty($organization)) { $organization = '<h2 align="left">' . $organization . '</h2>'; } } // Use custom logo image. $pdfLogo = api_get_setting('pdf_logo_header'); if ($pdfLogo === 'true') { $visualTheme = api_get_visual_theme(); $img = api_get_path(SYS_CSS_PATH) . 'themes/' . $visualTheme . '/images/pdf_logo_header.png'; if (file_exists($img)) { $img = api_get_path(WEB_CSS_PATH) . 'themes/' . $visualTheme . '/images/pdf_logo_header.png'; $organization = "<img src='{$img}'>"; } } $tpl->assign('organization', $organization); //Showing only the current teacher/admin instead the all teacher list name see BT#4080 if (isset($this->params['show_real_course_teachers']) && $this->params['show_real_course_teachers']) { if (isset($this->params['session_info']) && !empty($this->params['session_info'])) { $teacher_list = SessionManager::getCoachesByCourseSessionToString($this->params['session_info']['id'], $this->params['course_info']['real_id']); } else { $teacher_list = CourseManager::get_teacher_list_from_course_code_to_string($this->params['course_code']); } } else { $user_info = api_get_user_info(); if ($this->params['show_teacher_as_myself']) { $teacher_list = $user_info['complete_name']; } } $tpl->assign('pdf_course', $this->params['course_code']); $tpl->assign('pdf_course_info', $this->params['course_info']); $tpl->assign('pdf_session_info', $this->params['session_info']); $tpl->assign('pdf_date', $this->params['pdf_date']); $tpl->assign('pdf_teachers', $teacher_list); $tpl->assign('pdf_title', $this->params['pdf_title']); $tpl->assign('pdf_student_info', $this->params['student_info']); $tpl->assign('show_grade_generated_date', $this->params['show_grade_generated_date']); $tpl->assign('add_signatures', $this->params['add_signatures']); // Getting template $tableTemplate = $tpl->get_template('export/table_pdf.tpl'); $html = $tpl->fetch($tableTemplate); $html = api_utf8_encode($html); $css_file = api_get_path(TO_SYS, WEB_CSS_PATH) . '/print.css'; $css = file_exists($css_file) ? @file_get_contents($css_file) : ''; $html = self::content_to_pdf($html, $css, $this->params['filename'], $this->params['course_code'], 'D', $saveToFile, null, $returnHtml); if ($returnHtml) { return $html; } }
/** * Note: Try to avoid using this function. Use api_preg_replace() with Perl-compatible regular expression syntax. * * Scans string for matches to pattern, then replaces the matched text with replacement, ignoring case, with extended multibyte support. * By default this function uses the platform character set. * @param string $pattern The regular expression pattern. * @param string $replacement The replacement text. * @param string $string The searched string. * @param string $option (optional) Matching condition. * If i is specified for the matching condition parameter, the case will be ignored. * If x is specified, white space will be ignored. * If m is specified, match will be executed in multiline mode and line break will be included in '.'. * If p is specified, match will be executed in POSIX mode, line break will be considered as normal character. * If e is specified, replacement string will be evaluated as PHP expression. * @return mixed The modified string is returned. If no matches are found within the string, then it will be returned unchanged. FALSE will be returned on error. * This function is aimed at replacing the functions eregi_replace() and mb_eregi_replace() for human-language strings. * @link http://php.net/manual/en/function.eregi-replace * @link http://php.net/manual/en/function.mb-eregi-replace */ function api_eregi_replace($pattern, $replacement, $string, $option = null) { $encoding = _api_mb_regex_encoding(); if (_api_mb_supports($encoding)) { if (is_null($option)) { return @mb_eregi_replace($pattern, $replacement, $string); } return @mb_eregi_replace($pattern, $replacement, $string, $option); } if (MBSTRING_INSTALLED && api_is_encoding_supported($encoding)) { _api_mb_regex_encoding('UTF-8'); if (is_null($option)) { $result = api_utf8_decode(@mb_eregi_replace(api_utf8_encode($pattern, $encoding), api_utf8_encode($replacement, $encoding), api_utf8_encode($string, $encoding)), $encoding); } else { $result = api_utf8_decode(@mb_eregi_replace(api_utf8_encode($pattern, $encoding), api_utf8_encode($replacement, $encoding), api_utf8_encode($string, $encoding), $option), $encoding); } _api_mb_regex_encoding($encoding); return $result; } return eregi_replace($pattern, $replacement, $string); }
/** * Export the given HTML to PDF, using a global template * @param string $content the HTML content * * @uses export/table_pdf.tpl */ public function html_to_pdf_with_template($content) { global $_configuration; Display :: display_no_header(); // Assignments Display::$global_template->assign('pdf_content', $content); $organization = api_get_setting('Institution'); $img = api_get_path(SYS_CODE_PATH).'css/'.api_get_visual_theme().'/images/header-logo.png'; // Search for classic logo if (file_exists($img)) { $img = api_get_path(WEB_CODE_PATH).'css/'.api_get_visual_theme().'/images/header-logo.png'; $organization = "<img src='$img'>"; } else { // Just use the platform title. if (!empty($organization)) { $organization = '<h2 align="left">'.$organization.'</h2>'; } } // Use custom logo image. if (isset($_configuration['pdf_logo_header']) && $_configuration['pdf_logo_header'] ) { $img = api_get_path(SYS_CODE_PATH).'css/'.api_get_visual_theme().'/images/pdf_logo_header.png'; if (file_exists($img)) { $img = api_get_path(WEB_CODE_PATH) . 'css/' . api_get_visual_theme() . '/images/pdf_logo_header.png'; $organization = "<img src='$img'>"; } } Display::$global_template->assign('organization', $organization); //Showing only the current teacher/admin instead the all teacher list name see BT#4080 if (isset($this->params['show_real_course_teachers']) && $this->params['show_real_course_teachers'] ) { if (isset($this->params['session_info']) && !empty($this->params['session_info']) ) { $teacher_list = SessionManager::getCoachesByCourseSessionToString( $this->params['session_info']['id'], $this->params['course_code'] ); } else { $teacher_list = CourseManager::get_teacher_list_from_course_code_to_string( $this->params['course_code'] ); } } else { $user_info = api_get_user_info(); $teacher_list = $user_info['complete_name']; } Display::$global_template->assign('pdf_course', $this->params['course_code']); Display::$global_template->assign('pdf_course_info', $this->params['course_info']); Display::$global_template->assign('pdf_session_info', $this->params['session_info']); Display::$global_template->assign('pdf_date', api_format_date(api_get_local_time(), DATE_TIME_FORMAT_LONG)); Display::$global_template->assign('pdf_teachers', $teacher_list); Display::$global_template->assign('pdf_title', $this->params['pdf_title']); Display::$global_template->assign('add_signatures', $this->params['add_signatures']); // Getting template $tpl = Display::$global_template->get_template('export/table_pdf.tpl'); $html = Display::$global_template->fetch($tpl); $html = api_utf8_encode($html); $css_file = api_get_path(TO_SYS, WEB_CSS_PATH).'/print.css'; $css = file_exists($css_file) ? @file_get_contents($css_file) : ''; self::content_to_pdf($html, $css, $this->params['filename'], $this->params['course_code']); }
function search_sessions($needle, $type) { global $session_in_promotion; $xajax_response = new xajaxResponse(); $return = ''; if (!empty($needle) && !empty($type)) { $session_list = SessionManager::get_sessions_list(array('s.name' => array('operator' => 'LIKE', 'value' => "{$needle}%"))); $return .= '<select id="session_not_in_promotion" name="session_not_in_promotion_name[]" multiple="multiple" size="15" style="width:360px;">'; foreach ($session_list as $row) { if (!in_array($row['id'], array_keys($session_in_promotion))) { $return .= '<option value="' . $row['id'] . '">' . $row['name'] . '</option>'; } } $return .= '</select>'; $xajax_response->addAssign('ajax_list_multiple', 'innerHTML', api_utf8_encode($return)); } return $xajax_response; }
function search_sessions($needle, $type) { global $elements_in; $xajax_response = new xajaxResponse(); $return = ''; if (!empty($needle) && !empty($type)) { if ($type == 'single') { // search users where username or firstname or lastname begins likes $needle /* $sql = 'SELECT user.user_id, username, lastname, firstname FROM '.$tbl_user.' user WHERE (username LIKE "'.$needle.'%" OR firstname LIKE "'.$needle.'%" OR lastname LIKE "'.$needle.'%") AND user.user_id<>"'.$user_anonymous.'" AND user.status<>'.DRH.''. $order_clause. ' LIMIT 11';*/ } else { if ($type == 'searchbox') { $session_list = SessionManager::get_sessions_list(array('s.name' => array('operator' => 'LIKE', 'value' => "%{$needle}%"))); } else { $session_list = SessionManager::get_sessions_list(array('s.name' => array('operator' => 'LIKE', 'value' => "{$needle}%"))); } } $i = 0; if ($type == 'single') { } else { $return .= '<select id="elements_not_in" name="elements_not_in_name[]" multiple="multiple" size="15" style="width:360px;">'; foreach ($session_list as $row) { if (!in_array($row['id'], array_keys($elements_in))) { $return .= '<option value="' . $row['id'] . '">' . $row['name'] . '</option>'; } } $return .= '</select>'; $xajax_response->addAssign('ajax_list_multiple', 'innerHTML', api_utf8_encode($return)); } } return $xajax_response; }
/** * @param $needle * @return xajaxResponse */ public static function searchUserGroupAjax($needle) { $response = new xajaxResponse(); $return = ''; if (!empty($needle)) { // xajax send utf8 datas... datas in db can be non-utf8 datas $charset = api_get_system_encoding(); $needle = api_convert_encoding($needle, $charset, 'utf-8'); $needle = Database::escape_string($needle); // search courses where username or firstname or lastname begins likes $needle $sql = 'SELECT id, name FROM ' . Database::get_main_table(TABLE_USERGROUP) . ' u WHERE name LIKE "' . $needle . '%" ORDER BY name LIMIT 11'; $result = Database::query($sql); $i = 0; while ($data = Database::fetch_array($result)) { $i++; if ($i <= 10) { $return .= '<a href="javascript: void(0);" onclick="javascript: add_user_to_url(\'' . addslashes($data['id']) . '\',\'' . addslashes($data['name']) . ' \')">' . $data['name'] . ' </a><br />'; } else { $return .= '...<br />'; } } } $response->addAssign('ajax_list_courses', 'innerHTML', api_utf8_encode($return)); return $response; }
function search_courses($id_session, $type) { global $tbl_course, $tbl_session_rel_course, $course_list; $xajax_response = new xajaxResponse(); $select_destination = ''; $return = null; if (!empty($type)) { $id_session = intval($id_session); if ($type == 'origin') { $course_list = SessionManager::get_course_list_by_session_id($id_session); $temp_course_list = array(); $return .= '<select id="origin" name="SessionCoursesListOrigin[]" class="form-control" onclick="javascript: checkSelected(this.id,\'copy_option_2\',\'title_option2\',\'destination\');">'; foreach ($course_list as $course) { $temp_course_list[] = "'{$course['code']}'"; $return .= '<option value="' . $course['code'] . '" title="' . @htmlspecialchars($course['title'] . ' (' . $course['visual_code'] . ')', ENT_QUOTES, api_get_system_encoding()) . '">' . $course['title'] . ' (' . $course['visual_code'] . ')</option>'; } $return .= '</select>'; $_SESSION['course_list'] = $temp_course_list; $_SESSION['session_origin'] = $id_session; // Build select for destination sessions where is not included current session from select origin if (!empty($id_session)) { $sessions = SessionManager::get_sessions_list(array(), array('name', 'ASC')); $select_destination .= '<select name="sessions_list_destination" class="form-control" onchange = "javascript: xajax_search_courses(this.value,\'destination\');">'; $select_destination .= '<option value = "0">-- ' . get_lang('SelectASession') . ' --</option>'; foreach ($sessions as $session) { if ($id_session == $session['id']) { continue; } if (!empty($session['category_name'])) { $session['category_name'] = ' (' . $session['category_name'] . ') '; } $select_destination .= '<option value="' . $session['id'] . '">' . $session['name'] . ' ' . $session['category_name'] . '</option>'; } $select_destination .= '</select>'; $xajax_response->addAssign('ajax_sessions_list_destination', 'innerHTML', api_utf8_encode($select_destination)); } else { $select_destination .= '<select name="sessions_list_destination" class="form-control" onchange = "javascript: xajax_search_courses(this.value,\'destination\');">'; $select_destination .= '<option value = "0">' . get_lang('ThereIsNotStillASession') . '</option>'; $select_destination .= '</select>'; $xajax_response->addAssign('ajax_sessions_list_destination', 'innerHTML', api_utf8_encode($select_destination)); } // Select multiple destination empty $select_multiple_empty = '<select id="destination" name="SessionCoursesListDestination[]" class="form-control"></select>'; // Send response by ajax $xajax_response->addAssign('ajax_list_courses_origin', 'innerHTML', api_utf8_encode($return)); $xajax_response->addAssign('ajax_list_courses_destination', 'innerHTML', api_utf8_encode($select_multiple_empty)); } else { //Left Select - Destination $list_courses_origin = implode(',', $_SESSION['course_list']); $session_origin = $_SESSION['session_origin']; // Search courses by id_session where course codes is include en courses list destination $sql = "SELECT c.code, c.visual_code, c.title, src.session_id\n FROM {$tbl_course} c, {$tbl_session_rel_course} src\n WHERE src.c_id = c.id\n AND src.session_id = '" . intval($id_session) . "'"; //AND c.code IN ($list_courses_origin)"; $rs = Database::query($sql); $course_list_destination = array(); $return .= '<select id="destination" name="SessionCoursesListDestination[]" class="form-control">'; while ($course = Database::fetch_array($rs)) { $course_list_destination[] = $course['code']; $return .= '<option value="' . $course['code'] . '" title="' . @htmlspecialchars($course['title'] . ' (' . $course['visual_code'] . ')', ENT_QUOTES, api_get_system_encoding()) . '">' . $course['title'] . ' (' . $course['visual_code'] . ')</option>'; } $return .= '</select>'; $_SESSION['course_list_destination'] = $course_list_destination; // Send response by ajax $xajax_response->addAssign('ajax_list_courses_destination', 'innerHTML', api_utf8_encode($return)); } } return $xajax_response; }