Passed
Push — master ( 342765...ba14c4 )
by Blizzz
13:12 queued 11s
created
lib/private/Avatar/UserAvatar.php 1 patch
Indentation   +291 added lines, -291 removed lines patch added patch discarded remove patch
@@ -44,295 +44,295 @@
 block discarded – undo
44 44
  * This class represents a registered user's avatar.
45 45
  */
46 46
 class UserAvatar extends Avatar {
47
-	/** @var IConfig */
48
-	private $config;
49
-
50
-	/** @var ISimpleFolder */
51
-	private $folder;
52
-
53
-	/** @var IL10N */
54
-	private $l;
55
-
56
-	/** @var User */
57
-	private $user;
58
-
59
-	/**
60
-	 * UserAvatar constructor.
61
-	 *
62
-	 * @param IConfig $config The configuration
63
-	 * @param ISimpleFolder $folder The avatar files folder
64
-	 * @param IL10N $l The localization helper
65
-	 * @param User $user The user this class manages the avatar for
66
-	 * @param ILogger $logger The logger
67
-	 */
68
-	public function __construct(
69
-		ISimpleFolder $folder,
70
-		IL10N $l,
71
-		$user,
72
-		ILogger $logger,
73
-		IConfig $config) {
74
-		parent::__construct($logger);
75
-		$this->folder = $folder;
76
-		$this->l = $l;
77
-		$this->user = $user;
78
-		$this->config = $config;
79
-	}
80
-
81
-	/**
82
-	 * Check if an avatar exists for the user
83
-	 *
84
-	 * @return bool
85
-	 */
86
-	public function exists() {
87
-		return $this->folder->fileExists('avatar.jpg') || $this->folder->fileExists('avatar.png');
88
-	}
89
-
90
-	/**
91
-	 * Sets the users avatar.
92
-	 *
93
-	 * @param IImage|resource|string $data An image object, imagedata or path to set a new avatar
94
-	 * @throws \Exception if the provided file is not a jpg or png image
95
-	 * @throws \Exception if the provided image is not valid
96
-	 * @throws NotSquareException if the image is not square
97
-	 * @return void
98
-	 */
99
-	public function set($data) {
100
-		$img = $this->getAvatarImage($data);
101
-		$data = $img->data();
102
-
103
-		$this->validateAvatar($img);
104
-
105
-		$this->remove(true);
106
-		$type = $this->getAvatarImageType($img);
107
-		$file = $this->folder->newFile('avatar.' . $type);
108
-		$file->putContent($data);
109
-
110
-		try {
111
-			$generated = $this->folder->getFile('generated');
112
-			$generated->delete();
113
-		} catch (NotFoundException $e) {
114
-			//
115
-		}
116
-
117
-		$this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'false');
118
-		$this->user->triggerChange('avatar', $file);
119
-	}
120
-
121
-	/**
122
-	 * Returns an image from several sources.
123
-	 *
124
-	 * @param IImage|resource|string $data An image object, imagedata or path to the avatar
125
-	 * @return IImage
126
-	 */
127
-	private function getAvatarImage($data) {
128
-		if ($data instanceof IImage) {
129
-			return $data;
130
-		}
131
-
132
-		$img = new OC_Image();
133
-		if (is_resource($data) && get_resource_type($data) === 'gd') {
134
-			$img->setResource($data);
135
-		} elseif (is_resource($data)) {
136
-			$img->loadFromFileHandle($data);
137
-		} else {
138
-			try {
139
-				// detect if it is a path or maybe the images as string
140
-				$result = @realpath($data);
141
-				if ($result === false || $result === null) {
142
-					$img->loadFromData($data);
143
-				} else {
144
-					$img->loadFromFile($data);
145
-				}
146
-			} catch (\Error $e) {
147
-				$img->loadFromData($data);
148
-			}
149
-		}
150
-
151
-		return $img;
152
-	}
153
-
154
-	/**
155
-	 * Returns the avatar image type.
156
-	 *
157
-	 * @param IImage $avatar
158
-	 * @return string
159
-	 */
160
-	private function getAvatarImageType(IImage $avatar) {
161
-		$type = substr($avatar->mimeType(), -3);
162
-		if ($type === 'peg') {
163
-			$type = 'jpg';
164
-		}
165
-		return $type;
166
-	}
167
-
168
-	/**
169
-	 * Validates an avatar image:
170
-	 * - must be "png" or "jpg"
171
-	 * - must be "valid"
172
-	 * - must be in square format
173
-	 *
174
-	 * @param IImage $avatar The avatar to validate
175
-	 * @throws \Exception if the provided file is not a jpg or png image
176
-	 * @throws \Exception if the provided image is not valid
177
-	 * @throws NotSquareException if the image is not square
178
-	 */
179
-	private function validateAvatar(IImage $avatar) {
180
-		$type = $this->getAvatarImageType($avatar);
181
-
182
-		if ($type !== 'jpg' && $type !== 'png') {
183
-			throw new \Exception($this->l->t('Unknown filetype'));
184
-		}
185
-
186
-		if (!$avatar->valid()) {
187
-			throw new \Exception($this->l->t('Invalid image'));
188
-		}
189
-
190
-		if (!($avatar->height() === $avatar->width())) {
191
-			throw new NotSquareException($this->l->t('Avatar image is not square'));
192
-		}
193
-	}
194
-
195
-	/**
196
-	 * Removes the users avatar.
197
-	 * @return void
198
-	 * @throws \OCP\Files\NotPermittedException
199
-	 * @throws \OCP\PreConditionNotMetException
200
-	 */
201
-	public function remove(bool $silent = false) {
202
-		$avatars = $this->folder->getDirectoryListing();
203
-
204
-		$this->config->setUserValue($this->user->getUID(), 'avatar', 'version',
205
-			(int) $this->config->getUserValue($this->user->getUID(), 'avatar', 'version', 0) + 1);
206
-
207
-		foreach ($avatars as $avatar) {
208
-			$avatar->delete();
209
-		}
210
-		$this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'true');
211
-		if(!$silent) {
212
-			$this->user->triggerChange('avatar', '');
213
-		}
214
-	}
215
-
216
-	/**
217
-	 * Get the extension of the avatar. If there is no avatar throw Exception
218
-	 *
219
-	 * @return string
220
-	 * @throws NotFoundException
221
-	 */
222
-	private function getExtension() {
223
-		if ($this->folder->fileExists('avatar.jpg')) {
224
-			return 'jpg';
225
-		} elseif ($this->folder->fileExists('avatar.png')) {
226
-			return 'png';
227
-		}
228
-		throw new NotFoundException;
229
-	}
230
-
231
-	/**
232
-	 * Returns the avatar for an user.
233
-	 *
234
-	 * If there is no avatar file yet, one is generated.
235
-	 *
236
-	 * @param int $size
237
-	 * @return ISimpleFile
238
-	 * @throws NotFoundException
239
-	 * @throws \OCP\Files\NotPermittedException
240
-	 * @throws \OCP\PreConditionNotMetException
241
-	 */
242
-	public function getFile($size) {
243
-		$size = (int) $size;
244
-
245
-		try {
246
-			$ext = $this->getExtension();
247
-		} catch (NotFoundException $e) {
248
-			if (!$data = $this->generateAvatarFromSvg(1024)) {
249
-				$data = $this->generateAvatar($this->getDisplayName(), 1024);
250
-			}
251
-			$avatar = $this->folder->newFile('avatar.png');
252
-			$avatar->putContent($data);
253
-			$ext = 'png';
254
-
255
-			$this->folder->newFile('generated', '');
256
-			$this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'true');
257
-		}
258
-
259
-		if ($size === -1) {
260
-			$path = 'avatar.' . $ext;
261
-		} else {
262
-			$path = 'avatar.' . $size . '.' . $ext;
263
-		}
264
-
265
-		try {
266
-			$file = $this->folder->getFile($path);
267
-		} catch (NotFoundException $e) {
268
-			if ($size <= 0) {
269
-				throw new NotFoundException;
270
-			}
271
-
272
-			if ($this->folder->fileExists('generated')) {
273
-				if (!$data = $this->generateAvatarFromSvg($size)) {
274
-					$data = $this->generateAvatar($this->getDisplayName(), $size);
275
-				}
276
-
277
-			} else {
278
-				$avatar = new OC_Image();
279
-				$file = $this->folder->getFile('avatar.' . $ext);
280
-				$avatar->loadFromData($file->getContent());
281
-				$avatar->resize($size);
282
-				$data = $avatar->data();
283
-			}
284
-
285
-			try {
286
-				$file = $this->folder->newFile($path);
287
-				$file->putContent($data);
288
-			} catch (NotPermittedException $e) {
289
-				$this->logger->error('Failed to save avatar for ' . $this->user->getUID());
290
-				throw new NotFoundException();
291
-			}
292
-
293
-		}
294
-
295
-		if ($this->config->getUserValue($this->user->getUID(), 'avatar', 'generated', null) === null) {
296
-			$generated = $this->folder->fileExists('generated') ? 'true' : 'false';
297
-			$this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', $generated);
298
-		}
299
-
300
-		return $file;
301
-	}
302
-
303
-	/**
304
-	 * Returns the user display name.
305
-	 *
306
-	 * @return string
307
-	 */
308
-	public function getDisplayName(): string {
309
-		return $this->user->getDisplayName();
310
-	}
311
-
312
-	/**
313
-	 * Handles user changes.
314
-	 *
315
-	 * @param string $feature The changed feature
316
-	 * @param mixed $oldValue The previous value
317
-	 * @param mixed $newValue The new value
318
-	 * @throws NotPermittedException
319
-	 * @throws \OCP\PreConditionNotMetException
320
-	 */
321
-	public function userChanged($feature, $oldValue, $newValue) {
322
-		// If the avatar is not generated (so an uploaded image) we skip this
323
-		if (!$this->folder->fileExists('generated')) {
324
-			return;
325
-		}
326
-
327
-		$this->remove();
328
-	}
329
-
330
-	/**
331
-	 * Check if the avatar of a user is a custom uploaded one
332
-	 *
333
-	 * @return bool
334
-	 */
335
-	public function isCustomAvatar(): bool {
336
-		return $this->config->getUserValue($this->user->getUID(), 'avatar', 'generated', 'false') !== 'true';
337
-	}
47
+    /** @var IConfig */
48
+    private $config;
49
+
50
+    /** @var ISimpleFolder */
51
+    private $folder;
52
+
53
+    /** @var IL10N */
54
+    private $l;
55
+
56
+    /** @var User */
57
+    private $user;
58
+
59
+    /**
60
+     * UserAvatar constructor.
61
+     *
62
+     * @param IConfig $config The configuration
63
+     * @param ISimpleFolder $folder The avatar files folder
64
+     * @param IL10N $l The localization helper
65
+     * @param User $user The user this class manages the avatar for
66
+     * @param ILogger $logger The logger
67
+     */
68
+    public function __construct(
69
+        ISimpleFolder $folder,
70
+        IL10N $l,
71
+        $user,
72
+        ILogger $logger,
73
+        IConfig $config) {
74
+        parent::__construct($logger);
75
+        $this->folder = $folder;
76
+        $this->l = $l;
77
+        $this->user = $user;
78
+        $this->config = $config;
79
+    }
80
+
81
+    /**
82
+     * Check if an avatar exists for the user
83
+     *
84
+     * @return bool
85
+     */
86
+    public function exists() {
87
+        return $this->folder->fileExists('avatar.jpg') || $this->folder->fileExists('avatar.png');
88
+    }
89
+
90
+    /**
91
+     * Sets the users avatar.
92
+     *
93
+     * @param IImage|resource|string $data An image object, imagedata or path to set a new avatar
94
+     * @throws \Exception if the provided file is not a jpg or png image
95
+     * @throws \Exception if the provided image is not valid
96
+     * @throws NotSquareException if the image is not square
97
+     * @return void
98
+     */
99
+    public function set($data) {
100
+        $img = $this->getAvatarImage($data);
101
+        $data = $img->data();
102
+
103
+        $this->validateAvatar($img);
104
+
105
+        $this->remove(true);
106
+        $type = $this->getAvatarImageType($img);
107
+        $file = $this->folder->newFile('avatar.' . $type);
108
+        $file->putContent($data);
109
+
110
+        try {
111
+            $generated = $this->folder->getFile('generated');
112
+            $generated->delete();
113
+        } catch (NotFoundException $e) {
114
+            //
115
+        }
116
+
117
+        $this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'false');
118
+        $this->user->triggerChange('avatar', $file);
119
+    }
120
+
121
+    /**
122
+     * Returns an image from several sources.
123
+     *
124
+     * @param IImage|resource|string $data An image object, imagedata or path to the avatar
125
+     * @return IImage
126
+     */
127
+    private function getAvatarImage($data) {
128
+        if ($data instanceof IImage) {
129
+            return $data;
130
+        }
131
+
132
+        $img = new OC_Image();
133
+        if (is_resource($data) && get_resource_type($data) === 'gd') {
134
+            $img->setResource($data);
135
+        } elseif (is_resource($data)) {
136
+            $img->loadFromFileHandle($data);
137
+        } else {
138
+            try {
139
+                // detect if it is a path or maybe the images as string
140
+                $result = @realpath($data);
141
+                if ($result === false || $result === null) {
142
+                    $img->loadFromData($data);
143
+                } else {
144
+                    $img->loadFromFile($data);
145
+                }
146
+            } catch (\Error $e) {
147
+                $img->loadFromData($data);
148
+            }
149
+        }
150
+
151
+        return $img;
152
+    }
153
+
154
+    /**
155
+     * Returns the avatar image type.
156
+     *
157
+     * @param IImage $avatar
158
+     * @return string
159
+     */
160
+    private function getAvatarImageType(IImage $avatar) {
161
+        $type = substr($avatar->mimeType(), -3);
162
+        if ($type === 'peg') {
163
+            $type = 'jpg';
164
+        }
165
+        return $type;
166
+    }
167
+
168
+    /**
169
+     * Validates an avatar image:
170
+     * - must be "png" or "jpg"
171
+     * - must be "valid"
172
+     * - must be in square format
173
+     *
174
+     * @param IImage $avatar The avatar to validate
175
+     * @throws \Exception if the provided file is not a jpg or png image
176
+     * @throws \Exception if the provided image is not valid
177
+     * @throws NotSquareException if the image is not square
178
+     */
179
+    private function validateAvatar(IImage $avatar) {
180
+        $type = $this->getAvatarImageType($avatar);
181
+
182
+        if ($type !== 'jpg' && $type !== 'png') {
183
+            throw new \Exception($this->l->t('Unknown filetype'));
184
+        }
185
+
186
+        if (!$avatar->valid()) {
187
+            throw new \Exception($this->l->t('Invalid image'));
188
+        }
189
+
190
+        if (!($avatar->height() === $avatar->width())) {
191
+            throw new NotSquareException($this->l->t('Avatar image is not square'));
192
+        }
193
+    }
194
+
195
+    /**
196
+     * Removes the users avatar.
197
+     * @return void
198
+     * @throws \OCP\Files\NotPermittedException
199
+     * @throws \OCP\PreConditionNotMetException
200
+     */
201
+    public function remove(bool $silent = false) {
202
+        $avatars = $this->folder->getDirectoryListing();
203
+
204
+        $this->config->setUserValue($this->user->getUID(), 'avatar', 'version',
205
+            (int) $this->config->getUserValue($this->user->getUID(), 'avatar', 'version', 0) + 1);
206
+
207
+        foreach ($avatars as $avatar) {
208
+            $avatar->delete();
209
+        }
210
+        $this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'true');
211
+        if(!$silent) {
212
+            $this->user->triggerChange('avatar', '');
213
+        }
214
+    }
215
+
216
+    /**
217
+     * Get the extension of the avatar. If there is no avatar throw Exception
218
+     *
219
+     * @return string
220
+     * @throws NotFoundException
221
+     */
222
+    private function getExtension() {
223
+        if ($this->folder->fileExists('avatar.jpg')) {
224
+            return 'jpg';
225
+        } elseif ($this->folder->fileExists('avatar.png')) {
226
+            return 'png';
227
+        }
228
+        throw new NotFoundException;
229
+    }
230
+
231
+    /**
232
+     * Returns the avatar for an user.
233
+     *
234
+     * If there is no avatar file yet, one is generated.
235
+     *
236
+     * @param int $size
237
+     * @return ISimpleFile
238
+     * @throws NotFoundException
239
+     * @throws \OCP\Files\NotPermittedException
240
+     * @throws \OCP\PreConditionNotMetException
241
+     */
242
+    public function getFile($size) {
243
+        $size = (int) $size;
244
+
245
+        try {
246
+            $ext = $this->getExtension();
247
+        } catch (NotFoundException $e) {
248
+            if (!$data = $this->generateAvatarFromSvg(1024)) {
249
+                $data = $this->generateAvatar($this->getDisplayName(), 1024);
250
+            }
251
+            $avatar = $this->folder->newFile('avatar.png');
252
+            $avatar->putContent($data);
253
+            $ext = 'png';
254
+
255
+            $this->folder->newFile('generated', '');
256
+            $this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'true');
257
+        }
258
+
259
+        if ($size === -1) {
260
+            $path = 'avatar.' . $ext;
261
+        } else {
262
+            $path = 'avatar.' . $size . '.' . $ext;
263
+        }
264
+
265
+        try {
266
+            $file = $this->folder->getFile($path);
267
+        } catch (NotFoundException $e) {
268
+            if ($size <= 0) {
269
+                throw new NotFoundException;
270
+            }
271
+
272
+            if ($this->folder->fileExists('generated')) {
273
+                if (!$data = $this->generateAvatarFromSvg($size)) {
274
+                    $data = $this->generateAvatar($this->getDisplayName(), $size);
275
+                }
276
+
277
+            } else {
278
+                $avatar = new OC_Image();
279
+                $file = $this->folder->getFile('avatar.' . $ext);
280
+                $avatar->loadFromData($file->getContent());
281
+                $avatar->resize($size);
282
+                $data = $avatar->data();
283
+            }
284
+
285
+            try {
286
+                $file = $this->folder->newFile($path);
287
+                $file->putContent($data);
288
+            } catch (NotPermittedException $e) {
289
+                $this->logger->error('Failed to save avatar for ' . $this->user->getUID());
290
+                throw new NotFoundException();
291
+            }
292
+
293
+        }
294
+
295
+        if ($this->config->getUserValue($this->user->getUID(), 'avatar', 'generated', null) === null) {
296
+            $generated = $this->folder->fileExists('generated') ? 'true' : 'false';
297
+            $this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', $generated);
298
+        }
299
+
300
+        return $file;
301
+    }
302
+
303
+    /**
304
+     * Returns the user display name.
305
+     *
306
+     * @return string
307
+     */
308
+    public function getDisplayName(): string {
309
+        return $this->user->getDisplayName();
310
+    }
311
+
312
+    /**
313
+     * Handles user changes.
314
+     *
315
+     * @param string $feature The changed feature
316
+     * @param mixed $oldValue The previous value
317
+     * @param mixed $newValue The new value
318
+     * @throws NotPermittedException
319
+     * @throws \OCP\PreConditionNotMetException
320
+     */
321
+    public function userChanged($feature, $oldValue, $newValue) {
322
+        // If the avatar is not generated (so an uploaded image) we skip this
323
+        if (!$this->folder->fileExists('generated')) {
324
+            return;
325
+        }
326
+
327
+        $this->remove();
328
+    }
329
+
330
+    /**
331
+     * Check if the avatar of a user is a custom uploaded one
332
+     *
333
+     * @return bool
334
+     */
335
+    public function isCustomAvatar(): bool {
336
+        return $this->config->getUserValue($this->user->getUID(), 'avatar', 'generated', 'false') !== 'true';
337
+    }
338 338
 }
Please login to merge, or discard this patch.
apps/dav/lib/CardDAV/PhotoCache.php 1 patch
Indentation   +249 added lines, -249 removed lines patch added patch discarded remove patch
@@ -39,253 +39,253 @@
 block discarded – undo
39 39
 
40 40
 class PhotoCache {
41 41
 
42
-	/** @var array  */
43
-	protected const ALLOWED_CONTENT_TYPES = [
44
-		'image/png' => 'png',
45
-		'image/jpeg' => 'jpg',
46
-		'image/gif' => 'gif',
47
-		'image/vnd.microsoft.icon' => 'ico',
48
-	];
49
-
50
-	/** @var IAppData */
51
-	protected $appData;
52
-
53
-	/** @var ILogger */
54
-	protected $logger;
55
-
56
-	/**
57
-	 * PhotoCache constructor.
58
-	 *
59
-	 * @param IAppData $appData
60
-	 * @param ILogger $logger
61
-	 */
62
-	public function __construct(IAppData $appData, ILogger $logger) {
63
-		$this->appData = $appData;
64
-		$this->logger = $logger;
65
-	}
66
-
67
-	/**
68
-	 * @param int $addressBookId
69
-	 * @param string $cardUri
70
-	 * @param int $size
71
-	 * @param Card $card
72
-	 *
73
-	 * @return ISimpleFile
74
-	 * @throws NotFoundException
75
-	 */
76
-	public function get($addressBookId, $cardUri, $size, Card $card) {
77
-		$folder = $this->getFolder($addressBookId, $cardUri);
78
-
79
-		if ($this->isEmpty($folder)) {
80
-			$this->init($folder, $card);
81
-		}
82
-
83
-		if (!$this->hasPhoto($folder)) {
84
-			throw new NotFoundException();
85
-		}
86
-
87
-		if ($size !== -1) {
88
-			$size = 2 ** ceil(log($size) / log(2));
89
-		}
90
-
91
-		return $this->getFile($folder, $size);
92
-	}
93
-
94
-	/**
95
-	 * @param ISimpleFolder $folder
96
-	 * @return bool
97
-	 */
98
-	private function isEmpty(ISimpleFolder $folder) {
99
-		return $folder->getDirectoryListing() === [];
100
-	}
101
-
102
-	/**
103
-	 * @param ISimpleFolder $folder
104
-	 * @param Card $card
105
-	 * @throws NotPermittedException
106
-	 */
107
-	private function init(ISimpleFolder $folder, Card $card): void {
108
-		$data = $this->getPhoto($card);
109
-
110
-		if ($data === false || !isset($data['Content-Type'])) {
111
-			$folder->newFile('nophoto', '');
112
-			return;
113
-		}
114
-
115
-		$contentType = $data['Content-Type'];
116
-		$extension = self::ALLOWED_CONTENT_TYPES[$contentType] ?? null;
117
-
118
-		if ($extension === null) {
119
-			$folder->newFile('nophoto', '');
120
-			return;
121
-		}
122
-
123
-		$file = $folder->newFile('photo.' . $extension);
124
-		$file->putContent($data['body']);
125
-	}
126
-
127
-	private function hasPhoto(ISimpleFolder $folder) {
128
-		return !$folder->fileExists('nophoto');
129
-	}
130
-
131
-	private function getFile(ISimpleFolder $folder, $size) {
132
-		$ext = $this->getExtension($folder);
133
-
134
-		if ($size === -1) {
135
-			$path = 'photo.' . $ext;
136
-		} else {
137
-			$path = 'photo.' . $size . '.' . $ext;
138
-		}
139
-
140
-		try {
141
-			$file = $folder->getFile($path);
142
-		} catch (NotFoundException $e) {
143
-			if ($size <= 0) {
144
-				throw new NotFoundException;
145
-			}
146
-
147
-			$photo = new \OC_Image();
148
-			/** @var ISimpleFile $file */
149
-			$file = $folder->getFile('photo.' . $ext);
150
-			$photo->loadFromData($file->getContent());
151
-
152
-			$ratio = $photo->width() / $photo->height();
153
-			if ($ratio < 1) {
154
-				$ratio = 1 / $ratio;
155
-			}
156
-
157
-			$size = (int) ($size * $ratio);
158
-			if ($size !== -1) {
159
-				$photo->resize($size);
160
-			}
161
-
162
-			try {
163
-				$file = $folder->newFile($path);
164
-				$file->putContent($photo->data());
165
-			} catch (NotPermittedException $e) {
166
-
167
-			}
168
-		}
169
-
170
-		return $file;
171
-	}
172
-
173
-	/**
174
-	 * @throws NotFoundException
175
-	 * @throws NotPermittedException
176
-	 */
177
-	private function getFolder(int $addressBookId, string $cardUri, bool $createIfNotExists = true): ISimpleFolder {
178
-		$hash = md5($addressBookId . ' ' . $cardUri);
179
-		try {
180
-			return $this->appData->getFolder($hash);
181
-		} catch (NotFoundException $e) {
182
-			if($createIfNotExists) {
183
-				return $this->appData->newFolder($hash);
184
-			} else {
185
-				throw $e;
186
-			}
187
-		}
188
-	}
189
-
190
-	/**
191
-	 * Get the extension of the avatar. If there is no avatar throw Exception
192
-	 *
193
-	 * @param ISimpleFolder $folder
194
-	 * @return string
195
-	 * @throws NotFoundException
196
-	 */
197
-	private function getExtension(ISimpleFolder $folder): string {
198
-		foreach (self::ALLOWED_CONTENT_TYPES as $extension) {
199
-			if ($folder->fileExists('photo.' . $extension)) {
200
-				return $extension;
201
-			}
202
-		}
203
-
204
-		throw new NotFoundException('Avatar not found');
205
-	}
206
-
207
-	private function getPhoto(Card $node) {
208
-		try {
209
-			$vObject = $this->readCard($node->get());
210
-			if (!$vObject->PHOTO) {
211
-				return false;
212
-			}
213
-
214
-			$photo = $vObject->PHOTO;
215
-			$val = $photo->getValue();
216
-
217
-			// handle data URI. e.g PHOTO;VALUE=URI:data:image/jpeg;base64,/9j/4AAQSkZJRgABAQE
218
-			if ($photo->getValueType() === 'URI') {
219
-				$parsed = \Sabre\URI\parse($val);
220
-
221
-				// only allow data://
222
-				if ($parsed['scheme'] !== 'data') {
223
-					return false;
224
-				}
225
-				if (substr_count($parsed['path'], ';') === 1) {
226
-					list($type) = explode(';', $parsed['path']);
227
-				}
228
-				$val = file_get_contents($val);
229
-			} else {
230
-				// get type if binary data
231
-				$type = $this->getBinaryType($photo);
232
-			}
233
-
234
-			if (empty($type) || !isset(self::ALLOWED_CONTENT_TYPES[$type])) {
235
-				$type = 'application/octet-stream';
236
-			}
237
-
238
-			return [
239
-				'Content-Type' => $type,
240
-				'body'         => $val
241
-			];
242
-		} catch (\Exception $e) {
243
-			$this->logger->logException($e, [
244
-				'message' => 'Exception during vcard photo parsing'
245
-			]);
246
-		}
247
-		return false;
248
-	}
249
-
250
-	/**
251
-	 * @param string $cardData
252
-	 * @return \Sabre\VObject\Document
253
-	 */
254
-	private function readCard($cardData) {
255
-		return Reader::read($cardData);
256
-	}
257
-
258
-	/**
259
-	 * @param Binary $photo
260
-	 * @return string
261
-	 */
262
-	private function getBinaryType(Binary $photo) {
263
-		$params = $photo->parameters();
264
-		if (isset($params['TYPE']) || isset($params['MEDIATYPE'])) {
265
-			/** @var Parameter $typeParam */
266
-			$typeParam = isset($params['TYPE']) ? $params['TYPE'] : $params['MEDIATYPE'];
267
-			$type = $typeParam->getValue();
268
-
269
-			if (strpos($type, 'image/') === 0) {
270
-				return $type;
271
-			} else {
272
-				return 'image/' . strtolower($type);
273
-			}
274
-		}
275
-		return '';
276
-	}
277
-
278
-	/**
279
-	 * @param int $addressBookId
280
-	 * @param string $cardUri
281
-	 * @throws NotPermittedException
282
-	 */
283
-	public function delete($addressBookId, $cardUri) {
284
-		try {
285
-			$folder = $this->getFolder($addressBookId, $cardUri, false);
286
-			$folder->delete();
287
-		} catch (NotFoundException $e) {
288
-			// that's OK, nothing to do
289
-		}
290
-	}
42
+    /** @var array  */
43
+    protected const ALLOWED_CONTENT_TYPES = [
44
+        'image/png' => 'png',
45
+        'image/jpeg' => 'jpg',
46
+        'image/gif' => 'gif',
47
+        'image/vnd.microsoft.icon' => 'ico',
48
+    ];
49
+
50
+    /** @var IAppData */
51
+    protected $appData;
52
+
53
+    /** @var ILogger */
54
+    protected $logger;
55
+
56
+    /**
57
+     * PhotoCache constructor.
58
+     *
59
+     * @param IAppData $appData
60
+     * @param ILogger $logger
61
+     */
62
+    public function __construct(IAppData $appData, ILogger $logger) {
63
+        $this->appData = $appData;
64
+        $this->logger = $logger;
65
+    }
66
+
67
+    /**
68
+     * @param int $addressBookId
69
+     * @param string $cardUri
70
+     * @param int $size
71
+     * @param Card $card
72
+     *
73
+     * @return ISimpleFile
74
+     * @throws NotFoundException
75
+     */
76
+    public function get($addressBookId, $cardUri, $size, Card $card) {
77
+        $folder = $this->getFolder($addressBookId, $cardUri);
78
+
79
+        if ($this->isEmpty($folder)) {
80
+            $this->init($folder, $card);
81
+        }
82
+
83
+        if (!$this->hasPhoto($folder)) {
84
+            throw new NotFoundException();
85
+        }
86
+
87
+        if ($size !== -1) {
88
+            $size = 2 ** ceil(log($size) / log(2));
89
+        }
90
+
91
+        return $this->getFile($folder, $size);
92
+    }
93
+
94
+    /**
95
+     * @param ISimpleFolder $folder
96
+     * @return bool
97
+     */
98
+    private function isEmpty(ISimpleFolder $folder) {
99
+        return $folder->getDirectoryListing() === [];
100
+    }
101
+
102
+    /**
103
+     * @param ISimpleFolder $folder
104
+     * @param Card $card
105
+     * @throws NotPermittedException
106
+     */
107
+    private function init(ISimpleFolder $folder, Card $card): void {
108
+        $data = $this->getPhoto($card);
109
+
110
+        if ($data === false || !isset($data['Content-Type'])) {
111
+            $folder->newFile('nophoto', '');
112
+            return;
113
+        }
114
+
115
+        $contentType = $data['Content-Type'];
116
+        $extension = self::ALLOWED_CONTENT_TYPES[$contentType] ?? null;
117
+
118
+        if ($extension === null) {
119
+            $folder->newFile('nophoto', '');
120
+            return;
121
+        }
122
+
123
+        $file = $folder->newFile('photo.' . $extension);
124
+        $file->putContent($data['body']);
125
+    }
126
+
127
+    private function hasPhoto(ISimpleFolder $folder) {
128
+        return !$folder->fileExists('nophoto');
129
+    }
130
+
131
+    private function getFile(ISimpleFolder $folder, $size) {
132
+        $ext = $this->getExtension($folder);
133
+
134
+        if ($size === -1) {
135
+            $path = 'photo.' . $ext;
136
+        } else {
137
+            $path = 'photo.' . $size . '.' . $ext;
138
+        }
139
+
140
+        try {
141
+            $file = $folder->getFile($path);
142
+        } catch (NotFoundException $e) {
143
+            if ($size <= 0) {
144
+                throw new NotFoundException;
145
+            }
146
+
147
+            $photo = new \OC_Image();
148
+            /** @var ISimpleFile $file */
149
+            $file = $folder->getFile('photo.' . $ext);
150
+            $photo->loadFromData($file->getContent());
151
+
152
+            $ratio = $photo->width() / $photo->height();
153
+            if ($ratio < 1) {
154
+                $ratio = 1 / $ratio;
155
+            }
156
+
157
+            $size = (int) ($size * $ratio);
158
+            if ($size !== -1) {
159
+                $photo->resize($size);
160
+            }
161
+
162
+            try {
163
+                $file = $folder->newFile($path);
164
+                $file->putContent($photo->data());
165
+            } catch (NotPermittedException $e) {
166
+
167
+            }
168
+        }
169
+
170
+        return $file;
171
+    }
172
+
173
+    /**
174
+     * @throws NotFoundException
175
+     * @throws NotPermittedException
176
+     */
177
+    private function getFolder(int $addressBookId, string $cardUri, bool $createIfNotExists = true): ISimpleFolder {
178
+        $hash = md5($addressBookId . ' ' . $cardUri);
179
+        try {
180
+            return $this->appData->getFolder($hash);
181
+        } catch (NotFoundException $e) {
182
+            if($createIfNotExists) {
183
+                return $this->appData->newFolder($hash);
184
+            } else {
185
+                throw $e;
186
+            }
187
+        }
188
+    }
189
+
190
+    /**
191
+     * Get the extension of the avatar. If there is no avatar throw Exception
192
+     *
193
+     * @param ISimpleFolder $folder
194
+     * @return string
195
+     * @throws NotFoundException
196
+     */
197
+    private function getExtension(ISimpleFolder $folder): string {
198
+        foreach (self::ALLOWED_CONTENT_TYPES as $extension) {
199
+            if ($folder->fileExists('photo.' . $extension)) {
200
+                return $extension;
201
+            }
202
+        }
203
+
204
+        throw new NotFoundException('Avatar not found');
205
+    }
206
+
207
+    private function getPhoto(Card $node) {
208
+        try {
209
+            $vObject = $this->readCard($node->get());
210
+            if (!$vObject->PHOTO) {
211
+                return false;
212
+            }
213
+
214
+            $photo = $vObject->PHOTO;
215
+            $val = $photo->getValue();
216
+
217
+            // handle data URI. e.g PHOTO;VALUE=URI:data:image/jpeg;base64,/9j/4AAQSkZJRgABAQE
218
+            if ($photo->getValueType() === 'URI') {
219
+                $parsed = \Sabre\URI\parse($val);
220
+
221
+                // only allow data://
222
+                if ($parsed['scheme'] !== 'data') {
223
+                    return false;
224
+                }
225
+                if (substr_count($parsed['path'], ';') === 1) {
226
+                    list($type) = explode(';', $parsed['path']);
227
+                }
228
+                $val = file_get_contents($val);
229
+            } else {
230
+                // get type if binary data
231
+                $type = $this->getBinaryType($photo);
232
+            }
233
+
234
+            if (empty($type) || !isset(self::ALLOWED_CONTENT_TYPES[$type])) {
235
+                $type = 'application/octet-stream';
236
+            }
237
+
238
+            return [
239
+                'Content-Type' => $type,
240
+                'body'         => $val
241
+            ];
242
+        } catch (\Exception $e) {
243
+            $this->logger->logException($e, [
244
+                'message' => 'Exception during vcard photo parsing'
245
+            ]);
246
+        }
247
+        return false;
248
+    }
249
+
250
+    /**
251
+     * @param string $cardData
252
+     * @return \Sabre\VObject\Document
253
+     */
254
+    private function readCard($cardData) {
255
+        return Reader::read($cardData);
256
+    }
257
+
258
+    /**
259
+     * @param Binary $photo
260
+     * @return string
261
+     */
262
+    private function getBinaryType(Binary $photo) {
263
+        $params = $photo->parameters();
264
+        if (isset($params['TYPE']) || isset($params['MEDIATYPE'])) {
265
+            /** @var Parameter $typeParam */
266
+            $typeParam = isset($params['TYPE']) ? $params['TYPE'] : $params['MEDIATYPE'];
267
+            $type = $typeParam->getValue();
268
+
269
+            if (strpos($type, 'image/') === 0) {
270
+                return $type;
271
+            } else {
272
+                return 'image/' . strtolower($type);
273
+            }
274
+        }
275
+        return '';
276
+    }
277
+
278
+    /**
279
+     * @param int $addressBookId
280
+     * @param string $cardUri
281
+     * @throws NotPermittedException
282
+     */
283
+    public function delete($addressBookId, $cardUri) {
284
+        try {
285
+            $folder = $this->getFolder($addressBookId, $cardUri, false);
286
+            $folder->delete();
287
+        } catch (NotFoundException $e) {
288
+            // that's OK, nothing to do
289
+        }
290
+    }
291 291
 }
Please login to merge, or discard this patch.