Completed
Push — master ( 02b07a...565813 )
by Sam
14:15
created

Thumbnail::getTemporaryDirectory()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 9
rs 9.6667
cc 2
eloc 5
nc 2
nop 0
1
<?php
2
3
/**
4
 * Represents a thumbnail. When used as a string the object will return the URL 
5
 * to a cached copy of the thumbnail if one exists, otherwise it will return 
6
 * the URL to ThumbnailController which generates the cached copy, thus the 
7
 * next time the thumbnail is rendered, the cached copy will be returned as the 
8
 * URL.
9
 *
10
 * @see ImageCache
11
 * @author Sam Stenvall <[email protected]>
12
 * @copyright Copyright &copy; Sam Stenvall 2013-
13
 * @license https://www.gnu.org/licenses/gpl.html The GNU General Public License v3.0
14
 */
15
class Thumbnail extends AbstractThumbnail
16
{
17
18
	const SIZE_VERY_SMALL = 70;
19
	const SIZE_SMALL = 116;
20
	const SIZE_MEDIUM = 160;
21
	const SIZE_LARGE = 434;
22
	
23
	/**
24
	 * Prefix used for storing temporary files
25
	 */
26
	const TEMP_FILE_PREFIX = 'xbmc-video-server-thumbnail';
27
	
28
	/**
29
	 * @var int the thumbnail size
30
	 */
31
	private $_size;
32
33
	/**
34
	 * @var ImageCache the cache
35
	 */
36
	private $_cache;
37
38
	/**
39
	 * Class constructor
40
	 * @param string $thumbnailPath the thumbnail path.
41
	 * @param int $size the thumbnail size. Defaults to SIZE_SMALL and can be 
42
	 * changed afterwards
43
	 */
44
	public function __construct($thumbnailPath, $size = self::SIZE_SMALL)
45
	{
46
		parent::__construct($thumbnailPath);
47
48
		$this->_size = $size;
49
		$this->_cache = new ImageCache();
50
	}
51
	
52
	/**
53
	 * Returns the absolute path to a cached thumbnail or false if no cached 
54
	 * copy exists
55
	 * @return string|false
56
	 */
57
	public function getPath()
58
	{
59
		$filename = $this->getFilename();
60
61
		if ($this->_cache->has($filename))
62
			return $this->_cache->getCachePath().DIRECTORY_SEPARATOR.$filename;
63
64
		return false;
65
	}
66
67
	/**
68
	 * Returns the URL to the thumbnail
69
	 * @return string
70
	 */
71
	public function getUrl()
72
	{
73
		$filename = $this->getFilename();
74
75
		if ($this->_cache->has($filename))
76
			return $this->_cache->getCacheUrl().'/'.$filename;
77
78
		// The image didn't exist in the cache
79
		return Yii::app()->controller->createUrl('thumbnail/generate', array(
80
					'path' => $this->_path,
81
					'size' => $this->_size));
82
	}
83
	
84
	/**
85
	 * @return string the URL to the original version of the image
86
	 */
87
	private function getOriginalUrl()
88
	{
89
		$response = Yii::app()->xbmc->performRequest('Files.PrepareDownload', array('path' => $this->_path));
90
91
		return Yii::app()->xbmc->getVFSHelper()->getUrl($response->result->details->path);
92
	}
93
	
94
	/**
95
	 * Generates and stores a cached copy of this thumbnail. It first retrieves 
96
	 * the original image to a temporary location for processing. This is done 
97
	 * because Kodi doesn't like the HTTP/1.0 requests that the built-in PHP 
98
	 * image manipulation functions (as well as file_get_contents()) use.
99
	 */
100
	public function generate()
101
	{
102
		// Create a HTTP/1.1 stream context
103
		$context = stream_context_create(array(
104
			'http' => array(
105
				'timeout' => Setting::getInteger('requestTimeout'),
106
				'protocol_version' => 1.1,
107
				'header' => 'Connection: close')));
108
109
		// Retrieve the image data and store it in a temporary file
110
		$imageData = file_get_contents($this->getOriginalUrl(), false, $context);
111
		$imageFile = tempnam(self::getTemporaryDirectory(), self::TEMP_FILE_PREFIX);
112
		
113
		if ($imageData === false || file_put_contents($imageFile, $imageData) === false)
114
			return;
115
		
116
		// Resize and cache the thumbnail
117
		$imagine = $this->imagineFactory();
118
119
		$imagine->open($imageFile)
120
				->thumbnail(new \Imagine\Image\Box($this->_size, PHP_INT_MAX))
121
				->save($this->_cache->getCachePath().DIRECTORY_SEPARATOR.
122
						$this->getFilename(), array('jpeg_quality' => 70));
123
124
		// Delete the temporary file
125
		unlink($imageFile);
126
	}
127
128
	/**
129
	 * Determines the filename to be used for the thumbnail
130
	 * @return string
131
	 */
132
	private function getFilename()
133
	{
134
		return md5($this->_path).'_'.$this->_size.'.jpg';
135
	}
136
	
137
	/**
138
	 * Returns the temporary directory where images should be stored for 
139
	 * processing. It will first try upload_tmp_dir and fall back to the 
140
	 * system default if that directive has not been set.
141
	 * @return string
142
	 */
143
	private static function getTemporaryDirectory()
144
	{
145
		$tempDir = ini_get('upload_tmp_dir');
146
147
		if ($tempDir === null)
148
			$tempDir = sys_get_temp_dir();
149
150
		return $tempDir;
151
	}
152
153
	/**
154
	 * Factory method for creating an Imagine instance
155
	 * @return \Imagine\Gd\Imagine|\Imagine\Imagick\Imagine
156
	 */
157
	private function imagineFactory()
158
	{
159
		// Try Imagick first, then fall back to GD. We have to check for
160
		// Imagick ourselves because Imagine is too stupid to do it correctly
161
		if (class_exists('Imagick', false))
162
			return new Imagine\Imagick\Imagine();
163
		else
164
			return new \Imagine\Gd\Imagine();
165
	}
166
167
}
168