<?php
/**
 * 系统设置里不存在的多个图片服务器，请填写带HTTP://和图片存储路径的完成URL，结尾无斜线
 * 例如：$ALLOWED_SERVERS = array('http://img2.171u.com/image', 'http://171u.oss-cn-hangzhou.aliyuncs.com/image');
 */
$ALLOWED_SERVERS = array ();
// 最大占用内存限制
define ( 'MEMORY_LIMIT', '256M' );
// 默认关闭自定义参数
define( 'DEFAULT_CUSTOM', false );
// 原图宽高都小于缩略图宽高是是否输出原图，1输出原图，0，继续裁剪
define( 'DEFAULT_MINOUT', true );
// 图片默认质量
define( 'DEFAULT_Q', 90 );
// 默认缩放模式
define( 'DEFAULT_ZC', 3 );
// 默认裁剪位置
define( 'DEFAULT_CP', 'c' );
// 默认背景色
define( 'DEFAULT_BG', 'ffffff' );
// 默认PNG背景透明
define( 'DEFAULT_PT', 1 );

define( 'SAXUE_IN_MOBILE', false );
include "../core.php";
timthumb :: start();
class timthumb {
	protected $width = 0;
	protected $height = 0;
	protected $cutpos = DEFAULT_CP;
	protected $bgcolor = DEFAULT_BG;
	protected $pngtrans = DEFAULT_PT;
	protected $quality = DEFAULT_Q;
	protected $zoomcrop = DEFAULT_ZC;
	protected $thumbpath = '';
	protected $src = '';
	protected $localImage = '';
	protected $cached = false;
	protected $cacheurl = '';
	protected $cachefile = '';
	protected $isLocal = false;
	protected $servers = array();
	protected $toDeletes = array();
	protected $_image;
	protected $_imageType;
	protected $_width;
	protected $_height;

	public static function start() {
		$timthumb = new timthumb();
		$timthumb -> run();
		exit( 0 );
	} 
	public function run() {
		$this -> checkCache();
		if ( $this -> cached ) {
			$this -> showImage();
		} 
		if ( $this -> isLocal ) {
			$this -> thumbLocalImage();
		} else {
			$this -> thumbServerImage();
		} 
		if ( $this -> cached ) {
			$this -> showImage();
		} 
		$this -> saveImage();
		$this -> displayImage();
		return true;
	} 
	public function __construct() {
		global $ALLOWED_SERVERS;
		$this -> servers = $ALLOWED_SERVERS;
		if ( SAXUE_ATTACHS_URL != '' ) {
			$this -> servers[] = saxue_uploadurl( 'image' );
		} 
		if ( OSS_URL != '' ) {
			$this -> servers[] = OSS_URL . '/image';
		} 
		$this -> src = $this -> param( 'src' );
		$this -> src = str_ireplace( SAXUE_URL, '', $this -> src );
		$src = $this -> src;
		if ( substr( $src, 0, 1 ) === '/' ) {
			$this -> isLocal = true;
		} elseif ( preg_match( '/^https?:\/\/[^\/]+/i', $src ) ) {
			if ( count( $this -> servers ) > 0 ) {
				$src = str_ireplace( $this -> servers, '', $src );
			} 
			if ( substr( $src, 0, 1 ) !== '/' ) {
				$this -> cached = true;
				$this -> cacheurl = $this -> src;
				return false;
			} 
		} else {
			$this -> error( "Invalid URL supplied" );
			return false;
		} 
		if ( strlen( $src ) <= 3 ) {
			$this -> error( "No image specified" );
			return false;
		} 
		global $saxueTimthumb;
		saxue_getconfigs( 'timthumb' );
		$tim = $this -> param( 'tim' );
		if ( isset( $saxueTimthumb[$tim] ) ) {
			$this -> thumbpath = $tim;
			$this -> width = intval( $saxueTimthumb[$tim]['width'] );
			$this -> height = intval( $saxueTimthumb[$tim]['height'] );
			$this -> zoomcrop = intval( $saxueTimthumb[$tim]['zoomcrop'] );
			$this -> pngtrans = intval( $saxueTimthumb[$tim]['pngtrans'] );
			$this -> cutpos = $saxueTimthumb[$tim]['cutpos'];
			if ( !empty( $saxueTimthumb[$tim]['quality'] ) ) {
				$this -> quality = intval( $saxueTimthumb[$tim]['quality'] );
			} 
			if ( !empty( $saxueTimthumb[$tim]['bgcolor'] ) ) {
				$this -> bgcolor = $saxueTimthumb[$tim]['bgcolor'];
			} 
		} elseif ( DEFAULT_CUSTOM ) {
			$this -> width = ( int ) abs( $this -> param( 'w', 0 ) );
			$this -> height = ( int ) abs( $this -> param( 'h', 0 ) );
			$this -> quality = ( int ) abs( $this -> param( 'q', DEFAULT_Q ) );
			$this -> zoomcrop = ( int ) $this -> param( 'zc', DEFAULT_ZC );
			$this -> pngtrans = ( int ) $this -> param( 'pt', DEFAULT_PT );
			$this -> cutpos = $this -> param( 'cp', DEFAULT_CP );
			$this -> bgcolor = $this -> param( 'bg', DEFAULT_BG );
		} else {
			$this -> cached = true;
			$this -> cacheurl = $this -> src;
			return false;
		} 
		if ( !$this -> width && !$this -> height ) {
			$this -> cached = true;
			$this -> cacheurl = $this -> src;
			return false;
		} 
		return true;
	} 
	public function __destruct() {
		foreach( $this -> toDeletes as $del ) {
			@unlink( $del );
		} 
		$this -> destroy();
	} 
	protected function thumbServerImage() {
		$cacheDir = SAXUE_CACHE_PATH . '/timthumb';
		saxue_checkdir( $cacheDir, true );
		$tempfile = tempnam( $cacheDir, 'timthumb' );
		$this -> toDeletes[] = $tempfile;
		if ( !$this -> getServerImage( $this -> src, $tempfile ) ) {
			$this -> error( "Error reading the URL you specified from remote host" );
			return false;
		} 
		$this -> processImage( $tempfile );
		return true;
	} 
	protected function thumbLocalImage() {
		if ( !is_file( $this -> localImage ) ) {
			$this -> error( "localImage does not exist" );
			return false;
		} 
		$fileSize = filesize( $this -> localImage );
		if ( $fileSize <= 0 ) {
			$this -> error( "The file you specified is <= 0 bytes" );
			return false;
		} 
		$this -> processImage( $this -> localImage );
		return true;
	} 
	protected function getServerImage( $url, $tempfile ) {
		$url = preg_replace( '/ /', '%20', $url );
		if ( function_exists( 'curl_init' ) ) {
			$cp = curl_init( $url );
			$fp = fopen( $tempfile, "w" );
			curl_setopt( $cp, CURLOPT_FILE, $fp );
			curl_setopt( $cp, CURLOPT_HEADER, 0 );
			curl_exec( $cp );
			curl_close( $cp );
			fclose( $fp );
		} else {
			$img = @file_get_contents ( $url );
			if ( $img === false ) {
				return false;
			} 
			if ( ! file_put_contents( $tempfile, $img ) ) {
				$this -> error( "Could not write to $tempfile" );
				return false;
			} 
		} 
		if ( is_file( $tempfile ) ) {
			@chmod( $tempfile, 0644 );
			return true;
		} else {
			return false;
		} 
	} 
	protected function setMemoryLimit() {
		$inimem = ini_get( 'memory_limit' );
		$inibytes = timthumb :: returnBytes( $inimem );
		$ourbytes = timthumb :: returnBytes( MEMORY_LIMIT );
		if ( $inibytes < $ourbytes ) {
			ini_set ( 'memory_limit', MEMORY_LIMIT );
		} 
	} 
	protected static function returnBytes( $size_str ) {
		switch ( substr ( $size_str, -1 ) ) {
			case 'M': case 'm': return ( int )$size_str * 1048576;
			case 'K': case 'k': return ( int )$size_str * 1024;
			case 'G': case 'g': return ( int )$size_str * 1073741824;
			default: return $size_str;
		} 
	} 
	protected function openImage( $src ) {
		switch ( $this -> _imageType ) {
			case 'jpg':
				$this -> _image = imagecreatefromjpeg ( $src );
				break;
			case 'png':
				$this -> _image = imagecreatefrompng ( $src );
				imagealphablending( $this -> _image, true );
				imagesavealpha( $this -> _image, true );
				break;
			case 'gif':
				$this -> _image = imagecreatefromgif ( $src );
				break;
			default:
				return false;
		} 
		$this -> getxy();
		return $this -> _image;
	} 
	protected function getxy() {
		if ( is_resource( $this -> _image ) ) {
			$this -> _width = imagesx( $this -> _image );
			$this -> _height = imagesy( $this -> _image );
		} 
	} 
	protected function get_type( $mimeType ) {
		if ( preg_match( '/^image\/(?:jpg|jpeg)$/i', $mimeType ) ) {
			$this -> _imageType = 'jpg';
		} else if ( preg_match( '/^image\/png$/i', $mimeType ) ) {
			$this -> _imageType = 'png';
		} else if ( preg_match( '/^image\/gif$/i', $mimeType ) ) {
			$this -> _imageType = 'gif';
		} else {
			return false;
		} 
		return true;
	} 
	protected function processImage( $localImage ) {
		$img = getimagesize( $localImage ); 
		// generate new w/h if not provided
		$new_width = $this -> width;
		$new_height = $this -> height;
		if ( !$new_height ) {
			$new_height = floor ( $img[1] * ( $new_width / $img[0] ) );
		} else if ( !$new_width ) {
			$new_width = floor ( $img[0] * ( $new_height / $img[1] ) );
		} 
		if ( DEFAULT_MINOUT && $img[0] <= $new_width && $img[1] <= $new_height ) {
			$this -> cached = true;
			$this -> cacheurl = $this -> src;
			return false;
		} 
		// set image mimeType
		$origType = $img[2];
		if ( !$this -> get_type( $img['mime'] ) ) {
			$this -> error( "Could not match mime type after verifying it previously" );
		} 
		// open the existing image
		$this -> setMemoryLimit();
		if ( !$this -> openImage ( $localImage ) ) {
			$this -> error( "Unable to open image" );
		} 
		// Get original width and height
		$origin_x = 0;
		$origin_y = 0; 
		// scale down and add borders
		if ( $this -> zoomcrop == 3 ) {
			$final_height = $this -> _height * ( $new_width / $this -> _width );
			if ( $final_height > $new_height ) {
				$new_width = $this -> _width * ( $new_height / $this -> _height );
			} else {
				$new_height = $final_height;
			} 
		} 
		// create a new true color image
		$canvas = imagecreatetruecolor ( $new_width, $new_height );
		imagealphablending ( $canvas, false );
		$canvas_color_R = hexdec ( substr ( $this -> bgcolor, 0, 2 ) );
		$canvas_color_G = hexdec ( substr ( $this -> bgcolor, 2, 2 ) );
		$canvas_color_B = hexdec ( substr ( $this -> bgcolor, 4, 2 ) ); 
		// Create a new transparent color for image
		// If is a png and PNG_IS_TRANSPARENT is false then remove the alpha transparency
		// (and if is set a canvas color show it in the background)
		if ( $this -> _imageType == 'png' && $this -> pngtrans ) {
			$color = imagecolorallocatealpha ( $canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 127 );
		} else {
			$color = imagecolorallocatealpha ( $canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 0 );
		} 
		// Completely fill the background of the new image with allocated color.
		imagefill ( $canvas, 0, 0, $color ); 
		// Restore transparency blending
		imagesavealpha ( $canvas, true ); 
		// scale down and add borders
		if ( $this -> zoomcrop == 2 ) {
			$final_height = $this -> _height * ( $new_width / $this -> _width );
			if ( $final_height > $new_height ) {
				$origin_x = $new_width / 2;
				$new_width = $this -> _width * ( $new_height / $this -> _height );
				$origin_x = round ( $origin_x - ( $new_width / 2 ) );
			} else {
				$origin_y = $new_height / 2;
				$new_height = $final_height;
				$origin_y = round ( $origin_y - ( $new_height / 2 ) );
			} 
		} 
		if ( $this -> zoomcrop > 0 ) {
			$src_x = $src_y = 0;
			$src_w = $this -> _width;
			$src_h = $this -> _height;
			$cmp_x = $this -> _width / $new_width;
			$cmp_y = $this -> _height / $new_height; 
			// calculate x or y coordinate and width or height of source
			if ( $cmp_x > $cmp_y ) {
				$src_w = round ( $this -> _width / $cmp_x * $cmp_y );
				$src_x = round ( ( $this -> _width - ( $this -> _width / $cmp_x * $cmp_y ) ) / 2 );
			} else if ( $cmp_y > $cmp_x ) {
				$src_h = round ( $this -> _height / $cmp_y * $cmp_x );
				$src_y = round ( ( $this -> _height - ( $this -> _height / $cmp_y * $cmp_x ) ) / 2 );
			} 
			// positional cropping!
			if ( $this -> cutpos ) {
				if ( strpos ( $this -> cutpos, 't' ) !== false ) {
					$src_y = 0;
				} 
				if ( strpos ( $this -> cutpos, 'b' ) !== false ) {
					$src_y = $this -> _height - $src_h;
				} 
				if ( strpos ( $this -> cutpos, 'l' ) !== false ) {
					$src_x = 0;
				} 
				if ( strpos ( $this -> cutpos, 'r' ) !== false ) {
					$src_x = $this -> _width - $src_w;
				} 
			} 
			imagecopyresampled ( $canvas, $this -> _image, $origin_x, $origin_y, $src_x, $src_y, $new_width, $new_height, $src_w, $src_h );
		} else {
			// copy and resize part of an image with resampling
			imagecopyresampled ( $canvas, $this -> _image, 0, 0, 0, 0, $new_width, $new_height, $this -> _width, $this -> _height );
		} 
		// Straight from Wordpress core code. Reduces filesize by up to 70% for PNG's
		if ( ( IMAGETYPE_PNG == $origType || IMAGETYPE_GIF == $origType ) && function_exists( 'imageistruecolor' ) && !imageistruecolor( $this -> _image ) && imagecolortransparent( $this -> _image ) > 0 ) {
			imagetruecolortopalette( $canvas, false, imagecolorstotal( $this -> _image ) );
		} 
		$this -> destroy();
		$this -> _image = $canvas;
		$this -> getxy();
		return true;
	} 
	protected function showImage() {
		header( "location: " . $this -> cacheurl );
		exit( 0 );
	} 
	protected function displayImage( $destroy = true ) {
		if ( !is_resource( $this -> _image ) ) {
			return false;
		} 
		switch ( $this -> _imageType ) {
			case "jpg" :
				header( "Content-type: image/jpeg" );
				imagejpeg( $this -> _image, null, $this -> quality );
				break;
			case "png" :
				header( "Content-type: image/png" );
				imagepng( $this -> _image, null, floor( $this -> quality * 0.09 ) );
				break;
			case "gif" :
				header( "Content-type: image/gif" );
				imagegif( $this -> _image );
				break;
		} 
		if ( $destroy ) {
			$this -> destroy();
		} 
		exit( 0 );
	} 
	protected function saveImage( $destroy = false ) {
		if ( !is_resource( $this -> _image ) ) {
			return false;
		} 
		switch ( $this -> _imageType ) {
			case "jpg" :
				$ret = imagejpeg( $this -> _image, $this -> cachefile, $this -> quality );
				break;
			case "png" :
				$ret = imagepng( $this -> _image, $this -> cachefile, floor( $this -> quality * 0.09 ) );
				break;
			case "gif" :
				$ret = imagegif( $this -> _image, $this -> cachefile );
				break;
		} 
		if ( $destroy ) {
			$this -> destroy();
		} 
		return $ret;
	} 
	protected function destroy() {
		if ( is_resource( $this -> _image ) ) {
			imagedestroy( $this -> _image );
		} 
	} 
	protected function checkCache() {
		if ( $this -> cached ) {
			return true;
		} 
		$uploadurl = saxue_uploadurl( 'image' );
		if ( $this -> thumbpath == '' ) {
			$arr = $_GET;
			unset( $arr['src'] );
			unset( $arr['tim'] );
			ksort( $arr );
			$salt = md5( implode( '', $arr ) );
			$thumbpath = saxue_uploadpath( 'timthumb' ) . '/' . $salt;
			$thumburl = saxue_uploadurl( 'timthumb' ) . '/' . $salt;
		} else {
			$thumbpath = saxue_uploadpath( $this -> thumbpath );
			$thumburl = saxue_uploadurl( $this -> thumbpath );
		} 
		if ( $this -> isLocal ) {
			$this -> cachefile = str_ireplace( str_ireplace( SAXUE_URL, '', $uploadurl ), $thumbpath, $this -> src );
			$this -> cacheurl = str_ireplace( str_ireplace( SAXUE_URL, '', $uploadurl ), $thumburl, $this -> src );
			$this -> localImage = SAXUE_WEB_PATH . $this -> src;
		} else {
			foreach( $this -> servers as $server ) {
				if ( false !== stripos( $this -> src, $server ) ) {
					$this -> cachefile = str_ireplace( $server, $thumbpath, $this -> src );
					$this -> cacheurl = str_ireplace( $server, $thumburl, $this -> src );
					if ( $server == $uploadurl ) {
						$this -> localImage = str_ireplace( $server, saxue_uploadpath( 'image' ), $this -> src );
						if ( is_file( $this -> localImage ) ) {
							$this -> isLocal = true;
						} 
					} 
					break;
				} 
			} 
		} 
		if ( is_file( $this -> cachefile ) ) {
			$this -> cached = true;
		} else {
			saxue_checkdir( dirname( $this -> cachefile ), true );
		} 
		return true;
	} 
	protected function param( $property, $default = '' ) {
		if ( isset ( $_GET[$property] ) ) {
			return $_GET[$property];
		} else {
			return $default;
		} 
	} 
	protected function error( $err ) {
		header ( $_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request' );
		echo '<h1>A TimThumb error has occured:</h1>' . htmlentities( $err ) . '<br />';
		echo '<br />Query String : ' . htmlentities ( $_SERVER['QUERY_STRING'] );
		exit( 0 );
	} 
} 
