more upgrades
[moodle.git] / locallib.php
CommitLineData
e355240d
PS
1<?php
2// This file is part of Book module for Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * Book module local lib functions
19 *
20 * @package mod
21 * @subpackage book
22 * @copyright 2010 Petr Skoda {@link http://skodak.org}
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
26defined('MOODLE_INTERNAL') || die;
27
28define('BOOK_NUM_NONE', '0');
29define('BOOK_NUM_NUMBERS', '1');
30define('BOOK_NUM_BULLETS', '2');
31define('BOOK_NUM_INDENTED', '3');
32
33require_once($CFG->dirroot.'/mod/book/lib.php');
34
35function book_get_numbering_types() {
36 return array (BOOK_NUM_NONE => get_string('numbering0', 'mod_book'),
37 BOOK_NUM_NUMBERS => get_string('numbering1', 'mod_book'),
38 BOOK_NUM_BULLETS => get_string('numbering2', 'mod_book'),
39 BOOK_NUM_INDENTED => get_string('numbering3', 'mod_book') );
40}
41
42
43//////////////////////////////////////////////////////////////////////////////////////
44/// Any other book functions go here. Each of them must have a name that
45/// starts with book_
46
47//check chapter ordering and
48//make sure subchapter is not first in book
49//hidden chapter must have all subchapters hidden too
50function book_check_structure($bookid) {
51 if ($chapters = get_records('book_chapters', 'bookid', $bookid, 'pagenum', 'id, pagenum, subchapter, hidden')) {
52 $first = true;
53 $hidesub = true;
54 $i = 1;
55 foreach($chapters as $ch) {
56 if ($first and $ch->subchapter) {
57 $ch->subchapter = 0;
58 }
59 $first = false;
60 if (!$ch->subchapter) {
61 $hidesub = $ch->hidden;
62 } else {
63 $ch->hidden = $hidesub ? true : $ch->hidden;
64 }
65 $ch->pagenum = $i;
66 update_record('book_chapters', $ch);
67 $i++;
68 }
69 }
70}
71
72
73/// prepare button to turn chapter editing on - connected with course editing
74function book_edit_button($id, $courseid, $chapterid) {
75 global $CFG, $USER;
76
77
78 if (isteacheredit($courseid)) {
79 if (!empty($USER->editing)) {
80 $string = get_string("turneditingoff");
81 $edit = '0';
82 } else {
83 $string = get_string("turneditingon");
84 $edit = '1';
85 }
86 return '<form method="get" action="'.$CFG->wwwroot.'/mod/book/view.php"><div>'.
87 '<input type="hidden" name="id" value="'.$id.'" />'.
88 '<input type="hidden" name="chapterid" value="'.$chapterid.'" />'.
89 '<input type="hidden" name="edit" value="'.$edit.'" />'.
90 '<input type="submit" value="'.$string.'" /></div></form>';
91 } else {
92 return '';
93 }
94}
95
96/// general function for logging to table
97function book_log($str1, $str2, $level = 0) {
98 switch ($level) {
99 case 1:
100 echo '<tr><td><span class="dimmed_text">'.$str1.'</span></td><td><span class="dimmed_text">'.$str2.'</span></td></tr>';
101 break;
102 case 2:
103 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>';
104 break;
105 default:
106 echo '<tr><td>'.$str1.'</class></td><td>'.$str2.'</td></tr>';
107 break;
108 }
109}
110
111//=================================================
112// import functions
113//=================================================
114
115/// normalize relative links (= remove ..)
116function book_prepare_link($ref) {
117 if ($ref == '') {
118 return '';
119 }
120 $ref = str_replace('\\','/',$ref); //anti MS hack
121 $cnt = substr_count($ref, '..');
122 for($i=0; $i<$cnt; $i++) {
123 $ref = ereg_replace('[^/]+/\.\./', '', $ref);
124 }
125 //still any '..' left?? == error! error!
126 if (substr_count($ref, '..') > 0) {
127 return '';
128 }
129 if (ereg('[\|\`]', $ref)) { // check for other bad characters
130 return '';
131 }
132 return $ref;
133}
134
135/// read chapter content from file
136function book_read_chapter($base, $ref) {
137 $file = $base.'/'.$ref;
138 if (filesize($file) <= 0 or !is_readable($file)) {
139 book_log($ref, get_string('error'), 2);
140 return;
141 }
142 //first read data
143 $handle = fopen($file, "rb");
144 $contents = fread($handle, filesize($file));
145 fclose($handle);
146 //extract title
147 $chapter = new object();
148 if (preg_match('/<title>([^<]+)<\/title>/i', $contents, $matches)) {
149 $chapter->title = $matches[1];
150 } else {
151 $chapter->title = $ref;
152 }
153 //extract page body
154 if (preg_match('/<body[^>]*>(.+)<\/body>/is', $contents, $matches)) {
155 $chapter->content = $matches[1];
156 } else {
157 book_log($ref, get_string('error'), 2);
158 return;
159 }
160 book_log($ref, get_string('ok'));
161 $chapter->importsrc = $ref;
162 //extract page head
163 if (preg_match('/<head[^>]*>(.+)<\/head>/is', $contents, $matches)) {
164 $head = $matches[1];
165 if (preg_match('/charset=([^"]+)/is', $head, $matches)) {
166 $enc = $matches[1];
167 $textlib = textlib_get_instance();
168 $chapter->content = $textlib->convert($chapter->content, $enc, current_charset());
169 $chapter->title = $textlib->convert($chapter->title, $enc, current_charset());
170 }
171 if (preg_match_all('/<link[^>]+rel="stylesheet"[^>]*>/i', $head, $matches)) { //dlnsk extract links to css
172 for($i=0; $i<count($matches[0]); $i++){
173 $chapter->content = $matches[0][$i]."\n".$chapter->content;
174 }
175 }
176 }
177 return $chapter;
178}
179
180///relink images and relative links
181function book_relink($id, $bookid, $courseid) {
182 global $CFG;
183 if ($CFG->slasharguments) {
184 $coursebase = $CFG->wwwroot.'/file.php/'.$courseid;
185 } else {
186 $coursebase = $CFG->wwwroot.'/file.php?file=/'.$courseid;
187 }
188 $chapters = get_records('book_chapters', 'bookid', $bookid, 'pagenum', 'id, pagenum, title, content, importsrc');
189 $originals = array();
190 foreach($chapters as $ch) {
191 $originals[$ch->importsrc] = $ch;
192 }
193 foreach($chapters as $ch) {
194 $rel = substr($ch->importsrc, 0, strrpos($ch->importsrc, '/')+1);
195 $base = $coursebase.strtr(urlencode($rel), array("%2F" => "/")); //for better internationalization (dlnsk)
196 $modified = false;
197 //image relinking
198 if ($ch->importsrc && preg_match_all('/(<img[^>]+src=")([^"]+)("[^>]*>)/i', $ch->content, $images)) {
199 for($i = 0; $i<count($images[0]); $i++) {
200 if (!preg_match('/[a-z]+:/i', $images[2][$i])) { // not absolute link
201 $link = book_prepare_link($base.$images[2][$i]);
202 if ($link == '') {
203 continue;
204 }
205 $origtag = $images[0][$i];
206 $newtag = $images[1][$i].$link.$images[3][$i];
207 $ch->content = str_replace($origtag, $newtag, $ch->content);
208 $modified = true;
209 book_log($ch->title, $images[2][$i].' --> '.$link);
210 }
211 }
212 }
213 //css relinking (dlnsk)
214 if ($ch->importsrc && preg_match_all('/(<link[^>]+href=")([^"]+)("[^>]*>)/i', $ch->content, $csslinks)) {
215 for($i = 0; $i<count($csslinks[0]); $i++) {
216 if (!preg_match('/[a-z]+:/i', $csslinks[2][$i])) { // not absolute link
217 $link = book_prepare_link($base.$csslinks[2][$i]);
218 if ($link == '') {
219 continue;
220 }
221 $origtag = $csslinks[0][$i];
222 $newtag = $csslinks[1][$i].$link.$csslinks[3][$i];
223 $ch->content = str_replace($origtag, $newtag, $ch->content);
224 $modified = true;
225 book_log($ch->title, $csslinks[2][$i].' --> '.$link);
226 }
227 }
228 }
229 //general embed relinking - flash and others??
230 if ($ch->importsrc && preg_match_all('/(<embed[^>]+src=")([^"]+)("[^>]*>)/i', $ch->content, $embeds)) {
231 for($i = 0; $i<count($embeds[0]); $i++) {
232 if (!preg_match('/[a-z]+:/i', $embeds[2][$i])) { // not absolute link
233 $link = book_prepare_link($base.$embeds[2][$i]);
234 if ($link == '') {
235 continue;
236 }
237 $origtag = $embeds[0][$i];
238 $newtag = $embeds[1][$i].$link.$embeds[3][$i];
239 $ch->content = str_replace($origtag, $newtag, $ch->content);
240 $modified = true;
241 book_log($ch->title, $embeds[2][$i].' --> '.$link);
242 }
243 }
244 }
245 //flash in IE <param name=movie value="something" - I do hate IE!
246 if ($ch->importsrc && preg_match_all('/<param[^>]+name\s*=\s*"?movie"?[^>]*>/i', $ch->content, $params)) {
247 for($i = 0; $i<count($params[0]); $i++) {
248 if (preg_match('/(value=\s*")([^"]+)(")/i', $params[0][$i], $values)) {
249 if (!preg_match('/[a-z]+:/i', $values[2])) { // not absolute link
250 $link = book_prepare_link($base.$values[2]);
251 if ($link == '') {
252 continue;
253 }
254 $newvalue = $values[1].$link.$values[3];
255 $newparam = str_replace($values[0], $newvalue, $params[0][$i]);
256 $ch->content = str_replace($params[0][$i], $newparam, $ch->content);
257 $modified = true;
258 book_log($ch->title, $values[2].' --> '.$link);
259 }
260 }
261 }
262 }
263 //java applet - add code bases if not present!!!!
264 if ($ch->importsrc && preg_match_all('/<applet[^>]*>/i', $ch->content, $applets)) {
265 for($i = 0; $i<count($applets[0]); $i++) {
266 if (!stripos($applets[0][$i], 'codebase')) {
267 $newapplet = str_ireplace('<applet', '<applet codebase="."', $applets[0][$i]);
268 $ch->content = str_replace($applets[0][$i], $newapplet, $ch->content);
269 $modified = true;
270 }
271 }
272 }
273 //relink java applet code bases
274 if ($ch->importsrc && preg_match_all('/(<applet[^>]+codebase=")([^"]+)("[^>]*>)/i', $ch->content, $codebases)) {
275 for($i = 0; $i<count($codebases[0]); $i++) {
276 if (!preg_match('/[a-z]+:/i', $codebases[2][$i])) { // not absolute link
277 $link = book_prepare_link($base.$codebases[2][$i]);
278 if ($link == '') {
279 continue;
280 }
281 $origtag = $codebases[0][$i];
282 $newtag = $codebases[1][$i].$link.$codebases[3][$i];
283 $ch->content = str_replace($origtag, $newtag, $ch->content);
284 $modified = true;
285 book_log($ch->title, $codebases[2][$i].' --> '.$link);
286 }
287 }
288 }
289 //relative link conversion
290 if ($ch->importsrc && preg_match_all('/(<a\s[^>]*href=")([^"^#]*)(#[^"]*)?("[^>]*>)/i', $ch->content, $links)) {
291 for($i = 0; $i<count($links[0]); $i++) {
292 if ($links[2][$i] != '' //check for inner anchor links
293 && !preg_match('/[a-z]+:/i', $links[2][$i])) { //not absolute link
294 $origtag = $links[0][$i];
295 $target = book_prepare_link($rel.$links[2][$i]); //target chapter
296 if ($target != '' && array_key_exists($target, $originals)) {
297 $o = $originals[$target];
298 $newtag = $links[1][$i].$CFG->wwwroot.'/mod/book/view.php?id='.$id.'&chapterid='.$o->id.$links[3][$i].$links[4][$i];
299 $newtag = preg_replace('/target=[^\s>]/i','', $newtag);
300 $ch->content = str_replace($origtag, $newtag, $ch->content);
301 $modified = true;
302 book_log($ch->title, $links[2][$i].$links[3][$i].' --> '.$CFG->wwwroot.'/mod/book/view.php?id='.$id.'&chapterid='.$o->id.$links[3][$i]);
303 } else if ($target!='' && (!preg_match('/\.html$|\.htm$/i', $links[2][$i]))) { // other relative non html links converted to download links
304 $target = book_prepare_link($base.$links[2][$i]);
305 $origtag = $links[0][$i];
306 $newtag = $links[1][$i].$target.$links[4][$i];
307 $ch->content = str_replace($origtag, $newtag, $ch->content);
308 $modified = true;
309 book_log($ch->title, $links[2][$i].' --> '.$target);
310 }
311 }
312 }
313 }
314 if ($modified) {
315 $ch->title = addslashes($ch->title);
316 $ch->content = addslashes($ch->content);
317 $ch->importsrc = addslashes($ch->importsrc);
318 if (!update_record('book_chapters', $ch)) {
319 error('Could not update your book');
320 }
321 }
322 }
323}