2 /************************************************************************/
4 /************************************************************************/
5 /* Copyright (c) 2002-2010 */
6 /* Inclusive Design Institute */
8 /* This program is free software. You can redistribute it and/or */
9 /* modify it under the terms of the GNU General Public License */
10 /* as published by the Free Software Foundation. */
11 /************************************************************************/
13 if (!defined('AT_INCLUDE_PATH')) { exit; }
15 function in_array_cin($strItem, $arItems)
17 foreach ($arItems as $key => $strValue)
19 if (strtoupper($strItem) == strtoupper($strValue))
29 //these are the _AT(x) variable names and their include file
30 /* tabs[tab_id] = array(tab_name, file_name, accesskey) */
31 $tabs[0] = array('content', 'edit.inc.php', 'n');
32 $tabs[1] = array('properties', 'properties.inc.php', 'p');
33 $tabs[2] = array('glossary_terms', 'glossary.inc.php', 'g');
34 //Silvia: Added to declare alternative resources
35 $tabs[3] = array('alternative_content', 'alternatives.inc.php', 'l');
36 //Harris: Extended test functionality into content export
37 $tabs[4] = array('tests', 'tests.inc.php', 't');
43 function output_tabs($current_tab, $changes) {
46 $num_tabs = count($tabs);
48 <br /><br /><table class="etabbed-table" border="0" cellpadding="0" cellspacing="0">
51 for ($i=0; $i < $num_tabs; $i++):
52 if ($current_tab == $i):?>
53 <td class="editor_tab_selected">
54 <?php if ($changes[$i]): ?>
55 <img src="<?php echo $_base_path; ?>images/changes_bullet.gif" alt="<?php echo _AT('usaved_changes_made'); ?>" height="12" width="15" />
57 <?php echo _AT($tabs[$i][0]); ?>
59 <td class="tab-spacer"> </td>
61 <td class="editor_tab">
62 <?php if ($changes[$i]): ?>
63 <img src="<?php echo $_base_path; ?>images/changes_bullet.gif" alt="<?php echo _AT('usaved_changes_made'); ?>" height="12" width="15" />
66 <?php echo '<input type="submit" name="button_'.$i.'" value="'._AT($tabs[$i][0]).'" title="'._AT($tabs[$i][0]).' - alt '.$tabs[$i][2].'" class="editor_buttontab" accesskey="'.$tabs[$i][2].'" onmouseover="this.style.cursor=\'pointer\';" '.$clickEvent.' />'; ?>
68 <td class="tab-spacer"> </td>
76 * Strips all tags and encodes special characters in the URL
77 * Returns false if the URL is invalid
80 * @return mixed - returns a stripped and encoded URL or false if URL is invalid
82 function isValidURL($url) {
83 if (substr($url,0,4) === 'http') {
84 return filter_var(filter_var($url, FILTER_SANITIZE_STRING), FILTER_VALIDATE_URL);
90 * Parse the primary resources out of the content and save into db.
91 * Clean up the removed primary resources from db.
92 * @param: $cid: content id
96 function populate_a4a($cid, $content, $formatting){
97 global $db, $my_files, $content_base_href, $contentManager;
99 // Defining alternatives is only available for content type "html".
100 // But don't clean up the a4a tables at other content types in case the user needs them back at html.
101 if ($formatting <> 1) return;
103 include_once(AT_INCLUDE_PATH.'../mods/_core/imsafa/classes/A4a.class.php');
104 include_once(AT_INCLUDE_PATH.'classes/XML/XML_HTMLSax/XML_HTMLSax.php'); /* for XML_HTMLSax */
105 include_once(AT_INCLUDE_PATH.'classes/ContentOutputParser.class.php'); /* for parser */
107 // initialize content_base_href; used in format_content
108 if (!isset($content_base_href)) {
109 $result = $contentManager->getContentPage($cid);
110 // return if the cid is not found
111 if (!($content_row = @mysql_fetch_assoc($result))) return;
112 $content_base_href = $content_row["content_path"].'/';
115 $body = format_content($content, $formatting,array());
117 $handler = new ContentOutputParser();
118 $parser = new XML_HTMLSax();
119 $parser->set_object($handler);
120 $parser->set_element_handler('openHandler','closeHandler');
123 $parser->parse($body);
124 $my_files = array_unique($my_files);
126 foreach ($my_files as $file) {
127 /* filter out full urls */
128 $url_parts = @parse_url($file);
130 // file should be relative to content
131 if ((substr($file, 0, 1) == '/')) {
135 // The URL of the movie from youtube.com has been converted above in embed_media().
136 // For example: http://www.youtube.com/watch?v=a0ryB0m0MiM is converted to
137 // http://www.youtube.com/v/a0ryB0m0MiM to make it playable. This creates the problem
138 // that the parsed-out url (http://www.youtube.com/v/a0ryB0m0MiM) does not match with
139 // the URL saved in content table (http://www.youtube.com/watch?v=a0ryB0m0MiM).
140 // The code below is to convert the URL back to original.
141 $file = convert_youtube_playURL_to_watchURL($file);
143 $resources[] = convert_amp($file); // converts & to &
146 $a4a = new A4a($cid);
147 $db_primary_resources = $a4a->getPrimaryResources();
149 // clean up the removed resources
150 foreach ($db_primary_resources as $primary_rid=>$db_resource){
151 //if this file from our table is not found in the $resource, then it's not used.
152 if(count($resources) == 0 || !in_array($db_resource['resource'], $resources)){
153 $a4a->deletePrimaryResource($primary_rid);
157 if (count($resources) == 0) return;
159 // insert the new resources
160 foreach($resources as $primary_resource)
162 if (!$a4a->getPrimaryResourceByName($primary_resource)){
163 $a4a->setPrimaryResource($cid, $primary_resource, $_SESSION['lang']);
168 // save all changes to the DB
169 function save_changes($redir, $current_tab) {
170 global $contentManager, $db, $addslashes, $msg, $stripslashes;
172 $_POST['pid'] = intval($_POST['pid']);
173 $_POST['cid'] = intval($_POST['cid']);
175 $_POST['alternatives'] = intval($_POST['alternatives']);
177 $_POST['title'] = trim($_POST['title']);
178 $_POST['head'] = trim($_POST['head']);
179 $_POST['use_customized_head'] = isset($_POST['use_customized_head'])?$_POST['use_customized_head']:0;
180 $_POST['body_text'] = $stripslashes(trim($_POST['body_text']));
181 $_POST['weblink_text'] = trim($_POST['weblink_text']);
182 $_POST['formatting'] = intval($_POST['formatting']);
183 $_POST['keywords'] = $stripslashes(trim($_POST['keywords']));
184 $_POST['test_message'] = trim($_POST['test_message']);
185 $_POST['allow_test_export'] = intval($_POST['allow_test_export']);
187 //if weblink is selected, use it
188 if ($_POST['formatting']==CONTENT_TYPE_WEBLINK) {
189 $url = $_POST['weblink_text'];
190 $validated_url = isValidURL($url);
191 if (!validated_url || $validated_url !== $url) {
192 $msg->addError(array('INVALID_INPUT', _AT('weblink')));
194 $_POST['body_text'] = $url;
195 $content_type_pref = CONTENT_TYPE_WEBLINK;
198 $content_type_pref = CONTENT_TYPE_CONTENT;
201 if (!($release_date = generate_release_date())) {
202 $msg->addError('BAD_DATE');
205 if ($_POST['title'] == '') {
206 $msg->addError(array('EMPTY_FIELDS', _AT('title')));
209 if (!$msg->containsErrors()) {
210 $orig_body_text = $_POST['body_text']; // used to populate a4a tables
212 $_POST['title'] = $addslashes($_POST['title']);
213 $_POST['body_text'] = $addslashes($_POST['body_text']);
214 $_POST['head'] = $addslashes($_POST['head']);
215 $_POST['keywords'] = $addslashes($_POST['keywords']);
216 $_POST['test_message'] = $addslashes($_POST['test_message']);
218 // add or edit content
220 /* editing an existing page */
221 $err = $contentManager->editContent($_POST['cid'], $_POST['title'], $_POST['body_text'],
222 $_POST['keywords'], $_POST['related'], $_POST['formatting'],
223 $release_date, $_POST['head'], $_POST['use_customized_head'],
224 $_POST['test_message'], $_POST['allow_test_export'], $content_type_pref);
225 $cid = $_POST['cid'];
229 $cid = $contentManager->addContent($_SESSION['course_id'],
236 $_POST['formatting'],
239 $_POST['use_customized_head'],
240 $_POST['test_message'],
241 $_POST['allow_test_export'],
243 $_POST['cid'] = $cid;
244 $_REQUEST['cid'] = $cid;
246 // re-populate a4a tables based on the new content
247 populate_a4a($cid, $orig_body_text, $_POST['formatting']);
251 /* insert glossary terms */
252 if (is_array($_POST['glossary_defs']) && ($num_terms = count($_POST['glossary_defs']))) {
253 global $glossary, $glossary_ids, $msg;
255 foreach($_POST['glossary_defs'] as $w => $d) {
257 $key = in_array_cin($w, $glossary_ids);
259 $d = $addslashes($d);
261 if (($key !== false) && (($glossary[$old_w] != $d) || isset($_POST['related_term'][$old_w])) ) {
263 $related_id = intval($_POST['related_term'][$old_w]);
264 $sql = "UPDATE ".TABLE_PREFIX."glossary SET definition='$d', related_word_id=$related_id WHERE word_id=$key AND course_id=$_SESSION[course_id]";
265 $result = mysql_query($sql, $db);
266 $glossary[$old_w] = $d;
267 } else if ($key === false && ($d != '')) {
269 $related_id = intval($_POST['related_term'][$old_w]);
270 $sql = "INSERT INTO ".TABLE_PREFIX."glossary VALUES (NULL, $_SESSION[course_id], '$w', '$d', $related_id)";
272 $result = mysql_query($sql, $db);
273 $glossary[$old_w] = $d;
277 if (isset($_GET['tab'])) {
278 $current_tab = intval($_GET['tab']);
280 if (isset($_POST['current_tab'])) {
281 $current_tab = intval($_POST['current_tab']);
284 // adapted content: save primary content type
285 if (isset($_POST['use_post_for_alt']))
287 // 1. delete old primary content type
288 $sql = "DELETE FROM ".TABLE_PREFIX."primary_resources_types
289 WHERE primary_resource_id in
290 (SELECT DISTINCT primary_resource_id
291 FROM ".TABLE_PREFIX."primary_resources
292 WHERE content_id=".$cid."
293 AND language_code='".$_SESSION['lang']."')";
294 $result = mysql_query($sql, $db);
296 // 2. insert the new primary content type
297 $sql = "SELECT pr.primary_resource_id, rt.type_id
298 FROM ".TABLE_PREFIX."primary_resources pr, ".
299 TABLE_PREFIX."resource_types rt
300 WHERE pr.content_id = ".$cid."
301 AND pr.language_code = '".$_SESSION['lang']."'";
302 $all_types_result = mysql_query($sql, $db);
304 while ($type = mysql_fetch_assoc($all_types_result)) {
305 if (isset($_POST['alt_'.$type['primary_resource_id'].'_'.$type['type_id']]))
307 $sql = "INSERT INTO ".TABLE_PREFIX."primary_resources_types (primary_resource_id, type_id)
308 VALUES (".$type['primary_resource_id'].", ".$type['type_id'].")";
309 $result = mysql_query($sql, $db);
314 //Add test to this content - @harris
315 $sql = 'SELECT * FROM '.TABLE_PREFIX."content_tests_assoc WHERE content_id=$_POST[cid]";
316 $result = mysql_query($sql, $db);
317 $db_test_array = array();
318 while ($row = mysql_fetch_assoc($result)) {
319 $db_test_array[] = $row['test_id'];
322 if (is_array($_POST['tid']) && sizeof($_POST['tid']) > 0){
323 $toBeDeleted = array_diff($db_test_array, $_POST['tid']);
324 $toBeAdded = array_diff($_POST['tid'], $db_test_array);
326 if (!empty($toBeDeleted)){
327 $tids = implode(",", $toBeDeleted);
328 $sql = 'DELETE FROM '. TABLE_PREFIX . "content_tests_assoc WHERE content_id=$_POST[cid] AND test_id IN ($tids)";
329 $result = mysql_query($sql, $db);
333 if (!empty($toBeAdded)){
334 foreach ($toBeAdded as $i => $tid){
336 $sql = 'INSERT INTO '. TABLE_PREFIX . "content_tests_assoc SET content_id=$_POST[cid], test_id=$tid";
337 $result = mysql_query($sql, $db);
338 if ($result===false){
339 $msg->addError('MYSQL_FAILED');
344 //All tests has been removed.
345 $sql = 'DELETE FROM '. TABLE_PREFIX . "content_tests_assoc WHERE content_id=$_POST[cid]";
346 $result = mysql_query($sql, $db);
351 $sql = "DELETE FROM ". TABLE_PREFIX . "content_prerequisites
352 WHERE content_id=".$_POST[cid]." AND type='".CONTENT_PRE_TEST."'";
353 $result = mysql_query($sql, $db);
355 if (is_array($_POST['pre_tid']) && sizeof($_POST['pre_tid']) > 0)
357 foreach ($_POST['pre_tid'] as $i => $tid){
359 $sql = "INSERT INTO ". TABLE_PREFIX . "content_prerequisites
360 SET content_id=".$_POST[cid].", type='".CONTENT_PRE_TEST."', item_id=$tid";
361 $result = mysql_query($sql, $db);
363 if ($result===false) $msg->addError('MYSQL_FAILED');
367 //TODO*******************BOLOGNA****************REMOVE ME**************/
368 if(isset($_SESSION['associated_forum']) && !$msg->containsErrors()){
369 if($_SESSION['associated_forum']=='none'){
370 $sql = "DELETE FROM ".TABLE_PREFIX."content_forums_assoc WHERE content_id='$_POST[cid]'";
371 mysql_query($sql,$db);
373 $sql = "DELETE FROM ".TABLE_PREFIX."content_forums_assoc WHERE content_id='$_POST[cid]'";
374 mysql_query($sql,$db);
375 $associated_forum = $_SESSION['associated_forum'];
376 for($i=0; $i<count($associated_forum); $i++){
377 $sql="INSERT INTO ".TABLE_PREFIX."content_forums_assoc SET content_id='$_POST[cid]',forum_id='$associated_forum[$i]'";
378 mysql_query($sql,$db);
381 unset($_SESSION['associated_forum']);
385 if (!$msg->containsErrors() && $redir) {
386 $_SESSION['save_n_close'] = $_POST['save_n_close'];
388 $msg->addFeedback('ACTION_COMPLETED_SUCCESSFULLY');
389 header('Location: '.basename($_SERVER['PHP_SELF']).'?cid='.$cid.SEP.'close='.$addslashes($_POST['save_n_close']).SEP.'tab='.$addslashes($_POST['current_tab']).SEP.'displayhead='.$addslashes($_POST['displayhead']).SEP.'alternatives='.$addslashes($_POST['alternatives']));
396 function generate_release_date($now = false) {
404 $day = intval($_POST['day']);
405 $month = intval($_POST['month']);
406 $year = intval($_POST['year']);
407 $hour = intval($_POST['hour']);
408 $min = intval($_POST['min']);
411 if (!checkdate($month, $day, $year)) {
415 if (strlen($month) == 1){
418 if (strlen($day) == 1){
421 if (strlen($hour) == 1){
424 if (strlen($min) == 1){
427 $release_date = "$year-$month-$day $hour:$min:00";
429 return $release_date;
432 function check_for_changes($row, $row_alternatives) {
433 global $contentManager, $cid, $glossary, $glossary_ids_related, $addslashes;
437 if ($row && strcmp(trim($addslashes($_POST['title'])), addslashes($row['title']))) {
439 } else if (!$row && $_POST['title']) {
443 if ($row && strcmp($addslashes(trim($_POST['head'])), trim(addslashes($row['head'])))) {
445 } else if (!$row && $_POST['head']) {
449 if ($row && strcmp($addslashes(trim($_POST['body_text'])), trim(addslashes($row['text'])))) {
451 } else if (!$row && $_POST['body_text']) {
455 if ($row && strcmp($addslashes(trim($_POST['weblink_text'])), trim(addslashes($row['text'])))) {
457 } else if (!$row && $_POST['weblink_text']) {
461 /* use customized head: */
462 if ($row && isset($_POST['use_customized_head']) && ($_POST['use_customized_head'] != $row['use_customized_head'])) {
467 if ($row && strcmp(trim($_POST['formatting']), $row['formatting'])) {
469 } else if (!$row && $_POST['formatting']) {
474 if ($row && strcmp(substr(generate_release_date(), 0, -2), substr($row['release_date'], 0, -2))) {
475 /* the substr was added because sometimes the release_date in the db has the seconds field set, which we dont use */
476 /* so it would show a difference, even though it should actually be the same, so we ignore the seconds with the -2 */
477 /* the seconds gets added if the course was created during the installation process. */
479 } else if (!$row && strcmp(generate_release_date(), generate_release_date(true))) {
483 /* related content: */
484 $row_related = $contentManager->getRelatedContent($cid);
486 if (is_array($_POST['related']) && is_array($row_related)) {
487 $sum = array_sum(array_diff($_POST['related'], $row_related));
488 $sum += array_sum(array_diff($row_related, $_POST['related']));
492 } else if (!is_array($_POST['related']) && !empty($row_related)) {
497 if ($row && strcmp(trim($_POST['keywords']), $row['keywords'])) {
499 } else if (!$row && $_POST['keywords']) {
505 if (is_array($_POST['glossary_defs'])) {
506 global $glossary_ids;
507 foreach ($_POST['glossary_defs'] as $w => $d) {
509 $key = in_array_cin($w, $glossary_ids);
510 if ($key === false) {
514 } else if ($cid && ($d &&($d != $glossary[$glossary_ids[$key]]))) {
521 if (is_array($_POST['related_term'])) {
522 foreach($_POST['related_term'] as $term => $r_id) {
523 if ($glossary_ids_related[$term] != $r_id) {
531 /* adapted content */
532 if (isset($_POST['use_post_for_alt']))
534 foreach ($_POST as $alt_id => $alt_value) {
535 if (substr($alt_id, 0 ,4) == 'alt_' && $alt_value != $row_alternatives[$alt_id]){
543 if ($row && isset($_POST['test_message']) && $_POST['test_message'] != $row['test_message']){
546 if ($row && isset($_POST['allow_test_export']) && $_POST['allow_test_export'] != $row['allow_test_export']){
553 function paste_from_file() {
555 if ($_FILES['uploadedfile_paste']['name'] == '') {
556 $msg->addError('FILE_NOT_SELECTED');
559 if ($_FILES['uploadedfile_paste']['name']
560 && (($_FILES['uploadedfile_paste']['type'] == 'text/plain')
561 || ($_FILES['uploadedfile_paste']['type'] == 'text/html')) )
564 $path_parts = pathinfo($_FILES['uploadedfile_paste']['name']);
565 $ext = strtolower($path_parts['extension']);
567 if (in_array($ext, array('html', 'htm'))) {
568 $_POST['body_text'] = file_get_contents($_FILES['uploadedfile_paste']['tmp_name']);
570 /* get the <title></title> of this page */
572 $start_pos = strpos(strtolower($_POST['body_text']), '<title>');
573 $end_pos = strpos(strtolower($_POST['body_text']), '</title>');
575 if (($start_pos !== false) && ($end_pos !== false)) {
576 $start_pos += strlen('<title>');
577 $_POST['title'] = trim(substr($_POST['body_text'], $start_pos, $end_pos-$start_pos));
582 $_POST['head'] = get_html_head_by_tag($_POST['body_text'], array("link", "style", "script"));
583 if (strlen(trim($_POST['head'])) > 0)
584 $_POST['use_customized_head'] = 1;
586 $_POST['use_customized_head'] = 0;
588 $_POST['body_text'] = get_html_body($_POST['body_text']);
590 $msg->addFeedback('FILE_PASTED');
591 } else if ($ext == 'txt') {
592 $_POST['body_text'] = file_get_contents($_FILES['uploadedfile_paste']['tmp_name']);
593 $msg->addFeedback('FILE_PASTED');
597 $msg->addError('BAD_FILE_TYPE');
603 //for accessibility checker
604 function write_temp_file() {
607 if (defined('AT_FORCE_GET_FILE') && AT_FORCE_GET_FILE) {
608 $content_base = 'get.php/';
610 $content_base = 'content/' . $_SESSION['course_id'] . '/';
613 if ($_POST['content_path']) {
614 $content_base .= $_POST['content_path'] . '/';
617 $file_name = $_POST['cid'].'.html';
619 if ($handle = fopen(AT_CONTENT_DIR . $file_name, 'wb+')) {
620 // $temp_content = '<h2>'.AT_print(stripslashes($_POST['title']), 'content.title').'</h2>';
622 // if ($_POST['body_text'] != '') {
623 // $temp_content .= format_content(stripslashes($_POST['body_text']), $_POST['formatting'], $_POST['glossary_defs']);
625 // $temp_title = $_POST['title'];
627 // $html_template = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
628 // "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
629 // <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
631 // <base href="{BASE_HREF}" />
632 // <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
633 // <title>{TITLE}</title>
634 // <meta name="Generator" content="ATutor accessibility checker file - can be deleted">
641 // $page_html = str_replace( array('{BASE_HREF}', '{TITLE}', '{CONTENT}'),
642 // array($content_base, $temp_title, $temp_content),
645 if (!@fwrite($handle, stripslashes($_POST['body_text']))) {
646 $msg->addError('FILE_NOT_SAVED');
649 $msg->addError('FILE_NOT_SAVED');