// Modified By: "Spencer D. Mindlin" // Modify Date: 11/21/1999 // Modified By: "Travis Swicegood" // Modified Date: 02/25/2000 // Last Modified Date: 02/25/2000 // //*********************************************************// // Note from Spencer D. Mindlin //*********************************************************// // Special thanks to "JP" for providing this // concept and a solid source foundation for this solution. // http://www.phpbuilder.com/columns/jprins20000201.php3 //*********************************************************// // Reserved Tags: REFRESH, EXPIRES, CACHE_NAME // // 1) REFRESH - // This tag will automatically check to see if this interval // has passed and refresh the cache appropriately. // I.E. QUARTERHOUR will automatically update the cache if // the cache is older that the latest quarter hour // arguments allowed: MINUTE, QUARTERHOUR, HALFHOUR, // HOUR, HALFDAY, DAY, MONTH // 2) EXPIRES - // arguments allowed: Any interval in seconds // // Please note the differences between REFRESH and EXPIRES. // EXPIRES - updates the content at the file's time of creation // plus the interval // REFRESH - updates the content on the interval hour. // HALFHOUR is 11:00 and 11:30. The first refresh will occur // at the first occurance that this interval is met after the // cache as been created. // I.E. a) Last cache creation @ 11:14 // b) Interval set at HALFHOUR // c) Next refresh occurs at 11:30 (or the first // request afterwards) // // refresh and expires may be used simultaneously if needed. // // 3) CACHE_NAME - this argument can be used to name the cache file // in lieu of the default method of concatenating the arguments // in the tag. This is useful when a tag contains characters // that are unusable for filenaming like slashes or colins as found // in date strings. // // Usage: // // // Note that code has been modified to use quoting (both, double and // single quotes) and also modified to allow spaces to be used in values //*********************************************************// // End of Note from Spencer D. Mindlin //*********************************************************// // //*********************************************************// // Note from Travis Swicegood //*********************************************************// /* * Most Recent Updates (02/25/2000 - Travis Swicegood): * 1. Expanded use of $DOCUMENT_ROOT - parse() and parse_it() both had * $doc_root strings added to their function. Below are the modifications * for parse() calls * parse( $DOCUMENT_ROOT . $REDIRECT_URL ) becomes * parse( $DOCUMENT_ROOT, $REDIRECT_URL ) * 2. Debug mode added - This is still being worked on as of 02/25/2000 * 3. Code streamlined - Several while() statements were removed in favor of * for() statements. Some for() statements called count() every * evaluation, this has been changed to only be called the first time. * Several redundant if() statements were combined. if() statements * that could be used as elseif() were changed so they would not be * evaluated when unnecessary. While some of theses changes may seem * small and inconsequential, if this script was in use on a virtual * server with several hundred users constantly using it, the * implications on server performance could be staggering * 4. Module file checking - No checking was done to insure that the correct * module file even existed, causing errors to be generated that caused * the system to halt. Module files are now checked, and if they don't exist * the parse_it() returns a quoted () error message which won't * return the desired effect, but won't cause the page to error. This * makes this parsing much easier to integrate with a large site were * confusing error messages popping up on websites can kill a site. * 5. CACHE attribute - The attribute CACHE has been added in order to force * or deny caching. This attribute overrides settings from tags * EXPIRE and REFRESH. * 6. Tag closing - Support has been added for tag closing (ie. ) * Functionality is, however, limited. Please see function * handle_close_xxx() for full documentation on how to use a closing * tag handler (the function has been commented to ensure that it does not * interfere with any other operations). * 7. Moved the call to parse() to the end of the file to ensure that all * functions are recognized (to ensure compatibility with all versions * of PHP) * 8. Dynamically generated tag-intro - This is probably the biggest feature * enhancement to this entire script, but was one of the last features * added (thus it is one of the later in this list). Before you could * only have your tags read as "", now the "my" has been replaced * to represent the file extention name. Thus, a file called "index.my" * would use the custom tags of "", or you can use "index.myhtml" * and make your tags "". This creates an endless supply of * custom tag names. * 9. Setup instructions - Instructions to setup this parser are found at * the bottom of the file. Included are examples of the '.htaccess' file, * handle_xxx(), handle_close_xxx(). ///*********************************************************/// /* The parse() function just reads the file and calls parse_it for every line to build * up the output in $buf. Changes made in the February 2000 version are: * 1. Debugging support added. * 2. File access changed - The file is now read in it's entirety via a file() * command, then parsed. */ function parse( $doc_root, $file, $_debug = false) { if( $_debug ) { print "
\n";
		print "function parse( \$doc_root,  \$file, \$_debug ) called with debug mode enabled\n";
		print "	\$doc_root	= $doc_root\n";
		print "	\$file	= $file\n";
		print "	\$_debug	= $_debug\n";
	}

	unset( $buf );
#    $buf =  ""; 

	if( eregi( "[a-z0-9]\.([a-z0-9]*)", $file, $ext ) )
		$extention = $ext[1];
	else
		return "\n";
	
	unset( $tag_use );
	for( $i = 0, $n = strlen( $extention ); $i < $n; $i++ ) {
		$use_tag .= "[" . substr( $extention, $i, 1 ) . "]";
	}

	if( $file_contents = file( $doc_root . $file ) ) {
		for( $i = 0, $n = count( $file_contents ); $i < $n; $i++ ) {
			if( $_debug ) print "\$file_contents[$i] = " . str_replace( ">", ">", str_replace( "<", "<", $file_contents[$i] ) );
			$buf .= parse_it( $file_contents[$i], $doc_root, $use_tag, $_debug );
		}
	}

	if( $_debug ) {
		print "	\$buf = $buf\n";
		print "\nEnd of parse()
\n"; } return $buf; } // Setup $str_cache_file = ""; /* The parse_it() function searches the information in $str to look for tags that * meet the format. When they are found, a search for the correct module * is started, and if found it is executed. The following changes have been made * to parse_it(): * 1. Debugging support added * 2. $def_cache_time was added to the function call so that the default * cache time could be set programmatically (this would require editing * the parse() function). * 3. Several multiple if() statements were combined where possible. Some * switch() statements were adapted over if() statements where it made the * function easier to read. * 4. Support for CACHE=write/read/no added - This attribute to a tag will * override any other cache settings, forcing a read or write of the cache. * Obviously, if the 'write' attribute is used, this forces a read of new * information instead of reading the cached version. Likewise, the 'read' * attribute attribute forces an attempt to read from the cache file * (useful if another program sets the cached information). The 'no' * attribute makes the site read new information, and doesn't allow it to * cache the retrieved information. This is extremely important when used * in areas of a website that demand stringent security. * 5. $end comment was removed from the return - An unchanged version of the * return is still available, but has been commented. To enable this feature * search for "return $pre_HTML . $start . $buf . $post_HTML;" and remove the * comment from the line above it. This might be useful for modules that * return a lot of information, but for testing purposes was redundant. * 6. Caching method changed - The method of caching that Spencer used seemed * be rather redundant. I've removed all but the neccessities for caching, * and it no longer states in the webpage (via comments) that a cached copy * is being used. * 7. Closing tags - In earlier versions, you could not close a custom tag. * This would not be a problem unless you were using your custom tags in * to setup * 8. Dynamically generated tag-intro - This is probably the biggest feature * enhancement to this entire script, but was one of the last features * added (thus it is one of the later in this list). Before you could * only have your tags read as "", now the "my" has been replaced * to represent the file extention name. Thus, a file called "index.my" * would use the custom tags of "", or you can use "index.myhtml" * and make your tags "". This creates an endless supply of * custom tag names. * 9. Streamlined eregi() functions - eregi() is case insensitive, it had * listed as "[A-Za-z...", this wasn't necessary, so it was removed in * favor or all uppercase or lowercase. * 10. Other HTML on the same line - This used to "eat" any HTML/text that was * on the same line as the special tag. Updates have been made to return * anything HTML/text that is outside the tag, along with the new code from * the module. Closing tags can be on the same line as well. */ function parse_it( $str, $doc_root, $use_tag, $_debug = false, $def_cache_time = 3600 ) { global $arr_loaded; // Listing of loaded modules global $str_cache_file; $int_default_cache_time = $def_cache_time; /*# This can be uncommented if needbe, but it provides generally useless information. if( $_debug ) { print "\nfunction parse_it( \$str, \$_debug )\n \$str = $str \$doc_root = $doc_root\n \$_debug = $_debug\n"; print " \$arr_loaded on line " . (__LINE__ - 1) . " = $arr_loaded\n"; print " \$str_cache_file on line " . (__LINE__ - 1) . " = $str_cache_file\n"; print " \$int_default_cache_time on line " . (__LINE__ - 1) . " = $int_default_cache_time\n"; } */ // Setup regular expression match for HTML before and/or after the custom tags. $HTML_regs = '[a-z0-9<> _=\'\"\\\/\!\.\?\#-]*'; if( eregi( "($HTML_regs)(<$use_tag-([A-Z0-9_]*) ([^>]*)[>])($HTML_regs)", $str, $regs ) ) { if( $_debug ) print "Custom start tag found on line " . (__LINE__ - 1) . "\n"; $str_tag = $regs[3]; $pre_HTML = $regs[1]; // Anything on the same line as the tag before it starts if( $_debug ) print " \$pre_HTML on line " . (__LINE__ - 1) . " = $pre_HTML\n"; $post_HTML = $regs[5]; // Anything on the same line as the tag after it ends if( $_debug ) print " \$post_HTML on line " . (__LINE__ - 1) . " = $post_HTML\n"; if( !file_exists( $doc_root . "/res/$str_tag.php3" ) ) { $return_str = $pre_HTML . "\n\n" . $str . $post_HTML; if( $_debug ) print " parse_it() preparing to return on line " . (__LINE__ - 1) . ". Below is what would be returned\n[start return]\n " . str_replace( ">", ">", str_replace( "<", "<", $return_str ) ) . "\n[end return]"; return $return_str; } elseif( !$arr_loaded[$str_tag] ) { // If module hasn't already been loaded, and exists, load now include( $doc_root . "/res/$str_tag.php3" ); // For Unix #include( "res\$str_tag\$str_tag.php3"); // For Win $arr_loaded[$str_tag] = 1; // Mark loaded } $str_func = "handle_$str_tag"; if( $_debug ) print " \$str_func on line " . (__LINE__ - 1) . " = $str_func\n"; $arr_list = explode( " ", strtolower( $regs[4] ) ); if( $_debug ) for( $i = 0, $n = count( $arr_list ); $i < $n; $i++ ) { print " \$arr_list[$i] on line " . (__LINE__ - 1) . " = $arr_list[$i]\n"; } $str_cache_file = "cache/$str_tag"; // For Unix // $str_cache_file = "cache\$str_tag"; // For Win $flag_quote = 0; for( $i = 0, $n = count( $arr_list ); $i < $n; $i++ ) { /* We must depart from the $str_cache_file name for a moment to check and see which * type of quotes, if any, are being used on each attribute. This is done * repeativitly to insure that all attributes are handled correctly. */ if( $flag_quote == 0 ) { if( $argname = strtok( $arr_list[$i], "=" ) ) { $val = strtok( "=" ); switch( $val[0] ) { case "'" : $char_quotetype = "'"; $flag_quote = 1; $arglist[$argname] = substr( $val, 1 ); break; case "\"" : $char_quotetype = "\""; $flag_quote = 1; $arglist[$argname] = substr($val, 1); break; default : $flag_quote = 0; $arglist[$argname] = $val; } if( substr( $arglist[$argname], -1 ) == $char_quotetype ) { $flag_quote = 0; $arglist[$argname] = substr($arglist[$argname], 0, -1); } } } elseif( $flag_quote == 1 ) { if( substr( $arr_list[$i], -1 ) == $char_quotetype ) { $arglist[$argname] .= " " . substr($arr_list[$i], 0, -1); $flag_quote = 0; } else { $arglist[$argname] .= " " . $arr_list[$i]; } } if( $_debug ) print " \$arglist[\"$argname\"] as of line " . (__LINE__) . " = " . $arglist["$argname"] . "\n"; } /* Check to see if "cache" is set to "no", if so, it ignore this block. */ if( $arglist["cache"] != "no" ) { if( $_debug ) print " Attribute \"cache\" is not set to \"no\" on line " . (__LINE__ - 1) . "\n"; if( isset( $arglist["cache_name"] ) ) { /* If "cache_name" has been set, it will be used and cache name will not * be generated. */ $str_cache_file = $arglist["cache_name"]; } else { for( $i = 0, $n = count( $arr_list ); $i < $n; $i++ ) { /* All other cache name options have failed, so a cache name must be * generated. The cache name is generated by using the tag name, plus * all of the attributes excluding the attributes "expires", "refresh", * "cache_name", and "cache". */ if( ( $argname != "expires" ) && ( $argname != "refresh" ) && ( $argname != "cache_name" ) && ( $argname != "cache" ) ) { $str_cache_file .= "_" . $argname . "=" . $arglist[$argname]; } } } } // Add $doc_root to $str_cache_file for Unix filesystem. $str_cache_file = $doc_root . "/" . $str_cache_file; if( $_debug ) print " \$str_cache_file on line " . (__LINE__ - 1) . " = $str_cache_file\n"; /* This section checks to see if the cache file is being used, by checking for * the cache_filename + .lock. This file is generated while the cache is being * written to. If the file exists, the system waits in 1 second intervals, and * checks again. After 20 seconds, if the lock file has not been removed, the * function returns with a commented error message. Generally, if the cached * locked for more than 20 seconds, an error has occurred which is prohibitting * the lock file from being removed. If such an error occurred, and the while() * doesn't terminate within a reasonable time it would create a potentially * system crashing infinite loop. */ clearstatcache(); if( file_exists($str_cache_file . '.lock') ) { register_shutdown_function( "remove_cache_lock" ); } $total_intervals = 0; while( file_exists( $str_cache_file . '.lock' ) ) { if( $_debug ) print " Lock file check $total_intervals\n"; if( $total_intervals == 20 ) { $return_str = "\n\n$str"; if( $_debug ) print " parse_it() preparing to return on line " . (__LINE__ - 1) . ". Below is what would be returned\n[start return]\n " . str_replace( ">", ">", str_replace( "<", "<", $return_str ) ) . "\n[end return]"; return $return_str; } sleep(2); clearstatcache(); $total_intervals++; continue; } clearstatcache(); // Setup the variables for reading and writing to the cache $flag_read_cache = 0; $flag_write_cache = 0; $flag_expires_read_cache = 0; $flag_expires_write_cache = 0; $flag_refresh_write_cache = 0; $flag_refresh_read_cache = 0; $flag_cache_write_cache = 0; $flag_cache_read_cache = 0; $flag_cache_no_cache = 0; // Check if the developer is using the 'expires' tag if( !( isset( $arglist["expires"] ) && ( $arglist["expires"] < 10 ) ) ) { if( $_debug ) print " Attribute \"expires\" is set on line " . (__LINE__ - 1) . ".\n"; $flag_expires_write_cache = 1; if( file_exists( $str_cache_file ) ) { if( ( !isset( $arglist["expires"] ) && ( filemtime( $str_cache_file ) + $int_default_cache_time ) > date( "U" ) ) || ( filemtime( $str_cache_file ) + $arglist["expires"] ) > date ( "U" ) ) { $flag_expires_read_cache = 1; $flag_expires_write_cache = 0; if( $_debug ) print " \$flag_expires_read_cache on line " . (__LINE__ - 2) . " = $flag_expires_read_cache\n \$flag_expires_write_cache on line " . (__LINE__ - 1) . " = $flag_expires_write_cache\n"; } } } // Check if the developer is using the 'refresh' tag if( isset( $arglist["refresh"] ) ) { if( $_debug ) print " Attribute \"refresh\" is set on line " . (__LINE__ - 1) . ".\n"; $flag_refresh_write_cache = 1; if( file_exists( $str_cache_file ) ) { $flag_refresh_read_cache = 1; $flag_refresh_write_cache = 0; switch( strtoupper( $arglist["refresh"] ) ) { case 'MINUTE': if ( !checkRefreshMinute( mktime( ), filemtime( $str_cache_file ) ) ) { $flag_refresh_write_cache = 1; $flag_refresh_read_cache = 0; } break; case 'QUARTERHOUR': if (!checkRefreshQuarterHour(mktime(), filemtime($str_cache_file))) { $flag_refresh_write_cache = 1; $flag_refresh_read_cache = 0; } break; case 'HALFHOUR': if (!checkRefreshHalfHour(mktime(), filemtime($str_cache_file))) { $flag_refresh_write_cache = 1; $flag_refresh_read_cache = 0; } break; case 'HOUR': if (!checkRefreshHour(mktime(), filemtime($str_cache_file))) { $flag_refresh_write_cache = 1; $flag_refresh_read_cache = 0; } break; case 'HALFDAY': if (!checkExpiredHalfDay(mktime(), filemtime($str_cache_file))) { $flag_refresh_write_cache = 1; $flag_refresh_read_cache = 0; } break; case 'DAY': if (!checkRefreshDay(mktime(), filemtime($str_cache_file))) { $flag_refresh_write_cache = 1; $flag_refresh_read_cache = 0; } break; case 'MONTH': if (!checkRefreshMonth(mktime(), filemtime($str_cache_file))) { $flag_refresh_write_cache = 1; $flag_refresh_read_cache = 0; } break; default: echo "Invalid REFRESH attribute
\n"; break; } } else { $flag_refresh_write_cache = 1; $flag_refresh_read_cache = 0; } } // Check if the developer is using the 'cache' tag if( isset( $arglist["cache"] ) ) { if( $_debug ) print " Attribute \"cache\" is set on line " . (__LINE__ - 1) . ".\n"; switch( $arglist["cache"] ) { case "write" : $flag_cache_write_cache = 1; if( $_debug ) print " \$flag_cache_write_cache on line " . (__LINE__ - 1) . " = $flag_cache_write_cache\n"; // $flag_cache_read_cache = 0; break; case "read" : // $flag_cache_write_cache = 0; $flag_cache_read_cache = 1; if( $_debug ) print " \$flag_cache_read_cache on line " . (__LINE__ - 1) . " = $flag_cache_read_cache\n"; break; case "no" : // $flag_cache_write_cache = 0; // $flag_cache_read_cache = 0; $flag_cache_no_cache = 1; if( $_debug ) print " \$flag_cache_no_cache on line " . (__LINE__ - 1) . " = $flag_cache_no_cache\n"; break; } } // Check for either cache update tags for reading and writing the cache if( $flag_cache_no_cache ) { if( $_debug ) print " Caching has been overruled as of line " . (__LINE__ - 1). "\n"; /* $flag_cache_no_cache overrides all other caching options, so if it is set * evaluation of the other xxx_cache is useless, thus not done. */ $flag_write_cache = 0; $flag_read_cache = 0; } elseif( ( ( ( $flag_expires_write_cache || $flag_refresh_write_cache ) && !file_exists( $str_cache_file . '.lock' ) ) || ( $flag_cache_write_cache && !$flag_cache_read_cache ) ) && !$flag_cache_no_cache ) { if( $_debug ) print " Caching will be performed as of line " . (__LINE__ - 3) . "\n"; $flag_write_cache = 1; touch( $str_cache_file . '.lock' ); register_shutdown_function( "remove_cache_lock" ); } elseif( ( ( ( $flag_expires_read_cache || $flag_refresh_read_cache ) && !$flag_write_cache ) || ( $flag_cache_read_cache && !$flag_cache_write_cache ) ) && !$flag_cache_no_cache ) { if( $_debug ) print " Cache will be read as of line " . (__LINE__ - 3) . "\n"; $flag_read_cache = 1; } $start = "\n\n"; if( $flag_read_cache || ( !strlen( $buf .= $str_func( $arglist ) ) ) ) { if( $_debug ) print " The cached version is going to be used as of line " . (__LINE__ - 1) . "\n"; if( $file_cache = file( $str_cache_file ) ) { if( $_debug ) print " A cached version has been found as of line " . (__LINE__ - 1) . "\n"; for( $i = 0, $n = count( $file_cache ); $i < $n; $i++ ) { $buf .= $file_cache[$i]; } $start .= "\n"; } else { if( $_debug ) print " A cached version was attempted, but the file was empty as of line " . (__LINE__ - 1) . "\n"; $buf .= "\n"; } } $end .= "\n\n"; if( $flag_write_cache && ( $f = fopen( $str_cache_file, "w" ) ) ) { if( $_debug ) print " A cache file is being made with the output from $str_func\n"; fputs( $f, $buf ); fclose( $f ); remove_cache_lock(); } // $return_str = $pre_HTML . $start . $buf . $end . $post_HTML; $return_str = $pre_HTML . $start . $buf . $post_HTML; if( $_debug ) print " parse_it() preparing to return on line " . (__LINE__ - 1) . ". Below is what would be returned\n[start return]\n " . str_replace( ">", ">", str_replace( "<", "<", $return_str ) ) . "\n[end return]\n"; return $return_str; } elseif( eregi( "($HTML_regs)(]*)[>]*)($HTML_regs)", $str, $regs ) ) { if( $_debug ) print "Closing tag found on line" . (__LINE__ - 1) . "\n"; /* A closing tag has been found, this code will proceed to process the information in * a similar fashion to that of the opening tag. All of the same arguments that were * saved in the opening tag have been applied to the closing tags. These commands can * be cached in the same fashion as the opening tag, except the following preceeds any * cache names: "close_" */ $pre_HTML = $regs[1]; // Anything on the same line as the tag before it starts if( $_debug ) print " \$pre_HTML on line " . (__LINE__ - 1) . " = $pre_HTML\n"; $post_HTML = $regs[5]; // Anything on the same line as the tag after it ends if( $_debug ) print " \$post_HTML on line " . (__LINE__ - 1) . " = $post_HTML\n"; $str_tag = $regs[3]; if( $_debug ) print " \$str_tag on line " . (__LINE__ - 1) . " = str_tag\n"; $str_func = "handle_close_" . $regs[3]; if( $_debug ) print " \$str_func on line " . (__LINE__ - 1) . " = str_func\n"; $arr_list = explode( " ", chop( strtolower( $regs[4] ) ) ); if( $_debug ) for( $i = 0, $n = count( $arr_list ); $i < $n; $i++ ) { print " \$arr_list[$i] on line " . (__LINE__ - 3) . " = $arr_list[$i]\n"; } $str_cache_file = "cache/close_$str_tag"; // For Unix // $str_cache_file = "cache\close_$str_tag"; // For Win $flag_quote = 0; for( $i = 0, $n = count( $arr_list ); $i < $n; $i++ ) { /* We must depart from the $str_cache_file name for a moment to check and see which * type of quotes, if any, are being used on each attribute. This is done * repeativitly to insure that all attributes are handled correctly. */ if( $flag_quote == 0 ) { if( $argname = strtok( $arr_list[$i], "=" ) ) { $val = strtok( "=" ); switch( $val[0] ) { case "'" : $char_quotetype = "'"; $flag_quote = 1; $arglist[$argname] = substr( $val, 1 ); break; case "\"" : $char_quotetype = "\""; $flag_quote = 1; $arglist[$argname] = substr($val, 1); break; default : $flag_quote = 0; $arglist[$argname] = $val; } if( substr( $arglist[$argname], -1 ) == $char_quotetype ) { $flag_quote = 0; $arglist[$argname] = substr($arglist[$argname], 0, -1); } } } elseif( $flag_quote == 1 ) { if( substr( $arr_list[$i], -1 ) == $char_quotetype ) { $arglist[$argname] .= " " . substr($arr_list[$i], 0, -1); $flag_quote = 0; } else { $arglist[$argname] .= " " . $arr_list[$i]; } } if( $_debug ) print " \$arglist[\"$argname\"] as of line " . (__LINE__) . " = " . $arglist["$argname"] . "\n"; } /* Check to see if "cache" is set to "no", if so, it ignore this block. */ if( $arglist["cache"] != "no" ) { if( $_debug ) print " Attribute \"cache\" is not set to \"no\" on line " . (__LINE__ - 1) . "\n"; if( isset( $arglist["cache_name"] ) ) { /* If "cache_name" has been set, it will be used and cache name will not * be generated. */ $str_cache_file = $arglist["cache_name"]; } else { for( $i = 0, $n = count( $arr_list ); $i < $n; $i++ ) { /* All other cache name options have failed, so a cache name must be * generated. The cache name is generated by using the tag name, plus * all of the attributes excluding the attributes "expires", "refresh", * "cache_name", and "cache". */ if( ( $argname != "expires" ) && ( $argname != "refresh" ) && ( $argname != "cache_name" ) && ( $argname != "cache" ) ) { $str_cache_file .= "_" . $argname . "=" . $arglist[$argname]; } } } } // Add $doc_root to $str_cache_file for Unix filesystem. $str_cache_file = $doc_root . "/" . $str_cache_file; if( $_debug ) print " \$str_cache_file on line " . (__LINE__ - 1) . " = $str_cache_file\n"; /* This section checks to see if the cache file is being used, by checking for * the cache_filename + .lock. This file is generated while the cache is being * written to. If the file exists, the system waits in 1 second intervals, and * checks again. After 20 seconds, if the lock file has not been removed, the * function returns with a commented error message. Generally, if the cached * locked for more than 20 seconds, an error has occurred which is prohibitting * the lock file from being removed. If such an error occurred, and the while() * doesn't terminate within a reasonable time it would create a potentially * system crashing infinite loop. */ clearstatcache(); if( file_exists($str_cache_file . '.lock') ) { register_shutdown_function( "remove_cache_lock" ); } $total_intervals = 0; while( file_exists( $str_cache_file . '.lock' ) ) { if( $_debug ) print " Lock file check $total_intervals\n"; if( $total_intervals == 20 ) { $return_str = "\n\n$str"; if( $_debug ) print " parse_it() preparing to return on line " . (__LINE__ - 1) . ". Below is what would be returned\n[start return]\n " . str_replace( ">", ">", str_replace( "<", "<", $return_str ) ) . "\n[end return]"; return $return_str; } sleep(2); clearstatcache(); $total_intervals++; continue; } clearstatcache(); // Setup the variables for reading and writing to the cache $flag_read_cache = 0; $flag_write_cache = 0; $flag_expires_read_cache = 0; $flag_expires_write_cache = 0; $flag_refresh_write_cache = 0; $flag_refresh_read_cache = 0; $flag_cache_write_cache = 0; $flag_cache_read_cache = 0; $flag_cache_no_cache = 0; // Check if the developer is using the 'expires' tag if( !( isset( $arglist["expires"] ) && ( $arglist["expires"] < 10 ) ) ) { if( $_debug ) print " Attribute \"expires\" is set on line " . (__LINE__ - 1) . ".\n"; $flag_expires_write_cache = 1; if( file_exists( $str_cache_file ) ) { if( ( !isset( $arglist["expires"] ) && ( filemtime( $str_cache_file ) + $int_default_cache_time ) > date( "U" ) ) || ( filemtime( $str_cache_file ) + $arglist["expires"] ) > date ( "U" ) ) { $flag_expires_read_cache = 1; $flag_expires_write_cache = 0; if( $_debug ) print " \$flag_expires_read_cache on line " . (__LINE__ - 2) . " = $flag_expires_read_cache\n \$flag_expires_write_cache on line " . (__LINE__ - 1) . " = $flag_expires_write_cache\n"; } } } // Check if the developer is using the 'refresh' tag if( isset( $arglist["refresh"] ) ) { if( $_debug ) print " Attribute \"refresh\" is set on line " . (__LINE__ - 1) . ".\n"; $flag_refresh_write_cache = 1; if( file_exists( $str_cache_file ) ) { $flag_refresh_read_cache = 1; $flag_refresh_write_cache = 0; switch( strtoupper( $arglist["refresh"] ) ) { case 'MINUTE': if ( !checkRefreshMinute( mktime( ), filemtime( $str_cache_file ) ) ) { $flag_refresh_write_cache = 1; $flag_refresh_read_cache = 0; } break; case 'QUARTERHOUR': if (!checkRefreshQuarterHour(mktime(), filemtime($str_cache_file))) { $flag_refresh_write_cache = 1; $flag_refresh_read_cache = 0; } break; case 'HALFHOUR': if (!checkRefreshHalfHour(mktime(), filemtime($str_cache_file))) { $flag_refresh_write_cache = 1; $flag_refresh_read_cache = 0; } break; case 'HOUR': if (!checkRefreshHour(mktime(), filemtime($str_cache_file))) { $flag_refresh_write_cache = 1; $flag_refresh_read_cache = 0; } break; case 'HALFDAY': if (!checkExpiredHalfDay(mktime(), filemtime($str_cache_file))) { $flag_refresh_write_cache = 1; $flag_refresh_read_cache = 0; } break; case 'DAY': if (!checkRefreshDay(mktime(), filemtime($str_cache_file))) { $flag_refresh_write_cache = 1; $flag_refresh_read_cache = 0; } break; case 'MONTH': if (!checkRefreshMonth(mktime(), filemtime($str_cache_file))) { $flag_refresh_write_cache = 1; $flag_refresh_read_cache = 0; } break; default: echo "Invalid REFRESH attribute
\n"; break; } } else { $flag_refresh_write_cache = 1; $flag_refresh_read_cache = 0; } } // Check if the developer is using the 'cache' tag if( isset( $arglist["cache"] ) ) { if( $_debug ) print " Attribute \"cache\" is set on line " . (__LINE__ - 1) . ".\n"; switch( $arglist["cache"] ) { case "write" : $flag_cache_write_cache = 1; if( $_debug ) print " \$flag_cache_write_cache on line " . (__LINE__ - 1) . " = $flag_cache_write_cache\n"; break; case "read" : $flag_cache_read_cache = 1; if( $_debug ) print " \$flag_cache_read_cache on line " . (__LINE__ - 1) . " = $flag_cache_read_cache\n"; break; case "no" : $flag_cache_no_cache = 1; if( $_debug ) print " \$flag_cache_no_cache on line " . (__LINE__ - 1) . " = $flag_cache_no_cache\n"; break; } } // Check for either cache update tags for reading and writing the cache if( $flag_cache_no_cache ) { if( $_debug ) print " Caching has been overruled as of line " . (__LINE__ - 1). "\n"; /* $flag_cache_no_cache overrides all other caching options, so if it is set * evaluation of the other xxx_cache is useless, thus not done. */ $flag_write_cache = 0; $flag_read_cache = 0; } elseif( ( ( ( $flag_expires_write_cache || $flag_refresh_write_cache ) && !file_exists( $str_cache_file . '.lock' ) ) || ( $flag_cache_write_cache && !$flag_cache_read_cache ) ) && !$flag_cache_no_cache ) { if( $_debug ) print " Caching will be performed as of line " . (__LINE__ - 3) . "\n"; $flag_write_cache = 1; touch( $str_cache_file . '.lock' ); register_shutdown_function( "remove_cache_lock" ); } elseif( ( ( ( $flag_expires_read_cache || $flag_refresh_read_cache ) && !$flag_write_cache ) || ( $flag_cache_read_cache && !$flag_cache_write_cache ) ) && !$flag_cache_no_cache ) { if( $_debug ) print " Cache will be read as of line " . (__LINE__ - 3) . "\n"; $flag_read_cache = 1; } $start = "\n\n"; if( $flag_read_cache || ( !strlen( $buf .= $str_func( $arglist ) ) ) ) { if( $_debug ) print " The cached version is going to be used as of line " . (__LINE__ - 1) . "\n"; if( $file_cache = file( $str_cache_file ) ) { if( $_debug ) print " A cached version has been found as of line " . (__LINE__ - 1) . "\n"; for( $i = 0, $n = count( $file_cache ); $i < $n; $i++ ) { $buf .= $file_cache[$i]; } $start .= "\n"; } else { if( $_debug ) print " A cached version was attempted, but the file was empty as of line " . (__LINE__ - 1) . "\n"; $buf .= "\n"; } } $end .= "\n\n"; if( $flag_write_cache && ( $f = fopen( $str_cache_file, "w" ) ) ) { if( $_debug ) print " A cache file is being made with the output from $str_func\n"; fputs( $f, $buf ); fclose( $f ); remove_cache_lock(); } $return_str = $pre_HTML . $buf . $post_HTML . $end; if( $_debug ) print " parse_it() preparing to return on line " . (__LINE__ - 1) . ". Below is what would be returned\n[start return]\n " . str_replace( ">", ">", str_replace( "<", "<", $return_str ) ) . "\n[end return]\n"; return $return_str; } else { return $str; } } function parse_my_tags( $file ) { $buf = ""; if ($f = fopen ($file, "r")) { while ($str = fgets ($f, 4096)) { if ($str != "") { $str = str_replace( "\"", "\\\"", $str); eval ( "\$str = \"$str\";" ); } $buf .= parse_it($str); } fclose ($f); } return $buf; } //*********************************/ // Some other functions function remove_cache_lock() { global $str_cache_file; clearstatcache(); if (file_exists($str_cache_file . '.lock')) { @unlink($str_cache_file . '.lock'); } } //*********************************/ // CACHE REFRESH CHECKING FUNCTIONS // Each function checks the next interval higher for verification function checkRefreshYear($systime, $filetime) { $sysYear = date( "y", $systime); $fileYear = date( "y", $filetime); if ($sysYear != $fileYear) return false; return true; } function checkRefreshMonth($systime, $filetime) { $sysMonth = date( "M", $systime); $fileMonth = date( "M", $filetime); if ($sysMonth != $fileMonth) return false; if (!(checkRefreshYear($systime, $filetime))) return false; return true; } function checkRefreshDay($systime, $filetime) { $sysDay = date( "j", $systime); $fileDay = date( "j", $filetime); if ($sysDay != $fileDay) return false; if (!(checkRefreshMonth($systime, $filetime))) return false; return true; } function checkRefreshDayHalf($systime, $filetime) { $sysHour = date( "H", $systime); $fileHour = date( "H", $filetime); if (($sysHour % 12) < ($fileHour % 12)) return false; if (!(checkRefreshDay($systime, $filetime))) return false; return true; } function checkRefreshHour($systime, $filetime) { $sysHour = date( "H", $systime); $fileHour = date( "H", $filetime); if ($sysHour != $fileHour) return false; if (!(checkRefreshDayHalf($systime, $filetime))) return false; return true; } function checkRefreshHalfHour($systime, $filetime) { $sysMin = date( "i", $systime); $fileMin = date( "i", $filetime); if (($sysMin % 30) < ($fileMin % 30)) return false; if (!(checkRefreshHour($systime, $filetime))) return false; return true; } function checkRefreshQuarterHour($systime, $filetime) { $sysMin = date( "i", $systime); $fileMin = date( "i", $filetime); if (($sysMin % 15) < ($fileMin % 15)) return false; if (!(checkRefreshHalfHour($systime, $filetime))) return false; return true; } function checkRefreshMinute($systime, $filetime) { $sysMin = date( "i", $systime); $fileMin = date( "i", $filetime); if ($sysMin != $fileMin) return false; if (!(checkRefreshQuarterHour($systime, $filetime))) return false; return true; } /* Debug variable - This can be set to true or false to enable or disable debugging * mode. As the debugging output is generated on the website, it is not reccomended * that you use this unless it is in a controlled situation where the general public * won't be peering in on your site. */ unset( $debug ); // This is set to avoid manipulation by an additional to the query // string. $debug = false; // Set this to true if you wish to enable debugging mode. /* This sets up the parse() function */ if( $REDIRECT_URL ) { echo parse( $DOCUMENT_ROOT, $REDIRECT_URL, $debug ); } /* * The parser can reside in any directory; however, the module files must be placed * in their correct directory: $DOCUMENT_ROOT/res/xxx.php3 * It is suggested that you use the directory /lib/ to place your parser file, and * all examples below use the assumption that you have done that. * The following is an example a .my file - /color.my: * Welcome to this example This text is blue * * * * The following is an example file for /res/xxx.php3: "; return ""; } function handle_close_xxx( $arguments ) { return ""; } ?> * * * The following is an example '/.htaccess' file: RewriteEngine on RewriteRule \.my /lib/parse.php3 * * The following is an example "/res/.htaccess" * (this is to keep snoops from looking in on your parsing files), * replace "%domainname%" with your domain name: Redirect permanent /res http://%domainname% * * The following is an example of "/lib/.htaccess" Redirect permanent /lib http://%domainname% */ /* END parse.php3 */ ?>