PHP Labware source code viewer / Internal utilities | 25 Apr, 2024
Root | Help
./LabWiki/_wikiLib.php
<?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(" ","&nbsp;", $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 = "&#8226;";
			$line = $matches[1];
		} 
		else if( preg_match( '/^- (.*)/', $line, $matches ) )
		{
			// Bullet with the em-dash
			$bullet = "&#8212;";
			$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 . '&nbsp;' . $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).'&amp;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 ); 
}
Presented with Sourceer
PHP Labware home | visitors since Sept 2017