HEX
Server: Apache
System: Linux uyu7574470001-7d78c9ff74-xfpwm 4.19.91-21.al7.x86_64 #1 SMP Wed Sep 2 19:47:49 CST 2020 x86_64
User: ()
PHP: 7.4.16
Disabled: chmod,exec,system,passthru,shell_exec,escapeshellarg,escapeshellcmd,proc_close,proc_open,ini_alter,dl,popen,pcntl_exec,socket_accept,socket_bind,socket_clear_error,socket_close,socket_connect,socket_create_listen,socket_create_pair,socket_create,socket_get_option,socket_getpeername,socket_getsockname,socket_last_error,socket_listen,socket_read,socket_recv,socket_recvfrom,socket_select,socket_send,socket_sendto,socket_set_block,socket_set_nonblock,socket_set_option,socket_shutdown,socket_strerror,socket_write,stream_socket_client,stream_socket_server,pfsockopen,disk_total_space,disk_free_space,chown,diskfreespace,getrusage,get_current_user,getmyuid,getmypid,dl,leak,listen,chgrp,link,symlink,dlopen,proc_nice,proc_get_stats,proc_terminate,shell_exec,sh2_exec,posix_getpwuid,posix_getgrgid,posix_kill,ini_restore,mkfifo,dbmopen,dbase_open,filepro,filepro_rowcount,posix_mkfifo,putenv,sleep,fsockopen
Upload Files
File: /usr/home/uyu7574470001/htdocs/wp-content/plugins/tiny-compress-images/src/class-tiny-image.php
<?php
/*
* Tiny Compress Images - WordPress plugin.
* Copyright (C) 2015-2018 Tinify B.V.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

class Tiny_Image {
	const ORIGINAL = 0;

	/** @var Tiny_Settings */
	private $settings;
	private $id;
	private $name;
	private $wp_metadata;
	private $sizes      = array();
	private $statistics = array();

	public function __construct(
		$settings,
		$id,
		$wp_metadata = null,
		$tiny_metadata = null,
		$active_sizes = null,
		$active_tinify_sizes = null
	) {
		$this->settings    = $settings;
		$this->id          = $id;
		$this->wp_metadata = $wp_metadata;
		$this->parse_wp_metadata();
		$this->parse_tiny_metadata( $tiny_metadata );
		$this->detect_duplicates( $active_sizes, $active_tinify_sizes );
	}

	private function parse_wp_metadata() {
		if ( ! is_array( $this->wp_metadata ) ) {
			$this->wp_metadata = wp_get_attachment_metadata( $this->id );
		}

		if ( ! is_array( $this->wp_metadata ) || ! isset( $this->wp_metadata['file'] ) ) {
			/* No file metadata found, this might be another plugin messing with
				metadata. Simply ignore this! */
			return;
		}

		$upload_dir  = wp_upload_dir();
		$path_prefix = $upload_dir['basedir'] . '/';
		$path_info   = pathinfo( $this->wp_metadata['file'] );
		if ( isset( $path_info['dirname'] ) ) {
			$path_prefix .= $path_info['dirname'] . '/';
		}

		/* Do not use pathinfo for getting the filename.
			It doesn't work when the filename starts with a special character. */
		$path_parts                    = explode( '/', $this->wp_metadata['file'] );
		$this->name                    = end( $path_parts );
		$filename                      = $path_prefix . $this->name;
		$this->sizes[ self::ORIGINAL ] = new Tiny_Image_Size( $filename );

		// Ensure 'sizes' exists and is an array to prevent PHP Warnings
		$sizes = isset( $this->wp_metadata['sizes'] ) && is_array( $this->wp_metadata['sizes'] )
		? $this->wp_metadata['sizes']
		: array();

		$sanitized_sizes = array();
		foreach ( $sizes as $size_name => $size_info ) {
			// size is valid when its an array and has a file
			if ( is_array( $size_info ) && isset( $size_info['file'] ) ) {
				// Add to sanitized metadata
				$sanitized_sizes[ $size_name ] = $size_info;
				$this->sizes[ $size_name ]     = new Tiny_Image_Size(
					$path_prefix . $size_info['file']
				);
			}
		}

		// Update the metadata with only the valid sizes found
		$this->wp_metadata['sizes'] = $sanitized_sizes;
	}

	private function detect_duplicates( $active_sizes, $active_tinify_sizes ) {
		$filenames = array();

		if ( is_array( $this->wp_metadata )
			&& isset( $this->wp_metadata['file'] )
			&& isset( $this->wp_metadata['sizes'] )
			&& is_array( $this->wp_metadata['sizes'] ) ) {

			if ( null == $active_sizes ) {
				$active_sizes = $this->settings->get_sizes();
			}
			if ( null == $active_tinify_sizes ) {
				$active_tinify_sizes = $this->settings->get_active_tinify_sizes();
			}

			foreach ( $this->wp_metadata['sizes'] as $size_name => $size ) {
				if ( $this->sizes[ $size_name ]->has_been_compressed()
					&& array_key_exists( $size_name, $active_sizes ) ) {
					$filenames = $this->duplicate_check( $filenames, $size['file'], $size_name );
				}
			}
			foreach ( $this->wp_metadata['sizes'] as $size_name => $size ) {
				if ( in_array( $size_name, $active_tinify_sizes, true ) ) {
					$filenames = $this->duplicate_check( $filenames, $size['file'], $size_name );
				}
			}
			foreach ( $this->wp_metadata['sizes'] as $size_name => $size ) {
				if ( array_key_exists( $size_name, $active_sizes ) ) {
					$filenames = $this->duplicate_check( $filenames, $size['file'], $size_name );
				}
			}
			foreach ( $this->wp_metadata['sizes'] as $size_name => $size ) {
				$filenames = $this->duplicate_check( $filenames, $size['file'], $size_name );
			}
		}
	}

	private function duplicate_check( $filenames, $file, $size_name ) {
		if ( isset( $filenames[ $file ] ) ) {
			if ( $filenames[ $file ] != $size_name ) {
				$this->sizes[ $size_name ]->mark_duplicate( $filenames[ $file ] );
			}
		} else {
			$filenames[ $file ] = $size_name;
		}
		return $filenames;
	}

	private function parse_tiny_metadata( $tiny_metadata = null ) {
		if ( is_null( $tiny_metadata ) ) {
			$tiny_metadata = get_post_meta( $this->id, Tiny_Config::META_KEY, true );
		}
		if ( $tiny_metadata ) {
			foreach ( $tiny_metadata as $size => $meta ) {
				if ( ! isset( $this->sizes[ $size ] ) ) {
					if ( self::is_retina( $size ) && Tiny_Settings::wr2x_active() ) {
						$size_name = rtrim( $size, '_wr2x' );
						if ( 'original' === $size_name ) {
							$size_name = '0';
						}
						$retina_path          = wr2x_get_retina(
							$this->sizes[ $size_name ]->filename
						);
						$this->sizes[ $size ] = new Tiny_Image_Size( $retina_path );
					} else {
						$this->sizes[ $size ] = new Tiny_Image_Size();
					}
				}
				$this->sizes[ $size ]->meta = $meta;
			}
		}
	}

	public function get_id() {
		return $this->id;
	}

	public function get_name() {
		return $this->name;
	}

	public function get_wp_metadata() {
		return $this->wp_metadata;
	}

	public function file_type_allowed() {
		return in_array(
			$this->get_mime_type(),
			array( 'image/jpeg', 'image/png', 'image/webp' ),
			true
		);
	}

	public function get_mime_type() {
		return get_post_mime_type( $this->id );
	}

	public function compress() {
		Tiny_Logger::debug(
			'compress',
			array(
				'image_id' => $this->id,
				'name'     => $this->name,
			)
		);
		if ( $this->settings->get_compressor() === null || ! $this->file_type_allowed() ) {
			return;
		}

		$success = 0;
		$failed  = 0;

		$active_tinify_sizes = $this->settings->get_active_tinify_sizes();

		if ( $this->settings->get_conversion_enabled() ) {
			$uncompressed_sizes = $this->filter_image_sizes( 'uncompressed', $active_tinify_sizes );
			$unconverted_sizes  = $this->filter_image_sizes( 'unconverted', $active_tinify_sizes );

			$unprocessed_sizes = $uncompressed_sizes + $unconverted_sizes;
		} else {
			$unprocessed_sizes = $this->filter_image_sizes( 'uncompressed', $active_tinify_sizes );
		}

		$compressor = $this->settings->get_compressor();
		$convert_to = $this->convert_to();

		foreach ( $unprocessed_sizes as $size_name => $size ) {
			if ( ! $size->is_duplicate() ) {
				$size->add_tiny_meta_start();
				$this->update_tiny_post_meta();
				$resize   = $this->settings->get_resize_options( $size_name );
				$preserve = $this->settings->get_preserve_options( $size_name );
				Tiny_Logger::debug(
					'compress size',
					array(
						'image_id'            => $this->id,
						'size'                => $size_name,
						'resize'              => $resize,
						'preserve'            => $preserve,
						'convert'             => $convert_to,
						'modified'            => $size->modified(),
						'filename'            => $size->filename,
						'is_duplicate'        => $size->is_duplicate(),
						'exists'              => $size->exists(),
						'has_been_compressed' => $size->has_been_compressed(),
						'filesize'            => $size->filesize(),
						'mimetype'            => $size->mimetype(),
					)
				);
				try {
					$response = $compressor->compress_file(
						$size->filename,
						$resize,
						$preserve,
						$convert_to
					);

					// ensure that all conversion are in the same format as the first one
					$convert_to = isset( $response['convert'] ) ?
						array( $response['convert']['type'] ) :
						$convert_to;

					$size->add_tiny_meta( $response );
					++$success;
					Tiny_Logger::debug(
						'compress success',
						array(
							'size'     => $size_name,
							'image_id' => $this->id,
						)
					);
				} catch ( Tiny_Exception $e ) {
					$size->add_tiny_meta_error( $e );
					++$failed;
					Tiny_Logger::error(
						'compress failed',
						array(
							'error'    => $e->get_message(),
							'size'     => $size_name,
							'image_id' => $this->id,
						)
					);
				}
				$this->add_wp_metadata( $size_name, $size );
				$this->update_tiny_post_meta();
			}// End if().
		}// End foreach().

		/*
			Other plugins can hook into this action to execute custom logic
			after the image sizes have been compressed, ie. cache flushing.
		*/
		do_action( 'tiny_image_after_compression', $this->id, $success );

		return array(
			'success' => $success,
			'failed'  => $failed,
		);
	}

	public function delete_converted_image() {
		$sizes = $this->get_image_sizes();
		foreach ( $sizes as $size ) {
			$size->delete_converted_image_size();
		}
	}

	public function compress_retina( $size_name, $path ) {
		if ( $this->settings->get_compressor() === null || ! $this->file_type_allowed() ) {
			return;
		}

		if ( ! isset( $this->sizes[ $size_name ] ) ) {
			$this->sizes[ $size_name ] = new Tiny_Image_Size( $path );
		}

		$size = $this->sizes[ $size_name ];

		$compressor = $this->settings->get_compressor();
		$convert_to = $this->convert_to();

		if ( ! $size->has_been_compressed() ) {
			$size->add_tiny_meta_start();
			$this->update_tiny_post_meta();
			$preserve = $this->settings->get_preserve_options( $size_name );

			try {
				$response = $compressor->compress_file( $path, false, $preserve, $convert_to );
				$size->add_tiny_meta( $response );
			} catch ( Tiny_Exception $e ) {
				$size->add_tiny_meta_error( $e );
			}
			$this->update_tiny_post_meta();
		}
	}

	public function remove_retina_metadata() {
		// Remove metadata from all sizes, as this callback only fires when all
		// retina sizes are deleted.
		foreach ( $this->sizes as $size_name => $size ) {
			if ( self::is_retina( $size_name ) ) {
				unset( $this->sizes[ $size_name ] );
			}
		}
		$this->update_tiny_post_meta();
	}

	public function add_wp_metadata( $size_name, $size ) {
		if ( self::is_original( $size_name ) ) {
			if ( isset( $size->meta['output'] ) ) {
				$output = $size->meta['output'];
				if ( isset( $output['width'] ) && isset( $output['height'] ) ) {
					$this->wp_metadata['width']    = $output['width'];
					$this->wp_metadata['height']   = $output['height'];
					$this->wp_metadata['filesize'] = $output['size'];
				}
			}
		}
	}

	public function update_tiny_post_meta() {
		$tiny_metadata = array();
		foreach ( $this->sizes as $size_name => $size ) {
			$tiny_metadata[ $size_name ] = $size->meta;
		}
		update_post_meta( $this->id, Tiny_Config::META_KEY, $tiny_metadata );
		/*
			This action is being used by WPML:
			https://gist.github.com/srdjan-jcc/5c47685cda4da471dff5757ba3ce5ab1
		*/
		do_action( 'updated_tiny_postmeta', $this->id, Tiny_Config::META_KEY, $tiny_metadata );
	}

	public function get_image_sizes() {
		$original     = isset( $this->sizes[ self::ORIGINAL ] )
			? array(
				self::ORIGINAL => $this->sizes[ self::ORIGINAL ],
			)
			: array();
		$compressed   = array();
		$uncompressed = array();
		foreach ( $this->sizes as $size_name => $size ) {
			if ( self::is_original( $size_name ) ) {
				continue;
			}

			if ( $size->has_been_compressed() ) {
				$compressed[ $size_name ] = $size;
			} else {
				$uncompressed[ $size_name ] = $size;
			}
		}
		ksort( $compressed );
		ksort( $uncompressed );
		return $original + $compressed + $uncompressed;
	}

	public function get_image_size( $size = self::ORIGINAL, $create = false ) {
		if ( isset( $this->sizes[ $size ] ) ) {
			return $this->sizes[ $size ];
		} elseif ( $create ) {
			return new Tiny_Image_Size();
		} else {
			return null;
		}
	}

	public function filter_image_sizes( $method, $filter_sizes = null ) {
		$selection = array();
		if ( is_null( $filter_sizes ) ) {
			$filter_sizes = array_keys( $this->sizes );
		}
		foreach ( $filter_sizes as $size_name ) {
			if ( ! isset( $this->sizes[ $size_name ] ) ) {
				continue;
			}

			$tiny_image_size = $this->sizes[ $size_name ];
			if ( $tiny_image_size->$method() ) {
				$selection[ $size_name ] = $tiny_image_size;
			}
		}
		return $selection;
	}

	public function get_count( $methods, $count_sizes = null ) {
		$stats = array_fill_keys( $methods, 0 );
		if ( is_null( $count_sizes ) ) {
			$count_sizes = array_keys( $this->sizes );
		}
		foreach ( $count_sizes as $size ) {
			if ( ! isset( $this->sizes[ $size ] ) ) {
				continue;
			}

			foreach ( $methods as $method ) {
				if ( $this->sizes[ $size ]->$method() ) {
					++$stats[ $method ];
				}
			}
		}
		return $stats;
	}

	public function get_latest_error() {
		$active_tinify_sizes = $this->settings->get_active_tinify_sizes();
		$error_message       = null;
		$last_timestamp      = null;
		foreach ( $this->sizes as $size_name => $size ) {
			if ( in_array( $size_name, $active_tinify_sizes, true ) ) {
				if ( isset( $size->meta['error'] ) && isset( $size->meta['message'] ) ) {
					if (
						null === $last_timestamp ||
						$last_timestamp < $size->meta['timestamp']
					) {
						$last_timestamp = $size->meta['timestamp'];
						$error_message  = Tiny_Helpers::truncate_text(
							$size->meta['message'],
							140
						);
					}
				}
			}
		}
		return $error_message;
	}

	public function get_savings( $stats ) {
		$before = $stats['initial_total_size'];
		$after  = $stats['compressed_total_size'];
		if ( 0 === $before ) {
			$savings = 0;
		} else {
			$savings = ( $before - $after ) / $before * 100;
		}
		return '' . number_format( $savings, 1 );
	}

	public function get_statistics( $active_sizes, $active_tinify_sizes ) {
		if ( $this->statistics ) {
			error_log( 'Strangely the image statistics are asked for again.' );
			return $this->statistics;
		}

		$this->statistics['initial_total_size']           = 0;
		$this->statistics['compressed_total_size']        = 0;
		$this->statistics['image_sizes_compressed']       = 0;
		$this->statistics['available_uncompressed_sizes'] = 0;
		$this->statistics['image_sizes_converted']        = 0;
		$this->statistics['available_unconverted_sizes']  = 0;

		foreach ( $this->sizes as $size_name => $size ) {
			// skip duplicates or inactive sizes
			if ( $size->is_duplicate() || ! isset( $active_sizes[ $size_name ] ) ) {
				continue;
			}

			$file_size      = $size->filesize();
			$is_active_size = in_array( $size_name, $active_tinify_sizes, true );

			if ( isset( $size->meta['input'] ) ) {
				$input_size                              = (int) $size->meta['input']['size'];
				$this->statistics['initial_total_size'] += $input_size;

				if ( isset( $size->meta['output'] ) ) {
					$output_size = (int) $size->meta['output']['size'];

					if ( $size->modified() ) {
						$this->statistics['compressed_total_size'] += $file_size;
						if ( $is_active_size ) {
							++$this->statistics['available_uncompressed_sizes'];
						}
					} else {
						$this->statistics['compressed_total_size'] += $output_size;
						++$this->statistics['image_sizes_compressed'];
					}
				} else {
					$this->statistics['compressed_total_size'] += $input_size;
				}
			} elseif ( $size->exists() ) {
				$this->statistics['initial_total_size']    += $file_size;
				$this->statistics['compressed_total_size'] += $file_size;
				if ( $is_active_size ) {
					++$this->statistics['available_uncompressed_sizes'];
				}
			}

			if ( $is_active_size ) {
				if ( $size->has_been_converted() ) {
					++$this->statistics['image_sizes_converted'];
				} else {
					++$this->statistics['available_unconverted_sizes'];
				}
			}
		}// End foreach().

		return $this->statistics;
	}


	public static function is_original( $size ) {
		return self::ORIGINAL === $size;
	}

	public static function is_retina( $size ) {
		return strrpos( $size, 'wr2x' ) === strlen( $size ) - strlen( 'wr2x' );
	}

	public function can_be_converted() {
		return $this->settings->get_conversion_enabled() && $this->file_type_allowed();
	}

	/**
	 * Get the targeted conversion.
	 * If original is already converted, then we use the originals' mimetype.
	 * If nothing is converted yet, we use the settings conversion settings.
	 *
	 * @since 3.6.4
	 *
	 * @return array{string} mimetypes to which the image should be converted to
	 */
	private function convert_to() {
		$convert_settings = $this->settings->get_conversion_options();
		if ( ! $convert_settings['convert'] ) {
			// conversion is off so return no mimetypes to convert to
			return array();
		}

		if ( isset( $this->sizes[ self::ORIGINAL ] ) ) {
			// original is not in sizes so mimetypes are open
			return $convert_settings['convert_to'];
		}

		$original_img_size = $this->sizes[ self::ORIGINAL ];
		if ( $original_img_size->converted() ) {
			// original has been convert so use that mimetype to convert to
			return array( $original_img_size->meta['convert']['type'] );
		}

		return $convert_settings['convert_to'];
	}

	/**
	 * Marks the image as compressed without actually compressing it.
	 *
	 * This method parses existing metadata and delegates to each image size to mark
	 * itself as compressed. It considers conversion settings when marking the sizes.
	 * This is useful for images that are already optimized or when you want to skip
	 * compression while still marking them as processed in the system.
	 *
	 * @since 3.0.0
	 */
	public function mark_as_compressed() {
		$this->parse_tiny_metadata();

		$conversion_enabled = $this->settings->get_conversion_enabled();

		$active_tinify_sizes = $this->settings->get_active_tinify_sizes();

		if ( $this->settings->get_conversion_enabled() ) {
			$uncompressed_sizes = $this->filter_image_sizes( 'uncompressed', $active_tinify_sizes );
			$unconverted_sizes  = $this->filter_image_sizes( 'unconverted', $active_tinify_sizes );

			$unprocessed_sizes = $uncompressed_sizes + $unconverted_sizes;
		} else {
			$unprocessed_sizes = $this->filter_image_sizes( 'uncompressed', $active_tinify_sizes );
		}

		foreach ( $unprocessed_sizes as $size ) {
			$size->mark_as_compressed( $conversion_enabled );
		}

		$this->update_tiny_post_meta();
	}
}