Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git

Reorgs code

AuthorDaveJarvis <email>
Date2023-11-11 14:04:06 GMT-0800
Commit98a910785f342babe25ee364f4ca1eb29ac93323
Parent8716c71
Delta149 lines added, 143 lines removed, 6-line increase
www/downloads/counter.php
/**
+ * Retrieve the file name being downloaded from the HTTP GET request.
+ *
+ * @return string The sanitized file name (without path information).
+ */
+ function get_sanitized_filename() {
+ $filepath = isset( $_GET[ 'filename' ] ) ? $_GET[ 'filename' ] : '';
+ $fileinfo = pathinfo( $filepath );
+
+ // Remove path information (no /etc/passwd or ../../etc/passwd for you).
+ $basename = $fileinfo[ 'basename' ];
+
+ if( isset( $_SERVER[ 'HTTP_USER_AGENT' ] ) ) {
+ $periods = substr_count( $basename, '.' );
+
+ // Address IE bug regarding multiple periods in filename.
+ $basename = strstr( $_SERVER[ 'HTTP_USER_AGENT' ], 'MSIE' )
+ ? mb_ereg_replace( '/\./', '%2e', $basename, $periods - 1 )
+ : $basename;
+ }
+
+ // Trim all spaces, even internal ones.
+ $basename = mb_ereg_replace( '/\s+/', '', $basename );
+
+ // Sanitize.
+ $basename = mb_ereg_replace( '([^\w\d\-_~,;\[\]\(\).])', '', $basename );
+
+ return $basename;
+ }
+
+ /**
* Answers whether the user's download token has expired.
*
return $expired;
- }
-
- function create_lock_filename( $filename ) {
- return $filename .'.lock';
}
/**
- * Acquires a lock for a particular file. Callers would be prudent to
- * call this function from within a try/finally block and close the lock
- * in the finally section. The amount of time between opening and closing
- * the lock must be minimal because parallel processes will be waiting on
- * the lock's release.
+ * Downloads a file, allowing for resuming partial downloads.
*
- * @param string $filename The name of file to lock.
+ * @param string $filename File to download, must be in script directory.
*
- * @return bool True if the lock was obtained, false upon excessive attempts.
+ * @return bool True if the file was transferred.
*/
- function lock_open( $filename ) {
- $lockdir = create_lock_filename( $filename );
-
- // Track the number of times a lock attempt is made.
- $iterations = 0;
+ function download( $filename ) {
+ // Don't cache the file stats result (e.g., file size).
+ clearstatcache();
- do {
- // Creates and tests lock file existence atomically.
- if( @mkdir( $lockdir, 0777 ) ) {
- // Exit the loop.
- $iterations = 0;
- }
- else {
- $iterations++;
- $lifetime = time() - filemtime( $lockdir );
+ $size = @filesize( $filename );
+ $size = $size === false || empty( $size ) ? 0 : $size;
+ $content_type = mime_content_type( $filename );
+ $content_length = $size;
+ $seek_start = 0;
- if( $lifetime > 10 ) {
- // If the lock has gone stale, delete it.
- @rmdir( $lockdir );
- }
- else {
- // Wait a random duration to avoid concurrency conflicts.
- usleep( rand( 1000, 10000 ) );
- }
- }
- }
- while( $iterations > 0 && $iterations < 10 );
+ // Added by PHP, removed by us.
+ header_remove( 'x-powered-by' );
- // Indicate whether the maximum number of lock attempts were exceeded.
- return $iterations == 0;
- }
+ // Check if a range is sent by browser or download manager.
+ if( isset( $_SERVER[ 'HTTP_RANGE' ] ) ) {
+ $range_format = '/^bytes=\d*-\d*(,\d*-\d*)*$/';
+ $request_range = $_SERVER[ 'HTTP_RANGE' ];
- /**
- * Releases the lock on a particular file.
- *
- * @param string $filename The name of file that was locked.
- */
- function lock_close( $filename ) {
- @rmdir( create_lock_filename( $filename ) );
- }
+ // Ensure the content request range is in a valid format.
+ if( !preg_match( $range_format, $request_range, $matches ) ) {
+ header( 'HTTP/1.1 416 Requested Range Not Satisfiable' );
+ header( "Content-Range: bytes */$size" );
- /**
- * Increments the number in a file using an exclusive lock. If the file
- * doesn't exist, it will be created and the initial value set to 0.
- *
- * @param string $filename The file containing a number to increment.
- */
- function increment_count( $filename ) {
- try {
- lock_open( $filename );
+ // Return early because the range is invalid.
+ return false;
+ }
- // Coerce value to largest natural numeric data type.
- $count = @file_get_contents( $filename ) + 0;
+ // Multiple ranges could be specified, but only serve the first range.
+ $seek_start = $matches[ 1 ] + 0;
- // Write the new counter value.
- file_put_contents( $filename, $count + 1 );
- }
- finally {
- lock_close( $filename );
- }
- }
+ if( isset( $matches[ 2 ] ) ) {
+ $seek_end = $matches[ 2 ] + 0;
+ }
+ else {
+ $seek_end = $size - 1;
+ }
- /**
- * Retrieve the file name being downloaded from the HTTP GET request.
- *
- * @return string The sanitized file name (without path information).
- */
- function get_sanitized_filename() {
- $filepath = isset( $_GET[ 'filename' ] ) ? $_GET[ 'filename' ] : '';
- $fileinfo = pathinfo( $filepath );
+ $range_bytes = $seek_start . '-' . $seek_end . '/' . $size;
+ $content_length = $seek_end - $seek_start + 1;
- // Remove path information (no /etc/passwd or ../../etc/passwd for you).
- $basename = $fileinfo[ 'basename' ];
+ header( 'HTTP/1.1 206 Partial Content' );
+ header( "Content-Range: bytes $range_bytes" );
+ }
- if( isset( $_SERVER[ 'HTTP_USER_AGENT' ] ) ) {
- $periods = substr_count( $basename, '.' );
+ // HTTP/1.1 clients must treat invalid date formats, especially 0, as past.
+ header( 'Expires: 0' );
- // Address IE bug regarding multiple periods in filename.
- $basename = strstr( $_SERVER[ 'HTTP_USER_AGENT' ], 'MSIE' )
- ? mb_ereg_replace( '/\./', '%2e', $basename, $periods - 1 )
- : $basename;
- }
+ // Prevent local caching.
+ header( 'Cache-Control: public, must-revalidate, post-check=0, pre-check=0' );
- // Trim all spaces, even internal ones.
- $basename = mb_ereg_replace( '/\s+/', '', $basename );
+ // No response message portion may be cached (e.g., by a proxy server).
+ header( 'Cache-Control: private', false );
- // Sanitize.
- $basename = mb_ereg_replace( '([^\w\d\-_~,;\[\]\(\).])', '', $basename );
+ // Force the browser to download, rather than displaying the file inline.
+ header( "Content-Disposition: attachment; filename=\"$filename\"" );
+ header( 'Accept-Ranges: bytes' );
+ header( "Content-Length: $content_length" );
+ header( "Content-Type: $content_type" );
- return $basename;
+ // Honour HTTP HEAD requests.
+ return $_SERVER['REQUEST_METHOD'] === 'HEAD'
+ ? false
+ : transmit( $filename, $seek_start, $size );
}
-
/**
* Transmits a file from the server to the client.
/**
- * Downloads a file, allowing for resuming partial downloads.
- *
- * @param string $filename File to download, must be in script directory.
+ * Increments the number in a file using an exclusive lock. If the file
+ * doesn't exist, it will be created and the initial value set to 0.
*
- * @return bool True if the file was transferred.
+ * @param string $filename The file containing a number to increment.
*/
- function download( $filename ) {
- // Don't cache the file stats result (e.g., file size).
- clearstatcache();
-
- $size = @filesize( $filename );
- $size = $size === false || empty( $size ) ? 0 : $size;
- $content_type = mime_content_type( $filename );
- $content_length = $size;
- $seek_start = 0;
-
- // Added by PHP, removed by us.
- header_remove( 'x-powered-by' );
+ function increment_count( $filename ) {
+ try {
+ lock_open( $filename );
- // Check if a range is sent by browser or download manager.
- if( isset( $_SERVER[ 'HTTP_RANGE' ] ) ) {
- $range_format = '/^bytes=\d*-\d*(,\d*-\d*)*$/';
- $request_range = $_SERVER[ 'HTTP_RANGE' ];
+ // Coerce value to largest natural numeric data type.
+ $count = @file_get_contents( $filename ) + 0;
- // Ensure the content request range is in a valid format.
- if( !preg_match( $range_format, $request_range, $matches ) ) {
- header( 'HTTP/1.1 416 Requested Range Not Satisfiable' );
- header( "Content-Range: bytes */$size" );
+ // Write the new counter value.
+ file_put_contents( $filename, $count + 1 );
+ }
+ finally {
+ lock_close( $filename );
+ }
+ }
- // Return early because the range is invalid.
- return false;
- }
+ /**
+ * Acquires a lock for a particular file. Callers would be prudent to
+ * call this function from within a try/finally block and close the lock
+ * in the finally section. The amount of time between opening and closing
+ * the lock must be minimal because parallel processes will be waiting on
+ * the lock's release.
+ *
+ * @param string $filename The name of file to lock.
+ *
+ * @return bool True if the lock was obtained, false upon excessive attempts.
+ */
+ function lock_open( $filename ) {
+ $lockdir = create_lock_filename( $filename );
- // Multiple ranges could be specified, but only serve the first range.
- $seek_start = $matches[ 1 ] + 0;
+ // Track the number of times a lock attempt is made.
+ $iterations = 0;
- if( isset( $matches[ 2 ] ) ) {
- $seek_end = $matches[ 2 ] + 0;
+ do {
+ // Creates and tests lock file existence atomically.
+ if( @mkdir( $lockdir, 0777 ) ) {
+ // Exit the loop.
+ $iterations = 0;
}
else {
- $seek_end = $size - 1;
- }
-
- $range_bytes = $seek_start . '-' . $seek_end . '/' . $size;
- $content_length = $seek_end - $seek_start + 1;
+ $iterations++;
+ $lifetime = time() - filemtime( $lockdir );
- header( 'HTTP/1.1 206 Partial Content' );
- header( "Content-Range: bytes $range_bytes" );
+ if( $lifetime > 10 ) {
+ // If the lock has gone stale, delete it.
+ @rmdir( $lockdir );
+ }
+ else {
+ // Wait a random duration to avoid concurrency conflicts.
+ usleep( rand( 1000, 10000 ) );
+ }
+ }
}
-
- // HTTP/1.1 clients must treat invalid date formats, especially 0, as past.
- header( 'Expires: 0' );
-
- // Prevent local caching.
- header( 'Cache-Control: public, must-revalidate, post-check=0, pre-check=0' );
+ while( $iterations > 0 && $iterations < 10 );
- // No response message portion may be cached (e.g., by a proxy server).
- header( 'Cache-Control: private', false );
+ // Indicate whether the maximum number of lock attempts were exceeded.
+ return $iterations == 0;
+ }
- // Force the browser to download, rather than displaying the file inline.
- header( "Content-Disposition: attachment; filename=\"$filename\"" );
- header( 'Accept-Ranges: bytes' );
- header( "Content-Length: $content_length" );
- header( "Content-Type: $content_type" );
+ /**
+ * Releases the lock on a particular file.
+ *
+ * @param string $filename The name of file that was locked.
+ */
+ function lock_close( $filename ) {
+ @rmdir( create_lock_filename( $filename ) );
+ }
- // Honour HTTP HEAD requests.
- return $_SERVER['REQUEST_METHOD'] === 'HEAD'
- ? false
- : transmit( $filename, $seek_start, $size );
+ /**
+ * Creates a uniquely named lock directory name.
+ *
+ * @param string $filename The name of the file under contention.
+ *
+ * @return string A unique lock file reference for the given filename.
+ */
+ function create_lock_filename( $filename ) {
+ return $filename .'.lock';
}
?>