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.

1683 lines
44 KiB

11 years ago
11 years ago
6 years ago
11 years ago
10 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
10 years ago
10 years ago
9 years ago
11 years ago
10 years ago
11 years ago
11 years ago
10 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
9 years ago
11 years ago
11 years ago
6 years ago
10 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
9 years ago
9 years ago
11 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. <?php
  2. /** @file boot.php
  3. *
  4. * This file defines some global constants and includes the central App class.
  5. */
  6. /**
  7. * Friendica
  8. *
  9. * Friendica is a communications platform for integrated social communications
  10. * utilising decentralised communications and linkage to several indie social
  11. * projects - as well as popular mainstream providers.
  12. *
  13. * Our mission is to free our friends and families from the clutches of
  14. * data-harvesting corporations, and pave the way to a future where social
  15. * communications are free and open and flow between alternate providers as
  16. * easily as email does today.
  17. */
  18. require_once(__DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php');
  19. use Friendica\App;
  20. use Friendica\Core\Config;
  21. use Friendica\Util\Lock;
  22. require_once 'include/config.php';
  23. require_once 'include/network.php';
  24. require_once 'include/plugin.php';
  25. require_once 'include/text.php';
  26. require_once 'include/datetime.php';
  27. require_once 'include/pgettext.php';
  28. require_once 'include/nav.php';
  29. require_once 'include/cache.php';
  30. require_once 'include/features.php';
  31. require_once 'include/identity.php';
  32. require_once 'update.php';
  33. require_once 'include/dbstructure.php';
  34. require_once 'include/poller.php';
  35. define ( 'FRIENDICA_PLATFORM', 'Friendica');
  36. define ( 'FRIENDICA_CODENAME', 'Asparagus');
  37. define ( 'FRIENDICA_VERSION', '3.5.3-dev' );
  38. define ( 'DFRN_PROTOCOL_VERSION', '2.23' );
  39. define ( 'DB_UPDATE_VERSION', 1233 );
  40. /**
  41. * @brief Constant with a HTML line break.
  42. *
  43. * Contains a HTML line break (br) element and a real carriage return with line
  44. * feed for the source.
  45. * This can be used in HTML and JavaScript where needed a line break.
  46. */
  47. define ( 'EOL', "<br />\r\n" );
  48. define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' );
  49. /**
  50. * @brief Image storage quality.
  51. *
  52. * Lower numbers save space at cost of image detail.
  53. * For ease of upgrade, please do not change here. Change jpeg quality with
  54. * $a->config['system']['jpeg_quality'] = n;
  55. * in .htconfig.php, where n is netween 1 and 100, and with very poor results
  56. * below about 50
  57. *
  58. */
  59. define ( 'JPEG_QUALITY', 100 );
  60. /**
  61. * $a->config['system']['png_quality'] from 0 (uncompressed) to 9
  62. */
  63. define ( 'PNG_QUALITY', 8 );
  64. /**
  65. *
  66. * An alternate way of limiting picture upload sizes. Specify the maximum pixel
  67. * length that pictures are allowed to be (for non-square pictures, it will apply
  68. * to the longest side). Pictures longer than this length will be resized to be
  69. * this length (on the longest side, the other side will be scaled appropriately).
  70. * Modify this value using
  71. *
  72. * $a->config['system']['max_image_length'] = n;
  73. *
  74. * in .htconfig.php
  75. *
  76. * If you don't want to set a maximum length, set to -1. The default value is
  77. * defined by 'MAX_IMAGE_LENGTH' below.
  78. *
  79. */
  80. define ( 'MAX_IMAGE_LENGTH', -1 );
  81. /**
  82. * Not yet used
  83. */
  84. define ( 'DEFAULT_DB_ENGINE', 'InnoDB' );
  85. /**
  86. * @name SSL Policy
  87. *
  88. * SSL redirection policies
  89. * @{
  90. */
  91. define ( 'SSL_POLICY_NONE', 0 );
  92. define ( 'SSL_POLICY_FULL', 1 );
  93. define ( 'SSL_POLICY_SELFSIGN', 2 );
  94. /* @}*/
  95. /**
  96. * @name Logger
  97. *
  98. * log levels
  99. * @{
  100. */
  101. define ( 'LOGGER_NORMAL', 0 );
  102. define ( 'LOGGER_TRACE', 1 );
  103. define ( 'LOGGER_DEBUG', 2 );
  104. define ( 'LOGGER_DATA', 3 );
  105. define ( 'LOGGER_ALL', 4 );
  106. /* @}*/
  107. /**
  108. * @name Cache
  109. *
  110. * Cache levels
  111. * @{
  112. */
  113. define ( 'CACHE_MONTH', 0 );
  114. define ( 'CACHE_WEEK', 1 );
  115. define ( 'CACHE_DAY', 2 );
  116. define ( 'CACHE_HOUR', 3 );
  117. define ( 'CACHE_HALF_HOUR', 4 );
  118. define ( 'CACHE_QUARTER_HOUR', 5 );
  119. define ( 'CACHE_FIVE_MINUTES', 6 );
  120. define ( 'CACHE_MINUTE', 7 );
  121. /* @}*/
  122. /**
  123. * @name Register
  124. *
  125. * Registration policies
  126. * @{
  127. */
  128. define ( 'REGISTER_CLOSED', 0 );
  129. define ( 'REGISTER_APPROVE', 1 );
  130. define ( 'REGISTER_OPEN', 2 );
  131. /** @}*/
  132. /**
  133. * @name Contact_is
  134. *
  135. * Relationship types
  136. * @{
  137. */
  138. define ( 'CONTACT_IS_FOLLOWER', 1);
  139. define ( 'CONTACT_IS_SHARING', 2);
  140. define ( 'CONTACT_IS_FRIEND', 3);
  141. /** @}*/
  142. /**
  143. * @name Update
  144. *
  145. * DB update return values
  146. * @{
  147. */
  148. define ( 'UPDATE_SUCCESS', 0);
  149. define ( 'UPDATE_FAILED', 1);
  150. /** @}*/
  151. /**
  152. * @name page/profile types
  153. *
  154. * PAGE_NORMAL is a typical personal profile account
  155. * PAGE_SOAPBOX automatically approves all friend requests as CONTACT_IS_SHARING, (readonly)
  156. * PAGE_COMMUNITY automatically approves all friend requests as CONTACT_IS_SHARING, but with
  157. * write access to wall and comments (no email and not included in page owner's ACL lists)
  158. * PAGE_FREELOVE automatically approves all friend requests as full friends (CONTACT_IS_FRIEND).
  159. *
  160. * @{
  161. */
  162. define ( 'PAGE_NORMAL', 0 );
  163. define ( 'PAGE_SOAPBOX', 1 );
  164. define ( 'PAGE_COMMUNITY', 2 );
  165. define ( 'PAGE_FREELOVE', 3 );
  166. define ( 'PAGE_BLOG', 4 );
  167. define ( 'PAGE_PRVGROUP', 5 );
  168. /** @}*/
  169. /**
  170. * @name account types
  171. *
  172. * ACCOUNT_TYPE_PERSON - the account belongs to a person
  173. * Associated page types: PAGE_NORMAL, PAGE_SOAPBOX, PAGE_FREELOVE
  174. *
  175. * ACCOUNT_TYPE_ORGANISATION - the account belongs to an organisation
  176. * Associated page type: PAGE_SOAPBOX
  177. *
  178. * ACCOUNT_TYPE_NEWS - the account is a news reflector
  179. * Associated page type: PAGE_SOAPBOX
  180. *
  181. * ACCOUNT_TYPE_COMMUNITY - the account is community forum
  182. * Associated page types: PAGE_COMMUNITY, PAGE_PRVGROUP
  183. * @{
  184. */
  185. define ( 'ACCOUNT_TYPE_PERSON', 0 );
  186. define ( 'ACCOUNT_TYPE_ORGANISATION',1 );
  187. define ( 'ACCOUNT_TYPE_NEWS', 2 );
  188. define ( 'ACCOUNT_TYPE_COMMUNITY', 3 );
  189. /** @}*/
  190. /**
  191. * @name CP
  192. *
  193. * Type of the community page
  194. * @{
  195. */
  196. define ( 'CP_NO_COMMUNITY_PAGE', -1 );
  197. define ( 'CP_USERS_ON_SERVER', 0 );
  198. define ( 'CP_GLOBAL_COMMUNITY', 1 );
  199. /** @}*/
  200. /**
  201. * @name Protocols
  202. *
  203. * Different protocols that we are storing
  204. * @{
  205. */
  206. define('PROTOCOL_UNKNOWN', 0);
  207. define('PROTOCOL_DFRN', 1);
  208. define('PROTOCOL_DIASPORA', 2);
  209. define('PROTOCOL_OSTATUS_SALMON', 3);
  210. define('PROTOCOL_OSTATUS_FEED', 4);
  211. define('PROTOCOL_GS_CONVERSATION', 5);
  212. /** @}*/
  213. /**
  214. * @name Network
  215. *
  216. * Network and protocol family types
  217. * @{
  218. */
  219. define ( 'NETWORK_DFRN', 'dfrn'); // Friendica, Mistpark, other DFRN implementations
  220. define ( 'NETWORK_ZOT', 'zot!'); // Zot!
  221. define ( 'NETWORK_OSTATUS', 'stat'); // status.net, identi.ca, GNU-social, other OStatus implementations
  222. define ( 'NETWORK_FEED', 'feed'); // RSS/Atom feeds with no known "post/notify" protocol
  223. define ( 'NETWORK_DIASPORA', 'dspr'); // Diaspora
  224. define ( 'NETWORK_MAIL', 'mail'); // IMAP/POP
  225. define ( 'NETWORK_MAIL2', 'mai2'); // extended IMAP/POP
  226. define ( 'NETWORK_FACEBOOK', 'face'); // Facebook API
  227. define ( 'NETWORK_LINKEDIN', 'lnkd'); // LinkedIn
  228. define ( 'NETWORK_XMPP', 'xmpp'); // XMPP
  229. define ( 'NETWORK_MYSPACE', 'mysp'); // MySpace
  230. define ( 'NETWORK_GPLUS', 'goog'); // Google+
  231. define ( 'NETWORK_PUMPIO', 'pump'); // pump.io
  232. define ( 'NETWORK_TWITTER', 'twit'); // Twitter
  233. define ( 'NETWORK_DIASPORA2', 'dspc'); // Diaspora connector
  234. define ( 'NETWORK_STATUSNET', 'stac'); // Statusnet connector
  235. define ( 'NETWORK_APPNET', 'apdn'); // app.net
  236. define ( 'NETWORK_NEWS', 'nntp'); // Network News Transfer Protocol
  237. define ( 'NETWORK_ICALENDAR', 'ical'); // iCalendar
  238. define ( 'NETWORK_PNUT', 'pnut'); // pnut.io
  239. define ( 'NETWORK_PHANTOM', 'unkn'); // Place holder
  240. /** @}*/
  241. /**
  242. * These numbers are used in stored permissions
  243. * and existing allocations MUST NEVER BE CHANGED
  244. * OR RE-ASSIGNED! You may only add to them.
  245. */
  246. $netgroup_ids = array(
  247. NETWORK_DFRN => (-1),
  248. NETWORK_ZOT => (-2),
  249. NETWORK_OSTATUS => (-3),
  250. NETWORK_FEED => (-4),
  251. NETWORK_DIASPORA => (-5),
  252. NETWORK_MAIL => (-6),
  253. NETWORK_MAIL2 => (-7),
  254. NETWORK_FACEBOOK => (-8),
  255. NETWORK_LINKEDIN => (-9),
  256. NETWORK_XMPP => (-10),
  257. NETWORK_MYSPACE => (-11),
  258. NETWORK_GPLUS => (-12),
  259. NETWORK_PUMPIO => (-13),
  260. NETWORK_TWITTER => (-14),
  261. NETWORK_DIASPORA2 => (-15),
  262. NETWORK_STATUSNET => (-16),
  263. NETWORK_APPNET => (-17),
  264. NETWORK_NEWS => (-18),
  265. NETWORK_ICALENDAR => (-19),
  266. NETWORK_PNUT => (-20),
  267. NETWORK_PHANTOM => (-127),
  268. );
  269. /**
  270. * Maximum number of "people who like (or don't like) this" that we will list by name
  271. */
  272. define ( 'MAX_LIKERS', 75);
  273. /**
  274. * Communication timeout
  275. */
  276. define ( 'ZCURL_TIMEOUT' , (-1));
  277. /**
  278. * @name Notify
  279. *
  280. * Email notification options
  281. * @{
  282. */
  283. define ( 'NOTIFY_INTRO', 0x0001 );
  284. define ( 'NOTIFY_CONFIRM', 0x0002 );
  285. define ( 'NOTIFY_WALL', 0x0004 );
  286. define ( 'NOTIFY_COMMENT', 0x0008 );
  287. define ( 'NOTIFY_MAIL', 0x0010 );
  288. define ( 'NOTIFY_SUGGEST', 0x0020 );
  289. define ( 'NOTIFY_PROFILE', 0x0040 );
  290. define ( 'NOTIFY_TAGSELF', 0x0080 );
  291. define ( 'NOTIFY_TAGSHARE', 0x0100 );
  292. define ( 'NOTIFY_POKE', 0x0200 );
  293. define ( 'NOTIFY_SHARE', 0x0400 );
  294. define ( 'NOTIFY_SYSTEM', 0x8000 );
  295. /* @}*/
  296. /**
  297. * @name Term
  298. *
  299. * Tag/term types
  300. * @{
  301. */
  302. define ( 'TERM_UNKNOWN', 0 );
  303. define ( 'TERM_HASHTAG', 1 );
  304. define ( 'TERM_MENTION', 2 );
  305. define ( 'TERM_CATEGORY', 3 );
  306. define ( 'TERM_PCATEGORY', 4 );
  307. define ( 'TERM_FILE', 5 );
  308. define ( 'TERM_SAVEDSEARCH', 6 );
  309. define ( 'TERM_CONVERSATION', 7 );
  310. define ( 'TERM_OBJ_POST', 1 );
  311. define ( 'TERM_OBJ_PHOTO', 2 );
  312. /**
  313. * @name Namespaces
  314. *
  315. * Various namespaces we may need to parse
  316. * @{
  317. */
  318. define ( 'NAMESPACE_ZOT', 'http://purl.org/zot' );
  319. define ( 'NAMESPACE_DFRN' , 'http://purl.org/macgirvin/dfrn/1.0' );
  320. define ( 'NAMESPACE_THREAD' , 'http://purl.org/syndication/thread/1.0' );
  321. define ( 'NAMESPACE_TOMB' , 'http://purl.org/atompub/tombstones/1.0' );
  322. define ( 'NAMESPACE_ACTIVITY', 'http://activitystrea.ms/spec/1.0/' );
  323. define ( 'NAMESPACE_ACTIVITY_SCHEMA', 'http://activitystrea.ms/schema/1.0/' );
  324. define ( 'NAMESPACE_MEDIA', 'http://purl.org/syndication/atommedia' );
  325. define ( 'NAMESPACE_SALMON_ME', 'http://salmon-protocol.org/ns/magic-env' );
  326. define ( 'NAMESPACE_OSTATUSSUB', 'http://ostatus.org/schema/1.0/subscribe' );
  327. define ( 'NAMESPACE_GEORSS', 'http://www.georss.org/georss' );
  328. define ( 'NAMESPACE_POCO', 'http://portablecontacts.net/spec/1.0' );
  329. define ( 'NAMESPACE_FEED', 'http://schemas.google.com/g/2010#updates-from' );
  330. define ( 'NAMESPACE_OSTATUS', 'http://ostatus.org/schema/1.0' );
  331. define ( 'NAMESPACE_STATUSNET', 'http://status.net/schema/api/1/' );
  332. define ( 'NAMESPACE_ATOM1', 'http://www.w3.org/2005/Atom' );
  333. define ( 'NAMESPACE_MASTODON', 'http://mastodon.social/schema/1.0' );
  334. /* @}*/
  335. /**
  336. * @name Activity
  337. *
  338. * Activity stream defines
  339. * @{
  340. */
  341. define ( 'ACTIVITY_LIKE', NAMESPACE_ACTIVITY_SCHEMA . 'like' );
  342. define ( 'ACTIVITY_DISLIKE', NAMESPACE_DFRN . '/dislike' );
  343. define ( 'ACTIVITY_ATTEND', NAMESPACE_ZOT . '/activity/attendyes' );
  344. define ( 'ACTIVITY_ATTENDNO', NAMESPACE_ZOT . '/activity/attendno' );
  345. define ( 'ACTIVITY_ATTENDMAYBE', NAMESPACE_ZOT . '/activity/attendmaybe' );
  346. define ( 'ACTIVITY_OBJ_HEART', NAMESPACE_DFRN . '/heart' );
  347. define ( 'ACTIVITY_FRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'make-friend' );
  348. define ( 'ACTIVITY_REQ_FRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'request-friend' );
  349. define ( 'ACTIVITY_UNFRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'remove-friend' );
  350. define ( 'ACTIVITY_FOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'follow' );
  351. define ( 'ACTIVITY_UNFOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'stop-following' );
  352. define ( 'ACTIVITY_JOIN', NAMESPACE_ACTIVITY_SCHEMA . 'join' );
  353. define ( 'ACTIVITY_POST', NAMESPACE_ACTIVITY_SCHEMA . 'post' );
  354. define ( 'ACTIVITY_UPDATE', NAMESPACE_ACTIVITY_SCHEMA . 'update' );
  355. define ( 'ACTIVITY_TAG', NAMESPACE_ACTIVITY_SCHEMA . 'tag' );
  356. define ( 'ACTIVITY_FAVORITE', NAMESPACE_ACTIVITY_SCHEMA . 'favorite' );
  357. define ( 'ACTIVITY_SHARE', NAMESPACE_ACTIVITY_SCHEMA . 'share' );
  358. define ( 'ACTIVITY_DELETE', NAMESPACE_ACTIVITY_SCHEMA . 'delete' );
  359. define ( 'ACTIVITY_POKE', NAMESPACE_ZOT . '/activity/poke' );
  360. define ( 'ACTIVITY_MOOD', NAMESPACE_ZOT . '/activity/mood' );
  361. define ( 'ACTIVITY_OBJ_BOOKMARK', NAMESPACE_ACTIVITY_SCHEMA . 'bookmark' );
  362. define ( 'ACTIVITY_OBJ_COMMENT', NAMESPACE_ACTIVITY_SCHEMA . 'comment' );
  363. define ( 'ACTIVITY_OBJ_NOTE', NAMESPACE_ACTIVITY_SCHEMA . 'note' );
  364. define ( 'ACTIVITY_OBJ_PERSON', NAMESPACE_ACTIVITY_SCHEMA . 'person' );
  365. define ( 'ACTIVITY_OBJ_IMAGE', NAMESPACE_ACTIVITY_SCHEMA . 'image' );
  366. define ( 'ACTIVITY_OBJ_PHOTO', NAMESPACE_ACTIVITY_SCHEMA . 'photo' );
  367. define ( 'ACTIVITY_OBJ_VIDEO', NAMESPACE_ACTIVITY_SCHEMA . 'video' );
  368. define ( 'ACTIVITY_OBJ_P_PHOTO', NAMESPACE_ACTIVITY_SCHEMA . 'profile-photo' );
  369. define ( 'ACTIVITY_OBJ_ALBUM', NAMESPACE_ACTIVITY_SCHEMA . 'photo-album' );
  370. define ( 'ACTIVITY_OBJ_EVENT', NAMESPACE_ACTIVITY_SCHEMA . 'event' );
  371. define ( 'ACTIVITY_OBJ_GROUP', NAMESPACE_ACTIVITY_SCHEMA . 'group' );
  372. define ( 'ACTIVITY_OBJ_TAGTERM', NAMESPACE_DFRN . '/tagterm' );
  373. define ( 'ACTIVITY_OBJ_PROFILE', NAMESPACE_DFRN . '/profile' );
  374. define ( 'ACTIVITY_OBJ_QUESTION', 'http://activityschema.org/object/question' );
  375. /* @}*/
  376. /**
  377. * @name Gravity
  378. *
  379. * Item weight for query ordering
  380. * @{
  381. */
  382. define ( 'GRAVITY_PARENT', 0);
  383. define ( 'GRAVITY_LIKE', 3);
  384. define ( 'GRAVITY_COMMENT', 6);
  385. /* @}*/
  386. /**
  387. * @name Priority
  388. *
  389. * Process priority for the worker
  390. * @{
  391. */
  392. define('PRIORITY_UNDEFINED', 0);
  393. define('PRIORITY_CRITICAL', 10);
  394. define('PRIORITY_HIGH', 20);
  395. define('PRIORITY_MEDIUM', 30);
  396. define('PRIORITY_LOW', 40);
  397. define('PRIORITY_NEGLIGIBLE',50);
  398. /* @}*/
  399. /**
  400. * @name Social Relay settings
  401. *
  402. * See here: https://github.com/jaywink/social-relay
  403. * and here: https://wiki.diasporafoundation.org/Relay_servers_for_public_posts
  404. * @{
  405. */
  406. define('SR_SCOPE_NONE', '');
  407. define('SR_SCOPE_ALL', 'all');
  408. define('SR_SCOPE_TAGS', 'tags');
  409. /* @}*/
  410. /**
  411. * Lowest possible date time value
  412. */
  413. define ('NULL_DATE', '0001-01-01 00:00:00');
  414. // Normally this constant is defined - but not if "pcntl" isn't installed
  415. if (!defined("SIGTERM")) {
  416. define("SIGTERM", 15);
  417. }
  418. /**
  419. * Depending on the PHP version this constant does exist - or not.
  420. * See here: http://php.net/manual/en/curl.constants.php#117928
  421. */
  422. if (!defined('CURLE_OPERATION_TIMEDOUT')) {
  423. define('CURLE_OPERATION_TIMEDOUT', CURLE_OPERATION_TIMEOUTED);
  424. }
  425. /**
  426. *
  427. * Reverse the effect of magic_quotes_gpc if it is enabled.
  428. * Please disable magic_quotes_gpc so we don't have to do this.
  429. * See http://php.net/manual/en/security.magicquotes.disabling.php
  430. *
  431. */
  432. function startup() {
  433. error_reporting(E_ERROR | E_WARNING | E_PARSE);
  434. set_time_limit(0);
  435. // This has to be quite large to deal with embedded private photos
  436. ini_set('pcre.backtrack_limit', 500000);
  437. if (get_magic_quotes_gpc()) {
  438. $process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
  439. while (list($key, $val) = each($process)) {
  440. foreach ($val as $k => $v) {
  441. unset($process[$key][$k]);
  442. if (is_array($v)) {
  443. $process[$key][stripslashes($k)] = $v;
  444. $process[] = &$process[$key][stripslashes($k)];
  445. } else {
  446. $process[$key][stripslashes($k)] = stripslashes($v);
  447. }
  448. }
  449. }
  450. unset($process);
  451. }
  452. }
  453. /**
  454. * @brief Retrieve the App structure
  455. *
  456. * Useful in functions which require it but don't get it passed to them
  457. */
  458. function get_app() {
  459. global $a;
  460. return $a;
  461. }
  462. /**
  463. * @brief Multi-purpose function to check variable state.
  464. *
  465. * Usage: x($var) or $x($array, 'key')
  466. *
  467. * returns false if variable/key is not set
  468. * if variable is set, returns 1 if has 'non-zero' value, otherwise returns 0.
  469. * e.g. x('') or x(0) returns 0;
  470. *
  471. * @param string|array $s variable to check
  472. * @param string $k key inside the array to check
  473. *
  474. * @return bool|int
  475. */
  476. function x($s, $k = NULL) {
  477. if ($k != NULL) {
  478. if ((is_array($s)) && (array_key_exists($k, $s))) {
  479. if ($s[$k]) {
  480. return (int) 1;
  481. }
  482. return (int) 0;
  483. }
  484. return false;
  485. } else {
  486. if (isset($s)) {
  487. if ($s) {
  488. return (int) 1;
  489. }
  490. return (int) 0;
  491. }
  492. return false;
  493. }
  494. }
  495. /**
  496. * @brief Called from db initialisation if db is dead.
  497. */
  498. function system_unavailable() {
  499. include('system_unavailable.php');
  500. system_down();
  501. killme();
  502. }
  503. function clean_urls() {
  504. $a = get_app();
  505. return true;
  506. }
  507. function z_path() {
  508. $base = App::get_baseurl();
  509. if (!clean_urls()) {
  510. $base .= '/?q=';
  511. }
  512. return $base;
  513. }
  514. /**
  515. * @brief Returns the baseurl.
  516. *
  517. * @see App::get_baseurl()
  518. *
  519. * @return string
  520. * @TODO Maybe super-flous and deprecated? Seems to only wrap App::get_baseurl()
  521. */
  522. function z_root() {
  523. return App::get_baseurl();
  524. }
  525. /**
  526. * @brief Return absolut URL for given $path.
  527. *
  528. * @param string $path
  529. *
  530. * @return string
  531. */
  532. function absurl($path) {
  533. if (strpos($path, '/') === 0) {
  534. return z_path() . $path;
  535. }
  536. return $path;
  537. }
  538. /**
  539. * @brief Function to check if request was an AJAX (xmlhttprequest) request.
  540. *
  541. * @return boolean
  542. */
  543. function is_ajax() {
  544. return (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
  545. }
  546. function check_db() {
  547. $build = get_config('system', 'build');
  548. if (!x($build)) {
  549. set_config('system', 'build', DB_UPDATE_VERSION);
  550. $build = DB_UPDATE_VERSION;
  551. }
  552. if ($build != DB_UPDATE_VERSION) {
  553. proc_run(PRIORITY_CRITICAL, 'include/dbupdate.php');
  554. }
  555. }
  556. /**
  557. * Sets the base url for use in cmdline programs which don't have
  558. * $_SERVER variables
  559. */
  560. function check_url(App $a) {
  561. $url = get_config('system', 'url');
  562. // if the url isn't set or the stored url is radically different
  563. // than the currently visited url, store the current value accordingly.
  564. // "Radically different" ignores common variations such as http vs https
  565. // and www.example.com vs example.com.
  566. // We will only change the url to an ip address if there is no existing setting
  567. if (!x($url)) {
  568. $url = set_config('system', 'url', App::get_baseurl());
  569. }
  570. if ((!link_compare($url, App::get_baseurl())) && (!preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $a->get_hostname))) {
  571. $url = set_config('system', 'url', App::get_baseurl());
  572. }
  573. return;
  574. }
  575. /**
  576. * @brief Automatic database updates
  577. */
  578. function update_db(App $a) {
  579. $build = get_config('system', 'build');
  580. if (!x($build)) {
  581. $build = set_config('system', 'build', DB_UPDATE_VERSION);
  582. }
  583. if ($build != DB_UPDATE_VERSION) {
  584. $stored = intval($build);
  585. $current = intval(DB_UPDATE_VERSION);
  586. if ($stored < $current) {
  587. Config::load('database');
  588. // We're reporting a different version than what is currently installed.
  589. // Run any existing update scripts to bring the database up to current.
  590. // make sure that boot.php and update.php are the same release, we might be
  591. // updating right this very second and the correct version of the update.php
  592. // file may not be here yet. This can happen on a very busy site.
  593. if (DB_UPDATE_VERSION == UPDATE_VERSION) {
  594. // Compare the current structure with the defined structure
  595. $t = get_config('database', 'dbupdate_' . DB_UPDATE_VERSION);
  596. if ($t !== false) {
  597. return;
  598. }
  599. set_config('database', 'dbupdate_' . DB_UPDATE_VERSION, time());
  600. // run old update routine (wich could modify the schema and
  601. // conflits with new routine)
  602. for ($x = $stored; $x < NEW_UPDATE_ROUTINE_VERSION; $x++) {
  603. $r = run_update_function($x);
  604. if (!$r) {
  605. break;
  606. }
  607. }
  608. if ($stored < NEW_UPDATE_ROUTINE_VERSION) {
  609. $stored = NEW_UPDATE_ROUTINE_VERSION;
  610. }
  611. // run new update routine
  612. // it update the structure in one call
  613. $retval = update_structure(false, true);
  614. if ($retval) {
  615. update_fail(
  616. DB_UPDATE_VERSION,
  617. $retval
  618. );
  619. return;
  620. } else {
  621. set_config('database', 'dbupdate_' . DB_UPDATE_VERSION, 'success');
  622. }
  623. // run any left update_nnnn functions in update.php
  624. for ($x = $stored; $x < $current; $x ++) {
  625. $r = run_update_function($x);
  626. if (!$r) {
  627. break;
  628. }
  629. }
  630. }
  631. }
  632. }
  633. return;
  634. }
  635. function run_update_function($x) {
  636. if (function_exists('update_' . $x)) {
  637. // There could be a lot of processes running or about to run.
  638. // We want exactly one process to run the update command.
  639. // So store the fact that we're taking responsibility
  640. // after first checking to see if somebody else already has.
  641. // If the update fails or times-out completely you may need to
  642. // delete the config entry to try again.
  643. $t = get_config('database', 'update_' . $x);
  644. if ($t !== false) {
  645. return false;
  646. }
  647. set_config('database', 'update_' . $x, time());
  648. // call the specific update
  649. $func = 'update_' . $x;
  650. $retval = $func();
  651. if ($retval) {
  652. //send the administrator an e-mail
  653. update_fail(
  654. $x,
  655. sprintf(t('Update %s failed. See error logs.'), $x)
  656. );
  657. return false;
  658. } else {
  659. set_config('database', 'update_' . $x, 'success');
  660. set_config('system', 'build', $x + 1);
  661. return true;
  662. }
  663. } else {
  664. set_config('database', 'update_' . $x, 'success');
  665. set_config('system', 'build', $x + 1);
  666. return true;
  667. }
  668. return true;
  669. }
  670. /**
  671. * @brief Synchronise plugins:
  672. *
  673. * $a->config['system']['addon'] contains a comma-separated list of names
  674. * of plugins/addons which are used on this system.
  675. * Go through the database list of already installed addons, and if we have
  676. * an entry, but it isn't in the config list, call the uninstall procedure
  677. * and mark it uninstalled in the database (for now we'll remove it).
  678. * Then go through the config list and if we have a plugin that isn't installed,
  679. * call the install procedure and add it to the database.
  680. *
  681. * @param App $a
  682. *
  683. */
  684. function check_plugins(App $a) {
  685. $r = q("SELECT * FROM `addon` WHERE `installed` = 1");
  686. if (dbm::is_result($r)) {
  687. $installed = $r;
  688. } else {
  689. $installed = array();
  690. }
  691. $plugins = get_config('system', 'addon');
  692. $plugins_arr = array();
  693. if ($plugins) {
  694. $plugins_arr = explode(',', str_replace(' ', '', $plugins));
  695. }
  696. $a->plugins = $plugins_arr;
  697. $installed_arr = array();
  698. if (count($installed)) {
  699. foreach ($installed as $i) {
  700. if (!in_array($i['name'], $plugins_arr)) {
  701. uninstall_plugin($i['name']);
  702. } else {
  703. $installed_arr[] = $i['name'];
  704. }
  705. }
  706. }
  707. if (count($plugins_arr)) {
  708. foreach ($plugins_arr as $p) {
  709. if (!in_array($p, $installed_arr)) {
  710. install_plugin($p);
  711. }
  712. }
  713. }
  714. load_hooks();
  715. return;
  716. }
  717. function get_guid($size = 16, $prefix = "") {
  718. if ($prefix == "") {
  719. $a = get_app();
  720. $prefix = hash("crc32", $a->get_hostname());
  721. }
  722. while (strlen($prefix) < ($size - 13)) {
  723. $prefix .= mt_rand();
  724. }
  725. if ($size >= 24) {
  726. $prefix = substr($prefix, 0, $size - 22);
  727. return(str_replace(".", "", uniqid($prefix, true)));
  728. } else {
  729. $prefix = substr($prefix, 0, max($size - 13, 0));
  730. return(uniqid($prefix));
  731. }
  732. }
  733. /**
  734. * @brief Wrapper for adding a login box.
  735. *
  736. * @param bool $register
  737. * If $register == true provide a registration link.
  738. * This will most always depend on the value of $a->config['register_policy'].
  739. * @param bool $hiddens
  740. *
  741. * @return string
  742. * Returns the complete html for inserting into the page
  743. *
  744. * @hooks 'login_hook'
  745. * string $o
  746. */
  747. function login($register = false, $hiddens = false) {
  748. $a = get_app();
  749. $o = "";
  750. $reg = false;
  751. if ($register) {
  752. $reg = array(
  753. 'title' => t('Create a New Account'),
  754. 'desc' => t('Register')
  755. );
  756. }
  757. $noid = get_config('system', 'no_openid');
  758. $dest_url = $a->query_string;
  759. if (local_user()) {
  760. $tpl = get_markup_template("logout.tpl");
  761. } else {
  762. $a->page['htmlhead'] .= replace_macros(get_markup_template("login_head.tpl"), array(
  763. '$baseurl' => $a->get_baseurl(true)
  764. ));
  765. $tpl = get_markup_template("login.tpl");
  766. $_SESSION['return_url'] = $a->query_string;
  767. $a->module = 'login';
  768. }
  769. $o .= replace_macros($tpl, array(
  770. '$dest_url' => $dest_url,
  771. '$logout' => t('Logout'),
  772. '$login' => t('Login'),
  773. '$lname' => array('username', t('Nickname or Email: ') , '', ''),
  774. '$lpassword' => array('password', t('Password: '), '', ''),
  775. '$lremember' => array('remember', t('Remember me'), 0, ''),
  776. '$openid' => !$noid,
  777. '$lopenid' => array('openid_url', t('Or login using OpenID: '),'',''),
  778. '$hiddens' => $hiddens,
  779. '$register' => $reg,
  780. '$lostpass' => t('Forgot your password?'),
  781. '$lostlink' => t('Password Reset'),
  782. '$tostitle' => t('Website Terms of Service'),
  783. '$toslink' => t('terms of service'),
  784. '$privacytitle' => t('Website Privacy Policy'),
  785. '$privacylink' => t('privacy policy'),
  786. ));
  787. call_hooks('login_hook', $o);
  788. return $o;
  789. }
  790. /**
  791. * @brief Used to end the current process, after saving session state.
  792. */
  793. function killme() {
  794. if (!get_app()->is_backend()) {
  795. session_write_close();
  796. }
  797. exit();
  798. }
  799. /**
  800. * @brief Redirect to another URL and terminate this process.
  801. */
  802. function goaway($s) {
  803. if (!strstr(normalise_link($s), "http://")) {
  804. $s = App::get_baseurl() . "/" . $s;
  805. }
  806. header("Location: $s");
  807. killme();
  808. }
  809. /**
  810. * @brief Returns the user id of locally logged in user or false.
  811. *
  812. * @return int|bool user id or false
  813. */
  814. function local_user() {
  815. if (x($_SESSION, 'authenticated') && x($_SESSION, 'uid')) {
  816. return intval($_SESSION['uid']);
  817. }
  818. return false;
  819. }
  820. /**
  821. * @brief Returns the public contact id of logged in user or false.
  822. *
  823. * @return int|bool public contact id or false
  824. */
  825. function public_contact() {
  826. static $public_contact_id = false;
  827. if (!$public_contact_id && x($_SESSION, 'authenticated')) {
  828. if (x($_SESSION, 'my_address')) {
  829. // Local user
  830. $public_contact_id = intval(get_contact($_SESSION['my_address'], 0));
  831. } elseif (x($_SESSION, 'visitor_home')) {
  832. // Remote user
  833. $public_contact_id = intval(get_contact($_SESSION['visitor_home'], 0));
  834. }
  835. } elseif (!x($_SESSION, 'authenticated')) {
  836. $public_contact_id = false;
  837. }
  838. return $public_contact_id;
  839. }
  840. /**
  841. * @brief Returns contact id of authenticated site visitor or false
  842. *
  843. * @return int|bool visitor_id or false
  844. */
  845. function remote_user() {
  846. if ((x($_SESSION, 'authenticated')) && (x($_SESSION, 'visitor_id'))) {
  847. return intval($_SESSION['visitor_id']);
  848. }
  849. return false;
  850. }
  851. /**
  852. * @brief Show an error message to user.
  853. *
  854. * This function save text in session, to be shown to the user at next page load
  855. *
  856. * @param string $s - Text of notice
  857. */
  858. function notice($s) {
  859. $a = get_app();
  860. if (!x($_SESSION, 'sysmsg')) {
  861. $_SESSION['sysmsg'] = array();
  862. }
  863. if ($a->interactive) {
  864. $_SESSION['sysmsg'][] = $s;
  865. }
  866. }
  867. /**
  868. * @brief Show an info message to user.
  869. *
  870. * This function save text in session, to be shown to the user at next page load
  871. *
  872. * @param string $s - Text of notice
  873. */
  874. function info($s) {
  875. $a = get_app();
  876. if (local_user() && get_pconfig(local_user(), 'system', 'ignore_info')) {
  877. return;
  878. }
  879. if (!x($_SESSION, 'sysmsg_info')) {
  880. $_SESSION['sysmsg_info'] = array();
  881. }
  882. if ($a->interactive) {
  883. $_SESSION['sysmsg_info'][] = $s;
  884. }
  885. }
  886. /**
  887. * @brief Wrapper around config to limit the text length of an incoming message
  888. *
  889. * @return int
  890. */
  891. function get_max_import_size() {
  892. $a = get_app();
  893. return ((x($a->config, 'max_import_size')) ? $a->config['max_import_size'] : 0 );
  894. }
  895. /**
  896. * @brief Wrap calls to proc_close(proc_open()) and call hook
  897. * so plugins can take part in process :)
  898. *
  899. * @param (integer|array) priority or parameter array, $cmd atrings are deprecated and are ignored
  900. *
  901. * next args are passed as $cmd command line
  902. * or: proc_run(PRIORITY_HIGH, "include/notifier.php", "drop", $drop_id);
  903. * or: proc_run(array('priority' => PRIORITY_HIGH, 'dont_fork' => true), "include/create_shadowentry.php", $post_id);
  904. *
  905. * @note $cmd and string args are surrounded with ""
  906. *
  907. * @hooks 'proc_run'
  908. * array $arr
  909. */
  910. function proc_run($cmd) {
  911. $a = get_app();
  912. $proc_args = func_get_args();
  913. $args = array();
  914. if (!count($proc_args)) {
  915. return;
  916. }
  917. // Preserve the first parameter
  918. // It could contain a command, the priority or an parameter array
  919. // If we use the parameter array we have to protect it from the following function
  920. $run_parameter = array_shift($proc_args);
  921. // expand any arrays
  922. foreach ($proc_args as $arg) {
  923. if (is_array($arg)) {
  924. foreach ($arg as $n) {
  925. $args[] = $n;
  926. }
  927. } else {
  928. $args[] = $arg;
  929. }
  930. }
  931. // Now we add the run parameters back to the array
  932. array_unshift($args, $run_parameter);
  933. $arr = array('args' => $args, 'run_cmd' => true);
  934. call_hooks("proc_run", $arr);
  935. if (!$arr['run_cmd'] || ! count($args)) {
  936. return;
  937. }
  938. $priority = PRIORITY_MEDIUM;
  939. $dont_fork = get_config("system", "worker_dont_fork");
  940. $created = datetime_convert();
  941. if (is_int($run_parameter)) {
  942. $priority = $run_parameter;
  943. } elseif (is_array($run_parameter)) {
  944. if (isset($run_parameter['priority'])) {
  945. $priority = $run_parameter['priority'];
  946. }
  947. if (isset($run_parameter['created'])) {
  948. $created = $run_parameter['created'];
  949. }
  950. if (isset($run_parameter['dont_fork'])) {
  951. $dont_fork = $run_parameter['dont_fork'];
  952. }
  953. }
  954. $argv = $args;
  955. array_shift($argv);
  956. $parameters = json_encode($argv);
  957. $found = dba::exists('workerqueue', array('parameter' => $parameters, 'done' => false));
  958. if (!$found) {
  959. dba::insert('workerqueue', array('parameter' => $parameters, 'created' => $created, 'priority' => $priority));
  960. }
  961. // Should we quit and wait for the poller to be called as a cronjob?
  962. if ($dont_fork) {
  963. return;
  964. }
  965. // If there is a lock then we don't have to check for too much worker
  966. if (!Lock::set('poller_worker', 0)) {
  967. return;
  968. }
  969. // If there are already enough workers running, don't fork another one
  970. $quit = poller_too_much_workers();
  971. Lock::remove('poller_worker');
  972. if ($quit) {
  973. return;
  974. }
  975. // Now call the poller to execute the jobs that we just added to the queue
  976. $args = array("include/poller.php", "no_cron");
  977. $a->proc_run($args);
  978. }
  979. function current_theme() {
  980. $app_base_themes = array('duepuntozero', 'dispy', 'quattro');
  981. $a = get_app();
  982. $page_theme = null;
  983. // Find the theme that belongs to the user whose stuff we are looking at
  984. if ($a->profile_uid && ($a->profile_uid != local_user())) {
  985. $r = q("select theme from user where uid = %d limit 1",
  986. intval($a->profile_uid)
  987. );
  988. if (dbm::is_result($r)) {
  989. $page_theme = $r[0]['theme'];
  990. }
  991. }
  992. // Allow folks to over-rule user themes and always use their own on their own site.
  993. // This works only if the user is on the same server
  994. if ($page_theme && local_user() && (local_user() != $a->profile_uid)) {
  995. if (get_pconfig(local_user(), 'system', 'always_my_theme')) {
  996. $page_theme = null;
  997. }
  998. }
  999. // $mobile_detect = new Mobile_Detect();
  1000. // $is_mobile = $mobile_detect->isMobile() || $mobile_detect->isTablet();
  1001. $is_mobile = $a->is_mobile || $a->is_tablet;
  1002. $standard_system_theme = Config::get('system', 'theme', '');
  1003. $standard_theme_name = ((isset($_SESSION) && x($_SESSION, 'theme')) ? $_SESSION['theme'] : $standard_system_theme);
  1004. if ($is_mobile) {
  1005. if (isset($_SESSION['show-mobile']) && !$_SESSION['show-mobile']) {
  1006. $system_theme = $standard_system_theme;
  1007. $theme_name = $standard_theme_name;
  1008. } else {
  1009. $system_theme = Config::get('system', 'mobile-theme', '');
  1010. if ($system_theme == '') {
  1011. $system_theme = $standard_system_theme;
  1012. }
  1013. $theme_name = ((isset($_SESSION) && x($_SESSION, 'mobile-theme')) ? $_SESSION['mobile-theme'] : $system_theme);
  1014. if ($theme_name === '---') {
  1015. // user has selected to have the mobile theme be the same as the normal one
  1016. $system_theme = $standard_system_theme;
  1017. $theme_name = $standard_theme_name;
  1018. if ($page_theme) {
  1019. $theme_name = $page_theme;
  1020. }
  1021. }
  1022. }
  1023. } else {
  1024. $system_theme = $standard_system_theme;
  1025. $theme_name = $standard_theme_name;
  1026. if ($page_theme) {
  1027. $theme_name = $page_theme;
  1028. }
  1029. }
  1030. if ($theme_name &&
  1031. (file_exists('view/theme/' . $theme_name . '/style.css') ||
  1032. file_exists('view/theme/' . $theme_name . '/style.php'))) {
  1033. return($theme_name);
  1034. }
  1035. foreach ($app_base_themes as $t) {
  1036. if (file_exists('view/theme/' . $t . '/style.css') ||
  1037. file_exists('view/theme/' . $t . '/style.php')) {
  1038. return($t);
  1039. }
  1040. }
  1041. $fallback = array_merge(glob('view/theme/*/style.css'), glob('view/theme/*/style.php'));
  1042. if (count($fallback)) {
  1043. return (str_replace('view/theme/', '', substr($fallback[0], 0, -10)));
  1044. }
  1045. /// @TODO No final return statement?
  1046. }
  1047. /**
  1048. * @brief Return full URL to theme which is currently in effect.
  1049. *
  1050. * Provide a sane default if nothing is chosen or the specified theme does not exist.
  1051. *
  1052. * @return string
  1053. */
  1054. function current_theme_url() {
  1055. $a = get_app();
  1056. $t = current_theme();
  1057. $opts = (($a->profile_uid) ? '?f=&puid=' . $a->profile_uid : '');
  1058. if (file_exists('view/theme/' . $t . '/style.php')) {
  1059. return('view/theme/' . $t . '/style.pcss' . $opts);
  1060. }
  1061. return('view/theme/' . $t . '/style.css');
  1062. }
  1063. function feed_birthday($uid, $tz) {
  1064. /**
  1065. *
  1066. * Determine the next birthday, but only if the birthday is published
  1067. * in the default profile. We _could_ also look for a private profile that the
  1068. * recipient can see, but somebody could get mad at us if they start getting
  1069. * public birthday greetings when they haven't made this info public.
  1070. *
  1071. * Assuming we are able to publish this info, we are then going to convert
  1072. * the start time from the owner's timezone to UTC.
  1073. *
  1074. * This will potentially solve the problem found with some social networks
  1075. * where birthdays are converted to the viewer's timezone and salutations from
  1076. * elsewhere in the world show up on the wrong day. We will convert it to the
  1077. * viewer's timezone also, but first we are going to convert it from the birthday
  1078. * person's timezone to GMT - so the viewer may find the birthday starting at
  1079. * 6:00PM the day before, but that will correspond to midnight to the birthday person.
  1080. *
  1081. */
  1082. $birthday = '';
  1083. if (!strlen($tz)) {
  1084. $tz = 'UTC';
  1085. }
  1086. $p = q("SELECT `dob` FROM `profile` WHERE `is-default` = 1 AND `uid` = %d LIMIT 1",
  1087. intval($uid)
  1088. );
  1089. if (dbm::is_result($p)) {
  1090. $tmp_dob = substr($p[0]['dob'], 5);
  1091. if (intval($tmp_dob)) {
  1092. $y = datetime_convert($tz, $tz, 'now', 'Y');
  1093. $bd = $y . '-' . $tmp_dob . ' 00:00';
  1094. $t_dob = strtotime($bd);
  1095. $now = strtotime(datetime_convert($tz, $tz, 'now'));
  1096. if ($t_dob < $now) {
  1097. $bd = $y + 1 . '-' . $tmp_dob . ' 00:00';
  1098. }
  1099. $birthday = datetime_convert($tz, 'UTC', $bd, ATOM_TIME);
  1100. }
  1101. }
  1102. return $birthday;
  1103. }
  1104. /**
  1105. * @brief Check if current user has admin role.
  1106. *
  1107. * @return bool true if user is an admin
  1108. */
  1109. function is_site_admin() {
  1110. $a = get_app();
  1111. $adminlist = explode(",", str_replace(" ", "", $a->config['admin_email']));
  1112. //if(local_user() && x($a->user,'email') && x($a->config,'admin_email') && ($a->user['email'] === $a->config['admin_email']))
  1113. if (local_user() && x($a->user, 'email') && x($a->config, 'admin_email') && in_array($a->user['email'], $adminlist)) {
  1114. return true;
  1115. }
  1116. return false;
  1117. }
  1118. /**
  1119. * @brief Returns querystring as string from a mapped array.
  1120. *
  1121. * @param array $params mapped array with query parameters
  1122. * @param string $name of parameter, default null
  1123. *
  1124. * @return string
  1125. */
  1126. function build_querystring($params, $name = null) {
  1127. $ret = "";
  1128. foreach ($params as $key => $val) {
  1129. if (is_array($val)) {
  1130. /// @TODO maybe not compare against null, use is_null()
  1131. if ($name == null) {
  1132. $ret .= build_querystring($val, $key);
  1133. } else {
  1134. $ret .= build_querystring($val, $name . "[$key]");
  1135. }
  1136. } else {
  1137. $val = urlencode($val);
  1138. /// @TODO maybe not compare against null, use is_null()
  1139. if ($name != null) {
  1140. /// @TODO two string concated, can be merged to one
  1141. $ret .= $name . "[$key]" . "=$val&