]> git.mxchange.org Git - friendica.git/blob - boot.php
3f2a2551b800b57262e8fd87a84b4d9039c9523a
[friendica.git] / boot.php
1 <?php
2
3 set_time_limit(0);
4
5 define ( 'BUILD_ID' , 1006 );
6
7 define ( 'EOL', "<br />\r\n");
8 define ( 'ATOM_TIME',  'Y-m-d\TH:i:s\Z' );
9
10 define ( 'REGISTER_CLOSED',  0);
11 define ( 'REGISTER_APPROVE', 1);
12 define ( 'REGISTER_OPEN',    2);
13
14 // relationship types
15
16 define ( 'REL_VIP',        1);
17 define ( 'REL_FAN',        2);
18 define ( 'REL_BUD',        3);
19
20 define ( 'NOTIFY_INTRO',   0x0001 );
21 define ( 'NOTIFY_CONFIRM', 0x0002 );
22 define ( 'NOTIFY_WALL',    0x0004 );
23 define ( 'NOTIFY_COMMENT', 0x0008 );
24 define ( 'NOTIFY_MAIL',    0x0010 );
25
26 define ( 'NAMESPACE_DFRN' ,           'http://purl.org/macgirvin/dfrn/1.0' ); 
27 define ( 'NAMESPACE_THREAD' ,         'http://purl.org/syndication/thread/1.0' );
28 define ( 'NAMESPACE_TOMB' ,           'http://purl.org/atompub/tombstones/1.0' );
29 define ( 'NAMESPACE_ACTIVITY',        'http://activitystrea.ms/spec/1.0/' );
30 define ( 'NAMESPACE_ACTIVITY_SCHEMA', 'http://activitystrea.ms/schema/1.0/');
31 define ( 'NAMESPACE_SALMON_ME',       'http://salmon-protocol.org/ns/magic-env');
32
33 define ( 'ACTIVITY_LIKE',        NAMESPACE_ACTIVITY_SCHEMA . 'like' );
34 define ( 'ACTIVITY_DISLIKE',     NAMESPACE_DFRN            . '/dislike' );
35 define ( 'ACTIVITY_OBJ_HEART',   NAMESPACE_DFRN            . '/heart' );
36
37 define ( 'ACTIVITY_FRIEND',      NAMESPACE_ACTIVITY_SCHEMA . 'make-friend' );
38 define ( 'ACTIVITY_POST',        NAMESPACE_ACTIVITY_SCHEMA . 'post' );
39 define ( 'ACTIVITY_UPDATE',      NAMESPACE_ACTIVITY_SCHEMA . 'update' );
40
41 define ( 'ACTIVITY_OBJ_COMMENT', NAMESPACE_ACTIVITY_SCHEMA . 'comment' );
42 define ( 'ACTIVITY_OBJ_NOTE',    NAMESPACE_ACTIVITY_SCHEMA . 'note' );
43 define ( 'ACTIVITY_OBJ_PERSON',  NAMESPACE_ACTIVITY_SCHEMA . 'person' );
44 define ( 'ACTIVITY_OBJ_PHOTO',   NAMESPACE_ACTIVITY_SCHEMA . 'photo' );
45 define ( 'ACTIVITY_OBJ_P_PHOTO', NAMESPACE_ACTIVITY_SCHEMA . 'profile-photo' );
46 define ( 'ACTIVITY_OBJ_ALBUM',   NAMESPACE_ACTIVITY_SCHEMA . 'photo-album' );
47
48 define ( 'GRAVITY_PARENT',       0);
49 define ( 'GRAVITY_LIKE',         3);
50 define ( 'GRAVITY_COMMENT',      6);
51
52
53 // Our main application structure for the life of this page
54 // Primarily deals with the URL that got us here
55 // and tries to make some sense of it, and 
56 // stores our page contents and config storage
57 // and anything else that might need to be passed around 
58 // before we spit the page out. 
59
60 if(! class_exists('App')) {
61 class App {
62
63         public  $module_loaded = false;
64         public  $config;
65         public  $page;
66         public  $profile;
67         public  $user;
68         public  $cid;
69         public  $contact;
70         public  $content;
71         public  $data;
72         public  $error = false;
73         public  $cmd;
74         public  $argv;
75         public  $argc;
76         public  $module;
77         public  $pager;
78         public  $strings;   
79         public  $path;
80
81         private $scheme;
82         private $hostname;
83         private $baseurl;
84         private $db;
85
86         function __construct() {
87
88                 $this->config = array();
89                 $this->page = array();
90                 $this->pager= array();
91
92                 $this->scheme = ((isset($_SERVER['HTTPS']) 
93                                 && ($_SERVER['HTTPS'])) ?  'https' : 'http' );
94                 $this->hostname = str_replace('www.','',
95                                 $_SERVER['SERVER_NAME']);
96                 set_include_path("include/$this->hostname" 
97                                 . PATH_SEPARATOR . 'include' 
98                                 . PATH_SEPARATOR . '.' );
99
100                 if(substr($_SERVER['QUERY_STRING'],0,2) == "q=")
101                         $_SERVER['QUERY_STRING'] = substr($_SERVER['QUERY_STRING'],2);
102                 $this->cmd = trim($_GET['q'],'/');
103
104
105                 $this->argv = explode('/',$this->cmd);
106                 $this->argc = count($this->argv);
107                 if((array_key_exists('0',$this->argv)) && strlen($this->argv[0])) {
108                         $this->module = $this->argv[0];
109                 }
110                 else {
111                         $this->module = 'home';
112                 }
113
114                 if($this->cmd === '.well-known/host-meta')
115                         require_once('include/hostxrd.php');
116
117                 $this->pager['page'] = ((x($_GET,'page')) ? $_GET['page'] : 1);
118                 $this->pager['itemspage'] = 50;
119                 $this->pager['start'] = ($this->pager['page'] * $this->pager['itemspage']) - $this->pager['itemspage'];
120                 $this->pager['total'] = 0;
121         }
122
123         function get_baseurl($ssl = false) {
124                 if(strlen($this->baseurl))
125                         return $this->baseurl;
126
127                 $this->baseurl = (($ssl) ? 'https' : $this->scheme) . "://" . $this->hostname
128                         . ((isset($this->path) && strlen($this->path)) 
129                         ? '/' . $this->path : '' );
130                 return $this->baseurl;
131         }
132
133         function set_baseurl($url) {
134                 $this->baseurl = $url;
135                 $this->hostname = basename($url);
136         }
137
138         function get_hostname() {
139                 return $this->hostname;
140         }
141
142         function set_hostname($h) {
143                 $this->hostname = $h;
144         }
145
146         function set_path($p) {
147                 $this->path = ltrim(trim($p),'/');
148         } 
149
150         function get_path() {
151                 return $this->path;
152         }
153
154         function set_pager_total($n) {
155                 $this->pager['total'] = intval($n);
156         }
157
158         function set_pager_itemspage($n) {
159                 $this->pager['itemspage'] = intval($n);
160                 $this->pager['start'] = ($this->pager['page'] * $this->pager['itemspage']) - $this->pager['itemspage'];
161
162         } 
163
164         function init_pagehead() {
165                 $tpl = load_view_file("view/head.tpl");
166                 $this->page['htmlhead'] = replace_macros($tpl,array(
167                         '$baseurl' => $this->get_baseurl()
168                 ));
169         }
170
171 }}
172
173 // retrieve the App structure
174 // useful in functions which require it but don't get it passed to them
175
176 if(! function_exists('get_app')) {
177 function get_app() {
178         global $a;
179         return $a;
180 }};
181
182
183 // Multi-purpose function to check variable state.
184 // Usage: x($var) or $x($array,'key')
185 // returns false if variable/key is not set
186 // if variable is set, returns 1 if has 'non-zero' value, otherwise returns 0.
187 // e.g. x('') or x(0) returns 0;
188
189 if(! function_exists('x')) {
190 function x($s,$k = NULL) {
191         if($k != NULL) {
192                 if((is_array($s)) && (array_key_exists($k,$s))) {
193                         if($s[$k])
194                                 return (int) 1;
195                         return (int) 0;
196                 }
197                 return false;
198         }
199         else {          
200                 if(isset($s)) {
201                         if($s) {
202                                 return (int) 1;
203                         }
204                         return (int) 0;
205                 }
206                 return false;
207         }
208 }}
209
210 // called from db initialisation if db is dead.
211
212 if(! function_exists('system_unavailable')) {
213 function system_unavailable() {
214         include('system_unavailable.php');
215         killme();
216 }}
217
218 // Primarily involved with database upgrade, but also sets the 
219 // base url for use in cmdline programs which don't have
220 // $_SERVER variables.
221
222 if(! function_exists('check_config')) {
223 function check_config(&$a) {
224
225         load_config('system');
226
227         $build = get_config('system','build');
228         if(! x($build))
229                 $build = set_config('system','build',BUILD_ID);
230
231         $url = get_config('system','url');
232         if(! x($url))
233                 $url = set_config('system','url',$a->get_baseurl());
234
235         if($build != BUILD_ID) {
236                 $stored = intval($build);
237                 $current = intval(BUILD_ID);
238                 if(($stored < $current) && file_exists('update.php')) {
239
240                         // We're reporting a different version than what is currently installed.
241                         // Run any existing update scripts to bring the database up to current.
242
243                         require_once('update.php');
244                         for($x = $stored; $x < $current; $x ++) {
245                                 if(function_exists('update_' . $x)) {
246                                         $func = 'update_' . $x;
247                                         $func($a);
248                                 }
249                         }
250                         set_config('system','build', BUILD_ID);
251                 }
252         }
253         return;
254 }}
255
256
257 // This is our template processor.
258 // $s is the string requiring macro substitution.
259 // $r is an array of key value pairs (search => replace)
260 // returns substituted string.
261 // WARNING: this is pretty basic, and doesn't properly handle search strings that are substrings of each other.
262 // For instance if 'test' => "foo" and 'testing' => "bar", testing could become either bar or fooing, 
263 // depending on the order in which they were declared in the array.   
264
265 if(! function_exists('replace_macros')) {  
266 function replace_macros($s,$r) {
267
268         $search = array();
269         $replace = array();
270
271         if(is_array($r) && count($r)) {
272                 foreach ($r as $k => $v ) {
273                         $search[] =  $k;
274                         $replace[] = $v;
275                 }
276         }
277         return str_replace($search,$replace,$s);
278 }}
279
280
281 // load string tranlsation table for alternate language
282
283 if(! function_exists('load_translation_table')) {
284 function load_translation_table($lang) {
285         global $a;
286
287         if(file_exists("view/$lang/strings.php"))
288                 include("view/$lang/strings.php");
289 }}
290
291 // translate string if translation exists
292
293 if(! function_exists('t')) {
294 function t($s) {
295         
296         $a = get_app();
297
298         if($a->strings[$s])
299                 return $a->strings[$s];
300         return $s;
301 }}
302
303 // curl wrapper. If binary flag is true, return binary
304 // results. 
305
306 if(! function_exists('fetch_url')) {
307 function fetch_url($url,$binary = false) {
308         $ch = curl_init($url);
309         if(! $ch) return false;
310
311         curl_setopt($ch, CURLOPT_HEADER, 0);
312         curl_setopt($ch, CURLOPT_FOLLOWLOCATION,true);
313         curl_setopt($ch, CURLOPT_MAXREDIRS,8);
314         curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
315
316         // by default we will allow self-signed certs
317         // but you can override this
318
319         $check_cert = get_config('system','verifyssl');
320         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, (($check_cert) ? true : false));
321
322         $prx = get_config('system','proxy');
323         if(strlen($prx)) {
324                 curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
325                 curl_setopt($ch, CURLOPT_PROXY, $prx);
326                 $prxusr = get_config('system','proxyuser');
327                 if(strlen($prxusr))
328                         curl_setopt($ch, CURLOPT_PROXYUSERPWD, $prxusr);
329         }
330         if($binary)
331                 curl_setopt($ch, CURLOPT_BINARYTRANSFER,1);
332
333         $s = curl_exec($ch);
334         curl_close($ch);
335         return($s);
336 }}
337
338 // post request to $url. $params is an array of post variables.
339
340 if(! function_exists('post_url')) {
341 function post_url($url,$params) {
342         $ch = curl_init($url);
343         if(! $ch) return false;
344
345         curl_setopt($ch, CURLOPT_HEADER, 0);
346         curl_setopt($ch, CURLOPT_FOLLOWLOCATION,true);
347         curl_setopt($ch, CURLOPT_MAXREDIRS,8);
348         curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
349         curl_setopt($ch, CURLOPT_POST,1);
350         curl_setopt($ch, CURLOPT_POSTFIELDS,$params);
351         $check_cert = get_config('system','verifyssl');
352         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, (($check_cert) ? true : false));
353         $prx = get_config('system','proxy');
354         if(strlen($prx)) {
355                 curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
356                 curl_setopt($ch, CURLOPT_PROXY, $prx);
357                 $prxusr = get_config('system','proxyuser');
358                 if(strlen($prxusr))
359                         curl_setopt($ch, CURLOPT_PROXYUSERPWD, $prxusr);
360         }
361
362         $s = curl_exec($ch);
363         curl_close($ch);
364         return($s);
365 }}
366
367 // random hash, 64 chars
368
369 if(! function_exists('random_string')) {
370 function random_string() {
371         return(hash('sha256',uniqid(rand(),true)));
372 }}
373
374 // This is our primary input filter. The high bit hack only involved some old
375 // IE browser, forget which. 
376 // Use this on any text input where angle chars are not valid or permitted
377 // They will be replaced with safer brackets. This may be filtered further
378 // if these are not allowed either.   
379
380 if(! function_exists('notags')) {
381 function notags($string) {
382         // protect against :<> with high-bit set
383         return(str_replace(array("<",">","\xBA","\xBC","\xBE"), array('[',']','','',''), $string));
384 }}
385
386 // use this on "body" or "content" input where angle chars shouldn't be removed,
387 // and allow them to be safely displayed.
388
389 if(! function_exists('escape_tags')) {
390 function escape_tags($string) {
391
392         return(htmlspecialchars($string));
393 }}
394
395 // wrapper for adding a login box. If $register == true provide a registration
396 // link. This will most always depend on the value of $a->config['register_policy'].
397
398 if(! function_exists('login')) {
399 function login($register = false) {
400         $o = "";
401         $register_html = (($register) ? load_view_file("view/register-link.tpl") : "");
402
403
404         if(x($_SESSION,'authenticated')) {
405                 $o = load_view_file("view/logout.tpl");
406         }
407         else {
408                 $o = load_view_file("view/login.tpl");
409
410                 $o = replace_macros($o,array('$register_html' => $register_html ));
411         }
412         return $o;
413 }}
414
415 // generate a string that's random, but usually pronounceable. 
416 // used to generate initial passwords
417
418 if(! function_exists('autoname')) {
419 function autoname($len) {
420
421         $vowels = array('a','a','ai','au','e','e','e','ee','ea','i','ie','o','ou','u'); 
422         if(mt_rand(0,5) == 4)
423                 $vowels[] = 'y';
424
425         $cons = array(
426                         'b','bl','br',
427                         'c','ch','cl','cr',
428                         'd','dr',
429                         'f','fl','fr',
430                         'g','gh','gl','gr',
431                         'h',
432                         'j',
433                         'k','kh','kl','kr',
434                         'l',
435                         'm',
436                         'n',
437                         'p','ph','pl','pr',
438                         'qu',
439                         'r','rh',
440                         's','sc','sh','sm','sp','st',
441                         't','th','tr',
442                         'v',
443                         'w','wh',
444                         'x',
445                         'z','zh'
446                         );
447
448         $midcons = array('ck','ct','gn','ld','lf','lm','lt','mb','mm', 'mn','mp',
449                                 'nd','ng','nk','nt','rn','rp','rt');
450
451         $noend = array('bl', 'br', 'cl','cr','dr','fl','fr','gl','gr',
452                                 'kh', 'kl','kr','mn','pl','pr','rh','tr','qu','wh');
453
454         $start = mt_rand(0,2);
455         if($start == 0)
456                 $table = $vowels;
457         else
458                 $table = $cons;
459
460         $word = '';
461
462         for ($x = 0; $x < $len; $x ++) {
463                 $r = mt_rand(0,count($table) - 1);
464                 $word .= $table[$r];
465   
466                 if($table == $vowels)
467                         $table = array_merge($cons,$midcons);
468                 else
469                         $table = $vowels;
470
471         }
472
473         $word = substr($word,0,$len);
474
475         foreach($noend as $noe) {
476                 if((strlen($word) > 2) && (substr($word,-2) == $noe)) {
477                         $word = substr($word,0,-1);
478                         break;
479                 }
480         }
481         if(substr($word,-1) == 'q')
482                 $word = substr($word,0,-1);    
483         return $word;
484 }}
485
486 // Used to end the current process, after saving session state. 
487
488 if(! function_exists('killme')) {
489 function killme() {
490         session_write_close();
491         exit;
492 }}
493
494 // redirect to another URL and terminate this process.
495
496 if(! function_exists('goaway')) {
497 function goaway($s) {
498         header("Location: $s");
499         killme();
500 }}
501
502 // Generic XML return
503 // Outputs a basic dfrn XML status structure to STDOUT, with a <status> variable 
504 // of $st and an optional text <message> of $message and terminates the current process. 
505
506 if(! function_exists('xml_status')) {
507 function xml_status($st, $message = '') {
508
509         if(strlen($message))
510                 $xml_message = "\t<message>" . xmlify($message) . "</message>\r\n";
511
512         header( "Content-type: text/xml" );
513         echo '<?xml version="1.0" encoding="UTF-8"?>'."\r\n";
514         echo "<result>\r\n\t<status>$st</status>\r\n$xml_message</result>\r\n";
515         killme();
516 }}
517
518 // Returns the uid of locally logged on user or false.
519
520 if(! function_exists('local_user')) {
521 function local_user() {
522         if((x($_SESSION,'authenticated')) && (x($_SESSION,'uid')))
523                 return $_SESSION['uid'];
524         return false;
525 }}
526
527 // Returns contact id of authenticated site visitor or false
528
529 if(! function_exists('remote_user')) {
530 function remote_user() {
531         if((x($_SESSION,'authenticated')) && (x($_SESSION,'visitor_id')))
532                 return $_SESSION['visitor_id'];
533         return false;
534 }}
535
536 // contents of $s are displayed prominently on the page the next time
537 // a page is loaded. Usually used for errors or alerts.
538
539 if(! function_exists('notice')) {
540 function notice($s) {
541
542         $_SESSION['sysmsg'] .= $s;
543
544 }}
545
546 // wrapper around config to limit the text length of an incoming message
547
548 if(! function_exists('get_max_import_size')) {
549 function get_max_import_size() {
550         global $a;
551         return ((x($a->config,'max_import_size')) ? $a->config['max_import_size'] : 0 );
552 }}
553
554
555 // escape text ($str) for XML transport
556 // returns escaped text.
557
558 if(! function_exists('xmlify')) {
559 function xmlify($str) {
560         $buffer = '';
561         
562         for($x = 0; $x < strlen($str); $x ++) {
563                 $char = $str[$x];
564         
565                 switch( $char ) {
566
567                         case "\r" :
568                                 break;
569                         case "&" :
570                                 $buffer .= '&amp;';
571                                 break;
572                         case "'" :
573                                 $buffer .= '&apos;';
574                                 break;
575
576                         case "\"" :
577                                 $buffer .= '&quot;';
578                                 break;
579                         case '<' :
580                                 $buffer .= '&lt;';
581                                 break;
582                         case '>' :
583                                 $buffer .= '&gt;';
584                                 break;
585                         case "\n" :
586                                 $buffer .= ' ';
587                                 break;
588                         default :
589                                 $buffer .= $char;
590                                 break;
591                 }       
592         }
593         $buffer = trim($buffer);
594         return($buffer);
595 }}
596
597 // undo an xmlify
598 // pass xml escaped text ($s), returns unescaped text
599
600 if(! function_exists('unxmlify')) {
601 function unxmlify($s) {
602         $ret = str_replace('&amp;','&', $s);
603         $ret = str_replace(array('&lt;','&gt;','&quot;','&apos;'),array('<','>','"',"'"),$ret);
604         return $ret;    
605 }}
606
607 // convenience wrapper, reverse the operation "bin2hex"
608
609 if(! function_exists('hex2bin')) {
610 function hex2bin($s) {
611         return(pack("H*",$s));
612 }}
613
614 // Automatic pagination.
615 // To use, get the count of total items.
616 // Then call $a->set_pager_total($number_items);
617 // Optionally call $a->set_pager_itemspage($n) to the number of items to display on each page
618 // Then call paginate($a) after the end of the display loop to insert the pager block on the page
619 // (assuming there are enough items to paginate).
620 // When using with SQL, the setting LIMIT %d, %d => $a->pager['start'],$a->pager['itemspage']
621 // will limit the results to the correct items for the current page. 
622 // The actual page handling is then accomplished at the application layer. 
623
624 if(! function_exists('paginate')) {
625 function paginate(&$a) {
626         $o = '';
627         $stripped = ereg_replace("(&page=[0-9]*)","",$_SERVER['QUERY_STRING']);
628         $stripped = str_replace('q=','',$stripped);
629         $stripped = trim($stripped,'/');
630         $url = $a->get_baseurl() . '/' . $stripped;
631
632
633           if($a->pager['total'] > $a->pager['itemspage']) {
634                 $o .= '<div class="pager">';
635                 if($a->pager['page'] != 1)
636                         $o .= '<span class="pager_prev">'."<a href=\"$url".'&page='.($a->pager['page'] - 1).'">' . t('prev') . '</a></span> ';
637
638                 $o .=  "<span class=\"pager_first\"><a href=\"$url"."&page=1\">" . t('first') . "</a></span> ";
639
640                 $numpages = $a->pager['total'] / $a->pager['itemspage'];
641
642                 $numstart = 1;
643                 $numstop = $numpages;
644
645                 if($numpages > 14) {
646                         $numstart = (($pagenum > 7) ? ($pagenum - 7) : 1);
647                         $numstop = (($pagenum > ($numpages - 7)) ? $numpages : ($numstart + 14));
648                 }
649    
650                 for($i = $numstart; $i <= $numstop; $i++){
651                         if($i == $a->pager['page'])
652                                 $o .= '<span class="pager_current">'.(($i < 10) ? '&nbsp;'.$i : $i);
653                         else
654                                 $o .= "<span class=\"pager_n\"><a href=\"$url"."&page=$i\">".(($i < 10) ? '&nbsp;'.$i : $i)."</a>";
655                         $o .= '</span> ';
656                 }
657
658                 if(($a->pager['total'] % $a->pager['itemspage']) != 0) {
659                         if($i == $a->pager['page'])
660                                 $o .= '<span class="pager_current">'.(($i < 10) ? '&nbsp;'.$i : $i);
661                         else
662                                 $o .= "<span class=\"pager_n\"><a href=\"$url"."&page=$i\">".(($i < 10) ? '&nbsp;'.$i : $i)."</a>";
663                         $o .= '</span> ';
664                 }
665
666                 $lastpage = (($numpages > intval($numpages)) ? intval($numpages)+1 : $numpages);
667                 $o .= "<span class=\"pager_last\"><a href=\"$url"."&page=$lastpage\">" . t('last') . "</a></span> ";
668
669                 if(($a->pager['total'] - ($a->pager['itemspage'] * $a->pager['page'])) > 0)
670                         $o .= '<span class="pager_next">'."<a href=\"$url"."&page=".($a->pager['page'] + 1).'">' . t('next') . '</a></span>';
671                 $o .= '</div>'."\r\n";
672         }
673         return $o;
674 }}
675
676 // Turn user/group ACLs stored as angle bracketed text into arrays
677
678 if(! function_exists('expand_acl')) {
679 function expand_acl($s) {
680         // turn string array of angle-bracketed elements into numeric array
681         // e.g. "<1><2><3>" => array(1,2,3);
682         $ret = array();
683
684         if(strlen($s)) {
685                 $t = str_replace('<','',$s);
686                 $a = explode('>',$t);
687                 foreach($a as $aa) {
688                         if(intval($aa))
689                                 $ret[] = intval($aa);
690                 }
691         }
692         return $ret;
693 }}              
694
695 // Used to wrap ACL elements in angle brackets for storage 
696
697 if(! function_exists('sanitise_acl')) {
698 function sanitise_acl(&$item) {
699         if(intval($item))
700                 $item = '<' . intval(notags(trim($item))) . '>';
701         else
702                 unset($item);
703 }}
704
705 // retrieve a "family" of config variables from database to cached storage
706
707 if(! function_exists('load_config')) {
708 function load_config($family) {
709         global $a;
710         $r = q("SELECT * FROM `config` WHERE `cat` = '%s'",
711                 dbesc($family)
712         );
713         if(count($r)) {
714                 foreach($r as $rr) {
715                         $k = $rr['k'];
716                         $a->config[$family][$k] = $rr['v'];
717                 }
718         }
719 }}
720
721 // get a particular config variable given the family name
722 // and key. Returns false if not set.
723 // $instore is only used by the set_config function
724 // to determine if the key already exists in the DB
725 // If a key is found in the DB but doesn't exist in
726 // local config cache, pull it into the cache so we don't have
727 // to hit the DB again for this item.
728
729 if(! function_exists('get_config')) {
730 function get_config($family, $key, $instore = false) {
731
732         global $a;
733
734         if(! $instore) {
735                 if(isset($a->config[$family][$key])) {
736                         if($a->config[$family][$key] === '!<unset>!') {
737                                 return false;
738                         }
739                         return $a->config[$family][$key];
740                 }
741         }
742         $ret = q("SELECT `v` FROM `config` WHERE `cat` = '%s' AND `k` = '%s' LIMIT 1",
743                 dbesc($family),
744                 dbesc($key)
745         );
746         if(count($ret)) {
747                 $a->config[$family][$key] = $ret[0]['v'];
748                 return $ret[0]['v'];
749         }
750         else {
751                 $a->config[$family][$key] = '!<unset>!';
752         }
753         return false;
754 }}
755
756 // Store a config value ($value) in the category ($family)
757 // under the key ($key)
758 // Return the value, or false if the database update failed
759
760 if(! function_exists('set_config')) {
761 function set_config($family,$key,$value) {
762
763         global $a;
764         $a->config[$family][$key] = $value;
765
766         if(get_config($family,$key,true) === false) {
767                 $ret = q("INSERT INTO `config` ( `cat`, `k`, `v` ) VALUES ( '%s', '%s', '%s' ) ",
768                         dbesc($family),
769                         dbesc($key),
770                         dbesc($value)
771                 );
772                 if($ret) 
773                         return $value;
774                 return $ret;
775         }
776         $ret = q("UPDATE `config` SET `v` = '%s' WHERE `cat` = '%s' AND `k` = '%s' LIMIT 1",
777                 dbesc($value),
778                 dbesc($family),
779                 dbesc($key)
780         );
781         if($ret)
782                 return $value;
783         return $ret;
784 }}
785
786 // convert an XML document to a normalised, case-corrected array
787 // used by webfinger
788
789 if(! function_exists('convert_xml_element_to_array')) {
790 function convert_xml_element_to_array($xml_element, &$recursion_depth=0) {
791
792         // If we're getting too deep, bail out
793         if ($recursion_depth > 512) {
794                 return(null);
795         }
796
797         if (!is_string($xml_element) &&
798         !is_array($xml_element) &&
799         (get_class($xml_element) == 'SimpleXMLElement')) {
800                 $xml_element_copy = $xml_element;
801                 $xml_element = get_object_vars($xml_element);
802         }
803
804         if (is_array($xml_element)) {
805                 $result_array = array();
806                 if (count($xml_element) <= 0) {
807                         return (trim(strval($xml_element_copy)));
808                 }
809
810                 foreach($xml_element as $key=>$value) {
811
812                         $recursion_depth++;
813                         $result_array[strtolower($key)] =
814                 convert_xml_element_to_array($value, $recursion_depth);
815                         $recursion_depth--;
816                 }
817                 if ($recursion_depth == 0) {
818                         $temp_array = $result_array;
819                         $result_array = array(
820                                 strtolower($xml_element_copy->getName()) => $temp_array,
821                         );
822                 }
823
824                 return ($result_array);
825
826         } else {
827                 return (trim(strval($xml_element)));
828         }
829 }}
830
831 // Given an email style address, perform webfinger lookup and 
832 // return the resulting DFRN profile URL.
833 // If this isn't an email style address just return $s.
834 // Return an empty string if email-style addresses but webfinger fails,
835 // or if the resultant personal XRD doesn't contain a DFRN profile.
836
837 if(! function_exists('webfinger')) {
838 function webfinger($s) {
839         if(! strstr($s,'@')) {
840                 return $s;
841         }
842         $host = substr($s,strpos($s,'@') + 1);
843         $url = 'http://' . $host . '/.well-known/host-meta' ;
844         $xml = fetch_url($url);
845         if (! $xml)
846                 return '';
847         $h = simplexml_load_string($xml);
848         $arr = convert_xml_element_to_array($h);
849
850         if(! isset($arr['xrd']['link']))
851                 return '';
852
853         $link = $arr['xrd']['link'];
854         if(! isset($link[0]))
855                 $links = array($link);
856         else
857                 $links = $link;
858
859         foreach($links as $link)
860                 if($link['@attributes']['rel'] && $link['@attributes']['rel'] === 'lrdd')
861                         $tpl = $link['@attributes']['template'];
862         if((empty($tpl)) || (! strpos($tpl, '{uri}')))
863                 return '';
864
865         $pxrd = str_replace('{uri}', urlencode('acct://'.$s), $tpl);
866
867         $xml = fetch_url($pxrd);
868         if (! $xml)
869                 return '';
870         $h = simplexml_load_string($xml);
871         $arr = convert_xml_element_to_array($h);
872
873         if(! isset($arr['xrd']['link']))
874                 return '';
875
876         $link = $arr['xrd']['link'];
877         if(! isset($link[0]))
878                 $links = array($link);
879         else
880                 $links = $link;
881
882         foreach($links as $link)
883                 if($link['@attributes']['rel'] == NAMESPACE_DFRN)
884                         return $link['@attributes']['href'];
885         return '';
886 }}
887
888
889 // Convert an ACL array to a storable string
890
891 if(! function_exists('perms2str')) {
892 function perms2str($p) {
893         $ret = '';
894         $tmp = $p;
895         if(is_array($tmp)) {
896                 array_walk($tmp,'sanitise_acl');
897                 $ret = implode('',$tmp);
898         }
899         return $ret;
900 }}
901
902 // generate a guaranteed unique (for this domain) item ID for ATOM
903 // safe from birthday paradox
904
905 if(! function_exists('item_new_uri')) {
906 function item_new_uri($hostname,$uid) {
907
908         do {
909                 $dups = false;
910                 $hash = random_string();
911
912                 $uri = "urn:X-dfrn:" . $hostname . ':' . $uid . ':' . $hash;
913
914                 $r = q("SELECT `id` FROM `item` WHERE `uri` = '%s' LIMIT 1",
915                         dbesc($uri));
916                 if(count($r))
917                         $dups = true;
918         } while($dups == true);
919         return $uri;
920 }}
921
922 // Generate a guaranteed unique photo ID.
923 // safe from birthday paradox
924
925 if(! function_exists('photo_new_resource')) {
926 function photo_new_resource() {
927
928         do {
929                 $found = false;
930                 $resource = hash('md5',uniqid(mt_rand(),true));
931                 $r = q("SELECT `id` FROM `photo` WHERE `resource-id` = '%s' LIMIT 1",
932                         dbesc($resource)
933                 );
934                 if(count($r))
935                         $found = true;
936         } while($found == true);
937         return $resource;
938 }}
939
940
941 // Returns logged in user ID
942
943 if(! function_exists('get_uid')) {
944 function get_uid() {
945         return ((x($_SESSION,'uid')) ? intval($_SESSION['uid']) : 0) ;
946 }}
947
948 // Take a URL from the wild, prepend http:// if necessary
949 // and check DNS to see if it's real
950 // return true if it's OK, false if something is wrong with it
951
952 if(! function_exists('validate_url')) {
953 function validate_url(&$url) {
954         if(substr($url,0,4) != 'http')
955                 $url = 'http://' . $url;
956         $h = parse_url($url);
957
958         if(! $h) {
959                 return false;
960         }
961         if(! checkdnsrr($h['host'], 'ANY')) {
962                 return false;
963         }
964         return true;
965 }}
966
967 // Check $url against our list of allowed sites,
968 // wildcards allowed. If allowed_sites is unset return true;
969 // If url is allowed, return true.
970 // otherwise, return false
971
972 if(! function_exists('allowed_url')) {
973 function allowed_url($url) {
974
975         $h = parse_url($url);
976
977         if(! $h) {
978                 return false;
979         }
980
981         $str_allowed = get_config('system','allowed_sites');
982         if(! $str_allowed)
983                 return true;
984
985         $found = false;
986
987         $host = strtolower($h['host']);
988
989         // always allow our own site
990
991         if($host == strtolower($_SERVER['SERVER_NAME']))
992                 return true;
993
994         $fnmatch = function_exists('fnmatch');
995         $allowed = explode(',',$str_allowed);
996
997         if(count($allowed)) {
998                 foreach($allowed as $a) {
999                         $pat = strtolower(trim($a));
1000                         if(($fnmatch && fnmatch($pat,$host)) || ($pat == $host)) {
1001                                 $found = true; 
1002                                 break;
1003                         }
1004                 }
1005         }
1006         return $found;
1007 }}
1008
1009 // check if email address is allowed to register here.
1010 // Compare against our list (wildcards allowed).
1011 // Returns false if not allowed, true if allowed or if
1012 // allowed list is not configured.
1013
1014 if(! function_exists('allowed_email')) {
1015 function allowed_email($email) {
1016
1017
1018         $domain = strtolower(substr($email,strpos($email,'@') + 1));
1019         if(! $domain)
1020                 return false;
1021
1022         $str_allowed = get_config('system','allowed_email');
1023         if(! $str_allowed)
1024                 return true;
1025
1026         $found = false;
1027
1028         $fnmatch = function_exists('fnmatch');
1029         $allowed = explode(',',$str_allowed);
1030
1031         if(count($allowed)) {
1032                 foreach($allowed as $a) {
1033                         $pat = strtolower(trim($a));
1034                         if(($fnmatch && fnmatch($pat,$host)) || ($pat == $host)) {
1035                                 $found = true; 
1036                                 break;
1037                         }
1038                 }
1039         }
1040         return $found;
1041 }}
1042
1043 // Format the like/dislike text for a profile item
1044 // $cnt = number of people who like/dislike the item
1045 // $arr = array of pre-linked names of likers/dislikers
1046 // $type = one of 'like, 'dislike'
1047 // $id  = item id
1048 // returns formatted text
1049
1050 if(! function_exists('format_like')) {
1051 function format_like($cnt,$arr,$type,$id) {
1052         if($cnt == 1)
1053                 $o .= $arr[0] . (($type === 'like') ? t(' likes this.') : t(' doesn\'t like this.')) . EOL ;
1054         else {
1055                 $o .= '<span class="fakelink" onclick="openClose(\'' . $type . 'list-' . $id . '\');" >' 
1056                         . $cnt . ' ' . t('people') . '</span> ' . (($type === 'like') ? t('like this.') : t('don\'t like this.')) . EOL ;
1057                 $total = count($arr);
1058                 if($total >= 75)
1059                         $arr = array_slice($arr,0,74);
1060                 if($total < 75)
1061                         $arr[count($arr)-1] = t('and') . ' ' . $arr[count($arr)-1];
1062                 $str = implode(', ', $arr);
1063                 if($total >= 75)
1064                         $str .= t(', and ') . $total - 75 . t(' other people');
1065                 $str .= (($type === 'like') ? t(' like this.') : t(' don\'t like this.'));
1066                 $o .= '<div id="' . $type . 'list-' . $id . '" style="display: none;" >' . $str . '</div>';
1067         }
1068         return $o;
1069 }}
1070
1071
1072 // wrapper to load a view template, checking for alternate
1073 // languages before falling back to the default
1074
1075 if(! function_exists('load_view_file')) {
1076 function load_view_file($s) {
1077         $b = basename($s);
1078         $d = dirname($s);
1079         $lang = get_config('system','language');
1080         if($lang && file_exists("$d/$lang/$b"))
1081                 return file_get_contents("$d/$lang/$b");
1082         return file_get_contents($s);
1083 }}