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.
 
 
 
 
 
 

765 lines
19 KiB

  1. <?php
  2. // curl wrapper. If binary flag is true, return binary
  3. // results.
  4. if(! function_exists('fetch_url')) {
  5. function fetch_url($url,$binary = false, &$redirects = 0, $timeout = 0) {
  6. $a = get_app();
  7. $ch = @curl_init($url);
  8. if(($redirects > 8) || (! $ch))
  9. return false;
  10. @curl_setopt($ch, CURLOPT_HEADER, true);
  11. @curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
  12. @curl_setopt($ch, CURLOPT_USERAGENT, "Friendika");
  13. if(intval($timeout)) {
  14. @curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  15. }
  16. else {
  17. $curl_time = intval(get_config('system','curl_timeout'));
  18. @curl_setopt($ch, CURLOPT_TIMEOUT, (($curl_time !== false) ? $curl_time : 60));
  19. }
  20. // by default we will allow self-signed certs
  21. // but you can override this
  22. $check_cert = get_config('system','verifyssl');
  23. @curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, (($check_cert) ? true : false));
  24. $prx = get_config('system','proxy');
  25. if(strlen($prx)) {
  26. @curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
  27. @curl_setopt($ch, CURLOPT_PROXY, $prx);
  28. $prxusr = @get_config('system','proxyuser');
  29. if(strlen($prxusr))
  30. @curl_setopt($ch, CURLOPT_PROXYUSERPWD, $prxusr);
  31. }
  32. if($binary)
  33. @curl_setopt($ch, CURLOPT_BINARYTRANSFER,1);
  34. $a->set_curl_code(0);
  35. // don't let curl abort the entire application
  36. // if it throws any errors.
  37. $s = @curl_exec($ch);
  38. $base = $s;
  39. $curl_info = @curl_getinfo($ch);
  40. $http_code = $curl_info['http_code'];
  41. $header = '';
  42. // Pull out multiple headers, e.g. proxy and continuation headers
  43. // allow for HTTP/2.x without fixing code
  44. while(preg_match('/^HTTP\/[1-2].+? [1-5][0-9][0-9]/',$base)) {
  45. $chunk = substr($base,0,strpos($base,"\r\n\r\n")+4);
  46. $header .= $chunk;
  47. $base = substr($base,strlen($chunk));
  48. }
  49. if($http_code == 301 || $http_code == 302 || $http_code == 303 || $http_code == 307) {
  50. $matches = array();
  51. preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches);
  52. $url = trim(array_pop($matches));
  53. $url_parsed = @parse_url($url);
  54. if (isset($url_parsed)) {
  55. $redirects++;
  56. return fetch_url($url,$binary,$redirects,$timeout);
  57. }
  58. }
  59. $a->set_curl_code($http_code);
  60. $body = substr($s,strlen($header));
  61. $a->set_curl_headers($header);
  62. @curl_close($ch);
  63. return($body);
  64. }}
  65. // post request to $url. $params is an array of post variables.
  66. if(! function_exists('post_url')) {
  67. function post_url($url,$params, $headers = null, &$redirects = 0, $timeout = 0) {
  68. $a = get_app();
  69. $ch = curl_init($url);
  70. if(($redirects > 8) || (! $ch))
  71. return false;
  72. curl_setopt($ch, CURLOPT_HEADER, true);
  73. curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
  74. curl_setopt($ch, CURLOPT_POST,1);
  75. curl_setopt($ch, CURLOPT_POSTFIELDS,$params);
  76. curl_setopt($ch, CURLOPT_USERAGENT, "Friendika");
  77. if(intval($timeout)) {
  78. curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  79. }
  80. else {
  81. $curl_time = intval(get_config('system','curl_timeout'));
  82. curl_setopt($ch, CURLOPT_TIMEOUT, (($curl_time !== false) ? $curl_time : 60));
  83. }
  84. if(defined('LIGHTTPD')) {
  85. if(!is_array($headers)) {
  86. $headers = array('Expect:');
  87. } else {
  88. if(!in_array('Expect:', $headers)) {
  89. array_push($headers, 'Expect:');
  90. }
  91. }
  92. }
  93. if($headers)
  94. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  95. $check_cert = get_config('system','verifyssl');
  96. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, (($check_cert) ? true : false));
  97. $prx = get_config('system','proxy');
  98. if(strlen($prx)) {
  99. curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
  100. curl_setopt($ch, CURLOPT_PROXY, $prx);
  101. $prxusr = get_config('system','proxyuser');
  102. if(strlen($prxusr))
  103. curl_setopt($ch, CURLOPT_PROXYUSERPWD, $prxusr);
  104. }
  105. $a->set_curl_code(0);
  106. // don't let curl abort the entire application
  107. // if it throws any errors.
  108. $s = @curl_exec($ch);
  109. $base = $s;
  110. $curl_info = curl_getinfo($ch);
  111. $http_code = $curl_info['http_code'];
  112. $header = '';
  113. // Pull out multiple headers, e.g. proxy and continuation headers
  114. // allow for HTTP/2.x without fixing code
  115. while(preg_match('/^HTTP\/[1-2].+? [1-5][0-9][0-9]/',$base)) {
  116. $chunk = substr($base,0,strpos($base,"\r\n\r\n")+4);
  117. $header .= $chunk;
  118. $base = substr($base,strlen($chunk));
  119. }
  120. if($http_code == 301 || $http_code == 302 || $http_code == 303) {
  121. $matches = array();
  122. preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches);
  123. $url = trim(array_pop($matches));
  124. $url_parsed = @parse_url($url);
  125. if (isset($url_parsed)) {
  126. $redirects++;
  127. return post_url($url,$params,$headers,$redirects,$timeout);
  128. }
  129. }
  130. $a->set_curl_code($http_code);
  131. $body = substr($s,strlen($header));
  132. $a->set_curl_headers($header);
  133. curl_close($ch);
  134. return($body);
  135. }}
  136. // Generic XML return
  137. // Outputs a basic dfrn XML status structure to STDOUT, with a <status> variable
  138. // of $st and an optional text <message> of $message and terminates the current process.
  139. if(! function_exists('xml_status')) {
  140. function xml_status($st, $message = '') {
  141. $xml_message = ((strlen($message)) ? "\t<message>" . xmlify($message) . "</message>\r\n" : '');
  142. if($st)
  143. logger('xml_status returning non_zero: ' . $st . " message=" . $message);
  144. header( "Content-type: text/xml" );
  145. echo '<?xml version="1.0" encoding="UTF-8"?>'."\r\n";
  146. echo "<result>\r\n\t<status>$st</status>\r\n$xml_message</result>\r\n";
  147. killme();
  148. }}
  149. if(! function_exists('http_status_exit')) {
  150. function http_status_exit($val) {
  151. if($val >= 400)
  152. $err = 'Error';
  153. if($val >= 200 && $val < 300)
  154. $err = 'OK';
  155. logger('http_status_exit ' . $val);
  156. header($_SERVER["SERVER_PROTOCOL"] . ' ' . $val . ' ' . $err);
  157. killme();
  158. }}
  159. // convert an XML document to a normalised, case-corrected array
  160. // used by webfinger
  161. if(! function_exists('convert_xml_element_to_array')) {
  162. function convert_xml_element_to_array($xml_element, &$recursion_depth=0) {
  163. // If we're getting too deep, bail out
  164. if ($recursion_depth > 512) {
  165. return(null);
  166. }
  167. if (!is_string($xml_element) &&
  168. !is_array($xml_element) &&
  169. (get_class($xml_element) == 'SimpleXMLElement')) {
  170. $xml_element_copy = $xml_element;
  171. $xml_element = get_object_vars($xml_element);
  172. }
  173. if (is_array($xml_element)) {
  174. $result_array = array();
  175. if (count($xml_element) <= 0) {
  176. return (trim(strval($xml_element_copy)));
  177. }
  178. foreach($xml_element as $key=>$value) {
  179. $recursion_depth++;
  180. $result_array[strtolower($key)] =
  181. convert_xml_element_to_array($value, $recursion_depth);
  182. $recursion_depth--;
  183. }
  184. if ($recursion_depth == 0) {
  185. $temp_array = $result_array;
  186. $result_array = array(
  187. strtolower($xml_element_copy->getName()) => $temp_array,
  188. );
  189. }
  190. return ($result_array);
  191. } else {
  192. return (trim(strval($xml_element)));
  193. }
  194. }}
  195. // Given an email style address, perform webfinger lookup and
  196. // return the resulting DFRN profile URL, or if no DFRN profile URL
  197. // is located, returns an OStatus subscription template (prefixed
  198. // with the string 'stat:' to identify it as on OStatus template).
  199. // If this isn't an email style address just return $s.
  200. // Return an empty string if email-style addresses but webfinger fails,
  201. // or if the resultant personal XRD doesn't contain a supported
  202. // subscription/friend-request attribute.
  203. // amended 7/9/2011 to return an hcard which could save potentially loading
  204. // a lengthy content page to scrape dfrn attributes
  205. if(! function_exists('webfinger_dfrn')) {
  206. function webfinger_dfrn($s,&$hcard) {
  207. if(! strstr($s,'@')) {
  208. return $s;
  209. }
  210. $profile_link = '';
  211. $links = webfinger($s);
  212. logger('webfinger_dfrn: ' . $s . ':' . print_r($links,true), LOGGER_DATA);
  213. if(count($links)) {
  214. foreach($links as $link) {
  215. if($link['@attributes']['rel'] === NAMESPACE_DFRN)
  216. $profile_link = $link['@attributes']['href'];
  217. if($link['@attributes']['rel'] === NAMESPACE_OSTATUSSUB)
  218. $profile_link = 'stat:' . $link['@attributes']['template'];
  219. if($link['@attributes']['rel'] === 'http://microformats.org/profile/hcard')
  220. $hcard = $link['@attributes']['href'];
  221. }
  222. }
  223. return $profile_link;
  224. }}
  225. // Given an email style address, perform webfinger lookup and
  226. // return the array of link attributes from the personal XRD file.
  227. // On error/failure return an empty array.
  228. if(! function_exists('webfinger')) {
  229. function webfinger($s) {
  230. $host = '';
  231. if(strstr($s,'@')) {
  232. $host = substr($s,strpos($s,'@') + 1);
  233. }
  234. if(strlen($host)) {
  235. $tpl = fetch_lrdd_template($host);
  236. logger('webfinger: lrdd template: ' . $tpl);
  237. if(strlen($tpl)) {
  238. $pxrd = str_replace('{uri}', urlencode('acct:' . $s), $tpl);
  239. logger('webfinger: pxrd: ' . $pxrd);
  240. $links = fetch_xrd_links($pxrd);
  241. if(! count($links)) {
  242. // try with double slashes
  243. $pxrd = str_replace('{uri}', urlencode('acct://' . $s), $tpl);
  244. logger('webfinger: pxrd: ' . $pxrd);
  245. $links = fetch_xrd_links($pxrd);
  246. }
  247. return $links;
  248. }
  249. }
  250. return array();
  251. }}
  252. if(! function_exists('lrdd')) {
  253. function lrdd($uri) {
  254. $a = get_app();
  255. // default priority is host priority, host-meta first
  256. $priority = 'host';
  257. // All we have is an email address. Resource-priority is irrelevant
  258. // because our URI isn't directly resolvable.
  259. if(strstr($uri,'@')) {
  260. return(webfinger($uri));
  261. }
  262. // get the host meta file
  263. $host = @parse_url($uri);
  264. if($host) {
  265. $url = ((x($host,'scheme')) ? $host['scheme'] : 'http') . '://';
  266. $url .= $host['host'] . '/.well-known/host-meta' ;
  267. }
  268. else
  269. return array();
  270. logger('lrdd: constructed url: ' . $url);
  271. $xml = fetch_url($url);
  272. $headers = $a->get_curl_headers();
  273. if (! $xml)
  274. return array();
  275. logger('lrdd: host_meta: ' . $xml, LOGGER_DATA);
  276. $h = parse_xml_string($xml);
  277. if(! $h)
  278. return array();
  279. $arr = convert_xml_element_to_array($h);
  280. if(isset($arr['xrd']['property'])) {
  281. $property = $arr['crd']['property'];
  282. if(! isset($property[0]))
  283. $properties = array($property);
  284. else
  285. $properties = $property;
  286. foreach($properties as $prop)
  287. if((string) $prop['@attributes'] === 'http://lrdd.net/priority/resource')
  288. $priority = 'resource';
  289. }
  290. // save the links in case we need them
  291. $links = array();
  292. if(isset($arr['xrd']['link'])) {
  293. $link = $arr['xrd']['link'];
  294. if(! isset($link[0]))
  295. $links = array($link);
  296. else
  297. $links = $link;
  298. }
  299. // do we have a template or href?
  300. if(count($links)) {
  301. foreach($links as $link) {
  302. if($link['@attributes']['rel'] && attribute_contains($link['@attributes']['rel'],'lrdd')) {
  303. if(x($link['@attributes'],'template'))
  304. $tpl = $link['@attributes']['template'];
  305. elseif(x($link['@attributes'],'href'))
  306. $href = $link['@attributes']['href'];
  307. }
  308. }
  309. }
  310. if((! isset($tpl)) || (! strpos($tpl,'{uri}')))
  311. $tpl = '';
  312. if($priority === 'host') {
  313. if(strlen($tpl))
  314. $pxrd = str_replace('{uri}', urlencode($uri), $tpl);
  315. elseif(isset($href))
  316. $pxrd = $href;
  317. if(isset($pxrd)) {
  318. logger('lrdd: (host priority) pxrd: ' . $pxrd);
  319. $links = fetch_xrd_links($pxrd);
  320. return $links;
  321. }
  322. $lines = explode("\n",$headers);
  323. if(count($lines)) {
  324. foreach($lines as $line) {
  325. if((stristr($line,'link:')) && preg_match('/<([^>].*)>.*rel\=[\'\"]lrdd[\'\"]/',$line,$matches)) {
  326. return(fetch_xrd_links($matches[1]));
  327. break;
  328. }
  329. }
  330. }
  331. }
  332. // priority 'resource'
  333. $html = fetch_url($uri);
  334. $headers = $a->get_curl_headers();
  335. logger('lrdd: headers=' . $headers, LOGGER_DEBUG);
  336. // don't try and parse raw xml as html
  337. if(! strstr($html,'<?xml')) {
  338. require_once('library/HTML5/Parser.php');
  339. try {
  340. $dom = HTML5_Parser::parse($html);
  341. } catch (DOMException $e) {
  342. logger('lrdd: parse error: ' . $e);
  343. }
  344. if($dom) {
  345. $items = $dom->getElementsByTagName('link');
  346. foreach($items as $item) {
  347. $x = $item->getAttribute('rel');
  348. if($x == "lrdd") {
  349. $pagelink = $item->getAttribute('href');
  350. break;
  351. }
  352. }
  353. }
  354. }
  355. if(isset($pagelink))
  356. return(fetch_xrd_links($pagelink));
  357. // next look in HTTP headers
  358. $lines = explode("\n",$headers);
  359. if(count($lines)) {
  360. foreach($lines as $line) {
  361. // TODO alter the following regex to support multiple relations (space separated)
  362. if((stristr($line,'link:')) && preg_match('/<([^>].*)>.*rel\=[\'\"]lrdd[\'\"]/',$line,$matches)) {
  363. $pagelink = $matches[1];
  364. break;
  365. }
  366. // don't try and run feeds through the html5 parser
  367. if(stristr($line,'content-type:') && ((stristr($line,'application/atom+xml')) || (stristr($line,'application/rss+xml'))))
  368. return array();
  369. if(stristr($html,'<rss') || stristr($html,'<feed'))
  370. return array();
  371. }
  372. }
  373. if(isset($pagelink))
  374. return(fetch_xrd_links($pagelink));
  375. // If we haven't found any links, return the host xrd links (which we have already fetched)
  376. if(isset($links))
  377. return $links;
  378. return array();
  379. }}
  380. // Given a host name, locate the LRDD template from that
  381. // host. Returns the LRDD template or an empty string on
  382. // error/failure.
  383. if(! function_exists('fetch_lrdd_template')) {
  384. function fetch_lrdd_template($host) {
  385. $tpl = '';
  386. $url1 = 'https://' . $host . '/.well-known/host-meta' ;
  387. $url2 = 'http://' . $host . '/.well-known/host-meta' ;
  388. $links = fetch_xrd_links($url1);
  389. logger('fetch_lrdd_template from: ' . $url1);
  390. logger('template (https): ' . print_r($links,true));
  391. if(! count($links)) {
  392. logger('fetch_lrdd_template from: ' . $url2);
  393. $links = fetch_xrd_links($url2);
  394. logger('template (http): ' . print_r($links,true));
  395. }
  396. if(count($links)) {
  397. foreach($links as $link)
  398. if($link['@attributes']['rel'] && $link['@attributes']['rel'] === 'lrdd')
  399. $tpl = $link['@attributes']['template'];
  400. }
  401. if(! strpos($tpl,'{uri}'))
  402. $tpl = '';
  403. return $tpl;
  404. }}
  405. // Given a URL, retrieve the page as an XRD document.
  406. // Return an array of links.
  407. // on error/failure return empty array.
  408. if(! function_exists('fetch_xrd_links')) {
  409. function fetch_xrd_links($url) {
  410. $xrd_timeout = intval(get_config('system','xrd_timeout'));
  411. $redirects = 0;
  412. $xml = fetch_url($url,false,$redirects,(($xrd_timeout) ? $xrd_timeout : 20));
  413. logger('fetch_xrd_links: ' . $xml, LOGGER_DATA);
  414. if ((! $xml) || (! stristr($xml,'<xrd')))
  415. return array();
  416. $h = parse_xml_string($xml);
  417. if(! $h)
  418. return array();
  419. $arr = convert_xml_element_to_array($h);
  420. $links = array();
  421. if(isset($arr['xrd']['link'])) {
  422. $link = $arr['xrd']['link'];
  423. if(! isset($link[0]))
  424. $links = array($link);
  425. else
  426. $links = $link;
  427. }
  428. if(isset($arr['xrd']['alias'])) {
  429. $alias = $arr['xrd']['alias'];
  430. if(! isset($alias[0]))
  431. $aliases = array($alias);
  432. else
  433. $aliases = $alias;
  434. if(is_array($aliases) && count($aliases)) {
  435. foreach($aliases as $alias) {
  436. $links[]['@attributes'] = array('rel' => 'alias' , 'href' => $alias);
  437. }
  438. }
  439. }
  440. logger('fetch_xrd_links: ' . print_r($links,true), LOGGER_DATA);
  441. return $links;
  442. }}
  443. // Take a URL from the wild, prepend http:// if necessary
  444. // and check DNS to see if it's real
  445. // return true if it's OK, false if something is wrong with it
  446. if(! function_exists('validate_url')) {
  447. function validate_url(&$url) {
  448. if(substr($url,0,4) != 'http')
  449. $url = 'http://' . $url;
  450. $h = @parse_url($url);
  451. if(($h) && (dns_get_record($h['host'], DNS_A + DNS_CNAME + DNS_PTR))) {
  452. return true;
  453. }
  454. return false;
  455. }}
  456. // checks that email is an actual resolvable internet address
  457. if(! function_exists('validate_email')) {
  458. function validate_email($addr) {
  459. if(! strpos($addr,'@'))
  460. return false;
  461. $h = substr($addr,strpos($addr,'@') + 1);
  462. if(($h) && (dns_get_record($h, DNS_A + DNS_CNAME + DNS_PTR + DNS_MX))) {
  463. return true;
  464. }
  465. return false;
  466. }}
  467. // Check $url against our list of allowed sites,
  468. // wildcards allowed. If allowed_sites is unset return true;
  469. // If url is allowed, return true.
  470. // otherwise, return false
  471. if(! function_exists('allowed_url')) {
  472. function allowed_url($url) {
  473. $h = @parse_url($url);
  474. if(! $h) {
  475. return false;
  476. }
  477. $str_allowed = get_config('system','allowed_sites');
  478. if(! $str_allowed)
  479. return true;
  480. $found = false;
  481. $host = strtolower($h['host']);
  482. // always allow our own site
  483. if($host == strtolower($_SERVER['SERVER_NAME']))
  484. return true;
  485. $fnmatch = function_exists('fnmatch');
  486. $allowed = explode(',',$str_allowed);
  487. if(count($allowed)) {
  488. foreach($allowed as $a) {
  489. $pat = strtolower(trim($a));
  490. if(($fnmatch && fnmatch($pat,$host)) || ($pat == $host)) {
  491. $found = true;
  492. break;
  493. }
  494. }
  495. }
  496. return $found;
  497. }}
  498. // check if email address is allowed to register here.
  499. // Compare against our list (wildcards allowed).
  500. // Returns false if not allowed, true if allowed or if
  501. // allowed list is not configured.
  502. if(! function_exists('allowed_email')) {
  503. function allowed_email($email) {
  504. $domain = strtolower(substr($email,strpos($email,'@') + 1));
  505. if(! $domain)
  506. return false;
  507. $str_allowed = get_config('system','allowed_email');
  508. if(! $str_allowed)
  509. return true;
  510. $found = false;
  511. $fnmatch = function_exists('fnmatch');
  512. $allowed = explode(',',$str_allowed);
  513. if(count($allowed)) {
  514. foreach($allowed as $a) {
  515. $pat = strtolower(trim($a));
  516. if(($fnmatch && fnmatch($pat,$domain)) || ($pat == $domain)) {
  517. $found = true;
  518. break;
  519. }
  520. }
  521. }
  522. return $found;
  523. }}
  524. if(! function_exists('gravatar_img')) {
  525. function gravatar_img($email) {
  526. $size = 175;
  527. $opt = 'identicon'; // psuedo-random geometric pattern if not found
  528. $rating = 'pg';
  529. $hash = md5(trim(strtolower($email)));
  530. $url = 'http://www.gravatar.com/avatar/' . $hash . '.jpg'
  531. . '?s=' . $size . '&d=' . $opt . '&r=' . $rating;
  532. logger('gravatar: ' . $email . ' ' . $url);
  533. return $url;
  534. }}
  535. if(! function_exists('parse_xml_string')) {
  536. function parse_xml_string($s,$strict = true) {
  537. if($strict) {
  538. if(! strstr($s,'<?xml'))
  539. return false;
  540. $s2 = substr($s,strpos($s,'<?xml'));
  541. }
  542. else
  543. $s2 = $s;
  544. libxml_use_internal_errors(true);
  545. $x = @simplexml_load_string($s2);
  546. if(! $x) {
  547. logger('libxml: parse: error: ' . $s2, LOGGER_DATA);
  548. foreach(libxml_get_errors() as $err)
  549. logger('libxml: parse: ' . $err->code." at ".$err->line.":".$err->column." : ".$err->message, LOGGER_DATA);
  550. libxml_clear_errors();
  551. }
  552. return $x;
  553. }}
  554. function add_fcontact($arr,$update = false) {
  555. if($update) {
  556. $r = q("UPDATE `fcontact` SET
  557. `name` = '%s',
  558. `photo` = '%s',
  559. `request` = '%s',
  560. `nick` = '%s',
  561. `addr` = '%s',
  562. `batch` = '%s',
  563. `notify` = '%s',
  564. `poll` = '%s',
  565. `confirm` = '%s',
  566. `alias` = '%s',
  567. `pubkey` = '%s',
  568. `updated` = '%s'
  569. WHERE `url` = '%s' AND `network` = '%s' LIMIT 1",
  570. dbesc($arr['name']),
  571. dbesc($arr['photo']),
  572. dbesc($arr['request']),
  573. dbesc($arr['nick']),
  574. dbesc($arr['addr']),
  575. dbesc($arr['batch']),
  576. dbesc($arr['notify']),
  577. dbesc($arr['poll']),
  578. dbesc($arr['confirm']),
  579. dbesc($arr['network']),
  580. dbesc($arr['alias']),
  581. dbesc($arr['pubkey']),
  582. dbesc(datetime_convert()),
  583. dbesc($arr['url']),
  584. dbesc($arr['network'])
  585. );
  586. }
  587. else {
  588. $r = q("insert into fcontact ( `url`,`name`,`photo`,`request`,`nick`,`addr`,
  589. `batch`, `notify`,`poll`,`confirm`,`network`,`alias`,`pubkey`,`updated` )
  590. values('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')",
  591. dbesc($arr['url']),
  592. dbesc($arr['name']),
  593. dbesc($arr['photo']),
  594. dbesc($arr['request']),
  595. dbesc($arr['nick']),
  596. dbesc($arr['addr']),
  597. dbesc($arr['batch']),
  598. dbesc($arr['notify']),
  599. dbesc($arr['poll']),
  600. dbesc($arr['confirm']),
  601. dbesc($arr['network']),
  602. dbesc($arr['alias']),
  603. dbesc($arr['pubkey']),
  604. dbesc(datetime_convert())
  605. );
  606. }
  607. return $r;
  608. }