From aca1551e8608a6df6dbe666372b5941a212457bd Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 13 Oct 2021 09:23:59 +0000 Subject: implement AS representation of photos and albums, cleanup and minor fixes --- Zotlabs/Lib/Activity.php | 212 ++++++++++++++++++++++++-------------------- Zotlabs/Module/Album.php | 103 +++++++++++++++++++++ Zotlabs/Module/Apschema.php | 2 +- Zotlabs/Module/Photo.php | 118 ++++++++++++++++-------- 4 files changed, 302 insertions(+), 133 deletions(-) create mode 100644 Zotlabs/Module/Album.php (limited to 'Zotlabs') diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index c355aa26e..96b747c30 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -8,8 +8,6 @@ use Zotlabs\Access\PermissionRoles; use Zotlabs\Access\Permissions; use Zotlabs\Daemon\Master; use Zotlabs\Web\HTTPSig; -use Zotlabs\Lib\XConfig; -use Zotlabs\Lib\Libzot; require_once('include/event.php'); require_once('include/html2plain.php'); @@ -104,7 +102,7 @@ class Activity { if ($x['success']) { $m = parse_url($url); if ($m) { - $y = [ 'scheme' => $m['scheme'], 'host' => $m['host'] ]; + $y = ['scheme' => $m['scheme'], 'host' => $m['host']]; if (array_key_exists('port', $m)) $y['port'] = $m['port']; $site_url = unparse_url($y); @@ -288,21 +286,21 @@ class Activity { 'type' => $type . 'Page', ]; - $numpages = $total / App::$pager['itemspage']; - $lastpage = (($numpages > intval($numpages)) ? intval($numpages) + 1 : $numpages); + $numpages = $total / App::$pager['itemspage']; + $lastpage = (($numpages > intval($numpages)) ? intval($numpages) + 1 : $numpages); $url_parts = parse_url($id); $ret['partOf'] = z_root() . '/' . $url_parts['path']; $extra_query_args = ''; - $query_args = null; - if(isset($url_parts['query'])) { + $query_args = null; + if (isset($url_parts['query'])) { parse_str($url_parts['query'], $query_args); } - if(is_array($query_args)) { + if (is_array($query_args)) { unset($query_args['page']); - foreach($query_args as $k => $v) + foreach ($query_args as $k => $v) $extra_query_args .= '&' . urlencode($k) . '=' . urlencode($v); } @@ -376,11 +374,33 @@ class Activity { return $ret; } - static function encode_item($i) { + static function encode_simple_collection($items, $id, $type, $total = 0, $extra = null) { - $ret = []; + $ret = [ + 'id' => z_root() . '/' . $id, + 'type' => $type, + 'totalItems' => $total, + ]; + + if ($extra) { + $ret = array_merge($ret, $extra); + } + if ($items) { + if ($type === 'OrderedCollection') { + $ret['orderedItems'] = $items; + } + else { + $ret['items'] = $items; + } + } + return $ret; + } + + static function encode_item($i) { + + $ret = []; if ($i['verb'] === ACTIVITY_FRIEND) { // Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note @@ -1108,7 +1128,7 @@ class Activity { } $arr = [ - 'xchan' => $p, + 'xchan' => $p, 'encoded' => $ret ]; @@ -1122,8 +1142,8 @@ class Activity { $ret = []; if ($item[$elm]) { - if (! is_array($item[$elm])) { - $item[$elm] = json_decode($item[$elm],true); + if (!is_array($item[$elm])) { + $item[$elm] = json_decode($item[$elm], true); } if ($item[$elm]['type'] === ACTIVITY_OBJ_PHOTO) { $item[$elm]['id'] = $item['mid']; @@ -1153,22 +1173,22 @@ class Activity { } $acts = [ - 'http://activitystrea.ms/schema/1.0/post' => 'Create', - 'http://activitystrea.ms/schema/1.0/share' => 'Announce', - 'http://activitystrea.ms/schema/1.0/update' => 'Update', - 'http://activitystrea.ms/schema/1.0/like' => 'Like', - 'http://activitystrea.ms/schema/1.0/favorite' => 'Like', - 'http://purl.org/zot/activity/dislike' => 'Dislike', - 'http://activitystrea.ms/schema/1.0/tag' => 'Add', - 'http://activitystrea.ms/schema/1.0/follow' => 'Follow', - 'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow', + 'http://activitystrea.ms/schema/1.0/post' => 'Create', + 'http://activitystrea.ms/schema/1.0/share' => 'Announce', + 'http://activitystrea.ms/schema/1.0/update' => 'Update', + 'http://activitystrea.ms/schema/1.0/like' => 'Like', + 'http://activitystrea.ms/schema/1.0/favorite' => 'Like', + 'http://purl.org/zot/activity/dislike' => 'Dislike', + 'http://activitystrea.ms/schema/1.0/tag' => 'Add', + 'http://activitystrea.ms/schema/1.0/follow' => 'Follow', + 'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow', 'http://activitystrea.ms/schema/1.0/stop-following' => 'Unfollow', - 'http://purl.org/zot/activity/attendyes' => 'Accept', - 'http://purl.org/zot/activity/attendno' => 'Reject', - 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept', - 'Invite' => 'Invite', - 'Delete' => 'Delete', - 'Undo' => 'Undo' + 'http://purl.org/zot/activity/attendyes' => 'Accept', + 'http://purl.org/zot/activity/attendno' => 'Reject', + 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept', + 'Invite' => 'Invite', + 'Delete' => 'Delete', + 'Undo' => 'Undo' ]; call_hooks('activity_mapper', $acts); @@ -1201,22 +1221,22 @@ class Activity { static function activity_decode_mapper($verb) { $acts = [ - 'http://activitystrea.ms/schema/1.0/post' => 'Create', - 'http://activitystrea.ms/schema/1.0/share' => 'Announce', - 'http://activitystrea.ms/schema/1.0/update' => 'Update', - 'http://activitystrea.ms/schema/1.0/like' => 'Like', - 'http://activitystrea.ms/schema/1.0/favorite' => 'Like', - 'http://purl.org/zot/activity/dislike' => 'Dislike', - 'http://activitystrea.ms/schema/1.0/tag' => 'Add', - 'http://activitystrea.ms/schema/1.0/follow' => 'Follow', - 'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow', + 'http://activitystrea.ms/schema/1.0/post' => 'Create', + 'http://activitystrea.ms/schema/1.0/share' => 'Announce', + 'http://activitystrea.ms/schema/1.0/update' => 'Update', + 'http://activitystrea.ms/schema/1.0/like' => 'Like', + 'http://activitystrea.ms/schema/1.0/favorite' => 'Like', + 'http://purl.org/zot/activity/dislike' => 'Dislike', + 'http://activitystrea.ms/schema/1.0/tag' => 'Add', + 'http://activitystrea.ms/schema/1.0/follow' => 'Follow', + 'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow', 'http://activitystrea.ms/schema/1.0/stop-following' => 'Unfollow', - 'http://purl.org/zot/activity/attendyes' => 'Accept', - 'http://purl.org/zot/activity/attendno' => 'Reject', - 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept', - 'Invite' => 'Invite', - 'Delete' => 'Delete', - 'Undo' => 'Undo' + 'http://purl.org/zot/activity/attendyes' => 'Accept', + 'http://purl.org/zot/activity/attendno' => 'Reject', + 'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept', + 'Invite' => 'Invite', + 'Delete' => 'Delete', + 'Undo' => 'Undo' ]; call_hooks('activity_decode_mapper', $acts); @@ -1328,7 +1348,7 @@ class Activity { * */ - if (in_array($act->type, [ 'Follow', 'Invite', 'Join'])) { + if (in_array($act->type, ['Follow', 'Invite', 'Join'])) { $their_follow_id = $act->id; } @@ -1351,8 +1371,8 @@ class Activity { } } - $x = \Zotlabs\Access\PermissionRoles::role_perms('social'); - $their_perms = \Zotlabs\Access\Permissions::FilledPerms($x['perms_connect']); + $x = PermissionRoles::role_perms('social'); + $their_perms = Permissions::FilledPerms($x['perms_connect']); if ($contact && $contact['abook_id']) { @@ -1426,7 +1446,7 @@ class Activity { } $ret = $r[0]; - $p = \Zotlabs\Access\Permissions::connect_perms($channel['channel_id']); + $p = Permissions::connect_perms($channel['channel_id']); $my_perms = $p['perms']; $automatic = $p['automatic']; @@ -1447,13 +1467,13 @@ class Activity { ] ); - if($my_perms) - foreach($my_perms as $k => $v) - set_abconfig($channel['channel_id'],$ret['xchan_hash'],'my_perms',$k,$v); + if ($my_perms) + foreach ($my_perms as $k => $v) + set_abconfig($channel['channel_id'], $ret['xchan_hash'], 'my_perms', $k, $v); - if($their_perms) - foreach($their_perms as $k => $v) - set_abconfig($channel['channel_id'],$ret['xchan_hash'],'their_perms',$k,$v); + if ($their_perms) + foreach ($their_perms as $k => $v) + set_abconfig($channel['channel_id'], $ret['xchan_hash'], 'their_perms', $k, $v); if ($r) { logger("New ActivityPub follower for {$channel['channel_name']}"); @@ -1543,16 +1563,16 @@ class Activity { return; } -/* not implemented - if (array_key_exists('movedTo',$person_obj) && $person_obj['movedTo'] && ! is_array($person_obj['movedTo'])) { - $tgt = self::fetch($person_obj['movedTo']); - if (is_array($tgt)) { - self::actor_store($person_obj['movedTo'],$tgt); - ActivityPub::move($person_obj['id'],$tgt); - } - return; - } -*/ + /* not implemented + if (array_key_exists('movedTo',$person_obj) && $person_obj['movedTo'] && ! is_array($person_obj['movedTo'])) { + $tgt = self::fetch($person_obj['movedTo']); + if (is_array($tgt)) { + self::actor_store($person_obj['movedTo'],$tgt); + ActivityPub::move($person_obj['id'],$tgt); + } + return; + } + */ $ap_hubloc = null; $hublocs = self::get_actor_hublocs($url); @@ -1570,7 +1590,7 @@ class Activity { if ($ap_hubloc) { // we already have a stored record. Determine if it needs updating. - if ($ap_hubloc['hubloc_updated'] < datetime_convert('UTC','UTC',' now - 3 days') || $force) { + if ($ap_hubloc['hubloc_updated'] < datetime_convert('UTC', 'UTC', ' now - 3 days') || $force) { $person_obj = self::fetch($url); } else { @@ -1582,7 +1602,7 @@ class Activity { $url = $person_obj['id']; } - if (! $url) { + if (!$url) { return; } @@ -1665,9 +1685,9 @@ class Activity { } $m = parse_url($url); - if($m) { + if ($m) { $hostname = $m['host']; - $baseurl = $m['scheme'] . '://' . $m['host'] . (($m['port']) ? ':' . $m['port'] : ''); + $baseurl = $m['scheme'] . '://' . $m['host'] . (($m['port']) ? ':' . $m['port'] : ''); $site_url = $m['scheme'] . '://' . $m['host']; } @@ -1675,11 +1695,11 @@ class Activity { dbesc($url) ); - if($r) { + if ($r) { // Record exists. Cache existing records for one week at most // then refetch to catch updated profile photos, names, etc. $d = datetime_convert('UTC', 'UTC', 'now - 3 days'); - if($r[0]['hubloc_updated'] > $d && !$force) { + if ($r[0]['hubloc_updated'] > $d && !$force) { return; } @@ -1713,14 +1733,14 @@ class Activity { xchan_store_lowlevel( [ - 'xchan_hash' => escape_tags($url), - 'xchan_guid' => escape_tags($url), - 'xchan_pubkey' => escape_tags($pubkey), - 'xchan_addr' => '', - 'xchan_url' => escape_tags($profile), - 'xchan_name' => escape_tags($name), - 'xchan_name_date' => datetime_convert(), - 'xchan_network' => 'activitypub' + 'xchan_hash' => escape_tags($url), + 'xchan_guid' => escape_tags($url), + 'xchan_pubkey' => escape_tags($pubkey), + 'xchan_addr' => '', + 'xchan_url' => escape_tags($profile), + 'xchan_name' => escape_tags($name), + 'xchan_name_date' => datetime_convert(), + 'xchan_network' => 'activitypub' ] ); @@ -1787,9 +1807,9 @@ class Activity { static function create_note($channel, $observer_hash, $act) { - $s = []; + $s = []; $is_sys_channel = is_sys_channel($channel['channel_id']); - $parent = ((array_key_exists('inReplyTo', $act->obj)) ? urldecode($act->obj['inReplyTo']) : ''); + $parent = ((array_key_exists('inReplyTo', $act->obj)) ? urldecode($act->obj['inReplyTo']) : ''); if ($parent) { @@ -2141,7 +2161,7 @@ class Activity { // Unfollow is not defined by ActivityStreams, which prefers Undo->Follow. // This may have to be revisited if AP projects start using Follow for objects other than actors. - if (in_array($act->type, [ 'Follow', 'Unfollow' ])) { + if (in_array($act->type, ['Follow', 'Unfollow'])) { return false; } @@ -2164,11 +2184,11 @@ class Activity { $s['parent_mid'] = $act->parent_id; if (array_key_exists('published', $act->data)) { - $s['created'] = datetime_convert('UTC', 'UTC', $act->data['published']); + $s['created'] = datetime_convert('UTC', 'UTC', $act->data['published']); $s['commented'] = $s['created']; } elseif (array_key_exists('published', $act->obj)) { - $s['created'] = datetime_convert('UTC', 'UTC', $act->obj['published']); + $s['created'] = datetime_convert('UTC', 'UTC', $act->obj['published']); $s['commented'] = $s['created']; } if (array_key_exists('updated', $act->data)) { @@ -2240,10 +2260,10 @@ class Activity { } } - if (! array_key_exists('created', $s)) + if (!array_key_exists('created', $s)) $s['created'] = datetime_convert(); - if (! array_key_exists('edited', $s)) + if (!array_key_exists('edited', $s)) $s['edited'] = $s['created']; $s['title'] = (($response_activity) ? EMPTY_STR : self::bb_content($content, 'name')); @@ -2452,7 +2472,7 @@ class Activity { } - if ($act->obj['type'] === 'Image' && strpos($s['body'],'zrl=') === false) { + if ($act->obj['type'] === 'Image' && strpos($s['body'], 'zrl=') === false) { $ptr = null; @@ -3120,7 +3140,7 @@ class Activity { static function announce_note($channel, $observer_hash, $act) { - $s = []; + $s = []; $is_sys_channel = is_sys_channel($channel['channel_id']); if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'send_stream') && !$is_sys_channel) { @@ -3380,7 +3400,7 @@ class Activity { $ret = false; foreach ($attach as $a) { - if (array_key_exists('type',$a) && stripos($a['type'], 'image') !== false) { + if (array_key_exists('type', $a) && stripos($a['type'], 'image') !== false) { if (self::media_not_in_body($a['href'], $body)) { $ret .= "\n\n" . '[img]' . $a['href'] . '[/img]'; } @@ -3553,7 +3573,7 @@ class Activity { } static function get_cached_actor($id) { - $actor = XConfig::Get($id,'system', 'actor_record'); + $actor = XConfig::Get($id, 'system', 'actor_record'); if ($actor) { return $actor; @@ -3561,7 +3581,7 @@ class Activity { // try other get_cached_actor providers (e.g. diaspora) $hookdata = [ - 'id' => $id, + 'id' => $id, 'actor' => false ]; @@ -3572,8 +3592,6 @@ class Activity { static function get_actor_hublocs($url, $options = 'all') { - $hublocs = false; - switch ($options) { case 'activitypub': $hublocs = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_hash = '%s' and hubloc_deleted = 0 ", @@ -3598,18 +3616,18 @@ class Activity { } static function get_actor_collections($url) { - $ret = []; - $actor_record = XConfig::Get($url,'system','actor_record'); - if (! $actor_record) { + $ret = []; + $actor_record = XConfig::Get($url, 'system', 'actor_record'); + if (!$actor_record) { return $ret; } - foreach ( [ 'inbox','outbox','followers','following' ] as $collection) { + foreach (['inbox', 'outbox', 'followers', 'following'] as $collection) { if (isset($actor_record[$collection]) && $actor_record[$collection]) { $ret[$collection] = $actor_record[$collection]; } } - if (array_path_exists('endpoints/sharedInbox',$actor_record) && $actor_record['endpoints']['sharedInbox']) { + if (array_path_exists('endpoints/sharedInbox', $actor_record) && $actor_record['endpoints']['sharedInbox']) { $ret['sharedInbox'] = $actor_record['endpoints']['sharedInbox']; } diff --git a/Zotlabs/Module/Album.php b/Zotlabs/Module/Album.php new file mode 100644 index 000000000..f80880184 --- /dev/null +++ b/Zotlabs/Module/Album.php @@ -0,0 +1,103 @@ + 1) { + $channel = channelx_by_nick(argv(1)); + } + if (!$channel) { + http_status_exit(404, 'Not found.'); + } + + $sql_extra = permissions_sql($channel['channel_id'], $observer_xchan); + + if (argc() > 2) { + $folder = argv(2); + $r = q("select * from attach where is_dir = 1 and hash = '%s' and uid = %d $sql_extra limit 1", + dbesc($folder), + intval($channel['channel_id']) + ); + $allowed = (($r) ? attach_can_view($channel['channel_id'], $observer_xchan, $r[0]['hash'] /*,$bear */) : false); + } + else { + $folder = EMPTY_STR; + $allowed = perm_is_allowed($channel['channel_id'], $observer_xchan, 'view_storage'); + } + + if (!$allowed) { + http_status_exit(403, 'Permission denied.'); + } + + $x = q("select * from attach where folder = '%s' and uid = %d $sql_extra", + dbesc($folder), + intval($channel['channel_id']) + ); + + $contents = []; + + if ($x) { + foreach ($x as $xv) { + if (intval($xv['is_dir'])) { + continue; + } + if (!attach_can_view($channel['channel_id'], $observer_xchan, $xv['hash'] /*,$bear*/)) { + continue; + } + if (intval($xv['is_photo'])) { + $contents[] = z_root() . '/photo/' . $xv['hash']; + } + } + } + + $obj = Activity::encode_simple_collection($contents, App::$query_string, 'OrderedCollection', count($contents)); + as_return_and_die($obj, $channel); + + } + + } + +} + diff --git a/Zotlabs/Module/Apschema.php b/Zotlabs/Module/Apschema.php index 6b0325d44..eab82eb29 100644 --- a/Zotlabs/Module/Apschema.php +++ b/Zotlabs/Module/Apschema.php @@ -50,7 +50,7 @@ class Apschema extends \Zotlabs\Web\Controller { 'guid' => 'diaspora:guid', 'Hashtag' => 'as:Hashtag' - + ] ]; diff --git a/Zotlabs/Module/Photo.php b/Zotlabs/Module/Photo.php index 87697f5a7..10d2e8f47 100644 --- a/Zotlabs/Module/Photo.php +++ b/Zotlabs/Module/Photo.php @@ -3,6 +3,12 @@ namespace Zotlabs\Module; +use Zotlabs\Lib\Activity; +use Zotlabs\Lib\ActivityStreams; +use Zotlabs\Web\HTTPSig; +use Zotlabs\Lib\Config; + + require_once('include/security.php'); require_once('include/attach.php'); require_once('include/photo/photo_driver.php'); @@ -11,6 +17,48 @@ class Photo extends \Zotlabs\Web\Controller { function init() { + if (ActivityStreams::is_as_request()) { + + $sigdata = HTTPSig::verify(EMPTY_STR); + if ($sigdata['portable_id'] && $sigdata['header_valid']) { + $portable_id = $sigdata['portable_id']; + if (! check_channelallowed($portable_id)) { + http_status_exit(403, 'Permission denied'); + } + if (! check_siteallowed($sigdata['signer'])) { + http_status_exit(403, 'Permission denied'); + } + observer_auth($portable_id); + } + elseif (Config::get('system','require_authenticated_fetch',false)) { + http_status_exit(403,'Permission denied'); + } + + $observer_xchan = get_observer_hash(); + $allowed = false; + + $bear = Activity::token_from_request(); + if ($bear) { + logger('bear: ' . $bear, LOGGER_DEBUG); + } + + $r = q("select * from item where resource_type = 'photo' and resource_id = '%s' limit 1", + dbesc(argv(1)) + ); + if ($r) { + $allowed = attach_can_view($r[0]['uid'],$observer_xchan,argv(1)/*,$bear*/); + } + if (! $allowed) { + http_status_exit(404,'Permission denied.'); + } + $channel = channelx_by_n($r[0]['uid']); + + $obj = json_decode($r[0]['obj'],true); + + as_return_and_die($obj,$channel); + + } + $streaming = null; $channel = null; $person = 0; @@ -33,19 +81,19 @@ class Photo extends \Zotlabs\Web\Controller { $cache_mode = [ 'on' => false, 'age' => 86400, 'exp' => true, 'leak' => false ]; call_hooks('cache_mode_hook', $cache_mode); - + $observer_xchan = get_observer_hash(); $cachecontrol = ', no-cache'; if(isset($type)) { - + /** * Profile photos - Access controls on default profile photos are not honoured since they need to be exchanged with remote sites. - * + * */ - + $default = get_default_profile_photo(); - + if($type === 'profile') { switch($res) { case 'm': @@ -62,9 +110,9 @@ class Photo extends \Zotlabs\Web\Controller { break; } } - + $uid = $person; - + $data = ''; if ($uid > 0) { @@ -81,13 +129,13 @@ class Photo extends \Zotlabs\Web\Controller { else $data = dbunescbin($r[0]['content']); } - + if(! $data) { $d = [ 'imgscale' => $resolution, 'channel_id' => $uid, 'default' => $default, 'data' => '', 'mimetype' => '' ]; call_hooks('get_profile_photo',$d); - + $resolution = $d['imgscale']; - $uid = $d['channel_id']; + $uid = $d['channel_id']; $default = $d['default']; $data = $d['data']; $mimetype = $d['mimetype']; @@ -105,11 +153,11 @@ class Photo extends \Zotlabs\Web\Controller { $cachecontrol .= ', must-revalidate'; } else { - + /** * Other photos */ - + /* Check for a cookie to indicate display pixel density, in order to detect high-resolution displays. This procedure was derived from the "Retina Images" by Jeremey Worboys, used in accordance with the Creative Commons Attribution 3.0 Unported License. @@ -127,12 +175,12 @@ class Photo extends \Zotlabs\Web\Controller { // $prvcachecontrol = 'no-cache'; $status = 'no cookie'; } - + $resolution = 0; - + if(strpos($photo,'.') !== false) $photo = substr($photo,0,strpos($photo,'.')); - + if(substr($photo,-2,1) == '-') { $resolution = intval(substr($photo,-1,1)); $photo = substr($photo,0,-2); @@ -140,7 +188,7 @@ class Photo extends \Zotlabs\Web\Controller { if ($resolution == 2 && ($cookie_value > 1)) $resolution = 1; } - + $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1", dbesc($photo), intval($resolution) @@ -151,7 +199,7 @@ class Photo extends \Zotlabs\Web\Controller { $u = intval($r[0]['photo_usage']); if($u) { $allowed = 1; - if($u === PHOTO_COVER) + if($u === PHOTO_COVER) if($resolution < PHOTO_RES_COVER_1200) $allowed = (-1); if($u === PHOTO_PROFILE) @@ -184,9 +232,9 @@ class Photo extends \Zotlabs\Web\Controller { dbesc($photo), intval($resolution) ); - + $exists = (($e) ? true : false); - + if($exists && $allowed) { $expires = strtotime($e[0]['expires'] . 'Z'); $data = dbunescbin($e[0]['content']); @@ -209,16 +257,16 @@ class Photo extends \Zotlabs\Web\Controller { } } - } + } else http_status_exit(404,'not found'); } if(! $data) killme(); - + $etag = '"' . md5($data . $modified) . '"'; - + if($modified == 0) $modified = time(); @@ -241,39 +289,39 @@ class Photo extends \Zotlabs\Web\Controller { } if(isset($prvcachecontrol)) { - + // it is a private photo that they have no permission to view. // tell the browser not to cache it, in case they authenticate // and subsequently have permission to see it - + header("Cache-Control: " . $prvcachecontrol); - + } else { // The photo cache default is 1 day to provide a privacy trade-off, - // as somebody reducing photo permissions on a photo that is already + // as somebody reducing photo permissions on a photo that is already // "in the wild" won't be able to stop the photo from being viewed // for this amount amount of time once it is in the browser cache. - // The privacy expectations of your site members and their perception + // The privacy expectations of your site members and their perception // of privacy where it affects the entire project may be affected. - // This has performance considerations but we highly recommend you - // leave it alone. - + // This has performance considerations but we highly recommend you + // leave it alone. + $maxage = $cache_mode['age']; if($cache_mode['exp'] || (! isset($expires)) || (isset($expires) && $expires - 60 < time())) $expires = time() + $maxage; else $maxage = $expires - time(); - + header("Expires: " . gmdate("D, d M Y H:i:s", $expires) . " GMT"); - // set CDN/Infrastructure caching much lower than maxage + // set CDN/Infrastructure caching much lower than maxage // in the event that infrastructure caching is present. $smaxage = intval($maxage/12); header("Cache-Control: s-maxage=" . $smaxage . ", max-age=" . $maxage . $cachecontrol); - + } header("Content-type: " . $mimetype); @@ -281,7 +329,7 @@ class Photo extends \Zotlabs\Web\Controller { header("ETag: " . $etag); header("Content-Length: " . (isset($filesize) ? $filesize : strlen($data))); - // If it's a file resource, stream it. + // If it's a file resource, stream it. if($streaming) { if(strpos($streaming,'store') !== false) $istream = fopen($streaming,'rb'); @@ -300,5 +348,5 @@ class Photo extends \Zotlabs\Web\Controller { killme(); } - + } -- cgit v1.2.3