streams/mod/item.php

1097 lines
35 KiB
PHP
Raw Normal View History

2010-07-01 23:48:07 +00:00
<?php
2011-02-04 21:37:04 +00:00
/**
*
* This is the POST destination for most all locally posted
* text stuff. This function handles status, wall-to-wall status,
2012-01-29 10:09:39 +00:00
* local comments, and remote coments that are posted on this site
2011-02-04 21:37:04 +00:00
* (as opposed to being delivered in a feed).
* Also processed here are posts and comments coming through the
* statusnet/twitter API.
2011-02-04 21:37:04 +00:00
* All of these become an "item" which is our basic unit of
* information.
* Posts that originate externally or do not fall into the above
* posting categories go through item_store() instead of this function.
*
*/
2010-10-06 07:33:11 +00:00
require_once('include/crypto.php');
2011-12-27 22:26:44 +00:00
require_once('include/enotify.php');
require_once('include/items.php');
require_once('include/attach.php');
2010-07-01 23:48:07 +00:00
function item_post(&$a) {
2010-07-19 13:58:03 +00:00
// This will change. Figure out who the observer is and whether or not
// they have permission to post here. Else ignore the post.
2015-01-29 04:58:59 +00:00
if((! local_channel()) && (! remote_channel()) && (! x($_REQUEST,'commenter')))
2010-07-01 23:48:07 +00:00
return;
require_once('include/security.php');
2015-01-29 04:56:04 +00:00
$uid = local_channel();
$channel = null;
2014-11-12 02:57:59 +00:00
$observer = null;
2014-11-12 02:57:59 +00:00
$profile_uid = ((x($_REQUEST,'profile_uid')) ? intval($_REQUEST['profile_uid']) : 0);
require_once('include/identity.php');
$sys = get_sys_channel();
if($sys && $profile_uid && ($sys['channel_id'] == $profile_uid) && is_site_admin()) {
$uid = intval($sys['channel_id']);
$channel = $sys;
$observer = $sys;
}
if(x($_REQUEST,'dropitems')) {
2011-06-16 03:43:39 +00:00
require_once('include/items.php');
$arr_drop = explode(',',$_REQUEST['dropitems']);
2011-06-16 03:43:39 +00:00
drop_items($arr_drop);
$json = array('success' => 1);
echo json_encode($json);
2011-06-16 03:43:39 +00:00
killme();
}
call_hooks('post_local_start', $_REQUEST);
2012-08-27 06:05:00 +00:00
2014-06-20 03:38:38 +00:00
// logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA);
2012-01-10 02:52:49 +00:00
$api_source = ((x($_REQUEST,'api_source') && $_REQUEST['api_source']) ? true : false);
2012-07-20 01:53:26 +00:00
2015-02-11 03:10:18 +00:00
$consensus = intval($_REQUEST['consensus']);
2012-07-20 01:53:26 +00:00
// 'origin' (if non-zero) indicates that this network is where the message originated,
// for the purpose of relaying comments to other conversation members.
// If using the API from a device (leaf node) you must set origin to 1 (default) or leave unset.
// If the API is used from another network with its own distribution
// and deliveries, you may wish to set origin to 0 or false and allow the other
// network to relay comments.
// If you are unsure, it is prudent (and important) to leave it unset.
$origin = (($api_source && array_key_exists('origin',$_REQUEST)) ? intval($_REQUEST['origin']) : 1);
// To represent message-ids on other networks - this will create an item_id record
$namespace = (($api_source && array_key_exists('namespace',$_REQUEST)) ? strip_tags($_REQUEST['namespace']) : '');
$remote_id = (($api_source && array_key_exists('remote_id',$_REQUEST)) ? strip_tags($_REQUEST['remote_id']) : '');
2013-01-03 09:42:28 +00:00
$owner_hash = null;
2012-07-20 01:53:26 +00:00
$message_id = ((x($_REQUEST,'message_id') && $api_source) ? strip_tags($_REQUEST['message_id']) : '');
$created = ((x($_REQUEST,'created')) ? datetime_convert('UTC','UTC',$_REQUEST['created']) : datetime_convert());
$post_id = ((x($_REQUEST,'post_id')) ? intval($_REQUEST['post_id']) : 0);
$app = ((x($_REQUEST,'source')) ? strip_tags($_REQUEST['source']) : '');
$return_path = ((x($_REQUEST,'return')) ? $_REQUEST['return'] : '');
$preview = ((x($_REQUEST,'preview')) ? intval($_REQUEST['preview']) : 0);
$categories = ((x($_REQUEST,'category')) ? escape_tags($_REQUEST['category']) : '');
$webpage = ((x($_REQUEST,'webpage')) ? intval($_REQUEST['webpage']) : 0);
$pagetitle = ((x($_REQUEST,'pagetitle')) ? escape_tags(urlencode($_REQUEST['pagetitle'])) : '');
$layout_mid = ((x($_REQUEST,'layout_mid')) ? escape_tags($_REQUEST['layout_mid']): '');
$plink = ((x($_REQUEST,'permalink')) ? escape_tags($_REQUEST['permalink']) : '');
$obj_type = ((x($_REQUEST,'obj_type')) ? escape_tags($_REQUEST['obj_type']) : ACTIVITY_OBJ_NOTE);
// allow API to bulk load a bunch of imported items with sending out a bunch of posts.
$nopush = ((x($_REQUEST,'nopush')) ? intval($_REQUEST['nopush']) : 0);
/*
* Check service class limits
*/
if ($uid && !(x($_REQUEST,'parent')) && !(x($_REQUEST,'post_id'))) {
$ret = item_check_service_class($uid,x($_REQUEST,'webpage'));
if (!$ret['success']) {
notice( t($ret['message']) . EOL) ;
if(x($_REQUEST,'return'))
goaway($a->get_baseurl() . "/" . $return_path );
killme();
}
}
if($pagetitle) {
require_once('library/urlify/URLify.php');
$pagetitle = strtolower(URLify::transliterate($pagetitle));
}
2011-08-01 03:01:00 +00:00
$item_flags = $item_restrict = 0;
2011-08-01 03:01:00 +00:00
/**
* Is this a reply to something?
*/
$parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : 0);
$parent_mid = ((x($_REQUEST,'parent_mid')) ? trim($_REQUEST['parent_mid']) : '');
$route = '';
$parent_item = null;
$parent_contact = null;
2011-08-01 03:01:00 +00:00
$thr_parent = '';
$parid = 0;
$r = false;
if($parent || $parent_mid) {
if(! x($_REQUEST,'type'))
$_REQUEST['type'] = 'net-comment';
if($obj_type == ACTIVITY_OBJ_POST)
$obj_type = ACTIVITY_OBJ_COMMENT;
if($parent) {
$r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1",
intval($parent)
);
}
elseif($parent_mid && $uid) {
// This is coming from an API source, and we are logged in
$r = q("SELECT * FROM `item` WHERE `mid` = '%s' AND `uid` = %d LIMIT 1",
dbesc($parent_mid),
intval($uid)
);
}
// if this isn't the real parent of the conversation, find it
if($r !== false && count($r)) {
$parid = $r[0]['parent'];
$parent_mid = $r[0]['mid'];
if($r[0]['id'] != $r[0]['parent']) {
2011-08-01 03:01:00 +00:00
$r = q("SELECT * FROM `item` WHERE `id` = `parent` AND `parent` = %d LIMIT 1",
intval($parid)
);
}
}
if(($r === false) || (! count($r))) {
2010-08-05 03:03:38 +00:00
notice( t('Unable to locate original post.') . EOL);
if(x($_REQUEST,'return'))
goaway($a->get_baseurl() . "/" . $return_path );
killme();
}
// can_comment_on_post() needs info from the following xchan_query
xchan_query($r);
$parent_item = $r[0];
$parent = $r[0]['id'];
2011-08-01 03:01:00 +00:00
// multi-level threading - preserve the info but re-parent to our single level threading
2013-08-01 01:57:14 +00:00
$thr_parent = $parent_mid;
$route = $parent_item['route'];
}
2014-11-12 02:57:59 +00:00
if(! $observer)
$observer = $a->get_observer();
2013-06-28 03:49:45 +00:00
if($parent) {
logger('mod_item: item_post parent=' . $parent);
$can_comment = false;
if((array_key_exists('owner',$parent_item)) && ($parent_item['owner']['abook_flags'] & ABOOK_FLAG_SELF))
$can_comment = perm_is_allowed($profile_uid,$observer['xchan_hash'],'post_comments');
else
$can_comment = can_comment_on_post($observer['xchan_hash'],$parent_item);
if(! $can_comment) {
notice( t('Permission denied.') . EOL) ;
if(x($_REQUEST,'return'))
goaway($a->get_baseurl() . "/" . $return_path );
killme();
}
2013-06-28 03:49:45 +00:00
}
else {
if(! perm_is_allowed($profile_uid,$observer['xchan_hash'],'post_wall')) {
notice( t('Permission denied.') . EOL) ;
if(x($_REQUEST,'return'))
goaway($a->get_baseurl() . "/" . $return_path );
killme();
}
2010-07-01 23:48:07 +00:00
}
2011-03-18 12:06:16 +00:00
// is this an edited post?
$orig_post = null;
if($namespace && $remote_id) {
// It wasn't an internally generated post - see if we've got an item matching this remote service id
$i = q("select iid from item_id where service = '%s' and sid = '%s' limit 1",
dbesc($namespace),
dbesc($remote_id)
);
if($i)
$post_id = $i[0]['iid'];
}
2011-03-18 12:06:16 +00:00
if($post_id) {
$i = q("SELECT * FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1",
intval($profile_uid),
intval($post_id)
);
if(! count($i))
killme();
$orig_post = $i[0];
}
if(! $channel) {
if($uid && $uid == $profile_uid) {
$channel = $a->get_channel();
}
else {
// posting as yourself but not necessarily to a channel you control
$r = q("select * from channel left join account on channel_account_id = account_id where channel_id = %d LIMIT 1",
intval($profile_uid)
);
if($r)
$channel = $r[0];
}
}
if(! $channel) {
logger("mod_item: no channel.");
2012-10-04 10:23:49 +00:00
if(x($_REQUEST,'return'))
goaway($a->get_baseurl() . "/" . $return_path );
killme();
}
2012-10-04 10:23:49 +00:00
$owner_xchan = null;
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
dbesc($channel['channel_hash'])
);
if($r && count($r)) {
$owner_xchan = $r[0];
}
else {
logger("mod_item: no owner.");
if(x($_REQUEST,'return'))
goaway($a->get_baseurl() . "/" . $return_path );
killme();
}
2013-08-01 01:57:14 +00:00
2014-10-21 23:33:35 +00:00
$walltowall = false;
$walltowall_comment = false;
2014-10-21 23:33:35 +00:00
2013-08-01 01:57:14 +00:00
if($observer) {
logger('mod_item: post accepted from ' . $observer['xchan_name'] . ' for ' . $owner_xchan['xchan_name'], LOGGER_DEBUG);
2014-10-21 23:33:35 +00:00
// wall-to-wall detection.
// For top-level posts, if the author and owner are different it's a wall-to-wall
// For comments, We need to additionally look at the parent and see if it's a wall post that originated locally.
2014-10-21 23:33:35 +00:00
if($observer['xchan_name'] != $owner_xchan['xchan_name']) {
if($parent_item && ($parent_item['item_flags'] & (ITEM_WALL|ITEM_ORIGIN)) == (ITEM_WALL|ITEM_ORIGIN)) {
$walltowall_comment = true;
$walltowall = true;
}
if(! $parent) {
$walltowall = true;
}
}
}
2014-08-08 22:27:17 +00:00
$public_policy = ((x($_REQUEST,'public_policy')) ? escape_tags($_REQUEST['public_policy']) : map_scope($channel['channel_r_stream'],true));
if($webpage)
$public_policy = '';
if($public_policy)
$private = 1;
2011-03-18 12:06:16 +00:00
if($orig_post) {
$private = 0;
2014-06-14 23:35:38 +00:00
// webpages are allowed to change ACLs after the fact. Normal conversation items aren't.
if($webpage) {
$str_group_allow = perms2str($_REQUEST['group_allow']);
$str_contact_allow = perms2str($_REQUEST['contact_allow']);
$str_group_deny = perms2str($_REQUEST['group_deny']);
$str_contact_deny = perms2str($_REQUEST['contact_deny']);
}
else {
$str_group_allow = $orig_post['allow_gid'];
$str_contact_allow = $orig_post['allow_cid'];
$str_group_deny = $orig_post['deny_gid'];
$str_contact_deny = $orig_post['deny_cid'];
2014-08-08 22:27:17 +00:00
$public_policy = $orig_post['public_policy'];
2014-06-14 23:35:38 +00:00
}
if((strlen($str_group_allow))
|| strlen($str_contact_allow)
|| strlen($str_group_deny)
2014-08-07 02:24:46 +00:00
|| strlen($str_contact_deny)
2014-08-07 04:16:24 +00:00
|| strlen($public_policy)) {
$private = 1;
}
2011-03-18 12:06:16 +00:00
$location = $orig_post['location'];
$coord = $orig_post['coord'];
$verb = $orig_post['verb'];
2013-10-06 22:56:22 +00:00
$app = $orig_post['app'];
2014-02-20 23:00:29 +00:00
$title = $_REQUEST['title'];
$body = $_REQUEST['body'];
$item_flags = $orig_post['item_flags'];
// force us to recalculate if we need to obscure this post
if($item_flags & ITEM_OBSCURED)
$item_flags = ($item_flags ^ ITEM_OBSCURED);
2013-10-06 22:56:22 +00:00
$item_restrict = $orig_post['item_restrict'];
$postopts = $orig_post['postopts'];
$created = $orig_post['created'];
2014-01-11 03:01:24 +00:00
$mid = $orig_post['mid'];
$parent_mid = $orig_post['parent_mid'];
$plink = $orig_post['plink'];
}
2011-03-18 12:06:16 +00:00
else {
// if coming from the API and no privacy settings are set,
// use the user default permissions - as they won't have
// been supplied via a form.
if(($api_source)
&& (! array_key_exists('contact_allow',$_REQUEST))
&& (! array_key_exists('group_allow',$_REQUEST))
&& (! array_key_exists('contact_deny',$_REQUEST))
&& (! array_key_exists('group_deny',$_REQUEST))) {
$str_group_allow = $channel['channel_allow_gid'];
$str_contact_allow = $channel['channel_allow_cid'];
$str_group_deny = $channel['channel_deny_gid'];
$str_contact_deny = $channel['channel_deny_cid'];
}
2014-10-21 23:33:35 +00:00
elseif($walltowall) {
// use the channel owner's default permissions
$str_group_allow = $channel['channel_allow_gid'];
$str_contact_allow = $channel['channel_allow_cid'];
$str_group_deny = $channel['channel_deny_gid'];
$str_contact_deny = $channel['channel_deny_cid'];
}
else {
// use the posted permissions
$str_group_allow = perms2str($_REQUEST['group_allow']);
$str_contact_allow = perms2str($_REQUEST['contact_allow']);
$str_group_deny = perms2str($_REQUEST['group_deny']);
$str_contact_deny = perms2str($_REQUEST['contact_deny']);
}
$location = notags(trim($_REQUEST['location']));
$coord = notags(trim($_REQUEST['coord']));
$verb = notags(trim($_REQUEST['verb']));
2013-03-15 05:21:38 +00:00
$title = escape_tags(trim($_REQUEST['title']));
$body = $_REQUEST['body'];
$postopts = '';
2012-03-22 23:17:10 +00:00
2012-10-29 03:01:36 +00:00
$private = (
( strlen($str_group_allow)
|| strlen($str_contact_allow)
|| strlen($str_group_deny)
|| strlen($str_contact_deny)
2014-08-08 22:27:17 +00:00
|| strlen($public_policy)
2012-10-29 03:01:36 +00:00
) ? 1 : 0);
2011-03-18 12:06:16 +00:00
// If this is a comment, set the permissions from the parent.
if($parent_item) {
$private = 0;
2012-10-08 01:44:06 +00:00
if(($parent_item['item_private'])
2011-03-18 12:06:16 +00:00
|| strlen($parent_item['allow_cid'])
|| strlen($parent_item['allow_gid'])
|| strlen($parent_item['deny_cid'])
2014-08-08 22:27:17 +00:00
|| strlen($parent_item['deny_gid'])
|| strlen($parent_item['public_policy'])) {
2012-10-08 01:44:06 +00:00
$private = (($parent_item['item_private']) ? $parent_item['item_private'] : 1);
}
2014-08-08 22:27:17 +00:00
$public_policy = $parent_item['public_policy'];
$str_contact_allow = $parent_item['allow_cid'];
$str_group_allow = $parent_item['allow_gid'];
$str_contact_deny = $parent_item['deny_cid'];
$str_group_deny = $parent_item['deny_gid'];
2013-01-03 09:42:28 +00:00
$owner_hash = $parent_item['owner_xchan'];
2011-03-18 12:06:16 +00:00
}
if(! strlen($body)) {
2012-01-10 04:03:00 +00:00
if($preview)
killme();
info( t('Empty post discarded.') . EOL );
if(x($_REQUEST,'return'))
goaway($a->get_baseurl() . "/" . $return_path );
2011-03-18 12:06:16 +00:00
killme();
}
2010-07-12 23:43:59 +00:00
}
2014-07-02 01:21:22 +00:00
2014-06-20 03:38:38 +00:00
$expires = NULL_DATE;
if(feature_enabled($profile_uid,'content_expire')) {
if(x($_REQUEST,'expire')) {
$expires = datetime_convert(date_default_timezone_get(),'UTC', $_REQUEST['expire']);
if($expires <= datetime_convert())
$expires = NULL_DATE;
}
}
2013-03-15 05:21:38 +00:00
$post_type = notags(trim($_REQUEST['type']));
$mimetype = notags(trim($_REQUEST['mimetype']));
if(! $mimetype)
$mimetype = 'text/bbcode';
2013-03-15 05:21:38 +00:00
if($preview) {
$body = z_input_filter($profile_uid,$body,$mimetype);
}
2013-03-15 05:21:38 +00:00
2014-06-20 03:38:38 +00:00
// Verify ability to use html or php!!!
$execflag = false;
if($mimetype === 'application/x-php') {
$z = q("select account_id, account_roles, channel_pageflags from account left join channel on channel_account_id = account_id where channel_id = %d limit 1",
intval($profile_uid)
);
if($z && (($z[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE) || ($z[0]['channel_pageflags'] & PAGE_ALLOWCODE))) {
if($uid && (get_account_id() == $z[0]['account_id'])) {
$execflag = true;
}
else {
notice( t('Executable content type not permitted to this channel.') . EOL);
if(x($_REQUEST,'return'))
goaway($a->get_baseurl() . "/" . $return_path );
killme();
}
}
}
2014-06-20 03:38:38 +00:00
if($mimetype === 'text/bbcode') {
require_once('include/text.php');
if($uid && $uid == $profile_uid && feature_enabled($uid,'markdown')) {
require_once('include/bb2diaspora.php');
$body = escape_tags($body);
$body = preg_replace_callback('/\[share(.*?)\]/ism','share_shield',$body);
$body = diaspora2bb($body,true);
$body = preg_replace_callback('/\[share(.*?)\]/ism','share_unshield',$body);
2014-07-02 01:21:22 +00:00
}
// BBCODE alert: the following functions assume bbcode input
// and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.)
// we may need virtual or template classes to implement the possible alternatives
// Work around doubled linefeeds in Tinymce 3.5b2
// First figure out if it's a status post that would've been
// created using tinymce. Otherwise leave it alone.
$plaintext = true;
// $plaintext = ((feature_enabled($profile_uid,'richtext')) ? false : true);
// if((! $parent) && (! $api_source) && (! $plaintext)) {
// $body = fix_mce_lf($body);
// }
// If we're sending a private top-level message with a single @-taggable channel as a recipient, @-tag it, if our pconfig is set.
if((! $parent) && (get_pconfig($profile_uid,'system','tagifonlyrecip')) && (substr_count($str_contact_allow,'<') == 1) && ($str_group_allow == '') && ($str_contact_deny == '') && ($str_group_deny == '')) {
$x = q("select abook_id, abook_their_perms from abook where abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc(str_replace(array('<','>'),array('',''),$str_contact_allow)),
intval($profile_uid)
);
if($x && ($x[0]['abook_their_perms'] & PERMS_W_TAGWALL))
$body .= "\n\n@group+" . $x[0]['abook_id'] . "\n";
}
/**
* fix naked links by passing through a callback to see if this is a red site
* (already known to us) which will get a zrl, otherwise link with url, add bookmark tag to both.
* First protect any url inside certain bbcode tags so we don't double link it.
*/
2015-02-09 03:28:18 +00:00
2014-02-10 09:44:21 +00:00
$body = preg_replace_callback('/\[code(.*?)\[\/(code)\]/ism','red_escape_codeblock',$body);
$body = preg_replace_callback('/\[url(.*?)\[\/(url)\]/ism','red_escape_codeblock',$body);
$body = preg_replace_callback('/\[zrl(.*?)\[\/(zrl)\]/ism','red_escape_codeblock',$body);
2014-02-08 20:08:07 +00:00
$body = preg_replace_callback("/([^\]\='".'"'."]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\+\,]+)/ism", 'red_zrl_callback', $body);
2014-02-10 09:44:21 +00:00
$body = preg_replace_callback('/\[\$b64zrl(.*?)\[\/(zrl)\]/ism','red_unescape_codeblock',$body);
$body = preg_replace_callback('/\[\$b64url(.*?)\[\/(url)\]/ism','red_unescape_codeblock',$body);
$body = preg_replace_callback('/\[\$b64code(.*?)\[\/(code)\]/ism','red_unescape_codeblock',$body);
// fix any img tags that should be zmg
$body = preg_replace_callback('/\[img(.*?)\](.*?)\[\/img\]/ism','red_zrlify_img_callback',$body);
/**
*
* When a photo was uploaded into the message using the (profile wall) ajax
* uploader, The permissions are initially set to disallow anybody but the
* owner from seeing it. This is because the permissions may not yet have been
* set for the post. If it's private, the photo permissions should be set
* appropriately. But we didn't know the final permissions on the post until
* now. So now we'll look for links of uploaded photos and attachments that are in the
* post and set them to the same permissions as the post itself.
*
* If the post was end-to-end encrypted we can't find images and attachments in the body,
* use our media_str input instead which only contains these elements - but only do this
* when encrypted content exists because the photo/attachment may have been removed from
* the post and we should keep it private. If it's encrypted we have no way of knowing
* so we'll set the permissions regardless and realise that the media may not be
* referenced in the post.
*
* What is preventing us from being able to upload photos into comments is dealing with
* the photo and attachment permissions, since we don't always know who was in the
* distribution for the top level post.
*
* We might be able to provide this functionality with a lot of fiddling:
* - if the top level post is public (make the photo public)
* - if the top level post was written by us or a wall post that belongs to us (match the top level post)
* - if the top level post has privacy mentions, add those to the permissions.
* - otherwise disallow the photo *or* make the photo public. This is the part that gets messy.
*/
if(! $preview) {
fix_attached_photo_permissions($profile_uid,$owner_xchan['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny);
2011-05-25 09:08:15 +00:00
fix_attached_file_permissions($channel,$observer['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny);
2011-05-25 09:08:15 +00:00
}
$body = bb_translate_video($body);
2012-02-25 22:22:51 +00:00
/**
* Fold multi-line [code] sequences
*/
$body = preg_replace('/\[\/code\]\s*\[code\]/ism',"\n",$body);
$body = scale_external_images($body,false);
2014-06-20 03:38:38 +00:00
// Look for tags and linkify them
$results = linkify_tags($a, $body, ($uid) ? $uid : $profile_uid);
if($results) {
// Set permissions based on tag replacements
set_linkified_perms($results, $str_contact_allow, $str_group_allow, $profile_uid, $parent_item);
$post_tags = array();
foreach($results as $result) {
$success = $result['success'];
if($success['replaced']) {
$post_tags[] = array(
'uid' => $profile_uid,
'type' => $success['termtype'],
'otype' => TERM_OBJ_POST,
'term' => $success['term'],
'url' => $success['url']
);
}
2012-05-30 05:57:15 +00:00
}
}
$attachments = '';
$match = false;
if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) {
$attachments = array();
foreach($match[2] as $mtch) {
$hash = substr($mtch,0,strpos($mtch,','));
$rev = intval(substr($mtch,strpos($mtch,',')));
$r = attach_by_hash_nodata($hash,$rev);
if($r['success']) {
$attachments[] = array(
'href' => $a->get_baseurl() . '/attach/' . $r['data']['hash'],
'length' => $r['data']['filesize'],
'type' => $r['data']['filetype'],
'title' => urlencode($r['data']['filename']),
'revision' => $r['data']['revision']
);
}
$body = str_replace($match[1],'',$body);
2011-05-25 09:08:15 +00:00
}
}
}
2013-03-15 05:21:38 +00:00
// BBCODE end alert
if(strlen($categories)) {
$cats = explode(',',$categories);
foreach($cats as $cat) {
$post_tags[] = array(
'uid' => $profile_uid,
'type' => TERM_CATEGORY,
'otype' => TERM_OBJ_POST,
'term' => trim($cat),
2013-10-14 22:34:47 +00:00
'url' => $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat))
2013-03-15 05:21:38 +00:00
);
}
}
$item_unseen = ((local_channel() != $profile_uid) ? 1 : 0);
2010-09-27 00:24:20 +00:00
if($post_type === 'wall' || $post_type === 'wall-comment')
$item_flags = $item_flags | ITEM_WALL;
if($origin)
$item_flags = $item_flags | ITEM_ORIGIN;
2010-09-10 04:16:40 +00:00
if($moderated)
$item_restrict = $item_restrict | ITEM_MODERATED;
if($webpage)
$item_restrict = $item_restrict | $webpage;
2010-09-10 04:16:40 +00:00
if(! strlen($verb))
$verb = ACTIVITY_POST ;
2010-09-10 05:02:28 +00:00
2010-07-09 00:49:41 +00:00
$notify_type = (($parent) ? 'comment-new' : 'wall-new' );
2014-01-11 03:01:24 +00:00
if(! $mid) {
$mid = (($message_id) ? $message_id : item_message_id());
}
if(! $parent_mid) {
$parent_mid = $mid;
}
if($parent_item)
$parent_mid = $parent_item['mid'];
2010-08-10 08:21:38 +00:00
// Fallback so that we alway have a thr_parent
if(!$thr_parent)
$thr_parent = $mid;
$datarray = array();
if(! $parent) {
$item_flags = $item_flags | ITEM_THREAD_TOP;
}
2015-02-11 03:10:18 +00:00
if($consensus)
$item_flags |= ITEM_CONSENSUS;
if ((! $plink) && ($item_flags & ITEM_THREAD_TOP)) {
$plink = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $mid;
}
$datarray['aid'] = $channel['channel_account_id'];
$datarray['uid'] = $profile_uid;
$datarray['owner_xchan'] = (($owner_hash) ? $owner_hash : $owner_xchan['xchan_hash']);
$datarray['author_xchan'] = $observer['xchan_hash'];
$datarray['created'] = $created;
$datarray['edited'] = (($orig_post) ? datetime_convert() : $created);
$datarray['expires'] = $expires;
$datarray['commented'] = (($orig_post) ? datetime_convert() : $created);
$datarray['received'] = (($orig_post) ? datetime_convert() : $created);
$datarray['changed'] = (($orig_post) ? datetime_convert() : $created);
$datarray['mid'] = $mid;
$datarray['parent_mid'] = $parent_mid;
$datarray['mimetype'] = $mimetype;
$datarray['title'] = $title;
$datarray['body'] = $body;
$datarray['app'] = $app;
$datarray['location'] = $location;
$datarray['coord'] = $coord;
$datarray['verb'] = $verb;
$datarray['obj_type'] = $obj_type;
$datarray['allow_cid'] = $str_contact_allow;
$datarray['allow_gid'] = $str_group_allow;
$datarray['deny_cid'] = $str_contact_deny;
$datarray['deny_gid'] = $str_group_deny;
$datarray['item_private'] = $private;
$datarray['attach'] = $attachments;
$datarray['thr_parent'] = $thr_parent;
$datarray['postopts'] = $postopts;
$datarray['item_restrict'] = $item_restrict;
$datarray['item_flags'] = $item_flags;
$datarray['layout_mid'] = $layout_mid;
2014-08-07 02:24:46 +00:00
$datarray['public_policy'] = $public_policy;
$datarray['comment_policy'] = map_scope($channel['channel_w_comment']);
$datarray['term'] = $post_tags;
$datarray['plink'] = $plink;
$datarray['route'] = $route;
$datarray['item_unseen'] = $item_unseen;
2011-08-08 00:29:26 +00:00
2012-01-05 23:02:44 +00:00
// preview mode - prepare the body for display and send it via json
if($preview) {
require_once('include/conversation.php');
2012-11-03 12:46:56 +00:00
$datarray['owner'] = $owner_xchan;
$datarray['author'] = $observer;
2014-01-02 05:09:12 +00:00
$datarray['attach'] = json_encode($datarray['attach']);
2012-11-03 12:46:56 +00:00
$o = conversation($a,array($datarray),'search',false,'preview');
logger('preview: ' . $o, LOGGER_DEBUG);
2012-01-06 02:11:53 +00:00
echo json_encode(array('preview' => $o));
2012-01-05 23:02:44 +00:00
killme();
}
if($orig_post)
$datarray['edit'] = true;
2012-01-05 23:02:44 +00:00
call_hooks('post_local',$datarray);
if(x($datarray,'cancel')) {
logger('mod_item: post cancelled by plugin.');
if($return_path) {
goaway($a->get_baseurl() . "/" . $return_path);
}
$json = array('cancel' => 1);
if(x($_REQUEST,'jsreload') && strlen($_REQUEST['jsreload']))
$json['reload'] = $a->get_baseurl() . '/' . $_REQUEST['jsreload'];
echo json_encode($json);
killme();
}
2011-03-18 12:06:16 +00:00
if(mb_strlen($datarray['title']) > 255)
$datarray['title'] = mb_substr($datarray['title'],0,255);
if(array_key_exists('item_private',$datarray) && $datarray['item_private']) {
$datarray['body'] = z_input_filter($datarray['uid'],$datarray['body'],$datarray['mimetype']);
if($uid) {
2013-10-03 04:04:48 +00:00
if($channel['channel_hash'] === $datarray['author_xchan']) {
$datarray['sig'] = base64url_encode(rsa_sign($datarray['body'],$channel['channel_prvkey']));
$datarray['item_flags'] = $datarray['item_flags'] | ITEM_VERIFIED;
}
}
logger('Encrypting local storage');
$key = get_config('system','pubkey');
$datarray['item_flags'] = $datarray['item_flags'] | ITEM_OBSCURED;
if($datarray['title'])
$datarray['title'] = json_encode(crypto_encapsulate($datarray['title'],$key));
if($datarray['body'])
$datarray['body'] = json_encode(crypto_encapsulate($datarray['body'],$key));
}
2011-03-18 12:06:16 +00:00
if($orig_post) {
$datarray['id'] = $post_id;
item_store_update($datarray,$execflag);
2014-01-04 21:44:43 +00:00
update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remote_id,$mid);
if(! $nopush)
proc_run('php', "include/notifier.php", 'edit_post', $post_id);
if((x($_REQUEST,'return')) && strlen($return_path)) {
logger('return: ' . $return_path);
goaway($a->get_baseurl() . "/" . $return_path );
2011-03-18 12:06:16 +00:00
}
killme();
}
else
$post_id = 0;
$post = item_store($datarray,$execflag);
$post_id = $post['item_id'];
if($post_id) {
2010-11-25 10:53:19 +00:00
logger('mod_item: saved item ' . $post_id);
2010-08-10 08:21:38 +00:00
if($parent) {
// only send comment notification if this is a wall-to-wall comment,
// otherwise it will happen during delivery
if(($datarray['owner_xchan'] != $datarray['author_xchan']) && ($parent_item['item_flags'] & ITEM_WALL)) {
2011-12-26 22:16:25 +00:00
notification(array(
'type' => NOTIFY_COMMENT,
2013-02-07 04:29:17 +00:00
'from_xchan' => $datarray['author_xchan'],
'to_xchan' => $datarray['owner_xchan'],
2011-12-26 22:16:25 +00:00
'item' => $datarray,
'link' => $a->get_baseurl() . '/display/' . $datarray['mid'],
'verb' => ACTIVITY_POST,
'otype' => 'item',
'parent' => $parent,
'parent_mid' => $parent_item['mid']
2011-05-22 02:27:56 +00:00
));
}
2010-08-10 08:21:38 +00:00
}
else {
$parent = $post_id;
2013-02-07 04:29:17 +00:00
if($datarray['owner_xchan'] != $datarray['author_xchan']) {
2011-12-26 22:16:25 +00:00
notification(array(
'type' => NOTIFY_WALL,
2013-02-07 04:29:17 +00:00
'from_xchan' => $datarray['author_xchan'],
'to_xchan' => $datarray['owner_xchan'],
2011-12-26 22:16:25 +00:00
'item' => $datarray,
'link' => $a->get_baseurl() . '/display/' . $datarray['mid'],
'verb' => ACTIVITY_POST,
'otype' => 'item'
2011-05-22 02:27:56 +00:00
));
}
2010-07-01 23:48:07 +00:00
}
2010-07-07 06:08:38 +00:00
2010-08-10 08:21:38 +00:00
// photo comments turn the corresponding item visible to the profile wall
2010-10-06 07:33:11 +00:00
// This way we don't see every picture in your new photo album posted to your wall at once.
// They will show up as people comment on them.
if($parent_item['item_restrict'] & ITEM_HIDDEN) {
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` = %d WHERE `id` = %d",
intval($parent_item['item_restrict'] - ITEM_HIDDEN),
2010-08-10 08:21:38 +00:00
intval($parent_item['id'])
);
}
}
2011-02-04 21:37:04 +00:00
else {
logger('mod_item: unable to retrieve post that was just stored.');
2012-04-15 12:11:52 +00:00
notice( t('System error. Post not saved.') . EOL);
goaway($a->get_baseurl() . "/" . $return_path );
2011-02-04 21:37:04 +00:00
// NOTREACHED
}
2010-08-17 03:47:40 +00:00
2014-08-30 00:31:40 +00:00
if($parent) {
// Store the comment signature information in case we need to relay to Diaspora
$ditem = $datarray;
$ditem['author'] = $observer;
store_diaspora_comment_sig($ditem,$channel,$parent_item, $post_id, (($walltowall_comment) ? 1 : 0));
2014-08-30 00:31:40 +00:00
}
2014-01-04 21:44:43 +00:00
update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remote_id,$mid);
2011-04-26 11:39:27 +00:00
$datarray['id'] = $post_id;
2013-11-25 22:54:14 +00:00
$datarray['llink'] = $a->get_baseurl() . '/display/' . $channel['channel_address'] . '/' . $post_id;
call_hooks('post_local_end', $datarray);
2011-02-01 02:18:28 +00:00
if(! $nopush)
proc_run('php', 'include/notifier.php', $notify_type, $post_id);
2011-02-17 05:17:49 +00:00
logger('post_complete');
// figure out how to return, depending on from whence we came
if($api_source)
return $post;
2011-09-12 04:52:50 +00:00
if($return_path) {
goaway($a->get_baseurl() . "/" . $return_path);
2011-02-17 05:17:49 +00:00
}
2011-09-12 04:52:50 +00:00
2011-02-14 12:43:49 +00:00
$json = array('success' => 1);
if(x($_REQUEST,'jsreload') && strlen($_REQUEST['jsreload']))
$json['reload'] = $a->get_baseurl() . '/' . $_REQUEST['jsreload'];
2011-02-17 05:17:49 +00:00
logger('post_json: ' . print_r($json,true), LOGGER_DEBUG);
2011-02-14 12:43:49 +00:00
echo json_encode($json);
2011-02-12 11:14:59 +00:00
killme();
2011-02-04 21:37:04 +00:00
// NOTREACHED
2010-07-27 00:01:37 +00:00
}
2010-07-27 00:01:37 +00:00
function item_content(&$a) {
2015-01-29 04:58:59 +00:00
if((! local_channel()) && (! remote_channel()))
2010-07-27 00:01:37 +00:00
return;
require_once('include/security.php');
2014-03-28 03:28:48 +00:00
if((argc() == 3) && (argv(1) === 'drop') && intval(argv(2))) {
2014-05-14 10:10:36 +00:00
2011-06-16 03:43:39 +00:00
require_once('include/items.php');
2014-05-14 10:10:36 +00:00
$i = q("select id, uid, author_xchan, owner_xchan, source_xchan, item_restrict from item where id = %d limit 1",
intval(argv(2))
2014-03-28 03:28:48 +00:00
);
2014-03-28 03:43:37 +00:00
2014-03-28 03:28:48 +00:00
if($i) {
2014-03-28 08:12:52 +00:00
$can_delete = false;
2014-03-28 08:19:30 +00:00
$local_delete = false;
2015-01-29 04:56:04 +00:00
if(local_channel() && local_channel() == $i[0]['uid'])
2014-03-28 08:19:30 +00:00
$local_delete = true;
2014-03-28 03:43:37 +00:00
$ob_hash = get_observer_hash();
2014-03-28 08:12:52 +00:00
if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan']))
$can_delete = true;
2014-03-28 08:19:30 +00:00
if(! ($can_delete || $local_delete)) {
2014-03-28 03:43:37 +00:00
notice( t('Permission denied.') . EOL);
return;
}
2014-03-28 08:19:30 +00:00
// if this is a different page type or it's just a local delete
// but not by the item author or owner, do a simple deletion
if($i[0]['item_restrict'] || ($local_delete && (! $can_delete))) {
2014-03-28 03:28:48 +00:00
drop_item($i[0]['id']);
2014-03-28 08:19:30 +00:00
}
2014-03-28 03:28:48 +00:00
else {
2014-03-28 08:19:30 +00:00
// complex deletion that needs to propagate and be performed in phases
2014-03-28 03:28:48 +00:00
drop_item($i[0]['id'],true,DROPITEM_PHASE1);
2014-03-28 03:43:37 +00:00
tag_deliver($i[0]['uid'],$i[0]['id']);
2014-03-28 03:28:48 +00:00
}
}
2010-07-27 00:01:37 +00:00
}
2011-05-22 04:40:16 +00:00
}
2012-03-09 11:57:11 +00:00
2012-10-29 03:01:36 +00:00
function fix_attached_photo_permissions($uid,$xchan_hash,$body,
$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny) {
if(get_pconfig($uid,'system','force_public_uploads')) {
$str_contact_allow = $str_group_allow = $str_contact_deny = $str_group_deny = '';
}
2012-10-29 03:01:36 +00:00
$match = null;
2013-05-28 11:50:16 +00:00
// match img and zmg image links
if(preg_match_all("/\[[zi]mg(.*?)\](.*?)\[\/[zi]mg\]/",$body,$match)) {
$images = $match[2];
2012-10-29 03:01:36 +00:00
if($images) {
foreach($images as $image) {
if(! stristr($image,get_app()->get_baseurl() . '/photo/'))
2012-10-29 03:01:36 +00:00
continue;
$image_uri = substr($image,strrpos($image,'/') + 1);
if(strpos($image_uri,'-') !== false)
$image_uri = substr($image_uri,0, strpos($image_uri,'-'));
if(strpos($image_uri,'.') !== false)
$image_uri = substr($image_uri,0, strpos($image_uri,'.'));
2012-10-29 03:01:36 +00:00
if(! strlen($image_uri))
continue;
$srch = '<' . $xchan_hash . '>';
$r = q("SELECT id FROM photo
WHERE allow_cid = '%s' AND allow_gid = '' AND deny_cid = '' AND deny_gid = ''
AND resource_id = '%s' AND uid = %d LIMIT 1",
dbesc($srch),
dbesc($image_uri),
intval($uid)
);
if($r) {
$r = q("UPDATE photo SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s'
WHERE resource_id = '%s' AND uid = %d ",
2012-10-29 03:01:36 +00:00
dbesc($str_contact_allow),
dbesc($str_group_allow),
dbesc($str_contact_deny),
dbesc($str_group_deny),
dbesc($image_uri),
intval($uid)
2012-10-29 03:01:36 +00:00
);
// also update the linked item (which is probably invisible)
$r = q("select id from item
WHERE allow_cid = '%s' AND allow_gid = '' AND deny_cid = '' AND deny_gid = ''
AND resource_id = '%s' and resource_type = 'photo' AND uid = %d LIMIT 1",
dbesc($srch),
dbesc($image_uri),
intval($uid)
);
if($r) {
$private = (($str_contact_allow || $str_group_allow || $str_contact_deny || $str_group_deny) ? true : false);
$r = q("UPDATE item SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', item_private = %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
WHERE id = %d AND uid = %d",
dbesc($str_contact_allow),
dbesc($str_group_allow),
dbesc($str_contact_deny),
dbesc($str_group_deny),
intval($private),
intval($r[0]['id']),
intval($uid)
);
}
2012-10-29 03:01:36 +00:00
}
}
}
}
}
function fix_attached_file_permissions($channel,$observer_hash,$body,
2012-10-29 03:01:36 +00:00
$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny) {
if(get_pconfig($channel['channel_id'],'system','force_public_uploads')) {
$str_contact_allow = $str_group_allow = $str_contact_deny = $str_group_deny = '';
}
2012-10-29 03:01:36 +00:00
$match = false;
if(preg_match_all("/\[attachment\](.*?)\[\/attachment\]/",$body,$match)) {
$attaches = $match[1];
if($attaches) {
foreach($attaches as $attach) {
$hash = substr($attach,0,strpos($attach,','));
$rev = intval(substr($attach,strpos($attach,',')));
attach_store($channel,$observer_hash,$options = 'update', array(
'hash' => $hash,
'revision' => $rev,
'allow_cid' => $str_contact_allow,
'allow_gid' => $str_group_allow,
'deny_cid' => $str_contact_deny,
'deny_gid' => $str_group_deny
));
2012-10-29 03:01:36 +00:00
}
}
}
}
function item_check_service_class($channel_id,$iswebpage) {
$ret = array('success' => false, $message => '');
if ($iswebpage) {
$r = q("select count(i.id) as total from item i
right join channel c on (i.author_xchan=c.channel_hash and i.uid=c.channel_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
and i.parent=i.id and (i.item_restrict & %d)>0 and not (i.item_restrict & %d)>0 and i.uid= %d ",
intval(ITEM_WEBPAGE),
intval(ITEM_DELETED),
intval($channel_id)
);
}
else {
$r = q("select count(i.id) as total from item i
right join channel c on (i.author_xchan=c.channel_hash and i.uid=c.channel_id )
and i.parent=i.id and (i.item_restrict=0) and i.uid= %d ",
intval($channel_id)
);
}
if(! ($r && count($r))) {
$ret['message'] = t('Unable to obtain identity information from database');
return $ret;
}
if (!$iswebpage) {
if(! service_class_allows($channel_id,'total_items',$r[0]['total'])) {
$result['message'] .= upgrade_message().sprintf(t("You have reached your limit of %1$.0f top level posts."),$r[0]['total']);
return $result;
}
}
else {
if(! service_class_allows($channel_id,'total_pages',$r[0]['total'])) {
$result['message'] .= upgrade_message().sprintf(t("You have reached your limit of %1$.0f webpages."),$r[0]['total']);
return $result;
}
}
$ret['success'] = true;
return $ret;
}
2014-08-30 00:31:40 +00:00