<?php /* this file stores all of the functions that are used over all of the other files. */ ini_set("log_errors", 1); $srv = $user_settings['instance']; //$token = ($token != false ? msc($token,'d') : false); $token = ($token != false ? $token : false); // FUNCTIONS THAT HAVE TO DO WITH INSTANCE COMMUNICATION AND RETRIEVAL /* a function to make an authenticated general GET api call to the logged-in instance. - $url is a string of an api call like "account/:id/statuses" - returns the array conversion of the json response */ function api_get($url) { global $srv; global $token; $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, "https://$srv/api/v1/" . $url); if (!is_null($token)) { curl_setopt($curl, CURLOPT_HTTPHEADER, array( 'Authorization: Bearer ' . $token )); } curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $result = curl_exec($curl); curl_close($curl); return json_decode($result, true); } /* same as above but used in some newer api endpoinds (v2) */ function api_getv2($url) { global $srv; global $token; $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, "https://$srv/api/v2/" . $url); if (!is_null($token)) { curl_setopt($curl, CURLOPT_HTTPHEADER, array( 'Authorization: Bearer ' . $token )); } curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $result = curl_exec($curl); curl_close($curl); return json_decode($result, true); } /* a function to make an authenticated general POST api call to the logged-in instance. - $url is a string of an api call like "account/:id/statuses" - returns the array conversion of the json response */ function api_post($url, $array) { global $srv; global $token; $cSession = curl_init(); curl_setopt($cSession, CURLOPT_HEADER, false); curl_setopt($cSession, CURLOPT_POST, 1); curl_setopt($cSession, CURLOPT_URL, "https://$srv/api/v1/" . $url); if (!is_null($token)) { curl_setopt($cSession, CURLOPT_HTTPHEADER, array( 'Authorization: Bearer ' . $token )); } curl_setopt($cSession, CURLOPT_POSTFIELDS, http_build_query($array)); curl_setopt($cSession, CURLOPT_RETURNTRANSFER, true); $result = curl_exec($cSession); curl_close($cSession); return json_decode($result, true); } /* a function to make an authenticated general DELETE api call to the logged-in instance. - $url is a string of an api call like "statuses/delete/:id" - returns the array conversion of the json response */ function api_delete($url, $array) { global $srv; global $token; $cSession = curl_init(); curl_setopt($cSession, CURLOPT_HEADER, false); curl_setopt($cSession, CURLOPT_POST, 1); curl_setopt($cSession, CURLOPT_URL, "https://$srv/api/v1/" . $url); curl_setopt($cSession, CURLOPT_CUSTOMREQUEST, "DELETE"); if (!is_null($token)) { curl_setopt($cSession, CURLOPT_HTTPHEADER, array( 'Authorization: Bearer ' . $token )); } curl_setopt($cSession, CURLOPT_POSTFIELDS, http_build_query($array)); curl_setopt($cSession, CURLOPT_RETURNTRANSFER, true); $result = curl_exec($cSession); curl_close($cSession); return json_decode($result, true); } /* a function to make an authenticated general PATCH api call to the logged-in instance. - $url is a string of an api call like "account/:id/statuses" - returns the array conversion of the json response */ function api_patch($url, $array) { global $srv; global $token; $cSession = curl_init(); curl_setopt($cSession, CURLOPT_HEADER, false); curl_setopt($cSession, CURLOPT_POST, 1); curl_setopt($cSession, CURLOPT_URL, "https://$srv/api/v1/" . $url); curl_setopt($cSession, CURLOPT_CUSTOMREQUEST, "PATCH"); if (!is_null($token)) { curl_setopt($cSession, CURLOPT_HTTPHEADER, array( 'Authorization: Bearer ' . $token )); } curl_setopt($cSession, CURLOPT_POSTFIELDS, http_build_query($array)); curl_setopt($cSession, CURLOPT_RETURNTRANSFER, true); $result = curl_exec($cSession); curl_close($cSession); return json_decode($result, true); } /* Function to upload files to the profile of the authenticated user - $type can be 'avatar' or 'header' - returns the json of the api call */ function upload_profile($file,$type){ global $srv; global $token; $mime = get_mime($file); $info = pathinfo($file); $name = $info['basename']; $output = new CURLFile($file, $mime, $name); $cSession = curl_init(); curl_setopt($cSession, CURLOPT_URL, "https://$srv/api/v1/accounts/update_credentials"); curl_setopt($cSession, CURLOPT_RETURNTRANSFER, true); curl_setopt($cSession, CURLOPT_POST, 1); curl_setopt($cSession, CURLOPT_CUSTOMREQUEST, "PATCH"); curl_setopt($cSession, CURLOPT_HTTPHEADER, array( 'Authorization: Bearer ' . $token )); curl_setopt($cSession, CURLOPT_POSTFIELDS, array( $type => $output )); $result = curl_exec($cSession); curl_close($cSession); return $result; } /* this function fetches all the data from a profile (bio, username, relationships, etc) - $user is the id of the queried user - returns the array conversion of the json response */ function user_info($user) { global $user_settings; $info = api_get("accounts/" . $user); $rel = api_get("accounts/relationships?id=" . $user); return array( $info, $rel ); } /* this function fetches the context (the previous posts and replies) of a specified post - $post = ID of the post queried. - returns an array conversion of the json response */ function context($post) { global $srv; global $token; $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, "https://$srv/api/v1/statuses/$post/context"); if (!is_null($token)) { curl_setopt($curl, CURLOPT_HTTPHEADER, array( 'Authorization: Bearer ' . $token )); } curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $result = curl_exec($curl); curl_close($curl); return $result; } /* a function to fav or unfav a specified post - $post = ID of the post queried. - $mode can be true if is a fav or false if it's an unfav - returns the number of favs of the post after the specified action or "error" if there was an error performing the action */ function favourite($post, $mode) { $result = api_post(($mode == true ? "statuses/$post/favourite" : "statuses/$post/unfavourite"),array()); if (isset($result['favourites_count'])) { return $result['favourites_count']; } else { return "error"; } } /* a function to reblog or unreblog a specified post - $post = ID of the post queried. - $mode can be true if is a reblog or false if it's an unreblog - returns the number of reblogs of the post after the specified action or "error" if there was an error performing the action */ function reblog($post, $mode) { $result = api_post(($mode == true ? "statuses/$post/reblog" : "statuses/$post/unreblog"),array()); if (isset($result['reblog']['reblogs_count'])) { return $result['reblog']['reblogs_count']; } elseif (isset($result['reblogs_count'])) { return $result['reblogs_count']; } else { return "error"; } } /* function to delete a post - $id is the id of the post to delete - returns 1 if the post was deleted succesfully or 0 if there was an error */ function delpost($id) { global $srv; global $token; if (!is_null($token)) { $curl = curl_init(); curl_setopt($curl, CURLOPT_HEADER, false); curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_URL, "https://$srv/api/v1/statuses/$id"); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE"); curl_setopt($curl, CURLOPT_HTTPHEADER, array( 'Authorization: Bearer ' . $token )); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $result = curl_exec($curl); curl_close($curl); $result = json_decode($result, true); if (empty($result)) { return "1"; } else { return "0"; } } } /* function to issue a vote to a poll - $id is the id of the poll to vote on - $choices is a comma separated string of the choices that will be voted. */ function vote($poll, $choices) { global $srv; global $token; if (!is_null($token)) { $cSession = curl_init(); curl_setopt($cSession, CURLOPT_URL, "https://$srv/api/v1/polls/$poll/votes"); curl_setopt($cSession, CURLOPT_RETURNTRANSFER, true); curl_setopt($cSession, CURLOPT_POST, 1); curl_setopt($cSession, CURLOPT_HTTPHEADER, array( 'Authorization: Bearer ' . $token )); $query = ""; $choicelist = explode(",",$choices); foreach($choicelist as $choice){ $query .= "choices[]=$choice&"; } curl_setopt($cSession, CURLOPT_POSTFIELDS, $query); $result = curl_exec($cSession); curl_close($cSession); return $result; } else { return false; } } /* function to send a new post to the logged in instance - $text = the body of the message - $media = array of uploaded media id's - $reply = the id of a post being replied to, can be null. - $markdown = specify if the post uses markdown (unused at this moment) - $scope = the scope of the post (public, private, unlisted or direct) - $sensitive = bool to specify if the post media is sensitive - $spoiler = string of the title of the post - returns the json of the api response */ function sendpost($text, $media, $reply = null, $markdown = false, $scope = "public", $sensitive = false, $spoiler = false) { global $srv; global $token; if (!is_null($token)) { $cSession = curl_init(); curl_setopt($cSession, CURLOPT_URL, "https://$srv/api/v1/statuses"); curl_setopt($cSession, CURLOPT_RETURNTRANSFER, true); curl_setopt($cSession, CURLOPT_POST, 1); curl_setopt($cSession, CURLOPT_HTTPHEADER, array( 'Authorization: Bearer ' . $token )); $query = ""; $query .= "status=" . urlencode(html_entity_decode($text, ENT_QUOTES)) . "&visibility=" . $scope;; if (!is_null($reply) && $reply != "null") { $query .= "&in_reply_to_id=" . $reply; } if ($markdown == true) { $query .= "&content_type=text/markdown"; } if ($sensitive == 'true') { $query .= "&sensitive=true"; } if ($spoiler == true) { $query .= "&spoiler_text=" . $spoiler; } if (!is_null($media)) { foreach ($media as $mid) { $query .= "&media_ids[]=" . $mid; } } curl_setopt($cSession, CURLOPT_POSTFIELDS, $query); $result = curl_exec($cSession); curl_close($cSession); return $result; } else { return false; } } /* uploads a file to the logged in instance. - $file = path of the file to upload on local storage - returns an array where: 0: the ID of the uploaded file 1: the url of the file (if the file isn't an image, returns a placeholder) */ function uploadpic($file) { global $srv; global $token; if (!is_null($token)) { $mime = get_mime($file); $info = pathinfo($file); $name = $info['basename']; $output = new CURLFile($file, $mime, $name); $cSession = curl_init(); curl_setopt($cSession, CURLOPT_URL, "https://$srv/api/v1/media"); curl_setopt($cSession, CURLOPT_RETURNTRANSFER, true); curl_setopt($cSession, CURLOPT_POST, 1); curl_setopt($cSession, CURLOPT_HTTPHEADER, array( 'Authorization: Bearer ' . $token )); curl_setopt($cSession, CURLOPT_POSTFIELDS, array( 'file' => $output )); $result = curl_exec($cSession); curl_close($cSession); $array = json_decode($result, true); $ext = explode(".", $array['url']); $ext = end($ext); $ext = explode("?", $ext) [0]; if (in_array($ext, array( 'jpg', 'jpeg', 'gif', 'png', 'svg' ))) { $file = $array['url']; } else { $file = "img/doc.png"; } return json_encode(array( $array['id'], $file )); } else { return false; } } /* this is used to register DashFE as an application on an instance mostly used when logging in - $instance = the url of the instance where to log in - returns the array conversion of the json response */ function register_app($instance) { global $setting; $cSession = curl_init(); curl_setopt($cSession, CURLOPT_URL, "https://$instance/api/v1/apps"); curl_setopt($cSession, CURLOPT_RETURNTRANSFER, true); curl_setopt($cSession, CURLOPT_HEADER, false); curl_setopt($cSession, CURLOPT_POST, 1); curl_setopt($cSession, CURLOPT_POSTFIELDS, http_build_query(array( 'client_name' => $setting['appname'], 'redirect_uris' => $setting['url'], 'scopes' => 'read write follow' ))); $result = curl_exec($cSession); curl_close($cSession); return json_decode($result, true); } /* this function will get all the notes (reblogs and favs) that has an specified post - $thread = the id of the post queried - returns an array with all the notes each note is another array where: 0 = type of note ("reb" reblog or "fab" favorite) 1 = array of the details of the user, converted from the json of the api response. */ function getnotes($thread) { global $user_settings; global $token; global $srv; global $setting; global $logedin; @$reb = array( api_get("statuses/" . $thread . "/reblogged_by") ); @$fab = array( api_get("statuses/" . $thread . "/favourited_by") ); $limit = (count($reb[0]) > count($fab[0]) ? count($reb[0]) - 1 : count($fab[0]) - 1); $notes = array(); $index = 0; for ($i = 0;$i <= $limit;$i++) { if (isset($reb[0][$i])) { $notes[$index][0] = "reb"; $notes[$index][1] = $reb[0][$i]; $index++; } if (isset($fab[0][$i])) { $notes[$index][0] = "fav"; $notes[$index][1] = $fab[0][$i]; $index++; } } return $notes; } /* this function will fetch replies of a post - $thread = the id of the post from where to fetch replies - $since = id of a post. If specified, the function will fetch the replies only since the specified id. - returns an array with all the replies each element is another array where: 'mode' = type of the reply (ancestor or descendant) 'content' = array of the contents of the reply, converted from the json of the api response. */ function getreplies($thread, $since = false) { global $user_settings; global $token; global $srv; global $setting; global $logedin; $context = json_decode(context($thread) , true); $array = array(); if (!empty($context['ancestors'])) { if ($since == false) { foreach ($context['ancestors'] as $elem) { $elem['type'] = 'ancestor'; $array[] = $elem; } } } $flag = 0; if (!empty($context['descendants'])) { foreach ($context['descendants'] as $elem) { if (($since != false && $flag == 1) || $since == false) { $elem['type'] = 'descendant'; $array[] = $elem; } if ($since != false && $elem['id'] == $since) { $flag = 1; } } } $replies = array(); foreach ($array as $item) { $reply['mode'] = ""; if ($item['type'] == 'ancestor') { $reply['mode'] = "ancestor"; } $replies[] = array( 'mode' => $reply['mode'], 'content' => $item ); } return $replies; } /* this function takes some options from the init.php file and the user_settings cookie and fetches all the posts of the appropiate timeline - $query = an array with a set of elements generated by the file "include/init.php" - returns an array of the posts list fetched converted from the json response of the api. */ function timeline($query) { global $token; global $srv; $notes = ""; $hq = array(); $hq['limit'] = 10; $hq['only_media'] = ($query['text'] == "off" ? 'true' : 'false'); if ($query['next']){ $hq['max_id'] = $query['next']; $next = $query['next']; } elseif ($query['since']) { $hq['since_id'] = $query['since']; } switch ($query['mode']) { case "home": $array = api_get("timelines/home?".http_build_query($hq)); break; case "federated": $array = api_get("timelines/public?".http_build_query($hq)); break; case "tag": $array = api_get("timelines/tag/" . $query['tag'] . "?".http_build_query($hq)); break; case "local": $array = api_get("timelines/public?local=true&".http_build_query($hq)); break; case "user": $array = api_get("accounts/" . $query['user'] . "/statuses?".http_build_query($hq)); break; case "thread": $array = array( api_get("statuses/" . $query['thread']) ); break; case "favourites": $array = api_get("favourites?".http_build_query($hq)); break; case "direct": $array = api_get("timelines/direct?".http_build_query($hq)); break; case "list": $array = api_get("timelines/list/" . $query['list'] . "?".http_build_query($hq)); break; case "bookmarks": $array = api_get("bookmarks?".http_build_query($hq)); break; case "search": $array = api_getv2("search?limit=40&q=".$query['search']."{$next}")['statuses']; break; case "account": $info = api_get("accounts/verify_credentials"); $array = api_get("accounts/" . $info['id'] . "/statuses?".http_build_query($hq)); break; default: $array = api_get("timelines/public?".http_build_query($hq)); break; } if (!is_array($array)) { return false; } $next = end($array) ['id']; $thread = array(); /* foreach ($array as $elem) { if ($query['replies'] == "on" || $query['mode'] == "thread") { $thread[] = $elem; } else { if ($elem['in_reply_to_id'] == null) { $thread[] = $elem; } } }*/ foreach ($array as $elem) { if ($query['replies'] == "on" || $query['mode'] == "thread") { $thread[] = $elem; } else { if ($elem['in_reply_to_id'] == null || $elem['in_reply_to_account_id'] == $query['uid']) { $thread[] = $elem; } else { $rel = api_get("accounts/relationships?id=" . $elem['in_reply_to_account_id']); if ($rel[0]['following']){ $thread[] = $elem; } } } } return $thread; } // FUNCTIONS THAT HAVE TO DO WITH RENDERING STUFF FOR THE PAGE /* this function is used to generate the html code of a poll */ function renderPoll($elem) { global $logedin; $output = ""; $output .= "<br>"; $votes = $elem['poll']['votes_count']; if ($elem['poll']['voted'] || $elem['poll']['expired']) { $output.= "<b>Votes: $votes</b><br>"; foreach ($elem['poll']['options'] as $option){ $percentage = ($option['votes_count'] / $votes ) * 100; $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>"; } } else { foreach ($elem['poll']['options'] as $option){ $output .= "<div class='polloption'>".$option['title']."</div>"; } $output .= ($logedin ? "<input type='submit' class='vote' id='".$elem['poll']['id']."' value='Send Vote' style='padding:2px;' onClick='return false;'>" : ""); } return $output; } /* this function is used to generate the html code of a reply */ function render_reply($item) { global $user_settings; global $logedin; global $srv; $reply['mode'] = ""; if (isset($item['type']) && $item['type'] == 'ancestor') { $reply['mode'] = "ancestor"; } $reply['id'] = $item['id']; $reply['uid'] = $item['account']['id']; $reply['name'] = emojify($item['account']['display_name'], $item['account']['emojis'], 20); $reply['acct'] = $item['account']['acct']; $reply['handle'] = "@".explode("@",$item['account']['acct'])[0]; $reply['avatar'] = $item['account']['avatar']; $reply['menu'] = "<ul>"; if ($logedin) { $reply['menu'] .= ($item['account']['id'] == $user_settings['uid'] ? "<li><a href='?action=delete&thread=" . $item['id'] . "' onClick='return false;' class='delete fontello' id=':id:'> Delete Post</a></li>" : ""); $reply['menu'] .= "<li><a href='?action=compose"e=" . $item['id'] . "' onClick='return false;' class='quote fontello' id='" . $item['id'] . "' style='background-color:transparent;'> Quote Post</a></li>"; $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;'> Mute User</a></li>" : ""); $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;'> Drop Thread</a></li>" : ""); $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;'> Hide Thread</a></li>" : ""); $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;'> " . ($item['bookmarked'] == true ? "Unb" : "B") . "ookmark</a></li>" : ""); $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;'> User is NSFW</a></li>" : ""); } $reply['menu'] .= "<li><a target='_blank' href='" . $item['url'] . "' class='original link fontello' style='background-color:transparent;'> Original Note</a></li>"; $reply['menu'] .= "</ul>"; $json['id'] = $item['id']; $json['scope'] = $item['visibility']; if ($logedin) { $json['mentions'] = ""; $array = $item["mentions"]; $json['mentions'] = ($user_settings['acct'] == $item["account"]['acct'] ? "" : "@" . $item["account"]['acct']) . " "; if (!empty($array)) { foreach ($array as $mnt) { if ($mnt['acct'] != $user_settings['acct']) { $json['mentions'] .= "@" . $mnt['acct'] . " "; } } } } $reply['json'] = json_encode($json); $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'] . "'></a> " : ""); $reply['text'] = processText($item); $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>"; $reply['visibility'] = $item['visibility']; $reply['media'] = ""; if (!empty($item['media_attachments'])) { $reply['media'] = "<div style='width:170px; display:inline-block; float:left; margin:15px 0px 10px 0px;'>"; $images = count($item['media_attachments']); $class = ($images > 1 ? "class='icon'" : ""); foreach ($item['media_attachments'] as $file) { $ext = explode(".", $file['url']); $ext = end($ext); $ext = explode("?", $ext) [0]; if (in_array($ext,array('webm','mp4','ogv'))) { $reply['media'] .= "<div style='text-align:center; width:100%;'><video preload='metadata' width='100%' controls ".($user_settings['videoloop'] == "on" ? "loop" : "")."> <source src='" . $file['url'] . "' type='video/".($ext == "ogv" ? "ogg" : $ext)."'> </video></div> "; } elseif (in_array($ext,array('mp3','ogg','oga','opus'))) { $reply['media'] .= "<div style='text-align:center; width:100%;'><audio controls> <source src='" . $file['url'] . "' type='audio/$ext'> Your browser does not support the audio tag. </audio> </div>"; } else { if ($item['sensitive'] == true && $user_settings['explicit'] != 'off') { $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>"; } else { $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>"; } } } $reply['media'] .= "</div>"; } $reply['buttons'] = " " . ($logedin ? "<div class='felem'><a onClick='return false' class='replyform' href='?thread=" . $item['id'] . "' style='font-family:fontello'></a></div>" : "") . " <div class='felem'><a onClick='return false' " . ($logedin ? "class='" . ($item['favourited'] == true ? "unfav" : "fav") . "' href='?action=fav&thread=" . $item['id'] . "'" : "") . " style='font-family:fontello'> <span>" . $item['favourites_count'] . "</span></a></div> <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'> <span>" . $item['reblogs_count'] . "</span></a></div> "; $result = themes("get","templates/reply.txt"); foreach ($reply as $key => $elem) { $result = str_replace(":$key:", $elem, $result); } return $result; } /* this is the same as above but is used on other places, like user bios and places where the shortcodes and the emoji url is defined in the same place */ function emojify($string, $emojis, $size = 40) { foreach ($emojis as $emoji) { $string = str_replace(":" . $emoji['shortcode'] . ":", "<img class='emoji' alt='" . $emoji['shortcode'] . "' title='" . $emoji['shortcode'] . "' src='" . $emoji['static_url'] . "' height=$size style='vertical-align: middle;'>", $string); } return $string; } /* This function displays the emoji list of an instance based on a search string given on $val */ function emoji_list($val){ $emojilist = api_get("/custom_emojis"); $c = 0; $return = ""; foreach ($emojilist as $emoji){ if (starts_with($emoji['shortcode'],$val) && $c < 50){ $return .= "<img style='margin:1px;' src='".$emoji['static_url']."' class='emoji' title='".$emoji['shortcode']."' height=40>"; $c++; } } if ($c < 50){ foreach ($emojilist as $emoji){ if ((contains($emoji['shortcode'],$val) && !starts_with($emoji['shortcode'],$val)) && $c < 50){ $return .= "<img style='margin:1px;' src='".$emoji['static_url']."' class='emoji' title='".$emoji['shortcode']."' height=40>"; $c++; } } } return $return; } function contact_search($val){ global $user_settings; $return = ""; $list = api_get("/accounts/search?q=".$val); foreach ($list as $contact){ $return .= "<div class='contact' title='@".$contact['acct']."' style='width:100%; clear:both; height:40px; display:inline-block;'> <div style='width:40px; height:40px; background-size:cover; background-image:url(".$contact['avatar']."); float:left;'></div> <div> <span style='font-weight:bold;'>".emojify($contact['display_name'], $contact['emojis'], 15)."</span><br> <span style='font-size:12px;'>".$contact['acct']."</span> </div> </div>"; } return $return; } /* This function will fetch and render all the notifications since an $id or get a list of all past notification ($max notifications specified) */ function getnotif($id = false, $max = false) { global $srv; global $token; global $user_settings; $n = ""; $notif = api_get("notifications?" . ($id == false ? "limit=9&" : "") . ($id != false ? ($max == true ? "max_id=$id" : "since_id=$id") : "")); if (!empty($notif)) { foreach ($notif as $post) { if (!isset($post["type"])){ break; } $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>"; $preview = ""; $buttons = ""; $media = ""; if ($post["type"] == "pleroma:emoji_reaction"){ continue; } switch ($post["type"]) { case "mention": if ($post['status']['in_reply_to_id'] == null) { $type = "<span class='fontello' style='color:#62C2CC; font-size:10px;'></span>"; $string = "mentioned you in a post"; $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>"; $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>" : ""); } else { $type = "<span class='fontello' style='color:#62C2CC; font-size:10px;'></span>"; $string = "replied to your post"; $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>"; $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>" : ""); } $array = $post['status']["mentions"]; $mentions = ($user_settings['acct'] == $post['status']['account']['acct'] ? "" : "@" . $post['status']['account']['acct']) . " "; if (!empty($array)) { foreach ($array as $mnt) { if ($mnt['acct'] != $user_settings['acct']) { $mentions .= "@" . $mnt['acct'] . " "; } } } $buttons = "<div class='post_buttons' id='" . $post['status']['id'] . "' style='position:absolute; right:10px; bottom:10px; border-radius:60px; padding:5px;'> <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'></a></div> <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'></a></div> <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'></a></div></div>"; break; case "favourite": $type = "<span class='fontello' style='color:#F17022; font-size:10px;'></span>"; $string = "favourited your post"; $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>"; $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>" : ""); break; case "reblog": $type = "<span class='fontello' style='color:#D1DC29; font-size:10px;'></span>"; $string = "reblogged your post"; $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>"; @$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>" : ""); break; case "follow": list($info, $rel) = user_info($post["account"]["id"]); $type = "<span class='fontello' style='color:#FDB813; font-size;10px;'></span>"; $preview = "started following you"; if ($rel[0]['following']) { $label = " Following"; $class = "unfollow"; } else { if ($info['locked']) { if ($rel[0]['requested']) { $label = " Follow Requested"; $class = "unfollow"; } else { $label = " Request Follow"; $class = "follow"; } } else { $label = " Follow"; $class = "follow"; } } $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>"; break; } $n .= " <div class='notif " . ($id == false ? "" : "new") . "' id='" . $post['id'] . "'> <div class='notifContents'> <div style='flex: 0 0 60px; background-size:cover; background-image:url(" . $post['account']['avatar'] . "); border-radius:5px;'></div> <div style='flex: 1; padding-left:5px; padding-right:5px; word-break: break-word; overflow:hidden;'> <span>$type <span style='font-size:12px; font-weight:bold;'>$user</span></span> " . trim($preview) . " $buttons </div> $media </div> </div> "; } return $n; } } /* this function takes in a whole post entity and spits out the HTMLfied text of the post with the urls and @handles linkified and all the emojis replaced */ function processText($elem) { global $user_settings; global $logedin; require_once "vendor/simple_html_dom.php"; $content = trim(html_entity_decode($elem['content'],ENT_QUOTES)); $content = preg_replace("/<(?=[^>]*(?:<|$))/","<",$content); if (!empty($content)) { $html = str_get_html($content); foreach ($html->find('a') as $lnk) { //remove text links to media attachments foreach ($elem['media_attachments'] as $f) { if (is_numeric(strpos($f['description'],explode("…",$lnk->innertext)[0]))) { $content = str_replace($lnk->outertext . "<br/>", null, $content); $content = str_replace("<br/>" . $lnk->outertext, null, $content); $content = str_replace($lnk->outertext, null, $content); } } //modify links for hashtags and external urls if (is_numeric(strpos($lnk->href, $user_settings['instance'])) || in_array($lnk->class, array( "u-url mention", "hashtag" )) || $lnk->rel == "tag") { $content = str_replace($lnk->outertext, $lnk->innertext, $content); } else { $prv = $lnk->outertext; $lnk->target = '_blank'; $lnk->class = 'link external'; $content = str_replace($prv, $lnk->outertext, $content); } } } $result = strip_tags($content, '<br><p><strong><a><em><strike>'); $result = str_replace('<br />', ' <br>', $result); //$result = str_replace(''', "'", $result); foreach ($elem['mentions'] as $mention) { $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); } //$result = preg_replace("/(?<!=\")(\b[\w]+:\/\/[\w-?&;#~=\.\/\@]+[\w\/])/", "<a target=\"_blank\" class='external' style='color:navy;' href=\"$1\">$1</a>", $result); $result = emojify($result, $elem['emojis']); if ($logedin){ $result = preg_replace("/#([A-Za-z0-9\/\.]*)/", "<a class='ldr' href=\"./?tag=$1\"><b>#$1</b></a>", $result); } else { $result = preg_replace("/#([A-Za-z0-9\/\.]*)/", "<b>#$1</b>", $result); } return $result; } // OTHER FUNCTIONS /* the purpose of this function is to encode the auth token it is not used for now */ function msc($string, $action = 'e') { // you may change these values to your own $secret_key = 'yAmfVhZwm0749FSY24dC'; $secret_iv = 'm37uvAeKjYLKdI1lPkcJ'; $output = false; $encrypt_method = "AES-256-CBC"; $key = hash('sha256', $secret_key); $iv = substr(hash('sha256', $secret_iv) , 0, 16); if ($action == 'e') { $output = base64_encode(openssl_encrypt($string, $encrypt_method, $key, 0, $iv)); } else if ($action == 'd') { $output = openssl_decrypt(base64_decode($string) , $encrypt_method, $key, 0, $iv); } return $output; } /* this function extracts the urls from a text and return them in an array */ function get_urls($input) { $pattern = '$(https?://[a-z0-9_./?=&-~]+)(?![^<>]*>)$i'; if (preg_match_all($pattern, $input, $matches)) { list($dummy, $links) = ($matches); return $links; } return false; } /* general function to check if one strings starts with a given search */ function starts_with($string,$search){ if (substr(strtolower($string),0,strlen($search)) == strtolower($search)){ return true; } return false; } /* general function to check if one strings contains with a given search */ function contains($string,$search){ if (is_numeric(strpos(strtolower($string),strtolower($search)))){ return true; } return false; } /* this function just reduces an image to a 1x1 pixel image to get the overall color. */ function averageColor($url) { @$image = imagecreatefromstring(file_get_contents($url)); if (!$image) { $mainColor = "CCCCCC"; } else { $thumb = imagecreatetruecolor(1, 1); imagecopyresampled($thumb, $image, 0, 0, 0, 0, 1, 1, imagesx($image) , imagesy($image)); $mainColor = strtoupper(dechex(imagecolorat($thumb, 0, 0))); } return $mainColor; } /* function used in the process of uploading a file */ function get_mime($filename) { $result = new finfo(); if (is_resource($result) === true) { return $result->file($filename, FILEINFO_MIME_TYPE); } return false; } function sanitize($text){ return preg_replace("/[^a-zA-Z0-9]+/", "", $text); } function themes($mode,$name = false){ global $user_settings; switch ($mode){ case "list": $themes = scandir("themes/"); $themelist = array(); foreach ($themes as $elem){ if ($elem != ".." && $elem != "." && $elem != "custom" && is_dir("themes/".$elem)){ $themelist[] = $elem; } } return $themelist; case "file": $theme = sanitize($user_settings['theme']); if (file_exists("themes/$theme/$name")){ return "themes/$theme/$name"; } else { return "$name"; } case "get": $theme = sanitize($user_settings['theme']); if (file_exists("themes/$theme/$name")){ return file_get_contents("themes/$theme/$name"); } else { return file_get_contents("$name"); } } } function time_elapsed_string($datetime, $full = false) { $now = new DateTime; $ago = new DateTime($datetime); $diff = $now->diff($ago); $diff->w = floor($diff->d / 7); $diff->d -= $diff->w * 7; $string = array( 'y' => 'year', 'm' => 'month', 'w' => 'week', 'd' => 'day', 'h' => 'hour', 'i' => 'minute', 's' => 'second', ); foreach ($string as $k => &$v) { if ($diff->$k) { $v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : ''); } else { unset($string[$k]); } } if (!$full) $string = array_slice($string, 0, 1); return $string ? implode(', ', $string) . ' ago' : 'just now'; } function getHeaders($respHeaders) { $headers = array(); $headerText = substr($respHeaders, 0, strpos($respHeaders, "\r\n\r\n")); foreach (explode("\r\n", $headerText) as $i => $line) { if ($i === 0) { $headers['http_code'] = $line; } else { list ($key, $value) = explode(': ', $line); $headers[$key] = $value; } } return $headerText; }