95 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			95 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env php
 | |
| <?php # -*- coding: utf-8 mode: php -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
 | |
| 
 | |
| function wfBaseConvert( $input, $sourceBase, $destBase, $pad = 1, $lowercase = true ) {
 | |
|   $input = strval( $input );
 | |
|   if( $sourceBase < 2 ||
 | |
|     $sourceBase > 36 ||
 | |
|     $destBase < 2 ||
 | |
|     $destBase > 36 ||
 | |
|     $pad < 1 ||
 | |
|     $sourceBase != intval( $sourceBase ) ||
 | |
|     $destBase != intval( $destBase ) ||
 | |
|     $pad != intval( $pad ) ||
 | |
|     !is_string( $input ) ||
 | |
|     $input == '' ) {
 | |
|     return false;
 | |
|   }
 | |
|   $digitChars = ( $lowercase ) ? '0123456789abcdefghijklmnopqrstuvwxyz' : '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
 | |
|   $inDigits = array();
 | |
|   $outChars = '';
 | |
| 
 | |
|   // Decode and validate input string
 | |
|   $input = strtolower( $input );
 | |
|   for( $i = 0; $i < strlen( $input ); $i++ ) {
 | |
|     $n = strpos( $digitChars, $input[$i] );
 | |
|     if( $n === false || $n > $sourceBase ) {
 | |
|       return false;
 | |
|     }
 | |
|     $inDigits[] = $n;
 | |
|   }
 | |
| 
 | |
|   // Iterate over the input, modulo-ing out an output digit
 | |
|   // at a time until input is gone.
 | |
|   while( count( $inDigits ) ) {
 | |
|     $work = 0;
 | |
|     $workDigits = array();
 | |
| 
 | |
|     // Long division...
 | |
|     foreach( $inDigits as $digit ) {
 | |
|       $work *= $sourceBase;
 | |
|       $work += $digit;
 | |
| 
 | |
|       if( $work < $destBase ) {
 | |
|         // Gonna need to pull another digit.
 | |
|         if( count( $workDigits ) ) {
 | |
|           // Avoid zero-padding; this lets us find
 | |
|           // the end of the input very easily when
 | |
|           // length drops to zero.
 | |
|           $workDigits[] = 0;
 | |
|         }
 | |
|       } else {
 | |
|         // Finally! Actual division!
 | |
|         $workDigits[] = intval( $work / $destBase );
 | |
| 
 | |
|         // Isn't it annoying that most programming languages
 | |
|         // don't have a single divide-and-remainder operator,
 | |
|         // even though the CPU implements it that way?
 | |
|         $work = $work % $destBase;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // All that division leaves us with a remainder,
 | |
|     // which is conveniently our next output digit.
 | |
|     $outChars .= $digitChars[$work];
 | |
| 
 | |
|     // And we continue!
 | |
|     $inDigits = $workDigits;
 | |
|   }
 | |
| 
 | |
|   while( strlen( $outChars ) < $pad ) {
 | |
|     $outChars .= '0';
 | |
|   }
 | |
| 
 | |
|   return strrev( $outChars );
 | |
| }
 | |
| 
 | |
| function base36Sha1( $text ) {
 | |
|   return wfBaseConvert( sha1( $text ), 16, 36, 31 );
 | |
| }
 | |
| 
 | |
| if ($argc > 1) {
 | |
|   $inf = fopen($argv[1], "rb");
 | |
|   if ($inf === FALSE) exit(1);
 | |
|   $close = TRUE;
 | |
| } else {
 | |
|   $inf = STDIN;
 | |
|   $close = FALSE;
 | |
| }
 | |
| 
 | |
| $data = stream_get_contents($inf);
 | |
| fwrite(STDOUT, base36Sha1($data));
 | |
| fwrite(STDOUT, "\n");
 | |
| 
 | |
| if ($close) fclose($inf);
 |