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.

2393 lines
65 KiB

11 years ago
10 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
10 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
10 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
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
9 years ago
9 years ago
11 years ago
7 years ago
7 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
10 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
8 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
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
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. require_once('include/features.php');
  12. require_once('update.php');
  13. require_once('include/dbstructure.php');
  14. define ( 'FRIENDICA_PLATFORM', 'Friendica');
  15. define ( 'FRIENDICA_CODENAME', 'Ginger');
  16. define ( 'FRIENDICA_VERSION', '3.3.3-RC' );
  17. define ( 'DFRN_PROTOCOL_VERSION', '2.23' );
  18. define ( 'DB_UPDATE_VERSION', 1178 );
  19. define ( 'EOL', "<br />\r\n" );
  20. define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' );
  21. /**
  22. *
  23. * Image storage quality. Lower numbers save space at cost of image detail.
  24. * For ease of upgrade, please do not change here. Change jpeg quality with
  25. * $a->config['system']['jpeg_quality'] = n;
  26. * in .htconfig.php, where n is netween 1 and 100, and with very poor results
  27. * below about 50
  28. *
  29. */
  30. define ( 'JPEG_QUALITY', 100 );
  31. /**
  32. * $a->config['system']['png_quality'] from 0 (uncompressed) to 9
  33. */
  34. define ( 'PNG_QUALITY', 8 );
  35. /**
  36. *
  37. * An alternate way of limiting picture upload sizes. Specify the maximum pixel
  38. * length that pictures are allowed to be (for non-square pictures, it will apply
  39. * to the longest side). Pictures longer than this length will be resized to be
  40. * this length (on the longest side, the other side will be scaled appropriately).
  41. * Modify this value using
  42. *
  43. * $a->config['system']['max_image_length'] = n;
  44. *
  45. * in .htconfig.php
  46. *
  47. * If you don't want to set a maximum length, set to -1. The default value is
  48. * defined by 'MAX_IMAGE_LENGTH' below.
  49. *
  50. */
  51. define ( 'MAX_IMAGE_LENGTH', -1 );
  52. /**
  53. * Not yet used
  54. */
  55. define ( 'DEFAULT_DB_ENGINE', 'MyISAM' );
  56. /**
  57. * SSL redirection policies
  58. */
  59. define ( 'SSL_POLICY_NONE', 0 );
  60. define ( 'SSL_POLICY_FULL', 1 );
  61. define ( 'SSL_POLICY_SELFSIGN', 2 );
  62. /**
  63. * log levels
  64. */
  65. define ( 'LOGGER_NORMAL', 0 );
  66. define ( 'LOGGER_TRACE', 1 );
  67. define ( 'LOGGER_DEBUG', 2 );
  68. define ( 'LOGGER_DATA', 3 );
  69. define ( 'LOGGER_ALL', 4 );
  70. /**
  71. * registration policies
  72. */
  73. define ( 'REGISTER_CLOSED', 0 );
  74. define ( 'REGISTER_APPROVE', 1 );
  75. define ( 'REGISTER_OPEN', 2 );
  76. /**
  77. * relationship types
  78. */
  79. define ( 'CONTACT_IS_FOLLOWER', 1);
  80. define ( 'CONTACT_IS_SHARING', 2);
  81. define ( 'CONTACT_IS_FRIEND', 3);
  82. /**
  83. * DB update return values
  84. */
  85. define ( 'UPDATE_SUCCESS', 0);
  86. define ( 'UPDATE_FAILED', 1);
  87. /**
  88. *
  89. * page/profile types
  90. *
  91. * PAGE_NORMAL is a typical personal profile account
  92. * PAGE_SOAPBOX automatically approves all friend requests as CONTACT_IS_SHARING, (readonly)
  93. * PAGE_COMMUNITY automatically approves all friend requests as CONTACT_IS_SHARING, but with
  94. * write access to wall and comments (no email and not included in page owner's ACL lists)
  95. * PAGE_FREELOVE automatically approves all friend requests as full friends (CONTACT_IS_FRIEND).
  96. *
  97. */
  98. define ( 'PAGE_NORMAL', 0 );
  99. define ( 'PAGE_SOAPBOX', 1 );
  100. define ( 'PAGE_COMMUNITY', 2 );
  101. define ( 'PAGE_FREELOVE', 3 );
  102. define ( 'PAGE_BLOG', 4 );
  103. define ( 'PAGE_PRVGROUP', 5 );
  104. /**
  105. * Network and protocol family types
  106. */
  107. define ( 'NETWORK_DFRN', 'dfrn'); // Friendica, Mistpark, other DFRN implementations
  108. define ( 'NETWORK_ZOT', 'zot!'); // Zot!
  109. define ( 'NETWORK_OSTATUS', 'stat'); // status.net, identi.ca, GNU-social, other OStatus implementations
  110. define ( 'NETWORK_FEED', 'feed'); // RSS/Atom feeds with no known "post/notify" protocol
  111. define ( 'NETWORK_DIASPORA', 'dspr'); // Diaspora
  112. define ( 'NETWORK_MAIL', 'mail'); // IMAP/POP
  113. define ( 'NETWORK_MAIL2', 'mai2'); // extended IMAP/POP
  114. define ( 'NETWORK_FACEBOOK', 'face'); // Facebook API
  115. define ( 'NETWORK_LINKEDIN', 'lnkd'); // LinkedIn
  116. define ( 'NETWORK_XMPP', 'xmpp'); // XMPP
  117. define ( 'NETWORK_MYSPACE', 'mysp'); // MySpace
  118. define ( 'NETWORK_GPLUS', 'goog'); // Google+
  119. define ( 'NETWORK_PUMPIO', 'pump'); // pump.io
  120. define ( 'NETWORK_TWITTER', 'twit'); // Twitter
  121. define ( 'NETWORK_DIASPORA2', 'dspc'); // Diaspora connector
  122. define ( 'NETWORK_STATUSNET', 'stac'); // Statusnet connector
  123. define ( 'NETWORK_APPNET', 'apdn'); // app.net
  124. define ( 'NETWORK_PHANTOM', 'unkn'); // Place holder
  125. /**
  126. * These numbers are used in stored permissions
  127. * and existing allocations MUST NEVER BE CHANGED
  128. * OR RE-ASSIGNED! You may only add to them.
  129. */
  130. $netgroup_ids = array(
  131. NETWORK_DFRN => (-1),
  132. NETWORK_ZOT => (-2),
  133. NETWORK_OSTATUS => (-3),
  134. NETWORK_FEED => (-4),
  135. NETWORK_DIASPORA => (-5),
  136. NETWORK_MAIL => (-6),
  137. NETWORK_MAIL2 => (-7),
  138. NETWORK_FACEBOOK => (-8),
  139. NETWORK_LINKEDIN => (-9),
  140. NETWORK_XMPP => (-10),
  141. NETWORK_MYSPACE => (-11),
  142. NETWORK_GPLUS => (-12),
  143. NETWORK_PUMPIO => (-13),
  144. NETWORK_TWITTER => (-14),
  145. NETWORK_DIASPORA2 => (-15),
  146. NETWORK_STATUSNET => (-16),
  147. NETWORK_APPNET => (-17),
  148. NETWORK_PHANTOM => (-127),
  149. );
  150. /**
  151. * Maximum number of "people who like (or don't like) this" that we will list by name
  152. */
  153. define ( 'MAX_LIKERS', 75);
  154. /**
  155. * Communication timeout
  156. */
  157. define ( 'ZCURL_TIMEOUT' , (-1));
  158. /**
  159. * email notification options
  160. */
  161. define ( 'NOTIFY_INTRO', 0x0001 );
  162. define ( 'NOTIFY_CONFIRM', 0x0002 );
  163. define ( 'NOTIFY_WALL', 0x0004 );
  164. define ( 'NOTIFY_COMMENT', 0x0008 );
  165. define ( 'NOTIFY_MAIL', 0x0010 );
  166. define ( 'NOTIFY_SUGGEST', 0x0020 );
  167. define ( 'NOTIFY_PROFILE', 0x0040 );
  168. define ( 'NOTIFY_TAGSELF', 0x0080 );
  169. define ( 'NOTIFY_TAGSHARE', 0x0100 );
  170. define ( 'NOTIFY_POKE', 0x0200 );
  171. define ( 'NOTIFY_SHARE', 0x0400 );
  172. define ( 'NOTIFY_SYSTEM', 0x8000 );
  173. /**
  174. * Tag/term types
  175. */
  176. define ( 'TERM_UNKNOWN', 0 );
  177. define ( 'TERM_HASHTAG', 1 );
  178. define ( 'TERM_MENTION', 2 );
  179. define ( 'TERM_CATEGORY', 3 );
  180. define ( 'TERM_PCATEGORY', 4 );
  181. define ( 'TERM_FILE', 5 );
  182. define ( 'TERM_SAVEDSEARCH', 6 );
  183. define ( 'TERM_CONVERSATION', 7 );
  184. define ( 'TERM_OBJ_POST', 1 );
  185. define ( 'TERM_OBJ_PHOTO', 2 );
  186. /**
  187. * various namespaces we may need to parse
  188. */
  189. define ( 'NAMESPACE_ZOT', 'http://purl.org/zot' );
  190. define ( 'NAMESPACE_DFRN' , 'http://purl.org/macgirvin/dfrn/1.0' );
  191. define ( 'NAMESPACE_THREAD' , 'http://purl.org/syndication/thread/1.0' );
  192. define ( 'NAMESPACE_TOMB' , 'http://purl.org/atompub/tombstones/1.0' );
  193. define ( 'NAMESPACE_ACTIVITY', 'http://activitystrea.ms/spec/1.0/' );
  194. define ( 'NAMESPACE_ACTIVITY_SCHEMA', 'http://activitystrea.ms/schema/1.0/' );
  195. define ( 'NAMESPACE_MEDIA', 'http://purl.org/syndication/atommedia' );
  196. define ( 'NAMESPACE_SALMON_ME', 'http://salmon-protocol.org/ns/magic-env' );
  197. define ( 'NAMESPACE_OSTATUSSUB', 'http://ostatus.org/schema/1.0/subscribe' );
  198. define ( 'NAMESPACE_GEORSS', 'http://www.georss.org/georss' );
  199. define ( 'NAMESPACE_POCO', 'http://portablecontacts.net/spec/1.0' );
  200. define ( 'NAMESPACE_FEED', 'http://schemas.google.com/g/2010#updates-from' );
  201. define ( 'NAMESPACE_OSTATUS', 'http://ostatus.org/schema/1.0' );
  202. define ( 'NAMESPACE_STATUSNET', 'http://status.net/schema/api/1/' );
  203. define ( 'NAMESPACE_ATOM1', 'http://www.w3.org/2005/Atom' );
  204. /**
  205. * activity stream defines
  206. */
  207. define ( 'ACTIVITY_LIKE', NAMESPACE_ACTIVITY_SCHEMA . 'like' );
  208. define ( 'ACTIVITY_DISLIKE', NAMESPACE_DFRN . '/dislike' );
  209. define ( 'ACTIVITY_OBJ_HEART', NAMESPACE_DFRN . '/heart' );
  210. define ( 'ACTIVITY_FRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'make-friend' );
  211. define ( 'ACTIVITY_REQ_FRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'request-friend' );
  212. define ( 'ACTIVITY_UNFRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'remove-friend' );
  213. define ( 'ACTIVITY_FOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'follow' );
  214. define ( 'ACTIVITY_UNFOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'stop-following' );
  215. define ( 'ACTIVITY_JOIN', NAMESPACE_ACTIVITY_SCHEMA . 'join' );
  216. define ( 'ACTIVITY_POST', NAMESPACE_ACTIVITY_SCHEMA . 'post' );
  217. define ( 'ACTIVITY_UPDATE', NAMESPACE_ACTIVITY_SCHEMA . 'update' );
  218. define ( 'ACTIVITY_TAG', NAMESPACE_ACTIVITY_SCHEMA . 'tag' );
  219. define ( 'ACTIVITY_FAVORITE', NAMESPACE_ACTIVITY_SCHEMA . 'favorite' );
  220. define ( 'ACTIVITY_POKE', NAMESPACE_ZOT . '/activity/poke' );
  221. define ( 'ACTIVITY_MOOD', NAMESPACE_ZOT . '/activity/mood' );
  222. define ( 'ACTIVITY_OBJ_BOOKMARK', NAMESPACE_ACTIVITY_SCHEMA . 'bookmark' );
  223. define ( 'ACTIVITY_OBJ_COMMENT', NAMESPACE_ACTIVITY_SCHEMA . 'comment' );
  224. define ( 'ACTIVITY_OBJ_NOTE', NAMESPACE_ACTIVITY_SCHEMA . 'note' );
  225. define ( 'ACTIVITY_OBJ_PERSON', NAMESPACE_ACTIVITY_SCHEMA . 'person' );
  226. define ( 'ACTIVITY_OBJ_IMAGE', NAMESPACE_ACTIVITY_SCHEMA . 'image' );
  227. define ( 'ACTIVITY_OBJ_PHOTO', NAMESPACE_ACTIVITY_SCHEMA . 'photo' );
  228. define ( 'ACTIVITY_OBJ_VIDEO', NAMESPACE_ACTIVITY_SCHEMA . 'video' );
  229. define ( 'ACTIVITY_OBJ_P_PHOTO', NAMESPACE_ACTIVITY_SCHEMA . 'profile-photo' );
  230. define ( 'ACTIVITY_OBJ_ALBUM', NAMESPACE_ACTIVITY_SCHEMA . 'photo-album' );
  231. define ( 'ACTIVITY_OBJ_EVENT', NAMESPACE_ACTIVITY_SCHEMA . 'event' );
  232. define ( 'ACTIVITY_OBJ_GROUP', NAMESPACE_ACTIVITY_SCHEMA . 'group' );
  233. define ( 'ACTIVITY_OBJ_TAGTERM', NAMESPACE_DFRN . '/tagterm' );
  234. define ( 'ACTIVITY_OBJ_PROFILE', NAMESPACE_DFRN . '/profile' );
  235. /**
  236. * item weight for query ordering
  237. */
  238. define ( 'GRAVITY_PARENT', 0);
  239. define ( 'GRAVITY_LIKE', 3);
  240. define ( 'GRAVITY_COMMENT', 6);
  241. /**
  242. *
  243. * Reverse the effect of magic_quotes_gpc if it is enabled.
  244. * Please disable magic_quotes_gpc so we don't have to do this.
  245. * See http://php.net/manual/en/security.magicquotes.disabling.php
  246. *
  247. */
  248. function startup() {
  249. error_reporting(E_ERROR | E_WARNING | E_PARSE);
  250. set_time_limit(0);
  251. // This has to be quite large to deal with embedded private photos
  252. ini_set('pcre.backtrack_limit', 500000);
  253. if (get_magic_quotes_gpc()) {
  254. $process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
  255. while (list($key, $val) = each($process)) {
  256. foreach ($val as $k => $v) {
  257. unset($process[$key][$k]);
  258. if (is_array($v)) {
  259. $process[$key][stripslashes($k)] = $v;
  260. $process[] = &$process[$key][stripslashes($k)];
  261. } else {
  262. $process[$key][stripslashes($k)] = stripslashes($v);
  263. }
  264. }
  265. }
  266. unset($process);
  267. }
  268. }
  269. /**
  270. *
  271. * class: App
  272. *
  273. * Our main application structure for the life of this page
  274. * Primarily deals with the URL that got us here
  275. * and tries to make some sense of it, and
  276. * stores our page contents and config storage
  277. * and anything else that might need to be passed around
  278. * before we spit the page out.
  279. *
  280. */
  281. if(! class_exists('App')) {
  282. class App {
  283. public $module_loaded = false;
  284. public $query_string;
  285. public $config;
  286. public $page;
  287. public $profile;
  288. public $user;
  289. public $cid;
  290. public $contact;
  291. public $contacts;
  292. public $page_contact;
  293. public $content;
  294. public $data = array();
  295. public $error = false;
  296. public $cmd;
  297. public $argv;
  298. public $argc;
  299. public $module;
  300. public $pager;
  301. public $strings;
  302. public $path;
  303. public $hooks;
  304. public $timezone;
  305. public $interactive = true;
  306. public $plugins;
  307. public $apps = array();
  308. public $identities;
  309. public $is_mobile;
  310. public $is_tablet;
  311. public $performance = array();
  312. public $nav_sel;
  313. public $category;
  314. // Allow themes to control internal parameters
  315. // by changing App values in theme.php
  316. public $sourcename = '';
  317. public $videowidth = 425;
  318. public $videoheight = 350;
  319. public $force_max_items = 0;
  320. public $theme_thread_allow = true;
  321. // An array for all theme-controllable parameters
  322. // Mostly unimplemented yet. Only options 'stylesheet' and
  323. // beyond are used.
  324. public $theme = array(
  325. 'sourcename' => '',
  326. 'videowidth' => 425,
  327. 'videoheight' => 350,
  328. 'force_max_items' => 0,
  329. 'thread_allow' => true,
  330. 'stylesheet' => '',
  331. 'template_engine' => 'smarty3',
  332. );
  333. // array of registered template engines ('name'=>'class name')
  334. public $template_engines = array();
  335. // array of instanced template engines ('name'=>'instance')
  336. public $template_engine_instance = array();
  337. // Used for reducing load to the ostatus completion
  338. public $last_ostatus_conversation_url;
  339. private $ldelim = array(
  340. 'internal' => '',
  341. 'smarty3' => '{{'
  342. );
  343. private $rdelim = array(
  344. 'internal' => '',
  345. 'smarty3' => '}}'
  346. );
  347. private $scheme;
  348. private $hostname;
  349. private $baseurl;
  350. private $db;
  351. private $curl_code;
  352. private $curl_content_type;
  353. private $curl_headers;
  354. private $cached_profile_image;
  355. private $cached_profile_picdate;
  356. function __construct() {
  357. global $default_timezone;
  358. $hostname = "";
  359. if (file_exists(".htpreconfig.php"))
  360. @include(".htpreconfig.php");
  361. $this->timezone = ((x($default_timezone)) ? $default_timezone : 'UTC');
  362. date_default_timezone_set($this->timezone);
  363. $this->performance["start"] = microtime(true);
  364. $this->performance["database"] = 0;
  365. $this->performance["network"] = 0;
  366. $this->performance["file"] = 0;
  367. $this->performance["rendering"] = 0;
  368. $this->performance["parser"] = 0;
  369. $this->performance["marktime"] = 0;
  370. $this->performance["markstart"] = microtime(true);
  371. $this->config = array();
  372. $this->page = array();
  373. $this->pager= array();
  374. $this->query_string = '';
  375. startup();
  376. set_include_path(
  377. 'include' . PATH_SEPARATOR
  378. . 'library' . PATH_SEPARATOR
  379. . 'library/phpsec' . PATH_SEPARATOR
  380. . 'library/langdet' . PATH_SEPARATOR
  381. . '.' );
  382. $this->scheme = 'http';
  383. if(x($_SERVER,'HTTPS') && $_SERVER['HTTPS'])
  384. $this->scheme = 'https';
  385. elseif(x($_SERVER,'SERVER_PORT') && (intval($_SERVER['SERVER_PORT']) == 443))
  386. $this->scheme = 'https';
  387. if(x($_SERVER,'SERVER_NAME')) {
  388. $this->hostname = $_SERVER['SERVER_NAME'];
  389. // See bug 437 - this didn't work so disabling it
  390. //if(stristr($this->hostname,'xn--')) {
  391. // PHP or webserver may have converted idn to punycode, so
  392. // convert punycode back to utf-8
  393. // require_once('library/simplepie/idn/idna_convert.class.php');
  394. // $x = new idna_convert();
  395. // $this->hostname = $x->decode($_SERVER['SERVER_NAME']);
  396. //}
  397. if(x($_SERVER,'SERVER_PORT') && $_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443)
  398. $this->hostname .= ':' . $_SERVER['SERVER_PORT'];
  399. /**
  400. * Figure out if we are running at the top of a domain
  401. * or in a sub-directory and adjust accordingly
  402. */
  403. $path = trim(dirname($_SERVER['SCRIPT_NAME']),'/\\');
  404. if(isset($path) && strlen($path) && ($path != $this->path))
  405. $this->path = $path;
  406. }
  407. if ($hostname != "")
  408. $this->hostname = $hostname;
  409. if (is_array($_SERVER["argv"]) && $_SERVER["argc"]>1 && substr(end($_SERVER["argv"]), 0, 4)=="http" ) {
  410. $this->set_baseurl(array_pop($_SERVER["argv"]) );
  411. $_SERVER["argc"] --;
  412. }
  413. #set_include_path("include/$this->hostname" . PATH_SEPARATOR . get_include_path());
  414. if((x($_SERVER,'QUERY_STRING')) && substr($_SERVER['QUERY_STRING'],0,9) === "pagename=") {
  415. $this->query_string = substr($_SERVER['QUERY_STRING'],9);
  416. // removing trailing / - maybe a nginx problem
  417. if (substr($this->query_string, 0, 1) == "/")
  418. $this->query_string = substr($this->query_string, 1);
  419. } elseif((x($_SERVER,'QUERY_STRING')) && substr($_SERVER['QUERY_STRING'],0,2) === "q=") {
  420. $this->query_string = substr($_SERVER['QUERY_STRING'],2);
  421. // removing trailing / - maybe a nginx problem
  422. if (substr($this->query_string, 0, 1) == "/")
  423. $this->query_string = substr($this->query_string, 1);
  424. }
  425. if (x($_GET,'pagename'))
  426. $this->cmd = trim($_GET['pagename'],'/\\');
  427. elseif (x($_GET,'q'))
  428. $this->cmd = trim($_GET['q'],'/\\');
  429. // fix query_string
  430. $this->query_string = str_replace($this->cmd."&",$this->cmd."?", $this->query_string);
  431. // unix style "homedir"
  432. if(substr($this->cmd,0,1) === '~')
  433. $this->cmd = 'profile/' . substr($this->cmd,1);
  434. // Diaspora style profile url
  435. if(substr($this->cmd,0,2) === 'u/')
  436. $this->cmd = 'profile/' . substr($this->cmd,2);
  437. /**
  438. *
  439. * Break the URL path into C style argc/argv style arguments for our
  440. * modules. Given "http://example.com/module/arg1/arg2", $this->argc
  441. * will be 3 (integer) and $this->argv will contain:
  442. * [0] => 'module'
  443. * [1] => 'arg1'
  444. * [2] => 'arg2'
  445. *
  446. *
  447. * There will always be one argument. If provided a naked domain
  448. * URL, $this->argv[0] is set to "home".
  449. *
  450. */
  451. $this->argv = explode('/',$this->cmd);
  452. $this->argc = count($this->argv);
  453. if((array_key_exists('0',$this->argv)) && strlen($this->argv[0])) {
  454. $this->module = str_replace(".", "_", $this->argv[0]);
  455. $this->module = str_replace("-", "_", $this->module);
  456. }
  457. else {
  458. $this->argc = 1;
  459. $this->argv = array('home');
  460. $this->module = 'home';
  461. }
  462. /**
  463. * See if there is any page number information, and initialise
  464. * pagination
  465. */
  466. $this->pager['page'] = ((x($_GET,'page') && intval($_GET['page']) > 0) ? intval($_GET['page']) : 1);
  467. $this->pager['itemspage'] = 50;
  468. $this->pager['start'] = ($this->pager['page'] * $this->pager['itemspage']) - $this->pager['itemspage'];
  469. if($this->pager['start'] < 0)
  470. $this->pager['start'] = 0;
  471. $this->pager['total'] = 0;
  472. /**
  473. * Detect mobile devices
  474. */
  475. $mobile_detect = new Mobile_Detect();
  476. $this->is_mobile = $mobile_detect->isMobile();
  477. $this->is_tablet = $mobile_detect->isTablet();
  478. /**
  479. * register template engines
  480. */
  481. $dc = get_declared_classes();
  482. foreach ($dc as $k) {
  483. if (in_array("ITemplateEngine", class_implements($k))){
  484. $this->register_template_engine($k);
  485. }
  486. }
  487. }
  488. function get_basepath() {
  489. $basepath = get_config("system", "basepath");
  490. if ($basepath == "")
  491. $basepath = $_SERVER["DOCUMENT_ROOT"];
  492. if ($basepath == "")
  493. $basepath = $_SERVER["PWD"];
  494. return($basepath);
  495. }
  496. function get_scheme() {
  497. return($this->scheme);
  498. }
  499. function get_baseurl($ssl = false) {
  500. $scheme = $this->scheme;
  501. if((x($this->config,'system')) && (x($this->config['system'],'ssl_policy'))) {
  502. if(intval($this->config['system']['ssl_policy']) === intval(SSL_POLICY_FULL))
  503. $scheme = 'https';
  504. // Basically, we have $ssl = true on any links which can only be seen by a logged in user
  505. // (and also the login link). Anything seen by an outsider will have it turned off.
  506. if($this->config['system']['ssl_policy'] == SSL_POLICY_SELFSIGN) {
  507. if($ssl)
  508. $scheme = 'https';
  509. else
  510. $scheme = 'http';
  511. }
  512. }
  513. if (get_config('config','hostname') != "")
  514. $this->hostname = get_config('config','hostname');
  515. $this->baseurl = $scheme . "://" . $this->hostname . ((isset($this->path) && strlen($this->path)) ? '/' . $this->path : '' );
  516. return $this->baseurl;
  517. }
  518. function set_baseurl($url) {
  519. $parsed = @parse_url($url);
  520. $this->baseurl = $url;
  521. if($parsed) {
  522. $this->scheme = $parsed['scheme'];
  523. $hostname = $parsed['host'];
  524. if(x($parsed,'port'))
  525. $hostname .= ':' . $parsed['port'];
  526. if(x($parsed,'path'))
  527. $this->path = trim($parsed['path'],'\\/');
  528. if (file_exists(".htpreconfig.php"))
  529. @include(".htpreconfig.php");
  530. if (get_config('config','hostname') != "")
  531. $this->hostname = get_config('config','hostname');
  532. if (!isset($this->hostname) OR ($this->hostname == ""))
  533. $this->hostname = $hostname;
  534. }
  535. }
  536. function get_hostname() {
  537. if (get_config('config','hostname') != "")
  538. $this->hostname = get_config('config','hostname');
  539. return $this->hostname;
  540. }
  541. function set_hostname($h) {
  542. $this->hostname = $h;
  543. }
  544. function set_path($p) {
  545. $this->path = trim(trim($p),'/');
  546. }
  547. function get_path() {
  548. return $this->path;
  549. }
  550. function set_pager_total($n) {
  551. $this->pager['total'] = intval($n);
  552. }
  553. function set_pager_itemspage($n) {
  554. $this->pager['itemspage'] = ((intval($n) > 0) ? intval($n) : 0);
  555. $this->pager['start'] = ($this->pager['page'] * $this->pager['itemspage']) - $this->pager['itemspage'];
  556. }
  557. function set_pager_page($n) {
  558. $this->pager['page'] = $n;
  559. $this->pager['start'] = ($this->pager['page'] * $this->pager['itemspage']) - $this->pager['itemspage'];
  560. }
  561. function init_pagehead() {
  562. $interval = ((local_user()) ? get_pconfig(local_user(),'system','update_interval') : 40000);
  563. if($interval < 10000)
  564. $interval = 40000;
  565. $this->page['title'] = $this->config['sitename'];
  566. /* put the head template at the beginning of page['htmlhead']
  567. * since the code added by the modules frequently depends on it
  568. * being first
  569. */
  570. if(!isset($this->page['htmlhead']))
  571. $this->page['htmlhead'] = '';
  572. // If we're using Smarty, then doing replace_macros() will replace
  573. // any unrecognized variables with a blank string. Since we delay
  574. // replacing $stylesheet until later, we need to replace it now
  575. // with another variable name
  576. if($this->theme['template_engine'] === 'smarty3')
  577. $stylesheet = $this->get_template_ldelim('smarty3') . '$stylesheet' . $this->get_template_rdelim('smarty3');
  578. else
  579. $stylesheet = '$stylesheet';
  580. $shortcut_icon = get_config("system", "shortcut_icon");
  581. if ($shortcut_icon == "")
  582. $shortcut_icon = $this->get_baseurl()."/images/friendica-32.png";
  583. $touch_icon = get_config("system", "touch_icon");
  584. if ($touch_icon == "")
  585. $touch_icon = $this->get_baseurl()."/images/friendica-128.png";
  586. $tpl = get_markup_template('head.tpl');
  587. $this->page['htmlhead'] = replace_macros($tpl,array(
  588. '$baseurl' => $this->get_baseurl(), // FIXME for z_path!!!!
  589. '$local_user' => local_user(),
  590. '$generator' => 'Friendica' . ' ' . FRIENDICA_VERSION,
  591. '$delitem' => t('Delete this item?'),
  592. '$comment' => t('Comment'),
  593. '$showmore' => t('show more'),
  594. '$showfewer' => t('show fewer'),
  595. '$update_interval' => $interval,
  596. '$shortcut_icon' => $shortcut_icon,
  597. '$touch_icon' => $touch_icon,
  598. '$stylesheet' => $stylesheet
  599. )) . $this->page['htmlhead'];
  600. }
  601. function init_page_end() {
  602. if(!isset($this->page['end']))
  603. $this->page['end'] = '';
  604. $tpl = get_markup_template('end.tpl');
  605. $this->page['end'] = replace_macros($tpl,array(
  606. '$baseurl' => $this->get_baseurl() // FIXME for z_path!!!!
  607. )) . $this->page['end'];
  608. }
  609. function set_curl_code($code) {
  610. $this->curl_code = $code;
  611. }
  612. function get_curl_code() {
  613. return $this->curl_code;
  614. }
  615. function set_curl_content_type($content_type) {
  616. $this->curl_content_type = $content_type;
  617. }
  618. function get_curl_content_type() {
  619. return $this->curl_content_type;
  620. }
  621. function set_curl_headers($headers) {
  622. $this->curl_headers = $headers;
  623. }
  624. function get_curl_headers() {
  625. return $this->curl_headers;
  626. }
  627. function get_cached_avatar_image($avatar_image){
  628. if($this->cached_profile_image[$avatar_image])
  629. return $this->cached_profile_image[$avatar_image];
  630. $path_parts = explode("/",$avatar_image);
  631. $common_filename = $path_parts[count($path_parts)-1];
  632. if($this->cached_profile_picdate[$common_filename]){
  633. $this->cached_profile_image[$avatar_image] = $avatar_image . $this->cached_profile_picdate[$common_filename];
  634. } else {
  635. $r = q("SELECT `contact`.`avatar-date` AS picdate FROM `contact` WHERE `contact`.`thumb` like '%%/%s'",
  636. $common_filename);
  637. if(! count($r)){
  638. $this->cached_profile_image[$avatar_image] = $avatar_image;
  639. } else {
  640. $this->cached_profile_picdate[$common_filename] = "?rev=".urlencode($r[0]['picdate']);
  641. $this->cached_profile_image[$avatar_image] = $avatar_image.$this->cached_profile_picdate[$common_filename];
  642. }
  643. }
  644. return $this->cached_profile_image[$avatar_image];
  645. }
  646. /**
  647. * register template engine class
  648. * if $name is "", is used class static property $class::$name
  649. * @param string $class
  650. * @param string $name
  651. */
  652. function register_template_engine($class, $name = '') {
  653. if ($name===""){
  654. $v = get_class_vars( $class );
  655. if(x($v,"name")) $name = $v['name'];
  656. }
  657. if ($name===""){
  658. echo "template engine <tt>$class</tt> cannot be registered without a name.\n";
  659. killme();
  660. }
  661. $this->template_engines[$name] = $class;
  662. }
  663. /**
  664. * return template engine instance. If $name is not defined,
  665. * return engine defined by theme, or default
  666. *
  667. * @param strin $name Template engine name
  668. * @return object Template Engine instance
  669. */
  670. function template_engine($name = ''){
  671. if ($name!=="") {
  672. $template_engine = $name;
  673. } else {
  674. $template_engine = 'smarty3';
  675. if (x($this->theme, 'template_engine')) {
  676. $template_engine = $this->theme['template_engine'];
  677. }
  678. }
  679. if (isset($this->template_engines[$template_engine])){
  680. if(isset($this->template_engine_instance[$template_engine])){
  681. return $this->template_engine_instance[$template_engine];
  682. } else {
  683. $class = $this->template_engines[$template_engine];
  684. $obj = new $class;
  685. $this->template_engine_instance[$template_engine] = $obj;
  686. return $obj;
  687. }
  688. }
  689. echo "template engine <tt>$template_engine</tt> is not registered!\n"; killme();
  690. }
  691. function get_template_engine() {
  692. return $this->theme['template_engine'];
  693. }
  694. function set_template_engine($engine = 'smarty3') {
  695. $this->theme['template_engine'] = $engine;
  696. /*
  697. $this->theme['template_engine'] = 'smarty3';
  698. switch($engine) {
  699. case 'smarty3':
  700. if(is_writable('view/smarty3/'))
  701. $this->theme['template_engine'] = 'smarty3';
  702. break;
  703. default:
  704. break;
  705. }
  706. */
  707. }
  708. function get_template_ldelim($engine = 'smarty3') {
  709. return $this->ldelim[$engine];
  710. }
  711. function get_template_rdelim($engine = 'smarty3') {
  712. return $this->rdelim[$engine];
  713. }
  714. function save_timestamp($stamp, $value) {
  715. $duration = (float)(microtime(true)-$stamp);
  716. $this->performance[$value] += (float)$duration;
  717. $this->performance["marktime"] += (float)$duration;
  718. }
  719. function mark_timestamp($mark) {
  720. //$this->performance["markstart"] -= microtime(true) - $this->performance["marktime"];
  721. $this->performance["markstart"] = microtime(true) - $this->performance["markstart"] - $this->performance["marktime"];
  722. }
  723. function get_useragent() {
  724. return(FRIENDICA_PLATFORM." '".FRIENDICA_CODENAME."' ".FRIENDICA_VERSION."-".DB_UPDATE_VERSION."; ".$this->get_baseurl());
  725. }
  726. }
  727. }
  728. // retrieve the App structure
  729. // useful in functions which require it but don't get it passed to them
  730. if(! function_exists('get_app')) {
  731. function get_app() {
  732. global $a;
  733. return $a;
  734. }
  735. };
  736. // Multi-purpose function to check variable state.
  737. // Usage: x($var) or $x($array,'key')
  738. // returns false if variable/key is not set
  739. // if variable is set, returns 1 if has 'non-zero' value, otherwise returns 0.
  740. // e.g. x('') or x(0) returns 0;
  741. if(! function_exists('x')) {
  742. function x($s,$k = NULL) {
  743. if($k != NULL) {
  744. if((is_array($s)) && (array_key_exists($k,$s))) {
  745. if($s[$k])
  746. return (int) 1;
  747. return (int) 0;
  748. }
  749. return false;
  750. }
  751. else {
  752. if(isset($s)) {
  753. if($s) {
  754. return (int) 1;
  755. }
  756. return (int) 0;
  757. }
  758. return false;
  759. }
  760. }
  761. }
  762. // called from db initialisation if db is dead.
  763. if(! function_exists('system_unavailable')) {
  764. function system_unavailable() {
  765. include('system_unavailable.php');
  766. system_down();
  767. killme();
  768. }
  769. }
  770. function clean_urls() {
  771. global $a;
  772. // if($a->config['system']['clean_urls'])
  773. return true;
  774. // return false;
  775. }
  776. function z_path() {
  777. global $a;
  778. $base = $a->get_baseurl();
  779. if(! clean_urls())
  780. $base .= '/?q=';
  781. return $base;
  782. }
  783. function z_root() {
  784. global $a;
  785. return $a->get_baseurl();
  786. }
  787. function absurl($path) {
  788. if(strpos($path,'/') === 0)
  789. return z_path() . $path;
  790. return $path;
  791. }
  792. function is_ajax() {
  793. return (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
  794. }
  795. function check_db() {
  796. $build = get_config('system','build');
  797. if(! x($build)) {
  798. set_config('system','build',DB_UPDATE_VERSION);
  799. $build = DB_UPDATE_VERSION;
  800. }
  801. if($build != DB_UPDATE_VERSION)
  802. proc_run('php', 'include/dbupdate.php');
  803. }
  804. // Sets the base url for use in cmdline programs which don't have
  805. // $_SERVER variables
  806. if(! function_exists('check_url')) {
  807. function check_url(&$a) {
  808. $url = get_config('system','url');
  809. // if the url isn't set or the stored url is radically different
  810. // than the currently visited url, store the current value accordingly.
  811. // "Radically different" ignores common variations such as http vs https
  812. // and www.example.com vs example.com.
  813. // We will only change the url to an ip address if there is no existing setting
  814. if(! x($url))
  815. $url = set_config('system','url',$a->get_baseurl());
  816. if((! link_compare($url,$a->get_baseurl())) && (! preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/",$a->get_hostname)))
  817. $url = set_config('system','url',$a->get_baseurl());
  818. return;
  819. }
  820. }
  821. // Automatic database updates
  822. if(! function_exists('update_db')) {
  823. function update_db(&$a) {
  824. $build = get_config('system','build');
  825. if(! x($build))
  826. $build = set_config('system','build',DB_UPDATE_VERSION);
  827. if($build != DB_UPDATE_VERSION) {
  828. $stored = intval($build);
  829. $current = intval(DB_UPDATE_VERSION);
  830. if($stored < $current) {
  831. load_config('database');
  832. // We're reporting a different version than what is currently installed.
  833. // Run any existing update scripts to bring the database up to current.
  834. // make sure that boot.php and update.php are the same release, we might be
  835. // updating right this very second and the correct version of the update.php
  836. // file may not be here yet. This can happen on a very busy site.
  837. if(DB_UPDATE_VERSION == UPDATE_VERSION) {
  838. // Compare the current structure with the defined structure
  839. $t = get_config('database','dbupdate_'.DB_UPDATE_VERSION);
  840. if($t !== false)
  841. return;
  842. set_config('database','dbupdate_'.DB_UPDATE_VERSION, time());
  843. // run old update routine (wich could modify the schema and
  844. // conflits with new routine)
  845. for ($x = $stored; $x < NEW_UPDATE_ROUTINE_VERSION; $x++) {
  846. $r = run_update_function($x);
  847. if (!$r) break;
  848. }
  849. if ($stored < NEW_UPDATE_ROUTINE_VERSION) $stored = NEW_UPDATE_ROUTINE_VERSION;
  850. // run new update routine
  851. // it update the structure in one call
  852. $retval = update_structure(false, true);
  853. if($retval) {
  854. update_fail(
  855. DB_UPDATE_VERSION,
  856. $retval
  857. );
  858. return;
  859. } else {
  860. set_config('database','dbupdate_'.DB_UPDATE_VERSION, 'success');
  861. }
  862. // run any left update_nnnn functions in update.php
  863. for($x = $stored; $x < $current; $x ++) {
  864. $r = run_update_function($x);
  865. if (!$r) break;
  866. }
  867. }
  868. }
  869. }
  870. return;
  871. }
  872. }
  873. if(!function_exists('run_update_function')){
  874. function run_update_function($x) {
  875. if(function_exists('update_' . $x)) {
  876. // There could be a lot of processes running or about to run.
  877. // We want exactly one process to run the update command.
  878. // So store the fact that we're taking responsibility
  879. // after first checking to see if somebody else already has.
  880. // If the update fails or times-out completely you may need to
  881. // delete the config entry to try again.
  882. $t = get_config('database','update_' . $x);
  883. if($t !== false)
  884. return false;
  885. set_config('database','update_' . $x, time());
  886. // call the specific update
  887. $func = 'update_' . $x;
  888. $retval = $func();
  889. if($retval) {
  890. //send the administrator an e-mail
  891. update_fail(
  892. $x,
  893. sprintf(t('Update %s failed. See error logs.'), $x)
  894. );
  895. return false;
  896. } else {
  897. set_config('database','update_' . $x, 'success');
  898. set_config('system','build', $x + 1);
  899. return true;
  900. }
  901. } else {
  902. set_config('database','update_' . $x, 'success');
  903. set_config('system','build', $x + 1);
  904. return true;
  905. }
  906. return true;
  907. }
  908. }
  909. if(! function_exists('check_plugins')) {
  910. function check_plugins(&$a) {
  911. /**
  912. *
  913. * Synchronise plugins:
  914. *
  915. * $a->config['system']['addon'] contains a comma-separated list of names
  916. * of plugins/addons which are used on this system.
  917. * Go through the database list of already installed addons, and if we have
  918. * an entry, but it isn't in the config list, call the uninstall procedure
  919. * and mark it uninstalled in the database (for now we'll remove it).
  920. * Then go through the config list and if we have a plugin that isn't installed,
  921. * call the install procedure and add it to the database.
  922. *
  923. */
  924. $r = q("SELECT * FROM `addon` WHERE `installed` = 1");
  925. if(count($r))
  926. $installed = $r;
  927. else
  928. $installed = array();
  929. $plugins = get_config('system','addon');
  930. $plugins_arr = array();
  931. if($plugins)
  932. $plugins_arr = explode(',',str_replace(' ', '',$plugins));
  933. $a->plugins = $plugins_arr;
  934. $installed_arr = array();
  935. if(count($installed)) {
  936. foreach($installed as $i) {
  937. if(! in_array($i['name'],$plugins_arr)) {
  938. uninstall_plugin($i['name']);
  939. }
  940. else {
  941. $installed_arr[] = $i['name'];
  942. }
  943. }
  944. }
  945. if(count($plugins_arr)) {
  946. foreach($plugins_arr as $p) {
  947. if(! in_array($p,$installed_arr)) {
  948. install_plugin($p);
  949. }
  950. }
  951. }
  952. load_hooks();
  953. return;
  954. }
  955. }
  956. function get_guid($size=16) {
  957. $exists = true; // assume by default that we don't have a unique guid
  958. do {
  959. $prefix = "";
  960. while (strlen($prefix) < ($size - 13))
  961. $prefix .= mt_rand();
  962. $s = substr(uniqid($prefix), -$size);
  963. $r = q("select id from guid where guid = '%s' limit 1", dbesc($s));
  964. if(! count($r))
  965. $exists = false;
  966. } while($exists);
  967. q("insert into guid (guid) values ('%s') ", dbesc($s));
  968. return $s;
  969. }
  970. /*function get_guid($size=16) {
  971. $exists = true; // assume by default that we don't have a unique guid
  972. do {
  973. $s = random_string($size);
  974. $r = q("select id from guid where guid = '%s' limit 1", dbesc($s));
  975. if(! count($r))
  976. $exists = false;
  977. } while($exists);
  978. q("insert into guid ( guid ) values ( '%s' ) ", dbesc($s));
  979. return $s;
  980. }*/
  981. // wrapper for adding a login box. If $register == true provide a registration
  982. // link. This will most always depend on the value of $a->config['register_policy'].
  983. // returns the complete html for inserting into the page
  984. if(! function_exists('login')) {
  985. function login($register = false, $hiddens=false) {
  986. $a = get_app();
  987. $o = "";
  988. $reg = false;
  989. if ($register) {
  990. $reg = array(
  991. 'title' => t('Create a New Account'),
  992. 'desc' => t('Register')
  993. );
  994. }
  995. $noid = get_config('system','no_openid');
  996. $dest_url = $a->get_baseurl(true) . '/' . $a->query_string;
  997. if(local_user()) {
  998. $tpl = get_markup_template("logout.tpl");
  999. }
  1000. else {
  1001. $a->page['htmlhead'] .= replace_macros(get_markup_template("login_head.tpl"),array(
  1002. '$baseurl' => $a->get_baseurl(true)
  1003. ));
  1004. $tpl = get_markup_template("login.tpl");
  1005. $_SESSION['return_url'] = $a->query_string;
  1006. $a->module = 'login';
  1007. }
  1008. $o .= replace_macros($tpl, array(
  1009. '$dest_url' => $dest_url,
  1010. '$logout' => t('Logout'),
  1011. '$login' => t('Login'),
  1012. '$lname' => array('username', t('Nickname or Email address: ') , '', ''),
  1013. '$lpassword' => array('password', t('Password: '), '', ''),
  1014. '$lremember' => array('remember', t('Remember me'), 0, ''),
  1015. '$openid' => !$noid,
  1016. '$lopenid' => array('openid_url', t('Or login using OpenID: '),'',''),
  1017. '$hiddens' => $hiddens,
  1018. '$register' => $reg,
  1019. '$lostpass' => t('Forgot your password?'),
  1020. '$lostlink' => t('Password Reset'),
  1021. '$tostitle' => t('Website Terms of Service'),
  1022. '$toslink' => t('terms of service'),
  1023. '$privacytitle' => t('Website Privacy Policy'),
  1024. '$privacylink' => t('privacy policy'),
  1025. ));
  1026. call_hooks('login_hook',$o);
  1027. return $o;
  1028. }
  1029. }
  1030. // Used to end the current process, after saving session state.
  1031. if(! function_exists('killme')) {
  1032. function killme() {
  1033. session_write_close();
  1034. exit;
  1035. }
  1036. }
  1037. // redirect to another URL and terminate this process.
  1038. if(! function_exists('goaway')) {
  1039. function goaway($s) {
  1040. header("Location: $s");
  1041. killme();
  1042. }
  1043. }
  1044. // Returns the uid of locally logged in user or false.
  1045. if(! function_exists('local_user')) {
  1046. function local_user() {
  1047. if((x($_SESSION,'authenticated')) && (x($_SESSION,'uid')))
  1048. return intval($_SESSION['uid']);
  1049. return false;
  1050. }
  1051. }
  1052. // Returns contact id of authenticated site visitor or false
  1053. if(! function_exists('remote_user')) {
  1054. function remote_user() {
  1055. if((x($_SESSION,'authenticated')) && (x($_SESSION,'visitor_id')))
  1056. return intval($_SESSION['visitor_id']);
  1057. return false;
  1058. }
  1059. }
  1060. // contents of $s are displayed prominently on the page the next time
  1061. // a page is loaded. Usually used for errors or alerts.
  1062. if(! function_exists('notice')) {
  1063. /**
  1064. * Show an error message to user.
  1065. *
  1066. * This function save text in session, to be shown to the user at next page load
  1067. *
  1068. * @param string $s - Text of notice
  1069. */
  1070. function notice($s) {
  1071. $a = get_app();
  1072. if(! x($_SESSION,'sysmsg')) $_SESSION['sysmsg'] = array();
  1073. if($a->interactive)
  1074. $_SESSION['sysmsg'][] = $s;
  1075. }
  1076. }
  1077. if(! function_exists('info')) {
  1078. /**
  1079. * Show an info message to user.
  1080. *
  1081. * This function save text in session, to be shown to the user at next page load
  1082. *
  1083. * @param string $s - Text of notice
  1084. */
  1085. function info($s) {
  1086. $a = get_app();
  1087. if (local_user() AND get_pconfig(local_user(),'system','ignore_info'))
  1088. return;
  1089. if(! x($_SESSION,'sysmsg_info')) $_SESSION['sysmsg_info'] = array();
  1090. if($a->interactive)
  1091. $_SESSION['sysmsg_info'][] = $s;
  1092. }
  1093. }
  1094. // wrapper around config to limit the text length of an incoming message
  1095. if(! function_exists('get_max_import_size')) {
  1096. function get_max_import_size() {
  1097. global $a;
  1098. return ((x($a->config,'max_import_size')) ? $a->config['max_import_size'] : 0 );
  1099. }
  1100. }
  1101. /**
  1102. *
  1103. * Function : profile_load
  1104. * @parameter App $a
  1105. * @parameter string $nickname
  1106. * @parameter int $profile
  1107. *
  1108. * Summary: Loads a profile into the page sidebar.
  1109. * The function requires a writeable copy of the main App structure, and the nickname
  1110. * of a registered local account.
  1111. *
  1112. * If the viewer is an authenticated remote viewer, the profile displayed is the
  1113. * one that has been configured for his/her viewing in the Contact manager.
  1114. * Passing a non-zero profile ID can also allow a preview of a selected profile
  1115. * by the owner.
  1116. *
  1117. * Profile information is placed in the App structure for later retrieval.
  1118. * Honours the owner's chosen theme for display.
  1119. *
  1120. * IMPORTANT: Should only be run in the _init() functions of a module. That ensures that
  1121. * the theme is chosen before the _init() function of a theme is run, which will usually
  1122. * load a lot of theme-specific content
  1123. *
  1124. */
  1125. if(! function_exists('profile_load')) {
  1126. function profile_load(&$a, $nickname, $profile = 0, $profiledata = array()) {
  1127. $user = q("SELECT `uid` FROM `user` WHERE `nickname` = '%s' LIMIT 1",
  1128. dbesc($nickname)
  1129. );
  1130. if(!$user && count($user) && !count($profiledata)) {
  1131. logger('profile error: ' . $a->query_string, LOGGER_DEBUG);
  1132. notice( t('Requested account is not available.') . EOL );
  1133. $a->error = 404;
  1134. return;
  1135. }
  1136. if(remote_user() && count($_SESSION['remote'])) {
  1137. foreach($_SESSION['remote'] as $visitor) {
  1138. if($visitor['uid'] == $user[0]['uid']) {
  1139. $r = q("SELECT `profile-id` FROM `contact` WHERE `id` = %d LIMIT 1",
  1140. intval($visitor['cid'])
  1141. );
  1142. if(count($r))
  1143. $profile = $r[0]['profile-id'];
  1144. break;
  1145. }
  1146. }
  1147. }
  1148. $r = null;
  1149. if($profile) {
  1150. $profile_int = intval($profile);
  1151. $r = q("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `contact`.`avatar-date` AS picdate, `user`.* FROM `profile`
  1152. INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` INNER JOIN `user` ON `profile`.`uid` = `user`.`uid`
  1153. WHERE `user`.`nickname` = '%s' AND `profile`.`id` = %d and `contact`.`self` = 1 LIMIT 1",
  1154. dbesc($nickname),
  1155. intval($profile_int)
  1156. );
  1157. }
  1158. if((!$r) && (!count($r))) {
  1159. $r = q("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `contact`.`avatar-date` AS picdate, `user`.* FROM `profile`
  1160. INNER JOIN `contact` on `contact`.`uid` = `profile`.`uid` INNER JOIN `user` ON `profile`.`uid` = `user`.`uid`
  1161. WHERE `user`.`nickname` = '%s' AND `profile`.`is-default` = 1 and `contact`.`self` = 1 LIMIT 1",
  1162. dbesc($nickname)
  1163. );
  1164. }
  1165. if(($r === false) || (!count($r)) && !count($profiledata)) {
  1166. logger('profile error: ' . $a->query_string, LOGGER_DEBUG);
  1167. notice( t('Requested profile is not available.') . EOL );
  1168. $a->error = 404;
  1169. return;
  1170. }
  1171. // fetch user tags if this isn't the default profile
  1172. if(!$r[0]['is-default']) {
  1173. $x = q("select `pub_keywords` from `profile` where uid = %d and `is-default` = 1 limit 1",
  1174. intval($r[0]['profile_uid'])
  1175. );
  1176. if($x && count($x))
  1177. $r[0]['pub_keywords'] = $x[0]['pub_keywords'];
  1178. }
  1179. $a->profile = $r[0];
  1180. $a->profile['mobile-theme'] = get_pconfig($a->profile['profile_uid'], 'system', 'mobile_theme');
  1181. $a->profile['network'] = NETWORK_DFRN;
  1182. $a->page['title'] = $a->profile['name'] . " @ " . $a->config['sitename'];
  1183. if (!$profiledata)
  1184. $_SESSION['theme'] = $a->profile['theme'];
  1185. $_SESSION['mobile-theme'] = $a->profile['mobile-theme'];
  1186. /**
  1187. * load/reload current theme info
  1188. */
  1189. $a->set_template_engine(); // reset the template engine to the default in case the user's theme doesn't specify one
  1190. $theme_info_file = "view/theme/".current_theme()."/theme.php";
  1191. if (file_exists($theme_info_file)){
  1192. require_once($theme_info_file);
  1193. }
  1194. if(! (x($a->page,'aside')))
  1195. $a->page['aside'] = '';
  1196. if(local_user() && local_user() == $a->profile['uid'] && $profiledata) {
  1197. $a->page['aside'] .= replace_macros(get_markup_template('profile_edlink.tpl'),array(
  1198. '$editprofile' => t('Edit profile'),
  1199. '$profid' => $a->profile['id']
  1200. ));
  1201. }
  1202. $block = (((get_config('system','block_public')) && (! local_user()) && (! remote_user())) ? true : false);
  1203. // To-Do:
  1204. // By now, the contact block isn't shown, when a different profile is given
  1205. // But: When this profile was on the same server, then we could display the contacts
  1206. if ($profiledata)
  1207. $a->page['aside'] .= profile_sidebar($profiledata, true);
  1208. else
  1209. $a->page['aside'] .= profile_sidebar($a->profile, $block);
  1210. /*if(! $block)
  1211. $a->page['aside'] .= contact_block();*/
  1212. return;
  1213. }
  1214. }
  1215. /**
  1216. *
  1217. * Function: profile_sidebar
  1218. *
  1219. * Formats a profile for display in the sidebar.
  1220. * It is very difficult to templatise the HTML completely
  1221. * because of all the conditional logic.
  1222. *
  1223. * @parameter: array $profile
  1224. *
  1225. * Returns HTML string stuitable for sidebar inclusion
  1226. * Exceptions: Returns empty string if passed $profile is wrong type or not populated
  1227. *
  1228. */
  1229. if(! function_exists('profile_sidebar')) {
  1230. function profile_sidebar($profile, $block = 0) {
  1231. $a = get_app();
  1232. $o = '';
  1233. $location = false;
  1234. $address = false;
  1235. $pdesc = true;
  1236. if((! is_array($profile)) && (! count($profile)))
  1237. return $o;
  1238. $profile['picdate'] = urlencode($profile['picdate']);
  1239. if (($profile['network'] != "") AND ($profile['network'] != NETWORK_DFRN)) {
  1240. require_once('include/contact_selectors.php');
  1241. if ($profile['url'] != "")
  1242. $profile['network_name'] = '<a href="'.$profile['url'].'">'.network_to_name($profile['network'])."</a>";
  1243. else
  1244. $profile['network_name'] = network_to_name($profile['network']);
  1245. } else
  1246. $profile['network_name'] = "";
  1247. call_hooks('profile_sidebar_enter', $profile);
  1248. // don't show connect link to yourself