<?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 ); }