PageRenderTime 73ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/inc/html.php

https://github.com/stechico/tweetnest
PHP | 493 lines | 471 code | 15 blank | 7 comment | 71 complexity | 1c2e0fd375442783a8499664f7365685 MD5 | raw file
  1. <?php
  2. // PONGSOCKET TWEET ARCHIVE
  3. // HTML output templates
  4. function displayMonths($tabs = 4){
  5. global $db, $selectedDate, $highlightedMonths, $filterMode, $home, $config;
  6. $months = array(); $max = 0; $total = 0; $amount = 0;
  7. $x = str_repeat("\t", $tabs); $y = str_repeat("\t", $tabs+1);
  8. $url = explode("?", $_SERVER['REQUEST_URI'], 2);
  9. $path = s(rtrim($config['path'], "/"));
  10. $q = $db->query("SELECT MONTH(FROM_UNIXTIME(`time`" . DB_OFFSET . ")) AS m, YEAR(FROM_UNIXTIME(`time`" . DB_OFFSET . ")) AS y, COUNT(*) AS c FROM `".DTP."tweets` GROUP BY y, m ORDER BY y DESC, m DESC");
  11. while($r = $db->fetch($q)){
  12. $months[] = $r;
  13. if($r['c'] > $max){ $max = $r['c']; }
  14. $total += $r['c'];
  15. $amount++;
  16. }
  17. $searching = $home ? false : (count($highlightedMonths) > 0);
  18. $s = "<ul id=\"months\">\n";
  19. if(!$home){
  20. $s .= $y . "<li class=\"home\"><a href=\"" . $path . "/\"><span class=\"m" . ($searching ? " ms\"><span class=\"a\">" : "\">") . "Recent tweets" . ($searching ? "</span><span class=\"b\"> (exit " . s($filterMode) . ")</span>" : "") . "</span></a></li>\n";
  21. }
  22. if(!$searching){
  23. $s .= $y . "<li class=\"fav\"><a href=\"" . $path . "/favorites\"><span class=\"m\">Favorites</span></a></li>\n";
  24. }
  25. if(count($highlightedMonths) > 0 && (!empty($_GET['m']) && !empty($_GET['y']))){
  26. // Generating URL
  27. $g = $_GET;
  28. unset($g['m']);
  29. unset($g['y']);
  30. $qsa = array();
  31. foreach($g as $k => $v){
  32. $qsa[] = $k . "=" . $v;
  33. }
  34. $qs = implode("&", $qsa);
  35. $cn = ($filterMode == "favorites") ? "fav" : "search";
  36. $res = ($filterMode == "favorites") ? "favorites" : "results";
  37. $s .= $y . "<li class=\"" . $cn . "\"><a href=\"" . s($url[0] . ($qs ? "?" . $qs : "")) . "\"><span class=\"m\">All " . $res . "</span></a></li>\n";
  38. }
  39. foreach($months as $m){
  40. $c = ""; $cc = 0;
  41. if($selectedDate['y'] == $m['y'] && $selectedDate['m'] == $m['m']){ $c .= " selected"; }
  42. if(array_key_exists($m['y'] . "-" . $m['m'], $highlightedMonths)){
  43. $c .= " highlighted";
  44. $cc = $highlightedMonths[$m['y'] . "-" . $m['m']];
  45. // Generating search URL
  46. $g = $_GET; $g['m'] = $m['m']; $g['y'] = $m['y'];
  47. $qsa = array();
  48. foreach($g as $k => $v){
  49. $qsa[] = $k . "=" . $v;
  50. }
  51. $qs = implode("&", $qsa);
  52. $pURL = $url[0] . "?" . $qs;
  53. }
  54. $c = trim($c);
  55. $s .= $y . "<li" . ($c ? " class=\"" . $c . "\"" : "") . ">" .
  56. "<a href=\"" . ($cc > 0 ? s($pURL) : $path . "/" . s($m['y']) . "/" . s(pad($m['m']))) . "\">" .
  57. "<span class=\"m\">" . date("F Y", mktime(1,0,0,$m['m'],1,$m['y'])) . "</span>" .
  58. "<span class=\"n\"> " . number_format($m['c']) . ($cc > 0 ? " <strong>(" . number_format($cc) . ")</strong>" : "") .
  59. "</span><span class=\"p\" style=\"width:" . round((($m['c']/$max)*100), 2) . "%\"></span></a></li>\n";
  60. }
  61. $s .= $y . "<li class=\"meta\">" . number_format($total) . " total tweets" . ($amount > 0 ? " <!-- approx. " . round(number_format($total / $amount), 2) . " monthly -->" : "") . "</li>\n" . $x . "</ul>\n";
  62. return $s;
  63. }
  64. function displayDays($year, $month, $tabs = 3){
  65. global $db, $selectedDate, $config;
  66. if(!is_numeric($month) || !is_numeric($year) || (is_numeric($month) && ($month > 12 || $month < 1)) || (is_numeric($year) && $year < 2000)){ return false; }
  67. $days = array(); $max = 0; $total = 0;
  68. $date = getdate(mktime(1,0,0, $month, 1, $year)); $wd = $date['wday'];
  69. $x = str_repeat("\t", $tabs); $y = str_repeat("\t", $tabs+1);
  70. $_year = "YEAR(FROM_UNIXTIME(`time`" . DB_OFFSET . "))";
  71. $_month = "MONTH(FROM_UNIXTIME(`time`" . DB_OFFSET . "))";
  72. $path = s(rtrim($config['path'], "/"));
  73. $q = $db->query("SELECT DAY(FROM_UNIXTIME(`time`" . DB_OFFSET . ")) as d, " . $_month . " AS m, " . $_year . " AS y, `type`, COUNT(*) AS c FROM `".DTP."tweets` WHERE " . $_year . " = '" . $db->s($year) . "' AND " . $_month . " = '" . $db->s($month) . "' GROUP BY y, m, d, `type` ORDER BY y ASC, m ASC, d ASC, `type` ASC");
  74. while($r = $db->fetch($q)){
  75. if(!array_key_exists($r['d'], $days)){
  76. $days[$r['d']] = array("total" => 0);
  77. }
  78. $days[$r['d']]['total'] += $r['c'];
  79. $days[$r['d']]['c' . $r['type']] = $r['c'];
  80. if($days[$r['d']]['total'] > $max){ $max = $days[$r['d']]['total']; }
  81. $total += $r['c'];
  82. }
  83. $daysInMonth = getDaysInMonth($month, $year);
  84. $s = "<div id=\"days\" class=\"days-" . s($daysInMonth) . "\"><div class=\"dr\">\n";
  85. for($i = 0; $i < $daysInMonth; $i++){
  86. $today = ($selectedDate['y'] == $year && $selectedDate['m'] == $month && $selectedDate['d'] == ($i+1));
  87. if(array_key_exists($i+1, $days)){
  88. $d = $days[$i+1];
  89. $s .= $y . "<div class=\"d\"><a title=\"" . s($d['total']) . " tweet" . (($d['total'] == 1) ? "" : "s") .
  90. (!empty($d['c1']) ? ", " . s($d['c1']) . " repl" . ($d['c1'] == 1 ? "y" : "ies") : "") .
  91. (!empty($d['c2']) ? ", " . s($d['c2']) . " retweet" . ($d['c2'] == 1 ? "" : "s") : "") .
  92. "\" href=\"" . $path . "/" . s($year) . "/" . s(pad($month)) . "/" . s(pad($i+1)) . "\">" .
  93. "<span class=\"p\" style=\"height:" . round((($d['total']/$max)*250), 2) . "px\">" .
  94. "<span class=\"n\">" . ($d['total'] != 1 ? number_format($d['total']) : "") . "</span>" .
  95. (!empty($d['c1']) ? "<span class=\"r\" style=\"height:" . round((($d['c1']/$max)*250), 2) . "px\"></span>" : "") .
  96. (!empty($d['c2']) ? "<span class=\"rt\" style=\"height:" . round((($d['c2']/$max)*250), 2) . "px\"></span>" : "") .
  97. "</span><span class=\"m" . (($wd == 0 || $wd == 6) ? " mm" : "") . ($today ? " ms" : "") . "\">" .
  98. ($today ? "<strong>" : "") . s($i+1) . ($today ? "</strong>" : "") .
  99. "</span></a></div>\n";
  100. } else {
  101. $s .= $y . "<div class=\"d\"><a href=\"" . $path . "/" . s($year) . "/" . s(pad($month)) . "/" . s(pad($i+1)) . "\">" .
  102. "<span class=\"z\">0</span><span class=\"m" . (($wd == 0 || $wd == 6) ? " mm" : "") . ($today ? " ms" : "") . "\">" .
  103. ($today ? "<strong>" : "") . s($i+1) . ($today ? "</strong>" : "") .
  104. "</span></a></div>\n";
  105. }
  106. $wd = ($wd == 6) ? 0 : $wd + 1;
  107. }
  108. $s .= $x . "</div></div>\n";
  109. return $s;
  110. }
  111. function tweetHTML($tweet, $tabs = 4){
  112. global $twitterApi;
  113. $tweetextra = array(); $tweetplace = array();
  114. if(!empty($tweet['extra'])){
  115. @$tweetextra = unserialize($tweet['extra']);
  116. }
  117. if(!empty($tweet['place'])){
  118. $tweetplace = unserialize(str_replace("O:16:\"SimpleXMLElement\"", "O:8:\"stdClass\"", $tweet['place']));
  119. }
  120. $rt = (array_key_exists("rt", $tweetextra) && !empty($tweetextra['rt']));
  121. $t = str_repeat("\t", $tabs);
  122. if($rt){ $retweet = $tweetextra['rt']; }
  123. // Entities
  124. $htmlcontent = s(stupefyRaw($rt ? $twitterApi->entityDecode($retweet['text']) : $tweet['text']), ENT_NOQUOTES);
  125. $entities = ($rt ? $tweetextra['rt']['extra']['entities'] : $tweetextra['entities']);
  126. if(areEntitiesEmpty($entities)){
  127. $htmlcontent = linkifyTweet($htmlcontent);
  128. } else {
  129. $htmlcontent = linkifyTweet(entitifyTweet($htmlcontent, $entities), true);
  130. }
  131. $d = $t . "<div id=\"tweet-" . s($tweet['tweetid']) . "\" class=\"tweet" . (($tweet['type'] == 1) ? " reply" : "") . (($tweet['type'] == 2) ? " retweet" : "") . "\">\n" .
  132. ($tweet['favorite'] ? $t . "\t<div class=\"fav\" title=\"A personal favorite\"><span>(A personal favorite)</span></div>\n" : "") .
  133. $t . "\t<p class=\"text\">" .
  134. ($rt ? "<a class=\"rt\" href=\"http://twitter.com/" . $retweet['screenname'] . "\"><strong>" . $retweet['screenname'] . "</strong></a> " : "") .
  135. nl2br(p(highlightQuery($htmlcontent, $tweet), 3)) . "</p>\n" .
  136. $t . "\t<p class=\"meta\">\n" . $t . "\t\t<a href=\"http://twitter.com/" . s($rt ? $retweet['screenname'] : $tweet['screenname']) . "/statuses/" . s($rt ? $retweet['tweetid'] : $tweet['tweetid']) . "\" class=\"permalink\">" . date("g:i A, M jS, Y", ($rt ? $retweet['time'] : $tweet['time'])) . "</a>\n" .
  137. $t . "\t\t<span class=\"via\">via " . ($rt ? $retweet['source'] : $tweet['source']) . "</span>\n" .
  138. ($rt ? $t . "\t\t<span class=\"rted\">(retweeted on " . date("g:i A, M jS, Y", $tweet['time']) . " <span class=\"via\">via " . $tweet['source'] . "</span>)</span>\n" : "") .
  139. ((!$rt && $tweetextra && @!empty($tweetextra['in_reply_to_status_id'])) ? $t . "\t\t<a class=\"replyto\" href=\"http://twitter.com/" . s($tweetextra['in_reply_to_screen_name']) . "/statuses/" . s($tweetextra['in_reply_to_status_id']) . "\">in reply to " . s($tweetextra['in_reply_to_screen_name']) . "</a>\n" : "") .
  140. (($tweetplace && @$tweetplace->full_name) ? "\t\t<span class=\"place\">from <a href=\"http://maps.google.com/?q=" . urlencode($tweetplace->full_name) . "\">" . s($tweetplace->full_name) . "</a></span>" : "") .
  141. $t . "\t</p>\n" . $t . "</div>\n";
  142. $dd = hook("displayTweet", array($d, $tweet));
  143. if(!empty($dd)){ $d = $dd[0]; }
  144. return $d;
  145. }
  146. function tweetsHTML($q, $mode = "", $tabs = 4){
  147. global $db, $home, $config;
  148. $maxTweets = 200;
  149. $s = "";
  150. $t = str_repeat("\t", $tabs);
  151. $path = s(rtrim($config['path'], "/"));
  152. $first = 0; $last = 0; $i = 0; $tweets = array();
  153. $array = is_array($q);
  154. $count = $array ? count($q) : $db->numRows($q);
  155. if($count > 0){
  156. if(!$array){
  157. while($tweet = $db->fetch($q)){
  158. $tweets[] = $tweet;
  159. }
  160. } else {
  161. $tweets = $q;
  162. }
  163. foreach($tweets as $tweet){
  164. if($tweet['time'] < $first || $first == 0){ $first = $tweet['time']; }
  165. if($tweet['time'] > $last){ $last = $tweet['time']; }
  166. $s .= tweetHTML($tweet, $tabs);
  167. $i++;
  168. if($mode == "month" && $i >= $maxTweets){
  169. $s .= $t . "<div class=\"truncated\"><strong>There&#8217;s more tweets in this month!</strong> <span>Go up and <a href=\"#top\">select a date</a> to see more &uarr;</span></div>\n";
  170. break;
  171. }
  172. if($mode == "search" && $i >= $maxTweets){
  173. $s .= $t . "<div class=\"truncated\"><strong>There&#8217;s even more search results!</strong> <span>Go up and <a href=\"#top\">add a couple of words</a> to your query to find the specific tweets you want &uarr;</span></div>\n";
  174. break;
  175. }
  176. }
  177. if($mode == "day"){
  178. $nextprev = "";
  179. $half = "SELECT `tweetid`, `time`, YEAR(FROM_UNIXTIME(`time`" . DB_OFFSET . ")) as `year`, MONTH(FROM_UNIXTIME(`time`" . DB_OFFSET . ")) as `month`, DAY(FROM_UNIXTIME(`time`" . DB_OFFSET . ")) as `day` FROM `".DTP."tweets` WHERE `time`";
  180. $pTQ = $db->query($half . " < '" . $db->s($first) . "' ORDER BY `time` DESC LIMIT 1");
  181. $nTQ = $db->query($half . " > '" . $db->s($last) . "' ORDER BY `time` ASC LIMIT 1");
  182. if($db->numRows($pTQ) > 0){
  183. $prevTweet = $db->fetch($pTQ);
  184. $nextprev .= "<a class=\"prev\" href=\"" . $path . "/" .
  185. s($prevTweet['year']) . "/" . s(pad($prevTweet['month'])) . "/" . s(pad($prevTweet['day'])) .
  186. "\">&larr; <span>" . date("F jS", mktime(4,0,0, $prevTweet['month'], $prevTweet['day'], $prevTweet['year'])) .
  187. "</span></a> ";
  188. }
  189. if($db->numRows($nTQ) > 0){
  190. $nextTweet = $db->fetch($nTQ);
  191. $nextprev .= "<a class=\"next\" href=\"" . $path . "/" .
  192. s($nextTweet['year']) . "/" . s(pad($nextTweet['month'])) . "/" . s(pad($nextTweet['day'])) .
  193. "\"><span>" . date("F jS", mktime(4,0,0, $nextTweet['month'], $nextTweet['day'], $nextTweet['year'])) .
  194. "</span> &rarr;</a>";
  195. }
  196. if($nextprev){
  197. $s .= $t . "<div class=\"nextprev\">" . trim($nextprev) . "</div>\n";
  198. }
  199. }
  200. } else {
  201. $s = $t . "<div class=\"notweets\">No tweets here!</div>\n";
  202. if($home){
  203. $s .= $t . "<p>If you have <strong>just installed</strong> Tweet Nest and this is your archive page, you need to load in your tweets before something will be displayed here. Check out the installation guide on the <a href=\"http://pongsocket.com/tweetnest/\">web site for Tweet Nest</a> for more information.</p>\n";
  204. }
  205. }
  206. return $s;
  207. }
  208. function errorPage($html, $tabs = 3){
  209. global $config, $author, $authorextra;
  210. $t = str_repeat("\t", $tabs);
  211. $pageTitle = "Whoops!";
  212. include "header.php";
  213. echo $t . "<p class=\"error\"><strong>An error occured:</strong> " . $html . "</p>\n";
  214. include "footer.php";
  215. exit;
  216. }
  217. function highlightQuery($str, $tweet){
  218. if(!isset($tweet['word']) || (!is_array($tweet['word']) && !is_string($tweet['word']))){ return $str; }
  219. if(!is_array($tweet['word'])){
  220. $q = array($tweet['word']);
  221. } else {
  222. $q = $tweet['word'];
  223. }
  224. foreach($q as $word){
  225. $s = preg_match("/[A-Za-z0-9_]/", $word[0]) ? "\b" : "\B";
  226. $e = preg_match("/[A-Za-z0-9_]/", $word[strlen($word)-1]) ? "\b" : "\B";
  227. $str = preg_replace(
  228. "/" . $s . "(" . preg_quote(s($word), "/") . ")" . $e . "/i",
  229. '<strong class="searchword">$1</strong>',
  230. $str
  231. );
  232. $str = preg_replace( '/(<[a-zA-Z]* [^>]*)<strong class="searchword">([^<]*)<\/strong>([^>]*>)/', '$1$2$3', $str);
  233. }
  234. return $str;
  235. }
  236. // CSS functions ------------------------------------
  237. $css_i = 0;
  238. global $css_i;
  239. function css($var, $canBeEmpty = false){ // Display CSS value found in given config variable
  240. global $config, $authorextra, $css_i;
  241. if($css_i >= 10){ $css_i = 0; return false; } // Too much recursion
  242. $var = trim(strtolower($var));
  243. $profile = array(
  244. "profile_background_color", "profile_text_color", "profile_link_color",
  245. "profile_sidebar_fill_color", "profile_sidebar_border_color"
  246. );
  247. if(isset($config['style'][$var])){
  248. $val = $config['style'][$var];
  249. if($val == "profile"){
  250. $css_i = 0;
  251. $pv = array(
  252. "text_color" => "profile_text_color",
  253. "link_color" => "profile_link_color",
  254. "content_background_color" => "#fff",
  255. "top_background_color" => "profile_background_color",
  256. "top_background_image" => "profile_background_image_url",
  257. "top_background_image_tile" => "profile_background_tile",
  258. "top_bar_background_color" => "profile_sidebar_fill_color",
  259. // Tweet
  260. "tweet_border_color" => "#eee",
  261. "tweet_meta_text_color" => "#999",
  262. );
  263. if(preg_match("/#[0-9a-f]+/", $pv[$var])){
  264. return cssHex($pv[$var]);
  265. } else {
  266. if($authorextra[$pv[$var]]){
  267. return profileCss($authorextra[$pv[$var]]);
  268. }
  269. return $canBeEmpty ? "" : standardCss($var);
  270. }
  271. }
  272. if(in_array($val, $profile)){
  273. $css_i = 0;
  274. return cssHex($authorextra[$val]); // They're only ever color vars, no need to run profileCss()
  275. }
  276. if(preg_match("/^[a-z_]+$/", $val) && isset($config['style'][$val])){
  277. $css_i++;
  278. return css($val, $canBeEmpty); // Recursion
  279. }
  280. if(preg_match("/^https?:\/\//", $val) || preg_match("/_image$/", $var)){
  281. $css_i = 0;
  282. return "url(" . $val . ")";
  283. }
  284. if(is_bool($val)){
  285. $css_i = 0;
  286. if(substr_count($var, "tile") > 0){
  287. return (!sBool($val) ? "no-" : "") . "repeat";
  288. }
  289. return $val ? 1 : 0;
  290. }
  291. if(preg_match("/^[a-zA-Z0-9-_ #\"'\(\),.]+$/i", $val)){ // Legit
  292. $css_i = 0;
  293. return preg_match("/#[0-9a-f]+/", $val) ? cssHex($val) : $val;
  294. }
  295. $css_i = 0;
  296. return $canBeEmpty ? "" : standardCss($var); // Empty or weird
  297. }
  298. $css_i = 0;
  299. return false;
  300. }
  301. function standardCss($var){
  302. $var = trim(strtolower($var));
  303. if(substr_count($var, "color") > 0){
  304. if(substr_count($var, "text_color") > 0 || substr_count($var, "link_color") > 0){
  305. return "#ccc";
  306. }
  307. return "transparent";
  308. } elseif(substr_count($var, "tile") > 0){
  309. return "repeat";
  310. } elseif(substr_count($var, "position") > 0){
  311. return "0 0";
  312. } elseif(substr_count($var, "image") > 0){
  313. return "none";
  314. } else {
  315. return false; // for the WTF case
  316. }
  317. }
  318. function profileCss($val){
  319. if(preg_match("/^https?:\/\//", $val)){
  320. return "url(" . $val . ")";
  321. }
  322. if(is_bool(sBool($val))){
  323. return (!sBool($val) ? "no-" : "") . "repeat";
  324. }
  325. return cssHex($val);
  326. }
  327. function cssHex($val){
  328. return "#" . preg_replace('/^([0-9a-f])\1([0-9a-f])\2([0-9a-f])\3$/i', '\1\2\3', ltrim($val, "#"));
  329. }
  330. function sBool($val){
  331. if(is_bool($val)){ return $val; }
  332. if(strtolower(trim($val)) == "false" || $val === 0){ return false; }
  333. if(strtolower(trim($val)) == "true" || $val === 1){ return true; }
  334. return $val;
  335. }
  336. // Internal functions -------------------------------
  337. function _linkifyTweet_link($a, $b, $c, $d){
  338. $url = stripslashes($a);
  339. $end = stripslashes($d);
  340. return "<a class=\"link\" href=\"" . ($b[0] == "w" ? "http://" : "") . str_replace("\"", "&quot;", $url) . "\">" . (strlen($url) > 25 ? substr($url, 0, 24) . "..." : $url) . "</a>" . $end;
  341. }
  342. function _linkifyTweet_at($a, $b){
  343. return "<span class=\"at\">@</span><a class=\"user\" href=\"http://twitter.com/" . $a . "\">" . $a . "</a>";
  344. }
  345. function _linkifyTweet_hashtag($a, $b){
  346. return "<a class=\"hashtag\" href=\"http://twitter.com/search?q=%23" . $a . "\">#" . $a . "</a>";
  347. }
  348. function linkifyTweet($str, $linksOnly = false){
  349. // Look behind (it kinda sucks, no | operator)
  350. $lookbehind = '(?<!href=\")(?<!title=\")' .
  351. '(?<!href=\"http:\/\/)(?<!href=\"https:\/\/)' .
  352. '(?<!title=\"http:\/\/)(?<!title=\"https:\/\/)' .
  353. '(?<!data-image=\")(?<!data-image=\"http:\/\/)(?<!data-image=\"https:\/\/)';
  354. // Expression
  355. $html = preg_replace("/$lookbehind\b(((https?:\/\/)|www\.).+?)(([!?,.\"\)]+)?(\s|$))/e", "_linkifyTweet_link('$1', '$2', '$3', '$4')", $str);
  356. if(!$linksOnly){
  357. $html = preg_replace("/\B\@([a-zA-Z0-9_]{1,20}(\/\w+)?)/e", "_linkifyTweet_at('$1', '$2')", $html);
  358. $html = preg_replace("/\B\#([\pL|0-9|_]+)/eu", "_linkifyTweet_hashtag('$1', '$2')", $html);
  359. }
  360. return $html;
  361. }
  362. function entitifyTweet($str, $entities, $newwindow = false){
  363. if(!$entities){ return $str; }
  364. $replacements = array();
  365. $tb = $newwindow ? ' target="_blank"' : '';
  366. // Mentions
  367. foreach($entities->user_mentions as $entity){
  368. $replacements[$entity->indices[0]] = array(
  369. 'end' => $entity->indices[1],
  370. 'content' => '<span class="at">@</span><a class="user"' . $tb . ' href="http://twitter.com/' . s($entity->screen_name) . '">' . s($entity->screen_name) . '</a>'
  371. );
  372. }
  373. // Hashtags
  374. foreach($entities->hashtags as $entity){
  375. $replacements[$entity->indices[0]] = array(
  376. 'end' => $entity->indices[1],
  377. 'content' => '<a class="hashtag" rel="search"' . $tb . ' href="http://twitter.com/search?q=%23' . urlencode($entity->text) . '">#' . s($entity->text) . '</a>'
  378. );
  379. }
  380. // URLs
  381. foreach($entities->urls as $entity){
  382. $truncated = (!empty($entity->display_url) && mb_substr($entity->display_url, -1) == '…');
  383. $replacements[$entity->indices[0]] = array(
  384. 'end' => $entity->indices[1], // quittin' rel="nofollow" since this is meant for your own site
  385. 'content' => '<a class="link" href="' . s($entity->url) . '"' . $tb .
  386. (!empty($entity->expanded_url) && $truncated ? ' title="' . s($entity->expanded_url) . '"' : '') . '>' .
  387. (!empty($entity->display_url) ? $entity->display_url : $entity->url) . '</a>'
  388. );
  389. }
  390. // Media
  391. if(isset($entities->media) && is_array($entities->media)){
  392. foreach($entities->media as $entity){
  393. $truncated = (!empty($entity->display_url) && mb_substr($entity->display_url, -1) == '…');
  394. $replacements[$entity->indices[0]] = array(
  395. 'end' => $entity->indices[1],
  396. 'content' => '<a class="media" href="' . s($entity->url) . '"' . $tb . ' data-image="' . s($entity->media_url) . '"' .
  397. (!empty($entity->expanded_url) && $truncated ? ' title="' . s($entity->expanded_url) . '"' : '') . '>' .
  398. (!empty($entity->display_url) ? $entity->display_url : $entity->url) . '</a>'
  399. );
  400. }
  401. }
  402. // Putting it all together
  403. $out = '';
  404. $lastEntityEnded = 0;
  405. ksort($replacements);
  406. foreach($replacements as $position => $replacement){
  407. $out .= mb_substr($str, $lastEntityEnded, $position - $lastEntityEnded);
  408. $out .= $replacement['content'];
  409. $lastEntityEnded = $replacement['end'];
  410. }
  411. $out .= mb_substr($str, $lastEntityEnded);
  412. return $out;
  413. }
  414. function areEntitiesEmpty($entities){
  415. if(is_object($entities)){
  416. foreach(get_object_vars($entities) as $property => $value){
  417. if(!empty($value)){
  418. return false;
  419. }
  420. }
  421. }
  422. return true;
  423. }
  424. // Altered "Days in Month" function taken from:
  425. // PHP Calendar Class Version 1.4 (5th March 2001)
  426. //
  427. // Copyright David Wilkinson 2000 - 2001. All Rights reserved.
  428. //
  429. // This software may be used, modified and distributed freely
  430. // providing this copyright notice remains intact at the head
  431. // of the file.
  432. //
  433. // This software is freeware. The author accepts no liability for
  434. // any loss or damages whatsoever incurred directly or indirectly
  435. // from the use of this script. The author of this software makes
  436. // no claims as to its fitness for any purpose whatsoever. If you
  437. // wish to use this software you should first satisfy yourself that
  438. // it meets your requirements.
  439. //
  440. // URL: http://www.cascade.org.uk/software/php/calendar/
  441. // Email: davidw@cascade.org.uk
  442. function getDaysInMonth($month, $year){
  443. if($month < 1 || $month > 12){ return 0; }
  444. $daysInMonth = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
  445. $d = $daysInMonth[$month - 1];
  446. if($month == 2){
  447. // Check for leap year
  448. // Forget the 4000 rule, I doubt I'll be around then...
  449. if($year%4 == 0){
  450. if($year%100 == 0){
  451. if($year%400 == 0){
  452. $d = 29;
  453. }
  454. } else {
  455. $d = 29;
  456. }
  457. }
  458. }
  459. return $d;
  460. }