User:Austin J. Che/Extensions/LatexDoc
From OpenWetWare
The LatexDoc extension in MediaWiki SVN has been modified as follows:
- The biggest change is to allow use of other files on the wiki so that bibtex and graphics works.
- Requires latexmk
- The default location for latexmk is in the extensions directory of your mediawiki installation.
- If you wish to use a different location, add $wgLatexDoc->latexmk = "/path/to/latexmk"; in LocalSettings.php after requiring/including LatexDoc.php.
- Removed DVI output (not useful on web)
- Security: Removed filter for "obviously dangerous control words" as it isn't a good security mechanism.
- Instead, change texmf.cnf so that shell_escape=f, openout_any=p, and openin_any=p. This disallows running system commands and reading or writing any files not under the directory of the tex file.
- texmf.cnf is located in /usr/share/texmf/web2c/texmf.cnf on tetex distributions. Debian users should edit /etc/texmf/texmf.d/95NonPath.cnf and run update-texmf as root.
- You may also want to run latex under a chroot jail.
- If anyone notices any other security issues, please let me know.
- Instead, change texmf.cnf so that shell_escape=f, openout_any=p, and openin_any=p. This disallows running system commands and reading or writing any files not under the directory of the tex file.
- Added link to get the log file
- If you want automatic syntax highlighting, install the SyntaxHighlight extension (and GeSHi).
Usage:
Any wiki page that looks like a latex document will automatically have links for added to the top. The Get PDF link will generate a PDF or grab it from the cache if it exists and the Regenerate PDF forces the PDF file to be regenerated.
The special command \usewikifile{Wiki Page Name}{texfilename} can be used. All such commands are stripped before being passed to latexmk for generation of pdf. In addition, the contents of Wiki Page Name are saved as texfilename in the same directory as the page. Thus, you can include graphics or use bibtex where the graphics and .bib file are stored on the wiki. Hint: If you wish to use the same file both on and off the wiki, you can put the \usewikifile in a comment or some other place where normal LaTeX won't parse it (such as after \end{document}). The extension does not care at all the context or the location of the command.
See an example.
Code
<?php /* This extension has been modified by Austin Che (c) 2006 See http://openwetware.org/wiki/User:Austin_J._Che/Extensions/LatexDoc for the latest documentation Changes: - Uses syntax highlighting if the SyntaxHighlight extension is installed - Uses/requires latexmk - Allows use of other files on wiki such as for bibtex and graphics - Removed DVI output (isn't very useful on web) - Removed filter for "obviously dangerous control words" (not a good security mechanism) - Add link to get log file Security: change texmf.cnf so that shell_escape=f openout_any=p openin_any=p and/or run latex under a chroot jail. Released under the GNU GPL. ---------------------------------------- Original documentation: INSTALLATION ------------ This is an extension for the collaborative editing of LaTeX documents. Installation is by the usual method, put the following line in your LocalSettings.php: require_once( "extensions/LatexDoc/LatexDoc.php" ); This creates an object called $wgLatexDoc. Member variables of that object can be changed in order to customise the behaviour of the extension. latexCommand Path to the latex command pdflatexCommand Path to the pdflatex command. This must be installed, otherwise the PDF links won't work. workingDir Filesystem directory where all related files go. Must be in the web server document root. workingPath Relative URI of workingDir All of these variables have sensible defaults, as long as latex and pdflatex are in the PATH, it should work out of the box. USE --- The extension operates by searching the text of articles at render time for "\begin{document}". If this string is present, the article is not rendered like ordinary wikitext. Instead, it's displayed with a fixed-width font, with a "Make DVI" and a "Make PDF" link at the top. Clicking on the links will invoke latex, generate the requested file, and redirect the browser to it. SECURITY -------- Executing LaTeX documents written by untrusted users is a security risk. I've put in a simple filter for some obviously dangerous control words, but there may well be holes. No guarantee is made. If you're brave enough to make a wiki with this extension publically editable, it's recommended that you run latex from a chroot jail. KEEP BACKUPS OF IMPORTANT DATA! COPYING ------- LatexDoc.php and this documentation were written by Tim Starling, (c) 2005. You may choose one of the following two licenses, at your option: 1) The GNU General Public License 2) You may use or copy this work for any purpose, with the sole restriction that the rights of GPL licensors other than myself are not infringed. Assessment of the extent of those rights is at your own risk. */ if ( !defined( 'MEDIAWIKI' ) ) { die( "Not a valid entry point\n" ); } $wgExtensionFunctions[] = 'wfLatexDocInit'; $wgExtensionCredits['other'][] = array( 'name' => 'LatexDoc', 'version' => '2008/03/09', 'author' => 'Austin Che', 'url' => 'http://openwetware.org/wiki/User:Austin_J._Che/Extensions/LatexDoc', 'description' => 'Write LaTeX documents on the wiki', ); class LatexDoc { var $latexmk; // full path to latexmk var $args; // args to latexmk var $workingDir; var $workingPath; function LatexDoc() { global $wgUploadDirectory, $wgUploadPath, $IP; $this->latexmk = "$IP/extensions/latexmk"; $this->args = "-f -silent -pdf"; if ($wgUploadDirectory) $this->workingDir = "$wgUploadDirectory/latexdoc"; else $this->workingDir = "$IP/images/latexdoc"; if ($wgUploadPath) $this->workingPath = "$wgUploadPath/latexdoc"; else $this->workingPath = "$wgScriptPath/images/latexdoc"; } function onUnknownAction( $action, &$article ) { global $wgOut, $wgRequest, $IP; // Respond only to latexdoc action if ( $action != 'latexdoc' ) { return true; } // Check for non-existent article if ( !$article || !( $text = $article->fetchContent() ) ) { $wgOut->addWikiText( wfMsg( 'latexdoc_no_text' ) ); return false; } // Check permissions if ( !$article->mTitle->userCanRead() ) { $wgOut->loginToUse(); return false; } $ext = $wgRequest->getText( 'ext' ); $wgOut->setArticleFlag( false ); $wgOut->setArticleRelated( true ); $wgOut->setRobotpolicy( 'noindex,nofollow' ); $wgOut->setPageTitle( $article->mTitle->getPrefixedText() ); // Get path if ( !is_dir( $this->workingDir ) ) { if ( !mkdir( $this->workingDir, 0777 ) ) { $wgOut->addWikiText( wfMsg( 'latexdoc_cant_create_dir', $this->workingDir ) ); return false; } } chdir( $this->workingDir ); $hash = md5( $text ); $filename = 'ltd_' . $hash; $fullpath = $this->workingDir . '/' . $filename; $url = $this->workingPath . '/' . $filename; if ( ! $wgRequest->getBool('cache', true) && file_exists( "$fullpath.$ext")) @unlink("$fullpath.$ext"); if ( ! file_exists( "$fullpath.$ext" ) ) { // need to generate/regenerate the output if ($this->getHelperFiles($text) && $this->runLatex( $text, $filename )) { $wgOut->redirect( "$url.$ext" ); } // else it failed } else $wgOut->redirect( "$url.$ext" ); chdir( $IP ); return false; } function getHelperFiles($text) { global $wgOut; // search for \usewikifile{..} preg_match_all("/\\\\usewikifile{(.*)}{(.*)}/", $text, $matches, PREG_SET_ORDER); foreach ($matches as $val) { $page = $val[1]; $outfile = $val[2]; if (preg_match("/[^-\w.]/", $outfile) || preg_match("/^[.]/", $outfile)) { $wgOut->addWikiText(wfMsg('latexdoc_invalid_filename', $outfile)); return false; } $title = Title::newFromText($page); if ($title) { if ($title->getNamespace() == NS_IMAGE) { $image = new Image($title); if (! $image->exists()) { $wgOut->addWikiText(wfMsg('latexdoc_no_page', $page)); return false; } if (! copy ($image->getImagePath(), $outfile)) { $wgOut->addWikiText( wfMsg( 'latexdoc_cant_write', "$outfile" ) ); return false; } continue; } $rev = Revision::newFromTitle($title); } if (!$title || ! $rev) { $wgOut->addWikiText(wfMsg('latexdoc_no_page', $page)); return false; } else { $inFile = fopen( $this->workingDir . '/' . $outfile, 'w' ); if ( !$inFile ) { $wgOut->addWikiText( wfMsg( 'latexdoc_cant_write', "$outfile" ) ); return false; } fwrite( $inFile, $rev->getText()); fclose( $inFile ); } } return true; } function runLatex( $text, $file ) { global $wgOut, $wgRequest; // remove all \usewikifile commands $text = preg_replace("/\\\\usewikifile{.*}{.*}/", "", $text); // Write input file $inFile = fopen( "$file.tex", 'w' ); if ( !$inFile ) { $wgOut->addWikiText( wfMsg( 'latexdoc_cant_write', "$file.tex" ) ); return false; } fwrite( $inFile, $text ); fclose( $inFile ); // Run LaTeX $cmd = $this->latexmk . " $this->args " . wfEscapeShellArg( "$file" ) . " 2>&1"; exec($cmd, $output, $error); // Report errors // we currently use -f with latexmk so that no exit code is returned // as we need to distinguish between undefined references (which we still consider success) // and genuine latex errors foreach ($output as $outputline) { if (preg_match("/^====.*error.*====$/", $outputline)) { // this is an erorr // could have partially generated pdf, delete it (some browsers will crash) @unlink("$file.pdf" ); wfSuppressWarnings(); $log = '<pre>' . file_get_contents( "$file.log" ) . '</pre>'; wfRestoreWarnings(); $wgOut->addWikiText( wfMsg( 'latexdoc_error', $log ) ); return false; } } return true; // Delete temporary files //@unlink( "$file.tex" ); //@unlink( "$file.aux" ); //@unlink( "$file.log" ); } function onParserBeforeStrip( &$parser, &$text, &$stripState ) { // If the article looks vaguely like TeX, render it with syntax highlighting (if available) // with a link for pdf generation global $wgSyntaxHighlight; if ( strpos( $text, '\begin{document}' ) !== false ) { $sk =& $parser->mOptions->getSkin(); $links = $sk->makeKnownLinkObj( $parser->mTitle, wfMsg( 'latexdoc_get_pdf' ), 'action=latexdoc&ext=pdf' ) . " | " . $sk->makeKnownLinkObj( $parser->mTitle, wfMsg( 'latexdoc_get_log' ), 'action=latexdoc&ext=log' ) . " | " . $sk->makeKnownLinkObj( $parser->mTitle, wfMsg( 'latexdoc_get_pdf_no_cache' ), 'action=latexdoc&ext=pdf&cache=0' ) . " | " . $sk->makeKnownLinkObj( $parser->mTitle, wfMsg( 'latexdoc_get_source' ), 'action=raw&ctype=application/x-tex&filename=wiki_latex_source.tex' ); $links = $parser->insertStripItem($links, $stripState); // make list of included files preg_match_all("/\\\\usewikifile{(.*)}{(.*)}/", $text, $matches, PREG_SET_ORDER); $files = '<div class="latexdoc-files">'; $files = $files . '<b>Included files:</b>'; foreach ($matches as $val) { $files = $files . "\n*[[:" . $val[1] . "]]"; } $files = $files . '</div>'; $text = wordwrap($text); if ($wgSyntaxHighlight) $text = $wgSyntaxHighlight->highlight($text, "latex"); else $text = "<pre>$text</pre>"; // no syntax highlighting $text = $parser->insertStripItem($text, $stripState); $text = "$links<hr />$files<p>$text"; } return true; } // Needed in some versions to prevent Special:Version from breaking function __toString() { return 'LatexDoc'; } } $wgLatexDoc = new LatexDoc; function wfLatexDocInit() { global $wgHooks, $wgLatexDoc, $wgMessageCache; $wgHooks['UnknownAction'][] = &$wgLatexDoc; $wgHooks['ParserBeforeStrip'][] = &$wgLatexDoc; $wgMessageCache->addMessages( array( 'latexdoc_invalid_filename' => 'Filename $1 is invalid', 'latexdoc_no_page' => 'Wiki page $1 does not exist', 'latexdoc_no_text' => 'Article contains no text, cannot generate output', 'latexdoc_cant_create_dir' => 'Cannot create temporary directory $1', 'latexdoc_cant_write' => 'Cannot write to file $1', 'latexdoc_error' => "LaTeX error:<br />\n\n$1", 'latexdoc_get_pdf' => 'Get PDF', 'latexdoc_get_log' => 'Get log', 'latexdoc_get_pdf_no_cache' => 'Regenerate PDF', 'latexdoc_get_source' => 'Export Source', )); } ?>
Send bugs and comments to Austin Che. Other extensions including sources can be found at User:Austin J. Che/Extensions.


