functions.php 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224
  1. <?php
  2. /* this file stores all of the functions that are used
  3. over all of the other files. */
  4. ini_set("log_errors", 1);
  5. $srv = $user_settings['instance'];
  6. //$token = ($token != false ? msc($token,'d') : false);
  7. $token = ($token != false ? $token : false);
  8. // FUNCTIONS THAT HAVE TO DO WITH INSTANCE COMMUNICATION AND RETRIEVAL
  9. /* a function to make an authenticated general GET api call to the logged-in instance.
  10. - $url is a string of an api call like "account/:id/statuses"
  11. - returns the array conversion of the json response
  12. */
  13. function api_get($url) {
  14. global $srv;
  15. global $token;
  16. $curl = curl_init();
  17. curl_setopt($curl, CURLOPT_URL, "https://$srv/api/v1/" . $url);
  18. if (!is_null($token)) {
  19. curl_setopt($curl, CURLOPT_HTTPHEADER, array(
  20. 'Authorization: Bearer ' . $token
  21. ));
  22. }
  23. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  24. $result = curl_exec($curl);
  25. curl_close($curl);
  26. return json_decode($result, true);
  27. }
  28. /* same as above but used in some newer api endpoinds (v2) */
  29. function api_getv2($url) {
  30. global $srv;
  31. global $token;
  32. $curl = curl_init();
  33. curl_setopt($curl, CURLOPT_URL, "https://$srv/api/v2/" . $url);
  34. if (!is_null($token)) {
  35. curl_setopt($curl, CURLOPT_HTTPHEADER, array(
  36. 'Authorization: Bearer ' . $token
  37. ));
  38. }
  39. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  40. $result = curl_exec($curl);
  41. curl_close($curl);
  42. return json_decode($result, true);
  43. }
  44. /* a function to make an authenticated general POST api call to the logged-in instance.
  45. - $url is a string of an api call like "account/:id/statuses"
  46. - returns the array conversion of the json response
  47. */
  48. function api_post($url, $array) {
  49. global $srv;
  50. global $token;
  51. $cSession = curl_init();
  52. curl_setopt($cSession, CURLOPT_HEADER, false);
  53. curl_setopt($cSession, CURLOPT_POST, 1);
  54. curl_setopt($cSession, CURLOPT_URL, "https://$srv/api/v1/" . $url);
  55. if (!is_null($token)) {
  56. curl_setopt($cSession, CURLOPT_HTTPHEADER, array(
  57. 'Authorization: Bearer ' . $token
  58. ));
  59. }
  60. curl_setopt($cSession, CURLOPT_POSTFIELDS, http_build_query($array));
  61. curl_setopt($cSession, CURLOPT_RETURNTRANSFER, true);
  62. $result = curl_exec($cSession);
  63. curl_close($cSession);
  64. return json_decode($result, true);
  65. }
  66. /* a function to make an authenticated general DELETE api call to the logged-in instance.
  67. - $url is a string of an api call like "statuses/delete/:id"
  68. - returns the array conversion of the json response
  69. */
  70. function api_delete($url, $array) {
  71. global $srv;
  72. global $token;
  73. $cSession = curl_init();
  74. curl_setopt($cSession, CURLOPT_HEADER, false);
  75. curl_setopt($cSession, CURLOPT_POST, 1);
  76. curl_setopt($cSession, CURLOPT_URL, "https://$srv/api/v1/" . $url);
  77. curl_setopt($cSession, CURLOPT_CUSTOMREQUEST, "DELETE");
  78. if (!is_null($token)) {
  79. curl_setopt($cSession, CURLOPT_HTTPHEADER, array(
  80. 'Authorization: Bearer ' . $token
  81. ));
  82. }
  83. curl_setopt($cSession, CURLOPT_POSTFIELDS, http_build_query($array));
  84. curl_setopt($cSession, CURLOPT_RETURNTRANSFER, true);
  85. $result = curl_exec($cSession);
  86. curl_close($cSession);
  87. return json_decode($result, true);
  88. }
  89. /* a function to make an authenticated general PATCH api call to the logged-in instance.
  90. - $url is a string of an api call like "account/:id/statuses"
  91. - returns the array conversion of the json response
  92. */
  93. function api_patch($url, $array) {
  94. global $srv;
  95. global $token;
  96. $cSession = curl_init();
  97. curl_setopt($cSession, CURLOPT_HEADER, false);
  98. curl_setopt($cSession, CURLOPT_POST, 1);
  99. curl_setopt($cSession, CURLOPT_URL, "https://$srv/api/v1/" . $url);
  100. curl_setopt($cSession, CURLOPT_CUSTOMREQUEST, "PATCH");
  101. if (!is_null($token)) {
  102. curl_setopt($cSession, CURLOPT_HTTPHEADER, array(
  103. 'Authorization: Bearer ' . $token
  104. ));
  105. }
  106. curl_setopt($cSession, CURLOPT_POSTFIELDS, http_build_query($array));
  107. curl_setopt($cSession, CURLOPT_RETURNTRANSFER, true);
  108. $result = curl_exec($cSession);
  109. curl_close($cSession);
  110. return json_decode($result, true);
  111. }
  112. /* Function to upload files to the profile of the authenticated user
  113. - $type can be 'avatar' or 'header'
  114. - returns the json of the api call
  115. */
  116. function upload_profile($file,$type){
  117. global $srv;
  118. global $token;
  119. $mime = get_mime($file);
  120. $info = pathinfo($file);
  121. $name = $info['basename'];
  122. $output = new CURLFile($file, $mime, $name);
  123. $cSession = curl_init();
  124. curl_setopt($cSession, CURLOPT_URL, "https://$srv/api/v1/accounts/update_credentials");
  125. curl_setopt($cSession, CURLOPT_RETURNTRANSFER, true);
  126. curl_setopt($cSession, CURLOPT_POST, 1);
  127. curl_setopt($cSession, CURLOPT_CUSTOMREQUEST, "PATCH");
  128. curl_setopt($cSession, CURLOPT_HTTPHEADER, array(
  129. 'Authorization: Bearer ' . $token
  130. ));
  131. curl_setopt($cSession, CURLOPT_POSTFIELDS, array(
  132. $type => $output
  133. ));
  134. $result = curl_exec($cSession);
  135. curl_close($cSession);
  136. return $result;
  137. }
  138. /* this function fetches all the data from a profile (bio, username, relationships, etc)
  139. - $user is the id of the queried user
  140. - returns the array conversion of the json response
  141. */
  142. function user_info($user) {
  143. global $user_settings;
  144. $info = api_get("accounts/" . $user);
  145. $rel = api_get("accounts/relationships?id=" . $user);
  146. return array(
  147. $info,
  148. $rel
  149. );
  150. }
  151. /* this function fetches the context (the previous posts and replies) of a specified post
  152. - $post = ID of the post queried.
  153. - returns an array conversion of the json response
  154. */
  155. function context($post) {
  156. global $srv;
  157. global $token;
  158. $curl = curl_init();
  159. curl_setopt($curl, CURLOPT_URL, "https://$srv/api/v1/statuses/$post/context");
  160. if (!is_null($token)) {
  161. curl_setopt($curl, CURLOPT_HTTPHEADER, array(
  162. 'Authorization: Bearer ' . $token
  163. ));
  164. }
  165. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  166. $result = curl_exec($curl);
  167. curl_close($curl);
  168. return $result;
  169. }
  170. /* a function to fav or unfav a specified post
  171. - $post = ID of the post queried.
  172. - $mode can be true if is a fav or false if it's an unfav
  173. - returns the number of favs of the post after the specified action or "error"
  174. if there was an error performing the action
  175. */
  176. function favourite($post, $mode) {
  177. $result = api_post(($mode == true ? "statuses/$post/favourite" : "statuses/$post/unfavourite"),array());
  178. if (isset($result['favourites_count'])) {
  179. return $result['favourites_count'];
  180. }
  181. else {
  182. return "error";
  183. }
  184. }
  185. /* a function to reblog or unreblog a specified post
  186. - $post = ID of the post queried.
  187. - $mode can be true if is a reblog or false if it's an unreblog
  188. - returns the number of reblogs of the post after the specified action or "error"
  189. if there was an error performing the action
  190. */
  191. function reblog($post, $mode) {
  192. $result = api_post(($mode == true ? "statuses/$post/reblog" : "statuses/$post/unreblog"),array());
  193. if (isset($result['reblog']['reblogs_count'])) {
  194. return $result['reblog']['reblogs_count'];
  195. }
  196. elseif (isset($result['reblogs_count'])) {
  197. return $result['reblogs_count'];
  198. }
  199. else {
  200. return "error";
  201. }
  202. }
  203. /* function to delete a post
  204. - $id is the id of the post to delete
  205. - returns 1 if the post was deleted succesfully or 0 if there was an error
  206. */
  207. function delpost($id) {
  208. global $srv;
  209. global $token;
  210. if (!is_null($token)) {
  211. $curl = curl_init();
  212. curl_setopt($curl, CURLOPT_HEADER, false);
  213. curl_setopt($curl, CURLOPT_POST, 1);
  214. curl_setopt($curl, CURLOPT_URL, "https://$srv/api/v1/statuses/$id");
  215. curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE");
  216. curl_setopt($curl, CURLOPT_HTTPHEADER, array(
  217. 'Authorization: Bearer ' . $token
  218. ));
  219. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  220. $result = curl_exec($curl);
  221. curl_close($curl);
  222. $result = json_decode($result, true);
  223. if (empty($result)) {
  224. return "1";
  225. }
  226. else {
  227. return "0";
  228. }
  229. }
  230. }
  231. /* function to issue a vote to a poll
  232. - $id is the id of the poll to vote on
  233. - $choices is a comma separated string of the choices that will be voted.
  234. */
  235. function vote($poll, $choices) {
  236. global $srv;
  237. global $token;
  238. if (!is_null($token)) {
  239. $cSession = curl_init();
  240. curl_setopt($cSession, CURLOPT_URL, "https://$srv/api/v1/polls/$poll/votes");
  241. curl_setopt($cSession, CURLOPT_RETURNTRANSFER, true);
  242. curl_setopt($cSession, CURLOPT_POST, 1);
  243. curl_setopt($cSession, CURLOPT_HTTPHEADER, array(
  244. 'Authorization: Bearer ' . $token
  245. ));
  246. $query = "";
  247. $choicelist = explode(",",$choices);
  248. foreach($choicelist as $choice){
  249. $query .= "choices[]=$choice&";
  250. }
  251. curl_setopt($cSession, CURLOPT_POSTFIELDS, $query);
  252. $result = curl_exec($cSession);
  253. curl_close($cSession);
  254. return $result;
  255. }
  256. else {
  257. return false;
  258. }
  259. }
  260. /* function to send a new post to the logged in instance
  261. - $text = the body of the message
  262. - $media = array of uploaded media id's
  263. - $reply = the id of a post being replied to, can be null.
  264. - $markdown = specify if the post uses markdown (unused at this moment)
  265. - $scope = the scope of the post (public, private, unlisted or direct)
  266. - $sensitive = bool to specify if the post media is sensitive
  267. - $spoiler = string of the title of the post
  268. - returns the json of the api response
  269. */
  270. function sendpost($text, $media, $reply = null, $markdown = false, $scope = "public", $sensitive = false, $spoiler = false) {
  271. global $srv;
  272. global $token;
  273. if (!is_null($token)) {
  274. $cSession = curl_init();
  275. curl_setopt($cSession, CURLOPT_URL, "https://$srv/api/v1/statuses");
  276. curl_setopt($cSession, CURLOPT_RETURNTRANSFER, true);
  277. curl_setopt($cSession, CURLOPT_POST, 1);
  278. curl_setopt($cSession, CURLOPT_HTTPHEADER, array(
  279. 'Authorization: Bearer ' . $token
  280. ));
  281. $query = "";
  282. $query .= "status=" . urlencode(html_entity_decode($text, ENT_QUOTES)) . "&visibility=" . $scope;;
  283. if (!is_null($reply) && $reply != "null") {
  284. $query .= "&in_reply_to_id=" . $reply;
  285. }
  286. if ($markdown == true) {
  287. $query .= "&content_type=text/markdown";
  288. }
  289. if ($sensitive == 'true') {
  290. $query .= "&sensitive=true";
  291. }
  292. if ($spoiler == true) {
  293. $query .= "&spoiler_text=" . $spoiler;
  294. }
  295. if (!is_null($media)) {
  296. foreach ($media as $mid) {
  297. $query .= "&media_ids[]=" . $mid;
  298. }
  299. }
  300. curl_setopt($cSession, CURLOPT_POSTFIELDS, $query);
  301. $result = curl_exec($cSession);
  302. curl_close($cSession);
  303. return $result;
  304. }
  305. else {
  306. return false;
  307. }
  308. }
  309. /* uploads a file to the logged in instance.
  310. - $file = path of the file to upload on local storage
  311. - returns an array where:
  312. 0: the ID of the uploaded file
  313. 1: the url of the file (if the file isn't an image, returns a placeholder)
  314. */
  315. function uploadpic($file) {
  316. global $srv;
  317. global $token;
  318. if (!is_null($token)) {
  319. $mime = get_mime($file);
  320. $info = pathinfo($file);
  321. $name = $info['basename'];
  322. $output = new CURLFile($file, $mime, $name);
  323. $cSession = curl_init();
  324. curl_setopt($cSession, CURLOPT_URL, "https://$srv/api/v1/media");
  325. curl_setopt($cSession, CURLOPT_RETURNTRANSFER, true);
  326. curl_setopt($cSession, CURLOPT_POST, 1);
  327. curl_setopt($cSession, CURLOPT_HTTPHEADER, array(
  328. 'Authorization: Bearer ' . $token
  329. ));
  330. curl_setopt($cSession, CURLOPT_POSTFIELDS, array(
  331. 'file' => $output
  332. ));
  333. $result = curl_exec($cSession);
  334. curl_close($cSession);
  335. echo $result;
  336. $array = json_decode($result, true);
  337. $ext = explode(".", $array['url']);
  338. $ext = end($ext);
  339. $ext = explode("?", $ext) [0];
  340. if (in_array($ext, array('jpg','jpeg','gif','png','svg','webm'))) {
  341. $file = $array['url'];
  342. } elseif (in_array($ext, array('mp4','webp','ogv'))) {
  343. $file = "img/vid.png";
  344. } elseif (in_array($ext, array('mp3','ogg','oga','opus'))) {
  345. $file = "img/aud.png";
  346. } else {
  347. $file = "img/doc.png";
  348. }
  349. return json_encode(array(
  350. $array['id'],
  351. $file
  352. ));
  353. }
  354. else {
  355. return false;
  356. }
  357. }
  358. /* this is used to register DashFE as an application on an instance
  359. mostly used when logging in
  360. - $instance = the url of the instance where to log in
  361. - returns the array conversion of the json response
  362. */
  363. function register_app($instance) {
  364. global $setting;
  365. $cSession = curl_init();
  366. curl_setopt($cSession, CURLOPT_URL, "https://$instance/api/v1/apps");
  367. curl_setopt($cSession, CURLOPT_RETURNTRANSFER, true);
  368. curl_setopt($cSession, CURLOPT_HEADER, false);
  369. curl_setopt($cSession, CURLOPT_POST, 1);
  370. curl_setopt($cSession, CURLOPT_POSTFIELDS, http_build_query(array(
  371. 'client_name' => $setting['appname'],
  372. 'redirect_uris' => $setting['url'],
  373. 'scopes' => 'read write follow'
  374. )));
  375. $result = curl_exec($cSession);
  376. curl_close($cSession);
  377. return json_decode($result, true);
  378. }
  379. /* this function will get all the notes (reblogs and favs) that has an specified post
  380. - $thread = the id of the post queried
  381. - returns an array with all the notes
  382. each note is another array where:
  383. 0 = type of note ("reb" reblog or "fab" favorite)
  384. 1 = array of the details of the user, converted from the json of the api response.
  385. */
  386. function getnotes($thread) {
  387. global $user_settings;
  388. global $token;
  389. global $srv;
  390. global $setting;
  391. global $logedin;
  392. @$reb = array(
  393. api_get("statuses/" . $thread . "/reblogged_by")
  394. );
  395. @$fab = array(
  396. api_get("statuses/" . $thread . "/favourited_by")
  397. );
  398. $limit = (count($reb[0]) > count($fab[0]) ? count($reb[0]) - 1 : count($fab[0]) - 1);
  399. $notes = array();
  400. $index = 0;
  401. for ($i = 0;$i <= $limit;$i++) {
  402. if (isset($reb[0][$i])) {
  403. $notes[$index][0] = "reb";
  404. $notes[$index][1] = $reb[0][$i];
  405. $index++;
  406. }
  407. if (isset($fab[0][$i])) {
  408. $notes[$index][0] = "fav";
  409. $notes[$index][1] = $fab[0][$i];
  410. $index++;
  411. }
  412. }
  413. return $notes;
  414. }
  415. /* this function will fetch replies of a post
  416. - $thread = the id of the post from where to fetch replies
  417. - $since = id of a post. If specified, the function will fetch the replies
  418. only since the specified id.
  419. - returns an array with all the replies
  420. each element is another array where:
  421. 'mode' = type of the reply (ancestor or descendant)
  422. 'content' = array of the contents of the reply, converted from the json of the api response.
  423. */
  424. function getreplies($thread, $since = false) {
  425. global $user_settings;
  426. global $token;
  427. global $srv;
  428. global $setting;
  429. global $logedin;
  430. $context = json_decode(context($thread) , true);
  431. $array = array();
  432. if (!empty($context['ancestors'])) {
  433. if ($since == false) {
  434. foreach ($context['ancestors'] as $elem) {
  435. $elem['type'] = 'ancestor';
  436. $array[] = $elem;
  437. }
  438. }
  439. }
  440. $flag = 0;
  441. if (!empty($context['descendants'])) {
  442. foreach ($context['descendants'] as $elem) {
  443. if (($since != false && $flag == 1) || $since == false) {
  444. $elem['type'] = 'descendant';
  445. $array[] = $elem;
  446. }
  447. if ($since != false && $elem['id'] == $since) {
  448. $flag = 1;
  449. }
  450. }
  451. }
  452. $replies = array();
  453. foreach ($array as $item) {
  454. $reply['mode'] = "";
  455. if ($item['type'] == 'ancestor') {
  456. $reply['mode'] = "ancestor";
  457. }
  458. $replies[] = array(
  459. 'mode' => $reply['mode'],
  460. 'content' => $item
  461. );
  462. }
  463. return $replies;
  464. }
  465. /* this function takes some options from the init.php file and the user_settings cookie
  466. and fetches all the posts of the appropiate timeline
  467. - $query = an array with a set of elements generated by the file "include/init.php"
  468. - returns an array of the posts list fetched converted from the json response of the api.
  469. */
  470. function timeline($query) {
  471. global $token;
  472. global $srv;
  473. $notes = "";
  474. $hq = array();
  475. $hq['limit'] = 10;
  476. $hq['only_media'] = ($query['text'] == "off" ? 'true' : 'false');
  477. if ($query['next']){
  478. $hq['max_id'] = $query['next'];
  479. $next = $query['next'];
  480. } elseif ($query['since']) {
  481. $hq['since_id'] = $query['since'];
  482. }
  483. switch ($query['mode']) {
  484. case "home":
  485. $array = api_get("timelines/home?".http_build_query($hq));
  486. break;
  487. case "federated":
  488. $array = api_get("timelines/public?".http_build_query($hq));
  489. break;
  490. case "tag":
  491. $array = api_get("timelines/tag/" . $query['tag'] . "?".http_build_query($hq));
  492. break;
  493. case "local":
  494. $array = api_get("timelines/public?local=true&".http_build_query($hq));
  495. break;
  496. case "user":
  497. $array = api_get("accounts/" . $query['user'] . "/statuses?".http_build_query($hq));
  498. break;
  499. case "thread":
  500. $array = array(
  501. api_get("statuses/" . $query['thread'])
  502. );
  503. break;
  504. case "favourites":
  505. $array = api_get("favourites?".http_build_query($hq));
  506. break;
  507. case "direct":
  508. $array = api_get("timelines/direct?".http_build_query($hq));
  509. break;
  510. case "list":
  511. $array = api_get("timelines/list/" . $query['list'] . "?".http_build_query($hq));
  512. break;
  513. case "bookmarks":
  514. $array = api_get("bookmarks?".http_build_query($hq));
  515. break;
  516. case "search":
  517. $array = api_getv2("search?limit=40&q=".$query['search']."{$next}")['statuses'];
  518. break;
  519. case "account":
  520. $info = api_get("accounts/verify_credentials");
  521. $array = api_get("accounts/" . $info['id'] . "/statuses?".http_build_query($hq));
  522. break;
  523. default:
  524. $array = api_get("timelines/public?".http_build_query($hq));
  525. break;
  526. }
  527. if (!is_array($array)) {
  528. return false;
  529. }
  530. $next = end($array) ['id'];
  531. $thread = array();
  532. /*
  533. foreach ($array as $elem) {
  534. if ($query['replies'] == "on" || $query['mode'] == "thread") {
  535. $thread[] = $elem;
  536. }
  537. else {
  538. if ($elem['in_reply_to_id'] == null) {
  539. $thread[] = $elem;
  540. }
  541. }
  542. }*/
  543. foreach ($array as $elem) {
  544. if ($query['replies'] == "on" || $query['mode'] == "thread") {
  545. $thread[] = $elem;
  546. }
  547. else {
  548. if ($elem['in_reply_to_id'] == null || $elem['in_reply_to_account_id'] == $query['uid']) {
  549. $thread[] = $elem;
  550. } else {
  551. $rel = api_get("accounts/relationships?id=" . $elem['in_reply_to_account_id']);
  552. if ($rel[0]['following']){
  553. $thread[] = $elem;
  554. }
  555. }
  556. }
  557. }
  558. return $thread;
  559. }
  560. // FUNCTIONS THAT HAVE TO DO WITH RENDERING STUFF FOR THE PAGE
  561. /* this function is used to generate the html code of a poll */
  562. function renderPoll($elem) {
  563. global $logedin;
  564. $output = "";
  565. $output .= "<br>";
  566. $votes = $elem['poll']['votes_count'];
  567. if ($elem['poll']['voted'] || $elem['poll']['expired']) {
  568. $output.= "<b>Votes: $votes</b><br>";
  569. foreach ($elem['poll']['options'] as $option){
  570. $percentage = ($option['votes_count'] / $votes ) * 100;
  571. $output .= "<div class='polloption fixed' title='".$option['votes_count']." votes'><div class='voteBar' style='font-weight:bold; max-width:".$percentage."%;padding:1px; height:10px;'> </div>".$option['title']."</div>";
  572. }
  573. } else {
  574. foreach ($elem['poll']['options'] as $option){
  575. $output .= "<div class='polloption'>".$option['title']."</div>";
  576. }
  577. $output .= ($logedin ? "<input type='submit' class='vote' id='".$elem['poll']['id']."' value='Send Vote' style='padding:2px;' onClick='return false;'>" : "");
  578. }
  579. return $output;
  580. }
  581. /* this function is used to generate the html code of a reply */
  582. function render_reply($item) {
  583. global $user_settings;
  584. global $logedin;
  585. global $srv;
  586. $reply['mode'] = "";
  587. if (isset($item['type']) && $item['type'] == 'ancestor') {
  588. $reply['mode'] = "ancestor";
  589. }
  590. $reply['id'] = $item['id'];
  591. $reply['uid'] = $item['account']['id'];
  592. $reply['name'] = emojify($item['account']['display_name'], $item['account']['emojis'], 20);
  593. $reply['acct'] = $item['account']['acct'];
  594. $reply['handle'] = "@".explode("@",$item['account']['acct'])[0];
  595. $reply['avatar'] = $item['account']['avatar'];
  596. $reply['menu'] = "<ul>";
  597. if ($logedin) {
  598. $reply['menu'] .= ($item['account']['id'] == $user_settings['uid'] ? "<li><a href='?action=delete&thread=" . $item['id'] . "' onClick='return false;' class='delete fontello' id=':id:'>&#xe80e; Delete Post</a></li>" : "");
  599. $reply['menu'] .= "<li><a href='?action=compose&quote=" . $item['id'] . "' onClick='return false;' class='quote fontello' id='" . $item['id'] . "' style='background-color:transparent;'>&#xf10e; Quote Post</a></li>";
  600. $reply['menu'] .= ($item['account']['id'] != $user_settings['uid'] ? "<li><a href='?action=mute&user=" . $item['account']['id'] . "' onClick='return false;' class='mute fontello' id='" . $item['account']['id'] . "' style='background-color:transparent;'>&#xe81b; Mute User</a></li>" : "");
  601. $reply['menu'] .= ($item['account']['id'] != $user_settings['uid'] ? "<li><a href='?action=mute&thread=" . $item['account']['id'] . "' onClick='return false;' class='muteconv fontello' id='" . $item['id'] . "' style='background-color:transparent;'>&#xf1f7; Drop Thread</a></li>" : "");
  602. $reply['menu'] .= (isset($user_settings['pleroma']) ? "<li><a href='?action=hide&thread=" . $item['pleroma']['conversation_id'] . "' onClick='return false;' class='hide fontello' id='" . $item['pleroma']['conversation_id'] . "' style='background-color:transparent;'>&#xf1f8; Hide Thread</a></li>" : "");
  603. $reply['menu'] .= (isset($user_settings['pleroma']) ? "<li><a href='?action=bookmark&thread=" . $item['account']['id'] . "' onClick='return false;' class='" . ($item['bookmarked'] == true ? "un" : "") . "bookmark fontello' id='" . $item['id'] . "' style='background-color:transparent;'>&#xe81e; " . ($item['bookmarked'] == true ? "Unb" : "B") . "ookmark</a></li>" : "");
  604. $reply['menu'] .= ($item['account']['id'] != $user_settings['uid'] ? "<li><a href='?action=nsfw&user=" . $item['account']['id'] . "' onClick='return false;' class='nsfw fontello' id='" . $item['account']['id'] . "' style='background-color:transparent;'>&#xe829; User is NSFW</a></li>" : "");
  605. }
  606. $reply['menu'] .= "<li><a target='_blank' href='" . $item['url'] . "' class='original link fontello' style='background-color:transparent;'>&#xf14c; Original Note</a></li>";
  607. $reply['menu'] .= "</ul>";
  608. $json['id'] = $item['id'];
  609. $json['scope'] = $item['visibility'];
  610. if ($logedin) {
  611. $json['mentions'] = "";
  612. $array = $item["mentions"];
  613. $json['mentions'] = ($user_settings['acct'] == $item["account"]['acct'] ? "" : "@" . $item["account"]['acct']) . " ";
  614. if (!empty($array)) {
  615. foreach ($array as $mnt) {
  616. if ($mnt['acct'] != $user_settings['acct']) {
  617. $json['mentions'] .= "@" . $mnt['acct'] . " ";
  618. }
  619. }
  620. }
  621. }
  622. $reply['json'] = json_encode($json);
  623. $reply['replyto'] = ($item['in_reply_to_id'] ? " <a class='fontello link preview ldr' target='_blank' id='" . $item['in_reply_to_id'] . "' href='?thread=" . $item['in_reply_to_id'] . "'>&#xf112;</a> " : "");
  624. $reply['text'] = processText($item);
  625. $reply['date'] = "<a class='ldr postAge' id='".strtotime($item['created_at'])."' style='text-decoration:none;' target='_blank' href='?thread=" . $item['id'] . "'>" . time_elapsed_string($item['created_at']) . "</a>";
  626. $reply['visibility'] = $item['visibility'];
  627. $reply['media'] = "";
  628. if (!empty($item['media_attachments'])) {
  629. $reply['media'] = "<div style='width:170px; display:inline-block; float:left; margin:15px 0px 10px 0px;'>";
  630. $images = count($item['media_attachments']);
  631. $class = ($images > 1 ? "class='icon'" : "");
  632. foreach ($item['media_attachments'] as $file) {
  633. $ext = explode(".", $file['url']);
  634. $ext = end($ext);
  635. $ext = explode("?", $ext) [0];
  636. if (in_array($ext,array('webm','mp4','ogv'))) {
  637. $reply['media'] .= "<div style='text-align:center; width:100%;'><video preload='metadata' width='100%' controls ".($user_settings['videoloop'] == "on" ? "loop" : "").">
  638. <source src='" . $file['url'] . "' type='video/".($ext == "ogv" ? "ogg" : $ext)."'>
  639. </video></div>
  640. ";
  641. }
  642. elseif (in_array($ext,array('mp3','ogg','oga','opus'))) {
  643. $reply['media'] .= "<div style='text-align:center; width:100%;'><audio controls>
  644. <source src='" . $file['url'] . "' type='audio/$ext'>
  645. Your browser does not support the audio tag.
  646. </audio> </div>";
  647. }
  648. else {
  649. if ($item['sensitive'] == true && $user_settings['explicit'] != 'off') {
  650. $reply['media'] .= "<div style='overflow:hidden; float:left; margin:2px;' $class><a target='_blank' href='" . $file['url'] . "' onClick='return false;' class='blur'><noscript><img src='" . $file['url'] . "' style='width:100%;'></noscript><img " . "data-src='" . $file['url'] . "'" . " class='' style='max-width:100%; max-height:100% vertical-align:middle;'></a><a target='_blank' href='" . $file['url'] . "' onClick='return false;' class='open-lightbox' style='display:none;'><img src='" . $file['url'] . "' class='' style='width:100%;'></a></div>";
  651. }
  652. else {
  653. $reply['media'] .= "<div style='margin:0px;' $class><a target='_blank' href='" . $file['url'] . "' onClick='return false;' class='open-lightbox'><img src='" . $file['url'] . "'" . " class='' style='max-width:100%; max-height:100%; vertical-align:middle;'><noscript><img src='" . $file['url'] . "' style='width:100%;'></noscript></a></div>";
  654. }
  655. }
  656. }
  657. $reply['media'] .= "</div>";
  658. }
  659. $reply['buttons'] = "
  660. " . ($logedin ? "<div class='felem'><a onClick='return false' class='replyform' href='?thread=" . $item['id'] . "' style='font-family:fontello'>&#xf112;</a></div>" : "") . "
  661. <div class='felem'><a onClick='return false' " . ($logedin ? "class='" . ($item['favourited'] == true ? "unfav" : "fav") . "' href='?action=fav&thread=" . $item['id'] . "'" : "") . " style='font-family:fontello'>&#xe802; <span>" . $item['favourites_count'] . "</span></a></div>
  662. <div class='felem'><a onClick='return false' " . ($logedin && ($item['visibility'] != "private" || $item['visibility'] != "direct") ? "class='" . ($item['reblogged'] == true ? "unreblog" : "reblog") . "' href='?action=reblog&thread=" . $item['id'] . "'" : "") . " style='font-family:fontello'>&#xe83a; <span>" . $item['reblogs_count'] . "</span></a></div>
  663. ";
  664. $result = themes("get","templates/reply.txt");
  665. foreach ($reply as $key => $elem) {
  666. $result = str_replace(":$key:", $elem, $result);
  667. }
  668. return $result;
  669. }
  670. /* this is the same as above but is used on other places, like user bios and places where the
  671. shortcodes and the emoji url is defined in the same place */
  672. function emojify($string, $emojis, $size = 40) {
  673. foreach ($emojis as $emoji) {
  674. $string = str_replace(":" . $emoji['shortcode'] . ":", "<img class='emoji' alt='" . $emoji['shortcode'] . "' title='" . $emoji['shortcode'] . "' src='" . $emoji['url'] . "' height=$size style='vertical-align: middle;'>", $string);
  675. }
  676. return $string;
  677. }
  678. /* This function displays the emoji list of an instance based on a search
  679. string given on $val */
  680. function emoji_list($val){
  681. $emojilist = api_get("/custom_emojis");
  682. $c = 0;
  683. $return = "";
  684. foreach ($emojilist as $emoji){
  685. if (starts_with($emoji['shortcode'],$val) && $c < 50){
  686. $return .= "<img style='margin:1px;' src='".$emoji['static_url']."' class='emoji' title='".$emoji['shortcode']."' height=40>";
  687. $c++;
  688. }
  689. }
  690. if ($c < 50){
  691. foreach ($emojilist as $emoji){
  692. if ((contains($emoji['shortcode'],$val) && !starts_with($emoji['shortcode'],$val)) && $c < 50){
  693. $return .= "<img style='margin:1px;' src='".$emoji['static_url']."' class='emoji' title='".$emoji['shortcode']."' height=40>";
  694. $c++;
  695. }
  696. }
  697. }
  698. return $return;
  699. }
  700. function contact_search($val){
  701. global $user_settings;
  702. $return = "";
  703. $list = api_get("/accounts/search?q=".$val);
  704. foreach ($list as $contact){
  705. $return .= "<div class='contact' title='@".$contact['acct']."' style='width:100%; clear:both; height:40px; display:inline-block;'>
  706. <div style='width:40px; height:40px; background-size:cover; background-image:url(".$contact['avatar']."); float:left;'></div>
  707. <div>
  708. <span style='font-weight:bold;'>".emojify($contact['display_name'], $contact['emojis'], 15)."</span><br>
  709. <span style='font-size:12px;'>".$contact['acct']."</span>
  710. </div>
  711. </div>";
  712. }
  713. return $return;
  714. }
  715. /* This function will fetch and render all the notifications since an $id
  716. or get a list of all past notification ($max notifications specified)
  717. */
  718. function getnotif($id = false, $max = false) {
  719. global $srv;
  720. global $token;
  721. global $user_settings;
  722. $n = "";
  723. $exclude = "";
  724. $exclude .= (str_split($user_settings['notif'])[0] == 0 ? "&exclude_types[]=favourite" : "");
  725. $exclude .= (str_split($user_settings['notif'])[1] == 0 ? "&exclude_types[]=reblog" : "");
  726. $exclude .= (str_split($user_settings['notif'])[2] == 0 ? "&exclude_types[]=mention" : "");
  727. $exclude .= (str_split($user_settings['notif'])[3] == 0 ? "&exclude_types[]=follow" : "");
  728. $notif = api_get("notifications?" . ($id == false ? "limit=9&" : "") . ($id != false ? ($max == true ? "max_id=$id" : "since_id=$id") : "").$exclude);
  729. if (!empty($notif)) {
  730. foreach ($notif as $post) {
  731. if (!isset($post["type"])){
  732. break;
  733. }
  734. $user = "<a class='link ldr uname' style='font-size:12px;' href='?user=" . $post['account']['id'] . "'>" . (empty($post['account']['display_name']) ? $post['account']['acct'] : emojify($post['account']['display_name'], $post['account']['emojis'], 10)) . "</a>";
  735. $preview = "";
  736. $buttons = "";
  737. $media = "";
  738. if (!in_array($post["type"],array("mention","favourite","reblog","follow"))){
  739. continue;
  740. }
  741. switch ($post["type"]) {
  742. case "mention":
  743. if ($post['status']['in_reply_to_id'] == null) {
  744. $type = "<span class='fontello' style='color:#62C2CC; font-size:10px;'>&#xf10d;</span>";
  745. $string = "mentioned you in a post";
  746. $preview = "<a style='text-decoration:none;' class='ldr text' href='?thread=" . $post['status']['id'] . "' target='_blank'><span style='display:block; opacity:1; font-size:10px; line-height:12px;'>" . emojify(strip_tags(trim($post['status']['content']) , '<br><br \>') , $post['status']['emojis'], 15) . "</span></a>";
  747. $media = (!empty($post['status']['media_attachments']) ? "<a style='text-decoration:none;' class='ldr' href='?thread=" . $post['status']['id'] . "' target='_blank'><div class='notifpic' style='flex: 0 0 60px; background-size:cover; background-image:url(" . $post['status']['media_attachments'][0]['url'] . ");'></div></a>" : "");
  748. }
  749. else {
  750. $type = "<span class='fontello' style='color:#62C2CC; font-size:10px;'>&#xf112;</span>";
  751. $string = "replied to your post";
  752. foreach ($post['status']['mentions'] as $mention) {
  753. if(!contains($post['status']['content'],$mention['username'])) {
  754. $post['status']['content'] = "@" . $mention['username'] . " ".$post['status']['content'];
  755. }
  756. }
  757. $preview = "<a style='text-decoration:none;' class='ldr text' href='?thread=" . $post['status']['id'] . "' target='_blank'><span style='display:block; opacity:1; font-size:10px; line-height:12px;'>" . emojify(strip_tags(trim($post['status']['content']) , '<br><br \>') , $post['status']['emojis'], 15) . "</span></a>";
  758. $media = (!empty($post['status']['media_attachments']) ? "<div class='notifpic' style='flex: 0 0 60px; background-size:cover; background-image:url(" . $post['status']['media_attachments'][0]['url'] . ");'></div>" : "");
  759. }
  760. $array = $post['status']["mentions"];
  761. $mentions = ($user_settings['acct'] == $post['status']['account']['acct'] ? "" : "@" . $post['status']['account']['acct']) . " ";
  762. if (!empty($array)) {
  763. foreach ($array as $mnt) {
  764. if ($mnt['acct'] != $user_settings['acct']) {
  765. $mentions .= "@" . $mnt['acct'] . " ";
  766. }
  767. }
  768. }
  769. $buttons = "<div class='post_buttons' id='" . $post['status']['id'] . "' style='position:absolute; right:10px; bottom:10px; border-radius:60px; padding:5px;'>
  770. <div class='felem'><a onClick='return false' class='quickreply' id='" . $post['status']['id'] . "' data-mentions='" . $mentions . "' href='?thread=" . $post['status']['id'] . "' style='font-family:fontello'>&#xe824;</a></div>
  771. <div class='felem'><a onClick='return false' class='" . ($post['status']['favourited'] == true ? "unfav" : "fav") . "' href='?action=fav&thread=" . $post['status']['id'] . "'" . " style='font-family:fontello'>&#xe802;</a></div>
  772. <div class='felem'><a onClick='return false' " . ($post['status']['visibility'] == "public" || $post['status']['visibility'] == "unlisted" ? "class='" . ($post['status']['reblogged'] == true ? "unreblog" : "reblog") . "' href='?action=reblog&thread=" . $post['status']['id'] . "'" : "") . " style='font-family:fontello'>&#xe83a;</a></div></div>";
  773. break;
  774. case "favourite":
  775. $type = "<span class='fontello' style='color:#F17022; font-size:10px;'>&#xe802;</span>";
  776. $string = "favourited your post";
  777. $preview = "<a style='text-decoration:none;' class='ldr text' href='?thread=" . $post['status']['id'] . "' target='_blank'><span style='display:block; opacity:1; font-size:10px; line-height:12px;'>" . (!empty($post['status']['content']) ? emojify(strip_tags(trim($post['status']['content']) , '<br><br \>') , $post['status']['emojis'], 15) : "Favourited your image") . "</span></a>";
  778. $media = (!empty($post['status']['media_attachments']) ? "<div class='notifpic' style='flex: 0 0 60px; background-size:cover; background-image:url(" . $post['status']['media_attachments'][0]['url'] . ");'></div>" : "");
  779. break;
  780. case "reblog":
  781. $type = "<span class='fontello' style='color:#D1DC29; font-size:10px;'>&#xe826;</span>";
  782. $string = "reblogged your post";
  783. $preview = "<a style='text-decoration:none;' class='ldr text' href='?thread=" . $post['status']['id'] . "' target='_blank'><span style='display:block; opacity:1; font-size:10px; line-height:12px;'>" . (!empty($post['status']['content']) ? emojify(strip_tags(trim($post['status']['content']) , '<br><br \>') , $post['status']['emojis'], 15) : "Reblogged your image") . "</span></a>";
  784. @$media = (!is_null($post['status']['media_attachments']) ? "<div class='notifpic' style='flex: 0 0 60px; background-size:cover; background-image:url(" . $post['status']['media_attachments'][0]['url'] . ");'></div>" : "");
  785. break;
  786. case "follow":
  787. list($info, $rel) = user_info($post["account"]["id"]);
  788. $type = "<span class='fontello' style='color:#FDB813; font-size;10px;'>&#xf234;</span>";
  789. $preview = "started following you";
  790. if ($rel[0]['following']) {
  791. $label = "&#xe80c; Following";
  792. $class = "unfollow";
  793. }
  794. else {
  795. if ($info['locked']) {
  796. if ($rel[0]['requested']) {
  797. $label = "&#xe806; Follow Requested";
  798. $class = "unfollow";
  799. }
  800. else {
  801. $label = "&#xe806; Request Follow";
  802. $class = "follow";
  803. }
  804. }
  805. else {
  806. $label = "&#xf234; Follow";
  807. $class = "follow";
  808. }
  809. }
  810. $buttons .= "<div class='post_buttons' style='position:absolute; right:10px; bottom:10px; border-radius:60px; padding:5px;'><span id='" . $info['id'] . "' class='profileButton $class' style='background-color:white; font-family:sans,fontello ;font-size:13px;'>$label</span></div>";
  811. break;
  812. }
  813. $n .= "
  814. <div class='notif " . ($id == false ? "" : "new") . "' id='" . $post['id'] . "'>
  815. <div class='notifContents'>
  816. <div style='flex: 0 0 60px; background-size:cover; background-image:url(" . $post['account']['avatar'] . "); border-radius:5px;'></div>
  817. <div style='flex: 1; padding-left:5px; padding-right:5px; word-break: break-word; overflow:hidden;'>
  818. <span>$type <span style='font-size:12px; font-weight:bold;'>$user</span></span>
  819. " . trim($preview) . "
  820. $buttons
  821. </div>
  822. $media
  823. </div>
  824. </div>
  825. ";
  826. }
  827. return $n;
  828. }
  829. }
  830. /* function to parse opengraph from a html source */
  831. /* taken from https://ajaxhispano.com/ask/como-obtener-el-protocolo-open-graph-de-una-pagina-web-por-php-109483/ */
  832. function getOgTags($html)
  833. {
  834. $pattern='/<\s*meta\s+property="og:([^"]+)"\s+content="([^"]*)/i';
  835. if(preg_match_all($pattern, $html, $out))
  836. return array_combine($out[1], $out[2]);
  837. return array();
  838. }
  839. /* this function takes in a whole post entity and spits out the HTMLfied text of the post
  840. with the urls and @handles linkified and all the emojis replaced */
  841. function processText($elem) {
  842. global $user_settings;
  843. global $logedin;
  844. require_once "vendor/simple_html_dom.php";
  845. $content = trim(html_entity_decode($elem['content'],ENT_QUOTES));
  846. $content = preg_replace("/<(?=[^>]*(?:<|$))/","&lt;",$content);
  847. if (!empty($content)) {
  848. $html = str_get_html($content);
  849. foreach ($html->find('a') as $lnk) {
  850. //remove text links to media attachments
  851. foreach ($elem['media_attachments'] as $f) {
  852. if (is_numeric(strpos($f['description'],explode("…",$lnk->innertext)[0]))) {
  853. $content = str_replace($lnk->outertext . "<br/>", null, $content);
  854. $content = str_replace("<br/>" . $lnk->outertext, null, $content);
  855. $content = str_replace($lnk->outertext, null, $content);
  856. }
  857. }
  858. //modify links for hashtags and external urls
  859. if (is_numeric(strpos($lnk->href, $user_settings['instance'])) || in_array($lnk->class, array(
  860. "u-url mention",
  861. "hashtag"
  862. )) || $lnk->rel == "tag") {
  863. $content = str_replace($lnk->outertext, $lnk->innertext, $content);
  864. }
  865. else {
  866. $prv = $lnk->outertext;
  867. $lnk->target = '_blank';
  868. $lnk->class = 'link external';
  869. $content = str_replace($prv, $lnk->outertext, $content);
  870. }
  871. }
  872. }
  873. $result = strip_tags($content, '<br><p><strong><a><em><strike>');
  874. $result = str_replace('<br />', ' <br>', $result);
  875. foreach ($elem['mentions'] as $mention) {
  876. if(contains($result,"@".$mention['username'])) {
  877. $result = str_replace("@" . $mention['username'], "<span class='user' id='" . $mention['id'] . "'><a href='?user=" . $mention['id'] . "' class='link ldr' onClick='return false;'>@" . $mention['username'] . "</a></span>", $result);
  878. } else {
  879. $result = "<span class='user' id='" . $mention['id'] . "'><a href='?user=" . $mention['id'] . "' class='link ldr' onClick='return false;'>@" . $mention['username'] . "</a></span> ".$result;
  880. }
  881. }
  882. $result = emojify($result, $elem['emojis']);
  883. /* We convert hashtags to clickable links. The regex detects only strings that are not part of an url.
  884. If the user is not logged in, it just shows the hashtag in bold.
  885. Regex expression got it from here https://stackoverflow.com/questions/39414007/php-find-all-hashtags-but-no-in-link
  886. */
  887. if ($logedin){
  888. $result = preg_replace("!(?:f|ht)tps?://[-a-zA-Zа-яА-Я()0-9@:%_+.~#?&;/=]+(*SKIP)(*F)|#(\w+)!", "<a class='ldr' href=\"./?tag=$1\"><b>#$1</b></a>", $result);
  889. } else {
  890. $result = preg_replace("!(?:f|ht)tps?://[-a-zA-Zа-яА-Я()0-9@:%_+.~#?&;/=]+(*SKIP)(*F)|#(\w+)!", "<b>#$1</b>", $result);
  891. }
  892. return $result;
  893. }
  894. // OTHER FUNCTIONS
  895. /* the purpose of this function is to encode the auth token
  896. it is not used for now */
  897. function msc($string, $action = 'e') {
  898. // you may change these values to your own
  899. $secret_key = 'yAmfVhZwm0749FSY24dC';
  900. $secret_iv = 'm37uvAeKjYLKdI1lPkcJ';
  901. $output = false;
  902. $encrypt_method = "AES-256-CBC";
  903. $key = hash('sha256', $secret_key);
  904. $iv = substr(hash('sha256', $secret_iv) , 0, 16);
  905. if ($action == 'e') {
  906. $output = base64_encode(openssl_encrypt($string, $encrypt_method, $key, 0, $iv));
  907. }
  908. else if ($action == 'd') {
  909. $output = openssl_decrypt(base64_decode($string) , $encrypt_method, $key, 0, $iv);
  910. }
  911. return $output;
  912. }
  913. /* this function extracts the urls from a text and return them in an array */
  914. function get_urls($input) {
  915. $pattern = '$(https?://[a-z0-9_./?=&-~]+)(?![^<>]*>)$i';
  916. if (preg_match_all($pattern, $input, $matches)) {
  917. list($dummy, $links) = ($matches);
  918. return $links;
  919. }
  920. return false;
  921. }
  922. /* general function to check if one strings starts with a given search */
  923. function starts_with($string,$search){
  924. if (substr(strtolower($string),0,strlen($search)) == strtolower($search)){
  925. return true;
  926. }
  927. return false;
  928. }
  929. /* general function to check if one strings contains with a given search */
  930. function contains($string,$search){
  931. if (is_numeric(strpos(strtolower($string),strtolower($search)))){
  932. return true;
  933. }
  934. return false;
  935. }
  936. /* same as avobe but check against all elements of an array */
  937. function contains_any($where, $array)
  938. {
  939. $n = 1;
  940. foreach ($array as $elem)
  941. {
  942. if (is_numeric(strpos($where, $elem)))
  943. {
  944. return $n;
  945. }
  946. $n++;
  947. }
  948. return false;
  949. }
  950. /* this function just reduces an image to a 1x1 pixel image to get the overall color.
  951. */
  952. function averageColor($url) {
  953. @$image = imagecreatefromstring(file_get_contents($url));
  954. if (!$image) {
  955. $mainColor = "CCCCCC";
  956. }
  957. else {
  958. $thumb = imagecreatetruecolor(1, 1);
  959. imagecopyresampled($thumb, $image, 0, 0, 0, 0, 1, 1, imagesx($image) , imagesy($image));
  960. $mainColor = strtoupper(dechex(imagecolorat($thumb, 0, 0)));
  961. }
  962. return $mainColor;
  963. }
  964. /* function used in the process of uploading a file */
  965. function get_mime($filename) {
  966. $result = new finfo();
  967. if (is_resource($result) === true) {
  968. return $result->file($filename, FILEINFO_MIME_TYPE);
  969. }
  970. return false;
  971. }
  972. function sanitize($text){
  973. return preg_replace("/[^a-zA-Z0-9.]+/", "", $text);
  974. }
  975. function themes($mode,$name = false){
  976. global $user_settings;
  977. switch ($mode){
  978. case "list":
  979. $themes = scandir("themes/");
  980. $themelist = array();
  981. foreach ($themes as $elem){
  982. if ($elem != ".." && $elem != "." && $elem != "custom" && is_dir("themes/".$elem)){
  983. $themelist[] = $elem;
  984. }
  985. }
  986. return $themelist;
  987. case "file":
  988. $theme = sanitize($user_settings['theme']);
  989. if (file_exists("themes/$theme/$name")){
  990. return "themes/$theme/$name";
  991. } else {
  992. return "$name";
  993. }
  994. case "get":
  995. $theme = sanitize($user_settings['theme']);
  996. if (file_exists("themes/$theme/$name")){
  997. return file_get_contents("themes/$theme/$name");
  998. } else {
  999. return file_get_contents("$name");
  1000. }
  1001. }
  1002. }
  1003. function time_elapsed_string($datetime, $full = false) {
  1004. $now = new DateTime;
  1005. $ago = new DateTime($datetime);
  1006. $diff = $now->diff($ago);
  1007. $diff->w = floor($diff->d / 7);
  1008. $diff->d -= $diff->w * 7;
  1009. $string = array(
  1010. 'y' => 'year',
  1011. 'm' => 'month',
  1012. 'w' => 'week',
  1013. 'd' => 'day',
  1014. 'h' => 'hour',
  1015. 'i' => 'minute',
  1016. 's' => 'second',
  1017. );
  1018. foreach ($string as $k => &$v) {
  1019. if ($diff->$k) {
  1020. $v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : '');
  1021. } else {
  1022. unset($string[$k]);
  1023. }
  1024. }
  1025. if (!$full) $string = array_slice($string, 0, 1);
  1026. return $string ? implode(', ', $string) . ' ago' : 'just now';
  1027. }
  1028. function getHeaders($respHeaders) {
  1029. $headers = array();
  1030. $headerText = substr($respHeaders, 0, strpos($respHeaders, "\r\n\r\n"));
  1031. foreach (explode("\r\n", $headerText) as $i => $line) {
  1032. if ($i === 0) {
  1033. $headers['http_code'] = $line;
  1034. } else {
  1035. list ($key, $value) = explode(': ', $line);
  1036. $headers[$key] = $value;
  1037. }
  1038. }
  1039. return $headerText;
  1040. }