]> git.mxchange.org Git - friendica.git/blob - src/Model/Attach.php
Merge pull request #8367 from annando/another-guid
[friendica.git] / src / Model / Attach.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2020, Friendica
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Model;
23
24 use Friendica\Core\System;
25 use Friendica\Database\DBA;
26 use Friendica\Database\DBStructure;
27 use Friendica\DI;
28 use Friendica\Object\Image;
29 use Friendica\Util\DateTimeFormat;
30 use Friendica\Util\Mimetype;
31 use Friendica\Util\Security;
32
33 /**
34  * Class to handle attach dabatase table
35  */
36 class Attach
37 {
38
39         /**
40          * Return a list of fields that are associated with the attach table
41          *
42          * @return array field list
43          * @throws \Exception
44          */
45         private static function getFields()
46         {
47                 $allfields = DBStructure::definition(DI::app()->getBasePath(), false);
48                 $fields = array_keys($allfields['attach']['fields']);
49                 array_splice($fields, array_search('data', $fields), 1);
50                 return $fields;
51         }
52
53         /**
54          * Select rows from the attach table and return them as array
55          *
56          * @param array $fields     Array of selected fields, empty for all
57          * @param array $conditions Array of fields for conditions
58          * @param array $params     Array of several parameters
59          *
60          * @return array
61          *
62          * @throws \Exception
63          * @see   \Friendica\Database\DBA::selectToArray
64          */
65         public static function selectToArray(array $fields = [], array $conditions = [], array $params = [])
66         {
67                 if (empty($fields)) {
68                         $fields = self::getFields();
69                 }
70
71                 return DBA::selectToArray('attach', $fields, $conditions, $params);
72         }
73
74         /**
75          * Retrieve a single record from the attach table
76          *
77          * @param array $fields     Array of selected fields, empty for all
78          * @param array $conditions Array of fields for conditions
79          * @param array $params     Array of several parameters
80          *
81          * @return bool|array
82          *
83          * @throws \Exception
84          * @see   \Friendica\Database\DBA::select
85          */
86         public static function selectFirst(array $fields = [], array $conditions = [], array $params = [])
87         {
88                 if (empty($fields)) {
89                         $fields = self::getFields();
90                 }
91
92                 return DBA::selectFirst('attach', $fields, $conditions, $params);
93         }
94
95         /**
96          * Check if attachment with given conditions exists
97          *
98          * @param array $conditions Array of extra conditions
99          *
100          * @return boolean
101          * @throws \Exception
102          */
103         public static function exists(array $conditions)
104         {
105                 return DBA::exists('attach', $conditions);
106         }
107
108         /**
109          * Retrive a single record given the ID
110          *
111          * @param int $id Row id of the record
112          *
113          * @return bool|array
114          *
115          * @throws \Exception
116          * @see   \Friendica\Database\DBA::select
117          */
118         public static function getById($id)
119         {
120                 return self::selectFirst([], ['id' => $id]);
121         }
122
123         /**
124          * Retrive a single record given the ID
125          *
126          * @param int $id Row id of the record
127          *
128          * @return bool|array
129          *
130          * @throws \Exception
131          * @see   \Friendica\Database\DBA::select
132          */
133         public static function getByIdWithPermission($id)
134         {
135                 $r = self::selectFirst(['uid'], ['id' => $id]);
136                 if ($r === false) {
137                         return false;
138                 }
139
140                 $sql_acl = Security::getPermissionsSQLByUserId($r['uid']);
141
142                 $conditions = [
143                         '`id` = ?' . $sql_acl,
144                         $id
145                 ];
146
147                 $item = self::selectFirst([], $conditions);
148
149                 return $item;
150         }
151
152         /**
153          * Get file data for given row id. null if row id does not exist
154          *
155          * @param array $item Attachment data. Needs at least 'id', 'backend-class', 'backend-ref'
156          *
157          * @return string  file data
158          * @throws \Exception
159          */
160         public static function getData($item)
161         {
162                 $backendClass = DI::storageManager()->getByName($photo['backend-class'] ?? '');
163                 if ($backendClass === null) {
164                         // legacy data storage in 'data' column
165                         $i = self::selectFirst(['data'], ['id' => $item['id']]);
166                         if ($i === false) {
167                                 return null;
168                         }
169                         return $i['data'];
170                 } else {
171                         $backendRef = $item['backend-ref'];
172                         return $backendClass->get($backendRef);
173                 }
174         }
175
176         /**
177          * Store new file metadata in db and binary in default backend
178          *
179          * @param string  $data      Binary data
180          * @param integer $uid       User ID
181          * @param string  $filename  Filename
182          * @param string  $filetype  Mimetype. optional, default = ''
183          * @param integer $filesize  File size in bytes. optional, default = null
184          * @param string  $allow_cid Permissions, allowed contacts. optional, default = ''
185          * @param string  $allow_gid Permissions, allowed groups. optional, default = ''
186          * @param string  $deny_cid  Permissions, denied contacts.optional, default = ''
187          * @param string  $deny_gid  Permissions, denied greoup.optional, default = ''
188          *
189          * @return boolean/integer Row id on success, False on errors
190          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
191          */
192         public static function store($data, $uid, $filename, $filetype = '' , $filesize = null, $allow_cid = '', $allow_gid = '', $deny_cid = '', $deny_gid = '')
193         {
194                 if ($filetype === '') {
195                         $filetype = Mimetype::getContentType($filename);
196                 }
197
198                 if (is_null($filesize)) {
199                         $filesize = strlen($data);
200                 }
201
202                 $backend_ref = DI::storage()->put($data);
203                 $data = '';
204
205                 $hash = System::createGUID(64);
206                 $created = DateTimeFormat::utcNow();
207
208                 $fields = [
209                         'uid' => $uid,
210                         'hash' => $hash,
211                         'filename' => $filename,
212                         'filetype' => $filetype,
213                         'filesize' => $filesize,
214                         'data' => $data,
215                         'created' => $created,
216                         'edited' => $created,
217                         'allow_cid' => $allow_cid,
218                         'allow_gid' => $allow_gid,
219                         'deny_cid' => $deny_cid,
220                         'deny_gid' => $deny_gid,
221                         'backend-class' => (string)DI::storage(),
222                         'backend-ref' => $backend_ref
223                 ];
224
225                 $r = DBA::insert('attach', $fields);
226                 if ($r === true) {
227                         return DBA::lastInsertId();
228                 }
229                 return $r;
230         }
231
232         /**
233          * Store new file metadata in db and binary in default backend from existing file
234          *
235          * @param        $src
236          * @param        $uid
237          * @param string $filename
238          * @param string $allow_cid
239          * @param string $allow_gid
240          * @param string $deny_cid
241          * @param string $deny_gid
242          * @return boolean True on success
243          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
244          */
245         public static function storeFile($src, $uid, $filename = '', $allow_cid = '', $allow_gid = '', $deny_cid = '', $deny_gid = '')
246         {
247                 if ($filename === '') {
248                         $filename = basename($src);
249                 }
250
251                 $data = @file_get_contents($src);
252
253                 return self::store($data, $uid, $filename, '', null, $allow_cid, $allow_gid,  $deny_cid, $deny_gid);
254         }
255
256
257         /**
258          * Update an attached file
259          *
260          * @param array         $fields     Contains the fields that are updated
261          * @param array         $conditions Condition array with the key values
262          * @param Image         $img        Image data to update. Optional, default null.
263          * @param array|boolean $old_fields Array with the old field values that are about to be replaced (true = update on duplicate)
264          *
265          * @return boolean  Was the update successful?
266          *
267          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
268          * @see   \Friendica\Database\DBA::update
269          */
270         public static function update($fields, $conditions, Image $img = null, array $old_fields = [])
271         {
272                 if (!is_null($img)) {
273                         // get items to update
274                         $items = self::selectToArray(['backend-class','backend-ref'], $conditions);
275
276                         foreach($items as $item) {
277                                 $backend_class = DI::storageManager()->getByName($item['backend-class'] ?? '');
278                                 if ($backend_class !== null) {
279                                         $fields['backend-ref'] = $backend_class->put($img->asString(), $item['backend-ref'] ?? '');
280                                 } else {
281                                         $fields['data'] = $img->asString();
282                                 }
283                         }
284                 }
285
286                 $fields['edited'] = DateTimeFormat::utcNow();
287
288                 return DBA::update('attach', $fields, $conditions, $old_fields);
289         }
290
291
292         /**
293          * Delete info from table and data from storage
294          *
295          * @param array $conditions Field condition(s)
296          * @param array $options    Options array, Optional
297          *
298          * @return boolean
299          *
300          * @throws \Exception
301          * @see   \Friendica\Database\DBA::delete
302          */
303         public static function delete(array $conditions, array $options = [])
304         {
305                 // get items to delete data info
306                 $items = self::selectToArray(['backend-class','backend-ref'], $conditions);
307
308                 foreach($items as $item) {
309                         $backend_class = DI::storageManager()->getByName($item['backend-class'] ?? '');
310                         if ($backend_class !== null) {
311                                 $backend_class->delete($item['backend-ref'] ?? '');
312                         }
313                 }
314
315                 return DBA::delete('attach', $conditions, $options);
316         }
317 }