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 ?> |