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.

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