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;
* @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)
{
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;
}
/**
* @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']);
}
/**
* 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), "");
*
* @param string $url Image URL
* @param int $uid User ID of the requesting person
- * @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 createPhotoForExternalResource($url, $uid = 0, $mimetype = "image/jpeg")
+ public static function createPhotoForExternalResource($url, $uid = 0, $mimetype = '')
{
+ if (empty($mimetype)) {
+ $mimetype = Images::guessTypeByExtension($url);
+ }
+
$fields = self::getFields();
$values = array_fill(0, count($fields), "");
// 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 = [
$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]);
}
}
$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();
}
}
$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 == "")) {
}
/**
- * 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];
}
/**
*/
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;
}
/**