MediaWiki RawFile
RawFile is an extension made by Philippe Teuwen to allow downloading directly text in <pre> or <source> block as a file.
This page is part of the pages dedicated to Mediawiki.
- RawFile on Yobi.be (latest version)
- Extension:RawFile on mediawiki.
Download and install instructions
- Download file RawFile.php below, and copy it to $IP/extensions/RawFile/RawFile.php on your mediawiki server.
<?php
if (defined('MEDIAWIKI')) {
//Avoid unstubbing $wgParser on setHook() too early on modern (1.12+) MW versions, as per r35980
if ( defined( 'MW_SUPPORTS_PARSERFIRSTCALLINIT' ) ) {
$wgHooks['ParserFirstCallInit'][] = 'efRawFile_Setup';
} else { // Otherwise do things the old fashioned way
$wgExtensionFunctions[] = 'efRawFile_Setup';
}
$wgHooks['LanguageGetMagic'][] = 'efRawFile_Magic';
$wgHooks['RawPageViewBeforeOutput'][] = 'fnRawFile_Strip';
function efRawFile_Setup() {
global $wgParser;
$wgParser->setFunctionHook( 'file', 'efRawFile_Render' );
$wgParser->setFunctionHook( 'filelink', 'efRawFile_Render' );
$wgParser->setFunctionHook( 'fileanchor', 'efRawFile_Empty' );
$wgParser->setHook( 'file', 'efRawFile_FileTagRender' );
return true;
}
function efRawFile_Magic( &$magicWords, $langCode ) {
$magicWords['file'] = array( 0, 'file' );
$magicWords['filelink'] = array( 0, 'filelink' );
$magicWords['fileanchor'] = array( 0, 'fileanchor' );
return true;
}
function efRawFile_Render( &$parser, $filename = '', $titleText = '') {
if( $titleText == '' )
$title = $parser->mTitle;
else
$title = Title::newFromText( $titleText );
//Don't expand templates or we'll lose our anchors {{#...}}
return $title->getFullURL( 'action=raw&anchor='.urlencode( $filename ) );
}
function efRawFile_Empty( &$parser, $filename = '') {
return '';
}
function efRawFile_FileTagRender( $input, $args, $parser, $frame ) {
if( $args['title'] == '' )
$title = $parser->mTitle;
else
$title = Title::newFromText($parser->recursiveTagParse( $args['title'], $frame ));
//We expand templates, so <file> tag cannot be mixed with {{#fileanchor}} anchors
$link=$title->getFullURL( 'action=raw&templates=expand' );
if( $args['name'] != '' )
$link.='&name='.urlencode( $parser->recursiveTagParse( $args['name'], $frame ) );
if( $args['anchor'] != '' )
$link.='&anchor='.urlencode( $parser->recursiveTagParse( $args['anchor'], $frame ) );
if( $args['tag'] != '' )
$link.='&tag='.urlencode( $parser->recursiveTagParse( $args['tag'], $frame ) );
return $parser->recursiveTagParse( "[$link $input]", $frame );
}
function fnRawFile_Strip_Error($msg,$out,&$text) {
$text=$msg;
if($out != '')
$text.="\nCandidate match: $out";
return true;
}
function fnRawFile_Strip(&$rawPage, &$text) {
$filename=$_GET['name'];
$anchor=$_GET['anchor'];
// for backward compatibility, accept also URLs with parameter 'file'
if( $anchor=='' )
$anchor=$_GET['file'];
$tag=$_GET['tag'];
// Either anchor or name must be specified
if( $filename=='' )
$filename=$anchor;
if ( $filename=='' )
return true;
// Uncomment the following line to avoid output buffering and gzipping:
// wfResetOutputBuffers();
header("Content-disposition: attachment;filename={$filename}");
header("Content-type: application/octet-stream");
header("Content-Transfer-Encoding: binary");
header("Expires: 0");
header("Pragma: no-cache");
header("Cache-Control: no-store");
$maskedtext=preg_replace_callback('!<nowiki>.*?</nowiki>!s',
function($m) { return ereg_replace(".","X",$m[0]); },
$text);
if (($anchor!='') && preg_match_all('/({{#fileanchor: *'.$anchor.' *}})|(<[^>]+ class *= *"([^"]*\w)?'.$anchor.'(\w[^"]*)?"[^>]*>)/i', $maskedtext, $matches, PREG_OFFSET_CAPTURE))
$offsets=$matches[0];
else if (preg_match_all('/{{#file: *'.$anchor.' *}}/i', $maskedtext, $matches, PREG_OFFSET_CAPTURE))
$offsets=array($matches[0][0]);
else if (preg_match_all('/<file( [^>]*)? name *= *"'.$filename.'"[^>]*>/i', $maskedtext, $matches, PREG_OFFSET_CAPTURE))
$offsets=array($matches[0][0]);
else {
// We didn't find our anchor
return fnRawFile_Strip_Error("ERROR - RawFile: anchor not found (anchor=$anchor, name=$filename, tag=$tag)","",$text);
}
unset($maskedtext);
$textorig=$text;
$text='';
foreach ($offsets as $offset) {
$out = substr($textorig, $offset[1]);
// If no tag specified, we take the first one
if ($tag == '')
{
// With a regex assertion, we can easily ignore 'br' and 'file' tags
if (!preg_match('/<((?!br\b|file\b)\w+\b)/', $out, $matches))
return fnRawFile_Strip_Error ("ERROR - RawFile: Can't find opening tag after anchor '$offset[0]' (anchor=$anchor, name=$filename, tag=$tag)",$out,$text);
$tag=$matches[1];
}
// Find the first tag matching $tag, and return enclosed text
if (!preg_match('/<'.$tag.'( [^>]*)?>\n?(.*?)<\/'.$tag.'>/s', $out, $matches))
return fnRawFile_Strip_Error ("ERROR - RawFile: no closing '$tag' found after anchor '$offset[0]' (anchor=$anchor, name=$filename, tag=$tag)",$out,$text);
$text .= $matches[2];
}
return true;
}
$wgExtensionCredits['parserhook'][] = array('name' => 'RawFile',
'version' => '0.5-mip.2',
'author' => 'Philippe Teuwen, Michael Peeters (modified by Jani Uusitalo)',
'url' => 'http://www.mediawiki.org/wiki/Extension:RawFile',
// 'url' => 'http://wiki.yobi.be/wiki/Mediawiki_RawFile',
'description' => 'Downloads a RAW copy of <nowiki><tag>data</tag></nowiki> in a file<br>'.
'Useful e.g. to download a script or a patch<br>'.
'It also allows what is called [http://en.wikipedia.org/wiki/Literate_programming Literate Programming]');
}
?>
- Edit $IP/LocalSettings.php, and add to the end of the file:
require_once("$IP/extensions/RawFile/RawFile.php");
History
- Version 0.5-mip.2
- Expand templates in raw output when using tag
<file>
to improve use of this tag in template. This allows to have the file content to come from templates as well (see Mediawiki parameters to index.php?action=raw).
- Version 0.5-mip.1
- Import changes from Mummila. This allows expanding template parameters in
<file>
tag.
Examples
Examples as for version 0.4:
* '''Method 1''': Returns the block that immediately follows. Save [{{#file: method1.txt}} this file]: <code>Hello, World!</code> : But this other example fails because of the <br> tag... So save [{{#file: method1-fail.txt}} this file]:<br> :<code>Hello, World!</code>. * '''Method 2''': Indicates the block(s) with anchors. Save [{{#filelink: method2.txt}} this file] (but not this <code>code text</code>):<br> :{{#fileanchor: method2.txt}}<code>We can then </code> very easily {{#fileanchor: method2.txt}}<code>interleave downloadable text with wiki comments</code> * '''Method 3''': Same as above, but using html attribute 'class'. Save [{{#filelink: method3.txt}} this file] (but not this <code>code text</code>):<br> :{{#fileanchor: method3.txt}}<code>We can still </code> very easily <code class="method3.txt">interleave downloadable text with wiki comments but with less typing</code> <code class="method3.txt"> Obviously, there is absolutely no limitation on the size of the text </code> * '''Method 4''': Same as method 1, but using new syntax (custom wiki tag). Save <file name="method4.txt">'''this''' file</file>: <code>Hello, World!</code> * '''Method 5''': Same as above, but specifying which tag to include. Save ''<file name="method5.txt" tag="code">this file</file>'': <source lang="text">This text is skipped.</source> :<code>This is the text that will be returned...</code> * '''Method 6''': Same as method 2 / 3, but using new syntax (custom wiki tag). Save <file anchor="method6.txt">this file</file>. Of course the old syntax <code>{{#fileanchor}}</code> for anchor is still supported.<br> :{{#fileanchor: method6.txt}}<code>Again, we can </code>also very easily <code class="method6.txt">interleave downloadable code with wiki text while using the new syntax</code>
This gives:
- Method 1: Returns the block that immediately follows. Save [{{#file: method1.txt}} this file]:
Hello, World!
- But this other example fails because of the <br> tag... So save [{{#file: method1-fail.txt}} this file]:
Hello, World!
.
- Method 2: Indicates the block(s) with anchors. Save [{{#filelink: method2.txt}} this file] (but not this
code text
):
- {{#fileanchor: method2.txt}}
We can then
very easily {{#fileanchor: method2.txt}}interleave downloadable text with wiki comments
- Method 3: Same as above, but using html attribute 'class'. Save [{{#filelink: method3.txt}} this file] (but not this
code text
):
- {{#fileanchor: method3.txt}}
We can still
very easilyinterleave downloadable text with wiki comments but with less typing
s
Obviously, there is absolutely
no limitation
on the size of the
text
- Method 4: Same as method 1, but using new syntax (custom wiki tag). Save <file name="method4.txt">this file</file>:
Hello, World!
- Method 5: Same as above, but specifying which tag to include. Save <file name="method5.txt" tag="code">this file</file>:
This text is skipped.
This is the text that will be returned...
- Method 6: Same as method 2 / 3, but using new syntax (custom wiki tag). Save <file anchor="method6.txt">this file</file>. Of course the old syntax
{{#fileanchor}}
for anchor is still supported.
- {{#fileanchor: method6.txt}}
Again, we can
also very easilyinterleave downloadable code with wiki text while using the new syntax
References:
Patches
I contributed some changes to RawFile. The patch are detailed below.
Patch v0.2 → v0.3
The patch below adds an optional parameter to hook {{#filelink}}. With 1 param, the file is fetched from the current page as usual:
Save [{{#filelink: fstab}} this file] in your <tt>/etc</tt> directory.
With 2 param, the 2nd param is telling which page to fetch the file from:
Save [{{#filelink: fstab|Config files - fstab}} this file] in your <tt>/etc</tt> directory.
--- original/RawFile.php 2009-09-21 16:20:51.000000000 +0200
+++ patched/RawFile.php 2009-09-21 18:07:06.000000000 +0200
@@ -18,8 +18,12 @@
$magicWords['fileanchor'] = array( 0, 'fileanchor' );
return true;
}
-function efRawFile_Render( &$parser, $filename = '') {
- return $parser->mTitle->getFullURL( 'action=raw&file='.urlencode( $filename ) );
+function efRawFile_Render( &$parser, $filename = '', $titleText = '') {
+ if( $titleText == '' ) {
+ $titleText = $parser->mTitle->getText();
+ }
+ $title=Title::newFromText( $titleText );
+ return $title->getFullURL( 'action=raw&file='.urlencode( $filename ) );
}
function efRawFile_Empty( &$parser, $filename = '') {
return '';
Patch v0.3 → v0.4
Changes in v0.4
- Anchors can be specified using html class attribute
- New syntax for Links and Anchor-links:
<file [name="..."] [anchor="..."] [tag="..."] [title="..."] >Link text</file>
- Support multiple files on the same page with same name.
- Can specify the tag name of the block to download (to skip some irrelevant blocks when using an anchor-link).
- Ignore
<br>
tag. - Some error reporting.
The extension introduces 3 elements:
- Anchor
- Used to flag that the next code block in the wiki text belongs to a specific file. The code block can be any wiki block (such as
<pre>
,<code>
,<tt>
,<source>
...).<br>
tags are ignored. Note that anchors are invisible in the wiki display. - Link
- They are transformed by the extension into links that allows for downloading all blocks attached to a given anchor name.
- Anchor-link
- A shortcut notation mixing both an anchor and download link, handy for regular use, when a single code block is used and when the download link can be at the same position as the anchor.
The syntax is as follows. The syntax using tag <file>
and tag attribute class
is new since v0.4. Note that elements of both syntaxes can be mixed in a same page.
Element | Syntax and description |
---|---|
Anchor | {{#fileAnchor: anchorname}} <pre class='anchorname'>...</pre> <code class="anchorname">...</code> <code class="cssclass anchorname">...</code> ... Indicates that the next wiki block is attached to an anchor anchorname. The content of that block will be downloaded (possibly appended with other blocks if there are several blocks attached to the same anchorname) when a file link is clicked on.
|
Link | [{{#fileLink: anchorname}} link text] [{{#fileLink: anchorname|pagetitle}} link text] <file anchor="anchorname" [name="filename"] [title="pagetitle"]>link text</file> Creates a link to download all blocks that are attached to an anchor anchorname.
|
Anchor-link | [{{#file: filename}} link text] <file name="filename" [tag="''tagname''"]>link text</file> Creates a link to download the next wiki block as a file named filename.
|
Bugs
- RawFile does not work well in templates. This is because templates parameters in tag values are not expanded by MediaWiki. See bugzilla 61341.