From 1c5b210d0d4ce7b5fcb1fd149228a73ac7da4ab6 Mon Sep 17 00:00:00 2001 From: zotlabs Date: Tue, 5 May 2020 21:34:31 -0700 Subject: [PATCH] several issues plus some cleanup --- Zotlabs/Lib/LDSignatures.php | 3 +- Zotlabs/Module/Dav.php | 8 +- Zotlabs/Module/Item.php | 2 +- Zotlabs/Storage/BasicAuth.php | 11 ++ Zotlabs/Storage/Directory.php | 203 +++++++++++++++++++--------------- Zotlabs/Storage/File.php | 128 +++++++++++++-------- boot.php | 9 +- include/attach.php | 3 +- include/photo_factory.php | 136 ++++++++++++----------- include/photos.php | 2 +- 10 files changed, 289 insertions(+), 216 deletions(-) diff --git a/Zotlabs/Lib/LDSignatures.php b/Zotlabs/Lib/LDSignatures.php index 6725cf383..b5c2d213c 100644 --- a/Zotlabs/Lib/LDSignatures.php +++ b/Zotlabs/Lib/LDSignatures.php @@ -95,7 +95,8 @@ class LDSignatures { $d = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]); } catch (\Exception $e) { - logger('normalise error:' . print_r($e,true)); + // Don't log the exception - this can exhaust memory + // logger('normalise error:' . print_r($e,true)); logger('normalise error: ' . print_r($data,true)); } diff --git a/Zotlabs/Module/Dav.php b/Zotlabs/Module/Dav.php index 8656eb7a4..55c6844ad 100644 --- a/Zotlabs/Module/Dav.php +++ b/Zotlabs/Module/Dav.php @@ -1,4 +1,6 @@ observer = get_observer_hash(); - +// $auth->observer = get_observer_hash(); + $auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . ' ' . 'WebDAV'); $rootDirectory = new \Zotlabs\Storage\Directory('/', $auth); diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index 19dd3e175..8cab7fb1b 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -856,7 +856,7 @@ class Item extends Controller { if($cnt) { $summary .= $match[1]; } - $body_content = preg_replace("/^(.*?)\[summary\](.*?)\[\/summary\](.*?)$/ism", '',$body); + $body_content = preg_replace("/^(.*?)\[summary\](.*?)\[\/summary\]/ism", '',$body); $body = trim($body_content); } diff --git a/Zotlabs/Storage/BasicAuth.php b/Zotlabs/Storage/BasicAuth.php index 851d022d4..5e08d649c 100644 --- a/Zotlabs/Storage/BasicAuth.php +++ b/Zotlabs/Storage/BasicAuth.php @@ -2,6 +2,7 @@ namespace Zotlabs\Storage; +use App; use Sabre\DAV; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; @@ -128,6 +129,16 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic { $this->channel_name = $r['channel_address']; $this->channel_id = $r['channel_id']; $this->channel_hash = $this->observer = $r['channel_hash']; + + if ($this->observer) { + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($this->observer) + ); + if ($r) { + App::set_observer(array_shift($r)); + } + } + $_SESSION['uid'] = $r['channel_id']; $_SESSION['account_id'] = $r['channel_account_id']; $_SESSION['authenticated'] = true; diff --git a/Zotlabs/Storage/Directory.php b/Zotlabs/Storage/Directory.php index 8eef71aa2..3e589b2b2 100644 --- a/Zotlabs/Storage/Directory.php +++ b/Zotlabs/Storage/Directory.php @@ -2,8 +2,13 @@ namespace Zotlabs\Storage; +use App; use Sabre\DAV; use Zotlabs\Lib\Libsync; +use Zotlabs\Daemon\Master; + + +require_once('include/photos.php'); /** * @brief RedDirectory class. @@ -14,7 +19,6 @@ use Zotlabs\Lib\Libsync; * @implements \\Sabre\\DAV\\ICollection * @implements \\Sabre\\DAV\\IQuota * - * @link http://github.com/friendica/red * @license http://opensource.org/licenses/mit-license.php The MIT License (MIT) */ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMoveTarget { @@ -54,9 +58,9 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo logger('directory ' . $ext_path, LOGGER_DATA); $this->ext_path = $ext_path; // remove "/cloud" from the beginning of the path - $modulename = \App::$module; + $modulename = App::$module; $this->red_path = ((strpos($ext_path, '/' . $modulename) === 0) ? substr($ext_path, strlen($modulename) + 1) : $ext_path); - if(! $this->red_path) { + if (! $this->red_path) { $this->red_path = '/'; } $this->auth = $auth_plugin; @@ -114,7 +118,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo throw new DAV\Exception\Forbidden('Permission denied.'); } - $modulename = \App::$module; + $modulename = App::$module; if ($this->red_path === '/' && $name === $modulename) { return new Directory('/' . $modulename, $this->auth); } @@ -133,7 +137,6 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo * @return string */ public function getName() { - //logger(basename($this->red_path), LOGGER_DATA); return (basename($this->red_path)); } @@ -179,8 +182,9 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo $ch = channelx_by_n($this->auth->owner_id); if ($ch) { $sync = attach_export_data($ch, $this->folder_hash); - if ($sync) + if ($sync) { Libsync::build_sync_packet($ch['channel_id'], array('file' => array($sync))); + } } $this->red_path = $new_path; @@ -215,11 +219,9 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo $mimetype = z_mime_content_type($name); - $c = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1", - intval($this->auth->owner_id) - ); + $channel = channelx_by_n($this->auth->owner_id); - if (! $c) { + if (! $channel) { logger('no channel'); throw new DAV\Exception\Forbidden('Permission denied.'); } @@ -234,29 +236,32 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo if ($this->folder_hash) { $r = q("select * from attach where hash = '%s' and is_dir = 1 and uid = %d limit 1", dbesc($this->folder_hash), - intval($c[0]['channel_id']) + intval($channel['channel_id']) ); - if ($r) - $direct = $r[0]; + if ($r) { + $direct = array_shift($r); + } } if (($direct) && (($direct['allow_cid']) || ($direct['allow_gid']) || ($direct['deny_cid']) || ($direct['deny_gid']))) { $allow_cid = $direct['allow_cid']; $allow_gid = $direct['allow_gid']; - $deny_cid = $direct['deny_cid']; - $deny_gid = $direct['deny_gid']; + $deny_cid = $direct['deny_cid']; + $deny_gid = $direct['deny_gid']; } else { - $allow_cid = $c[0]['channel_allow_cid']; - $allow_gid = $c[0]['channel_allow_gid']; - $deny_cid = $c[0]['channel_deny_cid']; - $deny_gid = $c[0]['channel_deny_gid']; + $allow_cid = $channel['channel_allow_cid']; + $allow_gid = $channel['channel_allow_gid']; + $deny_cid = $channel['channel_deny_cid']; + $deny_gid = $channel['channel_deny_gid']; } + $created = $edited = datetime_convert(); + $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, folder, os_storage, filetype, filesize, revision, is_photo, content, created, edited, os_path, display_path, allow_cid, allow_gid, deny_cid, deny_gid ) VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", - intval($c[0]['channel_account_id']), - intval($c[0]['channel_id']), + intval($channel['channel_account_id']), + intval($channel['channel_id']), dbesc($hash), dbesc($this->auth->observer), dbesc($name), @@ -265,10 +270,10 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo dbesc($mimetype), intval($filesize), intval(0), - intval($is_photo), + intval(0), dbesc($f), - dbesc(datetime_convert()), - dbesc(datetime_convert()), + dbesc($created), + dbesc($edited), '', '', dbesc($allow_cid), @@ -281,95 +286,111 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo $xpath = attach_syspaths($this->auth->owner_id, $hash); - // returns the number of bytes that were written to the file, or FALSE on failure - $size = file_put_contents($f, $data); + if (is_resource($data)) { + $fp = fopen($f,'wb'); + if ($fp) { + pipe_streams($data,$fp); + fclose($fp); + } + $size = filesize($f); + } + else { + $size = file_put_contents($f, $data); + } + // delete attach entry if file_put_contents() failed if ($size === false) { logger('file_put_contents() failed to ' . $f); - attach_delete($c[0]['channel_id'], $hash); + attach_delete($channel['channel_id'], $hash); return; } - // returns now - $edited = datetime_convert(); - $is_photo = 0; $gis = @getimagesize($f); logger('getimagesize: ' . print_r($gis,true), LOGGER_DATA); - if (($gis) && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG)) { + if (($gis) && supported_imagetype($gis[2])) { $is_photo = 1; } // If we know it's a photo, over-ride the type in case the source system could not determine what it was - if($is_photo) { + if ($is_photo) { q("update attach set filetype = '%s' where hash = '%s' and uid = %d", dbesc($gis['mime']), dbesc($hash), - intval($c[0]['channel_id']) + intval($channel['channel_id']) ); } - - // updates entry with filesize and timestamp - $d = q("UPDATE attach SET filesize = '%s', os_path = '%s', display_path = '%s', is_photo = %d, edited = '%s' WHERE hash = '%s' AND uid = %d", + // updates entry with path and filesize + $d = q("UPDATE attach SET filesize = '%s', os_path = '%s', display_path = '%s', is_photo = %d WHERE hash = '%s' AND uid = %d", dbesc($size), dbesc($xpath['os_path']), - dbesc($xpath['display_path']), + dbesc($xpath['path']), intval($is_photo), - dbesc($edited), dbesc($hash), - intval($c[0]['channel_id']) + intval($channel['channel_id']) ); - // update the folder's lastmodified timestamp + // update the parent folder's lastmodified timestamp $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d", dbesc($edited), dbesc($this->folder_hash), - intval($c[0]['channel_id']) + intval($channel['channel_id']) ); $maxfilesize = get_config('system', 'maxfilesize'); if (($maxfilesize) && ($size > $maxfilesize)) { - attach_delete($c[0]['channel_id'], $hash); + logger('system maxfilesize exceeded. Deleting uploaded file.'); + attach_delete($channel['channel_id'], $hash); return; } // check against service class quota - $limit = engr_units_to_bytes(service_class_fetch($c[0]['channel_id'], 'attach_upload_limit')); + $limit = engr_units_to_bytes(service_class_fetch($channel['channel_id'], 'attach_upload_limit')); if ($limit !== false) { $z = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d ", - intval($c[0]['channel_account_id']) + intval($channel['channel_account_id']) ); if (($z) && ($z[0]['total'] + $size > $limit)) { - logger('service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $z[0]['total'] . ' limit is ' . userReadableSize($limit)); - attach_delete($c[0]['channel_id'], $hash); + logger('service class limit exceeded for ' . $channel['channel_name'] . ' total usage is ' . $z[0]['total'] . ' limit is ' . userReadableSize($limit)); + attach_delete($channel['channel_id'], $hash); return; } } - if($is_photo) { + if ($is_photo) { $album = ''; if ($this->folder_hash) { $f1 = q("select filename, display_path from attach WHERE hash = '%s' AND uid = %d", dbesc($this->folder_hash), - intval($c[0]['channel_id']) + intval($channel['channel_id']) ); - if ($f1) + if ($f1) { $album = (($f1[0]['display_path']) ? $f1[0]['display_path'] : $f1[0]['filename']); + } } - require_once('include/photos.php'); - $args = array( 'resource_id' => $hash, 'album' => $album, 'os_syspath' => $f, 'os_path' => $xpath['os_path'], 'display_path' => $xpath['path'], 'filename' => $name, 'getimagesize' => $gis, 'directory' => $direct); - $p = photo_upload($c[0], \App::get_observer(), $args); + $args = [ + 'resource_id' => $hash, + 'album' => $album, + 'os_syspath' => $f, + 'os_path' => $xpath['os_path'], + 'display_path' => $xpath['path'], + 'filename' => $name, + 'getimagesize' => $gis, + 'directory' => $direct + ]; + $p = photo_upload($channel, App::get_observer(), $args); } - \Zotlabs\Daemon\Master::Summon([ 'Thumbnail' , $this->folder_hash ]); + Master::Summon([ 'Thumbnail' , $hash ]); - $sync = attach_export_data($c[0], $hash); + $sync = attach_export_data($channel, $hash); - if ($sync) - Libsync::build_sync_packet($c[0]['channel_id'], array('file' => array($sync))); + if ($sync) { + Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync))); + } } /** @@ -385,24 +406,22 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo throw new DAV\Exception\Forbidden('Permission denied.'); } - $r = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1", - intval($this->auth->owner_id) - ); + $channel = channelx_by_n($this->auth->owner_id); - if ($r) { + if ($channel) { // When initiated from DAV, set the 'force' flag on attach_mkdir(). This will cause the operation to report success even if the // folder already exists. require_once('include/attach.php'); - $result = attach_mkdir($r[0], $this->auth->observer, array('filename' => $name, 'folder' => $this->folder_hash, 'force' => true)); + $result = attach_mkdir($channel, $this->auth->observer, array('filename' => $name, 'folder' => $this->folder_hash, 'force' => true)); - if($result['success']) { - $sync = attach_export_data($r[0],$result['data']['hash']); + if ($result['success']) { + $sync = attach_export_data($channel,$result['data']['hash']); logger('createDirectory: attach_export_data returns $sync:' . print_r($sync, true), LOGGER_DEBUG); - if($sync) { - Libsync::build_sync_packet($r[0]['channel_id'], array('file' => array($sync))); + if ($sync) { + Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync))); } } else { @@ -429,11 +448,12 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo attach_delete($this->auth->owner_id, $this->folder_hash); - $ch = channelx_by_n($this->auth->owner_id); - if ($ch) { - $sync = attach_export_data($ch, $this->folder_hash, true); - if ($sync) - Libsync::build_sync_packet($ch['channel_id'], array('file' => array($sync))); + $channel = channelx_by_n($this->auth->owner_id); + if ($channel) { + $sync = attach_export_data($channel, $this->folder_hash, true); + if ($sync) { + Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync))); + } } } @@ -448,7 +468,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo public function childExists($name) { // On /cloud we show a list of available channels. // @todo what happens if no channels are available? - $modulename = \App::$module; + $modulename = App::$module; if ($this->red_path === '/' && $name === $modulename) { //logger('We are at ' $modulename . ' show a channel list', LOGGER_DEBUG); return true; @@ -456,16 +476,16 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo $x = $this->FileData($this->ext_path . '/' . $name, $this->auth, true); //logger('FileData returns: ' . print_r($x, true), LOGGER_DATA); - if ($x) + if ($x) { return true; - + } return false; } public function moveInto($targetName,$sourcePath, DAV\INode $sourceNode) { - if(! $this->auth->owner_id) { + if (! $this->auth->owner_id) { return false; } @@ -474,7 +494,6 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo } return attach_move($this->auth->owner_id, $sourceNode->data->hash, $this->folder_hash); - } @@ -488,7 +507,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo logger('GetDir: ' . $this->ext_path, LOGGER_DEBUG); $this->auth->log(); - $modulename = \App::$module; + $modulename = App::$module; $file = $this->ext_path; @@ -511,15 +530,13 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo $channel_name = $path_arr[0]; - $r = q("SELECT channel_id FROM channel WHERE channel_address = '%s' AND channel_removed = 0 LIMIT 1", - dbesc($channel_name) - ); + $channel = channelx_by_nick($channel_name); - if (! $r) { + if (! $channel) { throw new DAV\Exception\NotFound('The file with name: ' . $channel_name . ' could not be found.'); } - $channel_id = $r[0]['channel_id']; + $channel_id = $channel['channel_id']; $this->auth->owner_id = $channel_id; $this->auth->owner_nick = $channel_name; @@ -535,10 +552,10 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo ); if ($r && intval($r[0]['is_dir'])) { $folder = $r[0]['hash']; - if (strlen($os_path)) + if (strlen($os_path)) { $os_path .= '/'; + } $os_path .= $folder; - $path = $path . '/' . $r[0]['filename']; } } @@ -598,19 +615,19 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo $file = trim($file, '/'); $path_arr = explode('/', $file); - if (! $path_arr) + if (! $path_arr) { return null; + } $channel_name = $path_arr[0]; - $r = q("SELECT channel_id FROM channel WHERE channel_address = '%s' LIMIT 1", - dbesc($channel_name) - ); + $channel = channelx_by_nick($channel_name); - if (! $r) + if (! $channel) { return null; + } - $channel_id = $r[0]['channel_id']; + $channel_id = $channel['channel_id']; $perms = permissions_sql($channel_id); $auth->owner_id = $channel_id; @@ -687,17 +704,19 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo ); foreach ($r as $rr) { - if(\App::$module === 'cloud' && (strpos($rr['filename'],'.') === 0) && (! get_pconfig($channel_id,'system','show_dot_files')) ) + if (App::$module === 'cloud' && (strpos($rr['filename'],'.') === 0) && (! get_pconfig($channel_id,'system','show_dot_files')) ) { continue; + } // @FIXME I don't think we use revisions currently in attach structures. // In case we see any in the wild provide a unique filename. This // name may or may not be accessible - if($rr['revision']) + if ($rr['revision']) { $rr['filename'] .= '-' . $rr['revision']; + } - //logger('filename: ' . $rr['filename'], LOGGER_DEBUG); + // logger('filename: ' . $rr['filename'], LOGGER_DEBUG); if (intval($rr['is_dir'])) { $ret[] = new Directory($path . '/' . $rr['filename'], $auth); } diff --git a/Zotlabs/Storage/File.php b/Zotlabs/Storage/File.php index ddfea2ee4..0033c2fc9 100644 --- a/Zotlabs/Storage/File.php +++ b/Zotlabs/Storage/File.php @@ -2,8 +2,12 @@ namespace Zotlabs\Storage; +use App; use Sabre\DAV; use Zotlabs\Lib\Libsync; +use Zotlabs\Daemon\Master; + +require_once('include/photos.php'); /** * @brief This class represents a file in DAV. @@ -117,14 +121,22 @@ class File extends DAV\Node implements DAV\IFile { * @param resource $data * @return void */ + public function put($data) { logger('put file: ' . basename($this->name), LOGGER_DEBUG); $size = 0; - // @todo only 3 values are needed - $c = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1", - intval($this->auth->owner_id) - ); + + if ((! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) { + logger('permission denied for put operation'); + throw new DAV\Exception\Forbidden('Permission denied.'); + } + + $channel = channelx_by_n($this->auth->owner_id); + + if (! $channel) { + throw new DAV\Exception\Forbidden('Permission denied.'); + } $is_photo = false; $album = ''; @@ -135,22 +147,19 @@ class File extends DAV\Node implements DAV\IFile { // and delete from a networked operating system. In this case you are only allowed to over-write the file // if it is empty. Some DAV clients create the file and then store the contents so these would be allowed. - if(get_pconfig($this->auth->owner_id,'system','os_delete_prohibit') && \App::$module == 'dav') { + if (get_pconfig($this->auth->owner_id,'system','os_delete_prohibit') && App::$module == 'dav') { $r = q("select filesize from attach where hash = '%s' and uid = %d limit 1", dbesc($this->data['hash']), - intval($c[0]['channel_id']) + intval($channel['channel_id']) ); - if($r && intval($r[0]['filesize'])) { + if ($r && intval($r[0]['filesize'])) { throw new DAV\Exception\Forbidden('Permission denied.'); } } - - - $r = q("SELECT flags, folder, os_storage, os_path, display_path, filename, is_photo FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", dbesc($this->data['hash']), - intval($c[0]['channel_id']) + intval($channel['channel_id']) ); if ($r) { @@ -162,39 +171,51 @@ class File extends DAV\Node implements DAV\IFile { if (intval($r[0]['os_storage'])) { $d = q("select folder, content from attach where hash = '%s' and uid = %d limit 1", dbesc($this->data['hash']), - intval($c[0]['channel_id']) + intval($channel['channel_id']) ); - if($d) { - if($d[0]['folder']) { + if ($d) { + if ($d[0]['folder']) { $f1 = q("select * from attach where is_dir = 1 and hash = '%s' and uid = %d limit 1", dbesc($d[0]['folder']), - intval($c[0]['channel_id']) + intval($channel['channel_id']) ); - if($f1) { + if ($f1) { $album = $f1[0]['filename']; $direct = $f1[0]; } } $fname = dbunescbin($d[0]['content']); - if(strpos($fname,'store/') === false) + if (strpos($fname,'store/') === false) { $f = 'store/' . $this->auth->owner_nick . '/' . $fname ; - else + } + else { $f = $fname; + } + + if (is_resource($data)) { + $fp = fopen($f,'wb'); + if ($fp) { + pipe_streams($data,$fp); + fclose($fp); + } + } + else { + file_put_contents($f, $data); + } - // @todo check return value and set $size directly - @file_put_contents($f, $data); $size = @filesize($f); + logger('filename: ' . $f . ' size: ' . $size, LOGGER_DEBUG); } $gis = @getimagesize($f); logger('getimagesize: ' . print_r($gis,true), LOGGER_DATA); - if(($gis) && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG)) { + if ($gis && supported_imagetype($gis[2])) { $is_photo = 1; } // If we know it's a photo, over-ride the type in case the source system could not determine what it was - if($is_photo) { + if ($is_photo) { q("update attach set filetype = '%s' where hash = '%s' and uid = %d", dbesc($gis['mime']), dbesc($this->data['hash']), @@ -228,20 +249,29 @@ class File extends DAV\Node implements DAV\IFile { intval($is_photo), dbesc($edited), dbesc($this->data['hash']), - intval($c[0]['channel_id']) + intval($channel['channel_id']) ); - if($is_photo) { - require_once('include/photos.php'); - $args = array( 'resource_id' => $this->data['hash'], 'album' => $album, 'os_syspath' => $f, 'os_path' => $os_path, 'display_path' => $display_path, 'filename' => $filename, 'getimagesize' => $gis, 'directory' => $direct ); - $p = photo_upload($c[0],\App::get_observer(),$args); + if ($is_photo) { + $args = [ + 'resource_id' => $this->data['hash'], + 'album' => $album, + 'os_syspath' => $f, + 'os_path' => $os_path, + 'display_path' => $display_path, + 'filename' => $filename, + 'getimagesize' => $gis, + 'directory' => $direct + ]; + $p = photo_upload($channel, App::get_observer(), $args); + logger('photo_upload: ' . print_r($p,true), LOGGER_DATA); } // update the folder's lastmodified timestamp $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d", dbesc($edited), dbesc($r[0]['folder']), - intval($c[0]['channel_id']) + intval($channel['channel_id']) ); // @todo do we really want to remove the whole file if an update fails @@ -251,37 +281,37 @@ class File extends DAV\Node implements DAV\IFile { $maxfilesize = get_config('system', 'maxfilesize'); if (($maxfilesize) && ($size > $maxfilesize)) { - attach_delete($c[0]['channel_id'], $this->data['hash']); + attach_delete($channel['channel_id'], $this->data['hash']); return; } - $limit = engr_units_to_bytes(service_class_fetch($c[0]['channel_id'], 'attach_upload_limit')); + $limit = engr_units_to_bytes(service_class_fetch($channel['channel_id'], 'attach_upload_limit')); if ($limit !== false) { $x = q("select sum(filesize) as total from attach where aid = %d ", - intval($c[0]['channel_account_id']) + intval($channel['channel_account_id']) ); if (($x) && ($x[0]['total'] + $size > $limit)) { - logger('service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . userReadableSize($limit)); - attach_delete($c[0]['channel_id'], $this->data['hash']); + logger('service class limit exceeded for ' . $channel['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . userReadableSize($limit)); + attach_delete($channel['channel_id'], $this->data['hash']); return; } } - \Zotlabs\Daemon\Master::Summon([ 'Thumbnail' , $this->data['hash'] ]); + Master::Summon([ 'Thumbnail' , $this->data['hash'] ]); + $sync = attach_export_data($channel,$this->data['hash']); - $sync = attach_export_data($c[0],$this->data['hash']); - - if($sync) - Libsync::build_sync_packet($c[0]['channel_id'],array('file' => array($sync))); - + if ($sync) { + Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync))); + } } /** * @brief Returns the raw data. * - * @return string + * @return string || resource */ + public function get() { logger('get file ' . basename($this->name), LOGGER_DEBUG); logger('os_path: ' . $this->os_path, LOGGER_DATA); @@ -301,10 +331,12 @@ class File extends DAV\Node implements DAV\IFile { if (intval($r[0]['os_storage'])) { $x = dbunescbin($r[0]['content']); - if(strpos($x,'store') === false) + if (strpos($x,'store') === false) { $f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $x; - else + } + else { $f = $x; + } return @fopen($f, 'rb'); } return dbunescbin($r[0]['content']); @@ -362,6 +394,7 @@ class File extends DAV\Node implements DAV\IFile { * * @return int last modification time in UNIX timestamp */ + public function getLastModified() { return datetime_convert('UTC', 'UTC', $this->data['edited'], 'U'); } @@ -393,11 +426,12 @@ class File extends DAV\Node implements DAV\IFile { attach_delete($this->auth->owner_id, $this->data['hash']); - $ch = channelx_by_n($this->auth->owner_id); - if($ch) { - $sync = attach_export_data($ch, $this->data['hash'], true); - if($sync) - Libsync::build_sync_packet($ch['channel_id'], array('file' => array($sync))); + $channel = channelx_by_n($this->auth->owner_id); + if ($channel) { + $sync = attach_export_data($channel, $this->data['hash'], true); + if ($sync) { + Libsync::build_sync_packet($channel['channel_id'], [ 'file' => [ $sync ] ]); + } } } } diff --git a/boot.php b/boot.php index a6009d51f..6ab3b63b9 100755 --- a/boot.php +++ b/boot.php @@ -16,7 +16,7 @@ use Zotlabs\Daemon\Master; * @brief This file defines some global constants and includes the central App class. */ -define ( 'STD_VERSION', '20.05.04' ); +define ( 'STD_VERSION', '20.05.06' ); define ( 'ZOT_REVISION', '6.0' ); define ( 'DB_UPDATE_VERSION', 1239 ); @@ -2042,9 +2042,9 @@ function dba_timer() { */ function get_observer_hash() { $observer = App::get_observer(); - if(is_array($observer)) + if (is_array($observer)) { return $observer['xchan_hash']; - + } return ''; } @@ -2527,3 +2527,6 @@ function get_safemode() { return intval($_SESSION['safemode']); } +function supported_imagetype($x) { + return in_array($x, [ IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_WEBP ]); +} \ No newline at end of file diff --git a/include/attach.php b/include/attach.php index 7cdfa1756..c0dc8beb7 100644 --- a/include/attach.php +++ b/include/attach.php @@ -2577,8 +2577,9 @@ function attach_syspaths($channel_id,$attach_hash) { dbesc($attach_hash), intval($channel_id) ); - if(! $r) + if (! $r) { break; + } $os_path = $r[0]['hash'] . (($os_path) ? '/' . $os_path : ''); $path = $r[0]['filename'] . (($path) ? '/' . $path : ''); diff --git a/include/photo_factory.php b/include/photo_factory.php index c11580bdc..f49324fde 100644 --- a/include/photo_factory.php +++ b/include/photo_factory.php @@ -188,129 +188,131 @@ function delete_thing_photo($url, $ob_hash) { * * \e string \b 5 => modification date */ function import_xchan_photo($photo, $xchan, $thing = false, $force = false) { - $modified = ''; - $o = null; - - $flags = (($thing) ? PHOTO_THING : PHOTO_XCHAN); - $album = (($thing) ? 'Things' : 'Contact Photos'); logger('Updating channel photo from ' . $photo . ' for ' . $xchan, LOGGER_DEBUG); - if($thing) { - $hash = photo_new_resource(); - } else { - $r = q("select resource_id, edited, mimetype from photo where xchan = '%s' and photo_usage = %d and imgscale = 4 limit 1", dbesc($xchan), intval(PHOTO_XCHAN)); - if($r) { - $hash = $r[0]['resource_id']; - $modified = $r[0]['edited']; - $type = $r[0]['mimetype']; - } else { - $hash = photo_new_resource(); + $flags = (($thing) ? PHOTO_THING : PHOTO_XCHAN); + $album = (($thing) ? 'Things' : 'Contact Photos'); + $modified = EMPTY_STR; + $o = null; + $failed = true; + $img_str = EMPTY_STR; + $hash = photo_new_resource(); + + if (! $thing) { + $r = q("select resource_id, edited, mimetype from photo where xchan = '%s' and photo_usage = %d and imgscale = 4 limit 1", + dbesc($xchan), + intval(PHOTO_XCHAN) + ); + if ($r) { + $r = array_shift($r); + $hash = $r['resource_id']; + $modified = $r['edited']; + $type = $r['mimetype']; } } - $photo_failure = false; - $img_str = ''; - if($photo) { + if ($photo) { - if($force || $modified == '') { + if ($modified === EMPTY_STR || $force) { $result = z_fetch_url($photo, true); - } else { - $h = [ - 'headers' => [ - 'If-Modified-Since: ' . gmdate('D, d M Y H:i:s', strtotime($modified . 'Z')) . ' GMT' - ] - ]; + } + else { + $h = [ 'headers' => [ 'If-Modified-Since: ' . gmdate('D, d M Y H:i:s', strtotime($modified . 'Z')) . ' GMT' ] ]; $result = z_fetch_url($photo, true, 0, $h); } - if($result['success']) { + if ($result['success']) { $img_str = $result['body']; $type = guess_image_type($photo, $result['header']); $modified = gmdate('Y-m-d H:i:s', (preg_match('/last-modified: (.+) \S+/i', $result['header'], $o) ? strtotime($o[1] . 'Z') : time())); - if(is_null($type)) - $photo_failure = true; - } elseif($result['return_code'] == 304) { + if (! is_null($type)) { + $failed = false; + } + } + elseif ($result['return_code'] == 304) { $photo = z_root() . '/photo/' . $hash . '-4'; $thumb = z_root() . '/photo/' . $hash . '-5'; $micro = z_root() . '/photo/' . $hash . '-6'; - } else { - $photo_failure = true; + $failed = false; } - } else { - $photo_failure = true; } - if(!$photo_failure && $result['return_code'] != 304) { + if (! $failed && $result['return_code'] != 304) { $img = photo_factory($img_str, $type); - if($img->is_valid()) { + if ($img->is_valid()) { $width = $img->getWidth(); $height = $img->getHeight(); - if($width && $height) { - if(($width / $height) > 1.2) { + if ($width && $height) { + if (($width / $height) > 1.2) { // crop out the sides $margin = $width - $height; $img->cropImage(300, ($margin / 2), 0, $height, $height); - } elseif(($height / $width) > 1.2) { + } + elseif(($height / $width) > 1.2) { // crop out the bottom $margin = $height - $width; $img->cropImage(300, 0, 0, $width, $width); - } else { + } + else { $img->scaleImageSquare(300); } - } else { - $photo_failure = true; + } + else { + $failed = true; } $p = [ - 'xchan' => $xchan, - 'resource_id' => $hash, - 'filename' => basename($photo), - 'album' => $album, - 'photo_usage' => $flags, - 'imgscale' => 4, - 'edited' => $modified, + 'xchan' => $xchan, + 'resource_id' => $hash, + 'filename' => basename($photo), + 'album' => $album, + 'photo_usage' => $flags, + 'imgscale' => 4, + 'edited' => $modified, ]; $r = $img->save($p); - if($r === false) - $photo_failure = true; - + if ($r === false) { + $failed = true; + } $img->scaleImage(80); $p['imgscale'] = 5; $r = $img->save($p); - if($r === false) - $photo_failure = true; - + if ($r === false) { + $failed = true; + } $img->scaleImage(48); $p['imgscale'] = 6; $r = $img->save($p); - if($r === false) - $photo_failure = true; - + if ($r === false) { + $failed = true; + } $photo = z_root() . '/photo/' . $hash . '-4'; $thumb = z_root() . '/photo/' . $hash . '-5'; $micro = z_root() . '/photo/' . $hash . '-6'; - } else { + } + else { logger('Invalid image from ' . $photo); - $photo_failure = true; + $failed = true; } } - if($photo_failure) { - $default = get_default_profile_photo(); - $photo = z_root() . '/' . $default; - $thumb = z_root() . '/' . get_default_profile_photo(80); - $micro = z_root() . '/' . get_default_profile_photo(48); - $type = 'image/png'; + + if ($failed) { + $default = get_default_profile_photo(); + $photo = z_root() . '/' . $default; + $thumb = z_root() . '/' . get_default_profile_photo(80); + $micro = z_root() . '/' . get_default_profile_photo(48); + $type = 'image/png'; $modified = gmdate('Y-m-d H:i:s', filemtime($default)); } logger('HTTP code: ' . $result['return_code'] . '; modified: ' . $modified - . '; failure: ' . ($photo_failure ? 'yes' : 'no') . '; URL: ' . $photo, LOGGER_DEBUG); + . '; failure: ' . ($failed ? 'yes' : 'no') . '; URL: ' . $photo, LOGGER_DEBUG); - return([$photo, $thumb, $micro, $type, $photo_failure, $modified]); + return([$photo, $thumb, $micro, $type, $failed, $modified]); } /** diff --git a/include/photos.php b/include/photos.php index 45535ed71..0be6472d7 100644 --- a/include/photos.php +++ b/include/photos.php @@ -25,7 +25,7 @@ function photo_upload($channel, $observer, $args) { $ret = [ 'success' => false ]; $channel_id = $channel['channel_id']; $account_id = $channel['channel_account_id']; - + if (! perm_is_allowed($channel_id, $observer['xchan_hash'], 'write_storage')) { $ret['message'] = t('Permission denied.'); return $ret;