streams/include/items.php

4744 lines
146 KiB
PHP
Raw Normal View History

2013-02-26 01:09:40 +00:00
<?php /** @file */
2010-07-18 13:02:55 +00:00
require_once('include/bbcode.php');
require_once('include/oembed.php');
require_once('include/crypto.php');
2013-04-26 03:01:24 +00:00
require_once('include/photo/photo_driver.php');
require_once('include/permissions.php');
2010-07-18 13:02:55 +00:00
function collect_recipients($item,&$private_envelope) {
2012-12-08 22:18:02 +00:00
require_once('include/group.php');
$private_envelope = ((intval($item['item_private'])) ? true : false);
$recipients = array();
if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid']) {
// it is private
$allow_people = expand_acl($item['allow_cid']);
2014-08-31 00:03:26 +00:00
$allow_groups = expand_groups(expand_acl($item['allow_gid']));
2014-08-31 00:03:26 +00:00
$allow_groups = filter_insecure($item['uid'],$allow_groups);
$recipients = array_unique(array_merge($allow_people,$allow_groups));
// if you specifically deny somebody but haven't allowed anybody, we'll allow everybody in your
// address book minus the denied connections. The post is still private and can't be seen publicly
// as that would allow the denied person to see the post by logging out.
if((! $item['allow_cid']) && (! $item['allow_gid'])) {
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$r = q("select * from abook where abook_channel = %d and not (abook_flags & %d)>0 ",
intval($item['uid']),
2014-07-02 04:24:43 +00:00
intval(ABOOK_FLAG_SELF|ABOOK_FLAG_PENDING|ABOOK_FLAG_ARCHIVED)
);
if($r) {
foreach($r as $rr) {
$recipients[] = $rr['abook_xchan'];
}
}
}
$deny_people = expand_acl($item['deny_cid']);
$deny_groups = expand_groups(expand_acl($item['deny_gid']));
$deny = array_unique(array_merge($deny_people,$deny_groups));
2014-08-31 00:03:26 +00:00
// Don't deny anybody if nobody was allowed (e.g. they were all filtered out)
// That would lead to array_diff doing the wrong thing.
// This will result in a private post that won't be delivered to anybody.
if($recipients && $deny)
$recipients = array_diff($recipients,$deny);
$private_envelope = true;
}
else {
// if the post is marked private but there are no recipients and public_policy/scope = self,
// only add the author and owner as recipients. The ACL for the post may live on the hub of
// a different clone. We need to get the post to that hub.
// The post may be private by virtue of not being visible to anybody on the internet,
// but there are no envelope recipients, so set this to false. Delivery is controlled
// by the directives in $item['public_policy'].
$private_envelope = false;
2014-11-18 02:29:57 +00:00
require_once('include/identity.php');
$sys = get_sys_channel();
if(array_key_exists('public_policy',$item) && $item['public_policy'] !== 'self') {
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$r = q("select abook_xchan, xchan_network from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and not (abook_flags & %d)>0 ",
intval($item['uid']),
2014-07-02 04:24:43 +00:00
intval(ABOOK_FLAG_SELF|ABOOK_FLAG_PENDING|ABOOK_FLAG_ARCHIVED)
);
if($r) {
// filter out restrictive public_policy settings from remote networks
// which don't have this concept and will treat them as public.
$policy = substr($item['public_policy'],0,3);
foreach($r as $rr) {
switch($policy) {
case 'net':
case 'aut':
case 'sit':
case 'any':
case 'con':
if($rr['xchan_network'] != 'zot')
break;
case 'pub':
case '':
default:
$recipients[] = $rr['abook_xchan'];
break;
}
}
}
2014-11-18 02:29:57 +00:00
// we probably want to check that discovery channel delivery is allowed before uncommenting this.
// if($policy === 'pub')
// $recipients[] = $sys['xchan_hash'];
}
}
2014-10-21 23:33:35 +00:00
// This is a somewhat expensive operation but important.
// Don't send this item to anybody who isn't allowed to see it
$recipients = check_list_permissions($item['uid'],$recipients,'view_stream');
2014-03-31 23:29:46 +00:00
// remove any upstream recipients from our list.
// If it is ourself we'll add it back in a second.
// This should prevent complex delivery chains from getting overly complex by not
// sending to anybody who is on our list of those who sent it to us.
if($item['route']) {
$route = explode(',',$item['route']);
2014-03-30 04:53:50 +00:00
if(count($route)) {
$route = array_unique($route);
$recipients = array_diff($recipients,$route);
}
}
// add ourself just in case we have nomadic clones that need to get a copy.
$recipients[] = $item['author_xchan'];
if($item['owner_xchan'] != $item['author_xchan'])
$recipients[] = $item['owner_xchan'];
return $recipients;
}
2014-08-31 00:03:26 +00:00
/**
* If channel is configured to filter insecure members of privacy groups
* (those whose networks leak privacy via email notifications or other criteria)
* remove them from any privacy groups (collections) that were included in a post.
* They can still be addressed individually.
* Networks may need to be added or removed from this list as circumstances change.
2014-08-31 05:53:21 +00:00
*
* Update: this may need to be the default, which will force people to opt-in to sending stuff
* privately to insecure platforms.
2014-08-31 00:03:26 +00:00
*/
function filter_insecure($channel_id,$arr) {
$insecure_nets = " and not xchan_network in ('diaspora', 'friendica-over-diaspora') ";
$ret = array();
if((! intval(get_config($channel_id,'system','filter_insecure_collections'))) || (! $arr))
return $arr;
$str = '';
foreach($arr as $rr) {
if(strlen($str))
$str .= ',';
$str .= "'" . dbesc($rr) . "'";
}
$r = q("select xchan_hash from xchan where xchan_hash in ($str) $insecure_nets ");
if($r) {
foreach($r as $rr) {
$ret[] = $rr['xchan_hash'];
}
}
return $ret;
}
function comments_are_now_closed($item) {
if($item['comments_closed'] !== NULL_DATE) {
$d = datetime_convert();
if($d > $item['comments_closed'])
return true;
}
return false;
}
/**
* @function can_comment_on_post($observer_xchan,$item);
*
* This function examines the comment_policy attached to an item and decides if the current observer has
* sufficient privileges to comment. This will normally be called on a remote site where perm_is_allowed()
* will not be suitable because the post owner does not have a local channel_id.
* Generally we should look at the item - in particular the author['book_flags'] and see if ABOOK_FLAG_SELF is set.
* If it is, you should be able to use perm_is_allowed( ... 'post_comments'), and if it isn't you need to call
* can_comment_on_post()
* We also check the comments_closed date/time on the item if this is set.
2013-09-28 12:03:58 +00:00
*/
function can_comment_on_post($observer_xchan,$item) {
// logger('can_comment_on_post: comment_policy: ' . $item['comment_policy'], LOGGER_DEBUG);
if(! $observer_xchan)
return false;
if($item['comment_policy'] === 'none')
return false;
if(comments_are_now_closed($item))
return false;
if($observer_xchan === $item['author_xchan'] || $observer_xchan === $item['owner_xchan'])
return true;
switch($item['comment_policy']) {
case 'self':
if($observer_xchan === $item['author_xchan'] || $observer_xchan === $item['owner_xchan'])
return true;
break;
case 'public':
// We don't allow public comments yet, until a policy
// for dealing with anonymous comments is in place with
// a means to moderate comments. Until that time, return
// false.
return false;
break;
case 'any connections':
case 'contacts':
case 'authenticated':
case '':
2013-09-21 02:14:57 +00:00
if(array_key_exists('owner',$item)) {
if(($item['owner']['abook_xchan']) && ($item['owner']['abook_their_perms'] & PERMS_W_COMMENT))
return true;
}
break;
default:
break;
}
2013-06-17 06:07:04 +00:00
if(strstr($item['comment_policy'],'network:') && strstr($item['comment_policy'],'red'))
return true;
2013-06-17 06:07:04 +00:00
if(strstr($item['comment_policy'],'site:') && strstr($item['comment_policy'],get_app()->get_hostname()))
return true;
return false;
}
/**
* @function add_source_route($iid,$hash)
* Adds $hash to the item source route specified by $iid
* @param integer $iid
* item['id'] of target item
* @param string $hash
* xchan_hash of the channel that sent the item
* Modifies item pointed to by $iid
*
* $item['route'] contains a comma-separated list of xchans that sent the current message,
* somewhat analogous to the * Received: header line in email. We can use this to perform
* loop detection and to avoid sending a particular item to any "upstream" sender (they
* already have a copy because they sent it to us).
*
*/
2014-03-30 04:53:50 +00:00
function add_source_route($iid,$hash) {
2014-04-01 00:21:16 +00:00
// logger('add_source_route ' . $iid . ' ' . $hash, LOGGER_DEBUG);
2014-04-01 00:14:56 +00:00
2014-04-01 00:21:16 +00:00
if((! $iid) || (! $hash))
2014-03-30 04:53:50 +00:00
return;
$r = q("select route from item where id = %d limit 1",
2014-03-30 04:53:50 +00:00
intval($iid)
);
if($r) {
$new_route = (($r[0]['route']) ? $r[0]['route'] . ',' : '') . $hash;
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
q("update item set route = '%s' where id = %d",
(dbesc($new_route)),
2014-03-30 04:53:50 +00:00
intval($iid)
);
}
}
/**
* @function red_zrl_callback
* preg_match function when fixing 'naked' links in mod item.php
* Check if we've got a hubloc for the site and use a zrl if we do, a url if we don't.
* Remove any existing zid= param which may have been pasted by mistake - and will have
* the author's credentials. zid's are dynamic and can't really be passed around like
* that.
*/
function red_zrl_callback($matches) {
2014-07-14 08:38:16 +00:00
require_once('include/hubloc.php');
$zrl = is_matrix_url($matches[2]);
$t = strip_zids($matches[2]);
if($t !== $matches[2]) {
$zrl = true;
$matches[2] = $t;
}
2014-02-08 20:08:07 +00:00
if($matches[1] === '#^')
$matches[1] = '';
if($zrl)
return $matches[1] . '#^[zrl=' . $matches[2] . ']' . $matches[2] . '[/zrl]';
2014-02-07 00:22:40 +00:00
return $matches[1] . '#^[url=' . $matches[2] . ']' . $matches[2] . '[/url]';
}
2014-02-09 08:30:43 +00:00
// If we've got a url or zrl tag with a naked url somewhere in the link text,
// escape it with quotes unless the naked url is a linked photo.
function red_escape_zrl_callback($matches) {
// Uncertain why the url/zrl forms weren't picked up by the non-greedy regex.
if((strpos($matches[3],'zmg') !== false) || (strpos($matches[3],'img') !== false) || (strpos($matches[3],'zrl') !== false) || (strpos($matches[3],'url') !== false))
2014-02-09 08:30:43 +00:00
return $matches[0];
return '[' . $matches[1] . 'rl' . $matches[2] . ']' . $matches[3] . '"' . $matches[4] . '"' . $matches[5] . '[/' . $matches[6] . 'rl]';
}
function red_escape_codeblock($m) {
2014-02-10 09:44:21 +00:00
return '[$b64' . $m[2] . base64_encode($m[1]) . '[/' . $m[2] . ']';
}
function red_unescape_codeblock($m) {
2014-02-10 09:44:21 +00:00
return '[' . $m[2] . base64_decode($m[1]) . '[/' . $m[2] . ']';
}
function red_zrlify_img_callback($matches) {
2014-07-14 08:38:16 +00:00
require_once('include/hubloc.php');
$zrl = is_matrix_url($matches[2]);
$t = strip_zids($matches[2]);
if($t !== $matches[2]) {
$zrl = true;
$matches[2] = $t;
}
if($zrl)
return '[zmg' . $matches[1] . ']' . $matches[2] . '[/zmg]';
return $matches[0];
}
/**
* @function post_activity_item($arr)
*
* post an activity
*
* @param array $arr
*
* In its simplest form one needs only to set $arr['body'] to post a note to the logged in channel's wall.
* Much more complex activities can be created. Permissions are checked. No filtering, tag expansion
* or other processing is performed.
*
* @returns array
* 'success' => true or false
* 'activity' => the resulting activity if successful
*/
function post_activity_item($arr) {
$ret = array('success' => false);
$is_comment = false;
if((($arr['parent']) && $arr['parent'] != $arr['id']) || (($arr['parent_mid']) && $arr['parent_mid'] != $arr['mid']))
$is_comment = true;
if(! x($arr,'item_flags')) {
if($is_comment)
$arr['item_flags'] = ITEM_ORIGIN;
else
$arr['item_flags'] = ITEM_ORIGIN | ITEM_WALL | ITEM_THREAD_TOP;
}
$channel = get_app()->get_channel();
$observer = get_app()->get_observer();
$arr['aid'] = ((x($arr,'aid')) ? $arr['aid'] : $channel['channel_account_id']);
$arr['uid'] = ((x($arr,'uid')) ? $arr['uid'] : $channel['channel_id']);
if(! perm_is_allowed($arr['uid'],$observer['xchan_hash'],(($is_comment) ? 'post_comments' : 'post_wall'))) {
$ret['message'] = t('Permission denied');
return $ret;
}
$arr['public_policy'] = ((x($_REQUEST,'public_policy')) ? escape_tags($_REQUEST['public_policy']) : map_scope($channel['channel_r_stream'],true));
if($arr['public_policy'])
$arr['item_private'] = 1;
2013-12-08 07:29:26 +00:00
if(! array_key_exists('mimetype',$arr))
$arr['mimetype'] = 'text/bbcode';
if(array_key_exists('item_private',$arr) && $arr['item_private']) {
$arr['body'] = z_input_filter($arr['uid'],$arr['body'],$arr['mimetype']);
if($channel) {
if($channel['channel_hash'] === $arr['author_xchan']) {
$arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey']));
$arr['item_flags'] = $arr['item_flags'] | ITEM_VERIFIED;
}
}
logger('Encrypting local storage');
$key = get_config('system','pubkey');
$arr['item_flags'] = $arr['item_flags'] | ITEM_OBSCURED;
if($arr['title'])
$arr['title'] = json_encode(crypto_encapsulate($arr['title'],$key));
2013-12-08 07:29:26 +00:00
if($arr['body'])
$arr['body'] = json_encode(crypto_encapsulate($arr['body'],$key));
2013-12-08 07:29:26 +00:00
}
$arr['mid'] = ((x($arr,'mid')) ? $arr['mid'] : item_message_id());
$arr['parent_mid'] = ((x($arr,'parent_mid')) ? $arr['parent_mid'] : $arr['mid']);
$arr['thr_parent'] = ((x($arr,'thr_parent')) ? $arr['thr_parent'] : $arr['mid']);
2013-04-18 04:40:40 +00:00
$arr['owner_xchan'] = ((x($arr,'owner_xchan')) ? $arr['owner_xchan'] : $channel['channel_hash']);
$arr['author_xchan'] = ((x($arr,'author_xchan')) ? $arr['author_xchan'] : $observer['xchan_hash']);
$arr['verb'] = ((x($arr,'verb')) ? $arr['verb'] : ACTIVITY_POST);
$arr['obj_type'] = ((x($arr,'obj_type')) ? $arr['obj_type'] : ACTIVITY_OBJ_NOTE);
$arr['allow_cid'] = ((x($arr,'allow_cid')) ? $arr['allow_cid'] : $channel['channel_allow_cid']);
$arr['allow_gid'] = ((x($arr,'allow_gid')) ? $arr['allow_gid'] : $channel['channel_allow_gid']);
$arr['deny_cid'] = ((x($arr,'deny_cid')) ? $arr['deny_cid'] : $channel['channel_deny_cid']);
$arr['deny_gid'] = ((x($arr,'deny_gid')) ? $arr['deny_gid'] : $channel['channel_deny_gid']);
2013-06-17 06:08:52 +00:00
$arr['comment_policy'] = map_scope($channel['channel_w_comment']);
if ((! $arr['plink']) && ($arr['item_flags'] & ITEM_THREAD_TOP)) {
$arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid'];
}
// for the benefit of plugins, we will behave as if this is an API call rather than a normal online post
$_REQUEST['api_source'] = 1;
2013-05-22 04:54:21 +00:00
call_hooks('post_local',$arr);
if(x($arr,'cancel')) {
logger('post_activity_item: post cancelled by plugin.');
return $ret;
}
$post = item_store($arr);
2013-12-08 07:29:26 +00:00
if($post['success'])
$post_id = $post['item_id'];
if($post_id) {
$arr['id'] = $post_id;
call_hooks('post_local_end', $arr);
proc_run('php','include/notifier.php','activity',$post_id);
$ret['success'] = true;
2013-05-22 03:52:18 +00:00
$r = q("select * from item where id = %d limit 1",
intval($post_id)
);
if($r)
$ret['activity'] = $r[0];
}
return $ret;
}
/**
* @function get_public_feed($channel,$params)
* generate an Atom feed
*/
function get_public_feed($channel,$params) {
$type = 'xml';
$begin = NULL_DATE;
$end = '';
$start = 0;
$records = 40;
$direction = 'desc';
2013-09-06 02:31:26 +00:00
$pages = 0;
if(! $params)
$params = array();
2013-09-06 02:31:26 +00:00
$params['type'] = ((x($params,'type')) ? $params['type'] : 'xml');
$params['begin'] = ((x($params,'begin')) ? $params['begin'] : NULL_DATE);
2013-09-06 02:31:26 +00:00
$params['end'] = ((x($params,'end')) ? $params['end'] : datetime_convert('UTC','UTC','now'));
$params['start'] = ((x($params,'start')) ? $params['start'] : 0);
$params['records'] = ((x($params,'records')) ? $params['records'] : 40);
$params['direction'] = ((x($params,'direction')) ? $params['direction'] : 'desc');
$params['pages'] = ((x($params,'pages')) ? intval($params['pages']) : 0);
2014-08-22 22:51:48 +00:00
$params['top'] = ((x($params,'top')) ? intval($params['top']) : 0);
switch($params['type']) {
case 'json':
header("Content-type: application/atom+json");
break;
case 'xml':
default:
header("Content-type: application/atom+xml");
break;
}
2012-04-14 11:19:41 +00:00
return get_feed_for($channel,get_observer_hash(),$params);
}
2010-07-18 13:02:55 +00:00
function get_feed_for($channel, $observer_hash, $params) {
2010-09-10 08:45:58 +00:00
if(! channel)
http_status_exit(401);
2012-04-14 11:19:41 +00:00
2013-09-06 02:31:26 +00:00
if($params['pages']) {
if(! perm_is_allowed($channel['channel_id'],$observer_hash,'view_pages'))
http_status_exit(403);
}
else {
if(! perm_is_allowed($channel['channel_id'],$observer_hash,'view_stream'))
http_status_exit(403);
}
$items = items_fetch(array(
'wall' => '1',
'datequery' => $params['begin'],
'datequery2' => $params['end'],
'start' => $params['start'], // FIXME
'records' => $params['records'], // FIXME
'direction' => $params['direction'], // FIXME
2013-09-06 02:31:26 +00:00
'pages' => $params['pages'],
2014-08-22 22:51:48 +00:00
'order' => 'post',
'top' => $params['top']
), $channel, $observer_hash, CLIENT_MODE_NORMAL, get_app()->module);
2010-07-18 13:02:55 +00:00
$feed_template = get_markup_template('atom_feed.tpl');
2010-07-18 13:02:55 +00:00
$atom = '';
$atom .= replace_macros($feed_template, array(
2013-04-15 05:24:47 +00:00
'$version' => xmlify(RED_VERSION),
'$red' => xmlify(RED_PLATFORM),
2014-09-03 08:09:28 +00:00
'$feed_id' => xmlify($channel['xchan_url']),
'$feed_title' => xmlify($channel['channel_name']),
2010-10-31 23:38:22 +00:00
'$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now' , ATOM_TIME)) ,
'$hub' => '', // feed_hublinks(),
'$salmon' => '', // feed_salmonlinks($channel['channel_address']),
'$name' => xmlify($channel['channel_name']),
2014-09-03 08:09:28 +00:00
'$profile_page' => xmlify($channel['xchan_url']),
'$mimephoto' => xmlify($channel['xchan_photo_mimetype']),
'$photo' => xmlify($channel['xchan_photo_l']),
'$thumb' => xmlify($channel['xchan_photo_m']),
'$picdate' => '',
'$uridate' => '',
'$namdate' => '',
'$birthday' => '',
'$community' => '',
2010-07-18 13:02:55 +00:00
));
2010-12-25 02:32:23 +00:00
call_hooks('atom_feed', $atom);
if($items) {
$type = 'html';
foreach($items as $item) {
if($item['item_private'])
continue;
2010-09-09 03:14:17 +00:00
$atom .= atom_entry($item,$type,null,$owner,true);
}
2010-07-18 13:02:55 +00:00
}
2010-12-25 02:32:23 +00:00
call_hooks('atom_feed_end', $atom);
$atom .= '</feed>' . "\r\n";
2010-07-18 13:02:55 +00:00
return $atom;
2010-09-09 03:14:17 +00:00
}
function construct_verb($item) {
if($item['verb'])
return $item['verb'];
return ACTIVITY_POST;
}
function construct_activity_object($item) {
2010-09-09 03:14:17 +00:00
2010-09-17 10:10:19 +00:00
if($item['object']) {
$o = '<as:object>' . "\r\n";
$r = json_decode($item['object'],false);
if(! $r)
return '';
2010-09-17 10:10:19 +00:00
if($r->type)
$o .= '<as:obj_type>' . xmlify($r->type) . '</as:obj_type>' . "\r\n";
2010-09-17 10:10:19 +00:00
if($r->id)
$o .= '<id>' . xmlify($r->id) . '</id>' . "\r\n";
2010-11-05 03:47:44 +00:00
if($r->title)
$o .= '<title>' . xmlify($r->title) . '</title>' . "\r\n";
if($r->links) {
// FIXME!!
if(substr($r->link,0,1) === '<') {
$r->link = preg_replace('/\<link(.*?)\"\>/','<link$1"/>',$r->link);
2010-11-05 03:47:44 +00:00
$o .= $r->link;
}
else
$o .= '<link rel="alternate" type="text/html" href="' . xmlify($r->link) . '" />' . "\r\n";
}
2010-09-17 10:10:19 +00:00
if($r->content)
$o .= '<content type="html" >' . xmlify(bbcode($r->content)) . '</content>' . "\r\n";
2010-09-17 10:10:19 +00:00
$o .= '</as:object>' . "\r\n";
return $o;
2010-09-09 03:14:17 +00:00
}
2010-09-17 10:10:19 +00:00
2010-09-09 03:14:17 +00:00
return '';
2010-07-19 03:49:10 +00:00
}
function construct_activity_target($item) {
if($item['target']) {
$o = '<as:target>' . "\r\n";
$r = json_decode($item['target'],false);
if(! $r)
return '';
if($r->type)
$o .= '<as:obj_type>' . xmlify($r->type) . '</as:obj_type>' . "\r\n";
if($r->id)
$o .= '<id>' . xmlify($r->id) . '</id>' . "\r\n";
2010-11-05 03:47:44 +00:00
if($r->title)
$o .= '<title>' . xmlify($r->title) . '</title>' . "\r\n";
if($r->links) {
// FIXME !!!
if(substr($r->link,0,1) === '<') {
if(strstr($r->link,'&') && (! strstr($r->link,'&amp;')))
$r->link = str_replace('&','&amp;', $r->link);
$r->link = preg_replace('/\<link(.*?)\"\>/','<link$1"/>',$r->link);
2010-11-05 03:47:44 +00:00
$o .= $r->link;
}
else
$o .= '<link rel="alternate" type="text/html" href="' . xmlify($r->link) . '" />' . "\r\n";
}
if($r->content)
$o .= '<content type="html" >' . xmlify(bbcode($r->content)) . '</content>' . "\r\n";
$o .= '</as:target>' . "\r\n";
return $o;
}
return '';
}
/* limit_body_size()
*
* The purpose of this function is to apply system message length limits to
* imported messages without including any embedded photos in the length
*/
function limit_body_size($body) {
$maxlen = get_max_import_size();
// If the length of the body, including the embedded images, is smaller
// than the maximum, then don't waste time looking for the images
if($maxlen && (strlen($body) > $maxlen)) {
$orig_body = $body;
$new_body = '';
$textlen = 0;
$max_found = false;
$img_start = strpos($orig_body, '[img');
$img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false);
$img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false);
while(($img_st_close !== false) && ($img_end !== false)) {
$img_st_close++; // make it point to AFTER the closing bracket
$img_end += $img_start;
$img_end += strlen('[/img]');
if(! strcmp(substr($orig_body, $img_start + $img_st_close, 5), 'data:')) {
// This is an embedded image
if( ($textlen + $img_start) > $maxlen ) {
if($textlen < $maxlen) {
logger('limit_body_size: the limit happens before an embedded image', LOGGER_DEBUG);
$new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen);
$textlen = $maxlen;
}
}
else {
$new_body = $new_body . substr($orig_body, 0, $img_start);
2012-07-08 00:47:13 +00:00
$textlen += $img_start;
}
$new_body = $new_body . substr($orig_body, $img_start, $img_end - $img_start);
}
else {
if( ($textlen + $img_end) > $maxlen ) {
if($textlen < $maxlen) {
$new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen);
$textlen = $maxlen;
}
}
else {
$new_body = $new_body . substr($orig_body, 0, $img_end);
$textlen += $img_end;
}
}
$orig_body = substr($orig_body, $img_end);
if($orig_body === false) // in case the body ends on a closing image tag
$orig_body = '';
$img_start = strpos($orig_body, '[img');
$img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false);
$img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false);
}
if( ($textlen + strlen($orig_body)) > $maxlen) {
if($textlen < $maxlen) {
$new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen);
$textlen = $maxlen;
}
}
else {
$new_body = $new_body . $orig_body;
$textlen += strlen($orig_body);
}
return $new_body;
}
else
return $body;
}
function title_is_body($title, $body) {
$title = strip_tags($title);
$title = trim($title);
$title = str_replace(array("\n", "\r", "\t", " "), array("","","",""), $title);
$body = strip_tags($body);
$body = trim($body);
$body = str_replace(array("\n", "\r", "\t", " "), array("","","",""), $body);
if (strlen($title) < strlen($body))
$body = substr($body, 0, strlen($title));
if (($title != $body) and (substr($title, -3) == "...")) {
$pos = strrpos($title, "...");
if ($pos > 0) {
$title = substr($title, 0, $pos);
$body = substr($body, 0, $pos);
}
}
return($title == $body);
}
2010-07-19 03:49:10 +00:00
function get_item_elements($x) {
2012-07-30 05:43:51 +00:00
$arr = array();
$arr['body'] = (($x['body']) ? htmlspecialchars($x['body'],ENT_COMPAT,'UTF-8',false) : '');
2012-07-30 05:43:51 +00:00
$key = get_config('system','pubkey');
2014-08-10 06:38:33 +00:00
$maxlen = get_max_import_size();
if($maxlen && mb_strlen($arr['body']) > $maxlen) {
$arr['body'] = mb_substr($arr['body'],0,$maxlen,'UTF-8');
logger('get_item_elements: message length exceeds max_import_size: truncated');
}
$arr['created'] = datetime_convert('UTC','UTC',$x['created']);
$arr['edited'] = datetime_convert('UTC','UTC',$x['edited']);
2012-07-30 05:43:51 +00:00
if($arr['created'] > datetime_convert())
$arr['created'] = datetime_convert();
2012-07-30 05:43:51 +00:00
if($arr['edited'] > datetime_convert())
$arr['edited'] = datetime_convert();
$arr['expires'] = ((x($x,'expires') && $x['expires'])
? datetime_convert('UTC','UTC',$x['expires'])
: NULL_DATE);
$arr['commented'] = ((x($x,'commented') && $x['commented'])
? datetime_convert('UTC','UTC',$x['commented'])
: $arr['created']);
$arr['comments_closed'] = ((x($x,'comments_closed') && $x['comments_closed'])
? datetime_convert('UTC','UTC',$x['comments_closed'])
: NULL_DATE);
$arr['title'] = (($x['title']) ? htmlspecialchars($x['title'], ENT_COMPAT,'UTF-8',false) : '');
if(mb_strlen($arr['title']) > 255)
$arr['title'] = mb_substr($arr['title'],0,255);
$arr['app'] = (($x['app']) ? htmlspecialchars($x['app'], ENT_COMPAT,'UTF-8',false) : '');
$arr['route'] = (($x['route']) ? htmlspecialchars($x['route'], ENT_COMPAT,'UTF-8',false) : '');
$arr['mid'] = (($x['message_id']) ? htmlspecialchars($x['message_id'], ENT_COMPAT,'UTF-8',false) : '');
$arr['parent_mid'] = (($x['message_top']) ? htmlspecialchars($x['message_top'], ENT_COMPAT,'UTF-8',false) : '');
$arr['thr_parent'] = (($x['message_parent']) ? htmlspecialchars($x['message_parent'], ENT_COMPAT,'UTF-8',false) : '');
$arr['plink'] = (($x['permalink']) ? htmlspecialchars($x['permalink'], ENT_COMPAT,'UTF-8',false) : '');
$arr['location'] = (($x['location']) ? htmlspecialchars($x['location'], ENT_COMPAT,'UTF-8',false) : '');
$arr['coord'] = (($x['longlat']) ? htmlspecialchars($x['longlat'], ENT_COMPAT,'UTF-8',false) : '');
$arr['verb'] = (($x['verb']) ? htmlspecialchars($x['verb'], ENT_COMPAT,'UTF-8',false) : '');
$arr['mimetype'] = (($x['mimetype']) ? htmlspecialchars($x['mimetype'], ENT_COMPAT,'UTF-8',false) : '');
$arr['obj_type'] = (($x['object_type']) ? htmlspecialchars($x['object_type'], ENT_COMPAT,'UTF-8',false) : '');
$arr['tgt_type'] = (($x['target_type']) ? htmlspecialchars($x['target_type'], ENT_COMPAT,'UTF-8',false) : '');
$arr['public_policy'] = (($x['public_scope']) ? htmlspecialchars($x['public_scope'], ENT_COMPAT,'UTF-8',false) : '');
if($arr['public_policy'] === 'public')
$arr['public_policy'] = '';
$arr['comment_policy'] = (($x['comment_scope']) ? htmlspecialchars($x['comment_scope'], ENT_COMPAT,'UTF-8',false) : 'contacts');
2013-10-03 04:04:48 +00:00
$arr['sig'] = (($x['signature']) ? htmlspecialchars($x['signature'], ENT_COMPAT,'UTF-8',false) : '');
2013-10-03 04:04:48 +00:00
$arr['diaspora_meta'] = (($x['diaspora_signature']) ? json_encode(crypto_encapsulate($x['diaspora_signature'],$key)) : '');
2012-11-17 20:55:59 +00:00
$arr['object'] = activity_sanitise($x['object']);
$arr['target'] = activity_sanitise($x['target']);
2012-07-30 05:43:51 +00:00
$arr['attach'] = activity_sanitise($x['attach']);
2012-11-17 20:55:59 +00:00
$arr['term'] = decode_tags($x['tags']);
2012-07-30 05:43:51 +00:00
2012-11-27 01:07:23 +00:00
$arr['item_private'] = ((array_key_exists('flags',$x) && is_array($x['flags']) && in_array('private',$x['flags'])) ? 1 : 0);
2013-08-01 01:57:14 +00:00
$arr['item_flags'] = 0;
if(array_key_exists('flags',$x) && in_array('deleted',$x['flags']))
2015-01-09 14:18:45 +00:00
$arr['item_restrict'] = ITEM_DELETED;
if(array_key_exists('flags',$x) && in_array('hidden',$x['flags']))
$arr['item_restrict'] = ITEM_HIDDEN;
2012-11-27 01:07:23 +00:00
2012-11-17 20:55:59 +00:00
// Here's the deal - the site might be down or whatever but if there's a new person you've never
// seen before sending stuff to your stream, we MUST be able to look them up and import their data from their
// hub and verify that they are legit - or else we're going to toss the post. We only need to do this
// once, and after that your hub knows them. Sure some info is in the post, but it's only a transit identifier
// and not enough info to be able to look you up from your hash - which is the only thing stored with the post.
2012-07-30 05:43:51 +00:00
if(($xchan_hash = import_author_xchan($x['author'])) !== false)
$arr['author_xchan'] = $xchan_hash;
2012-11-17 20:55:59 +00:00
else
return array();
2012-07-30 05:43:51 +00:00
// save a potentially expensive lookup if author == owner
2014-07-15 04:21:24 +00:00
if($arr['author_xchan'] === make_xchan_hash($x['owner']['guid'],$x['owner']['guid_sig']))
$arr['owner_xchan'] = $arr['author_xchan'];
else {
if(($xchan_hash = import_author_xchan($x['owner'])) !== false)
$arr['owner_xchan'] = $xchan_hash;
else
return array();
}
2012-07-30 05:43:51 +00:00
2013-10-03 04:04:48 +00:00
if($arr['sig']) {
$r = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1",
dbesc($arr['author_xchan'])
);
if($r && rsa_verify($x['body'],base64url_decode($arr['sig']),$r[0]['xchan_pubkey']))
$arr['item_flags'] |= ITEM_VERIFIED;
else
logger('get_item_elements: message verification failed.');
}
// if it's a private post, encrypt it in the DB.
// We have to do that here because we need to cleanse the input and prevent bad stuff from getting in,
// and we need plaintext to do that.
2013-10-03 04:04:48 +00:00
if(intval($arr['item_private'])) {
$arr['item_flags'] = $arr['item_flags'] | ITEM_OBSCURED;
if($arr['title'])
$arr['title'] = json_encode(crypto_encapsulate($arr['title'],$key));
2013-10-03 04:04:48 +00:00
if($arr['body'])
$arr['body'] = json_encode(crypto_encapsulate($arr['body'],$key));
2013-10-03 04:04:48 +00:00
}
if(array_key_exists('revision',$x)) {
// extended export encoding
$arr['revision'] = $x['revision'];
$arr['allow_cid'] = $x['allow_cid'];
$arr['allow_gid'] = $x['allow_gid'];
$arr['deny_cid'] = $x['deny_cid'];
$arr['deny_gid'] = $x['deny_gid'];
$arr['layout_mid'] = $x['layout_mid'];
$arr['postopts'] = $x['postopts'];
$arr['resource_id'] = $x['resource_id'];
$arr['resource_type'] = $x['resource_type'];
$arr['item_restrict'] = $x['item_restrict'];
$arr['item_flags'] = $x['item_flags'];
$arr['attach'] = $x['attach'];
}
2012-07-30 05:43:51 +00:00
return $arr;
}
2012-12-06 00:44:07 +00:00
2012-11-17 20:55:59 +00:00
function import_author_xchan($x) {
$arr = array('xchan' => $x, 'xchan_hash' => '');
call_hooks('import_author_xchan',$arr);
if($arr['xchan_hash'])
return $arr['xchan_hash'];
if((! array_key_exists('network', $x)) || ($x['network'] === 'zot')) {
2014-02-17 22:30:02 +00:00
$y = import_author_zot($x);
}
if(! $y)
$y = import_author_diaspora($x);
2014-02-17 22:30:02 +00:00
if($x['network'] === 'rss') {
$y = import_author_rss($x);
}
if($x['network'] === 'unknown') {
$y = import_author_unknown($x);
}
2014-02-17 22:30:02 +00:00
return(($y) ? $y : false);
}
function import_author_diaspora($x) {
if(! $x['address'])
return false;
if(discover_by_webbie($x['address'])) {
$r = q("select xchan_hash from xchan where xchan_addr = '%s' limit 1",
dbesc($x['address'])
);
if($r)
return $r[0]['xchan_hash'];
}
return false;
}
2014-02-17 22:30:02 +00:00
function import_author_rss($x) {
if(! $x['url'])
return false;
$r = q("select xchan_hash from xchan where xchan_network = 'rss' and xchan_url = '%s' limit 1",
dbesc($x['url'])
);
if($r) {
logger('import_author_rss: in cache' , LOGGER_DEBUG);
return $r[0]['xchan_hash'];
}
$name = trim($x['name']);
$r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_url, xchan_name, xchan_network )
values ( '%s', '%s', '%s', '%s', '%s' )",
dbesc($x['guid']),
dbesc($x['guid']),
2014-02-17 22:30:02 +00:00
dbesc($x['url']),
dbesc(($name) ? $name : t('(Unknown)')),
2014-02-17 22:30:02 +00:00
dbesc('rss')
);
2014-09-08 23:06:15 +00:00
if($r && $x['photo']) {
2014-02-17 22:30:02 +00:00
2014-09-08 23:06:15 +00:00
$photos = import_profile_photo($x['photo']['src'],$x['url']);
2014-02-17 22:30:02 +00:00
if($photos) {
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$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_url = '%s' and xchan_network = 'rss'",
2014-02-17 22:30:02 +00:00
dbesc(datetime_convert('UTC','UTC',$arr['photo_updated'])),
dbesc($photos[0]),
dbesc($photos[1]),
dbesc($photos[2]),
dbesc($photos[3]),
dbesc($x['url'])
);
if($r)
return $x['url'];
}
}
return false;
2014-02-17 22:30:02 +00:00
2012-11-17 20:55:59 +00:00
}
2012-07-30 05:43:51 +00:00
function import_author_unknown($x) {
if(! $x['url'])
return false;
$r = q("select xchan_hash from xchan where xchan_network = 'unknown' and xchan_url = '%s' limit 1",
dbesc($x['url'])
);
if($r) {
logger('import_author_unknown: in cache' , LOGGER_DEBUG);
return $r[0]['xchan_hash'];
}
$name = trim($x['name']);
$r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_url, xchan_name, xchan_network )
values ( '%s', '%s', '%s', '%s', '%s' )",
dbesc($x['url']),
dbesc($x['url']),
dbesc($x['url']),
dbesc(($name) ? $name : t('(Unknown)')),
dbesc('unknown')
);
if($r && $x['photo']) {
$photos = import_profile_photo($x['photo']['src'],$x['url']);
if($photos) {
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$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_url = '%s' and xchan_network = 'unknown'",
dbesc(datetime_convert('UTC','UTC',$arr['photo_updated'])),
dbesc($photos[0]),
dbesc($photos[1]),
dbesc($photos[2]),
dbesc($photos[3]),
dbesc($x['url'])
);
if($r)
return $x['url'];
}
}
return false;
}
function encode_item($item,$mirror = false) {
2012-11-15 07:09:25 +00:00
$x = array();
$x['type'] = 'activity';
$x['encoding'] = 'zot';
2012-11-15 07:09:25 +00:00
2013-10-03 04:04:48 +00:00
// logger('encode_item: ' . print_r($item,true));
$r = q("select channel_r_stream, channel_w_comment from channel where channel_id = %d limit 1",
intval($item['uid'])
);
2014-08-08 22:27:17 +00:00
if($r)
$comment_scope = $r[0]['channel_w_comment'];
2014-08-08 22:27:17 +00:00
else
$comment_scope = 0;
2014-08-09 22:21:15 +00:00
$scope = $item['public_policy'];
2014-08-08 22:27:17 +00:00
if(! $scope)
$scope = 'public';
$c_scope = map_scope($comment_scope);
$key = get_config('system','prvkey');
if(array_key_exists('item_flags',$item) && ($item['item_flags'] & ITEM_OBSCURED)) {
if($item['title'])
$item['title'] = crypto_unencapsulate(json_decode_plus($item['title']),$key);
if($item['body'])
$item['body'] = crypto_unencapsulate(json_decode_plus($item['body']),$key);
}
// If we're trying to backup an item so that it's recoverable or for export/imprt,
// add all the attributes we need to recover it
if($mirror) {
$x['id'] = $item['id'];
$x['parent'] = $item['parent'];
$x['uid'] = $item['uid'];
$x['allow_cid'] = $item['allow_cid'];
$x['allow_gid'] = $item['allow_gid'];
$x['deny_cid'] = $item['deny_cid'];
$x['deny_gid'] = $item['deny_gid'];
$x['revision'] = $item['revision'];
$x['layout_mid'] = $item['layout_mid'];
$x['postopts'] = $item['postopts'];
$x['resource_id'] = $item['resource_id'];
$x['resource_type'] = $item['resource_type'];
$x['item_restrict'] = $item['item_restrict'];
$x['item_flags'] = $item['item_flags'];
$x['attach'] = $item['attach'];
}
$x['message_id'] = $item['mid'];
$x['message_top'] = $item['parent_mid'];
$x['message_parent'] = $item['thr_parent'];
$x['created'] = $item['created'];
$x['edited'] = $item['edited'];
// always send 0's over the wire
$x['expires'] = (($item['expires'] == '0001-01-01 00:00:00') ? '0000-00-00 00:00:00' : $item['expires']);
$x['commented'] = $item['commented'];
$x['mimetype'] = $item['mimetype'];
$x['title'] = $item['title'];
$x['body'] = $item['body'];
$x['app'] = $item['app'];
$x['verb'] = $item['verb'];
$x['object_type'] = $item['obj_type'];
$x['target_type'] = $item['tgt_type'];
$x['permalink'] = $item['plink'];
$x['location'] = $item['location'];
$x['longlat'] = $item['coord'];
$x['signature'] = $item['sig'];
$x['route'] = $item['route'];
$x['owner'] = encode_item_xchan($item['owner']);
$x['author'] = encode_item_xchan($item['author']);
if($item['object'])
$x['object'] = json_decode_plus($item['object']);
if($item['target'])
$x['target'] = json_decode_plus($item['target']);
if($item['attach'])
$x['attach'] = json_decode_plus($item['attach']);
if($y = encode_item_flags($item))
$x['flags'] = $y;
if($item['comments_closed'] !== NULL_DATE)
$x['comments_closed'] = $item['comments_closed'];
$x['public_scope'] = $scope;
if($item['item_flags'] & ITEM_NOCOMMENT)
$x['comment_scope'] = 'none';
else
$x['comment_scope'] = $c_scope;
if($item['term'])
$x['tags'] = encode_item_terms($item['term']);
2012-11-15 07:09:25 +00:00
if($item['diaspora_meta'])
$x['diaspora_signature'] = crypto_unencapsulate(json_decode($item['diaspora_meta'],true),$key);
logger('encode_item: ' . print_r($x,true), LOGGER_DATA);
2013-10-03 04:04:48 +00:00
2012-11-15 07:09:25 +00:00
return $x;
}
2014-08-07 02:24:46 +00:00
function map_scope($scope,$strip = false) {
switch($scope) {
2013-02-15 22:13:58 +00:00
case 0:
return 'self';
case PERMS_PUBLIC:
2014-08-07 02:24:46 +00:00
if($strip)
return '';
return 'public';
case PERMS_NETWORK:
return 'network: red';
2014-08-07 02:24:46 +00:00
case PERMS_AUTHED:
return 'authenticated';
case PERMS_SITE:
return 'site: ' . get_app()->get_hostname();
case PERMS_PENDING:
return 'any connections';
case PERMS_CONTACTS:
default:
return 'contacts';
}
}
2014-08-07 02:24:46 +00:00
function translate_scope($scope) {
if(! $scope || $scope === 'public')
return t('Visible to anybody on the internet.');
2014-08-07 02:24:46 +00:00
if(strpos($scope,'self') === 0)
return t('Visible to you only.');
if(strpos($scope,'network:') === 0)
return t('Visible to anybody in this network.');
if(strpos($scope,'authenticated') === 0)
return t('Visible to anybody authenticated.');
if(strpos($scope,'site:') === 0)
return sprintf( t('Visible to anybody on %s.'), strip_tags(substr($scope,6)));
if(strpos($scope,'any connections') === 0)
return t('Visible to all connections.');
if(strpos($scope,'contacts') === 0)
return t('Visible to approved connections.');
if(strpos($scope,'specific') === 0)
return t('Visible to specific connections.');
2014-08-07 02:24:46 +00:00
}
function encode_item_xchan($xchan) {
$ret = array();
$ret['name'] = $xchan['xchan_name'];
$ret['address'] = $xchan['xchan_addr'];
$ret['url'] = (($xchan['hubloc_url']) ? $xchan['hubloc_url'] : $xchan['xchan_url']);
$ret['network'] = $xchan['xchan_network'];
$ret['photo'] = array('mimetype' => $xchan['xchan_photo_mimetype'], 'src' => $xchan['xchan_photo_m']);
$ret['guid'] = $xchan['xchan_guid'];
$ret['guid_sig'] = $xchan['xchan_guid_sig'];
return $ret;
}
function encode_item_terms($terms) {
$ret = array();
2014-02-04 03:38:15 +00:00
$allowed_export_terms = array( TERM_UNKNOWN, TERM_HASHTAG, TERM_MENTION, TERM_CATEGORY, TERM_BOOKMARK );
if($terms) {
foreach($terms as $term) {
if(in_array($term['type'],$allowed_export_terms))
2012-11-17 20:55:59 +00:00
$ret[] = array('tag' => $term['term'], 'url' => $term['url'], 'type' => termtype($term['type']));
}
}
return $ret;
}
function termtype($t) {
2014-02-04 03:38:15 +00:00
$types = array('unknown','hashtag','mention','category','private_category','file','search','thing','bookmark');
return(($types[$t]) ? $types[$t] : 'unknown');
}
2010-07-19 03:49:10 +00:00
2012-11-17 20:55:59 +00:00
function decode_tags($t) {
if($t) {
$ret = array();
foreach($t as $x) {
$tag = array();
$tag['term'] = htmlspecialchars($x['tag'], ENT_COMPAT,'UTF-8',false);
$tag['url'] = htmlspecialchars($x['url'], ENT_COMPAT,'UTF-8',false);
2012-11-17 20:55:59 +00:00
switch($x['type']) {
case 'hashtag':
$tag['type'] = TERM_HASHTAG;
break;
case 'mention':
$tag['type'] = TERM_MENTION;
break;
case 'category':
$tag['type'] = TERM_CATEGORY;
break;
case 'private_category':
$tag['type'] = TERM_PCATEGORY;
break;
case 'file':
$tag['type'] = TERM_FILE;
break;
case 'search':
$tag['type'] = TERM_SEARCH;
break;
2014-02-04 03:38:15 +00:00
case 'thing':
$tag['type'] = TERM_THING;
break;
case 'bookmark':
$tag['type'] = TERM_BOOKMARK;
break;
2012-11-17 20:55:59 +00:00
default:
case 'unknown':
$tag['type'] = TERM_UNKNOWN;
break;
}
$ret[] = $tag;
}
return $ret;
}
return '';
}
// santise a potentially complex array
2012-11-17 20:55:59 +00:00
function activity_sanitise($arr) {
if($arr) {
if(is_array($arr)) {
$ret = array();
foreach($arr as $k => $x) {
if(is_array($x))
$ret[$k] = activity_sanitise($x);
else
$ret[$k] = htmlspecialchars($x, ENT_COMPAT,'UTF-8',false);
}
return $ret;
}
else {
return htmlspecialchars($arr, ENT_COMPAT,'UTF-8', false);
2012-11-17 20:55:59 +00:00
}
}
return '';
}
// sanitise a simple linear array
function array_sanitise($arr) {
if($arr) {
$ret = array();
foreach($arr as $x) {
$ret[] = htmlspecialchars($x, ENT_COMPAT,'UTF-8',false);
}
return $ret;
}
return '';
}
function encode_item_flags($item) {
// most of item_flags and item_restrict are local settings which don't apply when transmitted.
// We may need those for the case of syncing other hub locations which you are attached to.
$ret = array();
if($item['item_restrict'] & ITEM_DELETED)
$ret[] = 'deleted';
2015-01-09 14:18:45 +00:00
if($item['item_restrict'] & ITEM_HIDDEN)
$ret[] = 'hidden';
if($item['item_flags'] & ITEM_THREAD_TOP)
$ret[] = 'thread_parent';
if($item['item_flags'] & ITEM_NSFW)
$ret[] = 'nsfw';
2012-11-27 01:07:23 +00:00
if($item['item_private'])
$ret[] = 'private';
return $ret;
}
2012-12-06 00:44:07 +00:00
function encode_mail($item) {
$x = array();
$x['type'] = 'mail';
$x['encoding'] = 'zot';
2012-12-06 00:44:07 +00:00
2013-07-31 09:32:41 +00:00
if(array_key_exists('mail_flags',$item) && ($item['mail_flags'] & MAIL_OBSCURED)) {
$key = get_config('system','prvkey');
if($item['title'])
$item['title'] = crypto_unencapsulate(json_decode_plus($item['title']),$key);
2013-07-31 09:32:41 +00:00
if($item['body'])
$item['body'] = crypto_unencapsulate(json_decode_plus($item['body']),$key);
2013-07-31 09:32:41 +00:00
}
2012-12-06 00:44:07 +00:00
$x['message_id'] = $item['mid'];
$x['message_parent'] = $item['parent_mid'];
2012-12-06 00:44:07 +00:00
$x['created'] = $item['created'];
$x['expires'] = $item['expires'];
$x['diaspora_meta'] = $item['diaspora_meta'];
2012-12-06 00:44:07 +00:00
$x['title'] = $item['title'];
$x['body'] = $item['body'];
$x['from'] = encode_item_xchan($item['from']);
$x['to'] = encode_item_xchan($item['to']);
if($item['attach'])
$x['attach'] = json_decode_plus($item['attach']);
$x['flags'] = array();
if($item['mail_flags'] & MAIL_RECALLED) {
$x['flags'][] = 'recalled';
$x['title'] = '';
$x['body'] = '';
}
2012-12-06 00:44:07 +00:00
return $x;
}
function get_mail_elements($x) {
$arr = array();
$arr['body'] = (($x['body']) ? htmlspecialchars($x['body'], ENT_COMPAT,'UTF-8',false) : '');
$arr['title'] = (($x['title'])? htmlspecialchars($x['title'],ENT_COMPAT,'UTF-8',false) : '');
2012-12-06 00:44:07 +00:00
$arr['created'] = datetime_convert('UTC','UTC',$x['created']);
if((! array_key_exists('expires',$x)) || ($x['expires'] === NULL_DATE))
$arr['expires'] = NULL_DATE;
else
$arr['expires'] = datetime_convert('UTC','UTC',$x['expires']);
2012-12-06 00:44:07 +00:00
$arr['mail_flags'] = 0;
if($x['flags'] && is_array($x['flags'])) {
if(in_array('recalled',$x['flags'])) {
$arr['mail_flags'] |= MAIL_RECALLED;
}
}
2013-07-31 09:32:41 +00:00
$key = get_config('system','pubkey');
$arr['mail_flags'] |= MAIL_OBSCURED;
$arr['body'] = htmlspecialchars($arr['body'],ENT_COMPAT,'UTF-8',false);
2013-07-31 09:32:41 +00:00
if($arr['body'])
$arr['body'] = json_encode(crypto_encapsulate($arr['body'],$key));
$arr['title'] = htmlspecialchars($arr['title'],ENT_COMPAT,'UTF-8',false);
2013-07-31 09:32:41 +00:00
if($arr['title'])
$arr['title'] = json_encode(crypto_encapsulate($arr['title'],$key));
2012-12-06 00:44:07 +00:00
if($arr['created'] > datetime_convert())
$arr['created'] = datetime_convert();
$arr['mid'] = (($x['message_id']) ? htmlspecialchars($x['message_id'], ENT_COMPAT,'UTF-8',false) : '');
$arr['parent_mid'] = (($x['message_parent']) ? htmlspecialchars($x['message_parent'], ENT_COMPAT,'UTF-8',false) : '');
2012-12-06 00:44:07 +00:00
if($x['attach'])
$arr['attach'] = activity_sanitise($x['attach']);
if(($xchan_hash = import_author_xchan($x['from'])) !== false)
$arr['from_xchan'] = $xchan_hash;
2012-12-06 00:44:07 +00:00
else
return array();
if(($xchan_hash = import_author_xchan($x['to'])) !== false)
$arr['to_xchan'] = $xchan_hash;
2012-12-06 00:44:07 +00:00
else
return array();
return $arr;
}
function get_profile_elements($x) {
$arr = array();
if(($xchan_hash = import_author_xchan($x['from'])) !== false)
$arr['xprof_hash'] = $xchan_hash;
else
return array();
$arr['desc'] = (($x['title']) ? htmlspecialchars($x['title'],ENT_COMPAT,'UTF-8',false) : '');
$arr['dob'] = datetime_convert('UTC','UTC',$x['birthday'],'Y-m-d');
$arr['age'] = (($x['age']) ? intval($x['age']) : 0);
$arr['gender'] = (($x['gender']) ? htmlspecialchars($x['gender'], ENT_COMPAT,'UTF-8',false) : '');
$arr['marital'] = (($x['marital']) ? htmlspecialchars($x['marital'], ENT_COMPAT,'UTF-8',false) : '');
$arr['sexual'] = (($x['sexual']) ? htmlspecialchars($x['sexual'], ENT_COMPAT,'UTF-8',false) : '');
$arr['locale'] = (($x['locale']) ? htmlspecialchars($x['locale'], ENT_COMPAT,'UTF-8',false) : '');
$arr['region'] = (($x['region']) ? htmlspecialchars($x['region'], ENT_COMPAT,'UTF-8',false) : '');
$arr['postcode'] = (($x['postcode']) ? htmlspecialchars($x['postcode'], ENT_COMPAT,'UTF-8',false) : '');
$arr['country'] = (($x['country']) ? htmlspecialchars($x['country'], ENT_COMPAT,'UTF-8',false) : '');
$arr['keywords'] = (($x['keywords'] && is_array($x['keywords'])) ? array_sanitise($x['keywords']) : array());
return $arr;
}
2012-12-06 00:44:07 +00:00
function get_atom_elements($feed,$item,&$author) {
2010-07-19 03:49:10 +00:00
2010-09-09 03:14:17 +00:00
$best_photo = array();
2010-07-19 03:49:10 +00:00
$res = array();
2010-09-09 03:14:17 +00:00
$found_author = $item->get_author();
if($found_author) {
$author['author_name'] = unxmlify($found_author->get_name());
$author['author_link'] = unxmlify($found_author->get_link());
$author['author_is_feed'] = false;
2011-04-05 02:36:18 +00:00
}
else {
$author['author_name'] = unxmlify($feed->get_title());
$author['author_link'] = unxmlify($feed->get_permalink());
$author['author_is_feed'] = true;
2011-04-05 02:36:18 +00:00
}
2014-08-20 04:31:33 +00:00
if(substr($author['author_link'],-1,1) == '/')
$author['author_link'] = substr($author['author_link'],0,-1);
$res['mid'] = base64url_encode(unxmlify($item->get_id()));
2010-07-19 03:49:10 +00:00
$res['title'] = unxmlify($item->get_title());
$res['body'] = unxmlify($item->get_content());
$res['plink'] = unxmlify($item->get_link(0));
$res['item_flags'] = ITEM_RSS;
// removing the content of the title if its identically to the body
// This helps with auto generated titles e.g. from tumblr
if (title_is_body($res["title"], $res["body"]))
$res['title'] = "";
if($res['plink'])
$base_url = implode('/', array_slice(explode('/',$res['plink']),0,3));
else
$base_url = '';
// look for a photo. We should check media size and find the best one,
// but for now let's just find any author photo
$rawauthor = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
$base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
foreach($base as $link) {
if(!x($author, 'author_photo') || ! $author['author_photo']) {
if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
$author['author_photo'] = unxmlify($link['attribs']['']['href']);
}
}
}
$rawactor = $item->get_item_tags(NAMESPACE_ACTIVITY, 'actor');
if($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['obj_type'][0]['data'],ACTIVITY_OBJ_PERSON)) {
$base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
if($base && count($base)) {
foreach($base as $link) {
2014-08-20 04:31:33 +00:00
if($link['attribs']['']['rel'] === 'alternate' && (! $res['author_link']))
$author['author_link'] = unxmlify($link['attribs']['']['href']);
if(!x($author, 'author_photo') || ! $author['author_photo']) {
if($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo')
$author['author_photo'] = unxmlify($link['attribs']['']['href']);
}
}
}
}
// check for a yahoo media element (github etc.)
if(! $author['author_photo']) {
$rawmedia = $item->get_item_tags(NAMESPACE_YMEDIA,'thumbnail');
if($rawmedia && $rawmedia[0]['attribs']['']['url']) {
$author['author_photo'] = strip_tags(unxmlify($rawmedia[0]['attribs']['']['url']));
}
}
// No photo/profile-link on the item - look at the feed level
if((! (x($author,'author_link'))) || (! (x($author,'author_photo')))) {
$rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
$base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
foreach($base as $link) {
if($link['attribs']['']['rel'] === 'alternate' && (! $author['author_link'])) {
$author['author_link'] = unxmlify($link['attribs']['']['href']);
$author['author_is_feed'] = true;
}
if(! $author['author_photo']) {
if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
$author['author_photo'] = unxmlify($link['attribs']['']['href']);
}
}
}
$rawactor = $feed->get_feed_tags(NAMESPACE_ACTIVITY, 'subject');
if($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['obj_type'][0]['data'],ACTIVITY_OBJ_PERSON)) {
$base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
if($base && count($base)) {
foreach($base as $link) {
2014-08-20 04:31:33 +00:00
if($link['attribs']['']['rel'] === 'alternate' && (! $res['author_link']))
$author['author_link'] = unxmlify($link['attribs']['']['href']);
if(! (x($author,'author_photo'))) {
if($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo')
$author['author_photo'] = unxmlify($link['attribs']['']['href']);
}
}
}
}
}
2011-06-21 02:08:40 +00:00
$apps = $item->get_item_tags(NAMESPACE_STATUSNET,'notice_info');
if($apps && $apps[0]['attribs']['']['source']) {
2011-06-23 22:58:43 +00:00
$res['app'] = strip_tags(unxmlify($apps[0]['attribs']['']['source']));
2011-06-21 02:08:40 +00:00
}
/**
* If there's a copy of the body content which is guaranteed to have survived mangling in transit, use it.
*/
$have_real_body = false;
$rawenv = $item->get_item_tags(NAMESPACE_DFRN, 'env');
if($rawenv) {
$have_real_body = true;
$res['body'] = $rawenv[0]['data'];
$res['body'] = str_replace(array(' ',"\t","\r","\n"), array('','','',''),$res['body']);
2011-02-02 01:50:49 +00:00
// make sure nobody is trying to sneak some html tags by us
$res['body'] = notags(base64url_decode($res['body']));
// We could probably turn these old Friendica bbcode bookmarks into bookmark tags but we'd have to
// create a term table item for them. For now just make sure they stay as links.
2014-09-29 22:41:47 +00:00
$res['body'] = preg_replace('/\[bookmark(.*?)\](.*?)\[\/bookmark\]/','[url$1]$2[/url]',$res['body']);
}
$res['body'] = limit_body_size($res['body']);
2010-07-19 03:49:10 +00:00
2010-09-09 03:14:17 +00:00
// It isn't certain at this point whether our content is plaintext or html and we'd be foolish to trust
// the content type. Our own network only emits text normally, though it might have been converted to
2011-01-18 03:50:18 +00:00
// html if we used a pubsubhubbub transport. But if we see even one html tag in our text, we will
2010-09-09 03:14:17 +00:00
// have to assume it is all html and needs to be purified.
// It doesn't matter all that much security wise - because before this content is used anywhere, we are
// going to escape any tags we find regardless, but this lets us import a limited subset of html from
// the wild, by sanitising it and converting supported tags to bbcode before we rip out any remaining
// html.
if((strpos($res['body'],'<') !== false) && (strpos($res['body'],'>') !== false)) {
2010-09-09 03:14:17 +00:00
$res['body'] = reltoabs($res['body'],$base_url);
$res['body'] = html2bb_video($res['body']);
$res['body'] = oembed_html2bbcode($res['body']);
$res['body'] = purify_html($res['body']);
2010-09-09 09:00:54 +00:00
$res['body'] = @html2bbcode($res['body']);
2011-01-18 03:50:18 +00:00
}
elseif(! $have_real_body) {
// it's not one of our messages and it has no tags
// so it's probably just text. We'll escape it just to be safe.
$res['body'] = escape_tags($res['body']);
}
2014-09-24 09:18:13 +00:00
if($res['plink'] && $res['title']) {
$res['body'] = '#^[url=' . $res['plink'] . ']' . $res['title'] . '[/url]' . "\n\n" . $res['body'];
$terms = array();
$terms[] = array(
'otype' => TERM_OBJ_POST,
'type' => TERM_BOOKMARK,
'url' => $res['plink'],
'term' => $res['title'],
);
}
elseif($res['plink']) {
$res['body'] = '#^[url]' . $res['plink'] . '[/url]' . "\n\n" . $res['body'];
$terms = array();
$terms[] = array(
'otype' => TERM_OBJ_POST,
'type' => TERM_BOOKMARK,
'url' => $res['plink'],
'term' => $res['plink'],
);
}
2014-09-24 09:18:13 +00:00
$private = $item->get_item_tags(NAMESPACE_DFRN,'private');
if($private && intval($private[0]['data']) > 0)
2014-08-20 04:31:33 +00:00
$res['item_private'] = ((intval($private[0]['data'])) ? 1 : 0);
else
2014-08-20 04:31:33 +00:00
$res['item_private'] = 0;
$rawlocation = $item->get_item_tags(NAMESPACE_DFRN, 'location');
2010-08-20 21:33:15 +00:00
if($rawlocation)
$res['location'] = unxmlify($rawlocation[0]['data']);
$rawcreated = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'published');
if($rawcreated)
$res['created'] = unxmlify($rawcreated[0]['data']);
2010-07-19 03:49:10 +00:00
$rawedited = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'updated');
if($rawedited)
$res['edited'] = unxmlify($rawedited[0]['data']);
2010-07-19 03:49:10 +00:00
if((x($res,'edited')) && (! (x($res,'created'))))
2011-02-02 01:05:17 +00:00
$res['created'] = $res['edited'];
if(! $res['created'])
$res['created'] = $item->get_date('c');
if(! $res['edited'])
$res['edited'] = $item->get_date('c');
// Disallow time travelling posts
$d1 = strtotime($res['created']);
$d2 = strtotime($res['edited']);
$d3 = strtotime('now');
if($d1 > $d3)
$res['created'] = datetime_convert();
if($d2 > $d3)
$res['edited'] = datetime_convert();
2014-09-01 03:51:05 +00:00
$res['created'] = datetime_convert('UTC','UTC',$res['created']);
$res['edited'] = datetime_convert('UTC','UTC',$res['edited']);
2010-08-03 02:06:36 +00:00
$rawowner = $item->get_item_tags(NAMESPACE_DFRN, 'owner');
if(! $rawowner)
$rawowner = $item->get_item_tags(NAMESPACE_ZOT,'owner');
2010-09-09 03:14:17 +00:00
if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])
$author['owner_name'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']);
2010-09-09 03:14:17 +00:00
elseif($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data'])
$author['owner_name'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']);
2010-09-09 03:14:17 +00:00
if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])
$author['owner_link'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']);
2010-09-09 03:14:17 +00:00
elseif($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data'])
$author['owner_link'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']);
2010-09-09 03:14:17 +00:00
if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
$base = $rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
foreach($base as $link) {
if(!x($author, 'owner_photo') || ! $author['owner_photo']) {
if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
$author['owner_photo'] = unxmlify($link['attribs']['']['href']);
}
}
}
2010-07-19 03:49:10 +00:00
2010-10-20 03:52:05 +00:00
$rawgeo = $item->get_item_tags(NAMESPACE_GEORSS,'point');
if($rawgeo)
$res['coord'] = unxmlify($rawgeo[0]['data']);
2010-09-09 03:14:17 +00:00
$rawverb = $item->get_item_tags(NAMESPACE_ACTIVITY, 'verb');
2010-09-09 03:14:17 +00:00
// select between supported verbs
if($rawverb) {
2010-09-09 03:14:17 +00:00
$res['verb'] = unxmlify($rawverb[0]['data']);
}
// translate OStatus unfollow to activity streams if it happened to get selected
if((x($res,'verb')) && ($res['verb'] === 'http://ostatus.org/schema/1.0/unfollow'))
$res['verb'] = ACTIVITY_UNFOLLOW;
2011-04-06 00:41:02 +00:00
$cats = $item->get_categories();
if($cats) {
2014-09-24 08:58:24 +00:00
if(is_null($terms))
$terms = array();
2011-04-06 00:41:02 +00:00
foreach($cats as $cat) {
$term = $cat->get_term();
if(! $term)
$term = $cat->get_label();
$scheme = $cat->get_scheme();
2012-07-11 11:29:47 +00:00
$termurl = '';
if($scheme && $term && stristr($scheme,'X-DFRN:')) {
$termtype = ((substr($scheme,7,1) === '#') ? TERM_HASHTAG : TERM_MENTION);
$termurl = unxmlify(substr($scheme,9));
}
else {
2014-09-01 05:15:00 +00:00
$termtype = TERM_CATEGORY;
2012-07-11 11:29:47 +00:00
}
$termterm = notags(trim(unxmlify($term)));
if($termterm) {
2014-09-01 03:51:05 +00:00
$terms[] = array(
2012-07-11 11:29:47 +00:00
'otype' => TERM_OBJ_POST,
'type' => $termtype,
'url' => $termurl,
'term' => $termterm,
);
}
2011-04-06 00:41:02 +00:00
}
}
2010-09-09 03:14:17 +00:00
2014-09-24 09:08:35 +00:00
if(! is_null($terms))
$res['term'] = $terms;
$attach = $item->get_enclosures();
if($attach) {
2014-08-20 04:31:33 +00:00
$res['attach'] = array();
$att_arr = array();
foreach($attach as $att) {
2011-04-13 08:53:40 +00:00
$len = intval($att->get_length());
$link = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_link()))));
$title = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_title()))));
$type = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_type()))));
if(strpos($type,';'))
$type = substr($type,0,strpos($type,';'));
if((! $link) || (strpos($link,'http') !== 0))
continue;
if(! $title)
$title = ' ';
if(! $type)
$type = 'application/octet-stream';
2014-09-02 03:59:53 +00:00
$res['attach'][] = array('href' => $link, 'length' => $len, 'type' => $type, 'title' => $title );
}
}
2010-09-09 03:14:17 +00:00
$rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'object');
2010-09-17 10:10:19 +00:00
2010-09-09 03:14:17 +00:00
if($rawobj) {
2014-08-20 04:31:33 +00:00
$obj = array();
2012-04-17 11:33:50 +00:00
$child = $rawobj[0]['child'];
if($child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']) {
$res['obj_type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'];
2014-08-20 04:31:33 +00:00
$obj['type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'];
2010-09-17 10:10:19 +00:00
}
2012-04-17 11:33:50 +00:00
if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'])
2014-08-20 04:31:33 +00:00
$obj['id'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'];
2012-04-17 11:33:50 +00:00
if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link'])
2014-08-20 04:31:33 +00:00
$obj['link'] = encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']);
2012-04-17 11:33:50 +00:00
if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'title') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'])
2014-08-20 04:31:33 +00:00
$obj['title'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'];
2012-04-17 11:33:50 +00:00
if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'content') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) {
$body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data'];
2010-09-17 10:10:19 +00:00
if(! $body)
2012-04-17 11:33:50 +00:00
$body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data'];
// preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events
2014-08-20 04:31:33 +00:00
$obj['orig'] = xmlify($body);
if((strpos($body,'<') !== false) || (strpos($body,'>') !== false)) {
2010-09-17 10:10:19 +00:00
$body = purify_html($body);
2011-01-18 03:50:18 +00:00
$body = html2bbcode($body);
2010-09-17 10:10:19 +00:00
}
2014-08-20 04:31:33 +00:00
$obj['content'] = $body;
2010-09-17 10:10:19 +00:00
}
2014-08-20 04:31:33 +00:00
$res['object'] = $obj;
2010-09-09 03:14:17 +00:00
}
$rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'target');
if($rawobj) {
2014-08-20 04:31:33 +00:00
$obj = array();
2012-04-17 11:33:50 +00:00
$child = $rawobj[0]['child'];
if($child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']) {
2014-08-20 04:31:33 +00:00
$res['tgt_type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'];
$obj['type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'];
}
2012-04-17 11:33:50 +00:00
if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'])
2014-08-20 04:31:33 +00:00
$obj['id'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'];
2012-04-17 11:33:50 +00:00
if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link'])
2014-08-20 04:31:33 +00:00
$obj['link'] = encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']);
if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'title') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'])
$obj['title'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'];
if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'content') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) {
2012-04-17 11:33:50 +00:00
$body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data'];
if(! $body)
2012-04-17 11:33:50 +00:00
$body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data'];
// preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events
2014-08-20 04:31:33 +00:00
$obj['orig'] = xmlify($body);
if((strpos($body,'<') !== false) || (strpos($body,'>') !== false)) {
$body = purify_html($body);
2011-01-18 03:50:18 +00:00
$body = html2bbcode($body);
2014-08-20 04:31:33 +00:00
}
2014-08-20 04:31:33 +00:00
$obj['content'] = $body;
}
2014-08-20 04:31:33 +00:00
$res['target'] = $obj;
}
2014-09-01 03:51:05 +00:00
$res['public_policy'] = 'specific';
$res['comment_policy'] = 'none';
2010-12-25 23:01:02 +00:00
$arr = array('feed' => $feed, 'item' => $item, 'result' => $res);
call_hooks('parse_atom', $arr);
logger('get_atom_elements: author: ' . print_r($author,true),LOGGER_DATA);
logger('get_atom_elements: ' . print_r($res,true),LOGGER_DATA);
2010-12-25 02:32:23 +00:00
2010-07-19 03:49:10 +00:00
return $res;
}
function encode_rel_links($links) {
$o = '';
if(! ((is_array($links)) && (count($links))))
return $o;
2014-08-20 04:31:33 +00:00
foreach($links as $link) {
$o .= '<link ';
if($link['attribs']['']['rel'])
$o .= 'rel="' . $link['attribs']['']['rel'] . '" ';
if($link['attribs']['']['type'])
$o .= 'type="' . $link['attribs']['']['type'] . '" ';
if($link['attribs']['']['href'])
$o .= 'href="' . $link['attribs']['']['href'] . '" ';
2010-11-04 07:37:29 +00:00
if( (x($link['attribs'],NAMESPACE_MEDIA)) && $link['attribs'][NAMESPACE_MEDIA]['width'])
$o .= 'media:width="' . $link['attribs'][NAMESPACE_MEDIA]['width'] . '" ';
2010-11-04 07:37:29 +00:00
if( (x($link['attribs'],NAMESPACE_MEDIA)) && $link['attribs'][NAMESPACE_MEDIA]['height'])
$o .= 'media:height="' . $link['attribs'][NAMESPACE_MEDIA]['height'] . '" ';
$o .= ' />' . "\n" ;
}
return xmlify($o);
}
function item_store($arr,$allow_exec = false) {
2010-07-19 03:49:10 +00:00
2013-11-29 02:10:04 +00:00
$d = array('item' => $arr, 'allow_exec' => $allow_exec);
call_hooks('item_store', $d );
$arr = $d['item'];
$allow_exec = $d['allow_exec'];
$ret = array('success' => false, 'item_id' => 0);
if(! $arr['uid']) {
logger('item_store: no uid');
$ret['message'] = 'No uid.';
2014-08-30 00:31:40 +00:00
return $ret;
}
$uplinked_comment = false;
// If a page layout is provided, ensure it exists and belongs to us.
if(array_key_exists('layout_mid',$arr) && $arr['layout_mid']) {
$l = q("select item_restrict from item where mid = '%s' and uid = %d limit 1",
dbesc($arr['layout_mid']),
intval($arr['uid'])
);
if((! $l) || (! ($l[0]['item_restrict'] & ITEM_PDL)))
unset($arr['layout_mid']);
}
// Don't let anybody set these, either intentionally or accidentally
if(array_key_exists('id',$arr))
unset($arr['id']);
if(array_key_exists('parent',$arr))
unset($arr['parent']);
$arr['mimetype'] = ((x($arr,'mimetype')) ? notags(trim($arr['mimetype'])) : 'text/bbcode');
if(($arr['mimetype'] == 'application/x-php') && (! $allow_exec)) {
logger('item_store: php mimetype but allow_exec is denied.');
$ret['message'] = 'exec denied.';
return $ret;
}
$arr['title'] = ((array_key_exists('title',$arr) && strlen($arr['title'])) ? trim($arr['title']) : '');
$arr['body'] = ((array_key_exists('body',$arr) && strlen($arr['body'])) ? trim($arr['body']) : '');
$arr['diaspora_meta'] = ((x($arr,'diaspora_meta')) ? $arr['diaspora_meta'] : '');
$arr['allow_cid'] = ((x($arr,'allow_cid')) ? trim($arr['allow_cid']) : '');
$arr['allow_gid'] = ((x($arr,'allow_gid')) ? trim($arr['allow_gid']) : '');
$arr['deny_cid'] = ((x($arr,'deny_cid')) ? trim($arr['deny_cid']) : '');
$arr['deny_gid'] = ((x($arr,'deny_gid')) ? trim($arr['deny_gid']) : '');
$arr['item_private'] = ((x($arr,'item_private')) ? intval($arr['item_private']) : 0 );
$arr['item_flags'] = ((x($arr,'item_flags')) ? intval($arr['item_flags']) : 0 );
2013-10-03 04:04:48 +00:00
// only detect language if we have text content, and if the post is private but not yet
// obscured, make it so.
if(! ($arr['item_flags'] & ITEM_OBSCURED)) {
2013-10-03 04:04:48 +00:00
$arr['lang'] = detect_language($arr['body']);
// apply the input filter here - if it is obscured it has been filtered already
$arr['body'] = z_input_filter($arr['uid'],$arr['body'],$arr['mimetype']);
2013-10-03 04:04:48 +00:00
if(local_user() && (! $arr['sig'])) {
$channel = get_app()->get_channel();
if($channel['channel_hash'] === $arr['author_xchan']) {
$arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey']));
$arr['item_flags'] |= ITEM_VERIFIED;
}
}
$allowed_languages = get_pconfig($arr['uid'],'system','allowed_languages');
if((is_array($allowed_languages)) && ($arr['lang']) && (! array_key_exists($arr['lang'],$allowed_languages))) {
$translate = array('item' => $arr, 'from' => $arr['lang'], 'to' => $allowed_languages, 'translated' => false);
call_hooks('item_translate', $translate);
if((! $translate['translated']) && (intval(get_pconfig($arr['uid'],'system','reject_disallowed_languages')))) {
logger('item_store: language ' . $arr['lang'] . ' not accepted for uid ' . $arr['uid']);
$ret['message'] = 'language not accepted';
return $ret;
}
$arr = $translate['item'];
}
if($arr['item_private']) {
$key = get_config('system','pubkey');
$arr['item_flags'] = $arr['item_flags'] | ITEM_OBSCURED;
if($arr['title'])
$arr['title'] = json_encode(crypto_encapsulate($arr['title'],$key));
if($arr['body'])
$arr['body'] = json_encode(crypto_encapsulate($arr['body'],$key));
}
}
2013-01-07 21:58:25 +00:00
if((x($arr,'object')) && is_array($arr['object'])) {
activity_sanitise($arr['object']);
$arr['object'] = json_encode($arr['object']);
}
if((x($arr,'target')) && is_array($arr['target'])) {
activity_sanitise($arr['target']);
$arr['target'] = json_encode($arr['target']);
}
if((x($arr,'attach')) && is_array($arr['attach'])) {
activity_sanitise($arr['attach']);
$arr['attach'] = json_encode($arr['attach']);
}
$arr['aid'] = ((x($arr,'aid')) ? intval($arr['aid']) : 0);
$arr['mid'] = ((x($arr,'mid')) ? notags(trim($arr['mid'])) : random_string());
$arr['author_xchan'] = ((x($arr,'author_xchan')) ? notags(trim($arr['author_xchan'])) : '');
$arr['owner_xchan'] = ((x($arr,'owner_xchan')) ? notags(trim($arr['owner_xchan'])) : '');
2010-11-10 04:38:24 +00:00
$arr['created'] = ((x($arr,'created') !== false) ? datetime_convert('UTC','UTC',$arr['created']) : datetime_convert());
$arr['edited'] = ((x($arr,'edited') !== false) ? datetime_convert('UTC','UTC',$arr['edited']) : datetime_convert());
$arr['expires'] = ((x($arr,'expires') !== false) ? datetime_convert('UTC','UTC',$arr['expires']) : NULL_DATE);
$arr['commented'] = ((x($arr,'commented') !== false) ? datetime_convert('UTC','UTC',$arr['commented']) : datetime_convert());
$arr['comments_closed'] = ((x($arr,'comments_closed') !== false) ? datetime_convert('UTC','UTC',$arr['comments_closed']) : NULL_DATE);
$arr['received'] = datetime_convert();
2010-11-10 04:38:24 +00:00
$arr['changed'] = datetime_convert();
$arr['location'] = ((x($arr,'location')) ? notags(trim($arr['location'])) : '');
$arr['coord'] = ((x($arr,'coord')) ? notags(trim($arr['coord'])) : '');
2013-09-11 05:45:04 +00:00
$arr['parent_mid'] = ((x($arr,'parent_mid')) ? notags(trim($arr['parent_mid'])) : '');
$arr['thr_parent'] = ((x($arr,'thr_parent')) ? notags(trim($arr['thr_parent'])) : $arr['parent_mid']);
2010-11-10 04:38:24 +00:00
$arr['verb'] = ((x($arr,'verb')) ? notags(trim($arr['verb'])) : '');
2012-10-06 08:17:25 +00:00
$arr['obj_type'] = ((x($arr,'obj_type')) ? notags(trim($arr['obj_type'])) : '');
2010-11-10 04:38:24 +00:00
$arr['object'] = ((x($arr,'object')) ? trim($arr['object']) : '');
2012-10-06 08:17:25 +00:00
$arr['tgt_type'] = ((x($arr,'tgt_type')) ? notags(trim($arr['tgt_type'])) : '');
2010-11-10 04:38:24 +00:00
$arr['target'] = ((x($arr,'target')) ? trim($arr['target']) : '');
$arr['plink'] = ((x($arr,'plink')) ? notags(trim($arr['plink'])) : '');
2011-04-07 04:59:07 +00:00
$arr['attach'] = ((x($arr,'attach')) ? notags(trim($arr['attach'])) : '');
2011-06-21 02:08:40 +00:00
$arr['app'] = ((x($arr,'app')) ? notags(trim($arr['app'])) : '');
$arr['item_restrict'] = ((x($arr,'item_restrict')) ? intval($arr['item_restrict']) : 0 );
$arr['public_policy'] = ((x($arr,'public_policy')) ? notags(trim($arr['public_policy'])) : '' );
$arr['comment_policy'] = ((x($arr,'comment_policy')) ? notags(trim($arr['comment_policy'])) : 'contacts' );
2012-10-06 08:17:25 +00:00
$arr['item_flags'] = $arr['item_flags'] | ITEM_UNSEEN;
if($arr['comment_policy'] == 'none')
$arr['item_flags'] = $arr['item_flags'] | ITEM_NOCOMMENT;
2013-05-24 00:24:15 +00:00
// handle time travelers
// Allow a bit of fudge in case somebody just has a slightly slow/fast clock
$d1 = new DateTime('now +10 minutes', new DateTimeZone('UTC'));
$d2 = new DateTime($arr['created'] . '+00:00');
2013-05-24 00:24:15 +00:00
if($d2 > $d1)
$arr['item_restrict'] = $arr['item_restrict'] | ITEM_DELAYED_PUBLISH;
$arr['llink'] = z_root() . '/display/' . $arr['mid'];
if(! $arr['plink'])
$arr['plink'] = $arr['llink'];
if($arr['parent_mid'] === $arr['mid']) {
$parent_id = 0;
2012-02-28 12:56:16 +00:00
$parent_deleted = 0;
$allow_cid = $arr['allow_cid'];
$allow_gid = $arr['allow_gid'];
$deny_cid = $arr['deny_cid'];
$deny_gid = $arr['deny_gid'];
2014-08-09 22:21:15 +00:00
$public_policy = $arr['public_policy'];
$comments_closed = $arr['comments_closed'];
$arr['item_flags'] = $arr['item_flags'] | ITEM_THREAD_TOP;
}
else {
// find the parent and snarf the item id and ACL's
// and anything else we need to inherit
$r = q("SELECT * FROM `item` WHERE `mid` = '%s' AND `uid` = %d ORDER BY `id` ASC LIMIT 1",
dbesc($arr['parent_mid']),
intval($arr['uid'])
);
2013-07-22 05:39:21 +00:00
if($r) {
if(comments_are_now_closed($r[0])) {
logger('item_store: comments closed');
$ret['message'] = 'Comments closed.';
2014-08-30 00:31:40 +00:00
return $ret;
}
// is the new message multi-level threaded?
// even though we don't support it now, preserve the info
// and re-attach to the conversation parent.
if($r[0]['mid'] != $r[0]['parent_mid']) {
$arr['parent_mid'] = $r[0]['parent_mid'];
$z = q("SELECT * FROM `item` WHERE `mid` = '%s' AND `parent_mid` = '%s' AND `uid` = %d
2011-10-12 09:21:18 +00:00
ORDER BY `id` ASC LIMIT 1",
dbesc($r[0]['parent_mid']),
dbesc($r[0]['parent_mid']),
intval($arr['uid'])
);
if($z && count($z))
$r = $z;
}
$parent_id = $r[0]['id'];
$parent_deleted = $r[0]['item_restrict'] & ITEM_DELETED;
$allow_cid = $r[0]['allow_cid'];
$allow_gid = $r[0]['allow_gid'];
$deny_cid = $r[0]['deny_cid'];
$deny_gid = $r[0]['deny_gid'];
$public_policy = $r[0]['public_policy'];
$comments_closed = $r[0]['comments_closed'];
2012-10-06 08:17:25 +00:00
if($r[0]['item_flags'] & ITEM_WALL)
2012-10-06 08:17:25 +00:00
$arr['item_flags'] = $arr['item_flags'] | ITEM_WALL;
2012-06-11 12:28:08 +00:00
// An uplinked comment might arrive with a downstream owner.
// Fix it.
if($r[0]['owner_xchan'] !== $arr['owner_xchan']) {
$arr['owner_xchan'] = $r[0]['owner_xchan'];
$uplinked_comment = true;
}
2012-06-11 12:28:08 +00:00
// if the parent is private, force privacy for the entire conversation
2012-10-08 01:44:06 +00:00
if($r[0]['item_private'])
$arr['item_private'] = $r[0]['item_private'];
2012-06-11 12:28:08 +00:00
// Edge case. We host a public forum that was originally posted to privately.
// The original author commented, but as this is a comment, the permissions
// weren't fixed up so it will still show the comment as private unless we fix it here.
2012-10-08 01:44:06 +00:00
if((intval($r[0]['item_flags']) & ITEM_UPLINK) && (! $r[0]['item_private']))
$arr['item_private'] = 0;
}
else {
logger('item_store: item parent was not found - ignoring item');
$ret['message'] = 'parent not found.';
return $ret;
}
}
2010-07-19 03:49:10 +00:00
2012-10-06 08:17:25 +00:00
if($parent_deleted)
$arr['item_restrict'] = $arr['item_restrict'] | ITEM_DELETED;
$r = q("SELECT `id` FROM `item` WHERE `mid` = '%s' AND `uid` = %d LIMIT 1",
dbesc($arr['mid']),
2011-10-12 09:21:18 +00:00
intval($arr['uid'])
);
if($r) {
logger('item_store: duplicate item ignored. ' . print_r($arr,true));
$ret['message'] = 'duplicate post.';
return $ret;
}
2011-08-08 00:29:26 +00:00
2014-04-26 04:12:43 +00:00
call_hooks('item_store',$arr);
// This hook remains for backward compatibility.
call_hooks('post_remote',$arr);
if(x($arr,'cancel')) {
logger('item_store: post cancelled by plugin.');
$ret['message'] = 'cancelled.';
return $ret;
}
2012-07-11 11:29:47 +00:00
// pull out all the taxonomy stuff for separate storage
$terms = null;
if(array_key_exists('term',$arr)) {
2012-07-11 11:29:47 +00:00
$terms = $arr['term'];
unset($arr['term']);
}
logger('item_store: ' . print_r($arr,true), LOGGER_DATA);
dbesc_array($arr);
$r = dbq("INSERT INTO `item` (`"
2010-07-19 03:49:10 +00:00
. implode("`, `", array_keys($arr))
. "`) VALUES ('"
. implode("', '", array_values($arr))
. "')" );
// find the item we just created
2010-07-19 03:49:10 +00:00
2013-09-11 06:25:56 +00:00
$r = q("SELECT * FROM `item` WHERE `mid` = '%s' AND `uid` = %d ORDER BY `id` ASC ",
$arr['mid'], // already dbesc'd
2010-07-19 03:49:10 +00:00
intval($arr['uid'])
);
2013-09-11 06:25:56 +00:00
2012-10-08 07:23:43 +00:00
if($r && count($r)) {
2010-07-19 03:49:10 +00:00
$current_post = $r[0]['id'];
$arr = $r[0]; // This will gives us a fresh copy of what's now in the DB and undo the db escaping, which really messes up the notifications
2012-10-08 07:23:43 +00:00
logger('item_store: created item ' . $current_post, LOGGER_DEBUG);
}
else {
logger('item_store: could not locate stored item');
$ret['message'] = 'unable to retrieve.';
return $ret;
2010-09-09 03:14:17 +00:00
}
2011-10-12 09:21:18 +00:00
if(count($r) > 1) {
logger('item_store: duplicated post occurred. Removing duplicates.');
q("DELETE FROM `item` WHERE `mid` = '%s' AND `uid` = %d AND `id` != %d ",
$arr['mid'],
2011-10-12 09:21:18 +00:00
intval($arr['uid']),
intval($current_post)
);
}
2010-07-19 03:49:10 +00:00
if((! $parent_id) || ($arr['parent_mid'] === $arr['mid']))
$parent_id = $current_post;
2011-02-04 21:37:04 +00:00
2014-08-07 02:24:46 +00:00
if(strlen($allow_cid) || strlen($allow_gid) || strlen($deny_cid) || strlen($deny_gid) || strlen($public_policy))
$private = 1;
else
$private = $arr['item_private'];
// Set parent id - and also make sure to inherit the parent's ACL's.
$r = q("UPDATE item SET parent = %d, allow_cid = '%s', allow_gid = '%s',
deny_cid = '%s', deny_gid = '%s', public_policy = '%s', item_private = %d, comments_closed = '%s'
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
WHERE id = %d",
2010-07-19 03:49:10 +00:00
intval($parent_id),
dbesc($allow_cid),
dbesc($allow_gid),
dbesc($deny_cid),
dbesc($deny_gid),
2014-08-07 02:24:46 +00:00
dbesc($public_policy),
intval($private),
dbesc($comments_closed),
2010-07-19 03:49:10 +00:00
intval($current_post)
);
// These are probably redundant now that we've queried the just stored post
2012-10-08 07:23:43 +00:00
$arr['id'] = $current_post;
$arr['parent'] = $parent_id;
2012-07-11 11:29:47 +00:00
$arr['allow_cid'] = $allow_cid;
$arr['allow_gid'] = $allow_gid;
2012-10-08 07:23:43 +00:00
$arr['deny_cid'] = $deny_cid;
$arr['deny_gid'] = $deny_gid;
2014-08-07 02:24:46 +00:00
$arr['public_policy'] = $public_policy;
$arr['item_private'] = $private;
$arr['comments_closed'] = $comments_closed;
2012-10-08 07:23:43 +00:00
// Store taxonomy
2013-02-11 08:20:14 +00:00
2012-07-11 11:29:47 +00:00
if(($terms) && (is_array($terms))) {
foreach($terms as $t) {
q("insert into term (uid,oid,otype,type,term,url)
values(%d,%d,%d,%d,'%s','%s') ",
intval($arr['uid']),
intval($current_post),
2013-02-11 08:20:14 +00:00
intval(TERM_OBJ_POST),
2012-07-11 11:29:47 +00:00
intval($t['type']),
dbesc($t['term']),
dbesc($t['url'])
);
}
$arr['term'] = $terms;
}
call_hooks('post_remote_end',$arr);
2011-09-19 02:04:11 +00:00
// update the commented timestamp on the parent
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$z = q("select max(created) as commented from item where parent_mid = '%s' and uid = %d and not ( item_restrict & %d )>0 ",
dbesc($arr['parent_mid']),
intval($arr['uid']),
intval(ITEM_DELAYED_PUBLISH)
);
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
q("UPDATE item set commented = '%s', changed = '%s' WHERE id = %d",
2013-11-18 04:09:40 +00:00
dbesc(($z) ? $z[0]['commented'] : (datetime_convert())),
dbesc(datetime_convert()),
intval($parent_id)
);
2013-02-07 04:29:17 +00:00
send_status_notifications($current_post,$arr);
2012-02-10 05:18:50 +00:00
tag_deliver($arr['uid'],$current_post);
$ret['success'] = true;
$ret['item_id'] = $current_post;
2011-11-16 04:30:34 +00:00
return $ret;
2010-07-19 03:49:10 +00:00
}
2013-02-07 04:29:17 +00:00
function item_store_update($arr,$allow_exec = false) {
2013-11-29 02:10:04 +00:00
$d = array('item' => $arr, 'allow_exec' => $allow_exec);
call_hooks('item_store_update', $d );
$arr = $d['item'];
$allow_exec = $d['allow_exec'];
$ret = array('success' => false, 'item_id' => 0);
if(! intval($arr['uid'])) {
logger('item_store_update: no uid');
$ret['message'] = 'no uid.';
return $ret;
}
if(! intval($arr['id'])) {
logger('item_store_update: no id');
$ret['message'] = 'no id.';
return $ret;
}
$orig_post_id = $arr['id'];
$uid = $arr['uid'];
$orig = q("select * from item where id = %d and uid = %d limit 1",
intval($orig_post_id),
intval($uid)
);
if(! $orig) {
logger('item_store_update: original post not found: ' . $orig_post_id);
$ret['message'] = 'no original';
return $ret;
}
// override the unseen flag with the original
if($arr['item_flags'] & ITEM_UNSEEN)
$arr['item_flags'] = $arr['item_flags'] ^ ITEM_UNSEEN;
if($orig[0]['item_flags'] & ITEM_VERIFIED)
$orig[0]['item_flags'] = $orig[0]['item_flags'] ^ ITEM_VERIFIED;
if($orig[0]['item_flags'] & ITEM_OBSCURED)
$orig[0]['item_flags'] = $orig[0]['item_flags'] ^ ITEM_OBSCURED;
$arr['item_flags'] = intval($arr['item_flags']) | $orig[0]['item_flags'];
$arr['item_restrict'] = intval($arr['item_restrict']) | $orig[0]['item_restrict'];
if(array_key_exists('edit',$arr))
unset($arr['edit']);
$arr['mimetype'] = ((x($arr,'mimetype')) ? notags(trim($arr['mimetype'])) : 'text/bbcode');
if(($arr['mimetype'] == 'application/x-php') && (! $allow_exec)) {
logger('item_store: php mimetype but allow_exec is denied.');
$ret['message'] = 'exec denied.';
return $ret;
}
2013-10-03 04:04:48 +00:00
if(! ($arr['item_flags'] & ITEM_OBSCURED)) {
2013-10-03 04:04:48 +00:00
$arr['lang'] = detect_language($arr['body']);
// apply the input filter here - if it is obscured it has been filtered already
$arr['body'] = z_input_filter($arr['uid'],$arr['body'],$arr['mimetype']);
2013-10-03 04:04:48 +00:00
if(local_user() && (! $arr['sig'])) {
$channel = get_app()->get_channel();
if($channel['channel_hash'] === $arr['author_xchan']) {
$arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey']));
$arr['item_flags'] |= ITEM_VERIFIED;
}
}
2013-10-03 04:04:48 +00:00
$allowed_languages = get_pconfig($arr['uid'],'system','allowed_languages');
if((is_array($allowed_languages)) && ($arr['lang']) && (! array_key_exists($arr['lang'],$allowed_languages))) {
$translate = array('item' => $arr, 'from' => $arr['lang'], 'to' => $allowed_languages, 'translated' => false);
call_hooks('item_translate', $translate);
if((! $translate['translated']) && (intval(get_pconfig($arr['uid'],'system','reject_disallowed_languages')))) {
logger('item_store: language ' . $arr['lang'] . ' not accepted for uid ' . $arr['uid']);
$ret['message'] = 'language not accepted';
return $ret;
}
$arr = $translate['item'];
}
2013-10-03 04:04:48 +00:00
if($arr['item_private']) {
$key = get_config('system','pubkey');
$arr['item_flags'] = $arr['item_flags'] | ITEM_OBSCURED;
if($arr['title'])
$arr['title'] = json_encode(crypto_encapsulate($arr['title'],$key));
2013-10-03 04:04:48 +00:00
if($arr['body'])
$arr['body'] = json_encode(crypto_encapsulate($arr['body'],$key));
2013-10-03 04:04:48 +00:00
}
2013-10-03 04:04:48 +00:00
}
2013-10-03 04:04:48 +00:00
if((x($arr,'object')) && is_array($arr['object'])) {
activity_sanitise($arr['object']);
$arr['object'] = json_encode($arr['object']);
}
if((x($arr,'target')) && is_array($arr['target'])) {
activity_sanitise($arr['target']);
$arr['target'] = json_encode($arr['target']);
}
if((x($arr,'attach')) && is_array($arr['attach'])) {
activity_sanitise($arr['attach']);
$arr['attach'] = json_encode($arr['attach']);
}
2013-10-03 04:04:48 +00:00
unset($arr['id']);
unset($arr['uid']);
unset($arr['aid']);
unset($arr['mid']);
unset($arr['parent']);
unset($arr['parent_mid']);
unset($arr['created']);
unset($arr['author_xchan']);
unset($arr['owner_xchan']);
unset($arr['thr_parent']);
unset($arr['llink']);
$arr['edited'] = ((x($arr,'edited') !== false) ? datetime_convert('UTC','UTC',$arr['edited']) : datetime_convert());
2014-06-14 23:35:38 +00:00
$arr['expires'] = ((x($arr,'expires') !== false) ? datetime_convert('UTC','UTC',$arr['expires']) : $orig[0]['expires']);
if(array_key_exists('comments_closed',$arr) && $arr['comments_closed'] != NULL_DATE)
$arr['comments_closed'] = datetime_convert('UTC','UTC',$arr['comments_closed']);
else
$arr['comments_closed'] = $orig[0]['comments_closed'];
$arr['commented'] = $orig[0]['commented'];
$arr['received'] = datetime_convert();
$arr['changed'] = datetime_convert();
2014-10-10 21:45:18 +00:00
$arr['route'] = ((array_key_exists('route',$arr)) ? trim($arr['route']) : $orig[0]['route']);
$arr['diaspora_meta'] = ((x($arr,'diaspora_meta')) ? $arr['diaspora_meta'] : $orig[0]['diaspora_meta']);
$arr['location'] = ((x($arr,'location')) ? notags(trim($arr['location'])) : $orig[0]['location']);
$arr['coord'] = ((x($arr,'coord')) ? notags(trim($arr['coord'])) : $orig[0]['coord']);
$arr['verb'] = ((x($arr,'verb')) ? notags(trim($arr['verb'])) : $orig[0]['verb']);
$arr['obj_type'] = ((x($arr,'obj_type')) ? notags(trim($arr['obj_type'])) : $orig[0]['obj_type']);
$arr['object'] = ((x($arr,'object')) ? trim($arr['object']) : $orig[0]['object']);
$arr['tgt_type'] = ((x($arr,'tgt_type')) ? notags(trim($arr['tgt_type'])) : $orig[0]['tgt_type']);
$arr['target'] = ((x($arr,'target')) ? trim($arr['target']) : $orig[0]['target']);
$arr['plink'] = ((x($arr,'plink')) ? notags(trim($arr['plink'])) : $orig[0]['plink']);
2014-06-14 23:35:38 +00:00
$arr['allow_cid'] = ((array_key_exists('allow_cid',$arr)) ? trim($arr['allow_cid']) : $orig[0]['allow_cid']);
$arr['allow_gid'] = ((array_key_exists('allow_gid',$arr)) ? trim($arr['allow_gid']) : $orig[0]['allow_gid']);
$arr['deny_cid'] = ((array_key_exists('deny_cid',$arr)) ? trim($arr['deny_cid']) : $orig[0]['deny_cid']);
$arr['deny_gid'] = ((array_key_exists('deny_gid',$arr)) ? trim($arr['deny_gid']) : $orig[0]['deny_gid']);
$arr['item_private'] = ((array_key_exists('item_private',$arr)) ? intval($arr['item_private']) : $orig[0]['item_private']);
$arr['title'] = ((array_key_exists('title',$arr) && strlen($arr['title'])) ? trim($arr['title']) : '');
$arr['body'] = ((array_key_exists('body',$arr) && strlen($arr['body'])) ? trim($arr['body']) : '');
$arr['attach'] = ((x($arr,'attach')) ? notags(trim($arr['attach'])) : $orig[0]['attach']);
$arr['app'] = ((x($arr,'app')) ? notags(trim($arr['app'])) : $orig[0]['app']);
// $arr['item_restrict'] = ((x($arr,'item_restrict')) ? intval($arr['item_restrict']) : $orig[0]['item_restrict'] );
// $arr['item_flags'] = ((x($arr,'item_flags')) ? intval($arr['item_flags']) : $orig[0]['item_flags'] );
$arr['sig'] = ((x($arr,'sig')) ? $arr['sig'] : '');
$arr['layout_mid'] = ((array_key_exists('layout_mid',$arr)) ? dbesc($arr['layout_mid']) : $orig[0]['layout_mid'] );
$arr['public_policy'] = ((x($arr,'public_policy')) ? notags(trim($arr['public_policy'])) : $orig[0]['public_policy'] );
$arr['comment_policy'] = ((x($arr,'comment_policy')) ? notags(trim($arr['comment_policy'])) : $orig[0]['comment_policy'] );
call_hooks('post_remote_update',$arr);
if(x($arr,'cancel')) {
logger('item_store_update: post cancelled by plugin.');
$ret['message'] = 'cancelled.';
return $ret;
}
// pull out all the taxonomy stuff for separate storage
$terms = null;
if(array_key_exists('term',$arr)) {
$terms = $arr['term'];
unset($arr['term']);
}
dbesc_array($arr);
logger('item_store_update: ' . print_r($arr,true), LOGGER_DATA);
$str = '';
foreach($arr as $k => $v) {
if($str)
$str .= ",";
$str .= " `" . $k . "` = '" . $v . "' ";
}
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$r = dbq("update `item` set " . $str . " where id = " . $orig_post_id );
if($r)
logger('item_store_update: updated item ' . $orig_post_id, LOGGER_DEBUG);
else {
logger('item_store_update: could not update item');
$ret['message'] = 'DB update failed.';
return $ret;
}
$r = q("delete from term where oid = %d and otype = %d",
intval($orig_post_id),
intval(TERM_OBJ_POST)
);
if(($terms) && (is_array($terms))) {
foreach($terms as $t) {
q("insert into term (uid,oid,otype,type,term,url)
values(%d,%d,%d,%d,'%s','%s') ",
intval($uid),
intval($orig_post_id),
intval(TERM_OBJ_POST),
intval($t['type']),
dbesc($t['term']),
dbesc($t['url'])
);
}
$arr['term'] = $terms;
}
call_hooks('post_remote_update_end',$arr);
send_status_notifications($orig_post_id,$arr);
tag_deliver($uid,$orig_post_id);
$ret['success'] = true;
$ret['item_id'] = $orig_post_id;
return $ret;
}
function store_diaspora_comment_sig($datarray, $channel, $parent_item, $post_id, $walltowall = false) {
2014-08-30 00:31:40 +00:00
// We won't be able to sign Diaspora comments for authenticated visitors
// - we don't have their private key
// since Diaspora doesn't handle edits we can only do this for the original text and not update it.
require_once('include/bb2diaspora.php');
$signed_body = bb2diaspora_itembody($datarray,$walltowall);
2014-08-30 00:31:40 +00:00
if($walltowall) {
logger('wall to wall comment',LOGGER_DEBUG);
// post will come across with the owner's identity. Throw a preamble onto the post to indicate the true author.
$signed_body = "\n\n"
. '![' . $datarray['author']['xchan_name'] . '](' . $datarray['author']['xchan_photo_m'] . ')'
. '[' . $datarray['author']['xchan_name'] . '](' . $datarray['author']['xchan_url'] . ')' . "\n\n"
. $signed_body;
}
logger('storing diaspora comment signature',LOGGER_DEBUG);
2014-08-30 00:31:40 +00:00
$diaspora_handle = $channel['channel_address'] . '@' . get_app()->get_hostname();
$signed_text = $datarray['mid'] . ';' . $parent_item['mid'] . ';' . $signed_body . ';' . $diaspora_handle;
if( $uprvkey !== false )
$authorsig = base64_encode(rsa_sign($signed_text,$channel['channel_prvkey'],'sha256'));
else
$authorsig = '';
$x = array('signer' => $diaspora_handle, 'body' => $signed_body, 'signed_text' => $signed_text, 'signature' => base64_encode($authorsig));
$key = get_config('system','pubkey');
$y = crypto_encapsulate(json_encode($x),$key);
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$r = q("update item set diaspora_meta = '%s' where id = %d",
dbesc(json_encode($y)),
intval($post_id)
);
2014-08-30 00:31:40 +00:00
if(! $r)
logger('store_diaspora_comment_sig: DB write failed');
return;
}
2013-02-07 04:29:17 +00:00
function send_status_notifications($post_id,$item) {
$notify = false;
$parent = 0;
$r = q("select channel_hash from channel where channel_id = %d limit 1",
intval($item['uid'])
);
if(! $r)
return;
// my own post - no notification needed
if($item['author_xchan'] === $r[0]['channel_hash'])
return;
// I'm the owner - notify me
if($item['owner_hash'] === $r[0]['channel_hash'])
$notify = true;
// Was I involved in this conversation?
$x = q("select * from item where parent_mid = '%s' and uid = %d",
dbesc($item['parent_mid']),
2013-02-07 04:29:17 +00:00
intval($item['uid'])
);
if($x) {
foreach($x as $xx) {
if($xx['author_xchan'] === $r[0]['channel_hash']) {
$notify = true;
}
if($xx['id'] == $xx['parent']) {
$parent = $xx['parent'];
2013-02-07 04:29:17 +00:00
}
}
}
$link = get_app()->get_baseurl() . '/display/' . $item['mid'];
$y = q("select id from notify where link = '%s' and uid = %d limit 1",
dbesc($link),
intval($item['uid'])
);
if($y)
$notify = false;
2013-02-07 04:29:17 +00:00
if(! $notify)
return;
require_once('include/enotify.php');
notification(array(
'type' => NOTIFY_COMMENT,
'from_xchan' => $item['author_xchan'],
'to_xchan' => $r[0]['channel_hash'],
'item' => $item,
'link' => $link,
2013-02-07 04:29:17 +00:00
'verb' => ACTIVITY_POST,
'otype' => 'item',
'parent' => $parent,
'parent_mid' => $item['parent_mid']
2013-02-07 04:29:17 +00:00
));
return;
}
function get_item_contact($item,$contacts) {
if(! count($contacts) || (! is_array($item)))
return false;
foreach($contacts as $contact) {
if($contact['id'] == $item['contact-id']) {
return $contact;
break; // NOTREACHED
}
}
return false;
}
2012-02-10 05:18:50 +00:00
function tag_deliver($uid,$item_id) {
2011-11-16 04:30:34 +00:00
// Called when we deliver things that might be tagged in ways that require delivery processing.
// Handles community tagging of posts and also look for mention tags
// and sets up a second delivery chain if appropriate
2011-11-16 04:30:34 +00:00
$a = get_app();
2012-02-10 05:18:50 +00:00
$mention = false;
2011-11-16 04:30:34 +00:00
2014-08-20 04:31:33 +00:00
/**
* Fetch stuff we need - a channel and an item
*/
2012-10-08 07:23:43 +00:00
$u = q("select * from channel where channel_id = %d limit 1",
2012-02-10 05:18:50 +00:00
intval($uid)
2011-11-16 04:30:34 +00:00
);
2013-02-11 08:20:14 +00:00
if(! $u)
2011-11-16 04:30:34 +00:00
return;
2012-10-08 07:23:43 +00:00
2011-11-19 11:13:46 +00:00
$i = q("select * from item where id = %d and uid = %d limit 1",
2011-11-16 04:30:34 +00:00
intval($item_id),
intval($uid)
);
if(! $i)
2011-11-16 04:30:34 +00:00
return;
2013-01-13 02:06:34 +00:00
$i = fetch_post_tags($i);
2011-11-16 04:30:34 +00:00
$item = $i[0];
if(($item['source_xchan']) && ($item['item_flags'] & ITEM_UPLINK)
&& ($item['item_flags'] & ITEM_THREAD_TOP) && ($item['edited'] != $item['created'])) {
// this is an update (edit) to a post which was already processed by us and has a second delivery chain
// Just start the second delivery chain to deliver the updated post
proc_run('php','include/notifier.php','tgroup',$item['id']);
return;
}
2014-08-20 04:31:33 +00:00
/**
* Seems like a good place to plug in a poke notification.
*/
2014-06-05 05:15:52 +00:00
if (stristr($item['verb'],ACTIVITY_POKE)) {
$poke_notify = true;
if(($item['obj_type'] == "") || ($item['obj_type'] !== ACTIVITY_OBJ_PERSON) || (! $item['object']))
$poke_notify = false;
$obj = json_decode_plus($item['object']);
if($obj) {
if($obj['id'] !== $u[0]['channel_hash'])
$poke_notify = false;
}
$verb = urldecode(substr($item['verb'],strpos($item['verb'],'#')+1));
if($poke_notify) {
require_once('include/enotify.php');
notification(array(
'to_xchan' => $u[0]['channel_hash'],
'from_xchan' => $item['author_xchan'],
'type' => NOTIFY_POKE,
'item' => $item,
'link' => $i[0]['llink'],
'verb' => ACTIVITY_POKE,
'activity' => $verb,
'otype' => 'item'
));
}
}
2014-08-20 04:31:33 +00:00
/**
* Do community tagging
*/
if($item['obj_type'] === ACTIVITY_OBJ_TAGTERM) {
// We received a community tag activity for a post.
// See if we are the owner of the parent item and have given permission to tag our posts.
// If so tag the parent post.
2013-06-21 04:19:22 +00:00
logger('tag_deliver: community tag activity received');
if(($item['owner_xchan'] === $u[0]['channel_hash']) && (! get_pconfig($u[0]['channel_id'],'system','blocktags'))) {
logger('tag_deliver: community tag recipient: ' . $u[0]['channel_name']);
$j_tgt = json_decode_plus($item['target']);
2013-06-21 04:19:22 +00:00
if($j_tgt && $j_tgt['id']) {
$p = q("select * from item where mid = '%s' and uid = %d limit 1",
2013-06-21 04:19:22 +00:00
dbesc($j_tgt['id']),
intval($u[0]['channel_id'])
);
if($p) {
$j_obj = json_decode_plus($item['object']);
2013-06-21 04:19:22 +00:00
logger('tag_deliver: tag object: ' . print_r($j_obj,true), LOGGER_DATA);
if($j_obj && $j_obj['id'] && $j_obj['title']) {
2013-07-01 06:04:27 +00:00
if(is_array($j_obj['link']))
$taglink = get_rel_link($j_obj['link'],'alternate');
2013-07-01 06:04:27 +00:00
store_item_tag($u[0]['channel_id'],$p[0]['id'],TERM_OBJ_POST,TERM_HASHTAG,$j_obj['title'],$j_obj['id']);
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$x = q("update item set edited = '%s', received = '%s', changed = '%s' where mid = '%s' and uid = %d",
dbesc(datetime_convert()),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
dbesc($j_tgt['id']),
intval($u[0]['channel_id'])
);
proc_run('php','include/notifier.php','edit_post',$p[0]['id']);
}
}
}
}
2013-06-21 04:19:22 +00:00
else
logger('tag_deliver: tag permission denied for ' . $u[0]['channel_address']);
}
2014-08-20 04:31:33 +00:00
/**
* A "union" is a message which our channel has sourced from another channel.
* This sets up a second delivery chain just like forum tags do.
* Find out if this is a source-able post.
*/
2013-09-27 02:34:45 +00:00
$union = check_item_source($uid,$item);
if($union)
logger('check_item_source returns true');
// This might be a followup (e.g. comment) by the original post author to a tagged forum
// If so setup a second delivery chain
if( ! ($item['item_flags'] & ITEM_THREAD_TOP)) {
$x = q("select * from item where id = parent and parent = %d and uid = %d limit 1",
intval($item['parent']),
intval($uid)
);
if(($x) && ($x[0]['item_flags'] & ITEM_UPLINK)) {
start_delivery_chain($u[0],$item,$item_id,$x[0]);
}
}
2014-08-20 04:31:33 +00:00
/**
* Now we've got those out of the way. Let's see if this is a post that's tagged for re-delivery
*/
2013-01-13 02:06:34 +00:00
$terms = get_terms_oftype($item['term'],TERM_MENTION);
if($terms)
logger('tag_deliver: post mentions: ' . print_r($terms,true), LOGGER_DATA);
2013-01-13 02:06:34 +00:00
2013-02-11 07:19:52 +00:00
$link = normalise_link($a->get_baseurl() . '/channel/' . $u[0]['channel_address']);
2011-11-16 04:30:34 +00:00
2013-01-13 02:06:34 +00:00
if($terms) {
foreach($terms as $term) {
if(link_compare($term['url'],$link)) {
2012-02-10 05:18:50 +00:00
$mention = true;
2013-01-13 02:06:34 +00:00
break;
2011-11-16 04:30:34 +00:00
}
}
2013-01-13 02:06:34 +00:00
}
2011-11-16 04:30:34 +00:00
2013-01-13 02:06:34 +00:00
if($mention) {
2013-02-11 07:19:52 +00:00
logger('tag_deliver: mention found for ' . $u[0]['channel_name']);
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$r = q("update item set item_flags = ( item_flags | %d ) where id = %d",
2013-01-13 02:06:34 +00:00
intval(ITEM_MENTIONSME),
intval($item_id)
);
2011-11-16 04:30:34 +00:00
2013-09-27 02:34:45 +00:00
// At this point we've determined that the person receiving this post was mentioned in it or it is a union.
// Now let's check if this mention was inside a reshare so we don't spam a forum
// If it's private we may have to unobscure it momentarily so that we can parse it.
$body = '';
if($item['item_flags'] & ITEM_OBSCURED) {
$key = get_config('system','prvkey');
if($item['body'])
$body = crypto_unencapsulate(json_decode_plus($item['body']),$key);
}
else
$body = $item['body'];
$body = preg_replace('/\[share(.*?)\[\/share\]/','',$body);
$tagged = false;
$plustagged = false;
$pattern = '/@\!?\[zrl\=' . preg_quote($term['url'],'/') . '\]' . preg_quote($term['term'],'/') . '\[\/zrl\]/';
if(preg_match($pattern,$body,$matches))
$tagged = true;
$pattern = '/@\!?\[zrl\=' . preg_quote($term['url'],'/') . '\]' . preg_quote($term['term'] . '+','/') . '\[\/zrl\]/';
if(preg_match($pattern,$body,$matches))
$plustagged = true;
2013-02-11 23:51:43 +00:00
if(! ($tagged || $plustagged)) {
2013-09-27 02:34:45 +00:00
logger('tag_deliver: mention was in a reshare - ignoring');
return;
}
2014-04-26 04:12:43 +00:00
$arr = array('channel_id' => $uid, 'item' => $item, 'body' => $body);
call_hooks('tagged',$arr);
2014-08-20 04:31:33 +00:00
/**
* Kill two birds with one stone. As long as we're here, send a mention notification.
*/
2013-09-27 02:34:45 +00:00
require_once('include/enotify.php');
notification(array(
'to_xchan' => $u[0]['channel_hash'],
'from_xchan' => $item['author_xchan'],
'type' => NOTIFY_TAGSELF,
'item' => $item,
'link' => $i[0]['llink'],
'verb' => ACTIVITY_TAG,
'otype' => 'item'
));
// Just a normal tag?
if(! $plustagged) {
logger('tag_deliver: not a plus tag', LOGGER_DEBUG);
return;
}
// plustagged - keep going, next check permissions
2013-01-13 02:06:34 +00:00
2013-09-27 02:34:45 +00:00
if(! perm_is_allowed($uid,$item['author_xchan'],'tag_deliver')) {
logger('tag_delivery denied for uid ' . $uid . ' and xchan ' . $item['author_xchan']);
return;
}
2013-08-06 04:42:55 +00:00
}
if((! $mention) && (! $union)) {
logger('tag_deliver: no mention and no union.');
2013-09-27 02:34:45 +00:00
return;
}
2013-09-27 02:34:45 +00:00
// tgroup delivery - setup a second delivery chain
// prevent delivery looping - only proceed
// if the message originated elsewhere and is a top-level post
if(($item['item_flags'] & ITEM_WALL)
|| ($item['item_flags'] & ITEM_ORIGIN)
|| (!($item['item_flags'] & ITEM_THREAD_TOP))
|| ($item['id'] != $item['parent'])) {
2013-08-06 04:42:55 +00:00
logger('tag_deliver: item was local or a comment. rejected.');
return;
2013-08-06 04:42:55 +00:00
}
2011-11-16 04:30:34 +00:00
2013-02-12 00:59:48 +00:00
logger('tag_deliver: creating second delivery chain.');
start_delivery_chain($u[0],$item,$item_id,null);
2011-11-16 04:30:34 +00:00
}
2014-08-20 04:31:33 +00:00
/**
* @function tgroup_check($uid,$item)
*
* This function is called pre-deliver to see if a post matches the criteria to be tag delivered.
* We don't actually do anything except check that it matches the criteria.
* This is so that the channel with tag_delivery enabled can receive the post even if they turn off
* permissions for the sender to send their stream. tag_deliver() can't be called until the post is actually stored.
* By then it would be too late to reject it.
*/
2011-11-16 04:30:34 +00:00
function tgroup_check($uid,$item) {
$a = get_app();
$mention = false;
// check that the message originated elsewhere and is a top-level post
// or is a followup and we have already accepted the top level post as an uplink
if($item['mid'] != $item['parent_mid']) {
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$r = q("select id from item where mid = '%s' and uid = %d and ( item_flags & %d )>0 limit 1",
dbesc($item['parent_mid']),
intval($uid),
intval(ITEM_UPLINK)
);
if($r)
return true;
return false;
}
if(! perm_is_allowed($uid,$item['author_xchan'],'tag_deliver'))
return false;
$u = q("select * from channel where channel_id = %d limit 1",
intval($uid)
);
if(! $u)
return false;
$terms = get_terms_oftype($item['term'],TERM_MENTION);
if($terms)
logger('tgroup_check: post mentions: ' . print_r($terms,true), LOGGER_DATA);
$link = normalise_link($a->get_baseurl() . '/channel/' . $u[0]['channel_address']);
if($terms) {
foreach($terms as $term) {
if(link_compare($term['url'],$link)) {
$mention = true;
break;
}
}
}
if($mention) {
logger('tgroup_check: mention found for ' . $u[0]['channel_name']);
}
else
return false;
// At this point we've determined that the person receiving this post was mentioned in it.
// Now let's check if this mention was inside a reshare so we don't spam a forum
$body = $item['body'];
if(array_key_exists('item_flags',$item) && ($item['item_flags'] & ITEM_OBSCURED) && $body) {
$key = get_config('system','prvkey');
$body = crypto_unencapsulate(json_decode($body,true),$key);
}
$body = preg_replace('/\[share(.*?)\[\/share\]/','',$body);
$pattern = '/@\!?\[zrl\=' . preg_quote($term['url'],'/') . '\]' . preg_quote($term['term'] . '+','/') . '\[\/zrl\]/';
if(! preg_match($pattern,$body,$matches)) {
logger('tgroup_check: mention was in a reshare - ignoring');
return false;
}
return true;
}
/**
* Sourced and tag-delivered posts are re-targetted for delivery to the connections of the channel
* receiving the post. This starts the second delivery chain, by resetting permissions and ensuring
* that ITEM_UPLINK is set on the parent post, and storing the current owner_xchan as the source_xchan.
* We'll become the new owner. If called without $parent, this *is* the parent post.
*/
function start_delivery_chain($channel,$item,$item_id,$parent) {
// Change this copy of the post to a forum head message and deliver to all the tgroup members
// also reset all the privacy bits to the forum default permissions
$private = (($channel['channel_allow_cid'] || $channel['channel_allow_gid']
|| $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 1 : 0);
$new_public_policy = map_scope($channel['channel_r_stream'],true);
if((! $private) && $new_public_policy)
$private = 1;
$flag_bits = $item['item_flags'] | ITEM_WALL|ITEM_ORIGIN;
// unset the nocomment bit if it's there.
if($flag_bits & ITEM_NOCOMMENT)
$flag_bits = $flag_bits ^ ITEM_NOCOMMENT;
// maintain the original source, which will be the original item owner and was stored in source_xchan
// when we created the delivery fork
if($parent) {
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$r = q("update item set source_xchan = '%s' where id = %d",
dbesc($parent['source_xchan']),
intval($item_id)
);
}
else {
$flag_bits = $flag_bits | ITEM_UPLINK;
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$r = q("update item set source_xchan = owner_xchan where id = %d",
intval($item_id)
);
}
$title = $item['title'];
$body = $item['body'];
if($private) {
if(!($flag_bits & ITEM_OBSCURED)) {
$key = get_config('system','pubkey');
$flag_bits = $flag_bits|ITEM_OBSCURED;
2014-08-23 00:34:18 +00:00
if($title)
$title = json_encode(crypto_encapsulate($title,$key));
2014-08-23 00:34:18 +00:00
if($body)
$body = json_encode(crypto_encapsulate($body,$key));
}
}
else {
if($flag_bits & ITEM_OBSCURED) {
$key = get_config('system','prvkey');
$flag_bits = $flag_bits ^ ITEM_OBSCURED;
2014-08-23 00:34:18 +00:00
if($title)
$title = crypto_unencapsulate(json_decode($title,true),$key);
if($body)
$body = crypto_unencapsulate(json_decode($body,true),$key);
}
}
$r = q("update item set item_flags = %d, owner_xchan = '%s', allow_cid = '%s', allow_gid = '%s',
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
deny_cid = '%s', deny_gid = '%s', item_private = %d, public_policy = '%s', comment_policy = '%s', title = '%s', body = '%s' where id = %d",
intval($flag_bits),
dbesc($channel['channel_hash']),
dbesc($channel['channel_allow_cid']),
dbesc($channel['channel_allow_gid']),
dbesc($channel['channel_deny_cid']),
dbesc($channel['channel_deny_gid']),
intval($private),
dbesc($new_public_policy),
dbesc(map_scope($channel['channel_w_comment'])),
dbesc($title),
dbesc($body),
intval($item_id)
);
if($r)
proc_run('php','include/notifier.php','tgroup',$item_id);
else
logger('start_delivery_chain: failed to update item');
return;
}
2013-09-27 02:34:45 +00:00
/**
* @function check_item_source($uid,$item)
* @param $uid
* @param $item
*
* @description
* Checks to see if this item owner is referenced as a source for this channel and if the post
* matches the rules for inclusion in this channel. Returns true if we should create a second delivery
* chain and false if none of the rules apply, or if the item is private.
*/
function check_item_source($uid,$item) {
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$r = q("select * from source where src_channel_id = %d and ( src_xchan = '%s' or src_xchan = '*' ) limit 1",
2013-09-27 02:34:45 +00:00
intval($uid),
dbesc(($item['source_xchan']) ? $item['source_xchan'] : $item['owner_xchan'])
2013-09-27 02:34:45 +00:00
);
2013-09-27 02:34:45 +00:00
if(! $r)
return false;
$x = q("select abook_their_perms, abook_flags from abook where abook_channel = %d and abook_xchan = '%s' limit 1",
intval($uid),
dbesc($item['owner_xchan'])
);
if(! $x)
return false;
if(! ($x[0]['abook_their_perms'] & PERMS_A_REPUBLISH))
return false;
if($item['item_private'] && (! ($x[0]['abook_flags'] & ABOOK_FLAG_FEED)))
return false;
2013-09-27 02:34:45 +00:00
if($r[0]['src_channel_xchan'] === $item['owner_xchan'])
return false;
if(! $r[0]['src_patt'])
return true;
require_once('include/html2plain.php');
$text = prepare_text($item['body'],$item['mimetype']);
$text = html2plain($text);
2013-09-27 02:34:45 +00:00
$tags = ((count($items['term'])) ? $items['term'] : false);
$words = explode("\n",$r[0]['src_patt']);
if($words) {
foreach($words as $word) {
if(substr($word,0,1) === '#' && $tags) {
foreach($tags as $t)
if(($t['type'] == TERM_HASHTAG) && ((substr($t,1) === substr($word,1)) || (substr($word,1) === '*')))
2013-09-27 02:34:45 +00:00
return true;
}
if(stristr($text,$word) !== false)
2013-09-27 02:34:45 +00:00
return true;
}
}
return false;
}
2012-12-06 00:44:07 +00:00
function mail_store($arr) {
if(! $arr['channel_id']) {
logger('mail_store: no uid');
return 0;
}
if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false))
$arr['body'] = escape_tags($arr['body']);
if(array_key_exists('attach',$arr) && is_array($arr['attach']))
$arr['attach'] = json_encode($arr['attach']);
2012-12-06 00:44:07 +00:00
$arr['account_id'] = ((x($arr,'account_id')) ? intval($arr['account_id']) : 0);
$arr['mid'] = ((x($arr,'mid')) ? notags(trim($arr['mid'])) : random_string());
2012-12-06 00:44:07 +00:00
$arr['from_xchan'] = ((x($arr,'from_xchan')) ? notags(trim($arr['from_xchan'])) : '');
$arr['to_xchan'] = ((x($arr,'to_xchan')) ? notags(trim($arr['to_xchan'])) : '');
2012-12-06 00:44:07 +00:00
$arr['created'] = ((x($arr,'created') !== false) ? datetime_convert('UTC','UTC',$arr['created']) : datetime_convert());
$arr['expires'] = ((x($arr,'expires') !== false) ? datetime_convert('UTC','UTC',$arr['expires']) : NULL_DATE);
2012-12-06 00:44:07 +00:00
$arr['title'] = ((x($arr,'title')) ? notags(trim($arr['title'])) : '');
$arr['parent_mid'] = ((x($arr,'parent_mid')) ? notags(trim($arr['parent_mid'])) : '');
2012-12-06 00:44:07 +00:00
$arr['body'] = ((x($arr,'body')) ? trim($arr['body']) : '');
2012-12-06 00:44:07 +00:00
$arr['mail_flags'] = ((x($arr,'mail_flags')) ? intval($arr['mail_flags']) : 0 );
2012-12-06 01:11:38 +00:00
if(! $arr['parent_mid']) {
2012-12-06 01:11:38 +00:00
logger('mail_store: missing parent');
$arr['parent_mid'] = $arr['mid'];
2012-12-06 01:11:38 +00:00
}
$r = q("SELECT `id` FROM mail WHERE `mid` = '%s' AND channel_id = %d LIMIT 1",
dbesc($arr['mid']),
2012-12-06 00:44:07 +00:00
intval($arr['channel_id'])
);
if($r) {
logger('mail_store: duplicate item ignored. ' . print_r($arr,true));
return 0;
}
call_hooks('post_mail',$arr);
if(x($arr,'cancel')) {
logger('mail_store: post cancelled by plugin.');
return 0;
}
dbesc_array($arr);
logger('mail_store: ' . print_r($arr,true), LOGGER_DATA);
$r = dbq("INSERT INTO mail (`"
. implode("`, `", array_keys($arr))
. "`) VALUES ('"
. implode("', '", array_values($arr))
. "')" );
// find the item we just created
$r = q("SELECT `id` FROM mail WHERE `mid` = '%s' AND `channel_id` = %d ORDER BY `id` ASC ",
$arr['mid'], // already dbesc'd
2012-12-06 00:44:07 +00:00
intval($arr['channel_id'])
);
if($r) {
$current_post = $r[0]['id'];
logger('mail_store: created item ' . $current_post, LOGGER_DEBUG);
$arr['id'] = $current_post; // for notification
2012-12-06 00:44:07 +00:00
}
else {
logger('mail_store: could not locate created item');
return 0;
}
if(count($r) > 1) {
logger('mail_store: duplicated post occurred. Removing duplicates.');
q("DELETE FROM mail WHERE `mid` = '%s' AND `channel_id` = %d AND `id` != %d ",
$arr['mid'],
2012-12-06 00:44:07 +00:00
intval($arr['channel_id']),
intval($current_post)
);
}
else {
require_once('include/enotify.php');
$notif_params = array(
'from_xchan' => $arr['from_xchan'],
'to_xchan' => $arr['to_xchan'],
'type' => NOTIFY_MAIL,
'item' => $arr,
'verb' => ACTIVITY_POST,
'otype' => 'mail'
);
notification($notif_params);
}
2012-12-06 00:44:07 +00:00
call_hooks('post_mail_end',$arr);
return $current_post;
}
/**
*
* consume_feed - process atom feed and update anything/everything we might need to update
*
* $xml = the (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds.
*
* $importer = the contact_record (joined to user_record) of the local user who owns this relationship.
* It is this person's stuff that is going to be updated.
* $contact = the person who is sending us stuff. If not set, we MAY be processing a "follow" activity
* from an external network and MAY create an appropriate contact record. Otherwise, we MUST
* have a contact record.
2010-12-01 21:39:00 +00:00
* $hub = should we find a hub declation in the feed, pass it back to our calling process, who might (or
* might not) try and subscribe to it.
* $datedir sorts in reverse order
* $pass - by default ($pass = 0) we cannot guarantee that a parent item has been
* imported prior to its children being seen in the stream unless we are certain
* of how the feed is arranged/ordered.
* With $pass = 1, we only pull parent items out of the stream.
* With $pass = 2, we only pull children (comments/likes).
*
* So running this twice, first with pass 1 and then with pass 2 will do the right
* thing regardless of feed ordering. This won't be adequate in a fully-threaded
* model where comments can have sub-threads. That would require some massive sorting
* to get all the feed items into a mostly linear ordering, and might still require
* recursion.
*/
2014-08-20 05:47:11 +00:00
function consume_feed($xml,$importer,&$contact,$pass = 0) {
2010-10-01 02:41:22 +00:00
require_once('library/simplepie/simplepie.inc');
2010-10-01 02:41:22 +00:00
if(! strlen($xml)) {
logger('consume_feed: empty input');
return;
}
2010-10-01 02:41:22 +00:00
$feed = new SimplePie();
$feed->set_raw_data($xml);
$feed->init();
if($feed->error())
logger('consume_feed: Error parsing XML: ' . $feed->error());
2011-04-05 02:36:18 +00:00
$permalink = $feed->get_permalink();
2010-10-01 02:41:22 +00:00
// Check at the feed level for updated contact name and/or photo
2011-02-08 12:25:27 +00:00
// process any deleted entries
2010-10-01 02:41:22 +00:00
2011-02-08 12:25:27 +00:00
$del_entries = $feed->get_feed_tags(NAMESPACE_TOMB, 'deleted-entry');
2011-10-04 10:06:34 +00:00
if(is_array($del_entries) && count($del_entries) && $pass != 2) {
2011-02-08 12:25:27 +00:00
foreach($del_entries as $dentry) {
2010-10-01 02:41:22 +00:00
$deleted = false;
2011-02-08 12:25:27 +00:00
if(isset($dentry['attribs']['']['ref'])) {
$mid = $dentry['attribs']['']['ref'];
2010-10-01 02:41:22 +00:00
$deleted = true;
2011-02-08 12:25:27 +00:00
if(isset($dentry['attribs']['']['when'])) {
$when = $dentry['attribs']['']['when'];
2010-10-01 02:41:22 +00:00
$when = datetime_convert('UTC','UTC', $when, 'Y-m-d H:i:s');
}
else
$when = datetime_convert('UTC','UTC','now','Y-m-d H:i:s');
}
2014-08-20 04:31:33 +00:00
if($deleted && is_array($contact)) {
$r = q("SELECT * from item where mid = '%s' and author_xchan = '%s' and uid = %d limit 1",
dbesc(base64url_encode($mid)),
dbesc($contact['xchan_hash']),
intval($importer['channel_id'])
2010-10-01 02:41:22 +00:00
);
if($r) {
2010-10-01 02:41:22 +00:00
$item = $r[0];
2011-02-08 12:25:27 +00:00
if(! ($item['item_restrict'] & ITEM_DELETED)) {
logger('consume_feed: deleting item ' . $item['id'] . ' mid=' . base64url_decode($item['mid']), LOGGER_DEBUG);
drop_item($item['id'],false);
2010-10-01 02:41:22 +00:00
}
}
}
2011-02-08 12:25:27 +00:00
}
}
// Now process the feed
if($feed->get_item_quantity()) {
2011-02-08 12:25:27 +00:00
logger('consume_feed: feed item count = ' . $feed->get_item_quantity(), LOGGER_DEBUG);
2010-10-01 02:41:22 +00:00
$items = $feed->get_items();
2010-10-01 02:41:22 +00:00
2011-02-08 12:25:27 +00:00
foreach($items as $item) {
$is_reply = false;
$item_id = base64url_encode($item->get_id());
logger('consume_feed: processing ' . $item_id, LOGGER_DEBUG);
2010-10-01 02:41:22 +00:00
$rawthread = $item->get_item_tags( NAMESPACE_THREAD,'in-reply-to');
if(isset($rawthread[0]['attribs']['']['ref'])) {
$is_reply = true;
$parent_mid = base64url_encode($rawthread[0]['attribs']['']['ref']);
2010-10-01 02:41:22 +00:00
}
2013-08-07 10:54:47 +00:00
if($is_reply) {
if($pass == 1)
continue;
2010-10-01 02:41:22 +00:00
// Have we seen it? If not, import it.
$item_id = base64url_encode($item->get_id());
$author = array();
$datarray = get_atom_elements($feed,$item,$author);
if((! x($author,'author_name')) || ($author['author_is_feed']))
$author['author_name'] = $contact['xchan_name'];
if((! x($author,'author_link')) || ($author['author_is_feed']))
$author['author_link'] = $contact['xchan_url'];
if((! x($author,'author_photo'))|| ($author['author_is_feed']))
$author['author_photo'] = $contact['xchan_photo_m'];
$datarray['author_xchan'] = '';
if($author['author_link'] != $contact['xchan_url']) {
2014-09-25 18:47:06 +00:00
$x = import_author_unknown(array('name' => $author['author_name'],'url' => $author['author_link'],'photo' => array('src' => $author['author_photo'])));
if($x)
$datarray['author_xchan'] = $x;
}
if(! $datarray['author_xchan'])
$datarray['author_xchan'] = $contact['xchan_hash'];
$datarray['owner_xchan'] = $contact['xchan_hash'];
$r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1",
2010-10-01 02:41:22 +00:00
dbesc($item_id),
intval($importer['channel_id'])
2010-10-01 02:41:22 +00:00
);
// Update content if 'updated' changes
if($r) {
if((x($datarray,'edited') !== false)
&& (datetime_convert('UTC','UTC',$datarray['edited']) !== $r[0]['edited'])) {
// do not accept (ignore) an earlier edit than one we currently have.
2012-06-12 09:47:05 +00:00
if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited'])
continue;
update_feed_item($importer['channel_id'],$datarray);
}
2010-10-01 02:41:22 +00:00
continue;
}
$datarray['parent_mid'] = $parent_mid;
$datarray['uid'] = $importer['channel_id'];
2011-10-24 11:17:46 +00:00
logger('consume_feed: ' . print_r($datarray,true),LOGGER_DATA);
2014-09-01 03:51:05 +00:00
$xx = item_store($datarray);
$r = $xx['item_id'];
2010-10-01 02:41:22 +00:00
continue;
}
else {
2010-10-01 02:41:22 +00:00
// Head post of a conversation. Have we seen it? If not, import it.
$item_id = base64url_encode($item->get_id());
$author = array();
$datarray = get_atom_elements($feed,$item,$author);
2011-05-06 13:30:33 +00:00
if(is_array($contact)) {
if((! x($author,'author_name')) || ($author['author_is_feed']))
$author['author_name'] = $contact['xchan_name'];
if((! x($author,'author_link')) || ($author['author_is_feed']))
$author['author_link'] = $contact['xchan_url'];
if((! x($author,'author_photo'))|| ($author['author_is_feed']))
$author['author_photo'] = $contact['xchan_photo_m'];
2011-05-06 13:30:33 +00:00
}
if((! x($author,'author_name')) || (! x($author,'author_link'))) {
logger('consume_feed: no author information! ' . print_r($author,true));
continue;
}
$datarray['author_xchan'] = '';
if($author['author_link'] != $contact['xchan_url']) {
$x = import_author_unknown(array('name' => $author['author_name'],'url' => $author['author_link'],'photo' => array('src' => $author['author_photo'])));
if($x)
$datarray['author_xchan'] = $x;
}
if(! $datarray['author_xchan'])
$datarray['author_xchan'] = $contact['xchan_hash'];
$datarray['owner_xchan'] = $contact['xchan_hash'];
2011-06-14 02:06:49 +00:00
$r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1",
2010-10-01 02:41:22 +00:00
dbesc($item_id),
intval($importer['channel_id'])
2010-10-01 02:41:22 +00:00
);
// Update content if 'updated' changes
if($r) {
if((x($datarray,'edited') !== false)
&& (datetime_convert('UTC','UTC',$datarray['edited']) !== $r[0]['edited'])) {
// do not accept (ignore) an earlier edit than one we currently have.
2012-06-12 09:47:05 +00:00
if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited'])
continue;
update_feed_item($importer['channel_id'],$datarray);
}
2010-10-01 02:41:22 +00:00
continue;
}
$datarray['parent_mid'] = $item_id;
$datarray['uid'] = $importer['channel_id'];
if(! link_compare($author['owner_link'],$contact['xchan_url'])) {
logger('consume_feed: Correcting item owner.', LOGGER_DEBUG);
2014-09-01 03:51:05 +00:00
$author['owner_name'] = $contact['name'];
$author['owner_link'] = $contact['url'];
$author['owner_avatar'] = $contact['thumb'];
}
logger('consume_feed: author ' . print_r($author,true),LOGGER_DEBUG);
2014-09-01 03:51:05 +00:00
logger('consume_feed: ' . print_r($datarray,true),LOGGER_DATA);
2014-09-01 03:51:05 +00:00
$xx = item_store($datarray);
$r = $xx['item_id'];
2010-10-01 02:41:22 +00:00
continue;
}
}
}
}
function update_feed_item($uid,$datarray) {
logger('update_feed_item: not implemented! ' . $uid . ' ' . print_r($datarray,true), LOGGER_DATA);
}
2011-10-02 23:18:01 +00:00
2014-08-20 05:47:11 +00:00
function handle_feed($uid,$abook_id,$url) {
require_once('include/Contact.php');
$channel = channelx_by_n($uid);
if(! $channel)
return;
$x = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d limit 1",
dbesc($abook_id),
intval($uid)
);
$recurse = 0;
$z = z_fetch_url($url,false,$recurse,array('novalidate' => true));
2014-09-01 03:51:05 +00:00
//logger('handle_feed:' . print_r($z,true));
2014-08-20 05:47:11 +00:00
if($z['success']) {
consume_feed($z['body'],$channel,$x[0],0);
consume_feed($z['body'],$channel,$x[0],1);
}
}
function atom_author($tag,$name,$uri,$h,$w,$type,$photo) {
2010-11-02 00:56:36 +00:00
$o = '';
if(! $tag)
return $o;
$name = xmlify($name);
$uri = xmlify($uri);
$h = intval($h);
$w = intval($w);
$photo = xmlify($photo);
$o .= "<$tag>\r\n";
$o .= "<name>$name</name>\r\n";
$o .= "<uri>$uri</uri>\r\n";
$o .= '<link rel="photo" type="' . $type . '" media:width="' . $w . '" media:height="' . $h . '" href="' . $photo . '" />' . "\r\n";
$o .= '<link rel="avatar" type="' . $type . '" media:width="' . $w . '" media:height="' . $h . '" href="' . $photo . '" />' . "\r\n";
2010-12-25 02:32:23 +00:00
call_hooks('atom_author', $o);
2010-11-02 00:56:36 +00:00
$o .= "</$tag>\r\n";
return $o;
}
function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) {
2010-11-02 00:56:36 +00:00
2011-05-01 00:24:37 +00:00
$a = get_app();
if(! $item['parent'])
return;
2010-11-02 00:56:36 +00:00
if($item['deleted'])
return '<at:deleted-entry ref="' . xmlify($item['mid']) . '" when="' . xmlify(datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)) . '" />' . "\r\n";
2010-11-02 00:56:36 +00:00
2011-05-01 00:24:37 +00:00
if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid'])
$body = fix_private_photos($item['body'],$owner['uid'],$item,$cid);
2011-05-01 00:24:37 +00:00
else
$body = $item['body'];
2010-11-02 00:56:36 +00:00
2010-11-02 06:42:26 +00:00
$o = "\r\n\r\n<entry>\r\n";
2010-11-02 00:56:36 +00:00
if(is_array($author))
$o .= atom_author('author',$author['xchan_name'],$author['xchan_url'],80,80,$author['xchan_photo_mimetype'],$author['xchan_photo_m']);
2010-11-02 00:56:36 +00:00
else
$o .= atom_author('author',$item['author']['xchan_name'],$item['author']['xchan_url'],80,80,$item['author']['xchan_photo_mimetype'], $item['author']['xchan_photo_m']);
$o .= atom_author('zot:owner',$item['owner']['xchan_name'],$item['owner']['xchan_url'],80,80,$item['owner']['xchan_photo_mimetype'],$item['owner']['xchan_photo_m']);
2010-11-02 00:56:36 +00:00
if(($item['parent'] != $item['id']) || ($item['parent_mid'] !== $item['mid']) || (($item['thr_parent'] !== '') && ($item['thr_parent'] !== $item['mid']))) {
$parent_item = (($item['thr_parent']) ? $item['thr_parent'] : $item['parent_mid']);
$o .= '<thr:in-reply-to ref="' . xmlify($parent_item) . '" type="text/html" href="' . xmlify($item['plink']) . '" />' . "\r\n";
2012-06-23 13:04:56 +00:00
}
2010-11-02 00:56:36 +00:00
$o .= '<id>' . xmlify($item['mid']) . '</id>' . "\r\n";
2010-11-02 00:56:36 +00:00
$o .= '<title>' . xmlify($item['title']) . '</title>' . "\r\n";
$o .= '<published>' . xmlify(datetime_convert('UTC','UTC',$item['created'] . '+00:00',ATOM_TIME)) . '</published>' . "\r\n";
$o .= '<updated>' . xmlify(datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)) . '</updated>' . "\r\n";
2013-09-06 02:31:26 +00:00
$o .= '<content type="' . $type . '" >' . xmlify(prepare_text($body,$item['mimetype'])) . '</content>' . "\r\n";
$o .= '<link rel="alternate" type="text/html" href="' . xmlify($item['plink']) . '" />' . "\r\n";
2010-11-10 04:38:24 +00:00
if($item['location']) {
$o .= '<zot:location>' . xmlify($item['location']) . '</zot:location>' . "\r\n";
2010-11-10 04:38:24 +00:00
$o .= '<poco:address><poco:formatted>' . xmlify($item['location']) . '</poco:formatted></poco:address>' . "\r\n";
}
2010-11-02 00:56:36 +00:00
if($item['coord'])
$o .= '<georss:point>' . xmlify($item['coord']) . '</georss:point>' . "\r\n";
if(($item['item_private']) || strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid']))
$o .= '<zot:private>' . (($item['item_private']) ? $item['item_private'] : 1) . '</zot:private>' . "\r\n";
2011-06-21 02:08:40 +00:00
if($item['app'])
$o .= '<statusnet:notice_info local_id="' . $item['id'] . '" source="' . xmlify($item['app']) . '" ></statusnet:notice_info>' . "\r\n";
2010-11-02 00:56:36 +00:00
$verb = construct_verb($item);
$o .= '<as:verb>' . xmlify($verb) . '</as:verb>' . "\r\n";
$actobj = construct_activity_object($item);
2010-11-02 00:56:36 +00:00
if(strlen($actobj))
$o .= $actobj;
$actarg = construct_activity_target($item);
if(strlen($actarg))
$o .= $actarg;
2010-11-02 00:56:36 +00:00
// FIXME
// $tags = item_getfeedtags($item);
// if(count($tags)) {
// foreach($tags as $t) {
// $o .= '<category scheme="X-DFRN:' . xmlify($t[0]) . ':' . xmlify($t[1]) . '" term="' . xmlify($t[2]) . '" />' . "\r\n";
// }
// }
2011-04-06 00:41:02 +00:00
// FIXME
// $o .= item_getfeedattach($item);
// $mentioned = get_mentions($item,$tags);
// if($mentioned)
// $o .= $mentioned;
2010-11-02 00:56:36 +00:00
2010-12-25 02:32:23 +00:00
call_hooks('atom_entry', $o);
2010-11-02 00:56:36 +00:00
$o .= '</entry>' . "\r\n";
return $o;
}
2011-04-06 00:41:02 +00:00
function fix_private_photos($s, $uid, $item = null, $cid = 0) {
2011-05-01 00:24:37 +00:00
$a = get_app();
logger('fix_private_photos', LOGGER_DEBUG);
$site = substr($a->get_baseurl(),strpos($a->get_baseurl(),'://'));
2011-05-01 00:24:37 +00:00
$orig_body = $s;
$new_body = '';
2013-05-28 11:50:16 +00:00
$img_start = strpos($orig_body, '[zmg');
$img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false);
2013-05-28 11:50:16 +00:00
$img_len = ($img_start !== false ? strpos(substr($orig_body, $img_start + $img_st_close + 1), '[/zmg]') : false);
while( ($img_st_close !== false) && ($img_len !== false) ) {
$img_st_close++; // make it point to AFTER the closing bracket
$image = substr($orig_body, $img_start + $img_st_close, $img_len);
logger('fix_private_photos: found photo ' . $image, LOGGER_DEBUG);
if(stristr($image , $site . '/photo/')) {
// Only embed locally hosted photos
$replace = false;
2011-05-01 00:24:37 +00:00
$i = basename($image);
$x = strpos($i,'-');
2011-05-01 00:24:37 +00:00
if($x) {
$res = substr($i,$x+1);
$i = substr($i,0,$x);
$r = q("SELECT * FROM `photo` WHERE `resource_id` = '%s' AND `scale` = %d AND `uid` = %d",
2011-05-01 00:24:37 +00:00
dbesc($i),
intval($res),
intval($uid)
);
if(count($r)) {
// Check to see if we should replace this photo link with an embedded image
// 1. No need to do so if the photo is public
// 2. If there's a contact-id provided, see if they're in the access list
// for the photo. If so, embed it.
// 3. Otherwise, if we have an item, see if the item permissions match the photo
// permissions, regardless of order but first check to see if they're an exact
// match to save some processing overhead.
if(has_permissions($r[0])) {
if($cid) {
$recips = enumerate_permissions($r[0]);
if(in_array($cid, $recips)) {
$replace = true;
}
}
elseif($item) {
if(compare_permissions($item,$r[0]))
$replace = true;
}
}
if($replace) {
$data = $r[0]['data'];
$type = $r[0]['type'];
// If a custom width and height were specified, apply before embedding
2013-05-28 11:50:16 +00:00
if(preg_match("/\[zmg\=([0-9]*)x([0-9]*)\]/is", substr($orig_body, $img_start, $img_st_close), $match)) {
logger('fix_private_photos: scaling photo', LOGGER_DEBUG);
$width = intval($match[1]);
$height = intval($match[2]);
2013-04-26 03:01:24 +00:00
$ph = photo_factory($data, $type);
if($ph->is_valid()) {
$ph->scaleImage(max($width, $height));
$data = $ph->imageString();
$type = $ph->getType();
}
}
2012-05-28 23:51:52 +00:00
logger('fix_private_photos: replacing photo', LOGGER_DEBUG);
$image = 'data:' . $type . ';base64,' . base64_encode($data);
logger('fix_private_photos: replaced: ' . $image, LOGGER_DATA);
}
2011-05-01 00:24:37 +00:00
}
}
}
2013-05-28 11:50:16 +00:00
$new_body = $new_body . substr($orig_body, 0, $img_start + $img_st_close) . $image . '[/zmg]';
$orig_body = substr($orig_body, $img_start + $img_st_close + $img_len + strlen('[/zmg]'));
if($orig_body === false)
$orig_body = '';
2013-05-28 11:50:16 +00:00
$img_start = strpos($orig_body, '[zmg');
$img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false);
2013-05-28 11:50:16 +00:00
$img_len = ($img_start !== false ? strpos(substr($orig_body, $img_start + $img_st_close + 1), '[/zmg]') : false);
2011-05-01 00:24:37 +00:00
}
2012-07-08 00:47:13 +00:00
$new_body = $new_body . $orig_body;
return($new_body);
2011-05-01 00:24:37 +00:00
}
function has_permissions($obj) {
if(($obj['allow_cid'] != '') || ($obj['allow_gid'] != '') || ($obj['deny_cid'] != '') || ($obj['deny_gid'] != ''))
return true;
return false;
}
function compare_permissions($obj1,$obj2) {
// first part is easy. Check that these are exactly the same.
if(($obj1['allow_cid'] == $obj2['allow_cid'])
&& ($obj1['allow_gid'] == $obj2['allow_gid'])
&& ($obj1['deny_cid'] == $obj2['deny_cid'])
&& ($obj1['deny_gid'] == $obj2['deny_gid']))
return true;
// This is harder. Parse all the permissions and compare the resulting set.
$recipients1 = enumerate_permissions($obj1);
$recipients2 = enumerate_permissions($obj2);
sort($recipients1);
sort($recipients2);
if($recipients1 == $recipients2)
return true;
return false;
}
// returns an array of contact-ids that are allowed to see this object
function enumerate_permissions($obj) {
require_once('include/group.php');
$allow_people = expand_acl($obj['allow_cid']);
$allow_groups = expand_groups(expand_acl($obj['allow_gid']));
$deny_people = expand_acl($obj['deny_cid']);
$deny_groups = expand_groups(expand_acl($obj['deny_gid']));
$recipients = array_unique(array_merge($allow_people,$allow_groups));
$deny = array_unique(array_merge($deny_people,$deny_groups));
$recipients = array_diff($recipients,$deny);
return $recipients;
}
2011-05-01 00:24:37 +00:00
2011-04-06 00:41:02 +00:00
function item_getfeedtags($item) {
2012-07-11 11:29:47 +00:00
$terms = get_terms_oftype($item['term'],array(TERM_HASHTAG,TERM_MENTION));
2011-04-06 00:41:02 +00:00
$ret = array();
2012-07-11 11:29:47 +00:00
if(count($terms)) {
foreach($terms as $term) {
if($term['type'] == TERM_HASHTAG)
$ret[] = array('#',$term['url'],$term['term']);
else
$ret[] = array('@',$term['url'],$term['term']);
2011-04-06 00:41:02 +00:00
}
}
return $ret;
}
function item_getfeedattach($item) {
$ret = '';
$arr = explode(',',$item['attach']);
if(count($arr)) {
foreach($arr as $r) {
$matches = false;
2011-08-04 02:18:58 +00:00
$cnt = preg_match('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\" title=\"(.*?)\"\[\/attach\]|',$r,$matches);
if($cnt) {
2011-04-07 03:36:24 +00:00
$ret .= '<link rel="enclosure" href="' . xmlify($matches[1]) . '" type="' . xmlify($matches[3]) . '" ';
if(intval($matches[2]))
2011-08-04 02:18:58 +00:00
$ret .= 'length="' . intval($matches[2]) . '" ';
if($matches[4] !== ' ')
2011-04-13 08:53:40 +00:00
$ret .= 'title="' . xmlify(trim($matches[4])) . '" ';
$ret .= ' />' . "\r\n";
}
}
}
return $ret;
}
2011-04-06 00:41:02 +00:00
2011-03-16 00:31:49 +00:00
function item_expire($uid,$days) {
if((! $uid) || ($days < 1))
2011-03-16 00:31:49 +00:00
return;
// $expire_network_only = save your own wall posts
// and just expire conversations started by others
// do not enable this until we can pass bulk delete messages through zot
// $expire_network_only = get_pconfig($uid,'expire','network_only');
$expire_network_only = 1;
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$sql_extra = ((intval($expire_network_only)) ? " AND not (item_flags & " . intval(ITEM_WALL) . ")>0 " : "");
2011-03-16 00:31:49 +00:00
$r = q("SELECT * FROM `item`
WHERE `uid` = %d
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
AND `created` < %s - INTERVAL %s
2011-03-16 00:31:49 +00:00
AND `id` = `parent`
$sql_extra
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
AND NOT ( item_flags & %d )>0
AND (item_restrict = 0 ) ",
2011-03-16 00:31:49 +00:00
intval($uid),
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
db_utcnow(), db_quoteinterval(intval($days).' DAY'),
intval(ITEM_RETAINED)
2011-03-16 00:31:49 +00:00
);
if(! $r)
2011-03-16 00:31:49 +00:00
return;
$r = fetch_post_tags($r,true);
2011-03-16 00:31:49 +00:00
foreach($r as $item) {
2012-03-27 07:54:34 +00:00
// don't expire filed items
$terms = get_terms_oftype($item['term'],TERM_FILE);
if($terms) {
retain_item($item['id']);
2012-03-27 07:54:34 +00:00
continue;
}
2012-03-27 07:54:34 +00:00
2011-03-16 00:31:49 +00:00
// Only expire posts, not photos and photo comments
if($item['resource_type'] === 'photo') {
retain_item($item['id']);
2011-03-16 00:31:49 +00:00
continue;
}
if($item['item_flags'] & ITEM_STARRED) {
retain_item($item['id']);
continue;
}
drop_item($item['id'],false);
2011-03-16 00:31:49 +00:00
}
// proc_run('php',"include/notifier.php","expire","$uid");
}
function retain_item($id) {
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$r = q("update item set item_flags = (item_flags | %d ) where id = %d",
intval(ITEM_RETAINED),
intval($id)
);
}
2011-06-16 03:43:39 +00:00
function drop_items($items) {
$uid = 0;
2012-04-17 11:33:50 +00:00
if(! local_user() && ! remote_user())
return;
2011-06-16 03:43:39 +00:00
if(count($items)) {
foreach($items as $item) {
$owner = drop_item($item,false);
if($owner && ! $uid)
$uid = $owner;
}
}
// multiple threads may have been deleted, send an expire notification
if($uid)
proc_run('php',"include/notifier.php","expire","$uid");
}
// Delete item with given item $id. $interactive means we're running interactively, and must check
// permissions to carry out this act. If it is non-interactive, we are deleting something at the
// system's request and do not check permission. This is very important to know.
2014-03-28 03:28:48 +00:00
// Some deletion requests (those coming from remote sites) must be staged.
// $stage = 0 => unstaged
// $stage = 1 => set deleted flag on the item and perform intial notifications
// $stage = 2 => perform low level delete at a later stage
function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = false) {
2011-06-16 03:43:39 +00:00
2011-06-16 03:43:39 +00:00
$a = get_app();
// locate item to be deleted
$r = q("SELECT * FROM item WHERE id = %d LIMIT 1",
2011-06-16 03:43:39 +00:00
intval($id)
);
2014-03-28 03:28:48 +00:00
if((! $r) || (($r[0]['item_restrict'] & ITEM_DELETED) && ($stage === DROPITEM_NORMAL))) {
2011-06-16 03:43:39 +00:00
if(! $interactive)
return 0;
notice( t('Item not found.') . EOL);
goaway($a->get_baseurl() . '/' . $_SESSION['return_url']);
}
$item = $r[0];
$linked_item = (($item['resource_id']) ? true : false);
$ok_to_delete = false;
2012-09-10 04:17:06 +00:00
// system deletion
if(! $interactive)
$ok_to_delete = true;
2011-06-16 03:43:39 +00:00
// owner deletion
if(local_user() && local_user() == $item['uid'])
$ok_to_delete = true;
// author deletion
$observer = $a->get_observer();
if($observer && $observer['xchan_hash'] && ($observer['xchan_hash'] === $item['author_xchan']))
$ok_to_delete = true;
if($ok_to_delete) {
2013-11-27 07:10:10 +00:00
// set the deleted flag immediately on this item just in case the
// hook calls a remote process which loops. We'll delete it properly in a second.
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$r = q("UPDATE item SET item_restrict = ( item_restrict | %d ) WHERE id = %d",
intval(($linked_item && ! $force) ? ITEM_HIDDEN : ITEM_DELETED),
2013-11-27 07:10:10 +00:00
intval($item['id'])
);
2014-03-28 03:28:48 +00:00
$arr = array('item' => $item, 'interactive' => $interactive, 'stage' => $stage);
2013-11-26 23:26:11 +00:00
call_hooks('drop_item', $arr );
$notify_id = intval($item['id']);
$items = q("select * from item where parent = %d and uid = %d",
intval($item['id']),
intval($item['uid'])
);
if($items) {
foreach($items as $i)
delete_item_lowlevel($i,$stage,$force);
2011-06-16 03:43:39 +00:00
}
2013-01-27 21:43:43 +00:00
else
delete_item_lowlevel($item,$stage,$force);
if(! $interactive)
return 1;
2011-06-16 03:43:39 +00:00
// send the notification upstream/downstream as the case may be
// only send notifications to others if this is the owner's wall item.
2011-06-16 03:43:39 +00:00
2014-10-12 08:40:48 +00:00
// This isn't optimal. We somehow need to pass to this function whether or not
// to call the notifier, or we need to call the notifier from the calling function.
// We'll rely on the undocumented behaviour that DROPITEM_PHASE1 is (hopefully) only
// set if we know we're going to send delete notifications out to others.
if((($item['item_flags'] & ITEM_WALL) && ($stage != DROPITEM_PHASE2)) || ($stage == DROPITEM_PHASE1))
proc_run('php','include/notifier.php','drop',$notify_id);
2011-06-16 03:43:39 +00:00
goaway($a->get_baseurl() . '/' . $_SESSION['return_url']);
2011-06-16 03:43:39 +00:00
}
else {
if(! $interactive)
return 0;
notice( t('Permission denied.') . EOL);
goaway($a->get_baseurl() . '/' . $_SESSION['return_url']);
}
2011-10-23 07:24:37 +00:00
}
2012-06-13 03:46:30 +00:00
// This function does not check for permission and does not send notifications and does not check recursion.
// It merely destroys all resources associated with an item.
// Please do not use without a suitable wrapper.
function delete_item_lowlevel($item,$stage = DROPITEM_NORMAL,$force = false) {
$linked_item = (($item['resource_id']) ? true : false);
2014-03-28 03:28:48 +00:00
switch($stage) {
case DROPITEM_PHASE2:
$r = q("UPDATE item SET item_restrict = ( item_restrict | %d ), body = '', title = '',
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
changed = '%s', edited = '%s' WHERE id = %d",
2014-03-28 03:28:48 +00:00
intval(ITEM_PENDING_REMOVE),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($item['id'])
);
break;
case DROPITEM_PHASE1:
$r = q("UPDATE item SET item_restrict = ( item_restrict | %d ),
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
changed = '%s', edited = '%s' WHERE id = %d",
intval(($linked_item && ! $force) ? ITEM_HIDDEN : ITEM_DELETED),
2014-03-28 03:28:48 +00:00
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($item['id'])
);
break;
case DROPITEM_NORMAL:
default:
if($linked_item && ! $force) {
$r = q("UPDATE item SET item_restrict = ( item_restrict | %d ),
changed = '%s', edited = '%s' WHERE id = %d",
intval(ITEM_HIDDEN),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($item['id'])
);
}
else {
$r = q("UPDATE item SET item_restrict = ( item_restrict | %d ), body = '', title = '',
changed = '%s', edited = '%s' WHERE id = %d",
intval(ITEM_DELETED),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($item['id'])
);
}
2014-03-28 03:28:48 +00:00
break;
}
// immediately remove any undesired profile likes.
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
q("delete from likes where iid = %d and channel_id = %d",
intval($item['id']),
intval($item['uid'])
);
// network deletion request. Keep the message structure so that we can deliver delete notifications.
// Come back after several days (or perhaps a month) to do the lowlevel delete (DROPITEM_PHASE2).
if($stage == DROPITEM_PHASE1)
return true;
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$r = q("delete from term where otype = %d and oid = %d",
intval(TERM_OBJ_POST),
intval($item['id'])
);
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
q("delete from item_id where iid = %d and uid = %d",
intval($item['id']),
intval($item['uid'])
);
2013-02-18 23:15:55 +00:00
q("delete from term where oid = %d and otype = %d",
intval($item['id']),
intval(TERM_OBJ_POST)
);
// FIXME remove notifications for this item
2013-02-18 23:15:55 +00:00
return true;
}
2012-06-13 03:46:30 +00:00
function first_post_date($uid,$wall = false) {
2012-10-08 01:44:06 +00:00
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$wall_sql = (($wall) ? sprintf(" and (item_flags & %d)>0 ", ITEM_WALL) : "" );
2012-10-08 01:44:06 +00:00
$r = q("select id, created from item
where item_restrict = %d and uid = %d and id = parent $wall_sql
2012-06-13 03:46:30 +00:00
order by created asc limit 1",
2012-10-08 01:44:06 +00:00
intval(ITEM_VISIBLE),
intval($uid)
2012-06-13 03:46:30 +00:00
);
if($r) {
2012-06-13 04:39:39 +00:00
// logger('first_post_date: ' . $r[0]['id'] . ' ' . $r[0]['created'], LOGGER_DATA);
return substr(datetime_convert('',date_default_timezone_get(),$r[0]['created']),0,10);
2012-06-13 04:34:28 +00:00
}
2012-06-13 03:46:30 +00:00
return false;
}
/**
* modified posted_dates() {below} to arrange the list in years, which we'll eventually
* use to make a menu of years with collapsible sub-menus for the months instead of the
* current flat list of all representative dates.
*/
function list_post_dates($uid,$wall,$mindate) {
$dnow = datetime_convert('',date_default_timezone_get(),'now','Y-m-d');
if($mindate)
$dthen = datetime_convert('',date_default_timezone_get(),$mindate);
else
$dthen = first_post_date($uid,$wall);
if(! $dthen)
return array();
// If it's near the end of a long month, backup to the 28th so that in
// consecutive loops we'll always get a whole month difference.
if(intval(substr($dnow,8)) > 28)
$dnow = substr($dnow,0,8) . '28';
if(intval(substr($dthen,8)) > 28)
$dthen = substr($dthen,0,8) . '28';
$ret = array();
// Starting with the current month, get the first and last days of every
// month down to and including the month of the first post
while(substr($dnow, 0, 7) >= substr($dthen, 0, 7)) {
$dyear = intval(substr($dnow,0,4));
$dstart = substr($dnow,0,8) . '01';
$dend = substr($dnow,0,8) . get_dim(intval($dnow),intval(substr($dnow,5)));
$start_month = datetime_convert('','',$dstart,'Y-m-d');
$end_month = datetime_convert('','',$dend,'Y-m-d');
$str = day_translate(datetime_convert('','',$dnow,'F'));
if(! $ret[$dyear])
$ret[$dyear] = array();
$ret[$dyear][] = array($str,$end_month,$start_month);
$dnow = datetime_convert('','',$dnow . ' -1 month', 'Y-m-d');
}
return $ret;
}
2012-06-13 03:46:30 +00:00
function posted_dates($uid,$wall) {
$dnow = datetime_convert('',date_default_timezone_get(),'now','Y-m-d');
2012-06-13 03:46:30 +00:00
$dthen = first_post_date($uid,$wall);
if(! $dthen)
return array();
// If it's near the end of a long month, backup to the 28th so that in
// consecutive loops we'll always get a whole month difference.
if(intval(substr($dnow,8)) > 28)
$dnow = substr($dnow,0,8) . '28';
if(intval(substr($dthen,8)) > 28)
$dthen = substr($dthen,0,8) . '28';
2012-06-13 03:46:30 +00:00
$ret = array();
// Starting with the current month, get the first and last days of every
// month down to and including the month of the first post
while(substr($dnow, 0, 7) >= substr($dthen, 0, 7)) {
$dstart = substr($dnow,0,8) . '01';
$dend = substr($dnow,0,8) . get_dim(intval($dnow),intval(substr($dnow,5)));
$start_month = datetime_convert('','',$dstart,'Y-m-d');
$end_month = datetime_convert('','',$dend,'Y-m-d');
2012-06-13 03:46:30 +00:00
$str = day_translate(datetime_convert('','',$dnow,'F Y'));
$ret[] = array($str,$end_month,$start_month);
$dnow = datetime_convert('','',$dnow . ' -1 month', 'Y-m-d');
}
return $ret;
}
2013-02-11 08:20:14 +00:00
function fetch_post_tags($items,$link = false) {
$tag_finder = array();
if($items) {
foreach($items as $item) {
2013-01-03 00:28:47 +00:00
if(is_array($item)) {
if(array_key_exists('item_id',$item)) {
if(! in_array($item['item_id'],$tag_finder))
$tag_finder[] = $item['item_id'];
}
else {
if(! in_array($item['id'],$tag_finder))
$tag_finder[] = $item['id'];
}
}
}
}
$tag_finder_str = implode(', ', $tag_finder);
2012-07-17 12:30:32 +00:00
if(strlen($tag_finder_str)) {
$tags = q("select * from term where oid in ( %s ) and otype = %d",
dbesc($tag_finder_str),
intval(TERM_OBJ_POST)
);
}
for($x = 0; $x < count($items); $x ++) {
2013-01-03 00:28:47 +00:00
if($tags) {
foreach($tags as $t) {
2013-02-11 08:20:14 +00:00
if(($link) && ($t['type'] == TERM_MENTION))
$t['url'] = chanlink_url($t['url']);
if(array_key_exists('item_id',$items[$x])) {
if($t['oid'] == $items[$x]['item_id']) {
if(! is_array($items[$x]['term']))
$items[$x]['term'] = array();
$items[$x]['term'][] = $t;
}
}
else {
if($t['oid'] == $items[$x]['id']) {
if(! is_array($items[$x]['term']))
$items[$x]['term'] = array();
$items[$x]['term'][] = $t;
}
}
}
}
}
return $items;
}
function zot_feed($uid,$observer_xchan,$arr) {
$result = array();
$mindate = null;
$message_id = null;
if(array_key_exists('mindate',$arr)) {
$mindate = datetime_convert('UTC','UTC',$arr['mindate']);
}
if(array_key_exists('message_id',$arr)) {
$message_id = $arr['message_id'];
}
if(! $mindate)
$mindate = NULL_DATE;
2013-07-30 03:39:12 +00:00
$mindate = dbesc($mindate);
logger('zot_feed: requested for uid ' . $uid . ' from observer ' . $observer_xchan, LOGGER_DEBUG);
2014-11-21 02:44:16 +00:00
if($message_id)
logger('message_id: ' . $message_id,LOGGER_DEBUG);
if(! perm_is_allowed($uid,$observer_xchan,'view_stream')) {
logger('zot_feed: permission denied.');
return $result;
}
2014-03-27 02:13:26 +00:00
if(! is_sys_channel($uid)) {
require_once('include/security.php');
$sql_extra = item_permissions_sql($uid);
}
if($mindate != NULL_DATE) {
$sql_extra .= " and ( created > '$mindate' or edited > '$mindate' ) ";
2013-07-30 03:39:12 +00:00
$limit = "";
}
else
$limit = " limit 0, 50 ";
if($message_id) {
$sql_extra .= " and mid = '" . dbesc($message_id) . "' ";
$limit = '';
}
2013-07-30 03:31:02 +00:00
$items = array();
if(is_sys_channel($uid)) {
2014-03-27 03:22:57 +00:00
require_once('include/security.php');
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$r = q("SELECT distinct parent, created from item
WHERE uid != %d
and uid in (" . stream_perms_api_uids(PERMS_PUBLIC) . ") AND item_restrict = 0
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
AND (item_flags & %d)>0
2014-03-27 02:13:26 +00:00
and item_private = 0 $sql_extra ORDER BY created ASC $limit",
intval($uid),
intval(ITEM_WALL)
);
}
else {
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$r = q("SELECT distinct parent, created from item
WHERE uid = %d AND item_restrict = 0
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
AND (item_flags & %d)>0
$sql_extra ORDER BY created ASC $limit",
intval($uid),
intval(ITEM_WALL)
);
}
2013-07-30 03:31:02 +00:00
if($r) {
$parents_str = ids_to_querystr($r,'parent');
$sys_query = ((is_sys_channel($uid)) ? $sql_extra : '');
2013-07-30 03:31:02 +00:00
$items = q("SELECT `item`.*, `item`.`id` AS `item_id` FROM `item`
WHERE `item`.`item_restrict` = 0
AND `item`.`parent` IN ( %s ) $sys_query ",
2013-07-30 03:31:02 +00:00
dbesc($parents_str)
);
}
if($items) {
xchan_query($items);
$items = fetch_post_tags($items);
2013-07-30 03:31:58 +00:00
require_once('include/conversation.php');
2013-07-30 03:31:02 +00:00
$items = conv_sort($items,'ascending');
}
2013-07-30 03:31:02 +00:00
else
$items = array();
logger('zot_feed: number items: ' . count($items),LOGGER_DEBUG);
foreach($items as $item)
$result[] = encode_item($item);
return $result;
}
2013-05-23 04:54:02 +00:00
function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = CLIENT_MODE_NORMAL,$module = 'network') {
2013-05-23 04:54:02 +00:00
$result = array('success' => false);
$a = get_app();
2013-05-23 04:54:02 +00:00
$sql_extra = '';
$sql_nets = '';
$sql_options = '';
$sql_extra2 = '';
$sql_extra3 = '';
$def_acl = '';
$item_uids = ' true ';
2014-01-25 02:50:47 +00:00
if ($arr['uid']) $uid= $arr['uid'];
if($channel) {
$uid = $channel['channel_id'];
$uidhash = $channel['channel_hash'];
$item_uids = " item.uid = " . intval($uid) . " ";
}
2014-01-22 22:15:42 +00:00
2013-05-23 04:54:02 +00:00
if($arr['star'])
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$sql_options .= " and (item_flags & " . intval(ITEM_STARRED) . ")>0 ";
if($arr['wall'])
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$sql_options .= " and (item_flags & " . intval(ITEM_WALL) . ")>0 ";
2014-01-25 02:50:47 +00:00
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$sql_extra = " AND item.parent IN ( SELECT parent FROM item WHERE (item_flags & " . intval(ITEM_THREAD_TOP) . ")>0 $sql_options ) ";
2014-01-22 22:15:42 +00:00
if($arr['since_id'])
$sql_extra .= " and item.id > " . $since_id . " ";
if($arr['gid'] && $uid) {
$r = q("SELECT * FROM `groups` WHERE id = %d AND uid = %d LIMIT 1",
2013-05-23 04:54:02 +00:00
intval($arr['group']),
intval($uid)
2013-05-23 04:54:02 +00:00
);
if(! $r) {
$result['message'] = t('Collection not found.');
return $result;
}
$contact_str = '';
$contacts = group_get_members($group);
if($contacts) {
foreach($contacts as $c) {
if($contact_str)
$contact_str .= ',';
$contact_str .= "'" . $c['xchan'] . "'";
}
2013-05-23 04:54:02 +00:00
}
else {
$contact_str = ' 0 ';
$result['message'] = t('Collection is empty.');
return $result;
2013-05-23 04:54:02 +00:00
}
$sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str)) or allow_gid like '" . protect_sprintf('%<' . dbesc($r[0]['hash']) . '>%') . "' ) and id = parent and item_restrict = 0 ) ";
2013-05-23 04:54:02 +00:00
$x = group_rec_byhash($uid,$r[0]['hash']);
$result['headline'] = sprintf( t('Collection: %s'),$x['name']);
2013-05-23 04:54:02 +00:00
}
elseif($arr['cid'] && $uid) {
2013-05-23 04:54:02 +00:00
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$r = q("SELECT abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d and not ( abook_flags & " . intval(ABOOK_FLAG_BLOCKED) . ")>0 limit 1",
2013-05-23 04:54:02 +00:00
intval($arr['cid']),
2013-09-29 09:47:36 +00:00
intval(local_user())
2013-05-23 04:54:02 +00:00
);
if($r) {
2013-06-28 04:40:56 +00:00
$sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND uid = " . intval($arr['uid']) . " AND ( author_xchan = '" . dbesc($r[0]['abook_xchan']) . "' or owner_xchan = '" . dbesc($r[0]['abook_xchan']) . "' ) and item_restrict = 0 ) ";
$result['headline'] = sprintf( t('Connection: %s'),$r[0]['xchan_name']);
2013-05-23 04:54:02 +00:00
}
else {
$result['message'] = t('Connection not found.');
return $result;
}
}
if($arr['datequery']) {
$sql_extra3 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$arr['datequery']))));
}
if($arr['datequery2']) {
$sql_extra3 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$arr['datequery2']))));
}
if(! array_key_exists('nouveau',$arr)) {
$sql_extra2 = " AND item.parent = item.id ";
2013-05-23 04:54:02 +00:00
$sql_extra3 = '';
}
if($arr['search']) {
if(strpos($arr['search'],'#') === 0)
$sql_extra .= term_query('item',substr($arr['search'],1),TERM_HASHTAG);
else
$sql_extra .= sprintf(" AND item.body like '%s' ",
dbesc(protect_sprintf('%' . $arr['search'] . '%'))
);
}
if(strlen($arr['file'])) {
$sql_extra .= term_query('item',$arr['files'],TERM_FILE);
}
if($arr['conv'] && $channel) {
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$sql_extra .= sprintf(" AND parent IN (SELECT distinct parent from item where ( author_xchan like '%s' or ( item_flags & %d )>0)) ",
dbesc(protect_sprintf($uidhash)),
2013-05-23 04:54:02 +00:00
intval(ITEM_MENTIONSME)
);
}
2014-01-25 23:51:10 +00:00
if(($client_mode & CLIENT_MODE_UPDATE) && (! ($client_mode & CLIENT_MODE_LOAD))) {
2013-05-23 04:54:02 +00:00
// only setup pagination on initial page view
$pager_sql = '';
}
else {
$itemspage = (($channel) ? get_pconfig($uid,'system','itemspage') : 20);
2013-05-23 04:54:02 +00:00
$a->set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20));
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(get_app()->pager['itemspage']), intval(get_app()->pager['start']));
2013-05-23 04:54:02 +00:00
}
2014-01-25 23:51:10 +00:00
if(isset($arr['start']) && isset($arr['records']))
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval($arr['records']), intval($arr['start']));
2013-05-23 04:54:02 +00:00
2014-03-18 23:50:46 +00:00
if(array_key_exists('cmin',$arr) || array_key_exists('cmax',$arr)) {
if(($arr['cmin'] != 0) || ($arr['cmax'] != 99)) {
2013-05-23 04:54:02 +00:00
// Not everybody who shows up in the network stream will be in your address book.
// By default those that aren't are assumed to have closeness = 99; but this isn't
// recorded anywhere. So if cmax is 99, we'll open the search up to anybody in
// the stream with a NULL address book entry.
2013-05-23 04:54:02 +00:00
2014-03-18 23:50:46 +00:00
$sql_nets .= " AND ";
2013-05-23 04:54:02 +00:00
2014-03-18 23:50:46 +00:00
if($arr['cmax'] == 99)
$sql_nets .= " ( ";
2013-05-23 04:54:02 +00:00
2014-03-18 23:50:46 +00:00
$sql_nets .= "( abook.abook_closeness >= " . intval($arr['cmin']) . " ";
$sql_nets .= " AND abook.abook_closeness <= " . intval($arr['cmax']) . " ) ";
if($cmax == 99)
$sql_nets .= " OR abook.abook_closeness IS NULL ) ";
}
}
2013-05-23 04:54:02 +00:00
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$simple_update = (($client_mode & CLIENT_MODE_UPDATE) ? " and ( item.item_flags & " . intval(ITEM_UNSEEN) . " )>0 " : '');
if($client_mode & CLIENT_MODE_LOAD)
2013-05-23 04:54:02 +00:00
$simple_update = '';
$start = dba_timer();
2013-06-14 00:53:16 +00:00
require_once('include/security.php');
$sql_extra .= item_permissions_sql($channel['channel_id']);
2013-09-06 02:31:26 +00:00
if($arr['pages'])
$item_restrict = " AND (item_restrict & " . ITEM_WEBPAGE . ") ";
else
$item_restrict = " AND item_restrict = 0 ";
2014-01-25 23:51:10 +00:00
if($arr['nouveau'] && ($client_mode & CLIENT_MODE_LOAD) && $channel) {
2013-05-23 04:54:02 +00:00
// "New Item View" - show all items unthreaded in reverse created date order
$items = q("SELECT item.*, item.id AS item_id FROM item
2013-09-06 02:31:26 +00:00
WHERE $item_uids $item_restrict
2013-05-23 04:54:02 +00:00
$simple_update
$sql_extra $sql_nets
ORDER BY item.received DESC $pager_sql "
2013-05-23 04:54:02 +00:00
);
require_once('include/items.php');
xchan_query($items);
$items = fetch_post_tags($items,true);
}
else {
2013-05-23 04:54:02 +00:00
// Normal conversation view
if($arr['order'] === 'post')
$ordering = "created";
2013-05-23 04:54:02 +00:00
else
$ordering = "commented";
2013-05-23 04:54:02 +00:00
2014-01-25 23:51:10 +00:00
if(($client_mode & CLIENT_MODE_LOAD) || ($client_mode == CLIENT_MODE_NORMAL)) {
2013-05-23 04:54:02 +00:00
// Fetch a page full of parent items for this page
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$r = q("SELECT distinct item.id AS item_id, item.$ordering FROM item
2013-05-23 04:54:02 +00:00
left join abook on item.author_xchan = abook.abook_xchan
2013-09-06 02:31:26 +00:00
WHERE $item_uids $item_restrict
2013-05-23 04:54:02 +00:00
AND item.parent = item.id
and ((abook.abook_flags & %d) = 0 or abook.abook_flags is null)
$sql_extra3 $sql_extra $sql_nets
ORDER BY item.$ordering DESC $pager_sql ",
intval(ABOOK_FLAG_BLOCKED)
);
2014-01-25 02:50:47 +00:00
2013-05-23 04:54:02 +00:00
}
else {
// update
$r = q("SELECT item.parent AS item_id FROM item
left join abook on item.author_xchan = abook.abook_xchan
2013-09-06 02:31:26 +00:00
WHERE $item_uids $item_restrict $simple_update
2013-05-23 04:54:02 +00:00
and ((abook.abook_flags & %d) = 0 or abook.abook_flags is null)
$sql_extra3 $sql_extra $sql_nets ",
intval(ABOOK_FLAG_BLOCKED)
);
}
$first = dba_timer();
// Then fetch all the children of the parents that are on this page
if($r) {
$parents_str = ids_to_querystr($r,'item_id');
2014-08-22 22:51:48 +00:00
if($arr['top'])
$sql_extra = ' and id = parent ' . $sql_extra;
$items = q("SELECT item.*, item.id AS item_id FROM item
2013-09-06 02:31:26 +00:00
WHERE $item_uids $item_restrict
AND item.parent IN ( %s )
2013-05-23 04:54:02 +00:00
$sql_extra ",
dbesc($parents_str)
);
$second = dba_timer();
xchan_query($items);
$third = dba_timer();
$items = fetch_post_tags($items,true);
$fourth = dba_timer();
require_once('include/conversation.php');
2013-05-23 04:54:02 +00:00
$items = conv_sort($items,$ordering);
//logger('items: ' . print_r($items,true));
}
else {
$items = array();
}
if($parents_str && $arr['mark_seen'])
2013-05-23 04:54:02 +00:00
$update_unseen = ' AND parent IN ( ' . dbesc($parents_str) . ' )';
// FIXME finish mark unseen sql
2013-05-23 04:54:02 +00:00
}
return $items;
}
2014-01-04 21:44:43 +00:00
function update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remote_id,$mid) {
$page_type = '';
if($webpage & ITEM_WEBPAGE)
$page_type = 'WEBPAGE';
elseif($webpage & ITEM_BUILDBLOCK)
$page_type = 'BUILDBLOCK';
elseif($webpage & ITEM_PDL)
$page_type = 'PDL';
elseif($namespace && $remote_id) {
$page_type = $namespace;
$pagetitle = $remote_id;
}
if($page_type) {
// store page info as an alternate message_id so we can access it via
// https://sitename/page/$channelname/$pagetitle
// if no pagetitle was given or it couldn't be transliterated into a url, use the first
// sixteen bytes of the mid - which makes the link portable and not quite as daunting
// as the entire mid. If it were the post_id the link would be less portable.
$r = q("select * from item_id where iid = %d and uid = %d and service = '%s' limit 1",
intval($post_id),
intval($channel['channel_id']),
dbesc($page_type)
);
if($r) {
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
q("update item_id set sid = '%s' where id = %d",
2014-01-04 21:44:43 +00:00
dbesc(($pagetitle) ? $pagetitle : substr($mid,0,16)),
intval($r[0]['id'])
);
}
else {
q("insert into item_id ( iid, uid, sid, service ) values ( %d, %d, '%s','%s' )",
intval($post_id),
intval($channel['channel_id']),
dbesc(($pagetitle) ? $pagetitle : substr($mid,0,16)),
dbesc($page_type)
);
}
}
}
/**
* change access control for item with message_id $mid and channel_id $uid
*/
function item_add_cid($xchan_hash,$mid,$uid) {
$r = q("select id from item where mid = '%s' and uid = %d and allow_cid like '%s'",
dbesc($mid),
intval($uid),
dbesc('<' . $xchan_hash . '>')
);
if(! $r) {
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$r = q("update item set allow_cid = concat(allow_cid,'%s') where mid = '%s' and uid = %d",
dbesc('<' . $xchan_hash . '>'),
dbesc($mid),
intval($uid)
);
}
}
function item_remove_cid($xchan_hash,$mid,$uid) {
$r = q("select allow_cid from item where mid = '%s' and uid = %d and allow_cid like '%s'",
dbesc($mid),
intval($uid),
dbesc('<' . $xchan_hash . '>')
);
if($r) {
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$x = q("update item set allow_cid = '%s' where mid = '%s' and uid = %d",
dbesc(str_replace('<' . $xchan_hash . '>','',$r[0]['allow_cid'])),
dbesc($mid),
intval($uid)
);
}
}
// Set item permissions based on results obtained from linkify_tags()
function set_linkified_perms($linkified, &$str_contact_allow, &$str_group_allow, $profile_uid, $parent_item = false) {
$first_access_tag = true;
foreach($linkified as $x) {
$access_tag = $x['access_tag'];
if(($access_tag) && (! $parent_item)) {
logger('access_tag: ' . $tag . ' ' . print_r($access_tag,true), LOGGER_DATA);
if ($first_access_tag && (! get_pconfig($profile_uid,'system','no_private_mention_acl_override'))) {
// This is a tough call, hence configurable. The issue is that one can type in a @!privacy mention
// and also have a default ACL (perhaps from viewing a collection) and could be suprised that the
// privacy mention wasn't the only recipient. So the default is to wipe out the existing ACL if a
// private mention is found. This can be over-ridden if you wish private mentions to be in
// addition to the current ACL settings.
$str_contact_allow = '';
$str_group_allow = '';
$first_access_tag = false;
}
if(strpos($access_tag,'cid:') === 0) {
$str_contact_allow .= '<' . substr($access_tag,4) . '>';
$access_tag = '';
}
elseif(strpos($access_tag,'gid:') === 0) {
$str_group_allow .= '<' . substr($access_tag,4) . '>';
$access_tag = '';
}
}
}
}