New update script, Version.php, new salted passwords, minor fixes.
[lhc/web/wiklou.git] / includes / OutputPage.php
1 <?
2 # See design.doc
3
4 function linkToMathImage ( $tex, $outputhash )
5 {
6 global $wgMathPath;
7 return "<img src=\"".$wgMathPath."/".$outputhash.".png\" alt=\"".wfEscapeHTML($tex)."\">";
8 }
9
10 function renderMath( $tex )
11 {
12 global $wgUser, $wgMathDirectory, $wgTmpDirectory, $wgInputEncoding;
13 $mf = wfMsg( "math_failure" );
14 $munk = wfMsg( "math_unknown_error" );
15
16 $fname = "renderMath";
17
18 $math = $wgUser->getOption("math");
19 if ($math == 3)
20 return ('$ '.wfEscapeHTML($tex).' $');
21
22 $md5 = md5($tex);
23 $md5_sql = mysql_escape_string(pack("H32", $md5));
24 if ($math == 0)
25 $sql = "SELECT math_outputhash FROM math WHERE math_inputhash = '".$md5_sql."'";
26 else
27 $sql = "SELECT math_outputhash,math_html_conservativeness,math_html FROM math WHERE math_inputhash = '".$md5_sql."'";
28
29 $res = wfQuery( $sql, $fname );
30 if ( wfNumRows( $res ) == 0 )
31 {
32 $cmd = "./math/texvc ".escapeshellarg($wgTmpDirectory)." ".
33 escapeshellarg($wgMathDirectory)." ".escapeshellarg($tex)." ".escapeshellarg($wgInputEncoding);
34 $contents = `$cmd`;
35
36 if (strlen($contents) == 0)
37 return "<b>".$mf." (".$munk."): ".wfEscapeHTML($tex)."</b>";
38 $retval = substr ($contents, 0, 1);
39 if (($retval == "C") || ($retval == "M") || ($retval == "L")) {
40 if ($retval == "C")
41 $conservativeness = 2;
42 else if ($retval == "M")
43 $conservativeness = 1;
44 else
45 $conservativeness = 0;
46 $outdata = substr ($contents, 33);
47
48 $i = strpos($outdata, "\000");
49
50 $outhtml = substr($outdata, 0, $i);
51 $mathml = substr($outdata, $i+1);
52
53 $sql_html = "'".mysql_escape_string($outhtml)."'";
54 $sql_mathml = "'".mysql_escape_string($mathml)."'";
55 } else if (($retval == "c") || ($retval == "m") || ($retval == "l")) {
56 $outhtml = substr ($contents, 33);
57 if ($retval == "c")
58 $conservativeness = 2;
59 else if ($retval == "m")
60 $conservativeness = 1;
61 else
62 $conservativeness = 0;
63 $sql_html = "'".mysql_escape_string($outhtml)."'";
64 $mathml = '';
65 $sql_mathml = 'NULL';
66 } else if ($retval == "X") {
67 $outhtml = '';
68 $mathml = substr ($contents, 33);
69 $sql_html = 'NULL';
70 $sql_mathml = "'".mysql_escape_string($mathml)."'";
71 $conservativeness = 0;
72 } else if ($retval == "+") {
73 $outhtml = '';
74 $mathml = '';
75 $sql_html = 'NULL';
76 $sql_mathml = 'NULL';
77 $conservativeness = 0;
78 } else {
79 if ($retval == "E")
80 $errmsg = wfMsg( "math_lexing_error" );
81 else if ($retval == "S")
82 $errmsg = wfMsg( "math_syntax_error" );
83 else if ($retval == "F")
84 $errmsg = wfMsg( "math_unknown_function" );
85 else
86 $errmsg = $munk;
87 return "<h3>".$mf." (".$errmsg.substr($contents, 1)."): ".wfEscapeHTML($tex)."</h3>";
88 }
89
90 $outmd5 = substr ($contents, 1, 32);
91 if (!preg_match("/^[a-f0-9]{32}$/", $outmd5))
92 return "<b>".$mf." (".$munk."): ".wfEscapeHTML($tex)."</b>";
93
94 $outmd5_sql = mysql_escape_string(pack("H32", $outmd5));
95
96 $sql = "INSERT INTO math VALUES ('".$md5_sql."', '".$outmd5_sql."', ".$conservativeness.", ".$sql_html.", ".$sql_mathml.")";
97
98 $res = wfQuery( $sql, $fname );
99 # we don't really care if it fails
100
101 if (($math == 0) || ($rpage->math_html == '') || (($math == 1) && ($conservativeness != 2)) || (($math == 4) && ($conservativeness == 0)))
102 return linkToMathImage($tex, $outmd5);
103 else
104 return $outhtml;
105 } else {
106 $rpage = wfFetchObject ( $res );
107 $outputhash = unpack( "H32md5", $rpage->math_outputhash . " " );
108 $outputhash = $outputhash ['md5'];
109
110 if (($math == 0) || ($rpage->math_html == '') || (($math == 1) && ($rpage->math_html_conservativeness != 2)) || (($math == 4) && ($rpage->math_html_conservativeness == 0)))
111 return linkToMathImage ( $tex, $outputhash );
112 else
113 return $rpage->math_html;
114 }
115 }
116
117 class OutputPage {
118 var $mHeaders, $mCookies, $mMetatags, $mKeywords;
119 var $mLinktags, $mPagetitle, $mBodytext, $mDebugtext;
120 var $mHTMLtitle, $mRobotpolicy, $mIsarticle, $mPrintable;
121 var $mSubtitle, $mRedirect, $mAutonumber, $mHeadtext;
122 var $mLastModified;
123
124 var $mDTopen, $mLastSection; # Used for processing DL, PRE
125 var $mLanguageLinks, $mSupressQuickbar;
126
127 function OutputPage()
128 {
129 $this->mHeaders = $this->mCookies = $this->mMetatags =
130 $this->mKeywords = $this->mLinktags = array();
131 $this->mHTMLtitle = $this->mPagetitle = $this->mBodytext =
132 $this->mLastSection = $this->mRedirect = $this->mLastModified =
133 $this->mSubtitle = $this->mDebugtext = $this->mRobotpolicy = "";
134 $this->mIsarticle = $this->mPrintable = true;
135 $this->mSupressQuickbar = $this->mDTopen = $this->mPrintable = false;
136 $this->mLanguageLinks = array();
137 $this->mAutonumber = 0;
138 }
139
140 function addHeader( $name, $val ) { array_push( $this->mHeaders, "$name: $val" ) ; }
141 function addCookie( $name, $val ) { array_push( $this->mCookies, array( $name, $val ) ); }
142 function redirect( $url ) { $this->mRedirect = $url; }
143
144 # To add an http-equiv meta tag, precede the name with "http:"
145 function addMeta( $name, $val ) { array_push( $this->mMetatags, array( $name, $val ) ); }
146 function addKeyword( $text ) { array_push( $this->mKeywords, $text ); }
147 function addLink( $rel, $rev, $target ) { array_push( $this->mLinktags, array( $rel, $rev, $target ) ); }
148
149 function checkLastModified ( $timestamp )
150 {
151 global $wgLang, $wgCachePages, $wgUser;
152 if( !$wgCachePages ) return;
153 if( preg_match( '/MSIE ([1-4]|5\.0)/', $_SERVER["HTTP_USER_AGENT"] ) ) {
154 # IE 5.0 has probs with our caching
155 return;
156 }
157
158 if( $_SERVER["HTTP_IF_MODIFIED_SINCE"] != "" ) {
159 $ismodsince = wfUnix2Timestamp( strtotime( $_SERVER["HTTP_IF_MODIFIED_SINCE"] ) );
160 $lastmod = gmdate( "D, j M Y H:i:s", wfTimestamp2Unix(
161 max( $timestamp, $wgUser->mTouched ) ) ) . " GMT";
162
163 if( ($ismodsince >= $timestamp ) and $wgUser->validateCache( $ismodsince ) ) {
164 # Make sure you're in a place you can leave when you call us!
165 header( "HTTP/1.0 304 Not Modified" );
166 header( "Expires: Mon, 15 Jan 2001 00:00:00 GMT" ); # Cachers always validate the page!
167 header( "Cache-Control: private, must-revalidate, max-age=0" );
168 header( "Last-Modified: {$lastmod}" );
169 #wfDebug( "CACHED client: $ismodsince ; user: $wgUser->mTouched ; page: $timestamp\n", false );
170 exit;
171 } else {
172 #wfDebug( "READY client: $ismodsince ; user: $wgUser->mTouched ; page: $timestamp\n", false );
173 $this->mLastModified = $lastmod;
174 }
175 }
176 }
177
178 function setRobotpolicy( $str ) { $this->mRobotpolicy = $str; }
179 function setHTMLtitle( $name ) { $this->mHTMLtitle = $name; }
180 function setPageTitle( $name ) { $this->mPagetitle = $name; }
181 function getPageTitle() { return $this->mPagetitle; }
182 function setSubtitle( $str ) { $this->mSubtitle = $str; }
183 function getSubtitle() { return $this->mSubtitle; }
184 function setArticleFlag( $v ) { $this->mIsarticle = $v; }
185 function isArticle() { return $this->mIsarticle; }
186 function setPrintable() { $this->mPrintable = true; }
187 function isPrintable() { return $this->mPrintable; }
188
189 function getLanguageLinks() {
190 global $wgUseNewInterlanguage, $wgTitle, $wgLanguageCode;
191 global $wgDBconnection, $wgDBname, $wgDBintlname;
192
193 if ( ! $wgUseNewInterlanguage )
194 return $this->mLanguageLinks;
195
196 mysql_select_db( $wgDBintlname, $wgDBconnection ) or die(
197 htmlspecialchars(mysql_error()) );
198
199 $list = array();
200 $sql = "SELECT * FROM ilinks WHERE lang_from=\"" .
201 "{$wgLanguageCode}\" AND title_from=\"" . $wgTitle->getDBkey() . "\"";
202 $res = mysql_query( $sql, $wgDBconnection );
203
204 while ( $q = mysql_fetch_object ( $res ) ) {
205 $list[] = $q->lang_to . ":" . $q->title_to;
206 }
207 mysql_free_result( $res );
208 mysql_select_db( $wgDBname, $wgDBconnection ) or die(
209 htmlspecialchars(mysql_error()) );
210
211 return $list;
212 }
213
214 function supressQuickbar() { $this->mSupressQuickbar = true; }
215 function isQuickbarSupressed() { return $this->mSupressQuickbar; }
216
217 function addHTML( $text ) { $this->mBodytext .= $text; }
218 function addHeadtext( $text ) { $this->mHeadtext .= $text; }
219 function debug( $text ) { $this->mDebugtext .= $text; }
220
221 # First pass--just handle <nowiki> sections, pass the rest off
222 # to doWikiPass2() which does all the real work.
223 #
224
225 function addWikiText( $text, $linestart = true )
226 {
227 global $wgUseTeX;
228 wfProfileIn( "OutputPage::addWikiText" );
229 $unique = "3iyZiyA7iMwg5rhxP0Dcc9oTnj8qD1jm1Sfv4";
230 $unique2 = "4LIQ9nXtiYFPCSfitVwDw7EYwQlL4GeeQ7qSO";
231 $unique3 = "fPaA8gDfdLBqzj68Yjg9Hil3qEF8JGO0uszIp";
232 $nwlist = array();
233 $nwsecs = 0;
234 $mathlist = array();
235 $mathsecs = 0;
236 $prelist = array ();
237 $presecs = 0;
238 $stripped = "";
239 $stripped2 = "";
240 $stripped3 = "";
241
242 while ( "" != $text ) {
243 $p = preg_split( "/<\\s*nowiki\\s*>/i", $text, 2 );
244 $stripped .= $p[0];
245 if ( ( count( $p ) < 2 ) || ( "" == $p[1] ) ) { $text = ""; }
246 else {
247 $q = preg_split( "/<\\/\\s*nowiki\\s*>/i", $p[1], 2 );
248 ++$nwsecs;
249 $nwlist[$nwsecs] = wfEscapeHTMLTagsOnly($q[0]);
250 $stripped .= $unique;
251 $text = $q[1];
252 }
253 }
254
255 if( $wgUseTeX ) {
256 while ( "" != $stripped ) {
257 $p = preg_split( "/<\\s*math\\s*>/i", $stripped, 2 );
258 $stripped2 .= $p[0];
259 if ( ( count( $p ) < 2 ) || ( "" == $p[1] ) ) { $stripped = ""; }
260 else {
261 $q = preg_split( "/<\\/\\s*math\\s*>/i", $p[1], 2 );
262 ++$mathsecs;
263 $mathlist[$mathsecs] = renderMath($q[0]);
264 $stripped2 .= $unique2;
265 $stripped = $q[1];
266 }
267 }
268 } else {
269 $stripped2 = $stripped;
270 }
271
272 while ( "" != $stripped2 ) {
273 $p = preg_split( "/<\\s*pre\\s*>/i", $stripped2, 2 );
274 $stripped3 .= $p[0];
275 if ( ( count( $p ) < 2 ) || ( "" == $p[1] ) ) { $stripped2 = ""; }
276 else {
277 $q = preg_split( "/<\\/\\s*pre\\s*>/i", $p[1], 2 );
278 ++$presecs;
279 $prelist[$presecs] = "<pre>". wfEscapeHTMLTagsOnly($q[0]). "</pre>";
280 $stripped3 .= $unique3;
281 $stripped2 = $q[1];
282 }
283 }
284
285 $text = $this->doWikiPass2( $stripped3, $linestart );
286
287 for ( $i = 1; $i <= $presecs; ++$i ) {
288 $text = preg_replace( "/{$unique3}/", str_replace( '$', '\$', $prelist[$i] ), $text, 1 );
289 }
290
291 for ( $i = 1; $i <= $mathsecs; ++$i ) {
292 $text = preg_replace( "/{$unique2}/", str_replace( '$', '\$', $mathlist[$i] ), $text, 1 );
293 }
294
295 for ( $i = 1; $i <= $nwsecs; ++$i ) {
296 $text = preg_replace( "/{$unique}/", str_replace( '$', '\$', $nwlist[$i] ), $text, 1 );
297 }
298 $this->addHTML( $text );
299 wfProfileOut();
300 }
301
302 # Finally, all the text has been munged and accumulated into
303 # the object, let's actually output it:
304 #
305 function output()
306 {
307 global $wgUser, $wgLang, $wgDebugComments, $wgCookieExpiration;
308 global $wgInputEncoding, $wgOutputEncoding, $wgLanguageCode;
309 wfProfileIn( "OutputPage::output" );
310 $sk = $wgUser->getSkin();
311
312 wfProfileIn( "OutputPage::output-headers" );
313 if( $this->mLastModified != "" ) {
314 header( "Cache-Control: private, must-revalidate, max-age=0" );
315 header( "Last-modified: {$this->mLastModified}" );
316 } else {
317 header( "Cache-Control: no-cache" ); # Experimental - see below
318 header( "Pragma: no-cache" );
319 header( "Last-modified: " . gmdate( "D, j M Y H:i:s" ) . " GMT" );
320 }
321 header( "Expires: Mon, 15 Jan 2001 00:00:00 GMT" ); # Cachers always validate the page!
322
323 header( "Content-type: text/html; charset={$wgOutputEncoding}" );
324 header( "Content-language: {$wgLanguageCode}" );
325
326 if ( "" != $this->mRedirect ) {
327 header( "Location: {$this->mRedirect}" );
328 wfProfileOut();
329 return;
330 }
331
332 $exp = time() + $wgCookieExpiration;
333 foreach( $this->mCookies as $name => $val ) {
334 setcookie( $name, $val, $exp, "/" );
335 }
336 wfProfileOut();
337
338 wfProfileIn( "OutputPage::output-middle" );
339 $sk->initPage();
340 $this->out( $this->headElement() );
341
342 $this->out( "\n<body" );
343 $ops = $sk->getBodyOptions();
344 foreach ( $ops as $name => $val ) {
345 $this->out( " $name='$val'" );
346 }
347 $this->out( ">\n" );
348 if ( $wgDebugComments ) {
349 $this->out( "<!-- Wiki debugging output:\n" .
350 $this->mDebugtext . "-->\n" );
351 }
352 $this->out( $sk->beforeContent() );
353 wfProfileOut();
354
355 wfProfileIn( "OutputPage::output-bodytext" );
356 $this->out( $this->mBodytext );
357 wfProfileOut();
358 wfProfileIn( "OutputPage::output-after" );
359 $this->out( $sk->afterContent() );
360 wfProfileOut();
361
362 wfProfileOut(); # A hack - we can't report after here
363 $this->out( $this->reportTime() );
364
365 $this->out( "\n</body></html>" );
366 flush();
367 }
368
369 function out( $ins )
370 {
371 global $wgInputEncoding, $wgOutputEncoding, $wgLang;
372 if ( 0 == strcmp( $wgInputEncoding, $wgOutputEncoding ) ) {
373 $outs = $ins;
374 } else {
375 $outs = $wgLang->iconv( $wgInputEncoding, $wgOutputEncoding, $ins );
376 if ( false === $outs ) { $outs = $ins; }
377 }
378 print $outs;
379 }
380
381 function setEncodings()
382 {
383 global $HTTP_SERVER_VARS, $wgInputEncoding, $wgOutputEncoding;
384 global $wgUser, $wgLang;
385
386 $wgInputEncoding = strtolower( $wgInputEncoding );
387 $s = $HTTP_SERVER_VARS['HTTP_ACCEPT_CHARSET'];
388
389 if( $wgUser->getOption( 'altencoding' ) ) {
390 $wgLang->setAltEncoding();
391 return;
392 }
393
394 if ( "" == $s ) {
395 $wgOutputEncoding = strtolower( $wgOutputEncoding );
396 return;
397 }
398 $a = explode( ",", $s );
399 $best = 0.0;
400 $bestset = "*";
401
402 foreach ( $a as $s ) {
403 if ( preg_match( "/(.*);q=(.*)/", $s, $m ) ) {
404 $set = $m[1];
405 $q = (float)($m[2]);
406 } else {
407 $set = $s;
408 $q = 1.0;
409 }
410 if ( $q > $best ) {
411 $bestset = $set;
412 $best = $q;
413 }
414 }
415 #if ( "*" == $bestset ) { $bestset = "iso-8859-1"; }
416 if ( "*" == $bestset ) { $bestset = $wgOutputEncoding; }
417 $wgOutputEncoding = strtolower( $bestset );
418
419 # Disable for now
420 #
421 $wgOutputEncoding = $wgInputEncoding;
422 }
423
424 function reportTime()
425 {
426 global $wgRequestTime, $wgDebugLogFile, $HTTP_SERVER_VARS;
427 global $wgProfiling, $wgProfileStack;
428
429 list( $usec, $sec ) = explode( " ", microtime() );
430 $now = (float)$sec + (float)$usec;
431
432 list( $usec, $sec ) = explode( " ", $wgRequestTime );
433 $start = (float)$sec + (float)$usec;
434 $elapsed = $now - $start;
435
436 if ( "" != $wgDebugLogFile ) {
437 $prof = "";
438 if( $wgProfiling and count( $wgProfileStack ) ) {
439 $lasttime = $start;
440 foreach( $wgProfileStack as $ile ) {
441 # "foo::bar 99 0.12345 1 0.23456 2"
442 if( preg_match( '/^(\S+)\s+([0-9]+)\s+([0-9\.]+)\s+([0-9\.]+)\s+([0-9\.]+)\s+([0-9\.]+)/', $ile, $m ) ) {
443 $thisstart = (float)$m[3] + (float)$m[4] - $start;
444 $thisend = (float)$m[5] + (float)$m[6] - $start;
445 $thiselapsed = $thisend - $thisstart;
446 $thispercent = $thiselapsed / $elapsed * 100.0;
447
448 $prof .= sprintf( "\tat %04.3f in %04.3f (%2.1f%%) - %s %s\n",
449 $thisstart, $thiselapsed, $thispercent,
450 str_repeat( "*", $m[2] ), $m[1] );
451 $lasttime = $thistime;
452 #$prof .= "\t(^ $ile)\n";
453 } else {
454 $prof .= "\t?broken? $ile\n";
455 }
456 }
457 }
458
459 if( $forward = $HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR'] )
460 $forward = " forwarded for $forward";
461 if( $client = $HTTP_SERVER_VARS['HTTP_CLIENT_IP'] )
462 $forward .= " client IP $client";
463 if( $from = $HTTP_SERVER_VARS['HTTP_FROM'] )
464 $forward .= " from $from";
465 if( $forward )
466 $forward = "\t(proxied via {$HTTP_SERVER_VARS['REMOTE_ADDR']}{$forward})";
467 $log = sprintf( "%s\t%04.3f\t%s\n",
468 date( "YmdHis" ), $elapsed,
469 urldecode( $HTTP_SERVER_VARS['REQUEST_URI'] . $forward ) );
470 error_log( $log . $prof, 3, $wgDebugLogFile );
471 }
472 $com = sprintf( "<!-- Time since request: %01.2f secs. -->",
473 $elapsed );
474 return $com;
475 }
476
477 # Note: these arguments are keys into wfMsg(), not text!
478 #
479 function errorpage( $title, $msg )
480 {
481 global $wgTitle;
482
483 $this->mDebugtext .= "Original title: " .
484 $wgTitle->getPrefixedText() . "\n";
485 $this->setHTMLTitle( wfMsg( "errorpagetitle" ) );
486 $this->setPageTitle( wfMsg( $title ) );
487 $this->setRobotpolicy( "noindex,nofollow" );
488 $this->setArticleFlag( false );
489
490 $this->mBodytext = "";
491 $this->addHTML( "<p>" . wfMsg( $msg ) . "\n" );
492 $this->returnToMain( false );
493
494 $this->output();
495 exit;
496 }
497
498 function sysopRequired()
499 {
500 global $wgUser;
501
502 $this->setHTMLTitle( wfMsg( "errorpagetitle" ) );
503 $this->setPageTitle( wfMsg( "sysoptitle" ) );
504 $this->setRobotpolicy( "noindex,nofollow" );
505 $this->setArticleFlag( false );
506 $this->mBodytext = "";
507
508 $sk = $wgUser->getSkin();
509 $ap = $sk->makeKnownLink( wfMsg( "administrators" ), "" );
510 $text = str_replace( "$1", $ap, wfMsg( "sysoptext" ) );
511 $this->addHTML( $text );
512 $this->returnToMain();
513 }
514
515 function developerRequired()
516 {
517 global $wgUser;
518
519 $this->setHTMLTitle( wfMsg( "errorpagetitle" ) );
520 $this->setPageTitle( wfMsg( "developertitle" ) );
521 $this->setRobotpolicy( "noindex,nofollow" );
522 $this->setArticleFlag( false );
523 $this->mBodytext = "";
524
525 $sk = $wgUser->getSkin();
526 $ap = $sk->makeKnownLink( wfMsg( "administrators" ), "" );
527 $text = str_replace( "$1", $ap, wfMsg( "developertext" ) );
528 $this->addHTML( $text );
529 $this->returnToMain();
530 }
531
532 function databaseError( $fname )
533 {
534 global $wgUser, $wgCommandLineMode;
535
536 $this->setPageTitle( wfMsg( "databaseerror" ) );
537 $this->setRobotpolicy( "noindex,nofollow" );
538 $this->setArticleFlag( false );
539
540 if ( $wgCommandLineMode ) {
541 $msg = wfMsg( "dberrortextcl" );
542 } else {
543 $msg = wfMsg( "dberrortextcl" );
544 }
545 $msg = str_replace( "$1", htmlspecialchars( wfLastDBquery() ), $msg );
546 $msg = str_replace( "$2", htmlspecialchars( $fname ), $msg );
547 $msg = str_replace( "$3", wfLastErrno(), $msg );
548 $msg = str_replace( "$4", htmlspecialchars( wfLastError() ), $msg );
549
550 if ( $wgCommandLineMode ) {
551 print $msg;
552 exit();
553 }
554 $sk = $wgUser->getSkin();
555 $shlink = $sk->makeKnownLink( wfMsg( "searchhelppage" ),
556 wfMsg( "searchingwikipedia" ) );
557 $msg = str_replace( "$5", $shlink, $msg );
558
559 $this->mBodytext = $msg;
560 $this->output();
561 exit();
562 }
563
564 function readOnlyPage()
565 {
566 global $wgUser, $wgReadOnlyFile;
567
568 $this->setPageTitle( wfMsg( "readonly" ) );
569 $this->setRobotpolicy( "noindex,nofollow" );
570 $this->setArticleFlag( false );
571
572 $reason = implode( "", file( $wgReadOnlyFile ) );
573 $text = str_replace( "$1", $reason, wfMsg( "readonlytext" ) );
574 $this->addHTML( $text );
575 $this->returnToMain( false );
576 }
577
578 function fatalError( $message )
579 {
580 $this->setPageTitle( wfMsg( "internalerror" ) );
581 $this->setRobotpolicy( "noindex,nofollow" );
582 $this->setArticleFlag( false );
583
584 $this->mBodytext = $message;
585 $this->output();
586 exit;
587 }
588
589 function unexpectedValueError( $name, $val )
590 {
591 $msg = str_replace( "$1", $name, wfMsg( "unexpected" ) );
592 $msg = str_replace( "$2", $val, $msg );
593 $this->fatalError( $msg );
594 }
595
596 function fileCopyError( $old, $new )
597 {
598 $msg = str_replace( "$1", $old, wfMsg( "filecopyerror" ) );
599 $msg = str_replace( "$2", $new, $msg );
600 $this->fatalError( $msg );
601 }
602
603 function fileRenameError( $old, $new )
604 {
605 $msg = str_replace( "$1", $old, wfMsg( "filerenameerror" ) );
606 $msg = str_replace( "$2", $new, $msg );
607 $this->fatalError( $msg );
608 }
609
610 function fileDeleteError( $name )
611 {
612 $msg = str_replace( "$1", $name, wfMsg( "filedeleteerror" ) );
613 $this->fatalError( $msg );
614 }
615
616 function fileNotFoundError( $name )
617 {
618 $msg = str_replace( "$1", $name, wfMsg( "filenotfound" ) );
619 $this->fatalError( $msg );
620 }
621
622 function returnToMain( $auto = true )
623 {
624 global $wgUser, $wgOut, $returnto;
625
626 $sk = $wgUser->getSkin();
627 if ( "" == $returnto ) {
628 $returnto = wfMsg( "mainpage" );
629 }
630 $link = $sk->makeKnownLink( $returnto, "" );
631
632 $r = str_replace( "$1", $link, wfMsg( "returnto" ) );
633 if ( $auto ) {
634 $wgOut->addMeta( "http:Refresh", "10;url=" .
635 wfLocalUrlE( wfUrlencode( $returnto ) ) );
636 }
637 $wgOut->addHTML( "\n<p>$r\n" );
638 }
639
640 # Well, OK, it's actually about 14 passes. But since all the
641 # hard lifting is done inside PHP's regex code, it probably
642 # wouldn't speed things up much to add a real parser.
643 #
644 function doWikiPass2( $text, $linestart )
645 {
646 global $wgUser;
647 wfProfileIn( "OutputPage::doWikiPass2" );
648
649 $text = $this->removeHTMLtags( $text );
650 $text = $this->replaceVariables( $text );
651
652 $text = preg_replace( "/(^|\n)-----*/", "\\1<hr>", $text );
653 $text = str_replace ( "<HR>", "<hr>", $text );
654
655 $text = $this->doQuotes( $text );
656 $text = $this->doHeadings( $text );
657 $text = $this->doBlockLevels( $text, $linestart );
658
659 $text = $this->replaceExternalLinks( $text );
660 $text = $this->replaceInternalLinks ( $text );
661
662 $text = $this->magicISBN( $text );
663 $text = $this->magicRFC( $text );
664 $text = $this->autoNumberHeadings( $text );
665
666 $sk = $wgUser->getSkin();
667 $text = $sk->transformContent( $text );
668
669 wfProfileOut();
670 return $text;
671 }
672
673 /* private */ function doQuotes( $text )
674 {
675 $text = preg_replace( "/'''(.+)'''/mU", "<strong>\$1</strong>", $text );
676 $text = preg_replace( "/''(.+)''/mU", "<em>\$1</em>", $text );
677 return $text;
678 }
679
680 /* private */ function doHeadings( $text )
681 {
682 for ( $i = 6; $i >= 1; --$i ) {
683 $h = substr( "======", 0, $i );
684 $text = preg_replace( "/^{$h}([^=]+){$h}(\\s|$)/m",
685 "<h{$i}>\\1</h{$i}>\\2", $text );
686 }
687 return $text;
688 }
689
690 # Note: we have to do external links before the internal ones,
691 # and otherwise take great care in the order of things here, so
692 # that we don't end up interpreting some URLs twice.
693
694 /* private */ function replaceExternalLinks( $text )
695 {
696 wfProfileIn( "OutputPage::replaceExternalLinks" );
697 $text = $this->subReplaceExternalLinks( $text, "http", true );
698 $text = $this->subReplaceExternalLinks( $text, "https", true );
699 $text = $this->subReplaceExternalLinks( $text, "ftp", false );
700 $text = $this->subReplaceExternalLinks( $text, "gopher", false );
701 $text = $this->subReplaceExternalLinks( $text, "news", false );
702 $text = $this->subReplaceExternalLinks( $text, "mailto", false );
703 wfProfileOut();
704 return $text;
705 }
706
707 /* private */ function subReplaceExternalLinks( $s, $protocol, $autonumber )
708 {
709 global $wgUser, $printable;
710 global $wgAllowExternalImages;
711
712
713 $unique = "4jzAfzB8hNvf4sqyO9Edd8pSmk9rE2in0Tgw3";
714 $uc = "A-Za-z0-9_\\/~%\\-+&*#?!=()@\\x80-\\xFF";
715
716 # this is the list of separators that should be ignored if they
717 # are the last character of an URL but that should be included
718 # if they occur within the URL, e.g. "go to www.foo.com, where .."
719 # in this case, the last comma should not become part of the URL,
720 # but in "www.foo.com/123,2342,32.htm" it should.
721 $sep = ",;\.:";
722 $fnc = "A-Za-z0-9_.,~%\\-+&;#*?!=()@\\x80-\\xFF";
723 $images = "gif|png|jpg|jpeg";
724
725 # PLEASE NOTE: The curly braces { } are not part of the regex,
726 # they are interpreted as part of the string (used to tell PHP
727 # that the content of the string should be inserted there).
728 $e1 = "/(^|[^\\[])({$protocol}:)([{$uc}{$sep}]+)\\/([{$fnc}]+)\\." .
729 "((?i){$images})([^{$uc}]|$)/";
730
731 $e2 = "/(^|[^\\[])({$protocol}:)(([".$uc."]|[".$sep."][".$uc."])+)([^". $uc . $sep. "]|[".$sep."]|$)/";
732 $sk = $wgUser->getSkin();
733
734 if ( $autonumber and $wgAllowExternalImages) { # Use img tags only for HTTP urls
735 $s = preg_replace( $e1, "\\1" . $sk->makeImage( "{$unique}:\\3" .
736 "/\\4.\\5", "\\4.\\5" ) . "\\6", $s );
737 }
738 $s = preg_replace( $e2, "\\1" . "<a href=\"{$unique}:\\3\"" .
739 $sk->getExternalLinkAttributes( "{$unique}:\\3", wfEscapeHTML(
740 "{$unique}:\\3" ) ) . ">" . wfEscapeHTML( "{$unique}:\\3" ) .
741 "</a>\\5", $s );
742 $s = str_replace( $unique, $protocol, $s );
743
744 $a = explode( "[{$protocol}:", " " . $s );
745 $s = array_shift( $a );
746 $s = substr( $s, 1 );
747
748 $e1 = "/^([{$uc}"."{$sep}]+)](.*)\$/sD";
749 $e2 = "/^([{$uc}"."{$sep}]+)\\s+([^\\]]+)](.*)\$/sD";
750
751 foreach ( $a as $line ) {
752 if ( preg_match( $e1, $line, $m ) ) {
753 $link = "{$protocol}:{$m[1]}";
754 $trail = $m[2];
755 if ( $autonumber ) { $text = "[" . ++$this->mAutonumber . "]"; }
756 else { $text = wfEscapeHTML( $link ); }
757 } else if ( preg_match( $e2, $line, $m ) ) {
758 $link = "{$protocol}:{$m[1]}";
759 $text = $m[2];
760 $trail = $m[3];
761 } else {
762 $s .= "[{$protocol}:" . $line;
763 continue;
764 }
765 if ( $printable == "yes") $paren = " (<i>" . htmlspecialchars ( $link ) . "</i>)";
766 else $paren = "";
767 $la = $sk->getExternalLinkAttributes( $link, $text );
768 $s .= "<a href='{$link}'{$la}>{$text}</a>{$paren}{$trail}";
769
770 }
771 return $s;
772 }
773
774 /* private */ function replaceInternalLinks( $s )
775 {
776 global $wgTitle, $wgUser, $wgLang;
777 global $wgLinkCache, $wgInterwikiMagic;
778 global $wgNamespacesWithSubpages;
779 wfProfileIn( "OutputPage::replaceInternalLinks" );
780
781 $tc = Title::legalChars() . "#";
782 $sk = $wgUser->getSkin();
783
784 $a = explode( "[[", " " . $s );
785 $s = array_shift( $a );
786 $s = substr( $s, 1 );
787
788 $e1 = "/^([{$tc}]+)\\|([^]]+)]](.*)\$/sD";
789 $e2 = "/^([{$tc}]+)]](.*)\$/sD";
790
791 foreach ( $a as $line ) {
792 if ( preg_match( $e1, $line, $m ) ) { # page with alternate text
793
794 $text = $m[2];
795 $trail = $m[3];
796
797 } else if ( preg_match( $e2, $line, $m ) ) { # page with normal text
798
799 $text = "";
800 $trail = $m[2];
801 }
802
803 else { # Invalid form; output directly
804 $s .= "[[" . $line ;
805 continue;
806 }
807 if(substr($m[1],0,1)=="/") { # subpage
808 if(substr($m[1],-1,1)=="/") { # / at end means we don't want the slash to be shown
809 $m[1]=substr($m[1],1,strlen($m[1])-2);
810 $noslash=$m[1];
811
812 } else {
813 $noslash=substr($m[1],1);
814 }
815 if($wgNamespacesWithSubpages[$wgTitle->getNamespace()]) { # subpages allowed here
816 $link = $wgTitle->getPrefixedText(). "/" . trim($noslash);
817 if(!$text) {
818 $text= $m[1];
819 } # this might be changed for ugliness reasons
820 } else {
821 $link = $noslash; # no subpage allowed, use standard link
822 }
823 } else { # no subpage
824 $link = $m[1];
825 }
826
827 if ( preg_match( "/^([A-Za-z\\x80-\\xff]+):(.*)\$/", $link, $m ) ) {
828 $pre = strtolower( $m[1] );
829 $suf = $m[2];
830 if ( $wgLang->getNsIndex( $pre ) ==
831 Namespace::getImage() ) {
832 $nt = Title::newFromText( $suf );
833 $name = $nt->getDBkey();
834 if ( "" == $text ) { $text = $nt->GetText(); }
835
836 $wgLinkCache->addImageLink( $name );
837 $s .= $sk->makeImageLink( $name,
838 wfImageUrl( $name ), $text );
839 $s .= $trail;
840 } else if ( "media" == $pre ) {
841 $nt = Title::newFromText( $suf );
842 $name = $nt->getDBkey();
843 if ( "" == $text ) { $text = $nt->GetText(); }
844
845 $wgLinkCache->addImageLink( $name );
846 $s .= $sk->makeMediaLink( $name,
847 wfImageUrl( $name ), $text );
848 $s .= $trail;
849 } else {
850 $l = $wgLang->getLanguageName( $pre );
851 if ( "" == $l or !$wgInterwikiMagic or
852 Namespace::isTalk( $wgTitle->getNamespace() ) ) {
853 if ( "" == $text ) { $text = $link; }
854 $s .= $sk->makeLink( $link, $text, "", $trail );
855 } else {
856 array_push( $this->mLanguageLinks, "$pre:$suf" );
857 $s .= $trail;
858 }
859 }
860 # } else if ( 0 == strcmp( "##", substr( $link, 0, 2 ) ) ) {
861 # $link = substr( $link, 2 );
862 # $s .= "<a name=\"{$link}\">{$text}</a>{$trail}";
863 } else {
864 if ( "" == $text ) { $text = $link; }
865 $s .= $sk->makeLink( $link, $text, "", $trail );
866 }
867 }
868 wfProfileOut();
869 return $s;
870 }
871
872 # Some functions here used by doBlockLevels()
873 #
874 /* private */ function closeParagraph()
875 {
876 $result = "";
877 if ( 0 != strcmp( "p", $this->mLastSection ) &&
878 0 != strcmp( "", $this->mLastSection ) ) {
879 $result = "</" . $this->mLastSection . ">";
880 }
881 $this->mLastSection = "";
882 return $result;
883 }
884 # getCommon() returns the length of the longest common substring
885 # of both arguments, starting at the beginning of both.
886 #
887 /* private */ function getCommon( $st1, $st2 )
888 {
889 $fl = strlen( $st1 );
890 $shorter = strlen( $st2 );
891 if ( $fl < $shorter ) { $shorter = $fl; }
892
893 for ( $i = 0; $i < $shorter; ++$i ) {
894 if ( $st1{$i} != $st2{$i} ) { break; }
895 }
896 return $i;
897 }
898 # These next three functions open, continue, and close the list
899 # element appropriate to the prefix character passed into them.
900 #
901 /* private */ function openList( $char )
902 {
903 $result = $this->closeParagraph();
904
905 if ( "*" == $char ) { $result .= "<ul><li>"; }
906 else if ( "#" == $char ) { $result .= "<ol><li>"; }
907 else if ( ":" == $char ) { $result .= "<dl><dd>"; }
908 else if ( ";" == $char ) {
909 $result .= "<dl><dt>";
910 $this->mDTopen = true;
911 }
912 else { $result = "<!-- ERR 1 -->"; }
913
914 return $result;
915 }
916
917 /* private */ function nextItem( $char )
918 {
919 if ( "*" == $char || "#" == $char ) { return "</li><li>"; }
920 else if ( ":" == $char || ";" == $char ) {
921 $close = "</dd>";
922 if ( $this->mDTopen ) { $close = "</dt>"; }
923 if ( ";" == $char ) {
924 $this->mDTopen = true;
925 return $close . "<dt>";
926 } else {
927 $this->mDTopen = false;
928 return $close . "<dd>";
929 }
930 }
931 return "<!-- ERR 2 -->";
932 }
933
934 /* private */function closeList( $char )
935 {
936 if ( "*" == $char ) { return "</li></ul>"; }
937 else if ( "#" == $char ) { return "</li></ol>"; }
938 else if ( ":" == $char ) {
939 if ( $this->mDTopen ) {
940 $this->mDTopen = false;
941 return "</dt></dl>";
942 } else {
943 return "</dd></dl>";
944 }
945 }
946 return "<!-- ERR 3 -->";
947 }
948
949 /* private */ function doBlockLevels( $text, $linestart )
950 {
951 wfProfileIn( "OutputPage::doBlockLevels" );
952 # Parsing through the text line by line. The main thing
953 # happening here is handling of block-level elements p, pre,
954 # and making lists from lines starting with * # : etc.
955 #
956 $a = explode( "\n", $text );
957 $text = $lastPref = "";
958 $this->mDTopen = $inBlockElem = false;
959
960 if ( ! $linestart ) { $text .= array_shift( $a ); }
961 foreach ( $a as $t ) {
962 if ( "" != $text ) { $text .= "\n"; }
963
964 $oLine = $t;
965 $opl = strlen( $lastPref );
966 $npl = strspn( $t, "*#:;" );
967 $pref = substr( $t, 0, $npl );
968 $pref2 = str_replace( ";", ":", $pref );
969 $t = substr( $t, $npl );
970
971 if ( 0 != $npl && 0 == strcmp( $lastPref, $pref2 ) ) {
972 $text .= $this->nextItem( substr( $pref, -1 ) );
973
974 if ( ";" == substr( $pref, -1 ) ) {
975 $cpos = strpos( $t, ":" );
976 if ( ! ( false === $cpos ) ) {
977 $term = substr( $t, 0, $cpos );
978 $text .= $term . $this->nextItem( ":" );
979 $t = substr( $t, $cpos + 1 );
980 }
981 }
982 } else if (0 != $npl || 0 != $opl) {
983 $cpl = $this->getCommon( $pref, $lastPref );
984
985 while ( $cpl < $opl ) {
986 $text .= $this->closeList( $lastPref{$opl-1} );
987 --$opl;
988 }
989 if ( $npl <= $cpl && $cpl > 0 ) {
990 $text .= $this->nextItem( $pref{$cpl-1} );
991 }
992 while ( $npl > $cpl ) {
993 $char = substr( $pref, $cpl, 1 );
994 $text .= $this->openList( $char );
995
996 if ( ";" == $char ) {
997 $cpos = strpos( $t, ":" );
998 if ( ! ( false === $cpos ) ) {
999 $term = substr( $t, 0, $cpos );
1000 $text .= $term . $this->nextItem( ":" );
1001 $t = substr( $t, $cpos + 1 );
1002 }
1003 }
1004 ++$cpl;
1005 }
1006 $lastPref = $pref2;
1007 }
1008 if ( 0 == $npl ) { # No prefix--go to paragraph mode
1009 if ( preg_match(
1010 "/(<table|<blockquote|<h1|<h2|<h3|<h4|<h5|<h6)/i", $t ) ) {
1011 $text .= $this->closeParagraph();
1012 $inBlockElem = true;
1013 }
1014 if ( ! $inBlockElem ) {
1015 if ( " " == $t{0} ) {
1016 $newSection = "pre";
1017 # $t = wfEscapeHTML( $t );
1018 }
1019 else { $newSection = "p"; }
1020
1021 if ( 0 == strcmp( "", trim( $oLine ) ) ) {
1022 $text .= $this->closeParagraph();
1023 $text .= "<" . $newSection . ">";
1024 } else if ( 0 != strcmp( $this->mLastSection,
1025 $newSection ) ) {
1026 $text .= $this->closeParagraph();
1027 if ( 0 != strcmp( "p", $newSection ) ) {
1028 $text .= "<" . $newSection . ">";
1029 }
1030 }
1031 $this->mLastSection = $newSection;
1032 }
1033 if ( $inBlockElem &&
1034 preg_match( "/(<\\/table|<\\/blockquote|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6)/i", $t ) ) {
1035 $inBlockElem = false;
1036 }
1037 }
1038 $text .= $t;
1039 }
1040 while ( $npl ) {
1041 $text .= $this->closeList( $pref2{$npl-1} );
1042 --$npl;
1043 }
1044 if ( "" != $this->mLastSection ) {
1045 if ( "p" != $this->mLastSection ) {
1046 $text .= "</" . $this->mLastSection . ">";
1047 }
1048 $this->mLastSection = "";
1049 }
1050 wfProfileOut();
1051 return $text;
1052 }
1053
1054 /* private */ function replaceVariables( $text )
1055 {
1056 global $wgLang;
1057 wfProfileIn( "OutputPage:replaceVariables" );
1058
1059 $v = date( "m" );
1060 $text = str_replace( "{{CURRENTMONTH}}", $v, $text );
1061 $v = $wgLang->getMonthName( date( "n" ) );
1062 $text = str_replace( "{{CURRENTMONTHNAME}}", $v, $text );
1063 $v = $wgLang->getMonthNameGen( date( "n" ) );
1064 $text = str_replace( "{{CURRENTMONTHNAMEGEN}}", $v, $text );
1065 $v = date( "j" );
1066 $text = str_replace( "{{CURRENTDAY}}", $v, $text );
1067 $v = $wgLang->getWeekdayName( date( "w" )+1 );
1068 $text = str_replace( "{{CURRENTDAYNAME}}", $v, $text );
1069 $v = date( "Y" );
1070 $text = str_replace( "{{CURRENTYEAR}}", $v, $text );
1071 $v = $wgLang->time( date( "YmdHis" ), false );
1072 $text = str_replace( "{{CURRENTTIME}}", $v, $text );
1073
1074 if ( false !== strstr( $text, "{{NUMBEROFARTICLES}}" ) ) {
1075 $v = wfNumberOfArticles();
1076 $text = str_replace( "{{NUMBEROFARTICLES}}", $v, $text );
1077 }
1078 wfProfileOut();
1079 return $text;
1080 }
1081
1082 /* private */ function removeHTMLtags( $text )
1083 {
1084 wfProfileIn( "OutputPage::removeHTMLtags" );
1085 $htmlpairs = array( # Tags that must be closed
1086 "b", "i", "u", "font", "big", "small", "sub", "sup", "h1",
1087 "h2", "h3", "h4", "h5", "h6", "cite", "code", "em", "s",
1088 "strike", "strong", "tt", "var", "div", "center",
1089 "blockquote", "ol", "ul", "dl", "table", "caption", "pre",
1090 "ruby", "rt" , "rb" , "rp"
1091 );
1092 $htmlsingle = array(
1093 "br", "p", "hr", "li", "dt", "dd"
1094 );
1095 $htmlnest = array( # Tags that can be nested--??
1096 "table", "tr", "td", "th", "div", "blockquote", "ol", "ul",
1097 "dl", "font", "big", "small", "sub", "sup"
1098 );
1099 $tabletags = array( # Can only appear inside table
1100 "td", "th", "tr"
1101 );
1102
1103 $htmlsingle = array_merge( $tabletags, $htmlsingle );
1104 $htmlelements = array_merge( $htmlsingle, $htmlpairs );
1105
1106 $htmlattrs = array( # Allowed attributes--no scripting, etc.
1107 "title", "align", "lang", "dir", "width", "height",
1108 "bgcolor", "clear", /* BR */ "noshade", /* HR */
1109 "cite", /* BLOCKQUOTE, Q */ "size", "face", "color",
1110 /* FONT */ "type", "start", "value", "compact",
1111 /* For various lists, mostly deprecated but safe */
1112 "summary", "width", "border", "frame", "rules",
1113 "cellspacing", "cellpadding", "valign", "char",
1114 "charoff", "colgroup", "col", "span", "abbr", "axis",
1115 "headers", "scope", "rowspan", "colspan", /* Tables */
1116 "id", "class", "name", "style" /* For CSS */
1117 );
1118
1119 # Remove HTML comments
1120 $text = preg_replace( "/<!--.*-->/sU", "", $text );
1121
1122 $bits = explode( "<", $text );
1123 $text = array_shift( $bits );
1124 $tagstack = array(); $tablestack = array();
1125
1126 foreach ( $bits as $x ) {
1127 $prev = error_reporting( E_ALL & ~( E_NOTICE | E_WARNING ) );
1128 preg_match( "/^(\\/?)(\\w+)([^>]*)(\\/{0,1}>)([^<]*)$/",
1129 $x, $regs );
1130 list( $qbar, $slash, $t, $params, $brace, $rest ) = $regs;
1131 error_reporting( $prev );
1132
1133 $badtag = 0 ;
1134 if ( in_array( $t = strtolower( $t ), $htmlelements ) ) {
1135 # Check our stack
1136 if ( $slash ) {
1137 # Closing a tag...
1138 if ( ! in_array( $t, $htmlsingle ) &&
1139 ( $ot = array_pop( $tagstack ) ) != $t ) {
1140 array_push( $tagstack, $ot );
1141 $badtag = 1;
1142 } else {
1143 if ( $t == "table" ) {
1144 $tagstack = array_pop( $tablestack );
1145 }
1146 $newparams = "";
1147 }
1148 } else {
1149 # Keep track for later
1150 if ( in_array( $t, $tabletags ) &&
1151 ! in_array( "table", $tagstack ) ) {
1152 $badtag = 1;
1153 } else if ( in_array( $t, $tagstack ) &&
1154 ! in_array ( $t , $htmlnest ) ) {
1155 $badtag = 1 ;
1156 } else if ( ! in_array( $t, $htmlsingle ) ) {
1157 if ( $t == "table" ) {
1158 array_push( $tablestack, $tagstack );
1159 $tagstack = array();
1160 }
1161 array_push( $tagstack, $t );
1162 }
1163 # Strip non-approved attributes from the tag
1164 $newparams = preg_replace(
1165 "/(\\w+)(\\s*=\\s*([^\\s\">]+|\"[^\">]*\"))?/e",
1166 "(in_array(strtolower(\"\$1\"),\$htmlattrs)?(\"\$1\".((\"x\$3\" != \"x\")?\"=\$3\":'')):'')",
1167 $params);
1168 }
1169 if ( ! $badtag ) {
1170 $rest = str_replace( ">", "&gt;", $rest );
1171 $text .= "<$slash$t$newparams$brace$rest";
1172 continue;
1173 }
1174 }
1175 $text .= "&lt;" . str_replace( ">", "&gt;", $x);
1176 }
1177 # Close off any remaining tags
1178 while ( $t = array_pop( $tagstack ) ) {
1179 $text .= "</$t>\n";
1180 if ( $t == "table" ) { $tagstack = array_pop( $tablestack ); }
1181 }
1182 wfProfileOut();
1183 return $text;
1184 }
1185
1186 /* private */ function autoNumberHeadings( $text )
1187 {
1188 global $wgUser;
1189 if ( 1 != $wgUser->getOption( "numberheadings" ) ) {
1190 return $text;
1191 }
1192 $j = 0;
1193 $n = -1;
1194 for ( $i = 0; $i < 9; ++$i ) {
1195 if ( stristr( $text, "<h$i>" ) != false ) {
1196 ++$j;
1197 if ( $n == -1 ) $n = $i;
1198 }
1199 }
1200 if ( $j < 2 ) return $text;
1201 $i = $n;
1202 $v = array( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
1203 $t = "";
1204 while ( count( spliti( "<h", $text, 2 ) ) == 2 ) {
1205 $a = spliti( "<h", $text, 2 );
1206 $j = substr( $a[1], 0, 1 );
1207 if ( strtolower( $j ) != "r" ) {
1208 $t .= $a[0] . "<h" . $j . ">";
1209 ++$v[$j];
1210 $b = array();
1211 for ( $k = $i; $k <= $j; $k++ ) array_push( $b, $v[$k] );
1212 for ( $k = $j+1; $k < 9; $k++ ) $v[$k] = 0;
1213 $t .= implode( ".", $b ) . " ";
1214 $text = substr( $a[1] , 2 ) ;
1215 } else { # <HR> tag, not a heading!
1216 $t .= $a[0] . "<hr>";
1217 $text = substr( $a[1], 2 );
1218 }
1219 }
1220 return $t . $text;
1221 }
1222
1223 /* private */ function magicISBN( $text )
1224 {
1225 global $wgLang;
1226
1227 $a = split( "ISBN ", " $text" );
1228 if ( count ( $a ) < 2 ) return $text;
1229 $text = substr( array_shift( $a ), 1);
1230 $valid = "0123456789-ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1231
1232 foreach ( $a as $x ) {
1233 $isbn = $blank = "" ;
1234 while ( " " == $x{0} ) {
1235 $blank .= " ";
1236 $x = substr( $x, 1 );
1237 }
1238 while ( strstr( $valid, $x{0} ) != false ) {
1239 $isbn .= $x{0};
1240 $x = substr( $x, 1 );
1241 }
1242 $num = str_replace( "-", "", $isbn );
1243 $num = str_replace( " ", "", $num );
1244
1245 if ( "" == $num ) {
1246 $text .= "ISBN $blank$x";
1247 } else {
1248 $text .= "<a href=\"" . wfLocalUrlE( $wgLang->specialPage(
1249 "Booksources"), "isbn={$num}" ) . "\">ISBN $isbn</a>";
1250 $text .= $x;
1251 }
1252 }
1253 return $text;
1254 }
1255
1256 /* private */ function magicRFC( $text )
1257 {
1258 return $text;
1259 }
1260
1261 /* private */ function headElement()
1262 {
1263 global $wgDocType, $wgUser, $wgLanguageCode, $wgOutputEncoding;
1264
1265 $ret = "<!DOCTYPE HTML PUBLIC \"$wgDocType\">\n";
1266
1267 if ( "" == $this->mHTMLtitle ) {
1268 $this->mHTMLtitle = $this->mPagetitle;
1269 }
1270 $ret .= "<html lang=\"$wgLanguageCode\"><head><title>{$this->mHTMLtitle}</title>\n";
1271 array_push( $this->mMetatags, array( "http:Content-type", "text/html; charset={$wgOutputEncoding}" ) );
1272 foreach ( $this->mMetatags as $tag ) {
1273 if ( 0 == strcasecmp( "http:", substr( $tag[0], 0, 5 ) ) ) {
1274 $a = "http-equiv";
1275 $tag[0] = substr( $tag[0], 5 );
1276 } else {
1277 $a = "name";
1278 }
1279 $ret .= "<meta $a=\"{$tag[0]}\" content=\"{$tag[1]}\">\n";
1280 }
1281 $p = $this->mRobotpolicy;
1282 if ( "" == $p ) { $p = "index,follow"; }
1283 $ret .= "<meta name=\"robots\" content=\"$p\">\n";
1284
1285 if ( count( $this->mKeywords ) > 0 ) {
1286 $ret .= "<meta name=\"keywords\" content=\"" .
1287 implode( ",", $this->mKeywords ) . "\">\n";
1288 }
1289 foreach ( $this->mLinktags as $tag ) {
1290 $ret .= "<link ";
1291 if ( "" != $tag[0] ) { $ret .= "rel=\"{$tag[0]}\" "; }
1292 if ( "" != $tag[1] ) { $ret .= "rev=\"{$tag[1]}\" "; }
1293 $ret .= "href=\"{$tag[2]}\">\n";
1294 }
1295 $sk = $wgUser->getSkin();
1296 $ret .= $sk->getHeadScripts();
1297 $ret .= $sk->getUserStyles();
1298
1299 $ret .= "</head>\n";
1300 return $ret;
1301 }
1302 }
1303
1304 ?>