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.
 
 
 
 
 
 

531 lines
15 KiB

  1. <?php
  2. /**
  3. *
  4. * Friendica
  5. *
  6. */
  7. /**
  8. *
  9. * bootstrap the application
  10. *
  11. */
  12. use \Friendica\Core\Config;
  13. require_once('boot.php');
  14. require_once('object/BaseObject.php');
  15. $a = new App;
  16. BaseObject::set_app($a);
  17. // We assume that the index.php is called by a frontend process
  18. // The value is set to "true" by default in boot.php
  19. $a->backend = false;
  20. /**
  21. *
  22. * Load the configuration file which contains our DB credentials.
  23. * Ignore errors. If the file doesn't exist or is empty, we are running in installation mode.
  24. *
  25. */
  26. $install = ((file_exists('.htconfig.php') && filesize('.htconfig.php')) ? false : true);
  27. @include(".htconfig.php");
  28. /**
  29. *
  30. * Try to open the database;
  31. *
  32. */
  33. require_once("include/dba.php");
  34. if(!$install) {
  35. $db = new dba($db_host, $db_user, $db_pass, $db_data, $install);
  36. unset($db_host, $db_user, $db_pass, $db_data);
  37. /**
  38. * Load configs from db. Overwrite configs from .htconfig.php
  39. */
  40. Config::load();
  41. if ($a->max_processes_reached() OR $a->maxload_reached()) {
  42. header($_SERVER["SERVER_PROTOCOL"].' 503 Service Temporarily Unavailable');
  43. header('Retry-After: 120');
  44. header('Refresh: 120; url='.App::get_baseurl()."/".$a->query_string);
  45. die("System is currently unavailable. Please try again later");
  46. }
  47. if (get_config('system','force_ssl') AND ($a->get_scheme() == "http") AND
  48. (intval(get_config('system','ssl_policy')) == SSL_POLICY_FULL) AND
  49. (substr(App::get_baseurl(), 0, 8) == "https://")) {
  50. header("HTTP/1.1 302 Moved Temporarily");
  51. header("Location: ".App::get_baseurl()."/".$a->query_string);
  52. exit();
  53. }
  54. require_once("include/session.php");
  55. load_hooks();
  56. call_hooks('init_1');
  57. $maintenance = get_config('system', 'maintenance');
  58. }
  59. $lang = get_browser_language();
  60. load_translation_table($lang);
  61. /**
  62. *
  63. * Important stuff we always need to do.
  64. *
  65. * The order of these may be important so use caution if you think they're all
  66. * intertwingled with no logical order and decide to sort it out. Some of the
  67. * dependencies have changed, but at least at one time in the recent past - the
  68. * order was critical to everything working properly
  69. *
  70. */
  71. // Exclude the backend processes from the session management
  72. if (!$a->is_backend()) {
  73. $stamp1 = microtime(true);
  74. session_start();
  75. $a->save_timestamp($stamp1, "parser");
  76. } else {
  77. require_once "include/poller.php";
  78. call_worker_if_idle();
  79. }
  80. /**
  81. * Language was set earlier, but we can over-ride it in the session.
  82. * We have to do it here because the session was just now opened.
  83. */
  84. if (x($_SESSION,'authenticated') && !x($_SESSION,'language')) {
  85. // we didn't loaded user data yet, but we need user language
  86. $r = q("SELECT language FROM user WHERE uid=%d", intval($_SESSION['uid']));
  87. $_SESSION['language'] = $lang;
  88. if (dbm::is_result($r)) $_SESSION['language'] = $r[0]['language'];
  89. }
  90. if((x($_SESSION,'language')) && ($_SESSION['language'] !== $lang)) {
  91. $lang = $_SESSION['language'];
  92. load_translation_table($lang);
  93. }
  94. if((x($_GET,'zrl')) && (!$install && !$maintenance)) {
  95. // Only continue when the given profile link seems valid
  96. // Valid profile links contain a path with "/profile/" and no query parameters
  97. if ((parse_url($_GET['zrl'], PHP_URL_QUERY) == "") AND
  98. strstr(parse_url($_GET['zrl'], PHP_URL_PATH), "/profile/")) {
  99. $_SESSION['my_url'] = $_GET['zrl'];
  100. $a->query_string = preg_replace('/[\?&]zrl=(.*?)([\?&]|$)/is','',$a->query_string);
  101. zrl_init($a);
  102. } else {
  103. // Someone came with an invalid parameter, maybe as a DDoS attempt
  104. // We simply stop processing here
  105. logger("Invalid ZRL parameter ".$_GET['zrl'], LOGGER_DEBUG);
  106. header('HTTP/1.1 403 Forbidden');
  107. echo "<h1>403 Forbidden</h1>";
  108. killme();
  109. }
  110. }
  111. /**
  112. *
  113. * For Mozilla auth manager - still needs sorting, and this might conflict with LRDD header.
  114. * Apache/PHP lumps the Link: headers into one - and other services might not be able to parse it
  115. * this way. There's a PHP flag to link the headers because by default this will over-write any other
  116. * link header.
  117. *
  118. * What we really need to do is output the raw headers ourselves so we can keep them separate.
  119. *
  120. */
  121. // header('Link: <' . App::get_baseurl() . '/amcd>; rel="acct-mgmt";');
  122. if (x($_COOKIE["Friendica"]) || (x($_SESSION,'authenticated')) || (x($_POST,'auth-params')) || ($a->module === 'login')) {
  123. require("include/auth.php");
  124. }
  125. if (! x($_SESSION,'authenticated')) {
  126. header('X-Account-Management-Status: none');
  127. }
  128. /* set up page['htmlhead'] and page['end'] for the modules to use */
  129. $a->page['htmlhead'] = '';
  130. $a->page['end'] = '';
  131. if (! x($_SESSION,'sysmsg')) {
  132. $_SESSION['sysmsg'] = array();
  133. }
  134. if (! x($_SESSION,'sysmsg_info')) {
  135. $_SESSION['sysmsg_info'] = array();
  136. }
  137. /*
  138. * check_config() is responsible for running update scripts. These automatically
  139. * update the DB schema whenever we push a new one out. It also checks to see if
  140. * any plugins have been added or removed and reacts accordingly.
  141. */
  142. // in install mode, any url loads install module
  143. // but we need "view" module for stylesheet
  144. if ($install && $a->module!="view") {
  145. $a->module = 'install';
  146. } elseif ($maintenance && $a->module!="view") {
  147. $a->module = 'maintenance';
  148. } else {
  149. check_url($a);
  150. check_db();
  151. check_plugins($a);
  152. }
  153. nav_set_selected('nothing');
  154. //Don't populate apps_menu if apps are private
  155. $privateapps = get_config('config','private_addons');
  156. if ((local_user()) || (! $privateapps === "1")) {
  157. $arr = array('app_menu' => $a->apps);
  158. call_hooks('app_menu', $arr);
  159. $a->apps = $arr['app_menu'];
  160. }
  161. /**
  162. *
  163. * We have already parsed the server path into $a->argc and $a->argv
  164. *
  165. * $a->argv[0] is our module name. We will load the file mod/{$a->argv[0]}.php
  166. * and use it for handling our URL request.
  167. * The module file contains a few functions that we call in various circumstances
  168. * and in the following order:
  169. *
  170. * "module"_init
  171. * "module"_post (only called if there are $_POST variables)
  172. * "module"_afterpost
  173. * "module"_content - the string return of this function contains our page body
  174. *
  175. * Modules which emit other serialisations besides HTML (XML,JSON, etc.) should do
  176. * so within the module init and/or post functions and then invoke killme() to terminate
  177. * further processing.
  178. */
  179. if(strlen($a->module)) {
  180. /**
  181. *
  182. * We will always have a module name.
  183. * First see if we have a plugin which is masquerading as a module.
  184. *
  185. */
  186. // Compatibility with the Android Diaspora client
  187. if ($a->module == "stream")
  188. $a->module = "network";
  189. // Compatibility with the Firefox App
  190. if (($a->module == "users") AND ($a->cmd == "users/sign_in"))
  191. $a->module = "login";
  192. $privateapps = get_config('config','private_addons');
  193. if (is_array($a->plugins) && in_array($a->module,$a->plugins) && file_exists("addon/{$a->module}/{$a->module}.php")) {
  194. //Check if module is an app and if public access to apps is allowed or not
  195. if ((!local_user()) && plugin_is_app($a->module) && $privateapps === "1") {
  196. info( t("You must be logged in to use addons. "));
  197. }
  198. else {
  199. include_once("addon/{$a->module}/{$a->module}.php");
  200. if(function_exists($a->module . '_module'))
  201. $a->module_loaded = true;
  202. }
  203. }
  204. /**
  205. * If not, next look for a 'standard' program module in the 'mod' directory
  206. */
  207. if ((! $a->module_loaded) && (file_exists("mod/{$a->module}.php"))) {
  208. include_once("mod/{$a->module}.php");
  209. $a->module_loaded = true;
  210. }
  211. /**
  212. *
  213. * The URL provided does not resolve to a valid module.
  214. *
  215. * On Dreamhost sites, quite often things go wrong for no apparent reason and they send us to '/internal_error.html'.
  216. * We don't like doing this, but as it occasionally accounts for 10-20% or more of all site traffic -
  217. * we are going to trap this and redirect back to the requested page. As long as you don't have a critical error on your page
  218. * this will often succeed and eventually do the right thing.
  219. *
  220. * Otherwise we are going to emit a 404 not found.
  221. *
  222. */
  223. if (! $a->module_loaded) {
  224. // Stupid browser tried to pre-fetch our Javascript img template. Don't log the event or return anything - just quietly exit.
  225. if ((x($_SERVER,'QUERY_STRING')) && preg_match('/{[0-9]}/',$_SERVER['QUERY_STRING']) !== 0) {
  226. killme();
  227. }
  228. if ((x($_SERVER,'QUERY_STRING')) && ($_SERVER['QUERY_STRING'] === 'q=internal_error.html') && isset($dreamhost_error_hack)) {
  229. logger('index.php: dreamhost_error_hack invoked. Original URI =' . $_SERVER['REQUEST_URI']);
  230. goaway(App::get_baseurl() . $_SERVER['REQUEST_URI']);
  231. }
  232. logger('index.php: page not found: ' . $_SERVER['REQUEST_URI'] . ' ADDRESS: ' . $_SERVER['REMOTE_ADDR'] . ' QUERY: ' . $_SERVER['QUERY_STRING'], LOGGER_DEBUG);
  233. header($_SERVER["SERVER_PROTOCOL"] . ' 404 ' . t('Not Found'));
  234. $tpl = get_markup_template("404.tpl");
  235. $a->page['content'] = replace_macros($tpl, array(
  236. '$message' => t('Page not found.' )
  237. ));
  238. }
  239. }
  240. /**
  241. * load current theme info
  242. */
  243. $theme_info_file = "view/theme/".current_theme()."/theme.php";
  244. if (file_exists($theme_info_file)){
  245. require_once($theme_info_file);
  246. }
  247. /* initialise content region */
  248. if (! x($a->page,'content')) {
  249. $a->page['content'] = '';
  250. }
  251. if (!$install && !$maintenance) {
  252. call_hooks('page_content_top',$a->page['content']);
  253. }
  254. /**
  255. * Call module functions
  256. */
  257. if($a->module_loaded) {
  258. $a->page['page_title'] = $a->module;
  259. $placeholder = '';
  260. if(function_exists($a->module . '_init')) {
  261. call_hooks($a->module . '_mod_init', $placeholder);
  262. $func = $a->module . '_init';
  263. $func($a);
  264. }
  265. if(function_exists(str_replace('-','_',current_theme()) . '_init')) {
  266. $func = str_replace('-','_',current_theme()) . '_init';
  267. $func($a);
  268. }
  269. // elseif (x($a->theme_info,"extends") && file_exists("view/theme/".$a->theme_info["extends"]."/theme.php")) {
  270. // require_once("view/theme/".$a->theme_info["extends"]."/theme.php");
  271. // if(function_exists(str_replace('-','_',$a->theme_info["extends"]) . '_init')) {
  272. // $func = str_replace('-','_',$a->theme_info["extends"]) . '_init';
  273. // $func($a);
  274. // }
  275. // }
  276. if(($_SERVER['REQUEST_METHOD'] === 'POST') && (! $a->error)
  277. && (function_exists($a->module . '_post'))
  278. && (! x($_POST,'auth-params'))) {
  279. call_hooks($a->module . '_mod_post', $_POST);
  280. $func = $a->module . '_post';
  281. $func($a);
  282. }
  283. if((! $a->error) && (function_exists($a->module . '_afterpost'))) {
  284. call_hooks($a->module . '_mod_afterpost',$placeholder);
  285. $func = $a->module . '_afterpost';
  286. $func($a);
  287. }
  288. if((! $a->error) && (function_exists($a->module . '_content'))) {
  289. $arr = array('content' => $a->page['content']);
  290. call_hooks($a->module . '_mod_content', $arr);
  291. $a->page['content'] = $arr['content'];
  292. $func = $a->module . '_content';
  293. $arr = array('content' => $func($a));
  294. call_hooks($a->module . '_mod_aftercontent', $arr);
  295. $a->page['content'] .= $arr['content'];
  296. }
  297. if(function_exists(str_replace('-','_',current_theme()) . '_content_loaded')) {
  298. $func = str_replace('-','_',current_theme()) . '_content_loaded';
  299. $func($a);
  300. }
  301. }
  302. /*
  303. * Create the page head after setting the language
  304. * and getting any auth credentials
  305. *
  306. * Moved init_pagehead() and init_page_end() to after
  307. * all the module functions have executed so that all
  308. * theme choices made by the modules can take effect
  309. */
  310. $a->init_pagehead();
  311. /**
  312. * Build the page ending -- this is stuff that goes right before
  313. * the closing </body> tag
  314. */
  315. $a->init_page_end();
  316. // If you're just visiting, let javascript take you home
  317. if(x($_SESSION,'visitor_home'))
  318. $homebase = $_SESSION['visitor_home'];
  319. elseif(local_user())
  320. $homebase = 'profile/' . $a->user['nickname'];
  321. if(isset($homebase))
  322. $a->page['content'] .= '<script>var homebase="' . $homebase . '" ; </script>';
  323. // now that we've been through the module content, see if the page reported
  324. // a permission problem and if so, a 403 response would seem to be in order.
  325. if(stristr( implode("",$_SESSION['sysmsg']), t('Permission denied'))) {
  326. header($_SERVER["SERVER_PROTOCOL"] . ' 403 ' . t('Permission denied.'));
  327. }
  328. /**
  329. *
  330. * Report anything which needs to be communicated in the notification area (before the main body)
  331. *
  332. */
  333. /*if(x($_SESSION,'sysmsg')) {
  334. $a->page['content'] = "<div id=\"sysmsg\" class=\"error-message\">{$_SESSION['sysmsg']}</div>\r\n"
  335. . ((x($a->page,'content')) ? $a->page['content'] : '');
  336. $_SESSION['sysmsg']="";
  337. unset($_SESSION['sysmsg']);
  338. }
  339. if(x($_SESSION,'sysmsg_info')) {
  340. $a->page['content'] = "<div id=\"sysmsg_info\" class=\"info-message\">{$_SESSION['sysmsg_info']}</div>\r\n"
  341. . ((x($a->page,'content')) ? $a->page['content'] : '');
  342. $_SESSION['sysmsg_info']="";
  343. unset($_SESSION['sysmsg_info']);
  344. }*/
  345. call_hooks('page_end', $a->page['content']);
  346. /**
  347. *
  348. * Add the navigation (menu) template
  349. *
  350. */
  351. if($a->module != 'install' && $a->module != 'maintenance') {
  352. nav($a);
  353. }
  354. /**
  355. * Add a "toggle mobile" link if we're using a mobile device
  356. */
  357. if($a->is_mobile || $a->is_tablet) {
  358. if(isset($_SESSION['show-mobile']) && !$_SESSION['show-mobile']) {
  359. $link = 'toggle_mobile?address=' . curPageURL();
  360. }
  361. else {
  362. $link = 'toggle_mobile?off=1&address=' . curPageURL();
  363. }
  364. $a->page['footer'] = replace_macros(get_markup_template("toggle_mobile_footer.tpl"), array(
  365. '$toggle_link' => $link,
  366. '$toggle_text' => t('toggle mobile')
  367. ));
  368. }
  369. /**
  370. * Build the page - now that we have all the components
  371. */
  372. if(!$a->theme['stylesheet'])
  373. $stylesheet = current_theme_url();
  374. else
  375. $stylesheet = $a->theme['stylesheet'];
  376. $a->page['htmlhead'] = str_replace('{{$stylesheet}}',$stylesheet,$a->page['htmlhead']);
  377. //$a->page['htmlhead'] = replace_macros($a->page['htmlhead'], array('$stylesheet' => $stylesheet));
  378. if (isset($_GET["mode"]) AND (($_GET["mode"] == "raw") OR ($_GET["mode"] == "minimal"))) {
  379. $doc = new DOMDocument();
  380. $target = new DOMDocument();
  381. $target->loadXML("<root></root>");
  382. $content = mb_convert_encoding($a->page["content"], 'HTML-ENTITIES', "UTF-8");
  383. @$doc->loadHTML($content);
  384. $xpath = new DomXPath($doc);
  385. $list = $xpath->query("//*[contains(@id,'tread-wrapper-')]"); /* */
  386. foreach ($list as $item) {
  387. $item = $target->importNode($item, true);
  388. // And then append it to the target
  389. $target->documentElement->appendChild($item);
  390. }
  391. }
  392. if (isset($_GET["mode"]) AND ($_GET["mode"] == "raw")) {
  393. header("Content-type: text/html; charset=utf-8");
  394. echo substr($target->saveHTML(), 6, -8);
  395. if (!$a->is_backend())
  396. session_write_close();
  397. exit;
  398. }
  399. $page = $a->page;
  400. $profile = $a->profile;
  401. header("X-Friendica-Version: ".FRIENDICA_VERSION);
  402. header("Content-type: text/html; charset=utf-8");
  403. // We use $_GET["mode"] for special page templates. So we will check if we have
  404. // to load another page template than the default one
  405. // The page templates are located in /view/php/ or in the theme directory
  406. if (isset($_GET["mode"])) {
  407. $template = theme_include($_GET["mode"].'.php');
  408. }
  409. // If there is no page template use the default page template
  410. if(!$template) {
  411. $template = theme_include("default.php");
  412. }
  413. require_once($template);
  414. if (!$a->is_backend())
  415. session_write_close();
  416. exit;