<?php
/*
LabWiki 1.2.1, 22 August 2012, by Santosh Patnaik, MD, PhD. Based on QwikiWiki 1.5 of David Barrett
*/
// QWLoadQwikiFile - read file content and make array
function QWLoadQwikiFile( $path )
{
// Verify the file exists
if( file_exists( $path ) )
{
// Output the file
$file_as_string = file_get_contents( $path);
// remove newline character added by file_get_contents at end
//$file_as_string = substr($file_as_string, 0, -1);
// clean line endings - should be \n - as old Mac OS uses \r, etc.
$file_as_string = str_replace("\r\n","\n",$file_as_string);
$file_as_string = str_replace("\r","\n",$file_as_string);
// clean out tabs, replacing with single-spaces
$file_as_string = str_replace("\t"," ",$file_as_string);
// get [pre]...[/pre] blocks
function evaluate_for_pre ($pre_matches){
$pre_match = htmlspecialchars($pre_matches[2]);
$pre_match = str_replace(" "," ", $pre_match);
$pre_match = str_replace("\n",'<br />', $pre_match);
return ( $pre_match );
}
// i, s, u modifiers
$file_as_string = preg_replace_callback
(
'/(\[pre\])(.*?)(\[\/pre\])/isu' ,
'evaluate_for_pre' ,
$file_as_string
);
// for <table>...</table> as they can't tolerate <br /> outside table elements
function evaluate_for_tables ($table_matches){
$table_match = str_replace("\n",' ', $table_matches[2]);
return ( '<table' . $table_match . '</table>');
}
// i, s, u modifiers
$file_as_string = preg_replace_callback
(
'/(<table)(.*?)(<\/table>)/isu' ,
'evaluate_for_tables' ,
$file_as_string
);
// make array based on newline characters
$fileArray = explode("\n", $file_as_string);
// Shift off the headers, and then shift off blank lines
while( preg_match( '/^\w+:.*$/', $fileArray[0] ) ) array_shift( $fileArray );
while( !strlen( $fileArray[0] ) ) array_shift( $fileArray );
// Return the results
return $fileArray;
}
else
{
// No file
return false;
}
} // output goes into QWFormatQwikiLineArray
// QWFormatQwikiLineArray
function QWFormatQwikiLineArray( &$lineArray ) // fileArray comes in here
{
// Walk across all the lines
$htmlBlock = "";
$htmlIndent = 0;
$inHTMLBlock = false;
$out = "";
$c = 0;
while( $c < count( $lineArray ) )
{
// Concate as many lines as necessary to close all <html> blocks (or until it runs out)
$line = "";
do $line .= $lineArray[ $c++ ];
while
(
(
$c < count( $lineArray )
)
&&
(
preg_match( '/<html>/i', $line ) != preg_match( '/<\/html>/i', $line )
)
);
// Process the line
$out .= QWFormatQwikiLine( $line ); // array made back to string
}
return $out;
}
// QWFormatQwikiLine
function QWFormatQwikiLine( $line ) // QWFormatQwikiLineArray uses this; uses QWFormatMixedText and QWFormatIndent
{
global $QW_CONFIG;
// Strip off trailing whitespace
$line = rtrim( $line );
// See if there is anything left
if( $line == "" )
{
// Just output a blank line
return "<br />";
}
else
{
// See if there is any justification
$align = 'left'; // default
if( preg_match( '/^(\s*)\[center\] (.*)/i', $line, $matches ) )
{
// Center - [center]space
$align = 'center';
$line = $matches[1].$matches[2];
}
elseif( preg_match( '/^(\s*)\[right\] (.*)/i', $line, $matches ) )
{
// Right justify - [right]space
$align = 'right';
$line = $matches[1].$matches[2];
}
elseif( preg_match( '/^(\s*)\[left\] (.*)/i', $line, $matches ) )
{
// Right justify - [right]space
$align = 'left';
$line = $matches[1].$matches[2];
}
// See if it's a heading (all initial-caps)
static $count;
foreach ($QW_CONFIG['headPatternArray'] as $pattern)
{
if( preg_match( $pattern, $line, $matches ) )
{
// Return the heading
return '<div class="QWHeading1" style="text-align:'.$align.';">' . QWFormatMixedText( $line ) . '</div>';
}
}
// See if it's indented at all
$bullet = "";
$indent = 0;
if( preg_match( '/^(\s+)(.*)/', $line, $matches ) )
{
// Otherwise just indent
$indent = strlen( $matches[1] );
$line = $matches[2];
}
// See if it's a bulleted list
if( preg_match( '/^\? (.*)/', $line, $matches ) )
{
// Bullet with the question icon
$bullet = '<img src="questionicon.gif" width="16" height="16" alt="?" />';
$line = $matches[1];
}
else if( preg_match( '/^! (.*)/', $line, $matches ) )
{
// Bullet with the exclamation icon
$bullet = '<img src="exclamationicon.gif" width="16" height="16" alt="!" />';
$line = $matches[1];
}
else if( preg_match( '/^\. (.*)/', $line, $matches ) )
{
// Bullet with the circle bullet
$bullet = "•";
$line = $matches[1];
}
else if( preg_match( '/^- (.*)/', $line, $matches ) )
{
// Bullet with the em-dash
$bullet = "—";
$line = $matches[1];
}
else if( preg_match( '/^(\d+)\. (.*)/', $line, $matches ) )
{
// Output a numbered list
if( $matches[1] == 1 ) $count[$indent] = 1;
else if( isset( $count[$indent] ) ) ++$count[$indent];
else $count[$indent]=$matches[1];
$bullet = "$count[$indent].";
$line = $matches[2];
}
// See if this line has a inline heading
$inlineHeading = "";
if( preg_match( '/^([A-Z]+[^\s:]*( [^a-z\s:]+[^\s:]*)*): (.*)/', $line, $matches ) )
{
// Create an inline heading
$inlineHeading = "<span class=\"inline_heading\">" . QWFormatMixedText( $matches[1] ) . "</span>: ";
$line = $matches[3];
}
// Output with or without bullet
if( $bullet != "" )
{$lineHTML = $bullet . ' ' . $inlineHeading . QWFormatMixedText( $line ) . '<br />';}
else
{$lineHTML = $inlineHeading . QWFormatMixedText( $line ). '<br />' ;}
return QWFormatIndent( $indent, $lineHTML, $align );
}
}
// QWFormatMixedText
function QWFormatMixedText( $text ) // used by QWFormatQwikiLine; uses QWFormatQwikiText
{
// Format intermixed HTML and Wiki blocks
$out = "";
while( strlen( $text ) )
{
// Get everything up to the first <html> chunk
$wikiEnd = strpos( strtoupper($text), '<HTML>' );
if( $wikiEnd === false )
{
// Everything left is Wiki text
$wikiText = $text;
$text = "";
}
else
{
// Peel off the front and include as Wiki text
$wikiText = substr( $text, 0, $wikiEnd );
$text = substr( $text, $wikiEnd );
}
// Output the front as Qwiki text, if there is any
if( strlen( $wikiText ) ){ $out .= QWFormatQwikiText( $wikiText ); }
// See if there is anything left
if( strlen( $text ) )
{
// Output everything up to the </html> direct
$htmlEnd = strpos( strtoupper($text), '</HTML>' );
if( $htmlEnd === false )
{
// All remaining text is html
$htmlText = $text . "</HTML>";
$text = "";
}
else
{
// Peel off the front and include as HTML text
$htmlText = substr( $text, 0, $htmlEnd + 7 ); // +7 == strlen( '</html>' )
$text = substr( $text, $htmlEnd + 7 );
}
// Output straight HTML, if any
$out .= $htmlText;
}
}
// Done
return $out;
}
// QWFormatQwikiText
function QWFormatQwikiText( $text ) // uses QWFormatQwikiBlock; used by QWFormatMixedText
{
// Split into whitespace-separated blocks
$result = "";
$blocks = preg_split( '/\s/', $text );
foreach( $blocks as $block )
{
// Process the block and add to the result
$processedBlock = QWFormatQwikiBlock( $block );
if( $result == "" ) $result = $processedBlock;
else $result .= " " . $processedBlock;
}
// Apply line-level processing
static $patternArray = array(
'/(?<=^|^\W|\s\W|\s|<b>|<strong>|<em>|<i>|<code>)\*(([^*\s]+\s+)*[^*\s]+)\*(?=<\/b>|<\/strong>|<\/em>|<\/i>|<\/code>|\s|\W\s|\W+$|$)/iuU', // Bold * *
'/(?<=^|^\W|\s\W|\s|<b>|<strong>|<em>|<i>|<code>)\/(([^\/\s]+\s+)*[^\/\s]+)\/(?=<\/b>|<\/i>|<\/code>|<\/strong>|<\/em>|\s|\W\s|\W+$|$)/iuU', // Italics / /
'/(?<=^|^\W|\s\W|\s|<b>|<strong>|<em>|<i>|<code>)~(([^~\s]+\s+)*[^~\s]+)~(?=<\/b>|<\/i>|<\/code>|<\/strong>|<\/em>|\s|\W\s|\W+$|$)/iuU', // Underlines ~ ~
'/(?<=^|^\W|\s\W|\s|<b>|<strong>|<em>|<i>|<code>)#(([^#\s]+\s+)*[^#\s]+)#(?=<\/b>|<\/i>|<\/code>|<\/strong>|<\/em>|\s|\W\s|\W+$|$)/iuU', // Code
);
static $replaceArray = array(
'<strong>$1</strong>', // Bold
'<em>$1</em>', // Italics
'<span class="underline">$1</span>', // Underlines
'<code>$1</code>' // Code
);
// Italics overlaid on bold requires two passes (ie, "/*blah*/"). I'd like to use
// while() here, but I'm afraid of entering an infinite loop
if( ($newResult = preg_replace( $patternArray, $replaceArray, $result )) != $result )
$newResult = preg_replace( $patternArray, $replaceArray, $newResult );
return $newResult;
}
// QWFormatQwikiBlock
function QWFormatQwikiBlock( $block ) // used by QWFormatQwikiText
{
// See if it looks like an attached file name
global $QW, $QW_CONFIG;
$replacedBlock = $block;
if( preg_match( '/^(\W*)([\w-]+(\.[\w-]+)+)(\W*)/i', $block, $matches ) )
if( is_dir( $QW['attachDir'] ) )
{
// Look to see if it matches an attachment
$attachDir = dir( $QW['attachDir'] );
while( $filename = $attachDir->read( ) )
if( !strcasecmp( $filename, $matches[2] ) )
{
// If it's an image, do an inline image
$pathParts = pathinfo( $filename );
$extension = $pathParts['extension'];
if( !strcasecmp( $extension, 'jpg' ) ||
!strcasecmp( $extension, 'png' ) ||
!strcasecmp( $extension, 'jpeg' ) ||
!strcasecmp( $extension, 'gif' ) )
// Give it an inline image
$replacedBlock = $matches[1].'<img src="'.$QW['attachDir'].'/'.htmlspecialchars($filename).'" alt="image" />'.htmlspecialchars($matches[4]);
else
// Link to the attachment
$replacedBlock = $matches[1].'<a href="'.$QW['attachDir'].'/'.htmlspecialchars($filename).'"'.$QW['hrefTarget'].'>'.htmlspecialchars($matches[2]).'</a>'.htmlspecialchars($matches[4]);
break;
}
$attachDir->close( );
if( $block != $replacedBlock ) return $replacedBlock;
}
// Determine what kind of block it is and mark it up
static $patternArray = array(
'/^(\W*)((([_a-z0-9-]+)(\.[_a-z0-9-]+)*@([a-z0-9-]+)(\.[a-z0-9-]+)*(\.[a-z]{2,4})))+(\W*)$/i', // Email
'/^(\W*)(\w+(\.\w+)*\.([\w-]+\.[a-z]{2}|com|net|org|edu|gov|biz|info|mil|int)(\/(~?[\w]+([.~-]+[\w]+)*)?)*)(\W*)$/i', // WWW
'/^(\W*)(([a-z]+:\/\/)([\w-]+@)?[\w-]+(\.[\w-]+)*(\/([\w~][\w.~-]*)?)*([\?#]\S+)?)(\W*)$/i' // WWW
);
$replaceArray = array(
'$1<a href="mailto:$2">$2</a>$5', // Email
'$1<a href="http://$2"' . $QW['hrefTarget'] . '>$2</a>$8', // Implicit WWW
'$1<a href="$2"' . $QW['hrefTarget'] . '>$2</a>$9' // Explicit WWW
);
$replacedBlock = preg_replace( $patternArray, $replaceArray, $block );
if( $block != $replacedBlock ) return $replacedBlock;
// Detect QuickiPages
return preg_replace_callback( $QW_CONFIG['tagPatternArray'], "QWFormatQwikiBlockCallback", $block );
}
// QWFormatQwikiFile
function QWFormatQwikiFile( $absolutePath )
{
// Read the file
global $QW;
if( $fileArray = QWLoadQwikiFile( $absolutePath ) ) {
return QWFormatQwikiLineArray( $fileArray );
echo $fileArray;
}
else
{
// The file doesn't exist
return QWFormatQwikiLine( "(This page does not exist - either it has never been created or has been deleted. Click <em>Edit this page</em> to create.)" );
}
}
// QWCreateDataPath
function QWCreateDataPath( $page, $extension )
{
// Convert to a filename
return 'data/' . $page . $extension;
}
// QWGetRecentlyChangedQwikiPageNameList
function QWGetRecentlyChangedQwikiPageNameList( )
{
// Get modified-sorted list of Qwiki pages
$changedFileList = QWGetRecentlyChangedFileList( 'data/', "/\.qwiki$/" );
if( !isset( $changedFileList ) ) return;
// Loop across and create Wiki page names
foreach( $changedFileList as $filename )
// Pluck off the last six characteres (the length of '.qwiki')
$pageNameList[] = substr( $filename, 0, strlen( $filename ) - 6 );
// Done
return $pageNameList;
}
// QWFormatQwikiPageNameInPlace
function QWFormatQwikiPageNameInPlace( &$page )
{
$page = QWFormatQwikiPageName( $page );
}
// QWFormatQwikiPageName
function QWFormatQwikiPageName( $page )
{
// Ignore it outright if it's in the ignore array
global $QW, $QW_CONFIG;
if( in_array( $page, $QW_CONFIG['ignoreQwikiTagArray'] ) ) {return $page;}
// Use the redirect if it's in the redirect array
if( array_key_exists( $page, $QW_CONFIG['redirectTagArray'] ) ) {return '<a href="' . htmlspecialchars($QW_CONFIG['redirectTagArray'][$page]) . '">' . htmlspecialchars(QWCleanQwikiPageName( $page )) . '</a>';}
// See if it's a valid QwikiPage, of if we can hack off a trailing 's'. If not, create a new QuikiPage.
$path = QWCreateDataPath( $page, '.qwiki' );
if( preg_match( '/(.+?)s$/', $page, $miniMatches ) ) {
$path2 = QWCreateDataPath( $miniMatches[1], '.qwiki' );
} else {
$path2 = "";
}
if( file_exists( $path ) ) {
return '<a href="index.php?page='.htmlspecialchars($page).$QW['URLSuffix'].'" '.$QW['hrefTarget'].'>' . htmlspecialchars(QWCleanQwikiPageName( $page )) . '</a>';
} else if( $path2 != "" && file_exists( $path2 ) ) {
return '<a href="index.php?page='.htmlspecialchars($miniMatches[1]).$QW['URLSuffix'].'" '.$QW['hrefTarget'].'>' . htmlspecialchars(QWCleanQwikiPageName( $miniMatches[1] )) . 's</a>';
} else {
return htmlspecialchars(QWCleanQwikiPageName( $page )) . ( !$QW['pageIsProtected'] || $QW['userIsAuthenticated'] ? '<a href="index.php?page='.htmlspecialchars($page).'&from='.htmlspecialchars($QW['page']).$QW['URLSuffix'].'" '.$QW['hrefTarget'].'>?</a>' : '' );
}
}
// QWFormatQwikiPageNameDelta
function QWFormatQwikiPageNameDeltaInPlace( &$pageName )
{
$pageName = QWFormatQwikiPageNameDelta( $pageName );
}
function QWFormatQwikiPageNameDelta( $pageName )
{
// Get the path and timestamp
$path = QWCreateDataPath( $pageName, '.qwiki' );
$then = filemtime( $path );
$delta = QWFormatRelativeDate( time( ), $then );
return QWFormatQwikiPageName( $pageName ) . " (" . $delta . ")";
}
// QWFormatHTMLList
function QWFormatHTMLList( $htmlList, $separator )
{
// Verify a list exists
if( !isset( $htmlList ) || !count( $htmlList ) ) return "";
// Loop across the page names and put into a list
$out = "";
for( $c=0; $c<count( $htmlList )-1; ++$c )
$out .= $htmlList[$c] . htmlspecialchars($separator);
$out .= $htmlList[$c];
return $out;
}
// QWSaveQwikiFile
function QWSaveQwikiFile( $path, $userAccount, $wikiData )
{
// Save the updated data (add a header for who changed it)
$fp = fopen( $path, "wb" );
$username = $userAccount['username'];
$email = $userAccount['email'];
fwrite( $fp, "From: $username ($email)\n" );
fwrite( $fp, "Date: " . date("F j, Y, g:i a") . "\n" );
fwrite( $fp, "\n" );
fwrite( $fp, $wikiData, strlen( $wikiData ) );
fclose( $fp );
}
// QWGetQwikiPageNameList
function QWGetQwikiPageNameList() {
// Get modified-sorted list of Qwiki pages
$changedFileList = QWGetFileList( 'data/', "/\.qwiki$/" );
if( !isset( $changedFileList ) ) return;
// Loop across and create Wiki page names
foreach( $changedFileList as $filename )
// Pluck off the last six characteres (the length of '.qwiki')
$pageNameList[] = substr( $filename, 0, strlen( $filename ) - 6 );
// Done
return $pageNameList;
}
// QWCleanQwikiPageName
function QWCleanQwikiPageName( $page )
{
// Just strip any underscores from the name for pretty display
return str_replace( '_', ' ', $page );
}
// QWFormatQwikiBlockCallback
function QWFormatQwikiBlockCallback( $matches )
{
return $matches[1] . QWFormatQwikiPageName( $matches[2] ) . $matches[3];
}
// QWFormatQwikiBlockInPlace
function QWFormatQwikiBlockInPlace( &$block )
{
$block = QWFormatQwikiBlock( $block );
}