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.

1673 lines
43 KiB

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