includes/functions.php
changeset 328 dc838fd61a06
parent 326 ab66d6d1f1f4
child 334 c72b545f1304
equal deleted inserted replaced
327:c2f4c900c507 328:dc838fd61a06
  3405   if ( file_exists($out_file) )
  3405   if ( file_exists($out_file) )
  3406     return true;
  3406     return true;
  3407   return false;
  3407   return false;
  3408 }
  3408 }
  3409 
  3409 
       
  3410 /**
       
  3411  * Determines whether a GIF file is animated or not. Credit goes to ZeBadger from <http://www.php.net/imagecreatefromgif>.
       
  3412  * Modified to conform to Enano coding standards.
       
  3413  * @param string Path to GIF file
       
  3414  * @return bool If animated, returns true
       
  3415  */
       
  3416 
       
  3417  
       
  3418 function is_gif_animated($filename)
       
  3419 {
       
  3420   $filecontents = @file_get_contents($filename);
       
  3421   if ( empty($filecontents) )
       
  3422     return false;
       
  3423 
       
  3424   $str_loc = 0;
       
  3425   $count = 0;
       
  3426   while ( $count < 2 ) // There is no point in continuing after we find a 2nd frame
       
  3427   {
       
  3428     $where1 = strpos($filecontents,"\x00\x21\xF9\x04", $str_loc);
       
  3429     if ( $where1 === false )
       
  3430     {
       
  3431       break;
       
  3432     }
       
  3433     else
       
  3434     {
       
  3435       $str_loc = $where1 + 1;
       
  3436       $where2 = strpos($filecontents,"\x00\x2C", $str_loc);
       
  3437       if ( $where2 === false )
       
  3438       {
       
  3439         break;
       
  3440       }
       
  3441       else
       
  3442       {
       
  3443         if ( $where1 + 8 == $where2 )
       
  3444         {
       
  3445           $count++;
       
  3446         }
       
  3447         $str_loc = $where2 + 1;
       
  3448       }
       
  3449     }
       
  3450   }
       
  3451   
       
  3452   return ( $count > 1 ) ? true : false;
       
  3453 }
       
  3454 
       
  3455 /**
       
  3456  * Retrieves the dimensions of a GIF image.
       
  3457  * @param string The path to the GIF file.
       
  3458  * @return array Key 0 is width, key 1 is height
       
  3459  */
       
  3460 
       
  3461 function gif_get_dimensions($filename)
       
  3462 {
       
  3463   $filecontents = @file_get_contents($filename);
       
  3464   if ( empty($filecontents) )
       
  3465     return false;
       
  3466   if ( strlen($filecontents) < 10 )
       
  3467     return false;
       
  3468   
       
  3469   $width = substr($filecontents, 6, 2);
       
  3470   $height = substr($filecontents, 8, 2);
       
  3471   $width = unpack('v', $width);
       
  3472   $height = unpack('v', $height);
       
  3473   return array($width[1], $height[1]);
       
  3474 }
       
  3475 
       
  3476 /**
       
  3477  * Determines whether a PNG image is animated or not. Based on some specification information from <http://wiki.mozilla.org/APNG_Specification>.
       
  3478  * @param string Path to PNG file.
       
  3479  * @return bool If animated, returns true
       
  3480  */
       
  3481 
       
  3482 function is_png_animated($filename)
       
  3483 {
       
  3484   $filecontents = @file_get_contents($filename);
       
  3485   if ( empty($filecontents) )
       
  3486     return false;
       
  3487   
       
  3488   $parsed = parse_png($filecontents);
       
  3489   if ( !$parsed )
       
  3490     return false;
       
  3491   
       
  3492   if ( !isset($parsed['fdAT']) )
       
  3493     return false;
       
  3494   
       
  3495   if ( count($parsed['fdAT']) > 1 )
       
  3496     return true;
       
  3497 }
       
  3498 
       
  3499 /**
       
  3500  * Gets the dimensions of a PNG image.
       
  3501  * @param string Path to PNG file
       
  3502  * @return array Key 0 is width, key 1 is length.
       
  3503  */
       
  3504 
       
  3505 function png_get_dimensions($filename)
       
  3506 {
       
  3507   $filecontents = @file_get_contents($filename);
       
  3508   if ( empty($filecontents) )
       
  3509     return false;
       
  3510   
       
  3511   $parsed = parse_png($filecontents);
       
  3512   if ( !$parsed )
       
  3513     return false;
       
  3514   
       
  3515   $ihdr_stream = $parsed['IHDR'][0];
       
  3516   $width = substr($ihdr_stream, 0, 4);
       
  3517   $height = substr($ihdr_stream, 4, 4);
       
  3518   $width = unpack('N', $width);
       
  3519   $height = unpack('N', $height);
       
  3520   $x = $width[1];
       
  3521   $y = $height[1];
       
  3522   return array($x, $y);
       
  3523 }
       
  3524 
       
  3525 /**
       
  3526  * Internal function to parse out the streams of a PNG file. Based on the W3 PNG spec: http://www.w3.org/TR/PNG/
       
  3527  * @param string The contents of the PNG
       
  3528  * @return array Associative array containing the streams
       
  3529  */
       
  3530 
       
  3531 function parse_png($data)
       
  3532 {
       
  3533   // Trim off first 8 bytes to check for PNG header
       
  3534   $header = substr($data, 0, 8);
       
  3535   if ( $header != "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a" )
       
  3536   {
       
  3537     return false;
       
  3538   }
       
  3539   $return = array();
       
  3540   $data = substr($data, 8);
       
  3541   while ( strlen($data) > 0 )
       
  3542   {
       
  3543     $chunklen_bin = substr($data, 0, 4);
       
  3544     $chunk_type = substr($data, 4, 4);
       
  3545     $chunklen = unpack('N', $chunklen_bin);
       
  3546     $chunklen = $chunklen[1];
       
  3547     $chunk_data = substr($data, 8, $chunklen);
       
  3548     
       
  3549     // If the chunk type is not valid, this may be a malicious PNG with bad offsets. Break out of the loop.
       
  3550     if ( !preg_match('/^[A-z]{4}$/', $chunk_type) )
       
  3551       break;
       
  3552     
       
  3553     if ( !isset($return[$chunk_type]) )
       
  3554       $return[$chunk_type] = array();
       
  3555     $return[$chunk_type][] = $chunk_data;
       
  3556     
       
  3557     $offset_next = 4 // Length
       
  3558                  + 4 // Type
       
  3559                  + $chunklen // Data
       
  3560                  + 4; // CRC
       
  3561     $data = substr($data, $offset_next);
       
  3562   }
       
  3563   return $return;
       
  3564 }
       
  3565 
       
  3566 /**
       
  3567  * Retreives information about the intrinsic characteristics of the jpeg image, such as Bits per Component, Height and Width. This function is from the PHP JPEG Metadata Toolkit. Licensed under the GPLv2 or later.
       
  3568  * @param array The JPEG header data, as retrieved from the get_jpeg_header_data function
       
  3569  * @return array An array containing the intrinsic JPEG values FALSE - if the comment segment couldnt be found
       
  3570  * @license GNU General Public License
       
  3571  * @copyright Copyright Evan Hunter 2004 
       
  3572  */
       
  3573 
       
  3574 function get_jpeg_intrinsic_values( $jpeg_header_data )
       
  3575 {
       
  3576   // Create a blank array for the output
       
  3577   $Outputarray = array( );
       
  3578 
       
  3579   //Cycle through the header segments until Start Of Frame (SOF) is found or we run out of segments
       
  3580   $i = 0;
       
  3581   while ( ( $i < count( $jpeg_header_data) )  && ( substr( $jpeg_header_data[$i]['SegName'], 0, 3 ) != "SOF" ) )
       
  3582   {
       
  3583     $i++;
       
  3584   }
       
  3585 
       
  3586   // Check if a SOF segment has been found
       
  3587   if ( substr( $jpeg_header_data[$i]['SegName'], 0, 3 ) == "SOF" )
       
  3588   {
       
  3589     // SOF segment was found, extract the information
       
  3590 
       
  3591     $data = $jpeg_header_data[$i]['SegData'];
       
  3592 
       
  3593     // First byte is Bits per component
       
  3594     $Outputarray['Bits per Component'] = ord( $data{0} );
       
  3595 
       
  3596     // Second and third bytes are Image Height
       
  3597     $Outputarray['Image Height'] = ord( $data{ 1 } ) * 256 + ord( $data{ 2 } );
       
  3598 
       
  3599     // Forth and fifth bytes are Image Width
       
  3600     $Outputarray['Image Width'] = ord( $data{ 3 } ) * 256 + ord( $data{ 4 } );
       
  3601 
       
  3602     // Sixth byte is number of components
       
  3603     $numcomponents = ord( $data{ 5 } );
       
  3604 
       
  3605     // Following this is a table containing information about the components
       
  3606     for( $i = 0; $i < $numcomponents; $i++ )
       
  3607     {
       
  3608       $Outputarray['Components'][] = array (  'Component Identifier' => ord( $data{ 6 + $i * 3 } ),
       
  3609                 'Horizontal Sampling Factor' => ( ord( $data{ 7 + $i * 3 } ) & 0xF0 ) / 16,
       
  3610                 'Vertical Sampling Factor' => ( ord( $data{ 7 + $i * 3 } ) & 0x0F ),
       
  3611                 'Quantization table destination selector' => ord( $data{ 8 + $i * 3 } ) );
       
  3612     }
       
  3613   }
       
  3614   else
       
  3615   {
       
  3616     // Couldn't find Start Of Frame segment, hence can't retrieve info
       
  3617     return FALSE;
       
  3618   }
       
  3619 
       
  3620   return $Outputarray;
       
  3621 }
       
  3622 
       
  3623 /**
       
  3624  * Reads all the JPEG header segments from an JPEG image file into an array. This function is from the PHP JPEG Metadata Toolkit. Licensed under the GPLv2 or later. Modified slightly for Enano coding standards and to remove unneeded capability.
       
  3625  * @param string the filename of the file to JPEG file to read
       
  3626  * @return string Array of JPEG header segments, or FALSE - if headers could not be read
       
  3627  * @license GNU General Public License
       
  3628  * @copyright Copyright Evan Hunter 2004
       
  3629  */
       
  3630 
       
  3631 function get_jpeg_header_data( $filename )
       
  3632 {
       
  3633   // Attempt to open the jpeg file - the at symbol supresses the error message about
       
  3634   // not being able to open files. The file_exists would have been used, but it
       
  3635   // does not work with files fetched over http or ftp.
       
  3636   $filehnd = @fopen($filename, 'rb');
       
  3637 
       
  3638   // Check if the file opened successfully
       
  3639   if ( ! $filehnd  )
       
  3640   {
       
  3641     // Could't open the file - exit
       
  3642     return FALSE;
       
  3643   }
       
  3644 
       
  3645 
       
  3646   // Read the first two characters
       
  3647   $data = fread( $filehnd, 2 );
       
  3648 
       
  3649   // Check that the first two characters are 0xFF 0xDA  (SOI - Start of image)
       
  3650   if ( $data != "\xFF\xD8" )
       
  3651   {
       
  3652     // No SOI (FF D8) at start of file - This probably isn't a JPEG file - close file and return;
       
  3653     fclose($filehnd);
       
  3654     return FALSE;
       
  3655   }
       
  3656 
       
  3657 
       
  3658   // Read the third character
       
  3659   $data = fread( $filehnd, 2 );
       
  3660 
       
  3661   // Check that the third character is 0xFF (Start of first segment header)
       
  3662   if ( $data{0} != "\xFF" )
       
  3663   {
       
  3664     // NO FF found - close file and return - JPEG is probably corrupted
       
  3665     fclose($filehnd);
       
  3666     return FALSE;
       
  3667   }
       
  3668 
       
  3669   // Flag that we havent yet hit the compressed image data
       
  3670   $hit_compressed_image_data = FALSE;
       
  3671 
       
  3672 
       
  3673   // Cycle through the file until, one of: 1) an EOI (End of image) marker is hit,
       
  3674   //               2) we have hit the compressed image data (no more headers are allowed after data)
       
  3675   //               3) or end of file is hit
       
  3676 
       
  3677   while ( ( $data{1} != "\xD9" ) && (! $hit_compressed_image_data) && ( ! feof( $filehnd ) ))
       
  3678   {
       
  3679     // Found a segment to look at.
       
  3680     // Check that the segment marker is not a Restart marker - restart markers don't have size or data after them
       
  3681     if (  ( ord($data{1}) < 0xD0 ) || ( ord($data{1}) > 0xD7 ) )
       
  3682     {
       
  3683       // Segment isn't a Restart marker
       
  3684       // Read the next two bytes (size)
       
  3685       $sizestr = fread( $filehnd, 2 );
       
  3686 
       
  3687       // convert the size bytes to an integer
       
  3688       $decodedsize = unpack ("nsize", $sizestr);
       
  3689 
       
  3690       // Save the start position of the data
       
  3691       $segdatastart = ftell( $filehnd );
       
  3692 
       
  3693       // Read the segment data with length indicated by the previously read size
       
  3694       $segdata = fread( $filehnd, $decodedsize['size'] - 2 );
       
  3695 
       
  3696 
       
  3697       // Store the segment information in the output array
       
  3698       $headerdata[] = array(  "SegType" => ord($data{1}),
       
  3699             "SegName" => $GLOBALS[ "JPEG_Segment_Names" ][ ord($data{1}) ],
       
  3700             "SegDataStart" => $segdatastart,
       
  3701             "SegData" => $segdata );
       
  3702     }
       
  3703 
       
  3704     // If this is a SOS (Start Of Scan) segment, then there is no more header data - the compressed image data follows
       
  3705     if ( $data{1} == "\xDA" )
       
  3706     {
       
  3707       // Flag that we have hit the compressed image data - exit loop as no more headers available.
       
  3708       $hit_compressed_image_data = TRUE;
       
  3709     }
       
  3710     else
       
  3711     {
       
  3712       // Not an SOS - Read the next two bytes - should be the segment marker for the next segment
       
  3713       $data = fread( $filehnd, 2 );
       
  3714 
       
  3715       // Check that the first byte of the two is 0xFF as it should be for a marker
       
  3716       if ( $data{0} != "\xFF" )
       
  3717       {
       
  3718         // NO FF found - close file and return - JPEG is probably corrupted
       
  3719         fclose($filehnd);
       
  3720         return FALSE;
       
  3721       }
       
  3722     }
       
  3723   }
       
  3724 
       
  3725   // Close File
       
  3726   fclose($filehnd);
       
  3727 
       
  3728   // Return the header data retrieved
       
  3729   return $headerdata;
       
  3730 }
       
  3731 
       
  3732 /**
       
  3733  * Returns the dimensions of a JPEG image in the same format as {php,gif}_get_dimensions().
       
  3734  * @param string JPEG file to check
       
  3735  * @return array Key 0 is width, key 1 is height
       
  3736  */
       
  3737 
       
  3738 function jpg_get_dimensions($filename)
       
  3739 {
       
  3740   if ( !file_exists($filename) )
       
  3741   {
       
  3742     echo "Doesn't exist<br />";
       
  3743     return false;
       
  3744   }
       
  3745   
       
  3746   $headers = get_jpeg_header_data($filename);
       
  3747   if ( !$headers )
       
  3748   {
       
  3749     echo "Bad headers<br />";
       
  3750     return false;
       
  3751   }
       
  3752   
       
  3753   $metadata = get_jpeg_intrinsic_values($headers);
       
  3754   if ( !$metadata )
       
  3755   {
       
  3756     echo "Bad metadata: <pre>" . print_r($metadata, true) . "</pre><br />";
       
  3757     return false;
       
  3758   }
       
  3759   
       
  3760   if ( !isset($metadata['Image Width']) || !isset($metadata['Image Height']) )
       
  3761   {
       
  3762     echo "No metadata<br />";
       
  3763     return false;
       
  3764   }
       
  3765   
       
  3766   return array($metadata['Image Width'], $metadata['Image Height']);
       
  3767 }
       
  3768 
       
  3769 /**
       
  3770  * Generates a URL for the avatar for the given user ID and avatar type.
       
  3771  * @param int User ID
       
  3772  * @param string Image type - must be one of jpg, png, or gif.
       
  3773  * @return string
       
  3774  */
       
  3775 
       
  3776 function make_avatar_url($user_id, $avi_type)
       
  3777 {
       
  3778   if ( !is_int($user_id) )
       
  3779     return false;
       
  3780   if ( !in_array($avi_type, array('png', 'gif', 'jpg')) )
       
  3781     return false;
       
  3782   return scriptPath . '/' . getConfig('avatar_directory') . '/' . $user_id . '.' . $avi_type;
       
  3783 }
       
  3784 
       
  3785 /**
       
  3786  * Determines an image's filetype based on its signature.
       
  3787  * @param string Path to image file
       
  3788  * @return string One of gif, png, or jpg, or false if none of these.
       
  3789  */
       
  3790 
       
  3791 function get_image_filetype($filename)
       
  3792 {
       
  3793   $filecontents = @file_get_contents($filename);
       
  3794   if ( empty($filecontents) )
       
  3795     return false;
       
  3796   
       
  3797   if ( substr($filecontents, 0, 8) == "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a" )
       
  3798     return 'png';
       
  3799   
       
  3800   if ( substr($filecontents, 0, 6) == 'GIF87a' || substr($filecontents, 0, 6) == 'GIF89a' )
       
  3801     return 'gif';
       
  3802   
       
  3803   if ( substr($filecontents, 0, 2) == "\xFF\xD8" )
       
  3804     return 'jpg';
       
  3805   
       
  3806   return false;
       
  3807 }
       
  3808 
  3410 //die('<pre>Original:  01010101010100101010100101010101011010'."\nProcessed: ".uncompress_bitfield(compress_bitfield('01010101010100101010100101010101011010')).'</pre>');
  3809 //die('<pre>Original:  01010101010100101010100101010101011010'."\nProcessed: ".uncompress_bitfield(compress_bitfield('01010101010100101010100101010101011010')).'</pre>');
  3411 
  3810 
  3412 ?>
  3811 ?>