]> git.mxchange.org Git - friendica.git/blob - mod/display.php
Merge remote-tracking branch 'upstream/develop' into develop
[friendica.git] / mod / display.php
1 <?php
2
3 use Friendica\App;
4 use Friendica\Core\System;
5
6 require_once('include/dfrn.php');
7
8 function display_init(App $a) {
9
10         if ((get_config('system','block_public')) && (! local_user()) && (! remote_user())) {
11                 return;
12         }
13
14         $nick = (($a->argc > 1) ? $a->argv[1] : '');
15         $profiledata = array();
16
17         if ($a->argc == 3) {
18                 if (substr($a->argv[2], -5) == '.atom') {
19                         $item_id = substr($a->argv[2], 0, -5);
20                         displayShowFeed($item_id);
21                 }
22         }
23
24         // If there is only one parameter, then check if this parameter could be a guid
25         if ($a->argc == 2) {
26                 $nick = "";
27                 $itemuid = 0;
28
29                 // Does the local user have this item?
30                 if (local_user()) {
31                         $r = dba::fetch_first("SELECT `id`, `parent`, `author-name`, `author-link`, `author-avatar`, `network`, `body`, `uid`, `owner-link` FROM `item`
32                                 WHERE `item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated`
33                                         AND `guid` = ? AND `uid` = ? LIMIT 1", $a->argv[1], local_user());
34                         if (dbm::is_result($r)) {
35                                 $nick = $a->user["nickname"];
36                                 $itemuid = local_user();
37                         }
38                 }
39
40                 // Or is it anywhere on the server?
41                 if ($nick == "") {
42                         $r = dba::fetch_first("SELECT `user`.`nickname`, `item`.`id`, `item`.`parent`, `item`.`author-name`,
43                                 `item`.`author-link`, `item`.`author-avatar`, `item`.`network`, `item`.`uid`, `item`.`owner-link`, `item`.`body`
44                                 FROM `item` STRAIGHT_JOIN `user` ON `user`.`uid` = `item`.`uid`
45                                 WHERE `item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated`
46                                         AND `item`.`allow_cid` = ''  AND `item`.`allow_gid` = ''
47                                         AND `item`.`deny_cid`  = '' AND `item`.`deny_gid`  = ''
48                                         AND NOT `item`.`private` AND NOT `user`.`hidewall`
49                                         AND `item`.`guid` = ? LIMIT 1", $a->argv[1]);
50                         if (dbm::is_result($r)) {
51                                 $nick = $r["nickname"];
52                                 $itemuid = $r["uid"];
53                         }
54                 }
55
56                 // Is it an item with uid=0?
57                 if ($nick == "") {
58                         $r = dba::fetch_first("SELECT `item`.`id`, `item`.`parent`, `item`.`author-name`, `item`.`author-link`,
59                                 `item`.`author-avatar`, `item`.`network`, `item`.`uid`, `item`.`owner-link`, `item`.`body`
60                                 FROM `item` WHERE `item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated`
61                                         AND `item`.`allow_cid` = ''  AND `item`.`allow_gid` = ''
62                                         AND `item`.`deny_cid`  = '' AND `item`.`deny_gid`  = ''
63                                         AND NOT `item`.`private` AND `item`.`uid` = 0
64                                         AND `item`.`guid` = ? LIMIT 1", $a->argv[1]);
65                 }
66                 if (dbm::is_result($r)) {
67
68                         if (strstr($_SERVER['HTTP_ACCEPT'], 'application/atom+xml')) {
69                                 logger('Directly serving XML for id '.$r["id"], LOGGER_DEBUG);
70                                 displayShowFeed($r["id"]);
71                         }
72
73                         if ($r["id"] != $r["parent"]) {
74                                 $r = dba::fetch_first("SELECT `id`, `author-name`, `author-link`, `author-avatar`, `network`, `body`, `uid`, `owner-link` FROM `item`
75                                         WHERE `item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated`
76                                                 AND `id` = ?", $r["parent"]);
77                         }
78                         if (($itemuid != local_user()) && local_user()) {
79                                 // Do we know this contact but we haven't got this item?
80                                 // Copy the wohle thread to our local storage so that we can interact.
81                                 // We really should change this need for the future since it scales very bad.
82                                 $contactid = get_contact($r['owner-link'], local_user());
83                                 if ($contactid) {
84                                         $items = dba::select('item', array(), array('parent' => $r["id"]), array('order' => array('id')));
85                                         while ($item = dba::fetch($items)) {
86                                                 $itemcontactid = get_contact($item['owner-link'], local_user());
87                                                 if (!$itemcontactid) {
88                                                         $itemcontactid = $contactid;
89                                                 }
90                                                 unset($item['id']);
91                                                 $item['uid'] = local_user();
92                                                 $item['origin'] = 0;
93                                                 $item['contact-id'] = $itemcontactid;
94                                                 $local_copy = item_store($item, false, false, true);
95                                                 logger("Stored local copy for post ".$item['guid']." under id ".$local_copy, LOGGER_DEBUG);
96                                         }
97                                         dba::close($items);
98                                 }
99                         }
100
101                         $profiledata = display_fetchauthor($a, $r);
102
103                         if (strstr(normalise_link($profiledata["url"]), normalise_link(System::baseUrl()))) {
104                                 $nickname = str_replace(normalise_link(System::baseUrl())."/profile/", "", normalise_link($profiledata["url"]));
105
106                                 if (($nickname != $a->user["nickname"])) {
107                                         $r = dba::fetch_first("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `contact`.`avatar-date` AS picdate, `user`.* FROM `profile`
108                                                 INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` INNER JOIN `user` ON `profile`.`uid` = `user`.`uid`
109                                                 WHERE `user`.`nickname` = ? AND `profile`.`is-default` AND `contact`.`self` LIMIT 1",
110                                                 $nickname
111                                         );
112                                         if (dbm::is_result($r)) {
113                                                 $profiledata = $r;
114                                         }
115                                         $profiledata["network"] = NETWORK_DFRN;
116                                 } else {
117                                         $profiledata = array();
118                                 }
119                         }
120                 } else {
121                         $a->error = 404;
122                         notice(t('Item not found.') . EOL);
123                         return;
124                 }
125         }
126
127         profile_load($a, $nick, 0, $profiledata);
128 }
129
130 function display_fetchauthor($a, $item) {
131
132         require_once("include/Contact.php");
133
134         $profiledata = array();
135         $profiledata["uid"] = -1;
136         $profiledata["nickname"] = $item["author-name"];
137         $profiledata["name"] = $item["author-name"];
138         $profiledata["picdate"] = "";
139         $profiledata["photo"] = $item["author-avatar"];
140         $profiledata["url"] = $item["author-link"];
141         $profiledata["network"] = $item["network"];
142
143         // Check for a repeated message
144         $skip = false;
145         $body = trim($item["body"]);
146
147         // Skip if it isn't a pure repeated messages
148         // Does it start with a share?
149         if (!$skip && strpos($body, "[share") > 0) {
150                 $skip = true;
151         }
152         // Does it end with a share?
153         if (!$skip && (strlen($body) > (strrpos($body, "[/share]") + 8))) {
154                 $skip = true;
155         }
156         if (!$skip) {
157                 $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body);
158                 // Skip if there is no shared message in there
159                 if ($body == $attributes) {
160                         $skip = true;
161                 }
162         }
163
164         if (!$skip) {
165                 $author = "";
166                 preg_match("/author='(.*?)'/ism", $attributes, $matches);
167                 if ($matches[1] != "") {
168                         $profiledata["name"] = html_entity_decode($matches[1],ENT_QUOTES,'UTF-8');
169                 }
170                 preg_match('/author="(.*?)"/ism', $attributes, $matches);
171                 if ($matches[1] != "") {
172                         $profiledata["name"] = html_entity_decode($matches[1],ENT_QUOTES,'UTF-8');
173                 }
174                 $profile = "";
175                 preg_match("/profile='(.*?)'/ism", $attributes, $matches);
176                 if ($matches[1] != "") {
177                         $profiledata["url"] = $matches[1];
178                 }
179                 preg_match('/profile="(.*?)"/ism', $attributes, $matches);
180                 if ($matches[1] != "") {
181                         $profiledata["url"] = $matches[1];
182                 }
183                 $avatar = "";
184                 preg_match("/avatar='(.*?)'/ism", $attributes, $matches);
185                 if ($matches[1] != "") {
186                         $profiledata["photo"] = $matches[1];
187                 }
188                 preg_match('/avatar="(.*?)"/ism', $attributes, $matches);
189                 if ($matches[1] != "") {
190                         $profiledata["photo"] = $matches[1];
191                 }
192                 $profiledata["nickname"] = $profiledata["name"];
193                 $profiledata["network"] = GetProfileUsername($profiledata["url"], "", false, true);
194
195                 $profiledata["address"] = "";
196                 $profiledata["about"] = "";
197         }
198
199         $profiledata = get_contact_details_by_url($profiledata["url"], local_user(), $profiledata);
200
201         $profiledata["photo"] = System::removedBaseUrl($profiledata["photo"]);
202
203         if (local_user()) {
204                 if (in_array($profiledata["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS))) {
205                         $profiledata["remoteconnect"] = System::baseUrl()."/follow?url=".urlencode($profiledata["url"]);
206                 }
207         } elseif ($profiledata["network"] == NETWORK_DFRN) {
208                 $connect = str_replace("/profile/", "/dfrn_request/", $profiledata["url"]);
209                 $profiledata["remoteconnect"] = $connect;
210         }
211
212         return($profiledata);
213 }
214
215 function display_content(App $a, $update = 0) {
216
217         if ((get_config('system','block_public')) && (! local_user()) && (! remote_user())) {
218                 notice(t('Public access denied.') . EOL);
219                 return;
220         }
221
222         require_once('include/security.php');
223         require_once('include/conversation.php');
224         require_once('include/acl_selectors.php');
225
226
227         $o = '';
228
229         if ($update) {
230                 $nick = $_REQUEST['nick'];
231         } else {
232                 $nick = (($a->argc > 1) ? $a->argv[1] : '');
233         }
234
235         if ($update) {
236                 $item_id = $_REQUEST['item_id'];
237                 $a->profile = array('uid' => intval($update), 'profile_uid' => intval($update));
238         } else {
239                 $item_id = (($a->argc > 2) ? $a->argv[2] : 0);
240
241                 if ($a->argc == 2) {
242                         $nick = "";
243
244                         if (local_user()) {
245                                 $r = dba::fetch_first("SELECT `id` FROM `item`
246                                         WHERE `item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated`
247                                                 AND `guid` = ? AND `uid` = ?", $a->argv[1], local_user());
248                                 if (dbm::is_result($r)) {
249                                         $item_id = $r["id"];
250                                         $nick = $a->user["nickname"];
251                                 }
252                         }
253
254                         if ($nick == "") {
255                                 $r = dba::fetch_first("SELECT `user`.`nickname`, `item`.`id` FROM `item` STRAIGHT_JOIN `user` ON `user`.`uid` = `item`.`uid`
256                                         WHERE `item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated`
257                                                 AND `item`.`allow_cid` = ''  AND `item`.`allow_gid` = ''
258                                                 AND `item`.`deny_cid`  = '' AND `item`.`deny_gid`  = ''
259                                                 AND NOT `item`.`private` AND NOT `user`.`hidewall`
260                                                 AND `item`.`guid` = ?", $a->argv[1]);
261                                 if (dbm::is_result($r)) {
262                                         $item_id = $r["id"];
263                                         $nick = $r["nickname"];
264                                 }
265                         }
266                         if ($nick == "") {
267                                 $r = dba::fetch_first("SELECT `item`.`id` FROM `item`
268                                         WHERE `item`.`visible` AND NOT `item`.`deleted` AND NOT `item`.`moderated`
269                                                 AND `item`.`allow_cid` = ''  AND `item`.`allow_gid` = ''
270                                                 AND `item`.`deny_cid`  = '' AND `item`.`deny_gid`  = ''
271                                                 AND NOT `item`.`private` AND `item`.`uid` = 0
272                                                 AND `item`.`guid` = ?", $a->argv[1]);
273                                 if (dbm::is_result($r)) {
274                                         $item_id = $r["id"];
275                                 }
276                         }
277                 }
278         }
279
280         if ($item_id && !is_numeric($item_id)) {
281                 $r = dba::select('item', array('id'), array('uri' => $item_id, 'uid' => $a->profile['uid']), array('limit' => 1));
282                 if (dbm::is_result($r)) {
283                         $item_id = $r["id"];
284                 } else {
285                         $item_id = false;
286                 }
287         }
288
289         if (!$item_id) {
290                 $a->error = 404;
291                 notice(t('Item not found.').EOL);
292                 return;
293         }
294
295         // We are displaying an "alternate" link if that post was public. See issue 2864
296         $is_public = dba::exists('item', array('id' => $item_id, 'private' => false));
297         if ($is_public) {
298                 $alternate = System::baseUrl().'/display/'.$nick.'/'.$item_id.'.atom';
299         } else {
300                 $alternate = '';
301         }
302
303         $a->page['htmlhead'] .= replace_macros(get_markup_template('display-head.tpl'),
304                                 array('$alternate' => $alternate));
305
306         $groups = array();
307
308         $contact = null;
309         $remote_contact = false;
310
311         $contact_id = 0;
312
313         if (is_array($_SESSION['remote'])) {
314                 foreach ($_SESSION['remote'] as $v) {
315                         if ($v['uid'] == $a->profile['uid']) {
316                                 $contact_id = $v['cid'];
317                                 break;
318                         }
319                 }
320         }
321
322         if ($contact_id) {
323                 $groups = init_groups_visitor($contact_id);
324                 $r = dba::fetch_first("SELECT * FROM `contact` WHERE `id` = ? AND `uid` = ? LIMIT 1",
325                         $contact_id,
326                         $a->profile['uid']
327                 );
328                 if (dbm::is_result($r)) {
329                         $contact = $r;
330                         $remote_contact = true;
331                 }
332         }
333
334         if (!$remote_contact) {
335                 if (local_user()) {
336                         $contact_id = $_SESSION['cid'];
337                         $contact = $a->contact;
338                 }
339         }
340
341         $r = dba::fetch_first("SELECT * FROM `contact` WHERE `uid` = ? AND `self` LIMIT 1", $a->profile['uid']);
342         if (dbm::is_result($r)) {
343                 $a->page_contact = $r;
344         }
345         $is_owner = ((local_user()) && (local_user() == $a->profile['profile_uid']) ? true : false);
346
347         if ($a->profile['hidewall'] && (! $is_owner) && (! $remote_contact)) {
348                 notice(t('Access to this profile has been restricted.') . EOL);
349                 return;
350         }
351
352         // We need the editor here to be able to reshare an item.
353
354         if ($is_owner) {
355                 $x = array(
356                         'is_owner' => true,
357                         'allow_location' => $a->user['allow_location'],
358                         'default_location' => $a->user['default-location'],
359                         'nickname' => $a->user['nickname'],
360                         'lockstate' => ( (is_array($a->user)) && ((strlen($a->user['allow_cid'])) || (strlen($a->user['allow_gid'])) || (strlen($a->user['deny_cid'])) || (strlen($a->user['deny_gid']))) ? 'lock' : 'unlock'),
361                         'acl' => populate_acl($a->user, true),
362                         'bang' => '',
363                         'visitor' => 'block',
364                         'profile_uid' => local_user(),
365                         'acl_data' => construct_acl_data($a, $a->user), // For non-Javascript ACL selector
366                 );
367                 $o .= status_editor($a,$x,0,true);
368         }
369
370         $sql_extra = item_permissions_sql($a->profile['uid'],$remote_contact,$groups);
371
372         if ($update) {
373                 $r = dba::p("SELECT `id` FROM `item` WHERE `item`.`uid` = ?
374                         AND `item`.`parent` = (SELECT `parent` FROM `item` WHERE `id` = ?)
375                         $sql_extra AND `unseen`",
376                         $a->profile['uid'],
377                         $item_id
378                 );
379
380                 if (dba::num_rows($r) == 0) {
381                         return '';
382                 }
383         }
384
385         $r = dba::p(item_query()."AND `item`.`parent` = (SELECT `parent` FROM `item` WHERE `id` = ?)
386                 $sql_extra
387                 ORDER BY `parent` DESC, `gravity` ASC, `id` ASC",
388                 $item_id
389         );
390
391         if (!dbm::is_result($r) && local_user()) {
392                 // Check if this is another person's link to a post that we have
393                 $r = dba::fetch_first("SELECT `item`.uri FROM `item`
394                         WHERE (`item`.`id` = ? OR `item`.`uri` = ?)
395                         LIMIT 1",
396                         $item_id,
397                         $item_id
398                 );
399                 if (dbm::is_result($r)) {
400                         $item_uri = $r['uri'];
401
402                         $r = dba::p(item_query()." AND `item`.`uid` = ?
403                                 AND `item`.`parent` = (SELECT `parent` FROM `item` WHERE `uri` = ? AND uid = ?)
404                                 ORDER BY `parent` DESC, `gravity` ASC, `id` ASC",
405                                 local_user(),
406                                 $item_uri,
407                                 local_user()
408                         );
409                 }
410         }
411
412         if (dbm::is_result($r)) {
413                 $s = dba::inArray($r);
414
415                 if ((local_user()) && (local_user() == $a->profile['uid'])) {
416                         $unseen = dba::select('item', array('id'), array('parent' => $s[0]['parent'], 'unseen' => true), array('limit' => 1));
417                         if (dbm::is_result($unseen)) {
418                                 dba::update('item', array('unseen' => false), array('parent' => $s[0]['parent'], 'unseen' => true));
419                         }
420                 }
421
422                 $items = conv_sort($s, "`commented`");
423
424                 if (!$update) {
425                         $o .= "<script> var netargs = '?f=&nick=" . $nick . "&item_id=" . $item_id . "'; </script>";
426                 }
427                 $o .= conversation($a, $items, 'display', $update);
428
429                 // Preparing the meta header
430                 require_once('include/bbcode.php');
431                 require_once("include/html2plain.php");
432                 $description = trim(html2plain(bbcode($s[0]["body"], false, false), 0, true));
433                 $title = trim(html2plain(bbcode($s[0]["title"], false, false), 0, true));
434                 $author_name = $s[0]["author-name"];
435
436                 $image = $a->remove_baseurl($s[0]["author-thumb"]);
437
438                 if ($title == "") {
439                         $title = $author_name;
440                 }
441
442                 // Limit the description to 160 characters
443                 if (strlen($description) > 160) {
444                         $description = substr($description, 0, 157) . '...';
445                 }
446
447                 $description = htmlspecialchars($description, ENT_COMPAT, 'UTF-8', true); // allow double encoding here
448                 $title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8', true); // allow double encoding here
449                 $author_name = htmlspecialchars($author_name, ENT_COMPAT, 'UTF-8', true); // allow double encoding here
450
451                 //<meta name="keywords" content="">
452                 $a->page['htmlhead'] .= '<meta name="author" content="'.$author_name.'" />'."\n";
453                 $a->page['htmlhead'] .= '<meta name="title" content="'.$title.'" />'."\n";
454                 $a->page['htmlhead'] .= '<meta name="fulltitle" content="'.$title.'" />'."\n";
455                 $a->page['htmlhead'] .= '<meta name="description" content="'.$description.'" />'."\n";
456
457                 // Schema.org microdata
458                 $a->page['htmlhead'] .= '<meta itemprop="name" content="'.$title.'" />'."\n";
459                 $a->page['htmlhead'] .= '<meta itemprop="description" content="'.$description.'" />'."\n";
460                 $a->page['htmlhead'] .= '<meta itemprop="image" content="'.$image.'" />'."\n";
461                 $a->page['htmlhead'] .= '<meta itemprop="author" content="'.$author_name.'" />'."\n";
462
463                 // Twitter cards
464                 $a->page['htmlhead'] .= '<meta name="twitter:card" content="summary" />'."\n";
465                 $a->page['htmlhead'] .= '<meta name="twitter:title" content="'.$title.'" />'."\n";
466                 $a->page['htmlhead'] .= '<meta name="twitter:description" content="'.$description.'" />'."\n";
467                 $a->page['htmlhead'] .= '<meta name="twitter:image" content="'.$image.'" />'."\n";
468                 $a->page['htmlhead'] .= '<meta name="twitter:url" content="'.$s[0]["plink"].'" />'."\n";
469
470                 // Dublin Core
471                 $a->page['htmlhead'] .= '<meta name="DC.title" content="'.$title.'" />'."\n";
472                 $a->page['htmlhead'] .= '<meta name="DC.description" content="'.$description.'" />'."\n";
473
474                 // Open Graph
475                 $a->page['htmlhead'] .= '<meta property="og:type" content="website" />'."\n";
476                 $a->page['htmlhead'] .= '<meta property="og:title" content="'.$title.'" />'."\n";
477                 $a->page['htmlhead'] .= '<meta property="og:image" content="'.$image.'" />'."\n";
478                 $a->page['htmlhead'] .= '<meta property="og:url" content="'.$s[0]["plink"].'" />'."\n";
479                 $a->page['htmlhead'] .= '<meta property="og:description" content="'.$description.'" />'."\n";
480                 $a->page['htmlhead'] .= '<meta name="og:article:author" content="'.$author_name.'" />'."\n";
481                 // article:tag
482
483                 return $o;
484         }
485         $r = dba::fetch_first("SELECT `id`,`deleted` FROM `item` WHERE `id` = ? OR `uri` = ? LIMIT 1",
486                 $item_id,
487                 $item_id
488         );
489         if (dbm::is_result($r)) {
490                 if ($r['deleted']) {
491                         notice(t('Item has been removed.') . EOL);
492                 } else {
493                         notice(t('Permission denied.') . EOL);
494                 }
495         } else {
496                 notice(t('Item not found.') . EOL);
497         }
498
499         return $o;
500 }
501
502 function displayShowFeed($item_id) {
503         $xml = dfrn::itemFeed($item_id);
504         if ($xml == '') {
505                 http_status_exit(500);
506         }
507         header("Content-type: application/atom+xml");
508         echo $xml;
509         killme();
510 }