MOON
Server: Apache
System: Linux 54-179-220-51.cprapid.com 3.10.0-1160.144.1.el7.tuxcare.els4.x86_64 #1 SMP Tue Apr 7 08:40:40 UTC 2026 x86_64
User: thehunarfound (1001)
PHP: 7.4.29
Disabled: NONE
Upload Files
File: /home/thehunarfound/public_html/sms/lib/image-compress/ImageCache.php.txt
<?php
/**
 * The primary class file for PHP Image Compressor & Caching
 *
 * This file is to be used in any PHP project that requires image compression
 *
 * @package PHP Image Compressor & Caching
 * @author Erik Nielsen <erik@312development.com | @erikkylenielsen>
 * @license http://freedomdefined.org/Licenses/CC-BY MIT
 * @version GIT: $Id$
 * 
 * @todo I have a laundry list of things I'd like to complete.  Among them:
 *  - Ensure that 304 headers are being returned each time.
 *  - Code cleanup and ensure PS2 standards are being met
 *  - Improve documentation
 *  - Write better unit tests for CI
 *  - Continue to optimize for memory usage
 *  - Create a method that returns new images sizes
 *  - Create a method that resizes the image
 */

namespace ImageCache;

class ImageCache
{

	/**
	 * @var string The current directory the class is being employed
	 */
	public $cached_directory;

	/**
	 * @var string The root of the source image
	 */
	public $original_root;

	/**
	 * @var bool If the directory containing the compressed images has already been created
	 */
	private $created_dir;

	/**
	 * @var array Options set by the user for the class
	 */
	private $options;

	/**
	 * @var string|int The original memory limit set by the server
	 */
	private $pre_memory_limit;

	/**
	 * @todo Add description
	 */
	static $compressed;

	/**
	 * @todo Add description
	 */
	private $original_image_source;

	/**
	 * @todo Add description
	 */
	public $src;

	/**
	 * The primary constructor function.  It sets up the environment and returns the class object
	 * 
	 * @param string $directory The base directory in which images are found - will soon be deprecated
	 * @param bool $create_new_directory Whether or not to create a new directory - will soon be deprecated
	 * @param object|array $opts The options array set by the user, or if none, defaults
	 * 
	 * @return self Returns the class object for contiuance
	 */
	public function __construct( $directory = null, $create_new_directory = true, $options = array() )
	{
		if ( is_null( $directory ) )
			$directory = dirname( dirname( __DIR__ ) );

		if( is_object( $options ) )
			$options = (array) $options;

		$defaults = array(
			'search_directory' => $directory,
			'quality' => 90,
			'directory' => 'compressed', // For backwards compatibility, but will soon be deprecated
			'directory_name' => 'compressed',
			'create_cached_directory' => true
		);

		$this->original_root = $directory;
		$this->options = array_merge( $defaults, $options );

		if( isset( $defaults['create_cached_directory'] ) && $defaults['create_cached_directory'] )
			return $this->createDirectory( $this->options['directory_name'] );

		if ( ! $create_new_directory )
			return $this;
		return $this->createDirectory();
	}

	/**
	 * Creates the directory in which the cached images will be stored
	 * 
	 * @return self Returns the class object for contiuance
	 */
	public function createDirectory( $directory_name = null )
	{
		if( ! $directory_name || is_null( $directory_name ) )
			$directory_name = $this->options['directory_name'];

		if( $this->created_dir && $this->cached_directory && is_dir( $this->cached_directory ) )
			return $this;

		$full_path = $this->original_root . '/' . $directory_name;
		if ( ! is_dir( $full_path ) ) {
			try {
				mkdir( $full_path, 0755 );
			} catch( \Exception $e ) {
				return $this->throwError( 'There was an error creating the new directory:', $e );
			}
		}
		$this->cached_directory = $full_path;
		$this->created_dir = true;
		return $this;
	}

	/**
	 * Reads the image and in turn compresses, relocations, and returns a cached copy
	 * 
	 * @param string $src Either a local image, with the relative or absolute directory path set during instatiation, or a URL
	 * 
	 * @return array Information on the newly compressed image, including the new source with modtime query, the height, and the width
	 */ 
	public function compress( $source )
	{
		// Set variables for this method
		$this->original_image_source = $source;
		$filename = basename( $source );
		$localfile = $this->cached_directory . '/' . $filename;

		// Check if the image is already downloaded and cached
		if( $this->isInDirectory( $localfile ) )
			return $this->outputSource( $this->makeSource( $localfile ), $this->getModTime( $localfile ) );

		// If the image is derived from a filepath, return the URL
		if( $this->isInDirectory( $source ) )
			$source = $this->makeSource( $source );

		if( $this->isURL( $source ) && ! $this->is404( $source ) ) {
			$file_resource = file_get_contents( $source );
			try {
				file_put_contents( $localfile, $file_resource );
			} catch( \Exception $e ) {
				return $this->throwError( 'There was an error downloading the image:', $e );
			}
		} else {
			return $this->show404();
		}
		if( ! $this->isInDirectory( $localfile ) )
			return $this->throwError( 'There was an error downloading the image.  Try again.' );

		$this->src = $this->makeSource( $localfile );
		$mime = $this->getMimeType( $localfile );
		try {
			$this->increaseMemoryLimit();
			switch( $mime ) {
				case 'image/jpeg' :
					$imageResource = imagecreatefromjpeg( $localfile );
				break;
				case 'image/png' :
					$imageResource = imagecreatefrompng( $localfile );
				break;
				case 'image/gif' :
					$imageResource = imagecreatefromgif( $localfile );
				break;
			}
			$this->resetMemoryLimit();
		} catch( \Exception $e ) {
			$this->throwError( 'There was an error processing your image.', $e );
		}
		imagejpeg( $imageResource, $localfile, $this->options['quality'] );
		return $this->outputSource( $this->makeSource( $localfile ), $this->getModTime( $localfile ) );
	}

	private function outputSource( $source, $modtime )
	{
		$outputSource = $source . '?' . $modtime;
		$this->src = $outputSource;
		$this->setHeaders();
		return $outputSource;
	}

	private function setHeaders()
	{
		$expiryDate = date( 'D, d M Y H:i:s e', strtotime() + ( 3600 * 24 * 30 ) );
		header( 'Cache-Control: cache, must-revalidate' );
		header( 'Expires: ' . $expiryDate );
		header( 'HTTP/1.0 304 Not Modified' );
		$GLOBALS['http_response_code'] = 304;
	}

	private function getModtime( $file )
	{
		if( ! $this->isInDirectory( $file ) )
			return null;
		return filemtime( $file );
	}

	/**
	 * Returns the filename basename without the extension, path, or URL
	 * 
	 * @param string $file The name of the file
	 * 
	 * @return string The name of the file sans extension
	 */
	private function getFilename( $file )
	{
		$pathinfo = pathinfo( $file );
		$filename = $pathinfo['filename'];
		return $filename;
	}

	private function isURL( $source )
	{
		if( filter_var( $source, FILTER_VALIDATE_URL ) )
			return true;
		return false;
	}

	private function isInDirectory( $source )
	{
		if( is_file( $source ) && file_exists( $source ) )
			return true;
		return false;
	}

	private function is404( $source )
	{
		$ch = curl_init();
		curl_setopt( $ch, CURLOPT_URL, $main_url );
		curl_setopt( $ch, CURLOPT_NOBODY, true );
		curl_exec( $ch );
		if( curl_getinfo( $ch, CURLINFO_HTTP_CODE ) == '404' )
			return $this->show404();
		return false;
	}

	private function show404()
	{
		return $this->src = 'http://placehold.it/500x300&text=Image Not Found';
	}

	/**
	 * Checks if the image is on the server currently being utilized
	 * 
	 * @param string $src 
	 * 
	 * @return bool Whether or not the image is local
	 */
	private function isLocal( $src )
	{
		$cururl = strtolower( reset( explode( '/', $_SERVER['SERVER_PROTOCOL'] ) ) ) . '://' . $_SERVER['SERVER_NAME'] . '/';
		if( strstr( $cururl, $src ) )
			return true;
		return false;
	}

	/**
	 * Creates an absolute URL based on the current protocol and location of the image on the server
	 * 
	 * @param string $dir 
	 * 
	 * @return string The 
	 */
	private function makeSource( $dir )
	{
		$protocol = $_SERVER[ 'SERVER_PROTOCOL' ];
		$protocol_array = explode( '/', $protocol );
		$host = $_SERVER[ 'SERVER_NAME' ];

		$current_url_tmp = reset( $protocol_array ) . '://' . $host;
		$current_url = strtolower( $current_url_tmp );

		$base = $_SERVER['DOCUMENT_ROOT'];
		if( $base == '/' ) {
			$localpath = substr( $dir, 1 );
		} else {
			$localpath = str_replace( $base, '', $dir );
		}
		return $current_url . $localpath;
	}

	private function increaseMemoryLimit()
	{
		if( isset( $this->pre_memory_limit ) )
			return;
		$memory_limit = ini_get( 'memory_limit' );
		$int_memory_limit = intval( $memory_limit );
		if( $int_memory_limit >= 128 )
			return;
		$this->pre_memory_limit = $int_memory_limit;
		ini_set( 'memory_limit', '128M' );
	}

	private function resetMemoryLimit()
	{
		if( ! isset( $this->pre_memory_limit ) )
			return;
		ini_set( 'memory_limit', $this->pre_memory_limit . 'M' );
	}

	private function getMimeType( $image )
	{
		$info = getimagesize( $image );
		return $info['mime'];
	}

	/**
	* A basic debug function for printing output - good if not using unit testing
	* 
	* @param mixed $a The input variable
	*/
	private function debug( $a )
	{
		echo '<pre>';
		print_r($a);
		echo '</pre><hr>';
	}

	/**
	 * Memory management function that releases an object's value
	 * 
	 * @param mixed $a Any input that is to be released
	 */
	private function release( $a )
	{
		if( ! $a || is_null( $a ) )
			return;
		foreach( $a as $b ) {
			unset( $b );
		}
		unset( $a );
	}

	private function throwError( $message = null, $error = null ) {
		if( is_null( $message ) )
			$message = 'Unknown Error:';
		echo $message . "\n";
		return $this->debug( $error );
	}
}