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.

1798 lines
49 KiB

11 years ago
10 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
10 years ago
9 years ago
11 years ago
10 years ago
11 years ago
9 years ago
11 years ago
9 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
9 years ago
9 years ago
9 years ago
9 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
10 years ago
9 years ago
9 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
9 years ago
9 years ago
9 years ago
11 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 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
9 years ago
9 years ago
10 years ago
  1. <?php
  2. require_once('include/config.php');
  3. require_once('include/network.php');
  4. require_once('include/plugin.php');
  5. require_once('include/text.php');
  6. require_once('include/datetime.php');
  7. require_once('include/pgettext.php');
  8. require_once('include/nav.php');
  9. require_once('include/cache.php');
  10. require_once('library/Mobile_Detect/Mobile_Detect.php');
  11. define ( 'FRIENDICA_PLATFORM', 'Friendica');
  12. define ( 'FRIENDICA_VERSION', '3.0.1500' );
  13. define ( 'DFRN_PROTOCOL_VERSION', '2.23' );
  14. define ( 'DB_UPDATE_VERSION', 1156 );
  15. define ( 'EOL', "<br />\r\n" );
  16. define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' );
  17. /**
  18. *
  19. * Image storage quality. Lower numbers save space at cost of image detail.
  20. * For ease of upgrade, please do not change here. Change jpeg quality with
  21. * $a->config['system']['jpeg_quality'] = n;
  22. * in .htconfig.php, where n is netween 1 and 100, and with very poor results
  23. * below about 50
  24. *
  25. */
  26. define ( 'JPEG_QUALITY', 100 );
  27. /**
  28. * $a->config['system']['png_quality'] from 0 (uncompressed) to 9
  29. */
  30. define ( 'PNG_QUALITY', 8 );
  31. /**
  32. *
  33. * An alternate way of limiting picture upload sizes. Specify the maximum pixel
  34. * length that pictures are allowed to be (for non-square pictures, it will apply
  35. * to the longest side). Pictures longer than this length will be resized to be
  36. * this length (on the longest side, the other side will be scaled appropriately).
  37. * Modify this value using
  38. *
  39. * $a->config['system']['max_image_length'] = n;
  40. *
  41. * in .htconfig.php
  42. *
  43. * If you don't want to set a maximum length, set to -1. The default value is
  44. * defined by 'MAX_IMAGE_LENGTH' below.
  45. *
  46. */
  47. define ( 'MAX_IMAGE_LENGTH', -1 );
  48. /**
  49. * Not yet used
  50. */
  51. define ( 'DEFAULT_DB_ENGINE', 'MyISAM' );
  52. /**
  53. * SSL redirection policies
  54. */
  55. define ( 'SSL_POLICY_NONE', 0 );
  56. define ( 'SSL_POLICY_FULL', 1 );
  57. define ( 'SSL_POLICY_SELFSIGN', 2 );
  58. /**
  59. * log levels
  60. */
  61. define ( 'LOGGER_NORMAL', 0 );
  62. define ( 'LOGGER_TRACE', 1 );
  63. define ( 'LOGGER_DEBUG', 2 );
  64. define ( 'LOGGER_DATA', 3 );
  65. define ( 'LOGGER_ALL', 4 );
  66. /**
  67. * registration policies
  68. */
  69. define ( 'REGISTER_CLOSED', 0 );
  70. define ( 'REGISTER_APPROVE', 1 );
  71. define ( 'REGISTER_OPEN', 2 );
  72. /**
  73. * relationship types
  74. */
  75. define ( 'CONTACT_IS_FOLLOWER', 1);
  76. define ( 'CONTACT_IS_SHARING', 2);
  77. define ( 'CONTACT_IS_FRIEND', 3);
  78. /**
  79. * DB update return values
  80. */
  81. define ( 'UPDATE_SUCCESS', 0);
  82. define ( 'UPDATE_FAILED', 1);
  83. /**
  84. *
  85. * page/profile types
  86. *
  87. * PAGE_NORMAL is a typical personal profile account
  88. * PAGE_SOAPBOX automatically approves all friend requests as CONTACT_IS_SHARING, (readonly)
  89. * PAGE_COMMUNITY automatically approves all friend requests as CONTACT_IS_SHARING, but with
  90. * write access to wall and comments (no email and not included in page owner's ACL lists)
  91. * PAGE_FREELOVE automatically approves all friend requests as full friends (CONTACT_IS_FRIEND).
  92. *
  93. */
  94. define ( 'PAGE_NORMAL', 0 );
  95. define ( 'PAGE_SOAPBOX', 1 );
  96. define ( 'PAGE_COMMUNITY', 2 );
  97. define ( 'PAGE_FREELOVE', 3 );
  98. define ( 'PAGE_BLOG', 4 );
  99. define ( 'PAGE_PRVGROUP', 5 );
  100. /**
  101. * Network and protocol family types
  102. */
  103. define ( 'NETWORK_DFRN', 'dfrn'); // Friendica, Mistpark, other DFRN implementations
  104. define ( 'NETWORK_ZOT', 'zot!'); // Zot!
  105. define ( 'NETWORK_OSTATUS', 'stat'); // status.net, identi.ca, GNU-social, other OStatus implementations
  106. define ( 'NETWORK_FEED', 'feed'); // RSS/Atom feeds with no known "post/notify" protocol
  107. define ( 'NETWORK_DIASPORA', 'dspr'); // Diaspora
  108. define ( 'NETWORK_MAIL', 'mail'); // IMAP/POP
  109. define ( 'NETWORK_MAIL2', 'mai2'); // extended IMAP/POP
  110. define ( 'NETWORK_FACEBOOK', 'face'); // Facebook API
  111. define ( 'NETWORK_LINKEDIN', 'lnkd'); // LinkedIn
  112. define ( 'NETWORK_XMPP', 'xmpp'); // XMPP
  113. define ( 'NETWORK_MYSPACE', 'mysp'); // MySpace
  114. define ( 'NETWORK_GPLUS', 'goog'); // Google+
  115. define ( 'NETWORK_PHANTOM', 'unkn'); // Place holder
  116. /**
  117. * These numbers are used in stored permissions
  118. * and existing allocations MUST NEVER BE CHANGED
  119. * OR RE-ASSIGNED! You may only add to them.
  120. */
  121. $netgroup_ids = array(
  122. NETWORK_DFRN => (-1),
  123. NETWORK_ZOT => (-2),
  124. NETWORK_OSTATUS => (-3),
  125. NETWORK_FEED => (-4),
  126. NETWORK_DIASPORA => (-5),
  127. NETWORK_MAIL => (-6),
  128. NETWORK_MAIL2 => (-7),
  129. NETWORK_FACEBOOK => (-8),
  130. NETWORK_LINKEDIN => (-9),
  131. NETWORK_XMPP => (-10),
  132. NETWORK_MYSPACE => (-11),
  133. NETWORK_GPLUS => (-12),
  134. NETWORK_PHANTOM => (-127),
  135. );
  136. /**
  137. * Maximum number of "people who like (or don't like) this" that we will list by name
  138. */
  139. define ( 'MAX_LIKERS', 75);
  140. /**
  141. * Communication timeout
  142. */
  143. define ( 'ZCURL_TIMEOUT' , (-1));
  144. /**
  145. * email notification options
  146. */
  147. define ( 'NOTIFY_INTRO', 0x0001 );
  148. define ( 'NOTIFY_CONFIRM', 0x0002 );
  149. define ( 'NOTIFY_WALL', 0x0004 );
  150. define ( 'NOTIFY_COMMENT', 0x0008 );
  151. define ( 'NOTIFY_MAIL', 0x0010 );
  152. define ( 'NOTIFY_SUGGEST', 0x0020 );
  153. define ( 'NOTIFY_PROFILE', 0x0040 );
  154. define ( 'NOTIFY_TAGSELF', 0x0080 );
  155. define ( 'NOTIFY_TAGSHARE', 0x0100 );
  156. define ( 'NOTIFY_POKE', 0x0200 );
  157. define ( 'NOTIFY_SYSTEM', 0x8000 );
  158. /**
  159. * Tag/term types
  160. */
  161. define ( 'TERM_UNKNOWN', 0 );
  162. define ( 'TERM_HASHTAG', 1 );
  163. define ( 'TERM_MENTION', 2 );
  164. define ( 'TERM_CATEGORY', 3 );
  165. define ( 'TERM_PCATEGORY', 4 );
  166. define ( 'TERM_FILE', 5 );
  167. define ( 'TERM_OBJ_POST', 1 );
  168. define ( 'TERM_OBJ_PHOTO', 2 );
  169. /**
  170. * various namespaces we may need to parse
  171. */
  172. define ( 'NAMESPACE_ZOT', 'http://purl.org/zot' );
  173. define ( 'NAMESPACE_DFRN' , 'http://purl.org/macgirvin/dfrn/1.0' );
  174. define ( 'NAMESPACE_THREAD' , 'http://purl.org/syndication/thread/1.0' );
  175. define ( 'NAMESPACE_TOMB' , 'http://purl.org/atompub/tombstones/1.0' );
  176. define ( 'NAMESPACE_ACTIVITY', 'http://activitystrea.ms/spec/1.0/' );
  177. define ( 'NAMESPACE_ACTIVITY_SCHEMA', 'http://activitystrea.ms/schema/1.0/' );
  178. define ( 'NAMESPACE_MEDIA', 'http://purl.org/syndication/atommedia' );
  179. define ( 'NAMESPACE_SALMON_ME', 'http://salmon-protocol.org/ns/magic-env' );
  180. define ( 'NAMESPACE_OSTATUSSUB', 'http://ostatus.org/schema/1.0/subscribe' );
  181. define ( 'NAMESPACE_GEORSS', 'http://www.georss.org/georss' );
  182. define ( 'NAMESPACE_POCO', 'http://portablecontacts.net/spec/1.0' );
  183. define ( 'NAMESPACE_FEED', 'http://schemas.google.com/g/2010#updates-from' );
  184. define ( 'NAMESPACE_OSTATUS', 'http://ostatus.org/schema/1.0' );
  185. define ( 'NAMESPACE_STATUSNET', 'http://status.net/schema/api/1/' );
  186. define ( 'NAMESPACE_ATOM1', 'http://www.w3.org/2005/Atom' );
  187. /**
  188. * activity stream defines
  189. */
  190. define ( 'ACTIVITY_LIKE', NAMESPACE_ACTIVITY_SCHEMA . 'like' );
  191. define ( 'ACTIVITY_DISLIKE', NAMESPACE_DFRN . '/dislike' );
  192. define ( 'ACTIVITY_OBJ_HEART', NAMESPACE_DFRN . '/heart' );
  193. define ( 'ACTIVITY_FRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'make-friend' );
  194. define ( 'ACTIVITY_REQ_FRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'request-friend' );
  195. define ( 'ACTIVITY_UNFRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'remove-friend' );
  196. define ( 'ACTIVITY_FOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'follow' );
  197. define ( 'ACTIVITY_UNFOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'stop-following' );
  198. define ( 'ACTIVITY_JOIN', NAMESPACE_ACTIVITY_SCHEMA . 'join' );
  199. define ( 'ACTIVITY_POST', NAMESPACE_ACTIVITY_SCHEMA . 'post' );
  200. define ( 'ACTIVITY_UPDATE', NAMESPACE_ACTIVITY_SCHEMA . 'update' );
  201. define ( 'ACTIVITY_TAG', NAMESPACE_ACTIVITY_SCHEMA . 'tag' );
  202. define ( 'ACTIVITY_FAVORITE', NAMESPACE_ACTIVITY_SCHEMA . 'favorite' );
  203. define ( 'ACTIVITY_POKE', NAMESPACE_ZOT . '/activity/poke' );
  204. define ( 'ACTIVITY_MOOD', NAMESPACE_ZOT . '/activity/mood' );
  205. define ( 'ACTIVITY_OBJ_COMMENT', NAMESPACE_ACTIVITY_SCHEMA . 'comment' );
  206. define ( 'ACTIVITY_OBJ_NOTE', NAMESPACE_ACTIVITY_SCHEMA . 'note' );
  207. define ( 'ACTIVITY_OBJ_PERSON', NAMESPACE_ACTIVITY_SCHEMA . 'person' );
  208. define ( 'ACTIVITY_OBJ_PHOTO', NAMESPACE_ACTIVITY_SCHEMA . 'photo' );
  209. define ( 'ACTIVITY_OBJ_P_PHOTO', NAMESPACE_ACTIVITY_SCHEMA . 'profile-photo' );
  210. define ( 'ACTIVITY_OBJ_ALBUM', NAMESPACE_ACTIVITY_SCHEMA . 'photo-album' );
  211. define ( 'ACTIVITY_OBJ_EVENT', NAMESPACE_ACTIVITY_SCHEMA . 'event' );
  212. define ( 'ACTIVITY_OBJ_GROUP', NAMESPACE_ACTIVITY_SCHEMA . 'group' );
  213. define ( 'ACTIVITY_OBJ_TAGTERM', NAMESPACE_DFRN . '/tagterm' );
  214. define ( 'ACTIVITY_OBJ_PROFILE', NAMESPACE_DFRN . '/profile' );
  215. /**
  216. * item weight for query ordering
  217. */
  218. define ( 'GRAVITY_PARENT', 0);
  219. define ( 'GRAVITY_LIKE', 3);
  220. define ( 'GRAVITY_COMMENT', 6);
  221. /**
  222. *
  223. * Reverse the effect of magic_quotes_gpc if it is enabled.
  224. * Please disable magic_quotes_gpc so we don't have to do this.
  225. * See http://php.net/manual/en/security.magicquotes.disabling.php
  226. *
  227. */
  228. function startup() {
  229. error_reporting(E_ERROR | E_WARNING | E_PARSE);
  230. set_time_limit(0);
  231. // This has to be quite large to deal with embedded private photos
  232. ini_set('pcre.backtrack_limit', 500000);
  233. if (get_magic_quotes_gpc()) {
  234. $process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
  235. while (list($key, $val) = each($process)) {
  236. foreach ($val as $k => $v) {
  237. unset($process[$key][$k]);
  238. if (is_array($v)) {
  239. $process[$key][stripslashes($k)] = $v;
  240. $process[] = &$process[$key][stripslashes($k)];
  241. } else {
  242. $process[$key][stripslashes($k)] = stripslashes($v);
  243. }
  244. }
  245. }
  246. unset($process);
  247. }
  248. }
  249. /**
  250. *
  251. * class: App
  252. *
  253. * Our main application structure for the life of this page
  254. * Primarily deals with the URL that got us here
  255. * and tries to make some sense of it, and
  256. * stores our page contents and config storage
  257. * and anything else that might need to be passed around
  258. * before we spit the page out.
  259. *
  260. */
  261. if(! class_exists('App')) {
  262. class App {
  263. public $module_loaded = false;
  264. public $query_string;
  265. public $config;
  266. public $page;
  267. public $profile;
  268. public $user;
  269. public $cid;
  270. public $contact;
  271. public $contacts;
  272. public $page_contact;
  273. public $content;
  274. public $data = array();
  275. public $error = false;
  276. public $cmd;
  277. public $argv;
  278. public $argc;
  279. public $module;
  280. public $pager;
  281. public $strings;
  282. public $path;
  283. public $hooks;
  284. public $timezone;
  285. public $interactive = true;
  286. public $plugins;
  287. public $apps = array();
  288. public $identities;
  289. public $is_mobile;
  290. public $is_tablet;
  291. public $nav_sel;
  292. public $category;
  293. // Allow themes to control internal parameters
  294. // by changing App values in theme.php
  295. //
  296. // Possibly should make these part of the plugin
  297. // system, but it seems like overkill to invoke
  298. // all the plugin machinery just to change a couple
  299. // of values
  300. public $sourcename = '';
  301. public $videowidth = 425;
  302. public $videoheight = 350;
  303. public $force_max_items = 0;
  304. public $theme_thread_allow = true;
  305. private $scheme;
  306. private $hostname;
  307. private $baseurl;
  308. private $db;
  309. private $curl_code;
  310. private $curl_headers;
  311. private $cached_profile_image;
  312. private $cached_profile_picdate;
  313. function __construct() {
  314. global $default_timezone;
  315. $this->timezone = ((x($default_timezone)) ? $default_timezone : 'UTC');
  316. date_default_timezone_set($this->timezone);
  317. $this->config = array();
  318. $this->page = array();
  319. $this->pager= array();
  320. $this->query_string = '';
  321. startup();
  322. $this->scheme = 'http';
  323. if(x($_SERVER,'HTTPS') && $_SERVER['HTTPS'])
  324. $this->scheme = 'https';
  325. elseif(x($_SERVER,'SERVER_PORT') && (intval($_SERVER['SERVER_PORT']) == 443))
  326. $this->scheme = 'https';
  327. if(x($_SERVER,'SERVER_NAME')) {
  328. $this->hostname = $_SERVER['SERVER_NAME'];
  329. // See bug 437 - this didn't work so disabling it
  330. //if(stristr($this->hostname,'xn--')) {
  331. // PHP or webserver may have converted idn to punycode, so
  332. // convert punycode back to utf-8
  333. // require_once('library/simplepie/idn/idna_convert.class.php');
  334. // $x = new idna_convert();
  335. // $this->hostname = $x->decode($_SERVER['SERVER_NAME']);
  336. //}
  337. if(x($_SERVER,'SERVER_PORT') && $_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443)
  338. $this->hostname .= ':' . $_SERVER['SERVER_PORT'];
  339. /**
  340. * Figure out if we are running at the top of a domain
  341. * or in a sub-directory and adjust accordingly
  342. */
  343. $path = trim(dirname($_SERVER['SCRIPT_NAME']),'/\\');
  344. if(isset($path) && strlen($path) && ($path != $this->path))
  345. $this->path = $path;
  346. }
  347. set_include_path(
  348. "include/$this->hostname" . PATH_SEPARATOR
  349. . 'include' . PATH_SEPARATOR
  350. . 'library' . PATH_SEPARATOR
  351. . 'library/phpsec' . PATH_SEPARATOR
  352. . 'library/langdet' . PATH_SEPARATOR
  353. . '.' );
  354. if((x($_SERVER,'QUERY_STRING')) && substr($_SERVER['QUERY_STRING'],0,2) === "q=") {
  355. $this->query_string = substr($_SERVER['QUERY_STRING'],2);
  356. // removing trailing / - maybe a nginx problem
  357. if (substr($this->query_string, 0, 1) == "/")
  358. $this->query_string = substr($this->query_string, 1);
  359. }
  360. if(x($_GET,'q'))
  361. $this->cmd = trim($_GET['q'],'/\\');
  362. // unix style "homedir"
  363. if(substr($this->cmd,0,1) === '~')
  364. $this->cmd = 'profile/' . substr($this->cmd,1);
  365. // Diaspora style profile url
  366. if(substr($this->cmd,0,2) === 'u/')
  367. $this->cmd = 'profile/' . substr($this->cmd,2);
  368. /**
  369. *
  370. * Break the URL path into C style argc/argv style arguments for our
  371. * modules. Given "http://example.com/module/arg1/arg2", $this->argc
  372. * will be 3 (integer) and $this->argv will contain:
  373. * [0] => 'module'
  374. * [1] => 'arg1'
  375. * [2] => 'arg2'
  376. *
  377. *
  378. * There will always be one argument. If provided a naked domain
  379. * URL, $this->argv[0] is set to "home".
  380. *
  381. */
  382. $this->argv = explode('/',$this->cmd);
  383. $this->argc = count($this->argv);
  384. if((array_key_exists('0',$this->argv)) && strlen($this->argv[0])) {
  385. $this->module = str_replace(".", "_", $this->argv[0]);
  386. $this->module = str_replace("-", "_", $this->module);
  387. }
  388. else {
  389. $this->argc = 1;
  390. $this->argv = array('home');
  391. $this->module = 'home';
  392. }
  393. /**
  394. * See if there is any page number information, and initialise
  395. * pagination
  396. */
  397. $this->pager['page'] = ((x($_GET,'page') && intval($_GET['page']) > 0) ? intval($_GET['page']) : 1);
  398. $this->pager['itemspage'] = 50;
  399. $this->pager['start'] = ($this->pager['page'] * $this->pager['itemspage']) - $this->pager['itemspage'];
  400. if($this->pager['start'] < 0)
  401. $this->pager['start'] = 0;
  402. $this->pager['total'] = 0;
  403. /**
  404. * Detect mobile devices
  405. */
  406. $mobile_detect = new Mobile_Detect();
  407. $this->is_mobile = $mobile_detect->isMobile();
  408. $this->is_tablet = $mobile_detect->isTablet();
  409. }
  410. function get_baseurl($ssl = false) {
  411. $scheme = $this->scheme;
  412. if((x($this->config,'system')) && (x($this->config['system'],'ssl_policy'))) {
  413. if(intval($this->config['system']['ssl_policy']) === intval(SSL_POLICY_FULL))
  414. $scheme = 'https';
  415. // Basically, we have $ssl = true on any links which can only be seen by a logged in user
  416. // (and also the login link). Anything seen by an outsider will have it turned off.
  417. if($this->config['system']['ssl_policy'] == SSL_POLICY_SELFSIGN) {
  418. if($ssl)
  419. $scheme = 'https';
  420. else
  421. $scheme = 'http';
  422. }
  423. }
  424. $this->baseurl = $scheme . "://" . $this->hostname . ((isset($this->path) && strlen($this->path)) ? '/' . $this->path : '' );
  425. return $this->baseurl;
  426. }
  427. function set_baseurl($url) {
  428. $parsed = @parse_url($url);
  429. $this->baseurl = $url;
  430. if($parsed) {
  431. $this->scheme = $parsed['scheme'];
  432. $this->hostname = $parsed['host'];
  433. if(x($parsed,'port'))
  434. $this->hostname .= ':' . $parsed['port'];
  435. if(x($parsed,'path'))
  436. $this->path = trim($parsed['path'],'\\/');
  437. }
  438. }
  439. function get_hostname() {
  440. return $this->hostname;
  441. }
  442. function set_hostname($h) {
  443. $this->hostname = $h;
  444. }
  445. function set_path($p) {
  446. $this->path = trim(trim($p),'/');
  447. }
  448. function get_path() {
  449. return $this->path;
  450. }
  451. function set_pager_total($n) {
  452. $this->pager['total'] = intval($n);
  453. }
  454. function set_pager_itemspage($n) {
  455. $this->pager['itemspage'] = ((intval($n) > 0) ? intval($n) : 0);
  456. $this->pager['start'] = ($this->pager['page'] * $this->pager['itemspage']) - $this->pager['itemspage'];
  457. }
  458. function init_pagehead() {
  459. $interval = ((local_user()) ? get_pconfig(local_user(),'system','update_interval') : 40000);
  460. if($interval < 10000)
  461. $interval = 40000;
  462. $this->page['title'] = $this->config['sitename'];
  463. $tpl = get_markup_template('head.tpl');
  464. $this->page['htmlhead'] = replace_macros($tpl,array(
  465. '$baseurl' => $this->get_baseurl(), // FIXME for z_path!!!!
  466. '$local_user' => local_user(),
  467. '$generator' => 'Friendica' . ' ' . FRIENDICA_VERSION,
  468. '$delitem' => t('Delete this item?'),
  469. '$comment' => t('Comment'),
  470. '$showmore' => t('show more'),
  471. '$showfewer' => t('show fewer'),
  472. '$update_interval' => $interval
  473. ));
  474. }
  475. function init_page_end() {
  476. $tpl = get_markup_template('end.tpl');
  477. $this->page['end'] = replace_macros($tpl,array(
  478. '$baseurl' => $this->get_baseurl() // FIXME for z_path!!!!
  479. ));
  480. }
  481. function set_curl_code($code) {
  482. $this->curl_code = $code;
  483. }
  484. function get_curl_code() {
  485. return $this->curl_code;
  486. }
  487. function set_curl_headers($headers) {
  488. $this->curl_headers = $headers;
  489. }
  490. function get_curl_headers() {
  491. return $this->curl_headers;
  492. }
  493. function get_cached_avatar_image($avatar_image){
  494. if($this->cached_profile_image[$avatar_image])
  495. return $this->cached_profile_image[$avatar_image];
  496. $path_parts = explode("/",$avatar_image);
  497. $common_filename = $path_parts[count($path_parts)-1];
  498. if($this->cached_profile_picdate[$common_filename]){
  499. $this->cached_profile_image[$avatar_image] = $avatar_image . $this->cached_profile_picdate[$common_filename];
  500. } else {
  501. $r = q("SELECT `contact`.`avatar-date` AS picdate FROM `contact` WHERE `contact`.`thumb` like \"%%/%s\"",
  502. $common_filename);
  503. if(! count($r)){
  504. $this->cached_profile_image[$avatar_image] = $avatar_image;
  505. } else {
  506. $this->cached_profile_picdate[$common_filename] = "?rev=" . urlencode($r[0]['picdate']);
  507. $this->cached_profile_image[$avatar_image] = $avatar_image . $this->cached_profile_picdate[$common_filename];
  508. }
  509. }
  510. return $this->cached_profile_image[$avatar_image];
  511. }
  512. }
  513. }
  514. // retrieve the App structure
  515. // useful in functions which require it but don't get it passed to them
  516. if(! function_exists('get_app')) {
  517. function get_app() {
  518. global $a;
  519. return $a;
  520. }
  521. };
  522. // Multi-purpose function to check variable state.
  523. // Usage: x($var) or $x($array,'key')
  524. // returns false if variable/key is not set
  525. // if variable is set, returns 1 if has 'non-zero' value, otherwise returns 0.
  526. // e.g. x('') or x(0) returns 0;
  527. if(! function_exists('x')) {
  528. function x($s,$k = NULL) {
  529. if($k != NULL) {
  530. if((is_array($s)) && (array_key_exists($k,$s))) {
  531. if($s[$k])
  532. return (int) 1;
  533. return (int) 0;
  534. }
  535. return false;
  536. }
  537. else {
  538. if(isset($s)) {
  539. if($s) {
  540. return (int) 1;
  541. }
  542. return (int) 0;
  543. }
  544. return false;
  545. }
  546. }
  547. }
  548. // called from db initialisation if db is dead.
  549. if(! function_exists('system_unavailable')) {
  550. function system_unavailable() {
  551. include('system_unavailable.php');
  552. system_down();
  553. killme();
  554. }
  555. }
  556. function clean_urls() {
  557. global $a;
  558. // if($a->config['system']['clean_urls'])
  559. return true;
  560. // return false;
  561. }
  562. function z_path() {
  563. global $a;
  564. $base = $a->get_baseurl();
  565. if(! clean_urls())
  566. $base .= '/?q=';
  567. return $base;
  568. }
  569. function z_root() {
  570. global $a;
  571. return $a->get_baseurl();
  572. }
  573. function absurl($path) {
  574. if(strpos($path,'/') === 0)
  575. return z_path() . $path;
  576. return $path;
  577. }
  578. function is_ajax() {
  579. return (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
  580. }
  581. // Primarily involved with database upgrade, but also sets the
  582. // base url for use in cmdline programs which don't have
  583. // $_SERVER variables, and synchronising the state of installed plugins.
  584. if(! function_exists('check_config')) {
  585. function check_config(&$a) {
  586. $build = get_config('system','build');
  587. if(! x($build))
  588. $build = set_config('system','build',DB_UPDATE_VERSION);
  589. $url = get_config('system','url');
  590. // if the url isn't set or the stored url is radically different
  591. // than the currently visited url, store the current value accordingly.
  592. // "Radically different" ignores common variations such as http vs https
  593. // and www.example.com vs example.com.
  594. // We will only change the url to an ip address if there is no existing setting
  595. if(! x($url))
  596. $url = set_config('system','url',$a->get_baseurl());
  597. if((! link_compare($url,$a->get_baseurl())) && (! preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/",$a->get_hostname)))
  598. $url = set_config('system','url',$a->get_baseurl());
  599. if($build != DB_UPDATE_VERSION) {
  600. $stored = intval($build);
  601. $current = intval(DB_UPDATE_VERSION);
  602. if(($stored < $current) && file_exists('update.php')) {
  603. load_config('database');
  604. // We're reporting a different version than what is currently installed.
  605. // Run any existing update scripts to bring the database up to current.
  606. require_once('update.php');
  607. // make sure that boot.php and update.php are the same release, we might be
  608. // updating right this very second and the correct version of the update.php
  609. // file may not be here yet. This can happen on a very busy site.
  610. if(DB_UPDATE_VERSION == UPDATE_VERSION) {
  611. for($x = $stored; $x < $current; $x ++) {
  612. if(function_exists('update_' . $x)) {
  613. // There could be a lot of processes running or about to run.
  614. // We want exactly one process to run the update command.
  615. // So store the fact that we're taking responsibility
  616. // after first checking to see if somebody else already has.
  617. // If the update fails or times-out completely you may need to
  618. // delete the config entry to try again.
  619. $t = get_config('database','update_' . $x);
  620. if($t !== false)
  621. break;
  622. set_config('database','update_' . $x, time());
  623. // call the specific update
  624. $func = 'update_' . $x;
  625. $retval = $func();
  626. if($retval) {
  627. //send the administrator an e-mail
  628. $email_tpl = get_intltext_template("update_fail_eml.tpl");
  629. $email_msg = replace_macros($email_tpl, array(
  630. '$sitename' => $a->config['sitename'],
  631. '$siteurl' => $a->get_baseurl(),
  632. '$update' => $x,
  633. '$error' => sprintf( t('Update %s failed. See error logs.'), $x)
  634. ));
  635. $subject=sprintf(t('Update Error at %s'), $a->get_baseurl());
  636. mail($a->config['admin_email'], $subject, $email_msg,
  637. 'From: ' . t('Administrator') . '@' . $_SERVER['SERVER_NAME'] . "\n"
  638. . 'Content-type: text/plain; charset=UTF-8' . "\n"
  639. . 'Content-transfer-encoding: 8bit' );
  640. //try the logger
  641. logger('CRITICAL: Update Failed: '. $x);
  642. break;
  643. }
  644. else {
  645. set_config('database','update_' . $x, 'success');
  646. set_config('system','build', $x + 1);
  647. }
  648. }
  649. }
  650. }
  651. }
  652. }
  653. /**
  654. *
  655. * Synchronise plugins:
  656. *
  657. * $a->config['system']['addon'] contains a comma-separated list of names
  658. * of plugins/addons which are used on this system.
  659. * Go through the database list of already installed addons, and if we have
  660. * an entry, but it isn't in the config list, call the uninstall procedure
  661. * and mark it uninstalled in the database (for now we'll remove it).
  662. * Then go through the config list and if we have a plugin that isn't installed,
  663. * call the install procedure and add it to the database.
  664. *
  665. */
  666. $r = q("SELECT * FROM `addon` WHERE `installed` = 1");
  667. if(count($r))
  668. $installed = $r;
  669. else
  670. $installed = array();
  671. $plugins = get_config('system','addon');
  672. $plugins_arr = array();
  673. if($plugins)
  674. $plugins_arr = explode(',',str_replace(' ', '',$plugins));
  675. $a->plugins = $plugins_arr;
  676. $installed_arr = array();
  677. if(count($installed)) {
  678. foreach($installed as $i) {
  679. if(! in_array($i['name'],$plugins_arr)) {
  680. uninstall_plugin($i['name']);
  681. }
  682. else {
  683. $installed_arr[] = $i['name'];
  684. }
  685. }
  686. }
  687. if(count($plugins_arr)) {
  688. foreach($plugins_arr as $p) {
  689. if(! in_array($p,$installed_arr)) {
  690. install_plugin($p);
  691. }
  692. }
  693. }
  694. load_hooks();
  695. return;
  696. }
  697. }
  698. function get_guid($size=16) {
  699. $exists = true; // assume by default that we don't have a unique guid
  700. do {
  701. $s = random_string($size);
  702. $r = q("select id from guid where guid = '%s' limit 1", dbesc($s));
  703. if(! count($r))
  704. $exists = false;
  705. } while($exists);
  706. q("insert into guid ( guid ) values ( '%s' ) ", dbesc($s));
  707. return $s;
  708. }
  709. // wrapper for adding a login box. If $register == true provide a registration
  710. // link. This will most always depend on the value of $a->config['register_policy'].
  711. // returns the complete html for inserting into the page
  712. if(! function_exists('login')) {
  713. function login($register = false, $hiddens=false) {
  714. $a = get_app();
  715. $o = "";
  716. $reg = false;
  717. if ($register) {
  718. $reg = array(
  719. 'title' => t('Create a New Account'),
  720. 'desc' => t('Register')
  721. );
  722. }
  723. $noid = get_config('system','no_openid');
  724. $dest_url = $a->get_baseurl(true) . '/' . $a->query_string;
  725. if(local_user()) {
  726. $tpl = get_markup_template("logout.tpl");
  727. }
  728. else {
  729. $a->page['htmlhead'] .= replace_macros(get_markup_template("login_head.tpl"),array(
  730. '$baseurl' => $a->get_baseurl(true)
  731. ));
  732. $tpl = get_markup_template("login.tpl");
  733. $_SESSION['return_url'] = $a->query_string;
  734. }
  735. $o .= replace_macros($tpl,array(
  736. '$dest_url' => $dest_url,
  737. '$logout' => t('Logout'),
  738. '$login' => t('Login'),
  739. '$lname' => array('username', t('Nickname or Email address: ') , '', ''),
  740. '$lpassword' => array('password', t('Password: '), '', ''),
  741. '$openid' => !$noid,
  742. '$lopenid' => array('openid_url', t('Or login using OpenID: '),'',''),
  743. '$hiddens' => $hiddens,
  744. '$register' => $reg,
  745. '$lostpass' => t('Forgot your password?'),
  746. '$lostlink' => t('Password Reset'),
  747. ));
  748. call_hooks('login_hook',$o);
  749. return $o;
  750. }
  751. }
  752. // Used to end the current process, after saving session state.
  753. if(! function_exists('killme')) {
  754. function killme() {
  755. session_write_close();
  756. exit;
  757. }
  758. }
  759. // redirect to another URL and terminate this process.
  760. if(! function_exists('goaway')) {
  761. function goaway($s) {
  762. header("Location: $s");
  763. killme();
  764. }
  765. }
  766. // Returns the uid of locally logged in user or false.
  767. if(! function_exists('local_user')) {
  768. function local_user() {
  769. if((x($_SESSION,'authenticated')) && (x($_SESSION,'uid')))
  770. return intval($_SESSION['uid']);
  771. return false;
  772. }
  773. }
  774. // Returns contact id of authenticated site visitor or false
  775. if(! function_exists('remote_user')) {
  776. function remote_user() {
  777. if((x($_SESSION,'authenticated')) && (x($_SESSION,'visitor_id')))
  778. return intval($_SESSION['visitor_id']);
  779. return false;
  780. }
  781. }
  782. // contents of $s are displayed prominently on the page the next time
  783. // a page is loaded. Usually used for errors or alerts.
  784. if(! function_exists('notice')) {
  785. function notice($s) {
  786. $a = get_app();
  787. if(! x($_SESSION,'sysmsg')) $_SESSION['sysmsg'] = array();
  788. if($a->interactive)
  789. $_SESSION['sysmsg'][] = $s;
  790. }
  791. }
  792. if(! function_exists('info')) {
  793. function info($s) {
  794. $a = get_app();
  795. if(! x($_SESSION,'sysmsg_info')) $_SESSION['sysmsg_info'] = array();
  796. if($a->interactive)
  797. $_SESSION['sysmsg_info'][] = $s;
  798. }
  799. }
  800. // wrapper around config to limit the text length of an incoming message
  801. if(! function_exists('get_max_import_size')) {
  802. function get_max_import_size() {
  803. global $a;
  804. return ((x($a->config,'max_import_size')) ? $a->config['max_import_size'] : 0 );
  805. }
  806. }
  807. /**
  808. *
  809. * Function : profile_load
  810. * @parameter App $a
  811. * @parameter string $nickname
  812. * @parameter int $profile
  813. *
  814. * Summary: Loads a profile into the page sidebar.
  815. * The function requires a writeable copy of the main App structure, and the nickname
  816. * of a registered local account.
  817. *
  818. * If the viewer is an authenticated remote viewer, the profile displayed is the
  819. * one that has been configured for his/her viewing in the Contact manager.
  820. * Passing a non-zero profile ID can also allow a preview of a selected profile
  821. * by the owner.
  822. *
  823. * Profile information is placed in the App structure for later retrieval.
  824. * Honours the owner's chosen theme for display.
  825. *
  826. */
  827. if(! function_exists('profile_load')) {
  828. function profile_load(&$a, $nickname, $profile = 0) {
  829. $user = q("select uid from user where nickname = '%s' limit 1",
  830. dbesc($nickname)
  831. );
  832. if(! ($user && count($user))) {
  833. logger('profile error: ' . $a->query_string, LOGGER_DEBUG);
  834. notice( t('Requested account is not available.') . EOL );
  835. $a->error = 404;
  836. return;
  837. }
  838. if(remote_user() && count($_SESSION['remote'])) {
  839. foreach($_SESSION['remote'] as $visitor) {
  840. if($visitor['uid'] == $user[0]['uid']) {
  841. $r = q("SELECT `profile-id` FROM `contact` WHERE `id` = %d LIMIT 1",
  842. intval($visitor['cid'])
  843. );
  844. if(count($r))
  845. $profile = $r[0]['profile-id'];
  846. break;
  847. }
  848. }
  849. }
  850. $r = null;
  851. if($profile) {
  852. $profile_int = intval($profile);
  853. $r = q("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `contact`.`avatar-date` AS picdate, `user`.* FROM `profile`
  854. left join `contact` on `contact`.`uid` = `profile`.`uid` LEFT JOIN `user` ON `profile`.`uid` = `user`.`uid`
  855. WHERE `user`.`nickname` = '%s' AND `profile`.`id` = %d and `contact`.`self` = 1 LIMIT 1",
  856. dbesc($nickname),
  857. intval($profile_int)
  858. );
  859. }
  860. if((! $r) && (! count($r))) {
  861. $r = q("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `contact`.`avatar-date` AS picdate, `user`.* FROM `profile`
  862. left join `contact` on `contact`.`uid` = `profile`.`uid` LEFT JOIN `user` ON `profile`.`uid` = `user`.`uid`
  863. WHERE `user`.`nickname` = '%s' AND `profile`.`is-default` = 1 and `contact`.`self` = 1 LIMIT 1",
  864. dbesc($nickname)
  865. );
  866. }
  867. if(($r === false) || (! count($r))) {
  868. logger('profile error: ' . $a->query_string, LOGGER_DEBUG);
  869. notice( t('Requested profile is not available.') . EOL );
  870. $a->error = 404;
  871. return;
  872. }
  873. // fetch user tags if this isn't the default profile
  874. if(! $r[0]['is-default']) {
  875. $x = q("select `pub_keywords` from `profile` where uid = %d and `is-default` = 1 limit 1",
  876. intval($profile_uid)
  877. );
  878. if($x && count($x))
  879. $r[0]['pub_keywords'] = $x[0]['pub_keywords'];
  880. }
  881. $a->profile = $r[0];
  882. $a->profile['mobile-theme'] = get_pconfig($profile_uid, 'system', 'mobile_theme');
  883. $a->page['title'] = $a->profile['name'] . " @ " . $a->config['sitename'];
  884. $_SESSION['theme'] = $a->profile['theme'];
  885. $_SESSION['mobile-theme'] = $a->profile['mobile-theme'];
  886. /**
  887. * load/reload current theme info
  888. */
  889. $theme_info_file = "view/theme/".current_theme()."/theme.php";
  890. if (file_exists($theme_info_file)){
  891. require_once($theme_info_file);
  892. }
  893. if(! (x($a->page,'aside')))
  894. $a->page['aside'] = '';
  895. if(local_user() && local_user() == $a->profile['uid']) {
  896. $a->page['aside'] .= replace_macros(get_markup_template('profile_edlink.tpl'),array(
  897. '$editprofile' => t('Edit profile'),
  898. '$profid' => $a->profile['id']
  899. ));
  900. }
  901. $block = (((get_config('system','block_public')) && (! local_user()) && (! remote_user())) ? true : false);
  902. $a->page['aside'] .= profile_sidebar($a->profile, $block);
  903. /*if(! $block)
  904. $a->page['aside'] .= contact_block();*/
  905. return;
  906. }
  907. }
  908. /**
  909. *
  910. * Function: profile_sidebar
  911. *
  912. * Formats a profile for display in the sidebar.
  913. * It is very difficult to templatise the HTML completely
  914. * because of all the conditional logic.
  915. *
  916. * @parameter: array $profile
  917. *
  918. * Returns HTML string stuitable for sidebar inclusion
  919. * Exceptions: Returns empty string if passed $profile is wrong type or not populated
  920. *
  921. */
  922. if(! function_exists('profile_sidebar')) {
  923. function profile_sidebar($profile, $block = 0) {
  924. $a = get_app();
  925. $o = '';
  926. $location = false;
  927. $address = false;
  928. $pdesc = true;
  929. if((! is_array($profile)) && (! count($profile)))
  930. return $o;
  931. $profile['picdate'] = urlencode($profile['picdate']);
  932. call_hooks('profile_sidebar_enter', $profile);
  933. // don't show connect link to yourself
  934. $connect = (($profile['uid'] != local_user()) ? t('Connect') : False);
  935. // don't show connect link to authenticated visitors either
  936. if(remote_user() && count($_SESSION['remote'])) {
  937. foreach($_SESSION['remote'] as $visitor) {
  938. if($visitor['uid'] == $profile['uid']) {
  939. $connect = false;
  940. break;
  941. }
  942. }
  943. }
  944. if(get_my_url() && $profile['unkmail'])
  945. $wallmessage = t('Message');
  946. else
  947. $wallmessage = false;
  948. // show edit profile to yourself
  949. if ($profile['uid'] == local_user()) {
  950. $profile['edit'] = array($a->get_baseurl(). '/profiles', t('Profiles'),"", t('Manage/edit profiles'));
  951. $r = q("SELECT * FROM `profile` WHERE `uid` = %d",
  952. local_user());
  953. $profile['menu'] = array(
  954. 'chg_photo' => t('Change profile photo'),
  955. 'cr_new' => t('Create New Profile'),
  956. 'entries' => array(),
  957. );
  958. if(count($r)) {
  959. foreach($r as $rr) {
  960. $profile['menu']['entries'][] = array(
  961. 'photo' => $rr['thumb'],
  962. 'id' => $rr['id'],
  963. 'alt' => t('Profile Image'),
  964. 'profile_name' => $rr['profile-name'],
  965. 'isdefault' => $rr['is-default'],
  966. 'visibile_to_everybody' => t('visible to everybody'),
  967. 'edit_visibility' => t('Edit visibility'),
  968. );
  969. }
  970. }
  971. }
  972. if((x($profile,'address') == 1)
  973. || (x($profile,'locality') == 1)
  974. || (x($profile,'region') == 1)
  975. || (x($profile,'postal-code') == 1)
  976. || (x($profile,'country-name') == 1))
  977. $location = t('Location:');
  978. $gender = ((x($profile,'gender') == 1) ? t('Gender:') : False);
  979. $marital = ((x($profile,'marital') == 1) ? t('Status:') : False);
  980. $homepage = ((x($profile,'homepage') == 1) ? t('Homepage:') : False);
  981. if(($profile['hidewall'] || $block) && (! local_user()) && (! remote_user())) {
  982. $location = $pdesc = $gender = $marital = $homepage = False;
  983. }
  984. $firstname = ((strpos($profile['name'],' '))
  985. ? trim(substr($profile['name'],0,strpos($profile['name'],' '))) : $profile['name']);
  986. $lastname = (($firstname === $profile['name']) ? '' : trim(substr($profile['name'],strlen($firstname))));
  987. $diaspora = array(
  988. 'podloc' => $a->get_baseurl(),
  989. 'searchable' => (($profile['publish'] && $profile['net-publish']) ? 'true' : 'false' ),
  990. 'nickname' => $profile['nickname'],
  991. 'fullname' => $profile['name'],
  992. 'firstname' => $firstname,
  993. 'lastname' => $lastname,
  994. 'photo300' => $a->get_cached_avatar_image($a->get_baseurl() . '/photo/custom/300/' . $profile['uid'] . '.jpg'),
  995. 'photo100' => $a->get_cached_avatar_image($a->get_baseurl() . '/photo/custom/100/' . $profile['uid'] . '.jpg'),
  996. 'photo50' => $a->get_cached_avatar_image($a->get_baseurl() . '/photo/custom/50/' . $profile['uid'] . '.jpg'),
  997. );
  998. if (!$block){
  999. $contact_block = contact_block();
  1000. }
  1001. $tpl = get_markup_template('profile_vcard.tpl');
  1002. $o .= replace_macros($tpl, array(
  1003. '$profile' => $profile,
  1004. '$connect' => $connect,
  1005. '$wallmessage' => $wallmessage,
  1006. '$location' => template_escape($location),
  1007. '$gender' => $gender,
  1008. '$pdesc' => $pdesc,
  1009. '$marital' => $marital,
  1010. '$homepage' => $homepage,
  1011. '$diaspora' => $diaspora,
  1012. '$contact_block' => $contact_block,
  1013. ));
  1014. $arr = array('profile' => &$profile, 'entry' => &$o);
  1015. call_hooks('profile_sidebar', $arr);
  1016. return $o;
  1017. }
  1018. }
  1019. if(! function_exists('get_birthdays')) {
  1020. function get_birthdays() {
  1021. $a = get_app();
  1022. $o = '';
  1023. if(! local_user() || $a->is_mobile || $a->is_tablet)
  1024. return $o;
  1025. // $mobile_detect = new Mobile_Detect();
  1026. // $is_mobile = $mobile_detect->isMobile() || $mobile_detect->isTablet();
  1027. // if($is_mobile)
  1028. // return $o;
  1029. $bd_format = t('g A l F d') ; // 8 AM Friday January 18
  1030. $bd_short = t('F d');
  1031. $r = q("SELECT `event`.*, `event`.`id` AS `eid`, `contact`.* FROM `event`
  1032. LEFT JOIN `contact` ON `contact`.`id` = `event`.`cid`
  1033. WHERE `event`.`uid` = %d AND `type` = 'birthday' AND `start` < '%s' AND `finish` > '%s'
  1034. ORDER BY `start` ASC ",
  1035. intval(local_user()),
  1036. dbesc(datetime_convert('UTC','UTC','now + 6 days')),
  1037. dbesc(datetime_convert('UTC','UTC','now'))
  1038. );
  1039. if($r && count($r)) {
  1040. $total = 0;
  1041. $now = strtotime('now');
  1042. $cids = array();
  1043. $istoday = false;
  1044. foreach($r as $rr) {
  1045. if(strlen($rr['name']))
  1046. $total ++;
  1047. if((strtotime($rr['start'] . ' +00:00') < $now) && (strtotime($rr['finish'] . ' +00:00') > $now))
  1048. $istoday = true;
  1049. }
  1050. $classtoday = $istoday ? ' birthday-today ' : '';
  1051. if($total) {
  1052. foreach($r as &$rr) {
  1053. if(! strlen($rr['name']))
  1054. continue;
  1055. // avoid duplicates
  1056. if(in_array($rr['cid'],$cids))
  1057. continue;
  1058. $cids[] = $rr['cid'];
  1059. $today = (((strtotime($rr['start'] . ' +00:00') < $now) && (strtotime($rr['finish'] . ' +00:00') > $now)) ? true : false);
  1060. $sparkle = '';
  1061. $url = $rr['url'];
  1062. if($rr['network'] === NETWORK_DFRN) {
  1063. $sparkle = " sparkle";
  1064. $url = $a->get_baseurl() . '/redir/' . $rr['cid'];
  1065. }
  1066. $rr['link'] = $url;
  1067. $rr['title'] = $rr['name'];
  1068. $rr['date'] = day_translate(datetime_convert('UTC', $a->timezone, $rr['start'], $rr['adjust'] ? $bd_format : $bd_short)) . (($today) ? ' ' . t('[today]') : '');
  1069. $rr['startime'] = Null;
  1070. $rr['today'] = $today;
  1071. }
  1072. }
  1073. }
  1074. $tpl = get_markup_template("birthdays_reminder.tpl");
  1075. return replace_macros($tpl, array(
  1076. '$baseurl' => $a->get_baseurl(),
  1077. '$classtoday' => $classtoday,
  1078. '$count' => $total,
  1079. '$event_reminders' => t('Birthday Reminders'),
  1080. '$event_title' => t('Birthdays this week:'),
  1081. '$events' => $r,
  1082. '$lbr' => '{', // raw brackets mess up if/endif macro processing
  1083. '$rbr' => '}'
  1084. ));
  1085. }
  1086. }
  1087. if(! function_exists('get_events')) {
  1088. function get_events() {
  1089. require_once('include/bbcode.php');
  1090. $a = get_app();
  1091. if(! local_user() || $a->is_mobile || $a->is_tablet)
  1092. return $o;
  1093. // $mobile_detect = new Mobile_Detect();
  1094. // $is_mobile = $mobile_detect->isMobile() || $mobile_detect->isTablet();
  1095. // if($is_mobile)
  1096. // return $o;
  1097. $bd_format = t('g A l F d') ; // 8 AM Friday January 18
  1098. $bd_short = t('F d');
  1099. $r = q("SELECT `event`.* FROM `event`
  1100. WHERE `event`.`uid` = %d AND `type` != 'birthday' AND `start` < '%s' AND `start` > '%s'
  1101. ORDER BY `start` ASC ",
  1102. intval(local_user()),
  1103. dbesc(datetime_convert('UTC','UTC','now + 6 days')),
  1104. dbesc(datetime_convert('UTC','UTC','now - 1 days'))
  1105. );
  1106. if($r && count($r)) {
  1107. $now = strtotime('now');
  1108. $istoday = false;
  1109. foreach($r as $rr) {
  1110. if(strlen($rr['name']))
  1111. $total ++;
  1112. $strt = datetime_convert('UTC',$rr['convert'] ? $a->timezone : 'UTC',$rr['start'],'Y-m-d');
  1113. if($strt === datetime_convert('UTC',$a->timezone,'now','Y-m-d'))
  1114. $istoday = true;
  1115. }
  1116. $classtoday = (($istoday) ? 'event-today' : '');
  1117. foreach($r as &$rr) {
  1118. if($rr['adjust'])
  1119. $md = datetime_convert('UTC',$a->timezone,$rr['start'],'Y/m');
  1120. else
  1121. $md = datetime_convert('UTC','UTC',$rr['start'],'Y/m');
  1122. $md .= "/#link-".$rr['id'];
  1123. $title = substr(strip_tags(bbcode($rr['desc'])),0,32) . '... ';
  1124. if(! $title)
  1125. $title = t('[No description]');
  1126. $strt = datetime_convert('UTC',$rr['convert'] ? $a->timezone : 'UTC',$rr['start']);
  1127. $today = ((substr($strt,0,10) === datetime_convert('UTC',$a->timezone,'now','Y-m-d')) ? true : false);
  1128. $rr['link'] = $md;
  1129. $rr['title'] = $title;
  1130. $rr['date'] = day_translate(datetime_convert('UTC', $rr['adjust'] ? $a->timezone : 'UTC', $rr['start'], $bd_format)) . (($today) ? ' ' . t('[today]') : '');
  1131. $rr['startime'] = $strt;
  1132. $rr['today'] = $today;
  1133. }
  1134. }
  1135. $tpl = get_markup_template("events_reminder.tpl");
  1136. return replace_macros($tpl, array(
  1137. '$baseurl' => $a->get_baseurl(),
  1138. '$classtoday' => $classtoday,
  1139. '$count' => count($r),
  1140. '$event_reminders' => t('Event Reminders'),
  1141. '$event_title' => t('Events this week:'),
  1142. '$events' => $r,
  1143. ));
  1144. }
  1145. }
  1146. /**
  1147. *
  1148. * Wrap calls to proc_close(proc_open()) and call hook
  1149. * so plugins can take part in process :)
  1150. *
  1151. * args:
  1152. * $cmd program to run
  1153. * next args are passed as $cmd command line
  1154. *
  1155. * e.g.: proc_run("ls","-la","/tmp");
  1156. *
  1157. * $cmd and string args are surrounded with ""
  1158. */
  1159. if(! function_exists('proc_run')) {
  1160. function proc_run($cmd){
  1161. $a = get_app();
  1162. $args = func_get_args();
  1163. $newargs = array();
  1164. if(! count($args))
  1165. return;
  1166. // expand any arrays
  1167. foreach($args as $arg) {
  1168. if(is_array($arg)) {
  1169. foreach($arg as $n) {
  1170. $newargs[] = $n;
  1171. }
  1172. }
  1173. else
  1174. $newargs[] = $arg;
  1175. }
  1176. $args = $newargs;
  1177. $arr = array('args' => $args, 'run_cmd' => true);
  1178. call_hooks("proc_run", $arr);
  1179. if(! $arr['run_cmd'])
  1180. return;
  1181. if(count($args) && $args[0] === 'php')
  1182. $args[0] = ((x($a->config,'php_path')) && (strlen($a->config['php_path'])) ? $a->config['php_path'] : 'php');
  1183. for($x = 0; $x < count($args); $x ++)
  1184. $args[$x] = escapeshellarg($args[$x]);
  1185. $cmdline = implode($args," ");
  1186. if(get_config('system','proc_windows'))
  1187. proc_close(proc_open('cmd /c start /b ' . $cmdline,array(),$foo));
  1188. else
  1189. proc_close(proc_open($cmdline." &",array(),$foo));
  1190. }
  1191. }
  1192. if(! function_exists('current_theme')) {
  1193. function current_theme(){
  1194. $app_base_themes = array('duepuntozero', 'dispy', 'quattro');
  1195. $a = get_app();
  1196. // $mobile_detect = new Mobile_Detect();
  1197. // $is_mobile = $mobile_detect->isMobile() || $mobile_detect->isTablet();
  1198. $is_mobile = $a->is_mobile || $a->is_tablet;
  1199. if($is_mobile) {
  1200. if(isset($_SESSION['show-mobile']) && !$_SESSION['show-mobile']) {
  1201. $system_theme = '';
  1202. $theme_name = '';
  1203. }
  1204. else {
  1205. $system_theme = ((isset($a->config['system']['mobile-theme'])) ? $a->config['system']['mobile-theme'] : '');
  1206. $theme_name = ((isset($_SESSION) && x($_SESSION,'mobile-theme')) ? $_SESSION['mobile-theme'] : $system_theme);
  1207. if($theme_name === '---') {
  1208. // user has selected to have the mobile theme be the same as the normal one
  1209. $system_theme = '';
  1210. $theme_name = '';
  1211. }
  1212. }
  1213. }
  1214. if(!$is_mobile || ($system_theme === '' && $theme_name === '')) {
  1215. $system_theme = ((isset($a->config['system']['theme'])) ? $a->config['system']['theme'] : '');
  1216. $theme_name = ((isset($_SESSION) && x($_SESSION,'theme')) ? $_SESSION['theme'] : $system_theme);
  1217. }
  1218. if($theme_name &&
  1219. (file_exists('view/theme/' . $theme_name . '/style.css') ||
  1220. file_exists('view/theme/' . $theme_name . '/style.php')))
  1221. return($theme_name);
  1222. foreach($app_base_themes as $t) {
  1223. if(file_exists('view/theme/' . $t . '/style.css')||
  1224. file_exists('view/theme/' . $t . '/style.php'))
  1225. return($t);
  1226. }
  1227. $fallback = array_merge(glob('view/theme/*/style.css'),glob('view/theme/*/style.php'));
  1228. if(count($fallback))
  1229. return (str_replace('view/theme/','', substr($fallback[0],0,-10)));
  1230. }
  1231. }
  1232. /*
  1233. * Return full URL to theme which is currently in effect.
  1234. * Provide a sane default if nothing is chosen or the specified theme does not exist.
  1235. */
  1236. if(! function_exists('current_theme_url')) {
  1237. function current_theme_url() {
  1238. global $a;
  1239. $t = current_theme();
  1240. if (file_exists('view/theme/' . $t . '/style.php'))
  1241. return($a->get_baseurl() . '/view/theme/' . $t . '/style.pcss');
  1242. return($a->get_baseurl() . '/view/theme/' . $t . '/style.css');
  1243. }
  1244. }
  1245. if(! function_exists('feed_birthday')) {
  1246. function feed_birthday($uid,$tz) {
  1247. /**
  1248. *
  1249. * Determine the next birthday, but only if the birthday is published
  1250. * in the default profile. We _could_ also look for a private profile that the
  1251. * recipient can see, but somebody could get mad at us if they start getting
  1252. * public birthday greetings when they haven't made this info public.
  1253. *
  1254. * Assuming we are able to publish this info, we are then going to convert
  1255. * the start time from the owner's timezone to UTC.
  1256. *
  1257. * This will potentially solve the problem found with some social networks
  1258. * where birthdays are converted to the viewer's timezone and salutations from
  1259. * elsewhere in the world show up on the wrong day. We will convert it to the
  1260. * viewer's timezone also, but first we are going to convert it from the birthday
  1261. * person's timezone to GMT - so the viewer may find the birthday starting at
  1262. * 6:00PM the day before, but that will correspond to midnight to the birthday person.
  1263. *
  1264. */
  1265. $birthday = '';
  1266. if(! strlen($tz))
  1267. $tz = 'UTC';
  1268. $p = q("SELECT `dob` FROM `profile` WHERE `is-default` = 1 AND `uid` = %d LIMIT 1",
  1269. intval($uid)
  1270. );
  1271. if($p && count($p)) {
  1272. $tmp_dob = substr($p[0]['dob'],5);
  1273. if(intval($tmp_dob)) {
  1274. $y = datetime_convert($tz,$tz,'now','Y');
  1275. $bd = $y . '-' . $tmp_dob . ' 00:00';
  1276. $t_dob = strtotime($bd);
  1277. $now = strtotime(datetime_convert($tz,$tz,'now'));
  1278. if($t_dob < $now)
  1279. $bd = $y + 1 . '-' . $tmp_dob . ' 00:00';
  1280. $birthday = datetime_convert($tz,'UTC',$bd,ATOM_TIME);
  1281. }
  1282. }
  1283. return $birthday;
  1284. }
  1285. }
  1286. if(! function_exists('is_site_admin')) {
  1287. function is_site_admin() {
  1288. $a = get_app();
  1289. if(local_user() && x($a->user,'email') && x($a->config,'admin_email') && ($a->user['email'] === $a->config['admin_email']))
  1290. return true;
  1291. return false;
  1292. }
  1293. }
  1294. if(! function_exists('load_contact_links')) {
  1295. function load_contact_links($uid) {
  1296. $a = get_app();
  1297. $ret = array();
  1298. if(! $uid || x($a->contacts,'empty'))
  1299. return;
  1300. $r = q("SELECT `id`,`network`,`url`,`thumb` FROM `contact` WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 ",
  1301. intval($uid)
  1302. );
  1303. if(count($r)) {
  1304. foreach($r as $rr){
  1305. $url = normalise_link($rr['url']);
  1306. $ret[$url] = $rr;
  1307. }
  1308. }
  1309. else
  1310. $ret['empty'] = true;
  1311. $a->contacts = $ret;
  1312. return;
  1313. }
  1314. }
  1315. if(! function_exists('profile_tabs')){
  1316. function profile_tabs($a, $is_owner=False, $nickname=Null){
  1317. //echo "<pre>"; var_dump($a->user); killme();
  1318. if (is_null($nickname))
  1319. $nickname = $a->user['nickname'];
  1320. if(x($_GET,'tab'))
  1321. $tab = notags(trim($_GET['tab']));
  1322. $url = $a->get_baseurl() . '/profile/' . $nickname;
  1323. $tabs = array(
  1324. array(
  1325. 'label'=>t('Status'),
  1326. 'url' => $url,
  1327. 'sel' => ((!isset($tab)&&$a->argv[0]=='profile')?'active':''),
  1328. 'title' => t('Status Messages and Posts'),
  1329. 'id' => 'status-tab',
  1330. ),
  1331. array(
  1332. 'label' => t('Profile'),
  1333. 'url' => $url.'/?tab=profile',
  1334. 'sel' => ((isset($tab) && $tab=='profile')?'active':''),
  1335. 'title' => t('Profile Details'),
  1336. 'id' => 'profile-tab',
  1337. ),
  1338. array(
  1339. 'label' => t('Photos'),
  1340. 'url' => $a->get_baseurl() . '/photos/' . $nickname,
  1341. 'sel' => ((!isset($tab)&&$a->argv[0]=='photos')?'active':''),
  1342. 'title' => t('Photo Albums'),
  1343. 'id' => 'photo-tab',
  1344. ),
  1345. );
  1346. if ($is_owner){
  1347. $tabs[] = array(
  1348. 'label' => t('Events'),
  1349. 'url' => $a->get_baseurl() . '/events',
  1350. 'sel' =>((!isset($tab)&&$a->argv[0]=='events')?'active':''),
  1351. 'title' => t('Events and Calendar'),
  1352. 'id' => 'events-tab',
  1353. );
  1354. $tabs[] = array(
  1355. 'label' => t('Personal Notes'),
  1356. 'url' => $a->get_baseurl() . '/notes',
  1357. 'sel' =>((!isset($tab)&&$a->argv[0]=='notes')?'active':''),
  1358. 'title' => t('Only You Can See This'),
  1359. 'id' => 'notes-tab',
  1360. );
  1361. }
  1362. $arr = array('is_owner' => $is_owner, 'nickname' => $nickname, 'tab' => (($tab) ? $tab : false), 'tabs' => $tabs);
  1363. call_hooks('profile_tabs', $arr);
  1364. $tpl = get_markup_template('common_tabs.tpl');
  1365. return replace_macros($tpl,array('$tabs' => $arr['tabs']));
  1366. }
  1367. }
  1368. function get_my_url() {
  1369. if(x($_SESSION,'my_url'))
  1370. return $_SESSION['my_url'];
  1371. return false;
  1372. }
  1373. function zrl_init(&$a) {
  1374. $tmp_str = get_my_url();
  1375. if(validate_url($tmp_str)) {
  1376. proc_run('php','include/gprobe.php',bin2hex($tmp_str));
  1377. $arr = array('zrl' => $tmp_str, 'url' => $a->cmd);
  1378. call_hooks('zrl_init',$arr);
  1379. }
  1380. }
  1381. function zrl($s,$force = false) {
  1382. if(! strlen($s))
  1383. return $s;
  1384. if((! strpos($s,'/profile/')) && (! $force))
  1385. return $s;
  1386. if($force && substr($s,-1,1) !== '/')
  1387. $s = $s . '/';
  1388. $achar = strpos($s,'?') ? '&' : '?';
  1389. $mine = get_my_url();
  1390. if($mine and ! link_compare($mine,$s))
  1391. return $s . $achar . 'zrl=' . urlencode($mine);
  1392. return $s;
  1393. }
  1394. /**
  1395. * returns querystring as string from a mapped array
  1396. *
  1397. * @param params Array
  1398. * @return string
  1399. */
  1400. function build_querystring($params, $name=null) {
  1401. $ret = "";
  1402. foreach($params as $key=>$val) {
  1403. if(is_array($val)) {
  1404. if($name==null) {
  1405. $ret .= build_querystring($val, $key);
  1406. } else {
  1407. $ret .= build_querystring($val, $name."[$key]");
  1408. }
  1409. } else {
  1410. $val = urlencode($val);
  1411. if($name!=null) {
  1412. $ret.=$name."[$key]"."=$val&";
  1413. } else {
  1414. $ret.= "$key=$val&";
  1415. }
  1416. }
  1417. }
  1418. return $ret;
  1419. }
  1420. /**
  1421. * Returns the complete URL of the current page, e.g.: http(s)://something.com/network
  1422. *
  1423. * Taken from http://webcheatsheet.com/php/get_current_page_url.php
  1424. */
  1425. function curPageURL() {
  1426. $pageURL = 'http';
  1427. if ($_SERVER["HTTPS"] == "on") {$pageURL .= "s";}
  1428. $pageURL .= "://";
  1429. if ($_SERVER["SERVER_PORT"] != "80" && $_SERVER["SERVER_PORT"] != "443") {
  1430. $pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
  1431. } else {
  1432. $pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
  1433. }
  1434. return $pageURL;
  1435. }