Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1179 lines
34 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. <?php
  2. // This is our template processor.
  3. // $s is the string requiring macro substitution.
  4. // $r is an array of key value pairs (search => replace)
  5. // returns substituted string.
  6. // WARNING: this is pretty basic, and doesn't properly handle search strings that are substrings of each other.
  7. // For instance if 'test' => "foo" and 'testing' => "bar", testing could become either bar or fooing,
  8. // depending on the order in which they were declared in the array.
  9. require_once("include/template_processor.php");
  10. if(! function_exists('replace_macros')) {
  11. function replace_macros($s,$r) {
  12. global $t;
  13. return $t->replace($s,$r);
  14. }}
  15. // random string, there are 86 characters max in text mode, 128 for hex
  16. // output is urlsafe
  17. define('RANDOM_STRING_HEX', 0x00 );
  18. define('RANDOM_STRING_TEXT', 0x01 );
  19. if(! function_exists('random_string')) {
  20. function random_string($size = 64,$type = RANDOM_STRING_HEX) {
  21. // generate a bit of entropy and run it through the whirlpool
  22. $s = hash('whirlpool', (string) rand() . uniqid(rand(),true) . (string) rand(),(($type == RANDOM_STRING_TEXT) ? true : false));
  23. $s = (($type == RANDOM_STRING_TEXT) ? str_replace("\n","",base64url_encode($s,true)) : $s);
  24. return(substr($s,0,$size));
  25. }}
  26. /**
  27. * This is our primary input filter.
  28. *
  29. * The high bit hack only involved some old IE browser, forget which (IE5/Mac?)
  30. * that had an XSS attack vector due to stripping the high-bit on an 8-bit character
  31. * after cleansing, and angle chars with the high bit set could get through as markup.
  32. *
  33. * This is now disabled because it was interfering with some legitimate unicode sequences
  34. * and hopefully there aren't a lot of those browsers left.
  35. *
  36. * Use this on any text input where angle chars are not valid or permitted
  37. * They will be replaced with safer brackets. This may be filtered further
  38. * if these are not allowed either.
  39. *
  40. */
  41. if(! function_exists('notags')) {
  42. function notags($string) {
  43. return(str_replace(array("<",">"), array('[',']'), $string));
  44. // High-bit filter no longer used
  45. // return(str_replace(array("<",">","\xBA","\xBC","\xBE"), array('[',']','','',''), $string));
  46. }}
  47. // use this on "body" or "content" input where angle chars shouldn't be removed,
  48. // and allow them to be safely displayed.
  49. if(! function_exists('escape_tags')) {
  50. function escape_tags($string) {
  51. return(htmlspecialchars($string));
  52. }}
  53. // generate a string that's random, but usually pronounceable.
  54. // used to generate initial passwords
  55. if(! function_exists('autoname')) {
  56. function autoname($len) {
  57. $vowels = array('a','a','ai','au','e','e','e','ee','ea','i','ie','o','ou','u');
  58. if(mt_rand(0,5) == 4)
  59. $vowels[] = 'y';
  60. $cons = array(
  61. 'b','bl','br',
  62. 'c','ch','cl','cr',
  63. 'd','dr',
  64. 'f','fl','fr',
  65. 'g','gh','gl','gr',
  66. 'h',
  67. 'j',
  68. 'k','kh','kl','kr',
  69. 'l',
  70. 'm',
  71. 'n',
  72. 'p','ph','pl','pr',
  73. 'qu',
  74. 'r','rh',
  75. 's','sc','sh','sm','sp','st',
  76. 't','th','tr',
  77. 'v',
  78. 'w','wh',
  79. 'x',
  80. 'z','zh'
  81. );
  82. $midcons = array('ck','ct','gn','ld','lf','lm','lt','mb','mm', 'mn','mp',
  83. 'nd','ng','nk','nt','rn','rp','rt');
  84. $noend = array('bl', 'br', 'cl','cr','dr','fl','fr','gl','gr',
  85. 'kh', 'kl','kr','mn','pl','pr','rh','tr','qu','wh');
  86. $start = mt_rand(0,2);
  87. if($start == 0)
  88. $table = $vowels;
  89. else
  90. $table = $cons;
  91. $word = '';
  92. for ($x = 0; $x < $len; $x ++) {
  93. $r = mt_rand(0,count($table) - 1);
  94. $word .= $table[$r];
  95. if($table == $vowels)
  96. $table = array_merge($cons,$midcons);
  97. else
  98. $table = $vowels;
  99. }
  100. $word = substr($word,0,$len);
  101. foreach($noend as $noe) {
  102. if((strlen($word) > 2) && (substr($word,-2) == $noe)) {
  103. $word = substr($word,0,-1);
  104. break;
  105. }
  106. }
  107. if(substr($word,-1) == 'q')
  108. $word = substr($word,0,-1);
  109. return $word;
  110. }}
  111. // escape text ($str) for XML transport
  112. // returns escaped text.
  113. if(! function_exists('xmlify')) {
  114. function xmlify($str) {
  115. $buffer = '';
  116. for($x = 0; $x < mb_strlen($str); $x ++) {
  117. $char = $str[$x];
  118. switch( $char ) {
  119. case "\r" :
  120. break;
  121. case "&" :
  122. $buffer .= '&amp;';
  123. break;
  124. case "'" :
  125. $buffer .= '&apos;';
  126. break;
  127. case "\"" :
  128. $buffer .= '&quot;';
  129. break;
  130. case '<' :
  131. $buffer .= '&lt;';
  132. break;
  133. case '>' :
  134. $buffer .= '&gt;';
  135. break;
  136. case "\n" :
  137. $buffer .= "\n";
  138. break;
  139. default :
  140. $buffer .= $char;
  141. break;
  142. }
  143. }
  144. $buffer = trim($buffer);
  145. return($buffer);
  146. }}
  147. // undo an xmlify
  148. // pass xml escaped text ($s), returns unescaped text
  149. if(! function_exists('unxmlify')) {
  150. function unxmlify($s) {
  151. $ret = str_replace('&amp;','&', $s);
  152. $ret = str_replace(array('&lt;','&gt;','&quot;','&apos;'),array('<','>','"',"'"),$ret);
  153. return $ret;
  154. }}
  155. // convenience wrapper, reverse the operation "bin2hex"
  156. if(! function_exists('hex2bin')) {
  157. function hex2bin($s) {
  158. if(! (is_string($s) && strlen($s)))
  159. return '';
  160. if(! ctype_xdigit($s)) {
  161. logger('hex2bin: illegal input: ' . print_r(debug_backtrace(), true));
  162. return($s);
  163. }
  164. return(pack("H*",$s));
  165. }}
  166. // Automatic pagination.
  167. // To use, get the count of total items.
  168. // Then call $a->set_pager_total($number_items);
  169. // Optionally call $a->set_pager_itemspage($n) to the number of items to display on each page
  170. // Then call paginate($a) after the end of the display loop to insert the pager block on the page
  171. // (assuming there are enough items to paginate).
  172. // When using with SQL, the setting LIMIT %d, %d => $a->pager['start'],$a->pager['itemspage']
  173. // will limit the results to the correct items for the current page.
  174. // The actual page handling is then accomplished at the application layer.
  175. if(! function_exists('paginate')) {
  176. function paginate(&$a) {
  177. $o = '';
  178. $stripped = preg_replace('/(&page=[0-9]*)/','',$a->query_string);
  179. $stripped = str_replace('q=','',$stripped);
  180. $stripped = trim($stripped,'/');
  181. $pagenum = $a->pager['page'];
  182. $url = $a->get_baseurl() . '/' . $stripped;
  183. if($a->pager['total'] > $a->pager['itemspage']) {
  184. $o .= '<div class="pager">';
  185. if($a->pager['page'] != 1)
  186. $o .= '<span class="pager_prev">'."<a href=\"$url".'&page='.($a->pager['page'] - 1).'">' . t('prev') . '</a></span> ';
  187. $o .= "<span class=\"pager_first\"><a href=\"$url"."&page=1\">" . t('first') . "</a></span> ";
  188. $numpages = $a->pager['total'] / $a->pager['itemspage'];
  189. $numstart = 1;
  190. $numstop = $numpages;
  191. if($numpages > 14) {
  192. $numstart = (($pagenum > 7) ? ($pagenum - 7) : 1);
  193. $numstop = (($pagenum > ($numpages - 7)) ? $numpages : ($numstart + 14));
  194. }
  195. for($i = $numstart; $i <= $numstop; $i++){
  196. if($i == $a->pager['page'])
  197. $o .= '<span class="pager_current">'.(($i < 10) ? '&nbsp;'.$i : $i);
  198. else
  199. $o .= "<span class=\"pager_n\"><a href=\"$url"."&page=$i\">".(($i < 10) ? '&nbsp;'.$i : $i)."</a>";
  200. $o .= '</span> ';
  201. }
  202. if(($a->pager['total'] % $a->pager['itemspage']) != 0) {
  203. if($i == $a->pager['page'])
  204. $o .= '<span class="pager_current">'.(($i < 10) ? '&nbsp;'.$i : $i);
  205. else
  206. $o .= "<span class=\"pager_n\"><a href=\"$url"."&page=$i\">".(($i < 10) ? '&nbsp;'.$i : $i)."</a>";
  207. $o .= '</span> ';
  208. }
  209. $lastpage = (($numpages > intval($numpages)) ? intval($numpages)+1 : $numpages);
  210. $o .= "<span class=\"pager_last\"><a href=\"$url"."&page=$lastpage\">" . t('last') . "</a></span> ";
  211. if(($a->pager['total'] - ($a->pager['itemspage'] * $a->pager['page'])) > 0)
  212. $o .= '<span class="pager_next">'."<a href=\"$url"."&page=".($a->pager['page'] + 1).'">' . t('next') . '</a></span>';
  213. $o .= '</div>'."\r\n";
  214. }
  215. return $o;
  216. }}
  217. // Turn user/group ACLs stored as angle bracketed text into arrays
  218. if(! function_exists('expand_acl')) {
  219. function expand_acl($s) {
  220. // turn string array of angle-bracketed elements into numeric array
  221. // e.g. "<1><2><3>" => array(1,2,3);
  222. $ret = array();
  223. if(strlen($s)) {
  224. $t = str_replace('<','',$s);
  225. $a = explode('>',$t);
  226. foreach($a as $aa) {
  227. if(intval($aa))
  228. $ret[] = intval($aa);
  229. }
  230. }
  231. return $ret;
  232. }}
  233. // Used to wrap ACL elements in angle brackets for storage
  234. if(! function_exists('sanitise_acl')) {
  235. function sanitise_acl(&$item) {
  236. if(intval($item))
  237. $item = '<' . intval(notags(trim($item))) . '>';
  238. else
  239. unset($item);
  240. }}
  241. // Convert an ACL array to a storable string
  242. if(! function_exists('perms2str')) {
  243. function perms2str($p) {
  244. $ret = '';
  245. $tmp = $p;
  246. if(is_array($tmp)) {
  247. array_walk($tmp,'sanitise_acl');
  248. $ret = implode('',$tmp);
  249. }
  250. return $ret;
  251. }}
  252. // generate a guaranteed unique (for this domain) item ID for ATOM
  253. // safe from birthday paradox
  254. if(! function_exists('item_new_uri')) {
  255. function item_new_uri($hostname,$uid) {
  256. do {
  257. $dups = false;
  258. $hash = random_string();
  259. $uri = "urn:X-dfrn:" . $hostname . ':' . $uid . ':' . $hash;
  260. $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' LIMIT 1",
  261. dbesc($uri));
  262. if(count($r))
  263. $dups = true;
  264. } while($dups == true);
  265. return $uri;
  266. }}
  267. // Generate a guaranteed unique photo ID.
  268. // safe from birthday paradox
  269. if(! function_exists('photo_new_resource')) {
  270. function photo_new_resource() {
  271. do {
  272. $found = false;
  273. $resource = hash('md5',uniqid(mt_rand(),true));
  274. $r = q("SELECT `id` FROM `photo` WHERE `resource-id` = '%s' LIMIT 1",
  275. dbesc($resource)
  276. );
  277. if(count($r))
  278. $found = true;
  279. } while($found == true);
  280. return $resource;
  281. }}
  282. // wrapper to load a view template, checking for alternate
  283. // languages before falling back to the default
  284. // obsolete, deprecated.
  285. if(! function_exists('load_view_file')) {
  286. function load_view_file($s) {
  287. global $lang, $a;
  288. if(! isset($lang))
  289. $lang = 'en';
  290. $b = basename($s);
  291. $d = dirname($s);
  292. if(file_exists("$d/$lang/$b"))
  293. return file_get_contents("$d/$lang/$b");
  294. $theme = current_theme();
  295. if(file_exists("$d/theme/$theme/$b"))
  296. return file_get_contents("$d/theme/$theme/$b");
  297. return file_get_contents($s);
  298. }}
  299. if(! function_exists('get_intltext_template')) {
  300. function get_intltext_template($s) {
  301. global $lang;
  302. if(! isset($lang))
  303. $lang = 'en';
  304. if(file_exists("view/$lang/$s"))
  305. return file_get_contents("view/$lang/$s");
  306. elseif(file_exists("view/en/$s"))
  307. return file_get_contents("view/en/$s");
  308. else
  309. return file_get_contents("view/$s");
  310. }}
  311. if(! function_exists('get_markup_template')) {
  312. function get_markup_template($s) {
  313. $a=get_app();
  314. $theme = current_theme();
  315. if(file_exists("view/theme/$theme/$s"))
  316. return file_get_contents("view/theme/$theme/$s");
  317. elseif (x($a->theme_info,"extends") && file_exists("view/theme/".$a->theme_info["extends"]."/$s"))
  318. return file_get_contents("view/theme/".$a->theme_info["extends"]."/$s");
  319. else
  320. return file_get_contents("view/$s");
  321. }}
  322. // for html,xml parsing - let's say you've got
  323. // an attribute foobar="class1 class2 class3"
  324. // and you want to find out if it contains 'class3'.
  325. // you can't use a normal sub string search because you
  326. // might match 'notclass3' and a regex to do the job is
  327. // possible but a bit complicated.
  328. // pass the attribute string as $attr and the attribute you
  329. // are looking for as $s - returns true if found, otherwise false
  330. if(! function_exists('attribute_contains')) {
  331. function attribute_contains($attr,$s) {
  332. $a = explode(' ', $attr);
  333. if(count($a) && in_array($s,$a))
  334. return true;
  335. return false;
  336. }}
  337. if(! function_exists('logger')) {
  338. function logger($msg,$level = 0) {
  339. // turn off logger in install mode
  340. global $a;
  341. global $db;
  342. if(($a->module == 'install') || (! ($db && $db->connected))) return;
  343. $debugging = get_config('system','debugging');
  344. $loglevel = intval(get_config('system','loglevel'));
  345. $logfile = get_config('system','logfile');
  346. if((! $debugging) || (! $logfile) || ($level > $loglevel))
  347. return;
  348. @file_put_contents($logfile, datetime_convert() . ':' . session_id() . ' ' . $msg . "\n", FILE_APPEND);
  349. return;
  350. }}
  351. if(! function_exists('activity_match')) {
  352. function activity_match($haystack,$needle) {
  353. if(($haystack === $needle) || ((basename($needle) === $haystack) && strstr($needle,NAMESPACE_ACTIVITY_SCHEMA)))
  354. return true;
  355. return false;
  356. }}
  357. // Pull out all #hashtags and @person tags from $s;
  358. // We also get @person@domain.com - which would make
  359. // the regex quite complicated as tags can also
  360. // end a sentence. So we'll run through our results
  361. // and strip the period from any tags which end with one.
  362. // Returns array of tags found, or empty array.
  363. if(! function_exists('get_tags')) {
  364. function get_tags($s) {
  365. $ret = array();
  366. // ignore anything in a code block
  367. $s = preg_replace('/\[code\](.*?)\[\/code\]/sm','',$s);
  368. // Match full names against @tags including the space between first and last
  369. // We will look these up afterward to see if they are full names or not recognisable.
  370. if(preg_match_all('/(@[^ \x0D\x0A,:?]+ [^ \x0D\x0A@,:?]+)([ \x0D\x0A@,:?]|$)/',$s,$match)) {
  371. foreach($match[1] as $mtch) {
  372. if(strstr($mtch,"]")) {
  373. // we might be inside a bbcode color tag - leave it alone
  374. continue;
  375. }
  376. if(substr($mtch,-1,1) === '.')
  377. $ret[] = substr($mtch,0,-1);
  378. else
  379. $ret[] = $mtch;
  380. }
  381. }
  382. // Otherwise pull out single word tags. These can be @nickname, @first_last
  383. // and #hash tags.
  384. if(preg_match_all('/([@#][^ \x0D\x0A,;:?]+)([ \x0D\x0A,;:?]|$)/',$s,$match)) {
  385. foreach($match[1] as $mtch) {
  386. if(strstr($mtch,"]")) {
  387. // we might be inside a bbcode color tag - leave it alone
  388. continue;
  389. }
  390. if(substr($mtch,-1,1) === '.')
  391. $mtch = substr($mtch,0,-1);
  392. // ignore strictly numeric tags like #1
  393. if((strpos($mtch,'#') === 0) && ctype_digit(substr($mtch,1)))
  394. continue;
  395. // try not to catch url fragments
  396. if(strpos($s,$mtch) && preg_match('/[a-zA-z0-9\/]/',substr($s,strpos($s,$mtch)-1,1)))
  397. continue;
  398. $ret[] = $mtch;
  399. }
  400. }
  401. return $ret;
  402. }}
  403. // quick and dirty quoted_printable encoding
  404. if(! function_exists('qp')) {
  405. function qp($s) {
  406. return str_replace ("%","=",rawurlencode($s));
  407. }}
  408. if(! function_exists('get_mentions')) {
  409. function get_mentions($item) {
  410. $o = '';
  411. if(! strlen($item['tag']))
  412. return $o;
  413. $arr = explode(',',$item['tag']);
  414. foreach($arr as $x) {
  415. $matches = null;
  416. if(preg_match('/@\[url=([^\]]*)\]/',$x,$matches)) {
  417. $o .= "\t\t" . '<link rel="mentioned" href="' . $matches[1] . '" />' . "\r\n";
  418. $o .= "\t\t" . '<link rel="ostatus:attention" href="' . $matches[1] . '" />' . "\r\n";
  419. }
  420. }
  421. return $o;
  422. }}
  423. if(! function_exists('contact_block')) {
  424. function contact_block() {
  425. $o = '';
  426. $a = get_app();
  427. $shown = get_pconfig($a->profile['uid'],'system','display_friend_count');
  428. if($shown === false)
  429. $shown = 24;
  430. if($shown == 0)
  431. return;
  432. if((! is_array($a->profile)) || ($a->profile['hide-friends']))
  433. return $o;
  434. $r = q("SELECT COUNT(*) AS `total` FROM `contact` WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 and `pending` = 0 AND `hidden` = 0",
  435. intval($a->profile['uid'])
  436. );
  437. if(count($r)) {
  438. $total = intval($r[0]['total']);
  439. }
  440. if(! $total) {
  441. $contacts = t('No contacts');
  442. $micropro = Null;
  443. } else {
  444. $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` = 0 AND `blocked` = 0 and `pending` = 0 AND `hidden` = 0 ORDER BY RAND() LIMIT %d",
  445. intval($a->profile['uid']),
  446. intval($shown)
  447. );
  448. if(count($r)) {
  449. $contacts = sprintf( tt('%d Contact','%d Contacts', $total),$total);
  450. $micropro = Array();
  451. foreach($r as $rr) {
  452. $micropro[] = micropro($rr,true,'mpfriend');
  453. }
  454. }
  455. }
  456. $tpl = get_markup_template('contact_block.tpl');
  457. $o = replace_macros($tpl, array(
  458. '$contacts' => $contacts,
  459. '$nickname' => $a->profile['nickname'],
  460. '$viewcontacts' => t('View Contacts'),
  461. '$micropro' => $micropro,
  462. ));
  463. $arr = array('contacts' => $r, 'output' => $o);
  464. call_hooks('contact_block_end', $arr);
  465. return $o;
  466. }}
  467. if(! function_exists('micropro')) {
  468. function micropro($contact, $redirect = false, $class = '', $textmode = false) {
  469. if($class)
  470. $class = ' ' . $class;
  471. $url = $contact['url'];
  472. $sparkle = '';
  473. $redir = false;
  474. if($redirect) {
  475. $a = get_app();
  476. $redirect_url = $a->get_baseurl() . '/redir/' . $contact['id'];
  477. if(local_user() && ($contact['uid'] == local_user()) && ($contact['network'] === 'dfrn')) {
  478. $redir = true;
  479. $url = $redirect_url;
  480. $sparkle = ' sparkle';
  481. }
  482. }
  483. $click = ((x($contact,'click')) ? ' onclick="' . $contact['click'] . '" ' : '');
  484. if($click)
  485. $url = '';
  486. if($textmode) {
  487. return '<div class="contact-block-textdiv' . $class . '"><a class="contact-block-link' . $class . $sparkle
  488. . (($click) ? ' fakelink' : '') . '" '
  489. . (($redir) ? ' target="redir" ' : '')
  490. . (($url) ? ' href="' . $url . '"' : '') . $click
  491. . '" title="' . $contact['name'] . ' [' . $contact['url'] . ']" alt="' . $contact['name']
  492. . '" >'. $contact['name'] . '</a></div>' . "\r\n";
  493. }
  494. else {
  495. return '<div class="contact-block-div' . $class . '"><a class="contact-block-link' . $class . $sparkle
  496. . (($click) ? ' fakelink' : '') . '" '
  497. . (($redir) ? ' target="redir" ' : '')
  498. . (($url) ? ' href="' . $url . '"' : '') . $click . ' ><img class="contact-block-img' . $class . $sparkle . '" src="'
  499. . $contact['micro'] . '" title="' . $contact['name'] . ' [' . $contact['url'] . ']" alt="' . $contact['name']
  500. . '" /></a></div>' . "\r\n";
  501. }
  502. }}
  503. if(! function_exists('search')) {
  504. function search($s,$id='search-box',$url='/search',$save = false) {
  505. $a = get_app();
  506. $o = '<div id="' . $id . '">';
  507. $o .= '<form action="' . $a->get_baseurl() . $url . '" method="get" >';
  508. $o .= '<input type="text" name="search" id="search-text" value="' . $s .'" />';
  509. $o .= '<input type="submit" name="submit" id="search-submit" value="' . t('Search') . '" />';
  510. if($save)
  511. $o .= '<input type="submit" name="save" id="search-save" value="' . t('Save') . '" />';
  512. $o .= '</form></div>';
  513. return $o;
  514. }}
  515. if(! function_exists('valid_email')) {
  516. function valid_email($x){
  517. if(preg_match('/^[_a-zA-Z0-9\-\+]+(\.[_a-zA-Z0-9\-\+]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+$/',$x))
  518. return true;
  519. return false;
  520. }}
  521. /**
  522. *
  523. * Function: linkify
  524. *
  525. * Replace naked text hyperlink with HTML formatted hyperlink
  526. *
  527. */
  528. if(! function_exists('linkify')) {
  529. function linkify($s) {
  530. $s = preg_replace("/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\'\%\$\!\+]*)/", ' <a href="$1" target="external-link">$1</a>', $s);
  531. $s = preg_replace("/\<(.*?)(src|href)=(.*?)\&amp\;(.*?)\>/ism",'<$1$2=$3&$4>',$s);
  532. return($s);
  533. }}
  534. /**
  535. *
  536. * Function: smilies
  537. *
  538. * Description:
  539. * Replaces text emoticons with graphical images
  540. *
  541. * @Parameter: string $s
  542. *
  543. * Returns string
  544. */
  545. if(! function_exists('smilies')) {
  546. function smilies($s, $sample = false) {
  547. $a = get_app();
  548. $texts = array(
  549. '&lt;3',
  550. '&lt;/3',
  551. '&lt;\\3',
  552. ':-)',
  553. // ':)',
  554. ';-)',
  555. // ';)',
  556. ':-(',
  557. // ':(',
  558. ':-P',
  559. // ':P',
  560. ':-"',
  561. ':-&quot;',
  562. ':-x',
  563. ':-X',
  564. ':-D',
  565. // ':D',
  566. '8-|',
  567. '8-O',
  568. ':-O',
  569. '\\o/',
  570. 'o.O',
  571. 'O.o',
  572. '\\.../',
  573. '\\ooo/',
  574. ":'(",
  575. ":-!",
  576. ":-/",
  577. ":-[",
  578. "8-)",
  579. ':beer',
  580. ':homebrew',
  581. ':coffee',
  582. ':facepalm',
  583. ':headdesk',
  584. '~friendika',
  585. '~friendica',
  586. 'Diaspora*'
  587. );
  588. $icons = array(
  589. '<img src="' . $a->get_baseurl() . '/images/smiley-heart.gif" alt="<3" />',
  590. '<img src="' . $a->get_baseurl() . '/images/smiley-brokenheart.gif" alt="</3" />',
  591. '<img src="' . $a->get_baseurl() . '/images/smiley-brokenheart.gif" alt="<\\3" />',
  592. '<img src="' . $a->get_baseurl() . '/images/smiley-smile.gif" alt=":-)" />',
  593. // '<img src="' . $a->get_baseurl() . '/images/smiley-smile.gif" alt=":)" />',
  594. '<img src="' . $a->get_baseurl() . '/images/smiley-wink.gif" alt=";-)" />',
  595. // '<img src="' . $a->get_baseurl() . '/images/smiley-wink.gif" alt=";)"/>',
  596. '<img src="' . $a->get_baseurl() . '/images/smiley-frown.gif" alt=":-(" />',
  597. // '<img src="' . $a->get_baseurl() . '/images/smiley-frown.gif" alt=":(" />',
  598. '<img src="' . $a->get_baseurl() . '/images/smiley-tongue-out.gif" alt=":-P" />',
  599. // '<img src="' . $a->get_baseurl() . '/images/smiley-tongue-out.gif" alt=":P" />',
  600. '<img src="' . $a->get_baseurl() . '/images/smiley-kiss.gif" alt=":-\"" />',
  601. '<img src="' . $a->get_baseurl() . '/images/smiley-kiss.gif" alt=":-\"" />',
  602. '<img src="' . $a->get_baseurl() . '/images/smiley-kiss.gif" alt=":-x" />',
  603. '<img src="' . $a->get_baseurl() . '/images/smiley-kiss.gif" alt=":-X" />',
  604. '<img src="' . $a->get_baseurl() . '/images/smiley-laughing.gif" alt=":-D" />',
  605. // '<img src="' . $a->get_baseurl() . '/images/smiley-laughing.gif" alt=":D"/>',
  606. '<img src="' . $a->get_baseurl() . '/images/smiley-surprised.gif" alt="8-|" />',
  607. '<img src="' . $a->get_baseurl() . '/images/smiley-surprised.gif" alt="8-O" />',
  608. '<img src="' . $a->get_baseurl() . '/images/smiley-surprised.gif" alt=":-O" />',
  609. '<img src="' . $a->get_baseurl() . '/images/smiley-thumbsup.gif" alt="\\o/" />',
  610. '<img src="' . $a->get_baseurl() . '/images/smiley-Oo.gif" alt="o.O" />',
  611. '<img src="' . $a->get_baseurl() . '/images/smiley-Oo.gif" alt="O.o" />',
  612. '<img src="' . $a->get_baseurl() . '/images/smiley-shaka.gif" alt="\\.../" />',
  613. '<img src="' . $a->get_baseurl() . '/images/smiley-shaka.gif" alt="\\ooo/" />',
  614. '<img src="' . $a->get_baseurl() . '/images/smiley-cry.gif" alt=":\'(" />',
  615. '<img src="' . $a->get_baseurl() . '/images/smiley-foot-in-mouth.gif" alt=":-!" />',
  616. '<img src="' . $a->get_baseurl() . '/images/smiley-undecided.gif" alt=":-/" />',
  617. '<img src="' . $a->get_baseurl() . '/images/smiley-embarassed.gif" alt=":-[" />',
  618. '<img src="' . $a->get_baseurl() . '/images/smiley-cool.gif" alt="8-)" />',
  619. '<img src="' . $a->get_baseurl() . '/images/beer_mug.gif" alt=":beer" />',
  620. '<img src="' . $a->get_baseurl() . '/images/beer_mug.gif" alt=":homebrew" />',
  621. '<img src="' . $a->get_baseurl() . '/images/coffee.gif" alt=":coffee" />',
  622. '<img src="' . $a->get_baseurl() . '/images/smiley-facepalm.gif" alt=":facepalm" />',
  623. '<img src="' . $a->get_baseurl() . '/images/smiley-bangheaddesk.gif" alt=":headdesk" />',
  624. '<a href="http://project.friendika.com">~friendika <img src="' . $a->get_baseurl() . '/images/friendika-16.png" alt="~friendika" /></a>',
  625. '<a href="http://friendica.com">~friendica <img src="' . $a->get_baseurl() . '/images/friendika-16.png" alt="~friendica" /></a>',
  626. '<a href="http://diasporafoundation.org">Diaspora<img src="' . $a->get_baseurl() . '/images/diaspora.png" alt="Diaspora*" /></a>',
  627. );
  628. $params = array('texts' => $texts, 'icons' => $icons, 'string' => $s);
  629. call_hooks('smilie', $params);
  630. if($sample) {
  631. $s = '<div class="smiley-sample">';
  632. for($x = 0; $x < count($params['texts']); $x ++) {
  633. $s .= '<dl><dt>' . $params['texts'][$x] . '</dt><dd>' . $params['icons'][$x] . '</dd></dl>';
  634. }
  635. }
  636. else {
  637. $s = str_replace($params['texts'],$params['icons'],$params['string']);
  638. }
  639. return $s;
  640. }}
  641. if(! function_exists('day_translate')) {
  642. function day_translate($s) {
  643. $ret = str_replace(array('Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'),
  644. array( t('Monday'), t('Tuesday'), t('Wednesday'), t('Thursday'), t('Friday'), t('Saturday'), t('Sunday')),
  645. $s);
  646. $ret = str_replace(array('January','February','March','April','May','June','July','August','September','October','November','December'),
  647. array( t('January'), t('February'), t('March'), t('April'), t('May'), t('June'), t('July'), t('August'), t('September'), t('October'), t('November'), t('December')),
  648. $ret);
  649. return $ret;
  650. }}
  651. if(! function_exists('normalise_link')) {
  652. function normalise_link($url) {
  653. $ret = str_replace(array('https:','//www.'), array('http:','//'), $url);
  654. return(rtrim($ret,'/'));
  655. }}
  656. /**
  657. *
  658. * Compare two URLs to see if they are the same, but ignore
  659. * slight but hopefully insignificant differences such as if one
  660. * is https and the other isn't, or if one is www.something and
  661. * the other isn't - and also ignore case differences.
  662. *
  663. * Return true if the URLs match, otherwise false.
  664. *
  665. */
  666. if(! function_exists('link_compare')) {
  667. function link_compare($a,$b) {
  668. if(strcasecmp(normalise_link($a),normalise_link($b)) === 0)
  669. return true;
  670. return false;
  671. }}
  672. // Given an item array, convert the body element from bbcode to html and add smilie icons.
  673. // If attach is true, also add icons for item attachments
  674. if(! function_exists('prepare_body')) {
  675. function prepare_body($item,$attach = false) {
  676. call_hooks('prepare_body_init', $item);
  677. $s = prepare_text($item['body']);
  678. $prep_arr = array('item' => $item, 'html' => $s);
  679. call_hooks('prepare_body', $prep_arr);
  680. $s = $prep_arr['html'];
  681. if(! $attach)
  682. return $s;
  683. $arr = explode(',',$item['attach']);
  684. if(count($arr)) {
  685. $s .= '<div class="body-attach">';
  686. foreach($arr as $r) {
  687. $matches = false;
  688. $icon = '';
  689. $cnt = preg_match('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\" title=\"(.*?)\"\[\/attach\]|',$r,$matches);
  690. if($cnt) {
  691. $icontype = strtolower(substr($matches[3],0,strpos($matches[3],'/')));
  692. switch($icontype) {
  693. case 'video':
  694. case 'audio':
  695. case 'image':
  696. case 'text':
  697. $icon = '<div class="attachtype icon s22 type-' . $icontype . '"></div>';
  698. break;
  699. default:
  700. $icon = '<div class="attachtype icon s22 type-unkn"></div>';
  701. break;
  702. }
  703. $title = ((strlen(trim($matches[4]))) ? escape_tags(trim($matches[4])) : escape_tags($matches[1]));
  704. $title .= ' ' . $matches[2] . ' ' . t('bytes');
  705. $s .= '<a href="' . strip_tags($matches[1]) . '" title="' . $title . '" class="attachlink" target="external-link" >' . $icon . '</a>';
  706. }
  707. }
  708. $s .= '<div class="clear"></div></div>';
  709. }
  710. $prep_arr = array('item' => $item, 'html' => $s);
  711. call_hooks('prepare_body_final', $prep_arr);
  712. return $prep_arr['html'];
  713. }}
  714. // Given a text string, convert from bbcode to html and add smilie icons.
  715. if(! function_exists('prepare_text')) {
  716. function prepare_text($text) {
  717. require_once('include/bbcode.php');
  718. if(stristr($text,'[nosmile]'))
  719. $s = bbcode($text);
  720. else
  721. $s = smilies(bbcode($text));
  722. return $s;
  723. }}
  724. /**
  725. * return atom link elements for all of our hubs
  726. */
  727. if(! function_exists('feed_hublinks')) {
  728. function feed_hublinks() {
  729. $hub = get_config('system','huburl');
  730. $hubxml = '';
  731. if(strlen($hub)) {
  732. $hubs = explode(',', $hub);
  733. if(count($hubs)) {
  734. foreach($hubs as $h) {
  735. $h = trim($h);
  736. if(! strlen($h))
  737. continue;
  738. $hubxml .= '<link rel="hub" href="' . xmlify($h) . '" />' . "\n" ;
  739. }
  740. }
  741. }
  742. return $hubxml;
  743. }}
  744. /* return atom link elements for salmon endpoints */
  745. if(! function_exists('feed_salmonlinks')) {
  746. function feed_salmonlinks($nick) {
  747. $a = get_app();
  748. $salmon = '<link rel="salmon" href="' . xmlify($a->get_baseurl() . '/salmon/' . $nick) . '" />' . "\n" ;
  749. // old style links that status.net still needed as of 12/2010
  750. $salmon .= ' <link rel="http://salmon-protocol.org/ns/salmon-replies" href="' . xmlify($a->get_baseurl() . '/salmon/' . $nick) . '" />' . "\n" ;
  751. $salmon .= ' <link rel="http://salmon-protocol.org/ns/salmon-mention" href="' . xmlify($a->get_baseurl() . '/salmon/' . $nick) . '" />' . "\n" ;
  752. return $salmon;
  753. }}
  754. if(! function_exists('get_plink')) {
  755. function get_plink($item) {
  756. $a = get_app();
  757. if (x($item,'plink') && (! $item['private'])){
  758. return array(
  759. 'href' => $item['plink'],
  760. 'title' => t('link to source'),
  761. );
  762. } else {
  763. return false;
  764. }
  765. }}
  766. if(! function_exists('unamp')) {
  767. function unamp($s) {
  768. return str_replace('&amp;', '&', $s);
  769. }}
  770. if(! function_exists('lang_selector')) {
  771. function lang_selector() {
  772. global $lang;
  773. $o = '<div id="lang-select-icon" class="icon language" title="' . t('Select an alternate language') . '" onclick="openClose(\'language-selector\');" ></div>';
  774. $o .= '<div id="language-selector" style="display: none;" >';
  775. $o .= '<form action="#" method="post" ><select name="system_language" onchange="this.form.submit();" >';
  776. $langs = glob('view/*/strings.php');
  777. if(is_array($langs) && count($langs)) {
  778. $langs[] = '';
  779. if(! in_array('view/en/strings.php',$langs))
  780. $langs[] = 'view/en/';
  781. asort($langs);
  782. foreach($langs as $l) {
  783. if($l == '') {
  784. $default_selected = ((! x($_SESSION,'language')) ? ' selected="selected" ' : '');
  785. $o .= '<option value="" ' . $default_selected . '>' . t('default') . '</option>';
  786. continue;
  787. }
  788. $ll = substr($l,5);
  789. $ll = substr($ll,0,strrpos($ll,'/'));
  790. $selected = (($ll === $lang && (x($_SESSION['language']))) ? ' selected="selected" ' : '');
  791. $o .= '<option value="' . $ll . '"' . $selected . '>' . $ll . '</option>';
  792. }
  793. }
  794. $o .= '</select></form></div>';
  795. return $o;
  796. }}
  797. if(! function_exists('return_bytes')) {
  798. function return_bytes ($size_str) {
  799. switch (substr ($size_str, -1))
  800. {
  801. case 'M': case 'm': return (int)$size_str * 1048576;
  802. case 'K': case 'k': return (int)$size_str * 1024;
  803. case 'G': case 'g': return (int)$size_str * 1073741824;
  804. default: return $size_str;
  805. }
  806. }}
  807. function generate_user_guid() {
  808. $found = true;
  809. do {
  810. $guid = random_string(16);
  811. $x = q("SELECT `uid` FROM `user` WHERE `guid` = '%s' LIMIT 1",
  812. dbesc($guid)
  813. );
  814. if(! count($x))
  815. $found = false;
  816. } while ($found == true );
  817. return $guid;
  818. }
  819. function base64url_encode($s, $strip_padding = false) {
  820. $s = strtr(base64_encode($s),'+/','-_');
  821. if($strip_padding)
  822. $s = str_replace('=','',$s);
  823. return $s;
  824. }
  825. function base64url_decode($s) {
  826. if(is_array($s)) {
  827. logger('base64url_decode: illegal input: ' . print_r(debug_backtrace(), true));
  828. return $s;
  829. }
  830. /*
  831. * // Placeholder for new rev of salmon which strips base64 padding.
  832. * // PHP base64_decode handles the un-padded input without requiring this step
  833. * // Uncomment if you find you need it.
  834. *
  835. * $l = strlen($s);
  836. * if(! strpos($s,'=')) {
  837. * $m = $l % 4;
  838. * if($m == 2)
  839. * $s .= '==';
  840. * if($m == 3)
  841. * $s .= '=';
  842. * }
  843. *
  844. */
  845. return base64_decode(strtr($s,'-_','+/'));
  846. }
  847. if (!function_exists('str_getcsv')) {
  848. function str_getcsv($input, $delimiter = ',', $enclosure = '"', $escape = '\\', $eol = '\n') {
  849. if (is_string($input) && !empty($input)) {
  850. $output = array();
  851. $tmp = preg_split("/".$eol."/",$input);
  852. if (is_array($tmp) && !empty($tmp)) {
  853. while (list($line_num, $line) = each($tmp)) {
  854. if (preg_match("/".$escape.$enclosure."/",$line)) {
  855. while ($strlen = strlen($line)) {
  856. $pos_delimiter = strpos($line,$delimiter);
  857. $pos_enclosure_start = strpos($line,$enclosure);
  858. if (
  859. is_int($pos_delimiter) && is_int($pos_enclosure_start)
  860. && ($pos_enclosure_start < $pos_delimiter)
  861. ) {
  862. $enclosed_str = substr($line,1);
  863. $pos_enclosure_end = strpos($enclosed_str,$enclosure);
  864. $enclosed_str = substr($enclosed_str,0,$pos_enclosure_end);
  865. $output[$line_num][] = $enclosed_str;
  866. $offset = $pos_enclosure_end+3;
  867. } else {
  868. if (empty($pos_delimiter) && empty($pos_enclosure_start)) {
  869. $output[$line_num][] = substr($line,0);
  870. $offset = strlen($line);
  871. } else {
  872. $output[$line_num][] = substr($line,0,$pos_delimiter);
  873. $offset = (
  874. !empty($pos_enclosure_start)
  875. && ($pos_enclosure_start < $pos_delimiter)
  876. )
  877. ?$pos_enclosure_start
  878. :$pos_delimiter+1;
  879. }
  880. }
  881. $line = substr($line,$offset);
  882. }
  883. } else {
  884. $line = preg_split("/".$delimiter."/",$line);
  885. /*
  886. * Validating against pesky extra line breaks creating false rows.
  887. */
  888. if (is_array($line) && !empty($line[0])) {
  889. $output[$line_num] = $line;
  890. }
  891. }
  892. }
  893. return $output;
  894. } else {
  895. return false;
  896. }
  897. } else {
  898. return false;
  899. }
  900. }
  901. }
  902. function cleardiv() {
  903. return '<div class="clear"></div>';
  904. }
  905. function bb_translate_video($s) {
  906. $matches = null;
  907. $r = preg_match_all("/\[video\](.*?)\[\/video\]/ism",$s,$matches,PREG_SET_ORDER);
  908. if($r) {
  909. foreach($matches as $mtch) {
  910. if((stristr($mtch[1],'youtube')) || (stristr($mtch[1],'youtu.be')))
  911. $s = str_replace($mtch[0],'[youtube]' . $mtch[1] . '[/youtube]',$s);
  912. elseif(stristr($mtch[1],'vimeo'))
  913. $s = str_replace($mtch[0],'[vimeo]' . $mtch[1] . '[/vimeo]',$s);
  914. }
  915. }
  916. return $s;
  917. }
  918. function html2bb_video($s) {
  919. $s = preg_replace('#<object[^>]+>(.*?)https+://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+)(.*?)</object>#ism',
  920. '[youtube]$2[/youtube]', $s);
  921. $s = preg_replace('#<iframe[^>](.*?)https+://www.youtube.com/embed/([A-Za-z0-9\-_=]+)(.*?)</iframe>#ism',
  922. '[youtube]$2[/youtube]', $s);
  923. $s = preg_replace('#<iframe[^>](.*?)https+://player.vimeo.com/video/([0-9]+)(.*?)</iframe>#ism',
  924. '[vimeo]$2[/vimeo]', $s);
  925. return $s;
  926. }
  927. /**
  928. * apply xmlify() to all values of array $val, recursively
  929. */
  930. function array_xmlify($val){
  931. if (is_bool($val)) return $val?"true":"false";
  932. if (is_array($val)) return array_map('array_xmlify', $val);
  933. return xmlify((string) $val);
  934. }
  935. function reltoabs($text, $base)
  936. {
  937. if (empty($base))
  938. return $text;
  939. $base = rtrim($base,'/');
  940. $base2 = $base . "/";
  941. // Replace links
  942. $pattern = "/<a([^>]*) href=\"(?!http|https|\/)([^\"]*)\"/";
  943. $replace = "<a\${1} href=\"" . $base2 . "\${2}\"";
  944. $text = preg_replace($pattern, $replace, $text);
  945. $pattern = "/<a([^>]*) href=\"(?!http|https)([^\"]*)\"/";
  946. $replace = "<a\${1} href=\"" . $base . "\${2}\"";
  947. $text = preg_replace($pattern, $replace, $text);
  948. // Replace images
  949. $pattern = "/<img([^>]*) src=\"(?!http|https|\/)([^\"]*)\"/";
  950. $replace = "<img\${1} src=\"" . $base2 . "\${2}\"";
  951. $text = preg_replace($pattern, $replace, $text);
  952. $pattern = "/<img([^>]*) src=\"(?!http|https)([^\"]*)\"/";
  953. $replace = "<img\${1} src=\"" . $base . "\${2}\"";
  954. $text = preg_replace($pattern, $replace, $text);
  955. // Done
  956. return $text;
  957. }