Passed
Push — 3.x ( 589a0f...691809 )
by Jerome
65:54 queued 11s
created

EntityIconService::generateIcon()   B

Complexity

Conditions 11
Paths 10

Size

Total Lines 66
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 11.727

Importance

Changes 0
Metric Value
cc 11
eloc 36
nc 10
nop 5
dl 0
loc 66
ccs 27
cts 33
cp 0.8182
crap 11.727
rs 7.3166
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Elgg;
4
5
use Elgg\Database\EntityTable;
6
use Elgg\Filesystem\MimeTypeDetector;
7
use Elgg\Http\Request as HttpRequest;
8
use ElggEntity;
9
use ElggFile;
10
use ElggIcon;
11
use InvalidParameterException;
12
use Psr\Log\LoggerInterface;
13
use Symfony\Component\HttpFoundation\BinaryFileResponse;
14
use Symfony\Component\HttpFoundation\Response;
15
16
/**
17
 * WARNING: API IN FLUX. DO NOT USE DIRECTLY.
18
 *
19
 * Use the elgg_* versions instead.
20
 *
21
 * @access private
22
 * @since 2.2
23
 */
24
class EntityIconService {
25
26
	use Loggable;
27
	use TimeUsing;
28
29
	/**
30
	 * @var Config
31
	 */
32
	private $config;
33
34
	/**
35
	 * @var PluginHooksService
36
	 */
37
	private $hooks;
38
39
	/**
40
	 * @var \Elgg\Http\Request
41
	 */
42
	private $request;
43
44
	/**
45
	 * @var EntityTable
46
	 */
47
	private $entities;
48
49
	/**
50
	 * @var UploadService
51
	 */
52
	private $uploads;
53
54
	/**
55
	 * @var ImageService
56
	 */
57
	private $images;
58
59
	/**
60
	 * Constructor
61
	 *
62
	 * @param Config             $config   Config
63
	 * @param PluginHooksService $hooks    Hook registration service
64
	 * @param HttpRequest        $request  Http request
65
	 * @param LoggerInterface    $logger   Logger
66
	 * @param EntityTable        $entities Entity table
67
	 * @param UploadService      $uploads  Upload service
68
	 * @param ImageService       $images   Image service
69
	 */
70 64
	public function __construct(
71
		Config $config,
72
		PluginHooksService $hooks,
73
		HttpRequest $request,
74
		LoggerInterface $logger,
75
		EntityTable $entities,
76
		UploadService $uploads,
77
		ImageService $images
78
	) {
79 64
		$this->config = $config;
80 64
		$this->hooks = $hooks;
81 64
		$this->request = $request;
82 64
		$this->logger = $logger;
83 64
		$this->entities = $entities;
84 64
		$this->uploads = $uploads;
85 64
		$this->images = $images;
86 64
	}
87
88
	/**
89
	 * Saves icons using an uploaded file as the source.
90
	 *
91
	 * @param ElggEntity $entity     Entity to own the icons
92
	 * @param string     $input_name Form input name
93
	 * @param string     $type       The name of the icon. e.g., 'icon', 'cover_photo'
94
	 * @param array      $coords     An array of cropping coordinates x1, y1, x2, y2
95
	 * @return bool
96
	 */
97 1
	public function saveIconFromUploadedFile(ElggEntity $entity, $input_name, $type = 'icon', array $coords = []) {
98 1
		$input = $this->uploads->getFile($input_name);
99 1
		if (empty($input)) {
100
			return false;
101
		}
102
				
103
		// auto detect cropping coordinates
104 1
		if (empty($coords)) {
105 1
			$auto_coords = $this->detectCroppingCoordinates();
106 1
			if (!empty($auto_coords)) {
107
				$coords = $auto_coords;
108
			}
109
		}
110
111 1
		$tmp = new \ElggTempFile();
112 1
		$tmp->setFilename(uniqid() . $input->getClientOriginalName());
113 1
		$tmp->open('write');
114 1
		$tmp->close();
115
		
116 1
		copy($input->getPathname(), $tmp->getFilenameOnFilestore());
117
118 1
		$tmp->mimetype = (new MimeTypeDetector())->getType($tmp->getFilenameOnFilestore(), $input->getClientMimeType());
119 1
		$tmp->simpletype = elgg_get_file_simple_type($tmp->mimetype);
120
121 1
		$result = $this->saveIcon($entity, $tmp, $type, $coords);
122
123 1
		$tmp->delete();
124
125 1
		return $result;
126
	}
127
128
	/**
129
	 * Saves icons using a local file as the source.
130
	 *
131
	 * @param ElggEntity $entity   Entity to own the icons
132
	 * @param string     $filename The full path to the local file
133
	 * @param string     $type     The name of the icon. e.g., 'icon', 'cover_photo'
134
	 * @param array      $coords   An array of cropping coordinates x1, y1, x2, y2
135
	 * @return bool
136
	 * @throws InvalidParameterException
137
	 */
138 5
	public function saveIconFromLocalFile(ElggEntity $entity, $filename, $type = 'icon', array $coords = []) {
139 5
		if (!file_exists($filename) || !is_readable($filename)) {
140 1
			throw new InvalidParameterException(__METHOD__ . " expects a readable local file. $filename is not readable");
141
		}
142
				
143 4
		$tmp = new \ElggTempFile();
144 4
		$tmp->setFilename(uniqid() . basename($filename));
145 4
		$tmp->open('write');
146 4
		$tmp->close();
147
		
148 4
		copy($filename, $tmp->getFilenameOnFilestore());
149
150 4
		$tmp->mimetype = (new MimeTypeDetector())->getType($tmp->getFilenameOnFilestore());
151 4
		$tmp->simpletype = elgg_get_file_simple_type($tmp->mimetype);
152
153 4
		$result = $this->saveIcon($entity, $tmp, $type, $coords);
154
155 4
		$tmp->delete();
156
157 4
		return $result;
158
	}
159
160
	/**
161
	 * Saves icons using a file located in the data store as the source.
162
	 *
163
	 * @param ElggEntity $entity Entity to own the icons
164
	 * @param ElggFile   $file   An ElggFile instance
165
	 * @param string     $type   The name of the icon. e.g., 'icon', 'cover_photo'
166
	 * @param array      $coords An array of cropping coordinates x1, y1, x2, y2
167
	 * @return bool
168
	 * @throws InvalidParameterException
169
	 */
170 41
	public function saveIconFromElggFile(ElggEntity $entity, ElggFile $file, $type = 'icon', array $coords = []) {
171 41
		if (!$file->exists()) {
172 1
			throw new InvalidParameterException(__METHOD__ . ' expects an instance of ElggFile with an existing file on filestore');
173
		}
174
		
175 40
		$tmp = new \ElggTempFile();
176 40
		$tmp->setFilename(uniqid() . basename($file->getFilenameOnFilestore()));
177 40
		$tmp->open('write');
178 40
		$tmp->close();
179
		
180 40
		copy($file->getFilenameOnFilestore(), $tmp->getFilenameOnFilestore());
181
182 40
		$tmp->mimetype = (new MimeTypeDetector())->getType($tmp->getFilenameOnFilestore(), $file->getMimeType());
183 40
		$tmp->simpletype = elgg_get_file_simple_type($tmp->mimetype);
184
185 40
		$result = $this->saveIcon($entity, $tmp, $type, $coords);
186
187 40
		$tmp->delete();
188
189 40
		return $result;
190
	}
191
192
	/**
193
	 * Saves icons using a created temporary file
194
	 *
195
	 * @param ElggEntity $entity Temporary ElggFile instance
196
	 * @param ElggFile   $file   Temporary ElggFile instance
197
	 * @param string     $type   The name of the icon. e.g., 'icon', 'cover_photo'
198
	 * @param array      $coords An array of cropping coordinates x1, y1, x2, y2
199
	 * @return bool
200
	 */
201 45
	public function saveIcon(ElggEntity $entity, ElggFile $file, $type = 'icon', array $coords = []) {
202
203 45
		$type = (string) $type;
204 45
		if (!strlen($type)) {
205
			$this->logger->error('Icon type passed to ' . __METHOD__ . ' can not be empty');
206
			return false;
207
		}
208
		
209 45
		$entity_type = $entity->getType();
210
		
211 45
		$file = $this->hooks->trigger("entity:$type:prepare", $entity_type, [
212 45
			'entity' => $entity,
213 45
			'file' => $file,
214 45
		], $file);
215
		
216 45
		if (!$file instanceof ElggFile || !$file->exists() || $file->getSimpleType() !== 'image') {
217
			$this->logger->error('Source file passed to ' . __METHOD__ . ' can not be resolved to a valid image');
218
			return false;
219
		}
220
		
221 45
		$this->prepareIcon($file->getFilenameOnFilestore());
222
		
223 45
		$x1 = (int) elgg_extract('x1', $coords);
224 45
		$y1 = (int) elgg_extract('y1', $coords);
225 45
		$x2 = (int) elgg_extract('x2', $coords);
226 45
		$y2 = (int) elgg_extract('y2', $coords);
227
		
228 45
		$created = $this->hooks->trigger("entity:$type:save", $entity_type, [
229 45
			'entity' => $entity,
230 45
			'file' => $file,
231 45
			'x1' => $x1,
232 45
			'y1' => $y1,
233 45
			'x2' => $x2,
234 45
			'y2' => $y2,
235 45
		], false);
236
237
		// did someone else handle saving the icon?
238 45
		if ($created !== true) {
239
			// remove existing icons
240 44
			$this->deleteIcon($entity, $type, true);
241
			
242
			// save master image
243 44
			$store = $this->generateIcon($entity, $file, $type, $coords, 'master');
244
			
245 44
			if (!$store) {
246
				$this->deleteIcon($entity, $type);
247
				return false;
248
			}
249
		}
250
251 45
		if ($type == 'icon') {
252 44
			$entity->icontime = time();
253 44
			if ($x1 || $y1 || $x2 || $y2) {
254 7
				$entity->x1 = $x1;
255 7
				$entity->y1 = $y1;
256 7
				$entity->x2 = $x2;
257 44
				$entity->y2 = $y2;
258
			}
259
		} else {
260 1
			if ($x1 || $y1 || $x2 || $y2) {
261 1
				$entity->{"{$type}_coords"} = serialize([
262 1
					'x1' => $x1,
263 1
					'y1' => $y1,
264 1
					'x2' => $x2,
265 1
					'y2' => $y2,
266
				]);
267
			}
268
		}
269
		
270 45
		$this->hooks->trigger("entity:$type:saved", $entity->getType(), [
271 45
			'entity' => $entity,
272 45
			'x1' => $x1,
273 45
			'y1' => $y1,
274 45
			'x2' => $x2,
275 45
			'y2' => $y2,
276
		]);
277
		
278 45
		return true;
279
	}
280
	
281
	/**
282
	 * Prepares an icon
283
	 *
284
	 * @param string $filename the file to prepare
285
	 *
286
	 * @return void
287
	 */
288 45
	protected function prepareIcon($filename) {
289
		
290
		// fix orientation
291 45
		$temp_file = new \ElggTempFile();
292 45
		$temp_file->setFilename(uniqid() . basename($filename));
293
		
294 45
		copy($filename, $temp_file->getFilenameOnFilestore());
295
		
296 45
		$rotated = $this->images->fixOrientation($temp_file->getFilenameOnFilestore());
297
298 45
		if ($rotated) {
299 45
			copy($temp_file->getFilenameOnFilestore(), $filename);
300
		}
301
		
302 45
		$temp_file->delete();
303 45
	}
304
	
305
	/**
306
	 * Generate an icon for the given entity
307
	 *
308
	 * @param ElggEntity $entity    Temporary ElggFile instance
309
	 * @param ElggFile   $file      Temporary ElggFile instance
310
	 * @param string     $type      The name of the icon. e.g., 'icon', 'cover_photo'
311
	 * @param array      $coords    An array of cropping coordinates x1, y1, x2, y2
312
	 * @param string     $icon_size The icon size to generate (leave empty to generate all supported sizes)
313
	 *
314
	 * @return bool
315
	 */
316 44
	protected function generateIcon(ElggEntity $entity, ElggFile $file, $type = 'icon', $coords = [], $icon_size = '') {
317
		
318 44
		if (!$file->exists()) {
319
			$this->logger->error('Trying to generate an icon from a non-existing file');
320
			return false;
321
		}
322
		
323 44
		$x1 = (int) elgg_extract('x1', $coords);
324 44
		$y1 = (int) elgg_extract('y1', $coords);
325 44
		$x2 = (int) elgg_extract('x2', $coords);
326 44
		$y2 = (int) elgg_extract('y2', $coords);
327
		
328 44
		$sizes = $this->getSizes($entity->getType(), $entity->getSubtype(), $type);
329
		
330 44
		if (!empty($icon_size) && !isset($sizes[$icon_size])) {
331
			$this->logger->warning("The provided icon size '{$icon_size}' doesn't exist for icon type '{$type}'");
332
			return false;
333
		}
334
		
335 44
		foreach ($sizes as $size => $opts) {
336 44
			if (!empty($icon_size) && ($icon_size !== $size)) {
337
				// only generate the given icon size
338 44
				continue;
339
			}
340
			
341
			// check if the icon config allows cropping
342 44
			if (!(bool) elgg_extract('crop', $opts, true)) {
343
				$coords = [
344 44
					'x1' => 0,
345
					'y1' => 0,
346
					'x2' => 0,
347
					'y2' => 0,
348
				];
349
			}
350
351 44
			$icon = $this->getIcon($entity, $size, $type, false);
352
353
			// We need to make sure that file path is readable by
354
			// Imagine\Image\ImagineInterface::save(), as it fails to
355
			// build the directory structure on owner's filestore otherwise
356 44
			$icon->open('write');
357 44
			$icon->close();
358
			
359
			// Save the image without resizing or cropping if the
360
			// image size value is an empty array
361 44
			if (is_array($opts) && empty($opts)) {
362 1
				copy($file->getFilenameOnFilestore(), $icon->getFilenameOnFilestore());
363 1
				continue;
364
			}
365
366 44
			$source = $file->getFilenameOnFilestore();
367 44
			$destination = $icon->getFilenameOnFilestore();
368
369 44
			$resize_params = array_merge($opts, $coords);
370
371 44
			$image_service = _elgg_services()->imageService;
372 44
			$image_service->setLogger($this->logger);
373
374 44
			if (!_elgg_services()->imageService->resize($source, $destination, $resize_params)) {
375
				$this->logger->error("Failed to create {$size} icon from
376
					{$file->getFilenameOnFilestore()} with coords [{$x1}, {$y1}],[{$x2}, {$y2}]");
377 44
				return false;
378
			}
379
		}
380
381 44
		return true;
382
	}
383
384
	/**
385
	 * Returns entity icon as an ElggIcon object
386
	 * The icon file may or may not exist on filestore
387
	 *
388
	 * @note Returned ElggIcon object may be a placeholder. Use ElggIcon::exists() to validate if file has been written to filestore
389
	 *
390
	 * @param ElggEntity $entity   Entity that owns the icon
391
	 * @param string     $size     Size of the icon
392
	 * @param string     $type     The name of the icon. e.g., 'icon', 'cover_photo'
393
	 * @param bool       $generate Try to generate an icon based on master if size doesn't exists
394
	 *
395
	 * @return ElggIcon
396
	 *
397
	 * @throws InvalidParameterException
398
	 */
399 66
	public function getIcon(ElggEntity $entity, $size, $type = 'icon', $generate = true) {
400
401 66
		$size = elgg_strtolower($size);
402
403
		$params = [
404 66
			'entity' => $entity,
405 66
			'size' => $size,
406 66
			'type' => $type,
407
		];
408
409 66
		$entity_type = $entity->getType();
410
411 66
		$default_icon = new ElggIcon();
412 66
		$default_icon->owner_guid = $entity->guid;
413 66
		$default_icon->setFilename("icons/$type/$size.jpg");
414
415 66
		$icon = $this->hooks->trigger("entity:$type:file", $entity_type, $params, $default_icon);
416 66
		if (!$icon instanceof ElggIcon) {
417 1
			throw new InvalidParameterException("'entity:$type:file', $entity_type hook must return an instance of ElggIcon");
418
		}
419
		
420 65
		if ($icon->exists() || !$generate) {
421 64
			return $icon;
422
		}
423
		
424 58
		if ($size === 'master') {
425
			// don't try to generate for master
426 10
			return $icon;
427
		}
428
		
429
		// try to generate icon based on master size
430 57
		$master_icon = $this->getIcon($entity, 'master', $type, false);
431 57
		if (!$master_icon->exists()) {
432 21
			return $icon;
433
		}
434
		
435 37
		if ($type === 'icon') {
436
			$coords = [
437 36
				'x1' => $entity->x1,
438 36
				'y1' => $entity->y1,
439 36
				'x2' => $entity->x2,
440 36
				'y2' => $entity->y2,
441
			];
442
		} else {
443 1
			$coords = $entity->{"{$type}_coords"};
444 1
			$coords = empty($coords) ? [] : unserialize($coords);
445
		}
446
		
447 37
		$this->generateIcon($entity, $master_icon, $type, $coords, $size);
448
		
449 37
		return $icon;
450
	}
451
452
	/**
453
	 * Removes all icon files and metadata for the passed type of icon.
454
	 *
455
	 * @param ElggEntity $entity        Entity that owns icons
456
	 * @param string     $type          The name of the icon. e.g., 'icon', 'cover_photo'
457
	 * @param bool       $retain_master Keep the master icon (default: false)
458
	 *
459
	 * @return bool
460
	 */
461 45
	public function deleteIcon(ElggEntity $entity, $type = 'icon', $retain_master = false) {
462 45
		$delete = $this->hooks->trigger("entity:$type:delete", $entity->getType(), [
463 45
			'entity' => $entity,
464 45
		], true);
465
466 45
		if ($delete === false) {
467 1
			return false;
468
		}
469
		
470 44
		$result = true;
471
472 44
		$sizes = array_keys($this->getSizes($entity->getType(), $entity->getSubtype(), $type));
473 44
		foreach ($sizes as $size) {
474 44
			if ($size === 'master' && $retain_master) {
475 43
				continue;
476
			}
477
			
478 44
			$icon = $this->getIcon($entity, $size, $type, false);
479 44
			$result &= $icon->delete();
480
		}
481
482 44
		if ($type == 'icon') {
483 43
			unset($entity->icontime);
484 43
			unset($entity->x1);
485 43
			unset($entity->y1);
486 43
			unset($entity->x2);
487 43
			unset($entity->y2);
488
		} else {
489 1
			unset($entity->{"{$type}_coords"});
490
		}
491
		
492 44
		return $result;
493
	}
494
495
	/**
496
	 * Get the URL for this entity's icon
497
	 *
498
	 * Plugins can register for the 'entity:icon:url', <type> plugin hook to customize the icon for an entity.
499
	 *
500
	 * @param ElggEntity $entity Entity that owns the icon
501
	 * @param mixed      $params A string defining the size of the icon (e.g. tiny, small, medium, large)
502
	 *                           or an array of parameters including 'size'
503
	 * @return string|void
504
	 */
505 9
	public function getIconURL(ElggEntity $entity, $params = []) {
506 9
		if (is_array($params)) {
507 1
			$size = elgg_extract('size', $params, 'medium');
508
		} else {
509 9
			$size = is_string($params) ? $params : 'medium';
510 9
			$params = [];
511
		}
512
513 9
		$size = elgg_strtolower($size);
514
515 9
		$params['entity'] = $entity;
516 9
		$params['size'] = $size;
517
518 9
		$type = elgg_extract('type', $params) ? : 'icon';
519 9
		$entity_type = $entity->getType();
520
521 9
		$url = $this->hooks->trigger("entity:$type:url", $entity_type, $params, null);
522 9
		if ($url == null) {
523 7
			if ($this->hasIcon($entity, $size, $type)) {
524 1
				$icon = $this->getIcon($entity, $size, $type);
525 1
				$default_use_cookie = (bool) elgg_get_config('session_bound_entity_icons', false);
526 1
				$url = $icon->getInlineURL((bool) elgg_extract('use_cookie', $params, $default_use_cookie));
527
			} else {
528 6
				$url = $this->getFallbackIconUrl($entity, $params);
529
			}
530
		}
531
532 9
		if ($url) {
533 4
			return elgg_normalize_url($url);
534
		}
535 5
	}
536
537
	/**
538
	 * Returns default/fallback icon
539
	 *
540
	 * @param ElggEntity $entity Entity
541
	 * @param array      $params Icon params
542
	 * @return string
543
	 */
544 6
	public function getFallbackIconUrl(ElggEntity $entity, array $params = []) {
545
546 6
		$type = elgg_extract('type', $params) ? : 'icon';
547 6
		$size = elgg_extract('size', $params) ? : 'medium';
548
		
549 6
		$entity_type = $entity->getType();
550 6
		$entity_subtype = $entity->getSubtype();
551
552 6
		$exts = ['svg', 'gif', 'png', 'jpg'];
553
554 6
		foreach ($exts as $ext) {
555 6
			foreach ([$entity_subtype, 'default'] as $subtype) {
556 6
				if ($ext == 'svg' && elgg_view_exists("$type/$entity_type/$subtype.svg")) {
557
					return elgg_get_simplecache_url("$type/$entity_type/$subtype.svg");
558
				}
559 6
				if (elgg_view_exists("$type/$entity_type/$subtype/$size.$ext")) {
560 6
					return elgg_get_simplecache_url("$type/$entity_type/$subtype/$size.$ext");
561
				}
562
			}
563
		}
564
565 5
		if (elgg_view_exists("$type/default/$size.png")) {
566
			return elgg_get_simplecache_url("$type/default/$size.png");
567
		}
568 5
	}
569
570
	/**
571
	 * Returns the timestamp of when the icon was changed.
572
	 *
573
	 * @param ElggEntity $entity Entity that owns the icon
574
	 * @param string     $size   The size of the icon
575
	 * @param string     $type   The name of the icon. e.g., 'icon', 'cover_photo'
576
	 *
577
	 * @return int|null A unix timestamp of when the icon was last changed, or null if not set.
578
	 */
579 1
	public function getIconLastChange(ElggEntity $entity, $size, $type = 'icon') {
580 1
		$icon = $this->getIcon($entity, $size, $type);
581 1
		if ($icon->exists()) {
582 1
			return $icon->getModifiedTime();
583
		}
584
	}
585
586
	/**
587
	 * Returns if the entity has an icon of the passed type.
588
	 *
589
	 * @param ElggEntity $entity Entity that owns the icon
590
	 * @param string     $size   The size of the icon
591
	 * @param string     $type   The name of the icon. e.g., 'icon', 'cover_photo'
592
	 * @return bool
593
	 */
594 23
	public function hasIcon(\ElggEntity $entity, $size, $type = 'icon') {
595 23
		return $this->getIcon($entity, $size, $type)->exists();
596
	}
597
598
	/**
599
	 * Returns a configuration array of icon sizes
600
	 *
601
	 * @param string $entity_type    Entity type
602
	 * @param string $entity_subtype Entity subtype
603
	 * @param string $type           The name of the icon. e.g., 'icon', 'cover_photo'
604
	 * @return array
605
	 * @throws InvalidParameterException
606
	 */
607 57
	public function getSizes($entity_type = null, $entity_subtype = null, $type = 'icon') {
608 57
		$sizes = [];
609 57
		if (!$type) {
610
			$type = 'icon';
611
		}
612 57
		if ($type == 'icon') {
613 55
			$sizes = $this->config->icon_sizes;
614
		}
615
		$params = [
616 57
			'type' => $type,
617 57
			'entity_type' => $entity_type,
618 57
			'entity_subtype' => $entity_subtype,
619
		];
620 57
		if ($entity_type) {
621 56
			$sizes = $this->hooks->trigger("entity:$type:sizes", $entity_type, $params, $sizes);
622
		}
623
624 57
		if (!is_array($sizes)) {
625
			throw new InvalidParameterException("The icon size configuration for image type '$type' " .
626
				"must be an associative array of image size names and their properties");
627
		}
628
629
		// lazy generation of icons requires a 'master' size
630
		// this ensures a default config for 'master' size
631 57
		$sizes['master'] = elgg_extract('master', $sizes, [
632 57
			'w' => 10240,
633
			'h' => 10240,
634
			'square' => false,
635
			'upscale' => false,
636
			'crop' => false,
637
		]);
638
		
639 57
		if (!isset($sizes['master']['crop'])) {
640
			$sizes['master']['crop'] = false;
641
		}
642
		
643 57
		return $sizes;
644
	}
645
646
	/**
647
	 * Handle request to /serve-icon handler
648
	 *
649
	 * @param bool $allow_removing_headers Alter PHP's global headers to allow caching
650
	 * @return BinaryFileResponse
651
	 */
652 3
	public function handleServeIconRequest($allow_removing_headers = true) {
653
654 3
		$response = new Response();
655 3
		$response->setExpires($this->getCurrentTime('-1 day'));
656 3
		$response->prepare($this->request);
657
658 3
		if ($allow_removing_headers) {
659
			// clear cache-boosting headers set by PHP session
660
			header_remove('Cache-Control');
661
			header_remove('Pragma');
662
			header_remove('Expires');
663
		}
664
665 3
		$path = implode('/', $this->request->getUrlSegments());
666 3
		if (!preg_match('~serve-icon/(\d+)/(.*+)$~', $path, $m)) {
667 1
			return $response->setStatusCode(400)->setContent('Malformatted request URL');
668
		}
669
670 2
		list(, $guid, $size) = $m;
671
672 2
		$entity = $this->entities->get($guid);
673 2
		if (!$entity instanceof \ElggEntity) {
674 1
			return $response->setStatusCode(404)->setContent('Item does not exist');
675
		}
676
677 1
		$thumbnail = $entity->getIcon($size);
678 1
		if (!$thumbnail->exists()) {
679
			return $response->setStatusCode(404)->setContent('Icon does not exist');
680
		}
681
682 1
		$if_none_match = $this->request->headers->get('if_none_match');
683 1
		if (!empty($if_none_match)) {
684
			// strip mod_deflate suffixes
685 1
			$this->request->headers->set('if_none_match', str_replace('-gzip', '', $if_none_match));
686
		}
687
688 1
		$filenameonfilestore = $thumbnail->getFilenameOnFilestore();
689 1
		$last_updated = filemtime($filenameonfilestore);
690 1
		$etag = '"' . $last_updated . '"';
691
692 1
		$response->setPrivate()
693 1
			->setEtag($etag)
694 1
			->setExpires($this->getCurrentTime('+1 day'))
695 1
			->setMaxAge(86400);
696
697 1
		if ($response->isNotModified($this->request)) {
698 1
			return $response;
699
		}
700
701
		$headers = [
702 1
			'Content-Type' => (new MimeTypeDetector())->getType($filenameonfilestore),
703
		];
704 1
		$response = new BinaryFileResponse($filenameonfilestore, 200, $headers, false, 'inline');
705 1
		$response->prepare($this->request);
706
707 1
		$response->setPrivate()
708 1
			->setEtag($etag)
709 1
			->setExpires($this->getCurrentTime('+1 day'))
710 1
			->setMaxAge(86400);
711
712 1
		return $response;
713
	}
714
	
715
	/**
716
	 * Automagicly detect cropping coordinates
717
	 *
718
	 * Based in the input names x1, x2, y1 and y2
719
	 *
720
	 * @return false|array
721
	 */
722 6
	protected function detectCroppingCoordinates() {
723
		
724
		$auto_coords = [
725 6
			'x1' => get_input('x1'),
726 6
			'x2' => get_input('x2'),
727 6
			'y1' => get_input('y1'),
728 6
			'y2' => get_input('y2'),
729
		];
730
		
731 6
		$auto_coords = array_filter($auto_coords, function($value) {
732 6
			return !elgg_is_empty($value) && is_numeric($value);
733 6
		});
734
		
735 6
		if (count($auto_coords) !== 4) {
736 4
			return false;
737
		}
738
		
739
		// make ints
740 2
		array_walk($auto_coords, function (&$value) {
741 2
			$value = (int) $value;
742 2
		});
743
		
744 2
		return $auto_coords;
745
	}
746
747
}
748