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.

2110 lines
54 KiB

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