mirror of
https://github.com/moodle/moodle.git
synced 2025-02-22 10:57:20 +01:00
324 lines
14 KiB
PHP
324 lines
14 KiB
PHP
|
<?php
|
||
|
// This file is part of Book module for Moodle - http://moodle.org/
|
||
|
//
|
||
|
// Moodle is free software: you can redistribute it and/or modify
|
||
|
// it under the terms of the GNU General Public License as published by
|
||
|
// the Free Software Foundation, either version 3 of the License, or
|
||
|
// (at your option) any later version.
|
||
|
//
|
||
|
// Moodle is distributed in the hope that it will be useful,
|
||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
// GNU General Public License for more details.
|
||
|
//
|
||
|
// You should have received a copy of the GNU General Public License
|
||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
/**
|
||
|
* Book module local lib functions
|
||
|
*
|
||
|
* @package mod
|
||
|
* @subpackage book
|
||
|
* @copyright 2010 Petr Skoda {@link http://skodak.org}
|
||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||
|
*/
|
||
|
|
||
|
defined('MOODLE_INTERNAL') || die;
|
||
|
|
||
|
define('BOOK_NUM_NONE', '0');
|
||
|
define('BOOK_NUM_NUMBERS', '1');
|
||
|
define('BOOK_NUM_BULLETS', '2');
|
||
|
define('BOOK_NUM_INDENTED', '3');
|
||
|
|
||
|
require_once($CFG->dirroot.'/mod/book/lib.php');
|
||
|
|
||
|
function book_get_numbering_types() {
|
||
|
return array (BOOK_NUM_NONE => get_string('numbering0', 'mod_book'),
|
||
|
BOOK_NUM_NUMBERS => get_string('numbering1', 'mod_book'),
|
||
|
BOOK_NUM_BULLETS => get_string('numbering2', 'mod_book'),
|
||
|
BOOK_NUM_INDENTED => get_string('numbering3', 'mod_book') );
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////////////
|
||
|
/// Any other book functions go here. Each of them must have a name that
|
||
|
/// starts with book_
|
||
|
|
||
|
//check chapter ordering and
|
||
|
//make sure subchapter is not first in book
|
||
|
//hidden chapter must have all subchapters hidden too
|
||
|
function book_check_structure($bookid) {
|
||
|
if ($chapters = get_records('book_chapters', 'bookid', $bookid, 'pagenum', 'id, pagenum, subchapter, hidden')) {
|
||
|
$first = true;
|
||
|
$hidesub = true;
|
||
|
$i = 1;
|
||
|
foreach($chapters as $ch) {
|
||
|
if ($first and $ch->subchapter) {
|
||
|
$ch->subchapter = 0;
|
||
|
}
|
||
|
$first = false;
|
||
|
if (!$ch->subchapter) {
|
||
|
$hidesub = $ch->hidden;
|
||
|
} else {
|
||
|
$ch->hidden = $hidesub ? true : $ch->hidden;
|
||
|
}
|
||
|
$ch->pagenum = $i;
|
||
|
update_record('book_chapters', $ch);
|
||
|
$i++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/// prepare button to turn chapter editing on - connected with course editing
|
||
|
function book_edit_button($id, $courseid, $chapterid) {
|
||
|
global $CFG, $USER;
|
||
|
|
||
|
|
||
|
if (isteacheredit($courseid)) {
|
||
|
if (!empty($USER->editing)) {
|
||
|
$string = get_string("turneditingoff");
|
||
|
$edit = '0';
|
||
|
} else {
|
||
|
$string = get_string("turneditingon");
|
||
|
$edit = '1';
|
||
|
}
|
||
|
return '<form method="get" action="'.$CFG->wwwroot.'/mod/book/view.php"><div>'.
|
||
|
'<input type="hidden" name="id" value="'.$id.'" />'.
|
||
|
'<input type="hidden" name="chapterid" value="'.$chapterid.'" />'.
|
||
|
'<input type="hidden" name="edit" value="'.$edit.'" />'.
|
||
|
'<input type="submit" value="'.$string.'" /></div></form>';
|
||
|
} else {
|
||
|
return '';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// general function for logging to table
|
||
|
function book_log($str1, $str2, $level = 0) {
|
||
|
switch ($level) {
|
||
|
case 1:
|
||
|
echo '<tr><td><span class="dimmed_text">'.$str1.'</span></td><td><span class="dimmed_text">'.$str2.'</span></td></tr>';
|
||
|
break;
|
||
|
case 2:
|
||
|
echo '<tr><td><span style="color: rgb(255, 0, 0);">'.$str1.'</span></td><td><span style="color: rgb(255, 0, 0);">'.$str2.'</span></td></tr>';
|
||
|
break;
|
||
|
default:
|
||
|
echo '<tr><td>'.$str1.'</class></td><td>'.$str2.'</td></tr>';
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//=================================================
|
||
|
// import functions
|
||
|
//=================================================
|
||
|
|
||
|
/// normalize relative links (= remove ..)
|
||
|
function book_prepare_link($ref) {
|
||
|
if ($ref == '') {
|
||
|
return '';
|
||
|
}
|
||
|
$ref = str_replace('\\','/',$ref); //anti MS hack
|
||
|
$cnt = substr_count($ref, '..');
|
||
|
for($i=0; $i<$cnt; $i++) {
|
||
|
$ref = ereg_replace('[^/]+/\.\./', '', $ref);
|
||
|
}
|
||
|
//still any '..' left?? == error! error!
|
||
|
if (substr_count($ref, '..') > 0) {
|
||
|
return '';
|
||
|
}
|
||
|
if (ereg('[\|\`]', $ref)) { // check for other bad characters
|
||
|
return '';
|
||
|
}
|
||
|
return $ref;
|
||
|
}
|
||
|
|
||
|
/// read chapter content from file
|
||
|
function book_read_chapter($base, $ref) {
|
||
|
$file = $base.'/'.$ref;
|
||
|
if (filesize($file) <= 0 or !is_readable($file)) {
|
||
|
book_log($ref, get_string('error'), 2);
|
||
|
return;
|
||
|
}
|
||
|
//first read data
|
||
|
$handle = fopen($file, "rb");
|
||
|
$contents = fread($handle, filesize($file));
|
||
|
fclose($handle);
|
||
|
//extract title
|
||
|
$chapter = new object();
|
||
|
if (preg_match('/<title>([^<]+)<\/title>/i', $contents, $matches)) {
|
||
|
$chapter->title = $matches[1];
|
||
|
} else {
|
||
|
$chapter->title = $ref;
|
||
|
}
|
||
|
//extract page body
|
||
|
if (preg_match('/<body[^>]*>(.+)<\/body>/is', $contents, $matches)) {
|
||
|
$chapter->content = $matches[1];
|
||
|
} else {
|
||
|
book_log($ref, get_string('error'), 2);
|
||
|
return;
|
||
|
}
|
||
|
book_log($ref, get_string('ok'));
|
||
|
$chapter->importsrc = $ref;
|
||
|
//extract page head
|
||
|
if (preg_match('/<head[^>]*>(.+)<\/head>/is', $contents, $matches)) {
|
||
|
$head = $matches[1];
|
||
|
if (preg_match('/charset=([^"]+)/is', $head, $matches)) {
|
||
|
$enc = $matches[1];
|
||
|
$textlib = textlib_get_instance();
|
||
|
$chapter->content = $textlib->convert($chapter->content, $enc, current_charset());
|
||
|
$chapter->title = $textlib->convert($chapter->title, $enc, current_charset());
|
||
|
}
|
||
|
if (preg_match_all('/<link[^>]+rel="stylesheet"[^>]*>/i', $head, $matches)) { //dlnsk extract links to css
|
||
|
for($i=0; $i<count($matches[0]); $i++){
|
||
|
$chapter->content = $matches[0][$i]."\n".$chapter->content;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return $chapter;
|
||
|
}
|
||
|
|
||
|
///relink images and relative links
|
||
|
function book_relink($id, $bookid, $courseid) {
|
||
|
global $CFG;
|
||
|
if ($CFG->slasharguments) {
|
||
|
$coursebase = $CFG->wwwroot.'/file.php/'.$courseid;
|
||
|
} else {
|
||
|
$coursebase = $CFG->wwwroot.'/file.php?file=/'.$courseid;
|
||
|
}
|
||
|
$chapters = get_records('book_chapters', 'bookid', $bookid, 'pagenum', 'id, pagenum, title, content, importsrc');
|
||
|
$originals = array();
|
||
|
foreach($chapters as $ch) {
|
||
|
$originals[$ch->importsrc] = $ch;
|
||
|
}
|
||
|
foreach($chapters as $ch) {
|
||
|
$rel = substr($ch->importsrc, 0, strrpos($ch->importsrc, '/')+1);
|
||
|
$base = $coursebase.strtr(urlencode($rel), array("%2F" => "/")); //for better internationalization (dlnsk)
|
||
|
$modified = false;
|
||
|
//image relinking
|
||
|
if ($ch->importsrc && preg_match_all('/(<img[^>]+src=")([^"]+)("[^>]*>)/i', $ch->content, $images)) {
|
||
|
for($i = 0; $i<count($images[0]); $i++) {
|
||
|
if (!preg_match('/[a-z]+:/i', $images[2][$i])) { // not absolute link
|
||
|
$link = book_prepare_link($base.$images[2][$i]);
|
||
|
if ($link == '') {
|
||
|
continue;
|
||
|
}
|
||
|
$origtag = $images[0][$i];
|
||
|
$newtag = $images[1][$i].$link.$images[3][$i];
|
||
|
$ch->content = str_replace($origtag, $newtag, $ch->content);
|
||
|
$modified = true;
|
||
|
book_log($ch->title, $images[2][$i].' --> '.$link);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//css relinking (dlnsk)
|
||
|
if ($ch->importsrc && preg_match_all('/(<link[^>]+href=")([^"]+)("[^>]*>)/i', $ch->content, $csslinks)) {
|
||
|
for($i = 0; $i<count($csslinks[0]); $i++) {
|
||
|
if (!preg_match('/[a-z]+:/i', $csslinks[2][$i])) { // not absolute link
|
||
|
$link = book_prepare_link($base.$csslinks[2][$i]);
|
||
|
if ($link == '') {
|
||
|
continue;
|
||
|
}
|
||
|
$origtag = $csslinks[0][$i];
|
||
|
$newtag = $csslinks[1][$i].$link.$csslinks[3][$i];
|
||
|
$ch->content = str_replace($origtag, $newtag, $ch->content);
|
||
|
$modified = true;
|
||
|
book_log($ch->title, $csslinks[2][$i].' --> '.$link);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//general embed relinking - flash and others??
|
||
|
if ($ch->importsrc && preg_match_all('/(<embed[^>]+src=")([^"]+)("[^>]*>)/i', $ch->content, $embeds)) {
|
||
|
for($i = 0; $i<count($embeds[0]); $i++) {
|
||
|
if (!preg_match('/[a-z]+:/i', $embeds[2][$i])) { // not absolute link
|
||
|
$link = book_prepare_link($base.$embeds[2][$i]);
|
||
|
if ($link == '') {
|
||
|
continue;
|
||
|
}
|
||
|
$origtag = $embeds[0][$i];
|
||
|
$newtag = $embeds[1][$i].$link.$embeds[3][$i];
|
||
|
$ch->content = str_replace($origtag, $newtag, $ch->content);
|
||
|
$modified = true;
|
||
|
book_log($ch->title, $embeds[2][$i].' --> '.$link);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//flash in IE <param name=movie value="something" - I do hate IE!
|
||
|
if ($ch->importsrc && preg_match_all('/<param[^>]+name\s*=\s*"?movie"?[^>]*>/i', $ch->content, $params)) {
|
||
|
for($i = 0; $i<count($params[0]); $i++) {
|
||
|
if (preg_match('/(value=\s*")([^"]+)(")/i', $params[0][$i], $values)) {
|
||
|
if (!preg_match('/[a-z]+:/i', $values[2])) { // not absolute link
|
||
|
$link = book_prepare_link($base.$values[2]);
|
||
|
if ($link == '') {
|
||
|
continue;
|
||
|
}
|
||
|
$newvalue = $values[1].$link.$values[3];
|
||
|
$newparam = str_replace($values[0], $newvalue, $params[0][$i]);
|
||
|
$ch->content = str_replace($params[0][$i], $newparam, $ch->content);
|
||
|
$modified = true;
|
||
|
book_log($ch->title, $values[2].' --> '.$link);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//java applet - add code bases if not present!!!!
|
||
|
if ($ch->importsrc && preg_match_all('/<applet[^>]*>/i', $ch->content, $applets)) {
|
||
|
for($i = 0; $i<count($applets[0]); $i++) {
|
||
|
if (!stripos($applets[0][$i], 'codebase')) {
|
||
|
$newapplet = str_ireplace('<applet', '<applet codebase="."', $applets[0][$i]);
|
||
|
$ch->content = str_replace($applets[0][$i], $newapplet, $ch->content);
|
||
|
$modified = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//relink java applet code bases
|
||
|
if ($ch->importsrc && preg_match_all('/(<applet[^>]+codebase=")([^"]+)("[^>]*>)/i', $ch->content, $codebases)) {
|
||
|
for($i = 0; $i<count($codebases[0]); $i++) {
|
||
|
if (!preg_match('/[a-z]+:/i', $codebases[2][$i])) { // not absolute link
|
||
|
$link = book_prepare_link($base.$codebases[2][$i]);
|
||
|
if ($link == '') {
|
||
|
continue;
|
||
|
}
|
||
|
$origtag = $codebases[0][$i];
|
||
|
$newtag = $codebases[1][$i].$link.$codebases[3][$i];
|
||
|
$ch->content = str_replace($origtag, $newtag, $ch->content);
|
||
|
$modified = true;
|
||
|
book_log($ch->title, $codebases[2][$i].' --> '.$link);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//relative link conversion
|
||
|
if ($ch->importsrc && preg_match_all('/(<a\s[^>]*href=")([^"^#]*)(#[^"]*)?("[^>]*>)/i', $ch->content, $links)) {
|
||
|
for($i = 0; $i<count($links[0]); $i++) {
|
||
|
if ($links[2][$i] != '' //check for inner anchor links
|
||
|
&& !preg_match('/[a-z]+:/i', $links[2][$i])) { //not absolute link
|
||
|
$origtag = $links[0][$i];
|
||
|
$target = book_prepare_link($rel.$links[2][$i]); //target chapter
|
||
|
if ($target != '' && array_key_exists($target, $originals)) {
|
||
|
$o = $originals[$target];
|
||
|
$newtag = $links[1][$i].$CFG->wwwroot.'/mod/book/view.php?id='.$id.'&chapterid='.$o->id.$links[3][$i].$links[4][$i];
|
||
|
$newtag = preg_replace('/target=[^\s>]/i','', $newtag);
|
||
|
$ch->content = str_replace($origtag, $newtag, $ch->content);
|
||
|
$modified = true;
|
||
|
book_log($ch->title, $links[2][$i].$links[3][$i].' --> '.$CFG->wwwroot.'/mod/book/view.php?id='.$id.'&chapterid='.$o->id.$links[3][$i]);
|
||
|
} else if ($target!='' && (!preg_match('/\.html$|\.htm$/i', $links[2][$i]))) { // other relative non html links converted to download links
|
||
|
$target = book_prepare_link($base.$links[2][$i]);
|
||
|
$origtag = $links[0][$i];
|
||
|
$newtag = $links[1][$i].$target.$links[4][$i];
|
||
|
$ch->content = str_replace($origtag, $newtag, $ch->content);
|
||
|
$modified = true;
|
||
|
book_log($ch->title, $links[2][$i].' --> '.$target);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ($modified) {
|
||
|
$ch->title = addslashes($ch->title);
|
||
|
$ch->content = addslashes($ch->content);
|
||
|
$ch->importsrc = addslashes($ch->importsrc);
|
||
|
if (!update_record('book_chapters', $ch)) {
|
||
|
error('Could not update your book');
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|