X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModel%2FPhoto.php;h=0e3661b0f33e4110915908a8542353e35823112b;hb=6bb418c5a7cdd71d28a8a572059efb14401b70bd;hp=3c22c52bc1d06ee9a25a32a5db38bcad2477f2f6;hpb=234c110d38f50dfcf181797cf02bd721847eb486;p=friendica.git diff --git a/src/Model/Photo.php b/src/Model/Photo.php index 3c22c52bc1..0e3661b0f3 100644 --- a/src/Model/Photo.php +++ b/src/Model/Photo.php @@ -10,10 +10,13 @@ use Friendica\BaseObject; use Friendica\Core\Cache; use Friendica\Core\Config; use Friendica\Core\L10n; +use Friendica\Core\StorageManager; use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Database\DBStructure; +use Friendica\Model\Storage\IStorage; use Friendica\Object\Image; +use Friendica\Protocol\DFRN; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; use Friendica\Util\Security; @@ -28,18 +31,19 @@ class Photo extends BaseObject /** * @brief Select rows from the photo table * - * @param array $fields Array of selected fields, empty for all - * @param array $conditions Array of fields for conditions - * @param array $params Array of several parameters + * @param array $fields Array of selected fields, empty for all + * @param array $conditions Array of fields for conditions + * @param array $params Array of several parameters * * @return boolean|array * - * @see \Friendica\Database\DBA::select + * @throws \Exception + * @see \Friendica\Database\DBA::select */ public static function select(array $fields = [], array $conditions = [], array $params = []) { if (empty($fields)) { - $selected = self::getFields(); + $fields = self::getFields(); } $r = DBA::select("photo", $fields, $conditions, $params); @@ -49,13 +53,14 @@ class Photo extends BaseObject /** * @brief Retrieve a single record from the photo table * - * @param array $fields Array of selected fields, empty for all - * @param array $conditions Array of fields for conditions - * @param array $params Array of several parameters + * @param array $fields Array of selected fields, empty for all + * @param array $conditions Array of fields for conditions + * @param array $params Array of several parameters * * @return bool|array * - * @see \Friendica\Database\DBA::select + * @throws \Exception + * @see \Friendica\Database\DBA::select */ public static function selectFirst(array $fields = [], array $conditions = [], array $params = []) { @@ -66,6 +71,50 @@ class Photo extends BaseObject return DBA::selectFirst("photo", $fields, $conditions, $params); } + /** + * @brief Get photos for user id + * + * @param integer $uid User id + * @param string $resourceid Rescource ID of the photo + * @param array $conditions Array of fields for conditions + * @param array $params Array of several parameters + * + * @return bool|array + * + * @throws \Exception + * @see \Friendica\Database\DBA::select + */ + public static function getPhotosForUser($uid, $resourceid, array $conditions = [], array $params = []) + { + $conditions["resource-id"] = $resourceid; + $conditions["uid"] = $uid; + + return self::select([], $conditions, $params); + } + + /** + * @brief Get a photo for user id + * + * @param integer $uid User id + * @param string $resourceid Rescource ID of the photo + * @param integer $scale Scale of the photo. Defaults to 0 + * @param array $conditions Array of fields for conditions + * @param array $params Array of several parameters + * + * @return bool|array + * + * @throws \Exception + * @see \Friendica\Database\DBA::select + */ + public static function getPhotoForUser($uid, $resourceid, $scale = 0, array $conditions = [], array $params = []) + { + $conditions["resource-id"] = $resourceid; + $conditions["uid"] = $uid; + $conditions["scale"] = $scale; + + return self::selectFirst([], $conditions, $params); + } + /** * @brief Get a single photo given resource id and scale * @@ -73,19 +122,31 @@ class Photo extends BaseObject * on success, "no sign" image info, if user has no permission, * false if photo does not exists * - * @param string $resourceid Rescource ID for the photo - * @param integer $scale Scale of the photo. Defaults to 0 + * @param string $resourceid Rescource ID of the photo + * @param integer $scale Scale of the photo. Defaults to 0 * * @return boolean|array + * @throws \Exception */ public static function getPhoto($resourceid, $scale = 0) { - $r = self::selectFirst(["uid"], ["resource-id" => $resourceid]); + $r = self::selectFirst(["uid", "allow_cid", "allow_gid", "deny_cid", "deny_gid"], ["resource-id" => $resourceid]); if ($r === false) { return false; } + $uid = $r["uid"]; + + // This is the first place, when retrieving just a photo, that we know who owns the photo. + // Check if the photo is public (empty allow and deny means public), if so, skip auth attempt, if not + // make sure that the requester's session is appropriately authenticated to that user + // otherwise permissions checks done by getPermissionsSQLByUserId() won't work correctly + if (!empty($r["allow_cid"]) || !empty($r["allow_gid"]) || !empty($r["deny_cid"]) || !empty($r["deny_gid"])) { + $r = DBA::selectFirst("user", ["nickname"], ["uid" => $uid], []); + // this will either just return (if auth all ok) or will redirect and exit (starting over) + DFRN::autoRedir(self::getApp(), $r["nickname"]); + } - $sql_acl = Security::getPermissionsSQLByUserId($r["uid"]); + $sql_acl = Security::getPermissionsSQLByUserId($uid); $conditions = [ "`resource-id` = ? AND `scale` <= ? " . $sql_acl, @@ -95,37 +156,40 @@ class Photo extends BaseObject $params = ["order" => ["scale" => true]]; $photo = self::selectFirst([], $conditions, $params); - if ($photo === false) { - return self::createPhotoForSystemResource("images/nosign.jpg"); - } + return $photo; } /** - * @brief Check if photo with given resource id exists + * @brief Check if photo with given conditions exists * - * @param string $resourceid Resource ID of the photo + * @param array $conditions Array of extra conditions * * @return boolean + * @throws \Exception */ - public static function exists($resourceid) + public static function exists(array $conditions) { - return DBA::count("photo", ["resource-id" => $resourceid]) > 0; + return DBA::exists("photo", $conditions); } + /** * @brief Get Image object for given row id. null if row id does not exist * - * @param integer $id Row id + * @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 getImageForPhoto($photo) + public static function getImageForPhoto(array $photo) { $data = ""; + if ($photo["backend-class"] == "") { // legacy data storage in "data" column - $i = self::selectFirst(["data"], ["id"=>$photo["id"]]); + $i = self::selectFirst(["data"], ["id" => $photo["id"]]); if ($i === false) { return null; } @@ -139,6 +203,7 @@ class Photo extends BaseObject if ($data === "") { return null; } + return new Image($data, $photo["type"]); } @@ -146,10 +211,11 @@ class Photo extends BaseObject * @brief Return a list of fields that are associated with the photo table * * @return array field list + * @throws \Exception */ private static function getFields() { - $allfields = DBStructure::definition(false); + $allfields = DBStructure::definition(self::getApp()->getBasePath(), false); $fields = array_keys($allfields["photo"]["fields"]); array_splice($fields, array_search("data", $fields), 1); return $fields; @@ -158,20 +224,23 @@ class Photo extends BaseObject /** * @brief 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 $filename Image file name relative to code root + * @param string $mimetype Image mime type. Defaults to "image/jpeg" * * @return array + * @throws \Exception */ public static function createPhotoForSystemResource($filename, $mimetype = "image/jpeg") { $fields = self::getFields(); $values = array_fill(0, count($fields), ""); + $photo = array_combine($fields, $values); - $photo["backend-class"] = "\Friendica\Model\Storage\SystemResource"; + $photo["backend-class"] = Storage\SystemResource::class; $photo["backend-ref"] = $filename; $photo["type"] = $mimetype; $photo["cacheable"] = false; + return $photo; } @@ -179,21 +248,22 @@ class Photo extends BaseObject /** * @brief store photo metadata in db and binary in default backend * - * @param Image $Image image - * @param integer $uid uid - * @param integer $cid cid - * @param integer $rid rid - * @param string $filename filename - * @param string $album album name - * @param integer $scale scale - * @param integer $profile optional, default = 0 - * @param string $allow_cid optional, default = "" - * @param string $allow_gid optional, default = "" - * @param string $deny_cid optional, default = "" - * @param string $deny_gid optional, default = "" - * @param string $desc optional, default = "" + * @param Image $Image Image object with data + * @param integer $uid User ID + * @param integer $cid Contact ID + * @param integer $rid Resource ID + * @param string $filename Filename + * @param string $album Album name + * @param integer $scale Scale + * @param integer $profile Is a profile image? optional, default = 0 + * @param string $allow_cid Permissions, allowed contacts. optional, default = "" + * @param string $allow_gid Permissions, allowed groups. optional, default = "" + * @param string $deny_cid Permissions, denied contacts.optional, default = "" + * @param string $deny_gid Permissions, denied greoup.optional, default = "" + * @param string $desc Photo caption. optional, default = "" * * @return boolean True on success + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ public static function store(Image $Image, $uid, $cid, $rid, $filename, $album, $scale, $profile = 0, $allow_cid = "", $allow_gid = "", $deny_cid = "", $deny_gid = "", $desc = "") { @@ -204,21 +274,26 @@ class Photo extends BaseObject $guid = System::createGUID(); } - $existing_photo = self::selectFirst(["id", "backend-class", "backend-ref"], ["resource-id" => $rid, "uid" => $uid, "contact-id" => $cid, "scale" => $scale]); + $existing_photo = self::selectFirst(["id", "created", "backend-class", "backend-ref"], ["resource-id" => $rid, "uid" => $uid, "contact-id" => $cid, "scale" => $scale]); + $created = DateTimeFormat::utcNow(); + if (DBA::isResult($existing_photo)) { + $created = $existing_photo["created"]; + } // 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 = ""; $backend_ref = ""; - $backend_class = ""; + /** @var IStorage $backend_class */ if (DBA::isResult($existing_photo)) { $backend_ref = (string)$existing_photo["backend-ref"]; $backend_class = (string)$existing_photo["backend-class"]; } else { - $backend_class = Config::get("storage", "class", ""); + $backend_class = StorageManager::getBackend(); } + if ($backend_class === "") { $data = $Image->asString(); } else { @@ -231,7 +306,7 @@ class Photo extends BaseObject "contact-id" => $cid, "guid" => $guid, "resource-id" => $rid, - "created" => DateTimeFormat::utcNow(), + "created" => $created, "edited" => DateTimeFormat::utcNow(), "filename" => basename($filename), "type" => $Image->getType(), @@ -260,12 +335,25 @@ class Photo extends BaseObject return $r; } - public static function delete(array $conditions, $options = []) + + /** + * @brief Delete info from table and data from storage + * + * @param array $conditions Field condition(s) + * @param array $options Options array, Optional + * + * @return boolean + * + * @throws \Exception + * @see \Friendica\Database\DBA::delete + */ + public static function delete(array $conditions, array $options = []) { // get photo to delete data info $photos = self::select(["backend-class","backend-ref"], $conditions); - + foreach($photos as $photo) { + /** @var IStorage $backend_class */ $backend_class = (string)$photo["backend-class"]; if ($backend_class !== "") { $backend_class::delete($photo["backend-ref"]); @@ -275,12 +363,50 @@ class Photo extends BaseObject return DBA::delete("photo", $conditions, $options); } + /** + * @brief Update a photo + * + * @param array $fields Contains the fields that are updated + * @param array $conditions Condition array with the key values + * @param Image $img Image to update. Optional, default null. + * @param array|boolean $old_fields Array with the old field values that are about to be replaced (true = update on duplicate) + * + * @return boolean Was the update successfull? + * + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @see \Friendica\Database\DBA::update + */ + public static function update($fields, $conditions, Image $img = null, array $old_fields = []) + { + if (!is_null($img)) { + // get photo to update + $photos = self::select(["backend-class","backend-ref"], $conditions); + + foreach($photos as $photo) { + /** @var IStorage $backend_class */ + $backend_class = (string)$photo["backend-class"]; + if ($backend_class !== "") { + $fields["backend-ref"] = $backend_class::put($img->asString(), $photo["backend-ref"]); + } else { + $fields["data"] = $img->asString(); + } + } + $fields['updated'] = DateTimeFormat::utcNow(); + } + + $fields['edited'] = DateTimeFormat::utcNow(); + + return DBA::update("photo", $fields, $conditions, $old_fields); + } + /** * @param string $image_url Remote URL * @param integer $uid user id * @param integer $cid contact id * @param boolean $quit_on_error optional, default false * @return array + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ public static function importProfilePhoto($image_url, $uid, $cid, $quit_on_error = false) { @@ -299,13 +425,22 @@ class Photo extends BaseObject $photo_failure = false; $filename = basename($image_url); - $img_str = Network::fetchUrl($image_url, true); + if (!empty($image_url)) { + $ret = Network::curl($image_url, true); + $img_str = $ret->getBody(); + $type = $ret->getContentType(); + } else { + $img_str = ''; + } if ($quit_on_error && ($img_str == "")) { return false; } - $type = Image::guessType($image_url, true); + if (empty($type)) { + $type = Image::guessType($image_url, true); + } + $Image = new Image($img_str, $type); if ($Image->isValid()) { $Image->scaleToSquare(300); @@ -374,7 +509,7 @@ class Photo extends BaseObject } /** - * @param string $exifCoord coordinate + * @param array $exifCoord coordinate * @param string $hemi hemi * @return float */ @@ -417,6 +552,7 @@ class Photo extends BaseObject * @param bool $update Update the cache * * @return array Returns array of the photo albums + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ public static function getAlbums($uid, $update = false) { @@ -454,6 +590,7 @@ class Photo extends BaseObject /** * @param int $uid User id of the photos * @return void + * @throws \Exception */ public static function clearAlbumCache($uid) { @@ -465,9 +602,10 @@ class Photo extends BaseObject * Generate a unique photo ID. * * @return string + * @throws \Exception */ public static function newResource() { - return system::createGUID(32, false); + return System::createGUID(32, false); } }