X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModel%2FPhoto.php;h=c09434d7f237a477c80fbb0dc25e63e4643aac8a;hb=a4b0ab90b1ac32f7cdb875387f511c980dbed9ce;hp=f79409e3f5c332f1115002d9b265f0388fbd2813;hpb=14c1f7167a15f29169f7f796f07a82fd3c2bd8de;p=friendica.git diff --git a/src/Model/Photo.php b/src/Model/Photo.php index f79409e3f5..c09434d7f2 100644 --- a/src/Model/Photo.php +++ b/src/Model/Photo.php @@ -27,6 +27,10 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Database\DBStructure; use Friendica\DI; +use Friendica\Model\Storage\ExternalResource; +use Friendica\Model\Storage\InvalidClassStorageException; +use Friendica\Model\Storage\ReferenceStorageException; +use Friendica\Model\Storage\StorageException; use Friendica\Model\Storage\SystemResource; use Friendica\Object\Image; use Friendica\Util\DateTimeFormat; @@ -183,8 +187,6 @@ class Photo * @param array $photo Photo data. Needs at least 'id', 'type', 'backend-class', 'backend-ref' * * @return \Friendica\Object\Image - * @throws \Friendica\Network\HTTPException\InternalServerErrorException - * @throws \ImagickException */ public static function getImageDataForPhoto(array $photo) { @@ -192,19 +194,31 @@ class Photo return $photo['data']; } - $backendClass = DI::storageManager()->getByName($photo['backend-class'] ?? ''); - if (empty($backendClass)) { - // legacy data storage in "data" column - $i = self::selectFirst(['data'], ['id' => $photo['id']]); - if ($i === false) { - return null; + try { + $backendClass = DI::storageManager()->getByName($photo['backend-class'] ?? ''); + /// @todo refactoring this returning, because the storage returns a "string" which is casted in different ways - a check "instanceof Image" will fail! + return $backendClass->get($photo['backend-ref'] ?? ''); + } catch (InvalidClassStorageException $storageException) { + try { + // legacy data storage in "data" column + $i = self::selectFirst(['data'], ['id' => $photo['id']]); + if ($i !== false) { + return $i['data']; + } else { + DI::logger()->info('Stored legacy data is empty', ['photo' => $photo]); + } + } catch (\Exception $exception) { + DI::logger()->info('Unexpected database exception', ['photo' => $photo, 'exception' => $exception]); } - $data = $i['data']; - } else { - $backendRef = $photo['backend-ref'] ?? ''; - $data = $backendClass->get($backendRef); + } catch (ReferenceStorageException $referenceStorageException) { + DI::logger()->debug('Invalid reference for photo', ['photo' => $photo, 'exception' => $referenceStorageException]); + } catch (StorageException $storageException) { + DI::logger()->info('Unexpected storage exception', ['photo' => $photo, 'exception' => $storageException]); + } catch (\ImagickException $imagickException) { + DI::logger()->info('Unexpected imagick exception', ['photo' => $photo, 'exception' => $imagickException]); } - return $data; + + return null; } /** @@ -216,14 +230,9 @@ class Photo * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function getImageForPhoto(array $photo) + public static function getImageForPhoto(array $photo): Image { - $data = self::getImageDataForPhoto($photo); - if (empty($data)) { - return null; - } - - return new Image($data, $photo['type']); + return new Image(self::getImageDataForPhoto($photo), $photo['type']); } /** @@ -244,13 +253,17 @@ class Photo * Construct a photo array for a system resource image * * @param string $filename Image file name relative to code root - * @param string $mimetype Image mime type. Defaults to "image/jpeg" + * @param string $mimetype Image mime type. Is guessed by file name when empty. * * @return array * @throws \Exception */ - public static function createPhotoForSystemResource($filename, $mimetype = "image/jpeg") + public static function createPhotoForSystemResource($filename, $mimetype = '') { + if (empty($mimetype)) { + $mimetype = Images::guessTypeByExtension($filename); + } + $fields = self::getFields(); $values = array_fill(0, count($fields), ""); @@ -263,6 +276,33 @@ class Photo return $photo; } + /** + * Construct a photo array for an external resource image + * + * @param string $url Image URL + * @param int $uid User ID of the requesting person + * @param string $mimetype Image mime type. Is guessed by file name when empty. + * + * @return array + * @throws \Exception + */ + public static function createPhotoForExternalResource($url, $uid = 0, $mimetype = '') + { + if (empty($mimetype)) { + $mimetype = Images::guessTypeByExtension($url); + } + + $fields = self::getFields(); + $values = array_fill(0, count($fields), ""); + + $photo = array_combine($fields, $values); + $photo['backend-class'] = ExternalResource::NAME; + $photo['backend-ref'] = json_encode(['url' => $url, 'uid' => $uid]); + $photo['type'] = $mimetype; + $photo['cacheable'] = true; + + return $photo; + } /** * store photo metadata in db and binary in default backend @@ -302,20 +342,20 @@ class Photo // Get defined storage backend. // if no storage backend, we use old "data" column in photo table. // if is an existing photo, reuse same backend - $data = ""; + $data = ""; $backend_ref = ""; + $storage = ""; - if (DBA::isResult($existing_photo)) { - $backend_ref = (string)$existing_photo["backend-ref"]; - $storage = DI::storageManager()->getByName($existing_photo["backend-class"] ?? ''); - } else { - $storage = DI::storage(); - } - - if (empty($storage)) { - $data = $Image->asString(); - } else { + try { + if (DBA::isResult($existing_photo)) { + $backend_ref = (string)$existing_photo["backend-ref"]; + $storage = DI::storageManager()->getWritableStorageByName($existing_photo["backend-class"] ?? ''); + } else { + $storage = DI::storage(); + } $backend_ref = $storage->put($Image->asString(), $backend_ref); + } catch (InvalidClassStorageException $storageException) { + $data = $Image->asString(); } $fields = [ @@ -371,12 +411,15 @@ class Photo $photos = DBA::select('photo', ['id', 'backend-class', 'backend-ref'], $conditions); while ($photo = DBA::fetch($photos)) { - $backend_class = DI::storageManager()->getByName($photo['backend-class'] ?? ''); - if (!empty($backend_class)) { - if ($backend_class->delete($photo["backend-ref"] ?? '')) { - // Delete the photos after they had been deleted successfully - DBA::delete("photo", ['id' => $photo['id']]); - } + try { + $backend_class = DI::storageManager()->getWritableStorageByName($photo['backend-class'] ?? ''); + $backend_class->delete($photo['backend-ref'] ?? ''); + // Delete the photos after they had been deleted successfully + DBA::delete("photo", ['id' => $photo['id']]); + } catch (InvalidClassStorageException $storageException) { + DI::logger()->debug('Storage class not found.', ['conditions' => $conditions, 'exception' => $storageException]); + } catch (ReferenceStorageException $referenceStorageException) { + DI::logger()->debug('Photo doesn\'t exist.', ['conditions' => $conditions, 'exception' => $referenceStorageException]); } } @@ -405,10 +448,10 @@ class Photo $photos = self::selectToArray(['backend-class', 'backend-ref'], $conditions); foreach($photos as $photo) { - $backend_class = DI::storageManager()->getByName($photo['backend-class'] ?? ''); - if (!empty($backend_class)) { + try { + $backend_class = DI::storageManager()->getWritableStorageByName($photo['backend-class'] ?? ''); $fields["backend-ref"] = $backend_class->put($img->asString(), $photo['backend-ref']); - } else { + } catch (InvalidClassStorageException $storageException) { $fields["data"] = $img->asString(); } } @@ -447,11 +490,12 @@ class Photo $filename = basename($image_url); if (!empty($image_url)) { - $ret = DI::httpRequest()->get($image_url); + $ret = DI::httpClient()->get($image_url); $img_str = $ret->getBody(); $type = $ret->getContentType(); } else { $img_str = ''; + $type = ''; } if ($quit_on_error && ($img_str == "")) { @@ -772,30 +816,33 @@ class Photo } /** - * Returns the GUID from picture links + * Fetch the guid and scale from picture links * * @param string $name Picture link - * @return string GUID - * @throws \Exception + * @return array */ - public static function getGUID($name) + public static function getResourceData(string $name):array { $base = DI::baseUrl()->get(); $guid = str_replace([Strings::normaliseLink($base), '/photo/'], '', Strings::normaliseLink($name)); + if (parse_url($guid, PHP_URL_SCHEME)) { + return []; + } + $guid = self::stripExtension($guid); if (substr($guid, -2, 1) != "-") { - return ''; + return []; } $scale = intval(substr($guid, -1, 1)); if (!is_numeric($scale)) { - return ''; + return []; } $guid = substr($guid, 0, -2); - return $guid; + return ['guid' => $guid, 'scale' => $scale]; } /** @@ -807,13 +854,27 @@ class Photo */ public static function isLocal($name) { - $guid = self::getGUID($name); + return (bool)self::getIdForName($name); + } - if (empty($guid)) { - return false; + /** + * Return the id of a local photo + * + * @param string $name Picture link + * @return int + */ + public static function getIdForName($name) + { + $data = self::getResourceData($name); + if (empty($data)) { + return 0; } - return DBA::exists('photo', ['resource-id' => $guid]); + $photo = DBA::selectFirst('photo', ['id'], ['resource-id' => $data['guid'], 'scale' => $data['scale']]); + if (!empty($photo['id'])) { + return $photo['id']; + } + return 0; } /**