diff options
author | Thomas Willingham <beardyunixer@beardyunixer.com> | 2014-09-02 01:57:30 +0100 |
---|---|---|
committer | Thomas Willingham <beardyunixer@beardyunixer.com> | 2014-09-02 01:57:30 +0100 |
commit | 1c0be3994382ca355db16a2ab9f54dd99a37f1ec (patch) | |
tree | 725c7b2e3ec9f5970fc3b932d7cf3d29e6845717 /include | |
parent | 473e582d1f3e5067c1aecee9c9f2f579864db3ef (diff) | |
parent | d507484cc52840e90fbe88568a56e61a183ef455 (diff) | |
download | volse-hubzilla-1c0be3994382ca355db16a2ab9f54dd99a37f1ec.tar.gz volse-hubzilla-1c0be3994382ca355db16a2ab9f54dd99a37f1ec.tar.bz2 volse-hubzilla-1c0be3994382ca355db16a2ab9f54dd99a37f1ec.zip |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'include')
-rw-r--r-- | include/Contact.php | 2 | ||||
-rw-r--r-- | include/activities.php | 2 | ||||
-rw-r--r-- | include/follow.php | 77 | ||||
-rwxr-xr-x | include/items.php | 33 | ||||
-rw-r--r-- | include/network.php | 185 | ||||
-rw-r--r-- | include/onepoll.php | 17 | ||||
-rw-r--r-- | include/poller.php | 15 | ||||
-rw-r--r-- | include/text.php | 5 | ||||
-rw-r--r-- | include/zot.php | 6 |
9 files changed, 276 insertions, 66 deletions
diff --git a/include/Contact.php b/include/Contact.php index 66c94ef50..a9e737bde 100644 --- a/include/Contact.php +++ b/include/Contact.php @@ -323,7 +323,7 @@ function mark_orphan_hubsxchans() { return; $r = q("update hubloc set hubloc_status = (hubloc_status | %d) where not (hubloc_status & %d) - and hubloc_connected < utc_timestamp() - interval 36 day", + and hubloc_network != 'zot' and hubloc_connected < utc_timestamp() - interval 36 day", intval(HUBLOC_OFFLINE), intval(HUBLOC_OFFLINE) ); diff --git a/include/activities.php b/include/activities.php index 4502b758e..d978ebcd6 100644 --- a/include/activities.php +++ b/include/activities.php @@ -25,7 +25,7 @@ function profile_activity($changed, $value) { $arr['verb'] = ACTIVITY_UPDATE; $arr['obj_type'] = ACTIVITY_OBJ_PROFILE; - $arr['$plink'] = z_root() . '/channel/' . $self['channel_address'] . '/?f=&mid=' . $arr['mid']; + $arr['plink'] = z_root() . '/channel/' . $self['channel_address'] . '/?f=&mid=' . $arr['mid']; $A = '[url=' . z_root() . '/channel/' . $self['channel_address'] . ']' . $self['channel_name'] . '[/url]'; diff --git a/include/follow.php b/include/follow.php index 55249db2b..d1c6afbee 100644 --- a/include/follow.php +++ b/include/follow.php @@ -17,7 +17,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) $a = get_app(); $is_red = false; - + $is_http = ((strpos($url,'://') !== false) ? true : false); if(! allowed_url($url)) { $result['message'] = t('Channel is blocked on this site.'); @@ -29,16 +29,32 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) return $result; } + + // check service class limits + + $r = q("select count(*) as total from abook where abook_channel = %d and not (abook_flags & %d) ", + intval($uid), + intval(ABOOK_FLAG_SELF) + ); + if($r) + $total_channels = $r[0]['total']; + + if(! service_class_allows($uid,'total_channels',$total_channels)) { + $result['message'] = upgrade_message(); + return $result; + } + + $arr = array('url' => $url, 'channel' => array()); call_hooks('follow', $arr); if($arr['channel']['success']) $ret = $arr['channel']; - else + elseif($is_http) $ret = zot_finger($url,$channel); - if($ret['success']) { + if($ret && $ret['success']) { $is_red = true; $j = json_decode($ret['body'],true); } @@ -61,20 +77,6 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) if(array_key_exists('connect_url',$j) && (! $confirm)) goaway(zid($j['connect_url'])); - // check service class limits - - $r = q("select count(*) as total from abook where abook_channel = %d and not (abook_flags & %d) ", - intval($uid), - intval(ABOOK_FLAG_SELF) - ); - if($r) - $total_channels = $r[0]['total']; - - if(! service_class_allows($uid,'total_channels',$total_channels)) { - $result['message'] = upgrade_message(); - return $result; - } - // do we have an xchan and hubloc? // If not, create them. @@ -121,7 +123,8 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) $their_perms = 0; $xchan_hash = ''; - $r = q("select * from xchan where xchan_hash = '%s' limit 1", + $r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' limit 1", + dbesc($url), dbesc($url) ); @@ -130,13 +133,21 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) if(strpos($url,'@')) { $r = discover_by_webbie($url); } + elseif($is_http) { + $r = discover_by_url($url); + } + if($r) { + $r = q("select * from xchan where xchan_hash = '%s' or xchan_url = '%s' limit 1", + dbesc($url), + dbesc($url) + ); + } } if($r) { - $xchan_hash = $url; + $xchan_hash = $r[0]['xchan_hash']; $their_perms = 0; $my_perms = PERMS_W_STREAM|PERMS_W_MAIL; } - } if(! $xchan_hash) { @@ -150,7 +161,6 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) $hash = get_observer_hash(); $ch = $a->get_channel(); $default_group = $ch['channel_default_group']; - } else { $r = q("select * from channel where channel_id = %d limit 1", @@ -164,7 +174,25 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) $hash = $r[0]['channel_hash']; $default_group = $r[0]['channel_default_group']; } - + + if($is_http) { + if(! intval(get_config('system','feed_contacts'))) { + $result['message'] = t('Protocol disabled.'); + return $result; + } + + $r = q("select count(*) as total from abook where abook_account = %d and abook_network = 'rss'", + intval($aid) + ); + if($r) + $total_feeds = $r[0]['total']; + + if(! service_class_allows($uid,'total_feeds',$total_feeds)) { + $result['message'] = upgrade_message(); + return $result; + } + } + if($hash == $xchan_hash) { $result['message'] = t('Cannot connect to yourself.'); return $result; @@ -181,11 +209,12 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) ); } else { - $r = q("insert into abook ( abook_account, abook_channel, abook_xchan, abook_their_perms, abook_my_perms, abook_created, abook_updated ) - values( %d, %d, '%s', %d, %d, '%s', '%s' ) ", + $r = q("insert into abook ( abook_account, abook_channel, abook_xchan, abook_flags, abook_their_perms, abook_my_perms, abook_created, abook_updated ) + values( %d, %d, '%s', %d, %d, %d, '%s', '%s' ) ", intval($aid), intval($uid), dbesc($xchan_hash), + intval(($is_http) ? ABOOK_FLAG_FEED : 0), intval($their_perms), intval($my_perms), dbesc(datetime_convert()), diff --git a/include/items.php b/include/items.php index 4614aa642..7764d2f62 100755 --- a/include/items.php +++ b/include/items.php @@ -1499,6 +1499,9 @@ function get_atom_elements($feed,$item,&$author) { if($d2 > $d3) $res['edited'] = datetime_convert(); + $res['created'] = datetime_convert('UTC','UTC',$res['created']); + $res['edited'] = datetime_convert('UTC','UTC',$res['edited']); + $rawowner = $item->get_item_tags(NAMESPACE_DFRN, 'owner'); if(! $rawowner) $rawowner = $item->get_item_tags(NAMESPACE_ZOT,'owner'); @@ -1555,12 +1558,12 @@ function get_atom_elements($feed,$item,&$author) { $termurl = unxmlify(substr($scheme,9)); } else { - $termtype = TERM_UNKNOWN; + $termtype = TERM_CATEGORY; } $termterm = notags(trim(unxmlify($term))); if($termterm) { - $terms = array( + $terms[] = array( 'otype' => TERM_OBJ_POST, 'type' => $termtype, 'url' => $termurl, @@ -1568,7 +1571,7 @@ function get_atom_elements($feed,$item,&$author) { ); } } - $res['term'] = implode(',', $tag_arr); + $res['term'] = $terms; } $attach = $item->get_enclosures(); @@ -1663,6 +1666,9 @@ function get_atom_elements($feed,$item,&$author) { $res['target'] = $obj; } + $res['public_policy'] = 'specific'; + $res['comment_policy'] = 'none'; + $arr = array('feed' => $feed, 'item' => $item, 'result' => $res); call_hooks('parse_atom', $arr); @@ -3207,14 +3213,14 @@ function consume_feed($xml,$importer,&$contact,$pass = 0) { $datarray['uid'] = $importer['channel_id']; //FIXME - $datarray['author_xchan'] = $contact['xchan_hash']; + $datarray['owner_xchan'] = $datarray['author_xchan'] = $contact['xchan_hash']; // FIXME pull out the author and owner logger('consume_feed: ' . print_r($datarray,true),LOGGER_DATA); -// $xx = item_store($datarray); + $xx = item_store($datarray); $r = $xx['item_id']; continue; } @@ -3267,18 +3273,21 @@ function consume_feed($xml,$importer,&$contact,$pass = 0) { $datarray['parent_mid'] = $item_id; $datarray['uid'] = $importer['channel_id']; //FIXME - $datarray['author_xchan'] = $contact['author_xchan']; - + $datarray['owner_xchan'] = $datarray['author_xchan'] = $contact['xchan_hash']; + if(! link_compare($author['owner_link'],$contact['xchan_url'])) { logger('consume_feed: Correcting item owner.', LOGGER_DEBUG); - $author['owner-name'] = $contact['name']; - $author['owner-link'] = $contact['url']; - $author['owner-avatar'] = $contact['thumb']; + $author['owner_name'] = $contact['name']; + $author['owner_link'] = $contact['url']; + $author['owner_avatar'] = $contact['thumb']; } + logger('consume_feed: author ' . print_r($author,true)); + + logger('consume_feed: ' . print_r($datarray,true),LOGGER_DATA); -// $xx = item_store($datarray); + $xx = item_store($datarray); $r = $xx['item_id']; continue; @@ -3311,7 +3320,7 @@ function handle_feed($uid,$abook_id,$url) { $recurse = 0; $z = z_fetch_url($url,false,$recurse,array('novalidate' => true)); -logger('handle_feed:' . print_r($z,true)); +//logger('handle_feed:' . print_r($z,true)); if($z['success']) { consume_feed($z['body'],$channel,$x[0],0); diff --git a/include/network.php b/include/network.php index ff0502f5a..c44ed77c4 100644 --- a/include/network.php +++ b/include/network.php @@ -819,6 +819,153 @@ function email_send($addr, $subject, $headers, $item) { } + +function discover_by_url($url,$arr = null) { + require_once('library/HTML5/Parser.php'); + + $x = scrape_feed($url); + if(! $x) { + if(! $arr) + return false; + $network = (($arr['network']) ? $arr['network'] : 'unknown'); + $name = (($arr['name']) ? $arr['name'] : 'unknown'); + $photo = (($arr['photo']) ? $arr['photo'] : ''); + $addr = (($arr['addr']) ? $arr['addr'] : ''); + $guid = $url; + } + + $profile = $url; + + logger('scrape_feed results: ' . print_r($x,true)); + + if($x['feed_atom']) + $guid = $x['feed_atom']; + if($x['feed_rss']) + $guid = $x['feed_rss']; + + if(! $guid) + return false; + + + // try and discover stuff from the feeed + + require_once('library/simplepie/simplepie.inc'); + $feed = new SimplePie(); + $level = 0; + $x = z_fetch_url($guid,false,$level,array('novalidate' => true)); + if(! $x['success']) { + logger('probe_url: feed fetch failed for ' . $poll); + return false; + } + $xml = $x['body']; + logger('probe_url: fetch feed: ' . $guid . ' returns: ' . $xml, LOGGER_DATA); + logger('probe_url: scrape_feed: headers: ' . $x['header'], LOGGER_DATA); + + // Don't try and parse an empty string + $feed->set_raw_data(($xml) ? $xml : '<?xml version="1.0" encoding="utf-8" ?><xml></xml>'); + + $feed->init(); + if($feed->error()) + logger('probe_url: scrape_feed: Error parsing XML: ' . $feed->error()); + + $photo = $feed->get_image_url(); + $author = $feed->get_author(); + + if($author) { + $name = unxmlify(trim($author->get_name())); + if(! $name) + $name = trim(unxmlify($author->get_email())); + if(strpos($name,'@') !== false) + $name = substr($name,0,strpos($name,'@')); + if(! $profile && $author->get_link()) + $profile = trim(unxmlify($author->get_link())); + if(! $photo) { + $rawtags = $feed->get_feed_tags( SIMPLEPIE_NAMESPACE_ATOM_10, 'author'); + if($rawtags) { + $elems = $rawtags[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]; + if((x($elems,'link')) && ($elems['link'][0]['attribs']['']['rel'] === 'photo')) + $photo = $elems['link'][0]['attribs']['']['href']; + } + } + } + else { + $item = $feed->get_item(0); + if($item) { + $author = $item->get_author(); + if($author) { + $name = trim(unxmlify($author->get_name())); + if(! $name) + $name = trim(unxmlify($author->get_email())); + if(strpos($name,'@') !== false) + $name = substr($name,0,strpos($name,'@')); + if(! $profile && $author->get_link()) + $profile = trim(unxmlify($author->get_link())); + } + if(! $photo) { + $rawmedia = $item->get_item_tags('http://search.yahoo.com/mrss/','thumbnail'); + if($rawmedia && $rawmedia[0]['attribs']['']['url']) + $photo = unxmlify($rawmedia[0]['attribs']['']['url']); + } + if(! $photo) { + $rawtags = $item->get_item_tags( SIMPLEPIE_NAMESPACE_ATOM_10, 'author'); + if($rawtags) { + $elems = $rawtags[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]; + if((x($elems,'link')) && ($elems['link'][0]['attribs']['']['rel'] === 'photo')) + $photo = $elems['link'][0]['attribs']['']['href']; + } + } + } + } + if($poll === $profile) + $lnk = $feed->get_permalink(); + if(isset($lnk) && strlen($lnk)) + $profile = $lnk; + + if(! $network) { + $network = 'rss'; + } + if(! $name) + $name = notags($feed->get_title()); + if(! $name) + $name = notags($feed->get_description()); + + if(! $guid) + return false; + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($guid) + ); + if($r) + return true; + + if(! $photo) + $photo = z_root() . '/images/rss_icon.png'; + + $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_pubkey, xchan_addr, xchan_url, xchan_name, xchan_network, xchan_instance_url, xchan_name_date ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", + dbesc($guid), + dbesc($guid), + dbesc($pubkey), + dbesc($addr), + dbesc($profile), + dbesc($name), + dbesc($network), + dbesc(z_root()), + dbesc(datetime_convert()) + ); + + $photos = import_profile_photo($photo,$guid); + $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s' limit 1", + dbesc(datetime_convert()), + dbesc($photos[0]), + dbesc($photos[1]), + dbesc($photos[2]), + dbesc($photos[3]), + dbesc($guid) + ); + return true; + +} + function discover_by_webbie($webbie) { require_once('library/HTML5/Parser.php'); @@ -882,14 +1029,12 @@ function discover_by_webbie($webbie) { } } - if($diaspora && $diaspora_base && $diaspora_guid) { + if($diaspora && $diaspora_base && $diaspora_guid && intval(get_config('system','diaspora_enabled'))) { $guid = $diaspora_guid; $diaspora_base = trim($diaspora_base,'/'); $notify = $diaspora_base . '/receive'; -// // '/users/' . $diaspora_guid; -// $batch = $diaspora_base . '/receive/public' ; if(strpos($webbie,'@')) { $addr = str_replace('acct:', '', $webbie); $hostname = substr($webbie,strpos($webbie,'@')+1); @@ -988,23 +1133,23 @@ function discover_by_webbie($webbie) { Array ( - [name] => Mike Macgirvin - [nick] => macgirvin - [guid] => a9174a618f8d269a - [url] => https://joindiaspora.com/u/macgirvin - [hostname] => joindiaspora.com - [addr] => macgirvin@joindiaspora.com - [batch] => - [notify] => https://joindiaspora.com/receive - [poll] => https://joindiaspora.com/public/macgirvin.atom - [request] => - [confirm] => - [poco] => - [photo] => https://joindiaspora.s3.amazonaws.com/uploads/images/thumb_large_fec4e6eef13ae5e56207.jpg - [priority] => - [network] => diaspora - [alias] => - [pubkey] => -----BEGIN PUBLIC KEY----- + [name] => Mike Macgirvin + [nick] => macgirvin + [guid] => a9174a618f8d269a + [url] => https://joindiaspora.com/u/macgirvin + [hostname] => joindiaspora.com + [addr] => macgirvin@joindiaspora.com + [batch] => + [notify] => https://joindiaspora.com/receive + [poll] => https://joindiaspora.com/public/macgirvin.atom + [request] => + [confirm] => + [poco] => + [photo] => https://joindiaspora.s3.amazonaws.com/uploads/images/thumb_large_fec4e6eef13ae5e56207.jpg + [priority] => + [network] => diaspora + [alias] => + [pubkey] => -----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtihtyIuRDWkDpCA+I1UaQ jI4S7k625+A7EEJm+pL2ZVSJxeCKiFeEgHBQENjLMNNm8l8F6blxgQqE6ZJ9Spa7f tlaXYTRCrfxKzh02L3hR7sNA+JS/nXJaUAIo+IwpIEspmcIRbD9GB7Wv/rr+M28uH diff --git a/include/onepoll.php b/include/onepoll.php index 947e936ac..d64785f92 100644 --- a/include/onepoll.php +++ b/include/onepoll.php @@ -38,7 +38,7 @@ function onepoll_run($argv, $argc){ AND NOT ( abook_flags & %d ) AND (( account_flags = %d ) OR ( account_flags = %d )) limit 1", intval($contact_id), - intval(ABOOK_FLAG_HIDDEN|ABOOK_FLAG_PENDING|ABOOK_FLAG_UNCONNECTED), + intval(ABOOK_FLAG_HIDDEN|ABOOK_FLAG_PENDING|ABOOK_FLAG_UNCONNECTED|ABOOK_FLAG_FEED), intval(0), intval(ABOOK_FLAG_ARCHIVED|ABOOK_FLAG_BLOCKED|ABOOK_FLAG_IGNORED), intval(ACCOUNT_OK), @@ -72,6 +72,19 @@ function onepoll_run($argv, $argc){ : datetime_convert('UTC','UTC',$contact['abook_updated'] . ' - 2 days') ); + if($contact['xchan_network'] === 'rss') { + logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG); + handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']); + q("update abook set abook_connected = '%s' where abook_id = %d limit 1", + dbesc(datetime_convert()), + intval($contact['abook_id']) + ); + return; + } + + if($contact['xchan_network'] !== 'zot') + return; + // update permissions $x = zot_refresh($contact,$importer); @@ -130,11 +143,9 @@ function onepoll_run($argv, $argc){ } } - // fetch some items // set last updated timestamp - if($contact['xchan_connurl']) { $r = q("SELECT xlink_id from xlink where xlink_xchan = '%s' and xlink_updated > UTC_TIMESTAMP() - INTERVAL 1 DAY limit 1", diff --git a/include/poller.php b/include/poller.php index b9d728e8d..2ba86dc0b 100644 --- a/include/poller.php +++ b/include/poller.php @@ -247,7 +247,7 @@ function poller_run($argv, $argc){ $sql_extra AND (( abook_flags & %d ) OR ( abook_flags = %d )) AND (( account_flags = %d ) OR ( account_flags = %d )) $abandon_sql ORDER BY RAND()", - intval(ABOOK_FLAG_HIDDEN|ABOOK_FLAG_PENDING|ABOOK_FLAG_UNCONNECTED), + intval(ABOOK_FLAG_HIDDEN|ABOOK_FLAG_PENDING|ABOOK_FLAG_UNCONNECTED|ABOOK_FLAG_FEED), intval(0), intval(ACCOUNT_OK), intval(ACCOUNT_UNVERIFIED) // FIXME @@ -263,6 +263,19 @@ function poller_run($argv, $argc){ $t = $contact['abook_updated']; $c = $contact['abook_connected']; + if($contact['abook_flags'] & ABOOK_FLAG_FEED) { + $min = intval(get_config('system','minimum_feedcheck_minutes')); + if(! $min) + $min = 60; + $x = datetime_convert('UTC','UTC',"now - $min minutes"); + if($c < $x) { + proc_run('php','include/onepoll.php',$contact['abook_id']); + if($interval) + @time_sleep_until(microtime(true) + (float) $interval); + } + continue; + } + if($c == $t) { if(datetime_convert('UTC','UTC', 'now') > datetime_convert('UTC','UTC', $t . " + 1 day")) diff --git a/include/text.php b/include/text.php index 410d9bc96..7da6a8f2b 100644 --- a/include/text.php +++ b/include/text.php @@ -1865,6 +1865,11 @@ function xchan_query(&$items,$abook = true) { $chans = q("select xchan.*,hubloc.* from xchan left join hubloc on hubloc_hash = xchan_hash where xchan_hash in (" . implode(',', $arr) . ") and ( hubloc_flags & " . intval(HUBLOC_FLAGS_PRIMARY) . " )"); } + $xchans = q("select * from xchan where xchan_hash in (" . implode(',',$arr) . ") and xchan_network in ('rss','unknown')"); + if(! $chans) + $chans = $xchans; + else + $chans = array_merge($xchans,$chans); } if($items && count($items) && $chans && count($chans)) { for($x = 0; $x < count($items); $x ++) { diff --git a/include/zot.php b/include/zot.php index 8627656c2..6ccee8c39 100644 --- a/include/zot.php +++ b/include/zot.php @@ -1791,8 +1791,6 @@ function process_mail_delivery($sender,$arr,$deliveries) { function process_profile_delivery($sender,$arr,$deliveries) { - // deliveries is irrelevant, what to do about birthday notification....? - logger('process_profile_delivery', LOGGER_DEBUG); $r = q("select xchan_addr from xchan where xchan_hash = '%s' limit 1", @@ -1864,7 +1862,7 @@ function import_directory_profile($hash,$profile,$addr,$ud_flags = UPDATE_FLAGS_ $update = false; foreach($r[0] as $k => $v) { if((array_key_exists($k,$arr)) && ($arr[$k] != $v)) { - logger('import_directory_profile: update' . $k . ' => ' . $arr[$k]); + logger('import_directory_profile: update ' . $k . ' => ' . $arr[$k]); $update = true; break; } @@ -1906,7 +1904,7 @@ function import_directory_profile($hash,$profile,$addr,$ud_flags = UPDATE_FLAGS_ } else { $update = true; - logger('import_directory_profile: new profile'); + logger('import_directory_profile: new profile '); $x = q("insert into xprof (xprof_hash, xprof_desc, xprof_dob, xprof_age, xprof_gender, xprof_marital, xprof_sexual, xprof_locale, xprof_region, xprof_postcode, xprof_country, xprof_about, xprof_homepage, xprof_hometown, xprof_keywords) values ('%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", dbesc($arr['xprof_hash']), dbesc($arr['xprof_desc']), |