1 <?php
2
3 4 5 6 7 8 9 10
11
12 13 14 15 16 17 18 19 20
21 class P3MediaImageAction extends CAction {
22
23 public function run() {
24 if (!isset(Yii::app()->image)) {
25 throw new CException("Application component 'image' not found.");
26 }
27
28 Yii::trace("Starting file image action ...", "p2.file");
29
30 if (isset($_GET['preset']) && isset($this->controller->module->params['presets'][$_GET['preset']])) {
31 $preset = new CMap($this->controller->module->params['presets'][$_GET['preset']]);
32 } else {
33 if (isset($_GET['preset'])) {
34 throw new Exception("Invalid preset '{$_GET['preset']}' specified!");
35 } else {
36 throw new Exception("No preset specified!");
37 }
38
39 }
40
41 if (is_numeric($_GET['id'])) {
42 $result = self::processMediaFile($_GET['id'], $preset);
43 switch ($result['type']) {
44 case 'public':
45 header('location: ' . $result['data']);
46 break;
47 case 'protected':
48 $model = self::findModel($_GET['id']);
49 self::sendImage($result['data'], $model, $preset);
50 break;
51 default:
52 self::sendErrorImage($preset);
53 }
54 } else {
55
56 self::sendErrorImage($preset);
57 }
58
59
60 }
61
62 63 64 65 66 67 68
69 public static function processMediaFile($id, $preset) {
70
71 Yii::trace('Processing media file #' . $id . ' ...', 'p2.file');
72
73
74 $model = self::findModel($id);
75 if (!$model)
76 return false;
77
78
79 $inFile = Yii::getPathOfAlias(Yii::app()->controller->module->dataAlias) . DIRECTORY_SEPARATOR . $model->path;
80 81 82 83 84
85
86 $path = self::prepareRenderPath($preset['savePublic']);
87
88 if (is_file($inFile)) {
89
90 $hash = self::generateHash($model, $preset);
91 $outFile = $path . DIRECTORY_SEPARATOR . $hash;
92
93 if ($preset['originalFile'] === true) {
94
95 if ($preset['savePublic'] === true) {
96 copy($inFile, $outFile);
97
98 $outUrl = str_replace(DIRECTORY_SEPARATOR, "/", $outFile);
99 header('location: '. str_replace(Yii::app()->basePath, Yii::app()->baseUrl, $outUrl));
100
101 } else {
102 self::sendImage($inFile, $model, $preset);
103 }
104 }
105
106
107 if (is_file($outFile)) {
108
109
110 } else {
111 Yii::log('Creating image from ' . $inFile, CLogger::LEVEL_INFO, 'p2.file');
112 if (!self::generateImage($inFile, $outFile, $preset)) {
113 Yii::log('Error while rendering ' . $inFile, CLogger::LEVEL_INFO, 'p2.file');
114
115 $mimeImageDir = Yii::getPathOfAlias('p3media.images.mimetypes');
116 $mimeImageFile = $mimeImageDir . DIRECTORY_SEPARATOR . CFileHelper::getMimeTypeByExtension($inFile) . '.png';
117
118
119 if (!is_file($mimeImageFile)) {
120 Yii::log('Missing mime type image ' . $mimeImageFile, CLogger::LEVEL_WARNING, 'p2.file');
121 $mimeImageFile = $mimeImageDir . DIRECTORY_SEPARATOR . "mime-empty.png";
122 }
123 self::generateImage($mimeImageFile, $outFile, $preset);
124 }
125 }
126 } else {
127 Yii::log("File #{$id} {$inFile} missing! [uniqid:" . uniqid() . "]", CLogger::LEVEL_WARNING, 'p2.file');
128 return false;
129 }
130
131 $info = getimagesize($outFile);
132
133
134 if ($preset['savePublic'] === true) {
135 return array(
136 'type' => 'public',
137 'data' => Yii::app()->baseUrl . Yii::app()->controller->module->params['publicRuntimeUrl'] . "/" . $hash,
138 'info' => $info);
139 } else {
140 return array(
141 'type' => 'protected',
142 'data' => $outFile,
143 'info' => $info);
144 }
145 }
146
147 private static function prepareRenderPath($public = false) {
148
149 if ($public === true) {
150 !empty(Yii::app()->controller->module->params['publicRuntimeAlias'])
151 ? $path = Yii::getPathOfAlias(Yii::app()->controller->module->params['publicRuntimeAlias'])
152 : $path = Yii::app()->basePath . DIRECTORY_SEPARATOR . Yii::app()->controller->module->params['publicRuntimePath'];
153 } else {
154 !empty(Yii::app()->controller->module->params['protectedRuntimeAlias'])
155 ? $path = Yii::getPathOfAlias(Yii::app()->controller->module->params['protectedRuntimeAlias'])
156 : $path = Yii::app()->basePath . DIRECTORY_SEPARATOR . Yii::app()->controller->module->params['protectedRuntimePath'];
157 }
158
159 if (!is_dir($path)) {
160 Yii::log('Creating render path in ' . $path, CLogger::LEVEL_INFO, 'p2.file');
161 if (!@mkdir($path, 0777, true)) {
162 throw new CException("Unable to create render path in '{$path}'");
163 }
164 }
165
166 if (!is_writable($path)) {
167 throw new Exception('Runtime data path ' . $path . ' not writable');
168 }
169
170 return $path;
171 }
172
173 private static function findModel($id) {
174 return P3Media::model()->with('metaData')->findByPk($id);
175 }
176
177 private static function generateHash($model, $preset) {
178 $pathInfo = pathinfo($model->path);
179 $hash = $model->title . "-" . substr(sha1($model->md5 . CJSON::encode($preset->toArray())), 0, 10) . "-" . $model->id;
180 if (isset($preset['type'])) {
181 $hash = $hash . '.' . $preset['type'];
182 } else {
183 $hash = $hash . '.' . $pathInfo['extension'];
184 }
185 return $hash;
186 }
187
188 private static function generateImage($src, $dest, $preset) {
189 try {
190 $image = Yii::app()->image->load($src);
191 } catch (Exception $e) {
192 Yii::log($e->getMessage() . ' ' . $src, CLogger::LEVEL_ERROR, "p2.file");
193 return false;
194 }
195 if (isset($preset['commands'])) {
196 $commands = $preset['commands'];
197 foreach ($commands as $command => $value) {
198 if ($command == 'savePublic') {
199 continue;
200 }
201 $count = count($value);
202 switch ($count) {
203 case '2':
204 $image->$command($value[0], $value[1]);
205 break;
206 case '3':
207 $image->$command($value[0], $value[1], $value[2]);
208 break;
209 case '4':
210 $image->$command($value[0], $value[1], $value[2], $value[3]);
211 break;
212 default:
213 $image->$command($value);
214 break;
215 }
216 }
217 }
218
219
220 try {
221 $image->save($dest);
222 return true;
223 } catch (Exception $e) {
224 Yii::log($e->getMessage(), CLogger::LEVEL_ERROR, "p2.file");
225 return false;
226 }
227 }
228
229 private static function sendImage($image, $model, $preset) {
230 $offset = 60 * 60 * 24 * 365;
231 header("Expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT");
232 header("Last-Modified: " . gmdate("D, d M Y H:i:s", filemtime($image)) . " GMT");
233 header("Content-Length: " . filesize($image) . "");
234
235 if ($preset['contentDisposition'] === 'attachment') {
236 header("Content-Disposition: attachment; filename=\"" . basename($model->title) . "\";\n\n");
237 } else {
238 header("Content-Disposition: inline; filename=\"" . basename($model->title) . "\";\n\n");
239 }
240
241 if ($preset['noCache'] === true) {
242 header("Cache-Control: no-store,max-age=0,must-revalidate");
243 header("Pragma: public");
244 header("Pragma: public_no_cache");
245 } else {
246 header('Cache-Control: max-age=0');
247 header("Pragma:");
248 }
249
250 if (function_exists("mime_content_type")) {
251 $mime = mime_content_type($image);
252 } else if (function_exists("finfo_open")) {
253
254 $finfo = finfo_open(FILEINFO_MIME);
255 $m = finfo_file($finfo, $image);
256 finfo_close($finfo);
257 } else {
258 $getimagesize = getimagesize($image);
259 $mime = $getimagesize['mime'];
260 }
261
262 header('Content-type: ' . $mime);
263 readfile($image);
264 }
265
266 private static function sendErrorImage($preset) {
267
268 header('Content-Type: png');
269 $path = self::prepareRenderPath($preset['savePublic']);
270 $outFile = $path . DIRECTORY_SEPARATOR . "missing-" . substr(sha1(serialize($preset)), 0, 10) . ".png";
271 self::generateImage(Yii::getPathOfAlias('p3media.images') . DIRECTORY_SEPARATOR . 'missing.png', $outFile, $preset);
272 readfile($outFile);
273
274
275 }
276
277 }
278
279 ?>
280