X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModel%2FPhoto.php;h=34a5acfc9f3694d4e35fce63587aa870b147bd1e;hb=1ddd2df4b89f397657cfe38b1154086d900cffa5;hp=1b308794566fdfcf1c02c51d4d599df297d3de83;hpb=15a3fc05d35ce957bc9663c8ed9819f1cf5c22c6;p=friendica.git diff --git a/src/Model/Photo.php b/src/Model/Photo.php index 1b30879456..34a5acfc9f 100644 --- a/src/Model/Photo.php +++ b/src/Model/Photo.php @@ -10,14 +10,18 @@ use Friendica\BaseObject; use Friendica\Core\Cache; use Friendica\Core\Config; use Friendica\Core\L10n; -use Friendica\Core\System; +use Friendica\Core\Logger; 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; +use Friendica\Util\Strings; require_once "include/dba.php"; @@ -27,36 +31,37 @@ require_once "include/dba.php"; class Photo extends BaseObject { /** - * @brief Select rows from the photo table + * @brief Select rows from the photo table and returns them as array * - * @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::selectToArray */ - public static function select(array $fields = [], array $conditions = [], array $params = []) + public static function selectToArray(array $fields = [], array $conditions = [], array $params = []) { if (empty($fields)) { - $selected = self::getFields(); + $fields = self::getFields(); } - $r = DBA::select("photo", $fields, $conditions, $params); - return DBA::toArray($r); + return DBA::selectToArray('photo', $fields, $conditions, $params); } /** * @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 = []) { @@ -70,35 +75,37 @@ class Photo extends BaseObject /** * @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 + * @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 * - * @see \Friendica\Database\DBA::select + * @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); + return self::selectToArray([], $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 + * @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 * - * @see \Friendica\Database\DBA::select + * @throws \Exception + * @see \Friendica\Database\DBA::select */ public static function getPhotoForUser($uid, $resourceid, $scale = 0, array $conditions = [], array $params = []) { @@ -116,65 +123,57 @@ 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 of 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]); - if ($r === false) { + if (!DBA::isResult($r)) { return false; } - $sql_acl = Security::getPermissionsSQLByUserId($r["uid"]); + $uid = $r["uid"]; - $conditions = [ - "`resource-id` = ? AND `scale` <= ? " . $sql_acl, - $resourceid, $scale - ]; + $sql_acl = Security::getPermissionsSQLByUserId($uid); + $conditions = ["`resource-id` = ? AND `scale` <= ? " . $sql_acl, $resourceid, $scale]; $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. Optional + * @param array $conditions Array of extra conditions * * @return boolean + * @throws \Exception */ - public static function exists($resourceid, array $conditions = []) + public static function exists(array $conditions) { - if (!is_null($resourceid)) { - $conditions["resource-id"] = $resourceid; - } - if (count($conditions) == 0) { - // no conditions defined. return false - return false; - } - return DBA::count("photo", $conditions) > 0; + return DBA::exists("photo", $conditions); } /** * @brief Get Image object for given row id. null if row id does not exist * - * @param array $photo Photo data. Needs at least 'id', 'type', 'backend-class', 'backend-ref' + * @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(array $photo) { $data = ""; + if ($photo["backend-class"] == "") { // legacy data storage in "data" column $i = self::selectFirst(["data"], ["id" => $photo["id"]]); @@ -191,6 +190,7 @@ class Photo extends BaseObject if ($data === "") { return null; } + return new Image($data, $photo["type"]); } @@ -198,10 +198,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; @@ -210,20 +211,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::class; + $photo["backend-class"] = Storage\SystemResource::class; $photo["backend-ref"] = $filename; $photo["type"] = $mimetype; $photo["cacheable"] = false; + return $photo; } @@ -246,6 +250,7 @@ class Photo extends BaseObject * @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 = "") { @@ -267,14 +272,15 @@ class Photo extends BaseObject // 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 = StorageManager::getBackend(); } + if ($backend_class === "") { $data = $Image->asString(); } else { @@ -316,22 +322,25 @@ class Photo extends BaseObject return $r; } + /** * @brief Delete info from table and data from storage * - * @param array $conditions Field condition(s) - * @param array $options Options array, Optional + * @param array $conditions Field condition(s) + * @param array $options Options array, Optional * * @return boolean * - * @see \Friendica\Database\DBA::delete + * @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); + $photos = self::selectToArray(['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"]); @@ -351,15 +360,17 @@ class Photo extends BaseObject * * @return boolean Was the update successfull? * - * @see \Friendica\Database\DBA::update + * @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); + $photos = self::selectToArray(['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"]); @@ -372,7 +383,7 @@ class Photo extends BaseObject $fields['edited'] = DateTimeFormat::utcNow(); - return DBA::update("photo", $fields, $conditions); + return DBA::update("photo", $fields, $conditions, $old_fields); } /** @@ -381,6 +392,8 @@ class Photo extends BaseObject * @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) { @@ -399,13 +412,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); @@ -474,7 +496,7 @@ class Photo extends BaseObject } /** - * @param string $exifCoord coordinate + * @param array $exifCoord coordinate * @param string $hemi hemi * @return float */ @@ -517,6 +539,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) { @@ -554,6 +577,7 @@ class Photo extends BaseObject /** * @param int $uid User id of the photos * @return void + * @throws \Exception */ public static function clearAlbumCache($uid) { @@ -565,9 +589,130 @@ class Photo extends BaseObject * Generate a unique photo ID. * * @return string + * @throws \Exception */ public static function newResource() { return System::createGUID(32, false); } + + /** + * Changes photo permissions that had been embedded in a post + * + * @todo This function currently does have some flaws: + * - Sharing a post with a forum will create a photo that only the forum can see. + * - Sharing a photo again that been shared non public before doesn't alter the permissions. + * + * @return string + * @throws \Exception + */ + public static function setPermissionFromBody($body, $uid, $original_contact_id, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny) + { + // Simplify image codes + $img_body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body); + $img_body = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", '[img]$1[/img]', $img_body); + + // Search for images + if (!preg_match_all("/\[img\](.*?)\[\/img\]/", $img_body, $match)) { + return false; + } + $images = $match[1]; + if (empty($images)) { + return false; + } + + foreach ($images as $image) { + if (!stristr($image, System::baseUrl() . '/photo/')) { + continue; + } + $image_uri = substr($image,strrpos($image,'/') + 1); + $image_uri = substr($image_uri,0, strpos($image_uri,'-')); + if (!strlen($image_uri)) { + continue; + } + + // Ensure to only modify photos that you own + $srch = '<' . intval($original_contact_id) . '>'; + + $condition = [ + 'allow_cid' => $srch, 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '', + 'resource-id' => $image_uri, 'uid' => $uid + ]; + if (!Photo::exists($condition)) { + continue; + } + + /// @todo Check if $str_contact_allow does contain a public forum. Then set the permissions to public. + + $fields = ['allow_cid' => $str_contact_allow, 'allow_gid' => $str_group_allow, + 'deny_cid' => $str_contact_deny, 'deny_gid' => $str_group_deny]; + $condition = ['resource-id' => $image_uri, 'uid' => $uid]; + Logger::info('Set permissions', ['condition' => $condition, 'permissions' => $fields]); + Photo::update($fields, $condition); + } + + return true; + } + + /** + * Strips known picture extensions from picture links + * + * @param string $name Picture link + * @return string stripped picture link + * @throws \Exception + */ + public static function stripExtension($name) + { + $name = str_replace([".jpg", ".png", ".gif"], ["", "", ""], $name); + foreach (Image::supportedTypes() as $m => $e) { + $name = str_replace("." . $e, "", $name); + } + return $name; + } + + /** + * Returns the GUID from picture links + * + * @param string $name Picture link + * @return string GUID + * @throws \Exception + */ + public static function getGUID($name) + { + $a = \get_app(); + $base = $a->getBaseURL(); + + $guid = str_replace([Strings::normaliseLink($base), '/photo/'], '', Strings::normaliseLink($name)); + + $guid = self::stripExtension($guid); + if (substr($guid, -2, 1) != "-") { + return ''; + } + + $scale = intval(substr($guid, -1, 1)); + if (empty($scale)) { + return ''; + } + + $guid = substr($guid, 0, -2); + return $guid; + } + + /** + * Tests if the picture link points to a locally stored picture + * + * @param string $name Picture link + * @return boolean + * @throws \Exception + */ + public static function isLocal($name) + { + $guid = self::getGUID($name); + + if (empty($guid)) { + return false; + } + + return DBA::exists('photo', ['resource-id' => $guid]); + } }