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.

1833 lines
49 KiB

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