Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1909 lines
58 KiB

5 years ago
10 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. <?php
  2. use Friendica\Core\Config;
  3. require_once 'include/Photo.php';
  4. require_once 'include/photos.php';
  5. require_once 'include/items.php';
  6. require_once 'include/acl_selectors.php';
  7. require_once 'include/bbcode.php';
  8. require_once 'include/security.php';
  9. require_once 'include/redir.php';
  10. require_once 'include/tags.php';
  11. require_once 'include/threads.php';
  12. require_once 'include/Probe.php';
  13. function photos_init(App $a) {
  14. if ($a->argc > 1) {
  15. auto_redir($a, $a->argv[1]);
  16. }
  17. if ((get_config('system', 'block_public')) && (! local_user()) && (! remote_user())) {
  18. return;
  19. }
  20. nav_set_selected('home');
  21. if ($a->argc > 1) {
  22. $nick = $a->argv[1];
  23. $user = qu("SELECT * FROM `user` WHERE `nickname` = '%s' AND `blocked` = 0 LIMIT 1",
  24. dbesc($nick)
  25. );
  26. if (! dbm::is_result($user)) {
  27. return;
  28. }
  29. $a->data['user'] = $user[0];
  30. $a->profile_uid = $user[0]['uid'];
  31. $is_owner = (local_user() && (local_user() == $a->profile_uid));
  32. $profile = get_profiledata_by_nick($nick, $a->profile_uid);
  33. $account_type = account_type($profile);
  34. $tpl = get_markup_template("vcard-widget.tpl");
  35. $vcard_widget .= replace_macros($tpl, array(
  36. '$name' => $profile['name'],
  37. '$photo' => $profile['photo'],
  38. '$addr' => (($profile['addr'] != "") ? $profile['addr'] : ""),
  39. '$account_type' => $account_type,
  40. '$pdesc' => (($profile['pdesc'] != "") ? $profile['pdesc'] : ""),
  41. ));
  42. $albums = photo_albums($a->data['user']['uid']);
  43. $albums_visible = ((intval($a->data['user']['hidewall']) && (! local_user()) && (! remote_user())) ? false : true);
  44. // add various encodings to the array so we can just loop through and pick them out in a template
  45. $ret = array('success' => false);
  46. if ($albums) {
  47. $a->data['albums'] = $albums;
  48. if ($albums_visible) {
  49. $ret['success'] = true;
  50. }
  51. $ret['albums'] = array();
  52. foreach ($albums as $k => $album) {
  53. //hide profile photos to others
  54. if ((! $is_owner) && (! remote_user()) && ($album['album'] == t('Profile Photos')))
  55. continue;
  56. $entry = array(
  57. 'text' => $album['album'],
  58. 'total' => $album['total'],
  59. 'url' => 'photos/' . $a->data['user']['nickname'] . '/album/' . bin2hex($album['album']),
  60. 'urlencode' => urlencode($album['album']),
  61. 'bin2hex' => bin2hex($album['album'])
  62. );
  63. $ret['albums'][] = $entry;
  64. }
  65. }
  66. $albums = $ret;
  67. if (local_user() && $a->data['user']['uid'] == local_user()) {
  68. $can_post = true;
  69. }
  70. if ($albums['success']) {
  71. $photo_albums_widget = replace_macros(get_markup_template('photo_albums.tpl'), array(
  72. '$nick' => $a->data['user']['nickname'],
  73. '$title' => t('Photo Albums'),
  74. '$recent' => t('Recent Photos'),
  75. '$albums' => $albums['albums'],
  76. '$baseurl' => z_root(),
  77. '$upload' => array(t('Upload New Photos'), 'photos/' . $a->data['user']['nickname'] . '/upload'),
  78. '$can_post' => $can_post
  79. ));
  80. }
  81. if (! x($a->page, 'aside')) {
  82. $a->page['aside'] = '';
  83. }
  84. $a->page['aside'] .= $vcard_widget;
  85. $a->page['aside'] .= $photo_albums_widget;
  86. $tpl = get_markup_template("photos_head.tpl");
  87. $a->page['htmlhead'] .= replace_macros($tpl,array(
  88. '$ispublic' => t('everybody')
  89. ));
  90. }
  91. return;
  92. }
  93. function photos_post(App $a) {
  94. logger('mod-photos: photos_post: begin' , LOGGER_DEBUG);
  95. logger('mod_photos: REQUEST ' . print_r($_REQUEST,true), LOGGER_DATA);
  96. logger('mod_photos: FILES ' . print_r($_FILES,true), LOGGER_DATA);
  97. $phototypes = Photo::supportedTypes();
  98. $can_post = false;
  99. $visitor = 0;
  100. $page_owner_uid = $a->data['user']['uid'];
  101. $community_page = (($a->data['user']['page-flags'] == PAGE_COMMUNITY) ? true : false);
  102. if ((local_user()) && (local_user() == $page_owner_uid)) {
  103. $can_post = true;
  104. } else {
  105. if ($community_page && remote_user()) {
  106. $contact_id = 0;
  107. if (is_array($_SESSION['remote'])) {
  108. foreach ($_SESSION['remote'] as $v) {
  109. if ($v['uid'] == $page_owner_uid) {
  110. $contact_id = $v['cid'];
  111. break;
  112. }
  113. }
  114. }
  115. if ($contact_id) {
  116. $r = qu("SELECT `uid` FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1",
  117. intval($contact_id),
  118. intval($page_owner_uid)
  119. );
  120. if (dbm::is_result($r)) {
  121. $can_post = true;
  122. $visitor = $contact_id;
  123. }
  124. }
  125. }
  126. }
  127. if (! $can_post) {
  128. notice( t('Permission denied.') . EOL );
  129. killme();
  130. }
  131. $r = qu("SELECT `contact`.*, `user`.`nickname` FROM `contact` LEFT JOIN `user` ON `user`.`uid` = `contact`.`uid`
  132. WHERE `user`.`uid` = %d AND `self` = 1 LIMIT 1",
  133. intval($page_owner_uid)
  134. );
  135. if (! dbm::is_result($r)) {
  136. notice( t('Contact information unavailable') . EOL);
  137. logger('photos_post: unable to locate contact record for page owner. uid=' . $page_owner_uid);
  138. killme();
  139. }
  140. $owner_record = $r[0];
  141. if (($a->argc > 3) && ($a->argv[2] === 'album')) {
  142. $album = hex2bin($a->argv[3]);
  143. if ($album === t('Profile Photos') || $album === 'Contact Photos' || $album === t('Contact Photos')) {
  144. goaway($_SESSION['photo_return']);
  145. return; // NOTREACHED
  146. }
  147. $r = qu("SELECT `album` FROM `photo` WHERE `album` = '%s' AND `uid` = %d",
  148. dbesc($album),
  149. intval($page_owner_uid)
  150. );
  151. if (!dbm::is_result($r)) {
  152. notice( t('Album not found.') . EOL);
  153. goaway($_SESSION['photo_return']);
  154. return; // NOTREACHED
  155. }
  156. // Check if the user has responded to a delete confirmation query
  157. if ($_REQUEST['canceled']) {
  158. goaway($_SESSION['photo_return']);
  159. }
  160. /*
  161. * RENAME photo album
  162. */
  163. $newalbum = notags(trim($_POST['albumname']));
  164. if ($newalbum != $album) {
  165. q("UPDATE `photo` SET `album` = '%s' WHERE `album` = '%s' AND `uid` = %d",
  166. dbesc($newalbum),
  167. dbesc($album),
  168. intval($page_owner_uid)
  169. );
  170. // Update the photo albums cache
  171. photo_albums($page_owner_uid, true);
  172. $newurl = str_replace(bin2hex($album),bin2hex($newalbum),$_SESSION['photo_return']);
  173. goaway($newurl);
  174. return; // NOTREACHED
  175. }
  176. /*
  177. * DELETE photo album and all its photos
  178. */
  179. if ($_POST['dropalbum'] == t('Delete Album')) {
  180. // Check if we should do HTML-based delete confirmation
  181. if ($_REQUEST['confirm']) {
  182. $drop_url = $a->query_string;
  183. $extra_inputs = array(
  184. array('name' => 'albumname', 'value' => $_POST['albumname']),
  185. );
  186. $a->page['content'] = replace_macros(get_markup_template('confirm.tpl'), array(
  187. '$method' => 'post',
  188. '$message' => t('Do you really want to delete this photo album and all its photos?'),
  189. '$extra_inputs' => $extra_inputs,
  190. '$confirm' => t('Delete Album'),
  191. '$confirm_url' => $drop_url,
  192. '$confirm_name' => 'dropalbum', // Needed so that confirmation will bring us back into this if statement
  193. '$cancel' => t('Cancel'),
  194. ));
  195. $a->error = 1; // Set $a->error so the other module functions don't execute
  196. return;
  197. }
  198. $res = array();
  199. // get the list of photos we are about to delete
  200. if ($visitor) {
  201. $r = q("SELECT distinct(`resource-id`) as `rid` FROM `photo` WHERE `contact-id` = %d AND `uid` = %d AND `album` = '%s'",
  202. intval($visitor),
  203. intval($page_owner_uid),
  204. dbesc($album)
  205. );
  206. } else {
  207. $r = q("SELECT distinct(`resource-id`) as `rid` FROM `photo` WHERE `uid` = %d AND `album` = '%s'",
  208. intval(local_user()),
  209. dbesc($album)
  210. );
  211. }
  212. if (dbm::is_result($r)) {
  213. foreach ($r as $rr) {
  214. $res[] = "'" . dbesc($rr['rid']) . "'" ;
  215. }
  216. } else {
  217. goaway($_SESSION['photo_return']);
  218. return; // NOTREACHED
  219. }
  220. $str_res = implode(',', $res);
  221. // remove the associated photos
  222. q("DELETE FROM `photo` WHERE `resource-id` IN ( $str_res ) AND `uid` = %d",
  223. intval($page_owner_uid)
  224. );
  225. // find and delete the corresponding item with all the comments and likes/dislikes
  226. $r = q("SELECT `parent-uri` FROM `item` WHERE `resource-id` IN ( $str_res ) AND `uid` = %d",
  227. intval($page_owner_uid)
  228. );
  229. if (dbm::is_result($r)) {
  230. foreach ($r as $rr) {
  231. q("UPDATE `item` SET `deleted` = 1, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d",
  232. dbesc(datetime_convert()),
  233. dbesc($rr['parent-uri']),
  234. intval($page_owner_uid)
  235. );
  236. create_tags_from_itemuri($rr['parent-uri'], $page_owner_uid);
  237. delete_thread_uri($rr['parent-uri'], $page_owner_uid);
  238. $drop_id = intval($rr['id']);
  239. // send the notification upstream/downstream as the case may be
  240. if ($rr['visible']) {
  241. proc_run(PRIORITY_HIGH, "include/notifier.php", "drop", $drop_id);
  242. }
  243. }
  244. }
  245. // Update the photo albums cache
  246. photo_albums($page_owner_uid, true);
  247. }
  248. goaway('photos/' . $a->data['user']['nickname']);
  249. return; // NOTREACHED
  250. }
  251. // Check if the user has responded to a delete confirmation query for a single photo
  252. if (($a->argc > 2) && $_REQUEST['canceled']) {
  253. goaway($_SESSION['photo_return']);
  254. }
  255. if (($a->argc > 2) && (x($_POST,'delete')) && ($_POST['delete'] == t('Delete Photo'))) {
  256. // same as above but remove single photo
  257. // Check if we should do HTML-based delete confirmation
  258. if ($_REQUEST['confirm']) {
  259. $drop_url = $a->query_string;
  260. $a->page['content'] = replace_macros(get_markup_template('confirm.tpl'), array(
  261. '$method' => 'post',
  262. '$message' => t('Do you really want to delete this photo?'),
  263. '$extra_inputs' => array(),
  264. '$confirm' => t('Delete Photo'),
  265. '$confirm_url' => $drop_url,
  266. '$confirm_name' => 'delete', // Needed so that confirmation will bring us back into this if statement
  267. '$cancel' => t('Cancel'),
  268. ));
  269. $a->error = 1; // Set $a->error so the other module functions don't execute
  270. return;
  271. }
  272. if ($visitor) {
  273. $r = q("SELECT `id`, `resource-id` FROM `photo` WHERE `contact-id` = %d AND `uid` = %d AND `resource-id` = '%s' LIMIT 1",
  274. intval($visitor),
  275. intval($page_owner_uid),
  276. dbesc($a->argv[2])
  277. );
  278. } else {
  279. $r = q("SELECT `id`, `resource-id` FROM `photo` WHERE `uid` = %d AND `resource-id` = '%s' LIMIT 1",
  280. intval(local_user()),
  281. dbesc($a->argv[2])
  282. );
  283. }
  284. if (dbm::is_result($r)) {
  285. q("DELETE FROM `photo` WHERE `uid` = %d AND `resource-id` = '%s'",
  286. intval($page_owner_uid),
  287. dbesc($r[0]['resource-id'])
  288. );
  289. $i = q("SELECT * FROM `item` WHERE `resource-id` = '%s' AND `uid` = %d LIMIT 1",
  290. dbesc($r[0]['resource-id']),
  291. intval($page_owner_uid)
  292. );
  293. if (dbm::is_result($i)) {
  294. q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d",
  295. dbesc(datetime_convert()),
  296. dbesc(datetime_convert()),
  297. dbesc($i[0]['uri']),
  298. intval($page_owner_uid)
  299. );
  300. create_tags_from_itemuri($i[0]['uri'], $page_owner_uid);
  301. delete_thread_uri($i[0]['uri'], $page_owner_uid);
  302. $url = App::get_baseurl();
  303. $drop_id = intval($i[0]['id']);
  304. // Update the photo albums cache
  305. photo_albums($page_owner_uid, true);
  306. if ($i[0]['visible']) {
  307. proc_run(PRIORITY_HIGH, "include/notifier.php", "drop", $drop_id);
  308. }
  309. }
  310. }
  311. goaway('photos/' . $a->data['user']['nickname']);
  312. return; // NOTREACHED
  313. }
  314. if (($a->argc > 2) && ((x($_POST,'desc') !== false) || (x($_POST,'newtag') !== false)) || (x($_POST,'albname') !== false)) {
  315. $desc = ((x($_POST,'desc')) ? notags(trim($_POST['desc'])) : '');
  316. $rawtags = ((x($_POST,'newtag')) ? notags(trim($_POST['newtag'])) : '');
  317. $item_id = ((x($_POST,'item_id')) ? intval($_POST['item_id']) : 0);
  318. $albname = ((x($_POST,'albname')) ? notags(trim($_POST['albname'])) : '');
  319. $origaname = ((x($_POST,'origaname')) ? notags(trim($_POST['origaname'])) : '');
  320. $str_group_allow = perms2str($_POST['group_allow']);
  321. $str_contact_allow = perms2str($_POST['contact_allow']);
  322. $str_group_deny = perms2str($_POST['group_deny']);
  323. $str_contact_deny = perms2str($_POST['contact_deny']);
  324. $resource_id = $a->argv[2];
  325. if (! strlen($albname)) {
  326. $albname = datetime_convert('UTC',date_default_timezone_get(),'now', 'Y');
  327. }
  328. if ((x($_POST,'rotate') !== false) &&
  329. ( (intval($_POST['rotate']) == 1) || (intval($_POST['rotate']) == 2) )) {
  330. logger('rotate');
  331. $r = q("SELECT * FROM `photo` WHERE `resource-id` = '%s' AND `uid` = %d AND `scale` = 0 LIMIT 1",
  332. dbesc($resource_id),
  333. intval($page_owner_uid)
  334. );
  335. if (dbm::is_result($r)) {
  336. $ph = new Photo($r[0]['data'], $r[0]['type']);
  337. if ($ph->is_valid()) {
  338. $rotate_deg = ( (intval($_POST['rotate']) == 1) ? 270 : 90 );
  339. $ph->rotate($rotate_deg);
  340. $width = $ph->getWidth();
  341. $height = $ph->getHeight();
  342. $x = q("UPDATE `photo` SET `data` = '%s', `height` = %d, `width` = %d WHERE `resource-id` = '%s' AND `uid` = %d AND `scale` = 0",
  343. dbesc($ph->imageString()),
  344. intval($height),
  345. intval($width),
  346. dbesc($resource_id),
  347. intval($page_owner_uid)
  348. );
  349. if ($width > 640 || $height > 640) {
  350. $ph->scaleImage(640);
  351. $width = $ph->getWidth();
  352. $height = $ph->getHeight();
  353. $x = q("UPDATE `photo` SET `data` = '%s', `height` = %d, `width` = %d WHERE `resource-id` = '%s' AND `uid` = %d AND `scale` = 1",
  354. dbesc($ph->imageString()),
  355. intval($height),
  356. intval($width),
  357. dbesc($resource_id),
  358. intval($page_owner_uid)
  359. );
  360. }
  361. if ($width > 320 || $height > 320) {
  362. $ph->scaleImage(320);
  363. $width = $ph->getWidth();
  364. $height = $ph->getHeight();
  365. $x = q("UPDATE `photo` SET `data` = '%s', `height` = %d, `width` = %d WHERE `resource-id` = '%s' AND `uid` = %d AND `scale` = 2",
  366. dbesc($ph->imageString()),
  367. intval($height),
  368. intval($width),
  369. dbesc($resource_id),
  370. intval($page_owner_uid)
  371. );
  372. }
  373. }
  374. }
  375. }
  376. $p = q("SELECT * FROM `photo` WHERE `resource-id` = '%s' AND `uid` = %d ORDER BY `scale` DESC",
  377. dbesc($resource_id),
  378. intval($page_owner_uid)
  379. );
  380. if (dbm::is_result($p)) {
  381. $ext = $phototypes[$p[0]['type']];
  382. $r = q("UPDATE `photo` SET `desc` = '%s', `album` = '%s', `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s' WHERE `resource-id` = '%s' AND `uid` = %d",
  383. dbesc($desc),
  384. dbesc($albname),
  385. dbesc($str_contact_allow),
  386. dbesc($str_group_allow),
  387. dbesc($str_contact_deny),
  388. dbesc($str_group_deny),
  389. dbesc($resource_id),
  390. intval($page_owner_uid)
  391. );
  392. // Update the photo albums cache if album name was changed
  393. if ($albname !== $origaname) {
  394. photo_albums($page_owner_uid, true);
  395. }
  396. }
  397. /* Don't make the item visible if the only change was the album name */
  398. $visibility = 0;
  399. if ($p[0]['desc'] !== $desc || strlen($rawtags)) {
  400. $visibility = 1;
  401. }
  402. if (! $item_id) {
  403. // Create item container
  404. $title = '';
  405. $uri = item_new_uri($a->get_hostname(),$page_owner_uid);
  406. $arr = array();
  407. $arr['guid'] = get_guid(32);
  408. $arr['uid'] = $page_owner_uid;
  409. $arr['uri'] = $uri;
  410. $arr['parent-uri'] = $uri;
  411. $arr['type'] = 'photo';
  412. $arr['wall'] = 1;
  413. $arr['resource-id'] = $p[0]['resource-id'];
  414. $arr['contact-id'] = $owner_record['id'];
  415. $arr['owner-name'] = $owner_record['name'];
  416. $arr['owner-link'] = $owner_record['url'];
  417. $arr['owner-avatar'] = $owner_record['thumb'];
  418. $arr['author-name'] = $owner_record['name'];
  419. $arr['author-link'] = $owner_record['url'];
  420. $arr['author-avatar'] = $owner_record['thumb'];
  421. $arr['title'] = $title;
  422. $arr['allow_cid'] = $p[0]['allow_cid'];
  423. $arr['allow_gid'] = $p[0]['allow_gid'];
  424. $arr['deny_cid'] = $p[0]['deny_cid'];
  425. $arr['deny_gid'] = $p[0]['deny_gid'];
  426. $arr['last-child'] = 1;
  427. $arr['visible'] = $visibility;
  428. $arr['origin'] = 1;
  429. $arr['body'] = '[url=' . App::get_baseurl() . '/photos/' . $a->data['user']['nickname'] . '/image/' . $p[0]['resource-id'] . ']'
  430. . '[img]' . App::get_baseurl() . '/photo/' . $p[0]['resource-id'] . '-' . $p[0]['scale'] . '.'. $ext . '[/img]'
  431. . '[/url]';
  432. $item_id = item_store($arr);
  433. }
  434. if ($item_id) {
  435. $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1",
  436. intval($item_id),
  437. intval($page_owner_uid)
  438. );
  439. }
  440. if (dbm::is_result($r)) {
  441. $old_tag = $r[0]['tag'];
  442. $old_inform = $r[0]['inform'];
  443. }
  444. if (strlen($rawtags)) {
  445. $str_tags = '';
  446. $inform = '';
  447. // if the new tag doesn't have a namespace specifier (@foo or #foo) give it a hashtag
  448. $x = substr($rawtags,0,1);
  449. if ($x !== '@' && $x !== '#') {
  450. $rawtags = '#' . $rawtags;
  451. }
  452. $taginfo = array();
  453. $tags = get_tags($rawtags);
  454. if (count($tags)) {
  455. foreach ($tags as $tag) {
  456. if (isset($profile)) {
  457. unset($profile);
  458. }
  459. if (strpos($tag, '@') === 0) {
  460. $name = substr($tag,1);
  461. if ((strpos($name, '@')) || (strpos($name, 'http://'))) {
  462. $newname = $name;
  463. $links = @Probe::lrdd($name);
  464. if (count($links)) {
  465. foreach ($links as $link) {
  466. if ($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page') {
  467. $profile = $link['@attributes']['href'];
  468. }
  469. if ($link['@attributes']['rel'] === 'salmon') {
  470. $salmon = '$url:' . str_replace(',', '%sc', $link['@attributes']['href']);
  471. if (strlen($inform)) {
  472. $inform .= ',';
  473. }
  474. $inform .= $salmon;
  475. }
  476. }
  477. }
  478. $taginfo[] = array($newname, $profile, $salmon);
  479. } else {
  480. $newname = $name;
  481. $alias = '';
  482. $tagcid = 0;
  483. if (strrpos($newname, '+')) {
  484. $tagcid = intval(substr($newname, strrpos($newname, '+') + 1));
  485. }
  486. if ($tagcid) {
  487. $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
  488. intval($tagcid),
  489. intval($profile_uid)
  490. );
  491. } else {
  492. $newname = str_replace('_',' ',$name);
  493. //select someone from this user's contacts by name
  494. $r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `uid` = %d LIMIT 1",
  495. dbesc($newname),
  496. intval($page_owner_uid)
  497. );
  498. if (! dbm::is_result($r)) {
  499. //select someone by attag or nick and the name passed in
  500. $r = q("SELECT * FROM `contact` WHERE `attag` = '%s' OR `nick` = '%s' AND `uid` = %d ORDER BY `attag` DESC LIMIT 1",
  501. dbesc($name),
  502. dbesc($name),
  503. intval($page_owner_uid)
  504. );
  505. }
  506. }
  507. if (dbm::is_result($r)) {
  508. $newname = $r[0]['name'];
  509. $profile = $r[0]['url'];
  510. $notify = 'cid:' . $r[0]['id'];
  511. if (strlen($inform)) {
  512. $inform .= ',';
  513. }
  514. $inform .= $notify;
  515. }
  516. }
  517. if ($profile) {
  518. if (substr($notify, 0, 4) === 'cid:') {
  519. $taginfo[] = array($newname, $profile, $notify, $r[0], '@[url=' . str_replace(',','%2c',$profile) . ']' . $newname . '[/url]');
  520. } else {
  521. $taginfo[] = array($newname, $profile, $notify, null, $str_tags .= '@[url=' . $profile . ']' . $newname . '[/url]');
  522. }
  523. if (strlen($str_tags)) {
  524. $str_tags .= ',';
  525. }
  526. $profile = str_replace(',', '%2c', $profile);
  527. $str_tags .= '@[url='.$profile.']'.$newname.'[/url]';
  528. }
  529. } elseif (strpos($tag, '#') === 0) {
  530. $tagname = substr($tag, 1);
  531. $str_tags .= '#[url=' . App::get_baseurl() . "/search?tag=" . $tagname . ']' . $tagname . '[/url]';
  532. }
  533. }
  534. }
  535. $newtag = $old_tag;
  536. if (strlen($newtag) && strlen($str_tags)) {
  537. $newtag .= ',';
  538. }
  539. $newtag .= $str_tags;
  540. $newinform = $old_inform;
  541. if (strlen($newinform) && strlen($inform)) {
  542. $newinform .= ',';
  543. }
  544. $newinform .= $inform;
  545. $r = q("UPDATE `item` SET `tag` = '%s', `inform` = '%s', `edited` = '%s', `changed` = '%s' WHERE `id` = %d AND `uid` = %d",
  546. dbesc($newtag),
  547. dbesc($newinform),
  548. dbesc(datetime_convert()),
  549. dbesc(datetime_convert()),
  550. intval($item_id),
  551. intval($page_owner_uid)
  552. );
  553. create_tags_from_item($item_id);
  554. update_thread($item_id);
  555. $best = 0;
  556. foreach ($p as $scales) {
  557. if (intval($scales['scale']) == 2) {
  558. $best = 2;
  559. break;
  560. }
  561. if (intval($scales['scale']) == 4) {
  562. $best = 4;
  563. break;
  564. }
  565. }
  566. if (count($taginfo)) {
  567. foreach ($taginfo as $tagged) {
  568. $uri = item_new_uri($a->get_hostname(),$page_owner_uid);
  569. $arr = array();
  570. $arr['guid'] = get_guid(32);
  571. $arr['uid'] = $page_owner_uid;
  572. $arr['uri'] = $uri;
  573. $arr['parent-uri'] = $uri;
  574. $arr['type'] = 'activity';
  575. $arr['wall'] = 1;
  576. $arr['contact-id'] = $owner_record['id'];
  577. $arr['owner-name'] = $owner_record['name'];
  578. $arr['owner-link'] = $owner_record['url'];
  579. $arr['owner-avatar'] = $owner_record['thumb'];
  580. $arr['author-name'] = $owner_record['name'];
  581. $arr['author-link'] = $owner_record['url'];
  582. $arr['author-avatar'] = $owner_record['thumb'];
  583. $arr['title'] = '';
  584. $arr['allow_cid'] = $p[0]['allow_cid'];
  585. $arr['allow_gid'] = $p[0]['allow_gid'];
  586. $arr['deny_cid'] = $p[0]['deny_cid'];
  587. $arr['deny_gid'] = $p[0]['deny_gid'];
  588. $arr['last-child'] = 1;
  589. $arr['visible'] = 1;
  590. $arr['verb'] = ACTIVITY_TAG;
  591. $arr['object-type'] = ACTIVITY_OBJ_PERSON;
  592. $arr['target-type'] = ACTIVITY_OBJ_IMAGE;
  593. $arr['tag'] = $tagged[4];
  594. $arr['inform'] = $tagged[2];
  595. $arr['origin'] = 1;
  596. $arr['body'] = sprintf( t('%1$s was tagged in %2$s by %3$s'), '[url=' . $tagged[1] . ']' . $tagged[0] . '[/url]', '[url=' . App::get_baseurl() . '/photos/' . $owner_record['nickname'] . '/image/' . $p[0]['resource-id'] . ']' . t('a photo') . '[/url]', '[url=' . $owner_record['url'] . ']' . $owner_record['name'] . '[/url]') ;
  597. $arr['body'] .= "\n\n" . '[url=' . App::get_baseurl() . '/photos/' . $owner_record['nickname'] . '/image/' . $p[0]['resource-id'] . ']' . '[img]' . App::get_baseurl() . "/photo/" . $p[0]['resource-id'] . '-' . $best . '.' . $ext . '[/img][/url]' . "\n" ;
  598. $arr['object'] = '<object><type>' . ACTIVITY_OBJ_PERSON . '</type><title>' . $tagged[0] . '</title><id>' . $tagged[1] . '/' . $tagged[0] . '</id>';
  599. $arr['object'] .= '<link>' . xmlify('<link rel="alternate" type="text/html" href="' . $tagged[1] . '" />' . "\n");
  600. if ($tagged[3]) {
  601. $arr['object'] .= xmlify('<link rel="photo" type="'.$p[0]['type'].'" href="' . $tagged[3]['photo'] . '" />' . "\n");
  602. }
  603. $arr['object'] .= '</link></object>' . "\n";
  604. $arr['target'] = '<target><type>' . ACTIVITY_OBJ_IMAGE . '</type><title>' . $p[0]['desc'] . '</title><id>'
  605. . App::get_baseurl() . '/photos/' . $owner_record['nickname'] . '/image/' . $p[0]['resource-id'] . '</id>';
  606. $arr['target'] .= '<link>' . xmlify('<link rel="alternate" type="text/html" href="' . App::get_baseurl() . '/photos/' . $owner_record['nickname'] . '/image/' . $p[0]['resource-id'] . '" />' . "\n" . '<link rel="preview" type="'.$p[0]['type'].'" href="' . App::get_baseurl() . "/photo/" . $p[0]['resource-id'] . '-' . $best . '.' . $ext . '" />') . '</link></target>';
  607. $item_id = item_store($arr);
  608. if ($item_id) {
  609. proc_run(PRIORITY_HIGH, "include/notifier.php", "tag", $item_id);
  610. }
  611. }
  612. }
  613. }
  614. goaway($_SESSION['photo_return']);
  615. return; // NOTREACHED
  616. }
  617. /**
  618. * default post action - upload a photo
  619. */
  620. call_hooks('photo_post_init', $_POST);
  621. /**
  622. * Determine the album to use
  623. */
  624. $album = notags(trim($_REQUEST['album']));
  625. $newalbum = notags(trim($_REQUEST['newalbum']));
  626. logger('mod/photos.php: photos_post(): album= ' . $album . ' newalbum= ' . $newalbum , LOGGER_DEBUG);
  627. if (! strlen($album)) {
  628. if (strlen($newalbum)) {
  629. $album = $newalbum;
  630. } else {
  631. $album = datetime_convert('UTC',date_default_timezone_get(),'now', 'Y');
  632. }
  633. }
  634. /*
  635. * We create a wall item for every photo, but we don't want to
  636. * overwhelm the data stream with a hundred newly uploaded photos.
  637. * So we will make the first photo uploaded to this album in the last several hours
  638. * visible by default, the rest will become visible over time when and if
  639. * they acquire comments, likes, dislikes, and/or tags
  640. */
  641. $r = q("SELECT * FROM `photo` WHERE `album` = '%s' AND `uid` = %d AND `created` > UTC_TIMESTAMP() - INTERVAL 3 HOUR ",
  642. dbesc($album),
  643. intval($page_owner_uid)
  644. );
  645. if ((! dbm::is_result($r)) || ($album == t('Profile Photos'))) {
  646. $visible = 1;
  647. } else {
  648. $visible = 0;
  649. }
  650. if (intval($_REQUEST['not_visible']) || $_REQUEST['not_visible'] === 'true') {
  651. $visible = 0;
  652. }
  653. $str_group_allow = perms2str(((is_array($_REQUEST['group_allow'])) ? $_REQUEST['group_allow'] : explode(',', $_REQUEST['group_allow'])));
  654. $str_contact_allow = perms2str(((is_array($_REQUEST['contact_allow'])) ? $_REQUEST['contact_allow'] : explode(',', $_REQUEST['contact_allow'])));
  655. $str_group_deny = perms2str(((is_array($_REQUEST['group_deny'])) ? $_REQUEST['group_deny'] : explode(',', $_REQUEST['group_deny'])));
  656. $str_contact_deny = perms2str(((is_array($_REQUEST['contact_deny'])) ? $_REQUEST['contact_deny'] : explode(',', $_REQUEST['contact_deny'])));
  657. $ret = array('src' => '', 'filename' => '', 'filesize' => 0, 'type' => '');
  658. call_hooks('photo_post_file',$ret);
  659. if (x($ret,'src') && x($ret,'filesize')) {
  660. $src = $ret['src'];
  661. $filename = $ret['filename'];
  662. $filesize = $ret['filesize'];
  663. $type = $ret['type'];
  664. } else {
  665. $src = $_FILES['userfile']['tmp_name'];
  666. $filename = basename($_FILES['userfile']['name']);
  667. $filesize = intval($_FILES['userfile']['size']);
  668. $type = $_FILES['userfile']['type'];
  669. }
  670. if ($type == "") {
  671. $type = guess_image_type($filename);
  672. }
  673. logger('photos: upload: received file: ' . $filename . ' as ' . $src . ' ('. $type . ') ' . $filesize . ' bytes', LOGGER_DEBUG);
  674. $maximagesize = get_config('system','maximagesize');
  675. if (($maximagesize) && ($filesize > $maximagesize)) {
  676. notice( sprintf(t('Image exceeds size limit of %s'), formatBytes($maximagesize)) . EOL);
  677. @unlink($src);
  678. $foo = 0;
  679. call_hooks('photo_post_end',$foo);
  680. return;
  681. }
  682. if (! $filesize) {
  683. notice( t('Image file is empty.') . EOL);
  684. @unlink($src);
  685. $foo = 0;
  686. call_hooks('photo_post_end',$foo);
  687. return;
  688. }
  689. logger('mod/photos.php: photos_post(): loading the contents of ' . $src , LOGGER_DEBUG);
  690. $imagedata = @file_get_contents($src);
  691. $limit = service_class_fetch($a->data['user']['uid'], 'photo_upload_limit');
  692. if ($limit) {
  693. $r = q("SELECT SUM(OCTET_LENGTH(`data`)) AS `total` FROM `photo` WHERE `uid` = %d AND `scale` = 0 AND `album` != 'Contact Photos'",
  694. intval($a->data['user']['uid'])
  695. );
  696. $size = $r[0]['total'];
  697. if (($size + strlen($imagedata)) > $limit) {
  698. notice( upgrade_message() . EOL );
  699. @unlink($src);
  700. $foo = 0;
  701. call_hooks('photo_post_end',$foo);
  702. killme();
  703. }
  704. }
  705. $ph = new Photo($imagedata, $type);
  706. if (! $ph->is_valid()) {
  707. logger('mod/photos.php: photos_post(): unable to process image' , LOGGER_DEBUG);
  708. notice( t('Unable to process image.') . EOL );
  709. @unlink($src);
  710. $foo = 0;
  711. call_hooks('photo_post_end',$foo);
  712. killme();
  713. }
  714. $exif = $ph->orient($src);
  715. @unlink($src);
  716. $max_length = get_config('system', 'max_image_length');
  717. if (! $max_length) {
  718. $max_length = MAX_IMAGE_LENGTH;
  719. }
  720. if ($max_length > 0) {
  721. $ph->scaleImage($max_length);
  722. }
  723. $width = $ph->getWidth();
  724. $height = $ph->getHeight();
  725. $smallest = 0;
  726. $photo_hash = photo_new_resource();
  727. $r = $ph->store($page_owner_uid, $visitor, $photo_hash, $filename, $album, 0 , 0, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny);
  728. if (! $r) {
  729. logger('mod/photos.php: photos_post(): image store failed' , LOGGER_DEBUG);
  730. notice( t('Image upload failed.') . EOL );
  731. killme();
  732. }
  733. if ($width > 640 || $height > 640) {
  734. $ph->scaleImage(640);
  735. $ph->store($page_owner_uid, $visitor, $photo_hash, $filename, $album, 1, 0, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny);
  736. $smallest = 1;
  737. }
  738. if ($width > 320 || $height > 320) {
  739. $ph->scaleImage(320);
  740. $ph->store($page_owner_uid, $visitor, $photo_hash, $filename, $album, 2, 0, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny);
  741. $smallest = 2;
  742. }
  743. $basename = basename($filename);
  744. $uri = item_new_uri($a->get_hostname(), $page_owner_uid);
  745. // Create item container
  746. $lat = $lon = null;
  747. /// @TODO merge these 2 if() into one?
  748. if ($exif && $exif['GPS']) {
  749. if (feature_enabled($channel_id,'photo_location')) {
  750. $lat = getGps($exif['GPS']['GPSLatitude'], $exif['GPS']['GPSLatitudeRef']);
  751. $lon = getGps($exif['GPS']['GPSLongitude'], $exif['GPS']['GPSLongitudeRef']);
  752. }
  753. }
  754. $arr = array();
  755. if ($lat && $lon) {
  756. $arr['coord'] = $lat . ' ' . $lon;
  757. }
  758. $arr['guid'] = get_guid(32);
  759. $arr['uid'] = $page_owner_uid;
  760. $arr['uri'] = $uri;
  761. $arr['parent-uri'] = $uri;
  762. $arr['type'] = 'photo';
  763. $arr['wall'] = 1;
  764. $arr['resource-id'] = $photo_hash;
  765. $arr['contact-id'] = $owner_record['id'];
  766. $arr['owner-name'] = $owner_record['name'];
  767. $arr['owner-link'] = $owner_record['url'];
  768. $arr['owner-avatar'] = $owner_record['thumb'];
  769. $arr['author-name'] = $owner_record['name'];
  770. $arr['author-link'] = $owner_record['url'];
  771. $arr['author-avatar'] = $owner_record['thumb'];
  772. $arr['title'] = '';
  773. $arr['allow_cid'] = $str_contact_allow;
  774. $arr['allow_gid'] = $str_group_allow;
  775. $arr['deny_cid'] = $str_contact_deny;
  776. $arr['deny_gid'] = $str_group_deny;
  777. $arr['last-child'] = 1;
  778. $arr['visible'] = $visible;
  779. $arr['origin'] = 1;
  780. $arr['body'] = '[url=' . App::get_baseurl() . '/photos/' . $owner_record['nickname'] . '/image/' . $photo_hash . ']'
  781. . '[img]' . App::get_baseurl() . "/photo/{$photo_hash}-{$smallest}.".$ph->getExt() . '[/img]'
  782. . '[/url]';
  783. $item_id = item_store($arr);
  784. // Update the photo albums cache
  785. photo_albums($page_owner_uid, true);
  786. if ($visible) {
  787. proc_run(PRIORITY_HIGH, "include/notifier.php", 'wall-new', $item_id);
  788. }
  789. call_hooks('photo_post_end',intval($item_id));
  790. /*
  791. * addon uploaders should call "killme()" [e.g. exit] within the photo_post_end hook
  792. * if they do not wish to be redirected
  793. */
  794. goaway($_SESSION['photo_return']);
  795. // NOTREACHED
  796. }
  797. function photos_content(App $a) {
  798. // URLs:
  799. // photos/name
  800. // photos/name/upload
  801. // photos/name/upload/xxxxx (xxxxx is album name)
  802. // photos/name/album/xxxxx
  803. // photos/name/album/xxxxx/edit
  804. // photos/name/image/xxxxx
  805. // photos/name/image/xxxxx/edit
  806. if ((get_config('system', 'block_public')) && (! local_user()) && (! remote_user())) {
  807. notice( t('Public access denied.') . EOL);
  808. return;
  809. }
  810. require_once('include/bbcode.php');
  811. require_once('include/security.php');
  812. require_once('include/conversation.php');
  813. if (! x($a->data,'user')) {
  814. notice( t('No photos selected') . EOL );
  815. return;
  816. }
  817. $phototypes = Photo::supportedTypes();
  818. $_SESSION['photo_return'] = $a->cmd;
  819. //
  820. // Parse arguments
  821. //
  822. if ($a->argc > 3) {
  823. $datatype = $a->argv[2];
  824. $datum = $a->argv[3];
  825. } elseif (($a->argc > 2) && ($a->argv[2] === 'upload')) {
  826. $datatype = 'upload';
  827. } else {
  828. $datatype = 'summary';
  829. }
  830. if ($a->argc > 4) {
  831. $cmd = $a->argv[4];
  832. } else {
  833. $cmd = 'view';
  834. }
  835. //
  836. // Setup permissions structures
  837. //
  838. $can_post = false;
  839. $visitor = 0;
  840. $contact = null;
  841. $remote_contact = false;
  842. $contact_id = 0;
  843. $owner_uid = $a->data['user']['uid'];
  844. $community_page = (($a->data['user']['page-flags'] == PAGE_COMMUNITY) ? true : false);
  845. if ((local_user()) && (local_user() == $owner_uid)) {
  846. $can_post = true;
  847. } else {
  848. if ($community_page && remote_user()) {
  849. if (is_array($_SESSION['remote'])) {
  850. foreach ($_SESSION['remote'] as $v) {
  851. if ($v['uid'] == $owner_uid) {
  852. $contact_id = $v['cid'];
  853. break;
  854. }
  855. }
  856. }
  857. if ($contact_id) {
  858. $r = q("SELECT `uid` FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1",
  859. intval($contact_id),
  860. intval($owner_uid)
  861. );
  862. if (dbm::is_result($r)) {
  863. $can_post = true;
  864. $contact = $r[0];
  865. $remote_contact = true;
  866. $visitor = $contact_id;
  867. }
  868. }
  869. }
  870. }
  871. // perhaps they're visiting - but not a community page, so they wouldn't have write access
  872. if (remote_user() && (! $visitor)) {
  873. $contact_id = 0;
  874. if (is_array($_SESSION['remote'])) {
  875. foreach ($_SESSION['remote'] as $v) {
  876. if ($v['uid'] == $owner_uid) {
  877. $contact_id = $v['cid'];
  878. break;
  879. }
  880. }
  881. }
  882. if ($contact_id) {
  883. $groups = init_groups_visitor($contact_id);
  884. $r = q("SELECT * FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1",
  885. intval($contact_id),
  886. intval($owner_uid)
  887. );
  888. if (dbm::is_result($r)) {
  889. $contact = $r[0];
  890. $remote_contact = true;
  891. }
  892. }
  893. }
  894. /// @TODO merge these 2 if() into one?
  895. if (! $remote_contact) {
  896. if (local_user()) {
  897. $contact_id = $_SESSION['cid'];
  898. $contact = $a->contact;
  899. }
  900. }
  901. if ($a->data['user']['hidewall'] && (local_user() != $owner_uid) && (! $remote_contact)) {
  902. notice( t('Access to this item is restricted.') . EOL);
  903. return;
  904. }
  905. $sql_extra = permissions_sql($owner_uid,$remote_contact,$groups);
  906. $o = "";
  907. // tabs
  908. $is_owner = (local_user() && (local_user() == $owner_uid));
  909. $o .= profile_tabs($a, $is_owner, $a->data['user']['nickname']);
  910. /**
  911. * Display upload form
  912. */
  913. if ($datatype === 'upload') {
  914. if (! ($can_post)) {
  915. notice(t('Permission denied.'));
  916. return;
  917. }
  918. $selname = (($datum) ? hex2bin($datum) : '');
  919. $albumselect = '';
  920. $albumselect .= '<option value="" ' . ((! $selname) ? ' selected="selected" ' : '') . '>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</option>';
  921. if (count($a->data['albums'])) {
  922. foreach ($a->data['albums'] as $album) {
  923. if (($album['album'] === '') || ($album['album'] === 'Contact Photos') || ($album['album'] === t('Contact Photos'))) {
  924. continue;
  925. }
  926. $selected = (($selname === $album['album']) ? ' selected="selected" ' : '');
  927. $albumselect .= '<option value="' . $album['album'] . '"' . $selected . '>' . $album['album'] . '</option>';
  928. }
  929. }
  930. $uploader = '';
  931. $ret = array('post_url' => 'photos/' . $a->data['user']['nickname'],
  932. 'addon_text' => $uploader,
  933. 'default_upload' => true);
  934. call_hooks('photo_upload_form',$ret);
  935. $default_upload_box = replace_macros(get_markup_template('photos_default_uploader_box.tpl'), array());
  936. $default_upload_submit = replace_macros(get_markup_template('photos_default_uploader_submit.tpl'), array(
  937. '$submit' => t('Submit'),
  938. ));
  939. $usage_message = '';
  940. $limit = service_class_fetch($a->data['user']['uid'], 'photo_upload_limit');
  941. if ($limit !== false) {
  942. $r = q("SELECT SUM(`datasize`) AS `total` FROM `photo` WHERE `uid` = %d AND `scale` = 0 AND `album` != 'Contact Photos'",
  943. intval($a->data['user']['uid'])
  944. );
  945. $usage_message = sprintf(t("You have used %1$.2f Mbytes of %2$.2f Mbytes photo storage."), $r[0]['total'] / 1024000, $limit / 1024000 );
  946. }
  947. // Private/public post links for the non-JS ACL form
  948. $private_post = 1;
  949. if ($_REQUEST['public']) {
  950. $private_post = 0;
  951. }
  952. $query_str = $a->query_string;
  953. if (strpos($query_str, 'public=1') !== false) {
  954. $query_str = str_replace(array('?public=1', '&public=1'), array('', ''), $query_str);
  955. }
  956. /*
  957. * I think $a->query_string may never have ? in it, but I could be wrong
  958. * It looks like it's from the index.php?q=[etc] rewrite that the web
  959. * server does, which converts any ? to &, e.g. suggest&ignore=61 for suggest?ignore=61
  960. */
  961. if (strpos($query_str, '?') === false) {
  962. $public_post_link = '?public=1';
  963. } else {
  964. $public_post_link = '&public=1';
  965. }
  966. $tpl = get_markup_template('photos_upload.tpl');
  967. if ($a->theme['template_engine'] === 'internal') {
  968. $albumselect_e = template_escape($albumselect);
  969. $aclselect_e = (($visitor) ? '' : template_escape(populate_acl($a->user)));
  970. } else {
  971. $albumselect_e = $albumselect;
  972. $aclselect_e = (($visitor) ? '' : populate_acl($a->user));
  973. }
  974. <