Merge remote-tracking branch 'upstream/develop' into develop

This commit is contained in:
Ralf Thees 2018-08-23 16:58:18 +02:00
commit 9b5bef6dea
41 changed files with 889 additions and 673 deletions

View file

@ -634,6 +634,73 @@ Friendica doesn't allow showing the friends of other users.
* trim_user
* contributor_details
---
### Return values for statuses/* api calls
Returned status object is conform to GNU Social/Twitter api.
Friendica adds some addictional fields:
- owner: a user object, it's the owner of the item.
- private: boolean, true if the item is marked as private
- activities: map with activities related to the item. Every activity is a list of user objects.
This properties are prefixed with "friendica_" in JSON responses and namespaced under "http://friendi.ca/schema/api/1/" in XML responses
JSON:
```json
[
{
// ...
'friendica_owner' : {
// user object
},
'friendica_private' : true,
'friendica_activities': {
'like': [
{
// user object
},
// ...
],
'dislike': [],
'attendyes': [],
'attendno': [],
'attendmaybe': []
}
},
// ...
]
```
XML:
```xml
<statuses xmlns="http://api.twitter.com" xmlns:statusnet="http://status.net/schema/api/1/" xmlns:friendica="http://friendi.ca/schema/api/1/" xmlns:georss="http://www.georss.org/georss">
<status>
<!-- ... -->
<friendica:owner><!-- user object --></friendica:owner>
<friendica:private>true</friendica:private>
<friendica:activities>
<friendica:like>
<user>
<!-- user object -->
</user>
<!-- ... --->
</friendica:like>
<friendica:dislike/>
<friendica:attendyes/>
<friendica:attendno/>
<friendica:attendmaybe/>
</friendica:activities>
</status>
<!-- ... -->
</statuses>
```
---
### statusnet/config (*)

View file

@ -2888,6 +2888,7 @@ function api_format_items($r, $user_info, $filter_user = false, $type = "json")
'favorited' => $item['starred'] ? true : false,
'user' => $status_user ,
'friendica_owner' => $owner_user,
'friendica_private' => $item['private'] == 1,
//'entities' => NULL,
'statusnet_html' => $converted["html"],
'statusnet_conversation_id' => $item['parent'],

View file

@ -471,6 +471,7 @@ function conversation(App $a, array $items, $mode, $update, $preview = false, $o
. "'; var profile_page = " . $a->pager['page'] . "; </script>\r\n";
}
} elseif ($mode === 'profile') {
$items = conversation_add_children($items, false, $order, $uid);
$profile_owner = $a->profile['profile_uid'];
if (!$update) {
@ -490,6 +491,7 @@ function conversation(App $a, array $items, $mode, $update, $preview = false, $o
}
}
} elseif ($mode === 'notes') {
$items = conversation_add_children($items, false, $order, $uid);
$profile_owner = local_user();
if (!$update) {
@ -498,6 +500,7 @@ function conversation(App $a, array $items, $mode, $update, $preview = false, $o
. "; var netargs = '/?f='; var profile_page = " . $a->pager['page'] . "; </script>\r\n";
}
} elseif ($mode === 'display') {
$items = conversation_add_children($items, false, $order, $uid);
$profile_owner = $a->profile['uid'];
if (!$update) {

View file

@ -5,9 +5,9 @@ use Friendica\Database\DBA;
/**
* @brief execute SQL query with printf style args - deprecated
*
* Please use the dba:: functions instead:
* dba::select, dba::exists, dba::insert
* dba::delete, dba::update, dba::p, dba::e
* Please use the DBA:: functions instead:
* DBA::select, DBA::exists, DBA::insert
* DBA::delete, DBA::update, DBA::p, DBA::e
*
* @param $args Query parameters (1 to N parameters of different types)
* @return array|bool Query array

View file

@ -32,6 +32,20 @@ function notification($params)
logger('Missing parameters.' . System::callstack());
}
// Ensure that the important fields are set at any time
$fields = ['notify-flags', 'language', 'username', 'email'];
$user = DBA::selectFirst('user', $fields, ['uid' => $params['uid']]);
if (!DBA::isResult($user)) {
logger('Unknown user ' . $params['uid']);
return;
}
$params['notify_flags'] = defaults($params, 'notify_flags', $user['notify-flags']);
$params['language'] = defaults($params, 'language', $user['language']);
$params['to_name'] = defaults($params, 'to_name', $user['username']);
$params['to_email'] = defaults($params, 'to_email', $user['email']);
// from here on everything is in the recipients language
L10n::pushLang($params['language']);
@ -510,7 +524,7 @@ function notification($params)
}
// send email notification if notification preferences permit
if ((!empty($params['notify_flags']) & intval($params['type']))
if ((intval($params['notify_flags']) & intval($params['type']))
|| $params['type'] == NOTIFY_SYSTEM
|| $params['type'] == SYSTEM_EMAIL) {
@ -661,7 +675,7 @@ function check_item_notification($itemid, $uid, $defaulttype = "") {
$profiles = $notification_data["profiles"];
$fields = ['notify-flags', 'language', 'username', 'email', 'nickname'];
$fields = ['nickname'];
$user = DBA::selectFirst('user', $fields, ['uid' => $uid]);
if (!DBA::isResult($user)) {
return false;
@ -724,10 +738,6 @@ function check_item_notification($itemid, $uid, $defaulttype = "") {
// Generate the notification array
$params = [];
$params["uid"] = $uid;
$params["notify_flags"] = $user["notify-flags"];
$params["language"] = $user["language"];
$params["to_name"] = $user["username"];
$params["to_email"] = $user["email"];
$params["item"] = $item;
$params["parent"] = $item["parent"];
$params["link"] = System::baseUrl().'/display/'.urlencode($item["guid"]);

View file

@ -371,7 +371,7 @@ function drop_item($id)
if ((local_user() == $item['uid']) || $contact_id) {
// Check if we should do HTML-based delete confirmation
if ($_REQUEST['confirm']) {
if (!empty($_REQUEST['confirm'])) {
// <form> can't take arguments in its "action" parameter
// so add any arguments as hidden inputs
$query = explode_querystring($a->query_string);
@ -395,7 +395,7 @@ function drop_item($id)
]);
}
// Now check how the user responded to the confirmation query
if ($_REQUEST['canceled']) {
if (!empty($_REQUEST['canceled'])) {
goaway(System::baseUrl() . '/' . $_SESSION['return_url']);
}

View file

@ -10,6 +10,7 @@ use Friendica\Core\Config;
use Friendica\Core\L10n;
use Friendica\Core\PConfig;
use Friendica\Database\DBA;
use Friendica\Model\Contact;
function community_init(App $a)
{
@ -35,6 +36,25 @@ function community_content(App $a, $update = 0)
return;
}
$accounttype = null;
if ($a->argc > 2) {
switch ($a->argv[2]) {
case 'person':
$accounttype = Contact::ACCOUNT_TYPE_PERSON;
break;
case 'organisation':
$accounttype = Contact::ACCOUNT_TYPE_ORGANISATION;
break;
case 'news':
$accounttype = Contact::ACCOUNT_TYPE_NEWS;
break;
case 'community':
$accounttype = Contact::ACCOUNT_TYPE_COMMUNITY;
break;
}
}
if ($a->argc > 1) {
$content = $a->argv[1];
} else {
@ -135,7 +155,7 @@ function community_content(App $a, $update = 0)
$a->set_pager_itemspage($itemspage_network);
$r = community_getitems($a->pager['start'], $a->pager['itemspage'], $content);
$r = community_getitems($a->pager['start'], $a->pager['itemspage'], $content, $accounttype);
if (!DBA::isResult($r)) {
info(L10n::t('No results.') . EOL);
@ -164,7 +184,7 @@ function community_content(App $a, $update = 0)
}
}
if (count($s) < $a->pager['itemspage']) {
$r = community_getitems($a->pager['start'] + ($count * $a->pager['itemspage']), $a->pager['itemspage'], $content);
$r = community_getitems($a->pager['start'] + ($count * $a->pager['itemspage']), $a->pager['itemspage'], $content, $accounttype);
}
} while ((count($s) < $a->pager['itemspage']) && ( ++$count < 50) && (count($r) > 0));
} else {
@ -186,24 +206,40 @@ function community_content(App $a, $update = 0)
]);
}
function community_getitems($start, $itemspage, $content)
function community_getitems($start, $itemspage, $content, $accounttype)
{
if ($content == 'local') {
if (!is_null($accounttype)) {
$sql_accounttype = " AND `user`.`account-type` = ?";
$values = [$accounttype, $start, $itemspage];
} else {
$sql_accounttype = "";
$values = [$start, $itemspage];
}
$r = DBA::p("SELECT `item`.`uri`, `author`.`url` AS `author-link` FROM `thread`
INNER JOIN `user` ON `user`.`uid` = `thread`.`uid` AND NOT `user`.`hidewall`
INNER JOIN `item` ON `item`.`id` = `thread`.`iid`
INNER JOIN `contact` AS `author` ON `author`.`id`=`item`.`author-id`
WHERE `thread`.`visible` AND NOT `thread`.`deleted` AND NOT `thread`.`moderated`
AND NOT `thread`.`private` AND `thread`.`wall` AND `thread`.`origin`
ORDER BY `thread`.`commented` DESC LIMIT " . intval($start) . ", " . intval($itemspage)
);
AND NOT `thread`.`private` AND `thread`.`wall` AND `thread`.`origin` $sql_accounttype
ORDER BY `thread`.`commented` DESC LIMIT ?, ?", $values);
return DBA::toArray($r);
} elseif ($content == 'global') {
if (!is_null($accounttype)) {
$sql_accounttype = " AND `owner`.`contact-type` = ?";
$values = [$accounttype, $start, $itemspage];
} else {
$sql_accounttype = "";
$values = [$start, $itemspage];
}
$r = DBA::p("SELECT `uri` FROM `thread`
INNER JOIN `item` ON `item`.`id` = `thread`.`iid`
INNER JOIN `contact` AS `author` ON `author`.`id`=`item`.`author-id`
WHERE `thread`.`uid` = 0 AND NOT `author`.`hidden` AND NOT `author`.`blocked`
ORDER BY `thread`.`commented` DESC LIMIT " . intval($start) . ", " . intval($itemspage));
INNER JOIN `contact` AS `owner` ON `owner`.`id`=`item`.`owner-id`
WHERE `thread`.`uid` = 0 AND NOT `author`.`hidden` AND NOT `author`.`blocked` $sql_accounttype
ORDER BY `thread`.`commented` DESC LIMIT ?, ?", $values);
return DBA::toArray($r);
}

View file

@ -71,7 +71,7 @@ function dfrn_notify_post(App $a) {
$user = DBA::selectFirst('user', ['uid'], ['nickname' => $a->argv[1]]);
if (!DBA::isResult($user)) {
logger('User not found for nickname ' . $$a->argv[1]);
logger('User not found for nickname ' . $a->argv[1]);
System::xmlExit(3, 'User not found');
}
@ -280,7 +280,7 @@ function dfrn_notify_content(App $a) {
$user = DBA::selectFirst('user', ['uid'], ['nickname' => $a->argv[1]]);
if (!DBA::isResult($user)) {
logger('User not found for nickname ' . $$a->argv[1]);
logger('User not found for nickname ' . $a->argv[1]);
killme();
}

View file

@ -480,6 +480,12 @@ function dfrn_poll_content(App $a)
}
if (($type === 'profile') && (strlen($sec))) {
// heluecht: I don't know why we don't fail immediately when the user or contact hadn't been found.
// Since it doesn't make sense to continue from this point on, we now fail here. This should be safe.
if (!DBA::isResult($r)) {
System::httpExit(404, ["title" => L10n::t('Page not found.')]);
}
// URL reply
if ($dfrn_version < 2.2) {
$s = Network::fetchUrl($r[0]['poll']

View file

@ -333,35 +333,34 @@ function display_content(App $a, $update = false, $update_uid = 0)
return '';
}
$condition = ["`item`.`parent-uri` = (SELECT `parent-uri` FROM `item` WHERE `id` = ?)
AND `item`.`uid` IN (0, ?) " . $sql_extra, $item_id, local_user()];
$params = ['order' => ['uid', 'parent' => true, 'gravity', 'id']];
$items_obj = Item::selectForUser(local_user(), [], $condition, $params);
$condition = ["`id` = ? AND `item`.`uid` IN (0, ?) " . $sql_extra, $item_id, local_user()];
$fields = ['parent-uri', 'body', 'title', 'author-name', 'author-avatar', 'plink'];
$item = Item::selectFirstForUser(local_user(), $fields, $condition);
if (!DBA::isResult($items_obj)) {
if (!DBA::isResult($item)) {
notice(L10n::t('Item not found.') . EOL);
return $o;
}
$item['uri'] = $item['parent-uri'];
if ($unseen) {
$condition = ['parent-uri' => $item_parent_uri, 'uid' => local_user(), 'unseen' => true];
Item::update(['unseen' => false], $condition);
}
$items = Item::inArray($items_obj);
$conversation_items = conv_sort($items, "`commented`");
if (!$update) {
$o .= "<script> var netargs = '?f=&item_id=" . $item_id . "'; </script>";
}
$o .= conversation($a, $conversation_items, 'display', $update_uid, false, 'commented', local_user());
$o .= conversation($a, [$item], 'display', $update_uid, false, 'commented', local_user());
// Preparing the meta header
$description = trim(HTML::toPlaintext(BBCode::convert($items[0]["body"], false), 0, true));
$title = trim(HTML::toPlaintext(BBCode::convert($items[0]["title"], false), 0, true));
$author_name = $items[0]["author-name"];
$description = trim(HTML::toPlaintext(BBCode::convert($item["body"], false), 0, true));
$title = trim(HTML::toPlaintext(BBCode::convert($item["title"], false), 0, true));
$author_name = $item["author-name"];
$image = $a->remove_baseurl($items[0]["author-avatar"]);
$image = $a->remove_baseurl($item["author-avatar"]);
if ($title == "") {
$title = $author_name;
@ -393,7 +392,7 @@ function display_content(App $a, $update = false, $update_uid = 0)
$a->page['htmlhead'] .= '<meta name="twitter:title" content="'.$title.'" />'."\n";
$a->page['htmlhead'] .= '<meta name="twitter:description" content="'.$description.'" />'."\n";
$a->page['htmlhead'] .= '<meta name="twitter:image" content="'.System::baseUrl().'/'.$image.'" />'."\n";
$a->page['htmlhead'] .= '<meta name="twitter:url" content="'.$items[0]["plink"].'" />'."\n";
$a->page['htmlhead'] .= '<meta name="twitter:url" content="'.$item["plink"].'" />'."\n";
// Dublin Core
$a->page['htmlhead'] .= '<meta name="DC.title" content="'.$title.'" />'."\n";
@ -403,7 +402,7 @@ function display_content(App $a, $update = false, $update_uid = 0)
$a->page['htmlhead'] .= '<meta property="og:type" content="website" />'."\n";
$a->page['htmlhead'] .= '<meta property="og:title" content="'.$title.'" />'."\n";
$a->page['htmlhead'] .= '<meta property="og:image" content="'.System::baseUrl().'/'.$image.'" />'."\n";
$a->page['htmlhead'] .= '<meta property="og:url" content="'.$items[0]["plink"].'" />'."\n";
$a->page['htmlhead'] .= '<meta property="og:url" content="'.$item["plink"].'" />'."\n";
$a->page['htmlhead'] .= '<meta property="og:description" content="'.$description.'" />'."\n";
$a->page['htmlhead'] .= '<meta name="og:article:author" content="'.$author_name.'" />'."\n";
// article:tag

View file

@ -16,9 +16,7 @@ use Friendica\Util\Proxy as ProxyUtils;
function follow_post(App $a)
{
if (!local_user()) {
notice(L10n::t('Permission denied.'));
goaway($_SESSION['return_url']);
// NOTREACHED
System::httpExit(403, ['title' => L10n::t('Access denied.')]);
}
if (isset($_REQUEST['cancel'])) {

View file

@ -72,7 +72,20 @@ function install_post(App $a) {
// connect to db
DBA::connect($dbhost, $dbuser, $dbpass, $dbdata);
Install::install($urlpath, $dbhost, $dbuser, $dbpass, $dbdata, $phpath, $timezone, $language, $adminmail);
$errors = Install::createConfig($urlpath, $dbhost, $dbuser, $dbpass, $dbdata, $phpath, $timezone, $language, $adminmail);
if ($errors) {
$a->data['db_failed'] = $errors;
return;
}
$errors = Install::installDatabaseStructure();
if ($errors) {
$a->data['db_failed'] = $errors;
} else {
$a->data['db_installed'] = true;
}
return;
break;

View file

@ -65,26 +65,13 @@ function notes_content(App $a, $update = false)
$params = ['order' => ['created' => true],
'limit' => [$a->pager['start'], $a->pager['itemspage']]];
$r = Item::selectForUser(local_user(), ['id'], $condition, $params);
$r = Item::selectThreadForUser(local_user(), ['uri'], $condition, $params);
$count = 0;
if (DBA::isResult($r)) {
$count = count($r);
$parents_arr = [];
while ($rr = Item::fetch($r)) {
$parents_arr[] = $rr['id'];
}
DBA::close($r);
$condition = ['uid' => local_user(), 'parent' => $parents_arr];
$result = Item::selectForUser(local_user(), [], $condition);
if (DBA::isResult($result)) {
$items = conv_sort(Item::inArray($result), 'commented');
$o .= conversation($a, $items, 'notes', $update);
}
$o .= conversation($a, DBA::toArray($r), 'notes', $update);
}
$o .= alt_pager($a, $count);

View file

@ -1093,6 +1093,12 @@ function photos_content(App $a)
'$albumselect' => $albumselect,
'$permissions' => L10n::t('Permissions'),
'$aclselect' => $aclselect_e,
'$lockstate' => is_array($a->user)
&& (strlen($a->user['allow_cid'])
|| strlen($a->user['allow_gid'])
|| strlen($a->user['deny_cid'])
|| strlen($a->user['deny_gid'])
) ? 'lock' : 'unlock',
'$alt_uploader' => $ret['addon_text'],
'$default_upload_box' => ($ret['default_upload'] ? $default_upload_box : ''),
'$default_upload_submit' => ($ret['default_upload'] ? $default_upload_submit : ''),

View file

@ -23,7 +23,7 @@ use Friendica\Util\DateTimeFormat;
function profile_init(App $a)
{
if (!x($a->page, 'aside')) {
if (empty($a->page['aside'])) {
$a->page['aside'] = '';
}
@ -54,15 +54,15 @@ function profile_init(App $a)
$blocked = !local_user() && !remote_user() && Config::get('system', 'block_public');
$userblock = !local_user() && !remote_user() && $a->profile['hidewall'];
if (x($a->profile, 'page-flags') && $a->profile['page-flags'] == Contact::PAGE_COMMUNITY) {
if (!empty($a->profile['page-flags']) && $a->profile['page-flags'] == Contact::PAGE_COMMUNITY) {
$a->page['htmlhead'] .= '<meta name="friendica.community" content="true" />';
}
if (x($a->profile, 'openidserver')) {
if (!empty($a->profile['openidserver'])) {
$a->page['htmlhead'] .= '<link rel="openid.server" href="' . $a->profile['openidserver'] . '" />' . "\r\n";
}
if (x($a->profile, 'openid')) {
if (!empty($a->profile['openid'])) {
$delegate = strstr($a->profile['openid'], '://') ? $a->profile['openid'] : 'https://' . $a->profile['openid'];
$a->page['htmlhead'] .= '<link rel="openid.delegate" href="' . $delegate . '" />' . "\r\n";
}
@ -109,7 +109,7 @@ function profile_content(App $a, $update = 0)
}
}
if (!x($category)) {
if (empty($category)) {
$category = defaults($_GET, 'category', '');
}
@ -140,7 +140,7 @@ function profile_content(App $a, $update = 0)
$contact_id = 0;
if (x($_SESSION, 'remote') && is_array($_SESSION['remote'])) {
if (!empty($_SESSION['remote'])) {
foreach ($_SESSION['remote'] as $v) {
if ($v['uid'] == $a->profile['profile_uid']) {
$contact_id = $v['cid'];
@ -171,14 +171,14 @@ function profile_content(App $a, $update = 0)
$is_owner = local_user() == $a->profile['profile_uid'];
$last_updated_key = "profile:" . $a->profile['profile_uid'] . ":" . local_user() . ":" . remote_user();
if (x($a->profile, 'hidewall') && !$is_owner && !$remote_contact) {
if (!empty($a->profile['hidewall']) && !$is_owner && !$remote_contact) {
notice(L10n::t('Access to this profile has been restricted.') . EOL);
return;
}
if (!$update) {
$tab = false;
if (x($_GET, 'tab')) {
if (!empty($_GET['tab'])) {
$tab = notags(trim($_GET['tab']));
}
@ -196,7 +196,7 @@ function profile_content(App $a, $update = 0)
$commvisitor = $commpage && $remote_contact;
$a->page['aside'] .= posted_date_widget(System::baseUrl(true) . '/profile/' . $a->profile['nickname'], $a->profile['profile_uid'], true);
$a->page['aside'] .= Widget::categories(System::baseUrl(true) . '/profile/' . $a->profile['nickname'], (x($category) ? xmlify($category) : ''));
$a->page['aside'] .= Widget::categories(System::baseUrl(true) . '/profile/' . $a->profile['nickname'], (!empty($category) ? xmlify($category) : ''));
$a->page['aside'] .= Widget::tagCloud();
if (can_write_wall($a->profile['profile_uid'])) {
@ -227,7 +227,7 @@ function profile_content(App $a, $update = 0)
$sql_extra2 = '';
if ($update) {
$last_updated = (x($_SESSION['last_updated'], $last_updated_key) ? $_SESSION['last_updated'][$last_updated_key] : 0);
$last_updated = (!empty($_SESSION['last_updated'][$last_updated_key]) ? $_SESSION['last_updated'][$last_updated_key] : 0);
// If the page user is the owner of the page we should query for unseen
// items. Otherwise use a timestamp of the last succesful update request.
@ -238,7 +238,7 @@ function profile_content(App $a, $update = 0)
$sql_extra4 = " AND `item`.`received` > '" . $gmupdate . "'";
}
$r = q("SELECT distinct(parent) AS `item_id`, `item`.`network` AS `item_network`, `item`.`created`
$items = q("SELECT DISTINCT(`parent-uri`) AS `uri`
FROM `item` INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
AND NOT `contact`.`blocked` AND NOT `contact`.`pending`
WHERE `item`.`uid` = %d AND `item`.`visible` AND
@ -250,38 +250,33 @@ function profile_content(App $a, $update = 0)
intval($a->profile['profile_uid']), intval(GRAVITY_ACTIVITY)
);
if (!DBA::isResult($r)) {
if (!DBA::isResult($items)) {
return '';
}
} else {
$sql_post_table = "";
if (x($category)) {
if (!empty($category)) {
$sql_post_table = sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ",
DBA::escape(protect_sprintf($category)), intval(TERM_OBJ_POST), intval(TERM_CATEGORY), intval($a->profile['profile_uid']));
}
if (x($hashtags)) {
if (!empty($hashtags)) {
$sql_post_table .= sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ",
DBA::escape(protect_sprintf($hashtags)), intval(TERM_OBJ_POST), intval(TERM_HASHTAG), intval($a->profile['profile_uid']));
}
if ($datequery) {
if (!empty($datequery)) {
$sql_extra2 .= protect_sprintf(sprintf(" AND `thread`.`created` <= '%s' ", DBA::escape(DateTimeFormat::convert($datequery, 'UTC', date_default_timezone_get()))));
}
if ($datequery2) {
if (!empty($datequery2)) {
$sql_extra2 .= protect_sprintf(sprintf(" AND `thread`.`created` >= '%s' ", DBA::escape(DateTimeFormat::convert($datequery2, 'UTC', date_default_timezone_get()))));
}
// Belongs the profile page to a forum?
// Does the profile page belong to a forum?
// If not then we can improve the performance with an additional condition
$r = q("SELECT `uid` FROM `user` WHERE `uid` = %d AND `page-flags` IN (%d, %d)",
intval($a->profile['profile_uid']),
intval(Contact::PAGE_COMMUNITY),
intval(Contact::PAGE_PRVGROUP)
);
if (!DBA::isResult($r)) {
$condition = ['uid' => $a->profile['profile_uid'], 'page-flags' => [Contact::PAGE_COMMUNITY, Contact::PAGE_PRVGROUP]];
if (!DBA::exists('user', $condition)) {
$sql_extra3 = sprintf(" AND `thread`.`contact-id` = %d ", intval(intval($a->profile['contact_id'])));
} else {
$sql_extra3 = "";
@ -305,7 +300,7 @@ function profile_content(App $a, $update = 0)
$pager_sql = sprintf(" LIMIT %d, %d ", intval($a->pager['start']), intval($a->pager['itemspage']));
$r = q("SELECT `thread`.`iid` AS `item_id`, `thread`.`network` AS `item_network`
$items = q("SELECT `item`.`uri`
FROM `thread`
STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid`
$sql_post_table
@ -321,31 +316,15 @@ function profile_content(App $a, $update = 0)
);
}
$parents_arr = [];
$parents_str = '';
// Set a time stamp for this page. We will make use of it when we
// search for new items (update routine)
$_SESSION['last_updated'][$last_updated_key] = time();
if (DBA::isResult($r)) {
foreach ($r as $rr) {
$parents_arr[] = $rr['item_id'];
}
$condition = ['uid' => $a->profile['profile_uid'], 'parent' => $parents_arr];
$result = Item::selectForUser($a->profile['profile_uid'], [], $condition);
$items = conv_sort(Item::inArray($result), 'created');
} else {
$items = [];
}
if ($is_owner && !$update && !Config::get('theme', 'hide_eventlist')) {
$o .= Profile::getBirthdays();
$o .= Profile::getEventsReminderHTML();
}
if ($is_owner) {
$unseen = Item::exists(['wall' => true, 'unseen' => true, 'uid' => local_user()]);
if ($unseen) {

View file

@ -23,7 +23,7 @@ function redir_init(App $a) {
}
if (!empty($cid)) {
$fields = ['id', 'uid', 'nurl', 'url', 'addr', 'name', 'network', 'poll', 'issued-id', 'dfrn-id', 'duplex'];
$fields = ['id', 'uid', 'nurl', 'url', 'addr', 'name', 'network', 'poll', 'issued-id', 'dfrn-id', 'duplex', 'pending'];
$contact = DBA::selectFirst('contact', $fields, ['id' => $cid, 'uid' => [0, local_user()]]);
if (!DBA::isResult($contact)) {
notice(L10n::t('Contact not found.'));
@ -80,7 +80,7 @@ function redir_init(App $a) {
}
// Doing remote auth with dfrn.
if (local_user()&& (!empty($contact['dfrn-id']) || !empty($contact['issued-id']))) {
if (local_user() && (!empty($contact['dfrn-id']) || !empty($contact['issued-id'])) && empty($contact['pending'])) {
$dfrn_id = $orig_id = (($contact['issued-id']) ? $contact['issued-id'] : $contact['dfrn-id']);
if ($contact['duplex'] && $contact['issued-id']) {

View file

@ -140,6 +140,8 @@ class App
* @brief App constructor.
*
* @param string $basepath Path to the app base folder
*
* @throws Exception if the Basepath is not usable
*/
public function __construct($basepath)
{

View file

@ -4,6 +4,7 @@ namespace Friendica\Core\Console;
use Asika\SimpleConsole\Console;
use Friendica\App;
use Friendica\BaseObject;
use Friendica\Core\Config;
use Friendica\Core\Install;
use Friendica\Core\Theme;
@ -20,19 +21,51 @@ class AutomaticInstallation extends Console
return <<<HELP
Installation - Install Friendica automatically
Synopsis
bin/console autoinstall [-h|--help|-?] [-v] [-a]
bin/console autoinstall [-h|--help|-?] [-v] [-a] [-f]
Description
Installs Friendica with data based on the htconfig.php file
Installs Friendica with data based on the local.ini.php file or environment variables
Notes:
Notes
Not checking .htaccess/URL-Rewrite during CLI installation.
Options
-h|--help|-? Show help information
-v Show more debug information.
-a All setup checks are required (except .htaccess)
-f prepared config file (e.g. ".htconfig.php" itself)
-h|--help|-? Show help information
-v Show more debug information.
-a All setup checks are required (except .htaccess)
-f|--file <config> prepared config file (e.g. "config/local.ini.php" itself) which will override every other config option - except the environment variables)
-s|--savedb Save the DB credentials to the file (if environment variables is used)
-h|--dbhost <host> The host of the mysql database (env MYSQL_HOST)
-p|--dbport <port> The port of the mysql database (env MYSQL_PORT)
-d|--dbdata <database> The name of the mysql database (env MYSQL_DATABASE)
-U|--dbuser <username> The username of the mysql database login (env MYSQL_USER or MYSQL_USERNAME)
-P|--dbpass <password> The password of the mysql database login (env MYSQL_PASSWORD)
-b|--phppath <path> The path of the PHP binary (env FRIENDICA_PHP_PATH)
-A|--admin <mail> The admin email address of Friendica (env FRIENDICA_ADMIN_MAIL)
-T|--tz <timezone> The timezone of Friendica (env FRIENDICA_TZ)
-L|--lang <language> The language of Friendica (env FRIENDICA_LANG)
Environment variables
MYSQL_HOST The host of the mysql database (mandatory if mysql and environment is used)
MYSQL_PORT The port of the mysql database
MYSQL_USERNAME|MYSQL_USER The username of the mysql database login (MYSQL_USERNAME is for mysql, MYSQL_USER for mariadb)
MYSQL_PASSWORD The password of the mysql database login
MYSQL_DATABASE The name of the mysql database
FRIENDICA_PHP_PATH The path of the PHP binary
FRIENDICA_ADMIN_MAIL The admin email address of Friendica
FRIENDICA_TZ The timezone of Friendica
FRIENDICA_LANG The langauge of Friendica
Examples
bin/console autoinstall -f 'input.ini.php
Installs Friendica with the prepared 'input.ini.php' file
bin/console autoinstall --savedb
Installs Friendica with environment variables and saves them to the 'config/local.ini.php' file
bin/console autoinstall -h localhost -p 3365 -U user -P passwort1234 -d friendica
Installs Friendica with a local mysql database with credentials
HELP;
}
@ -41,18 +74,59 @@ HELP;
// Initialise the app
$this->out("Initializing setup...\n");
$a = get_app();
$db_host = '';
$db_user = '';
$db_pass = '';
$db_data = '';
// if a config file is set,
$config_file = $this->getOption(['f', 'file']);
$config_file = $this->getOption('f', 'htconfig.php');
if (!empty($config_file)) {
if ($config_file != 'config/local.ini.php') {
// Copy config file
$this->out("Copying config file...\n");
if (!copy($config_file, 'config/local.ini.php')) {
throw new RuntimeException("ERROR: Saving config file failed. Please copy '$config_file' to 'config/local.ini.php' manually.\n");
}
}
$this->out("Using config $config_file...\n");
require_once $config_file;
// load the app after copying the file
$a = BaseObject::getApp();
Install::setInstallMode();
$db_host = $a->getConfigValue('database', 'hostname');
$db_user = $a->getConfigValue('database', 'username');
$db_pass = $a->getConfigValue('database', 'password');
$db_data = $a->getConfigValue('database', 'database');
} else {
// Creating config file
$this->out("Creating config file...\n");
// load the app first (for the template engine)
$a = BaseObject::getApp();
$save_db = $this->getOption(['s', 'savedb'], false);
$db_host = $this->getOption(['h', 'dbhost'], ($save_db) ? getenv('MYSQL_HOST') : '');
$db_port = $this->getOption(['p', 'dbport'], ($save_db) ? getenv('MYSQL_PORT') : null);
$db_data = $this->getOption(['d', 'dbdata'], ($save_db) ? getenv('MYSQL_DATABASE') : '');
$db_user = $this->getOption(['U', 'dbuser'], ($save_db) ? getenv('MYSQL_USER') . getenv('MYSQL_USERNAME') : '');
$db_pass = $this->getOption(['P', 'dbpass'], ($save_db) ? getenv('MYSQL_PASSWORD') : '');
$php_path = $this->getOption(['b', 'phppath'], (!empty('FRIENDICA_PHP_PATH')) ? getenv('FRIENDICA_PHP_PATH') : '');
$admin_mail = $this->getOption(['A', 'admin'], (!empty('FRIENDICA_ADMIN_MAIL')) ? getenv('FRIENDICA_ADMIN_MAIL') : '');
$tz = $this->getOption(['T', 'tz'], (!empty('FRIENDICA_TZ')) ? getenv('FRIENDICA_TZ') : '');
$lang = $this->getOption(['L', 'lang'], (!empty('FRIENDICA_LANG')) ? getenv('FRIENDICA_LANG') : '');
// creating config file
$this->out("Creating config file...\n");
Install::createConfig(
$php_path,
$db_host,
$db_user,
$db_pass,
$db_data,
$php_path,
$tz,
$lang,
$admin_mail
);
}
$this->out(" Complete!\n\n");
@ -99,15 +173,9 @@ HELP;
Theme::install(Config::get('system', 'theme'));
$this->out(" Complete\n\n");
} else {
$this->out(" Theme setting is empty. Please check the file htconfig.php\n\n");
$this->out(" Theme setting is empty. Please check the file 'config/local.ini.php'\n\n");
}
// Copy config file
$this->out("Saving config file...\n");
if ($config_file != '.htconfig.php' && !copy($config_file, '.htconfig.php')) {
throw new RuntimeException("ERROR: Saving config file failed. Please copy '$config_file' to '.htconfig.php' manually.\n");
}
$this->out(" Complete!\n\n");
$this->out("\nInstallation is finished\n");
return 0;

View file

@ -1,427 +1,409 @@
<?php
/**
* @file src/Core/Install.php
*/
namespace Friendica\Core;
use Friendica\BaseObject;
use Friendica\App;
use Friendica\Database\DBStructure;
use Friendica\Object\Image;
use Friendica\Util\Network;
use Exception;
use DOMDocument;
/**
* Contains methods for installation purpose of Friendica
*/
class Install extends BaseObject
{
/**
* Sets the install-mode for further methods
*/
public static function setInstallMode()
{
self::getApp()->mode = App::MODE_INSTALL;
}
/**
* Checks the current installation environment. There are optional and mandatory checks.
*
* @param string $phpath Optional path to the PHP binary (Default is 'php')
*
* @return array First element is a list of all checks and their results,
* the second element is a list of passed checks
*/
public static function check($phpath = 'php')
{
$checks = [];
self::checkFunctions($checks);
self::checkImagick($checks);
self::checkLocalIni($checks);
self::checkSmarty3($checks);
self::checkKeys($checks);
self::checkPHP($phpath, $checks);
self::checkHtAccess($checks);
$checkspassed = array_reduce($checks,
function ($v, $c) {
if (!empty($c['require'])) {
$v = $v && $c['status'];
}
return $v;
},
true);
return array($checks, $checkspassed);
}
/**
* Executes the installation of Friendica in the given environment.
* - Creates `config/local.ini.php`
* - Installs Database Structure
*
* @param string $urlpath Path based on the URL of Friendica (e.g. '/friendica')
* @param string $dbhost Hostname/IP of the Friendica Database
* @param string $dbuser Username of the Database connection credentials
* @param string $dbpass Password of the Database connection credentials
* @param string $dbdata Name of the Database
* @param string $phpath Path to the PHP-Binary (e.g. 'php' or '/usr/bin/php')
* @param string $timezone Timezone of the Friendica Installaton (e.g. 'Europe/Berlin')
* @param string $language 2-letter ISO 639-1 code (eg. 'en')
* @param string $adminmail Mail-Adress of the administrator
* @param int $rino Rino-enabled (1 = true, 0 = false)
*/
public static function install($urlpath, $dbhost, $dbuser, $dbpass, $dbdata, $phpath, $timezone, $language, $adminmail)
{
$tpl = get_markup_template('local.ini.tpl');
$txt = replace_macros($tpl,[
'$dbhost' => $dbhost,
'$dbuser' => $dbuser,
'$dbpass' => $dbpass,
'$dbdata' => $dbdata,
'$timezone' => $timezone,
'$language' => $language,
'$urlpath' => $urlpath,
'$phpath' => $phpath,
'$adminmail' => $adminmail,
]);
$result = file_put_contents('config/local.ini.php', $txt);
if (! $result) {
self::getApp()->data['txt'] = $txt;
}
$errors = self::installDatabaseStructure();
if ($errors) {
self::getApp()->data['db_failed'] = $errors;
} else {
self::getApp()->data['db_installed'] = true;
}
}
/**
* Adds new checks to the array $checks
*
* @param array $checks The list of all checks (by-ref parameter!)
* @param string $title The title of the current check
* @param bool $status 1 = check passed, 0 = check not passed
* @param bool $required 1 = check is mandatory, 0 = check is optional
* @param string $help A help-string for the current check
* @param string $error_msg Optional. A error message, if the current check failed
*/
private static function addCheck(&$checks, $title, $status, $required, $help, $error_msg = "")
{
$checks[] = [
'title' => $title,
'status' => $status,
'required' => $required,
'help' => $help,
'error_msg' => $error_msg,
];
}
/**
* PHP Check
*
* Checks the PHP environment.
*
* - Checks if a PHP binary is available
* - Checks if it is the CLI version
* - Checks if "register_argc_argv" is enabled
*
* @param string $phpath Optional. The Path to the PHP-Binary
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkPHP(&$phpath, &$checks)
{
$passed = $passed2 = $passed3 = false;
if (strlen($phpath)) {
$passed = file_exists($phpath);
} else {
$phpath = trim(shell_exec('which php'));
$passed = strlen($phpath);
}
$help = "";
if (!$passed) {
$help .= L10n::t('Could not find a command line version of PHP in the web server PATH.') . EOL;
$help .= L10n::t("If you don't have a command line version of PHP installed on your server, you will not be able to run the background processing. See <a href='https://github.com/friendica/friendica/blob/master/doc/Install.md#set-up-the-worker'>'Setup the worker'</a>") . EOL;
$help .= EOL . EOL;
$tpl = get_markup_template('field_input.tpl');
$help .= replace_macros($tpl, [
'$field' => ['phpath', L10n::t('PHP executable path'), $phpath, L10n::t('Enter full path to php executable. You can leave this blank to continue the installation.')],
]);
$phpath = "";
}
self::addCheck($checks, L10n::t('Command line PHP').($passed?" (<tt>$phpath</tt>)":""), $passed, false, $help);
if ($passed) {
$cmd = "$phpath -v";
$result = trim(shell_exec($cmd));
$passed2 = (strpos($result, "(cli)") !== false);
list($result) = explode("\n", $result);
$help = "";
if (!$passed2) {
$help .= L10n::t("PHP executable is not the php cli binary \x28could be cgi-fgci version\x29") . EOL;
$help .= L10n::t('Found PHP version: ') . "<tt>$result</tt>";
}
self::addCheck($checks, L10n::t('PHP cli binary'), $passed2, true, $help);
}
if ($passed2) {
$str = autoname(8);
$cmd = "$phpath testargs.php $str";
$result = trim(shell_exec($cmd));
$passed3 = $result == $str;
$help = "";
if (!$passed3) {
$help .= L10n::t('The command line version of PHP on your system does not have "register_argc_argv" enabled.') . EOL;
$help .= L10n::t('This is required for message delivery to work.');
}
self::addCheck($checks, L10n::t('PHP register_argc_argv'), $passed3, true, $help);
}
}
/**
* OpenSSL Check
*
* Checks the OpenSSL Environment
*
* - Checks, if the command "openssl_pkey_new" is available
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkKeys(&$checks)
{
$help = '';
$res = false;
if (function_exists('openssl_pkey_new')) {
$res = openssl_pkey_new([
'digest_alg' => 'sha1',
'private_key_bits' => 4096,
'encrypt_key' => false
]);
}
// Get private key
if (!$res) {
$help .= L10n::t('Error: the "openssl_pkey_new" function on this system is not able to generate encryption keys') . EOL;
$help .= L10n::t('If running under Windows, please see "http://www.php.net/manual/en/openssl.installation.php".');
}
self::addCheck($checks, L10n::t('Generate encryption keys'), $res, true, $help);
}
/**
* PHP functions Check
*
* Checks the following PHP functions
* - libCurl
* - GD Graphics
* - OpenSSL
* - PDO or MySQLi
* - mb_string
* - XML
* - iconv
* - POSIX
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkFunctions(&$checks)
{
$ck_funcs = [];
self::addCheck($ck_funcs, L10n::t('libCurl PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('GD graphics PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('OpenSSL PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('PDO or MySQLi PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('mb_string PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('XML PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('iconv PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('POSIX PHP module'), true, true, "");
if (function_exists('apache_get_modules')) {
if (! in_array('mod_rewrite',apache_get_modules())) {
self::addCheck($ck_funcs, L10n::t('Apache mod_rewrite module'), false, true, L10n::t('Error: Apache webserver mod-rewrite module is required but not installed.'));
} else {
self::addCheck($ck_funcs, L10n::t('Apache mod_rewrite module'), true, true, "");
}
}
if (!function_exists('curl_init')) {
$ck_funcs[0]['status'] = false;
$ck_funcs[0]['help'] = L10n::t('Error: libCURL PHP module required but not installed.');
}
if (!function_exists('imagecreatefromjpeg')) {
$ck_funcs[1]['status'] = false;
$ck_funcs[1]['help'] = L10n::t('Error: GD graphics PHP module with JPEG support required but not installed.');
}
if (!function_exists('openssl_public_encrypt')) {
$ck_funcs[2]['status'] = false;
$ck_funcs[2]['help'] = L10n::t('Error: openssl PHP module required but not installed.');
}
if (!function_exists('mysqli_connect') && !class_exists('pdo')) {
$ck_funcs[3]['status'] = false;
$ck_funcs[3]['help'] = L10n::t('Error: PDO or MySQLi PHP module required but not installed.');
}
if (!function_exists('mysqli_connect') && class_exists('pdo') && !in_array('mysql', \PDO::getAvailableDrivers())) {
$ck_funcs[3]['status'] = false;
$ck_funcs[3]['help'] = L10n::t('Error: The MySQL driver for PDO is not installed.');
}
if (!function_exists('mb_strlen')) {
$ck_funcs[4]['status'] = false;
$ck_funcs[4]['help'] = L10n::t('Error: mb_string PHP module required but not installed.');
}
if (!function_exists('iconv_strlen')) {
$ck_funcs[6]['status'] = false;
$ck_funcs[6]['help'] = L10n::t('Error: iconv PHP module required but not installed.');
}
if (!function_exists('posix_kill')) {
$ck_funcs[7]['status'] = false;
$ck_funcs[7]['help'] = L10n::t('Error: POSIX PHP module required but not installed.');
}
$checks = array_merge($checks, $ck_funcs);
// check for XML DOM Documents being able to be generated
try {
$xml = new DOMDocument();
} catch (Exception $e) {
$ck_funcs[5]['status'] = false;
$ck_funcs[5]['help'] = L10n::t('Error, XML PHP module required but not installed.');
}
}
/**
* "config/local.ini.php" - Check
*
* Checks if it's possible to create the "config/local.ini.php"
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkLocalIni(&$checks)
{
$status = true;
$help = "";
if ((file_exists('config/local.ini.php') && !is_writable('config/local.ini.php')) ||
(!file_exists('config/local.ini.php') && !is_writable('.'))) {
$status = false;
$help = L10n::t('The web installer needs to be able to create a file called "local.ini.php" in the "config" folder of your web server and it is unable to do so.') . EOL;
$help .= L10n::t('This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can.') . EOL;
$help .= L10n::t('At the end of this procedure, we will give you a text to save in a file named local.ini.php in your Friendica "config" folder.') . EOL;
$help .= L10n::t('You can alternatively skip this procedure and perform a manual installation. Please see the file "INSTALL.txt" for instructions.') . EOL;
}
self::addCheck($checks, L10n::t('config/local.ini.php is writable'), $status, false, $help);
}
/**
* Smarty3 Template Check
*
* Checks, if the directory of Smarty3 is writable
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkSmarty3(&$checks)
{
$status = true;
$help = "";
if (!is_writable('view/smarty3')) {
$status = false;
$help = L10n::t('Friendica uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering.') . EOL;
$help .= L10n::t('In order to store these compiled templates, the web server needs to have write access to the directory view/smarty3/ under the Friendica top level folder.') . EOL;
$help .= L10n::t("Please ensure that the user that your web server runs as \x28e.g. www-data\x29 has write access to this folder.") . EOL;
$help .= L10n::t("Note: as a security measure, you should give the web server write access to view/smarty3/ only--not the template files \x28.tpl\x29 that it contains.") . EOL;
}
self::addCheck($checks, L10n::t('view/smarty3 is writable'), $status, true, $help);
}
/**
* ".htaccess" - Check
*
* Checks, if "url_rewrite" is enabled in the ".htaccess" file
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkHtAccess(&$checks)
{
$status = true;
$help = "";
$error_msg = "";
if (function_exists('curl_init')) {
$test = Network::fetchUrlFull(System::baseUrl() . "/install/testrewrite");
$url = normalise_link(System::baseUrl() . "/install/testrewrite");
if ($test['body'] != "ok") {
$test = Network::fetchUrlFull($url);
}
if ($test['body'] != "ok") {
$status = false;
$help = L10n::t('Url rewrite in .htaccess is not working. Check your server configuration.');
$error_msg = [];
$error_msg['head'] = L10n::t('Error message from Curl when fetching');
$error_msg['url'] = $test['redirect_url'];
$error_msg['msg'] = defaults($test, 'error', '');
}
self::addCheck($checks, L10n::t('Url rewrite is working'), $status, true, $help, $error_msg);
} else {
// cannot check modrewrite if libcurl is not installed
/// @TODO Maybe issue warning here?
}
}
/**
* Imagick Check
*
* Checks, if the imagick module is available
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkImagick(&$checks)
{
$imagick = false;
$gif = false;
if (class_exists('Imagick')) {
$imagick = true;
$supported = Image::supportedTypes();
if (array_key_exists('image/gif', $supported)) {
$gif = true;
}
}
if ($imagick == false) {
self::addCheck($checks, L10n::t('ImageMagick PHP extension is not installed'), $imagick, false, "");
} else {
self::addCheck($checks, L10n::t('ImageMagick PHP extension is installed'), $imagick, false, "");
if ($imagick) {
self::addCheck($checks, L10n::t('ImageMagick supports GIF'), $gif, false, "");
}
}
}
/**
* Installs the Database structure
*
* @return string A possible error
*/
public static function installDatabaseStructure()
{
$errors = DBStructure::update(false, true, true);
return $errors;
}
}
<?php
/**
* @file src/Core/Install.php
*/
namespace Friendica\Core;
use DOMDocument;
use Exception;
use Friendica\BaseObject;
use Friendica\Database\DBStructure;
use Friendica\Object\Image;
use Friendica\Util\Network;
/**
* Contains methods for installation purpose of Friendica
*/
class Install extends BaseObject
{
/**
* Checks the current installation environment. There are optional and mandatory checks.
*
* @param string $phpath Optional path to the PHP binary (Default is 'php')
*
* @return array First element is a list of all checks and their results,
* the second element is a list of passed checks
*/
public static function check($phpath = 'php')
{
$checks = [];
self::checkFunctions($checks);
self::checkImagick($checks);
self::checkLocalIni($checks);
self::checkSmarty3($checks);
self::checkKeys($checks);
self::checkPHP($phpath, $checks);
self::checkHtAccess($checks);
$checkspassed = array_reduce($checks,
function ($v, $c) {
if (!empty($c['require'])) {
$v = $v && $c['status'];
}
return $v;
},
true);
return array($checks, $checkspassed);
}
/**
* Executes the installation of Friendica in the given environment.
* - Creates `config/local.ini.php`
* - Installs Database Structure
*
* @param string $urlpath Path based on the URL of Friendica (e.g. '/friendica')
* @param string $dbhost Hostname/IP of the Friendica Database
* @param string $dbuser Username of the Database connection credentials
* @param string $dbpass Password of the Database connection credentials
* @param string $dbdata Name of the Database
* @param string $phpath Path to the PHP-Binary (e.g. 'php' or '/usr/bin/php')
* @param string $timezone Timezone of the Friendica Installaton (e.g. 'Europe/Berlin')
* @param string $language 2-letter ISO 639-1 code (eg. 'en')
* @param string $adminmail Mail-Adress of the administrator
*/
public static function createConfig($urlpath, $dbhost, $dbuser, $dbpass, $dbdata, $phpath, $timezone, $language, $adminmail)
{
$tpl = get_markup_template('local.ini.tpl');
$txt = replace_macros($tpl,[
'$dbhost' => $dbhost,
'$dbuser' => $dbuser,
'$dbpass' => $dbpass,
'$dbdata' => $dbdata,
'$timezone' => $timezone,
'$language' => $language,
'$urlpath' => $urlpath,
'$phpath' => $phpath,
'$adminmail' => $adminmail,
]);
$result = file_put_contents('config/local.ini.php', $txt);
if (!$result) {
self::getApp()->data['txt'] = $txt;
}
}
/**
* Adds new checks to the array $checks
*
* @param array $checks The list of all checks (by-ref parameter!)
* @param string $title The title of the current check
* @param bool $status 1 = check passed, 0 = check not passed
* @param bool $required 1 = check is mandatory, 0 = check is optional
* @param string $help A help-string for the current check
* @param string $error_msg Optional. A error message, if the current check failed
*/
private static function addCheck(&$checks, $title, $status, $required, $help, $error_msg = "")
{
$checks[] = [
'title' => $title,
'status' => $status,
'required' => $required,
'help' => $help,
'error_msg' => $error_msg,
];
}
/**
* PHP Check
*
* Checks the PHP environment.
*
* - Checks if a PHP binary is available
* - Checks if it is the CLI version
* - Checks if "register_argc_argv" is enabled
*
* @param string $phpath Optional. The Path to the PHP-Binary
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkPHP($phpath, &$checks)
{
$passed = $passed2 = $passed3 = false;
if (strlen($phpath)) {
$passed = file_exists($phpath);
} else {
$phpath = trim(shell_exec('which php'));
$passed = strlen($phpath);
}
$help = "";
if (!$passed) {
$help .= L10n::t('Could not find a command line version of PHP in the web server PATH.') . EOL;
$help .= L10n::t("If you don't have a command line version of PHP installed on your server, you will not be able to run the background processing. See <a href='https://github.com/friendica/friendica/blob/master/doc/Install.md#set-up-the-worker'>'Setup the worker'</a>") . EOL;
$help .= EOL . EOL;
$tpl = get_markup_template('field_input.tpl');
$help .= replace_macros($tpl, [
'$field' => ['phpath', L10n::t('PHP executable path'), $phpath, L10n::t('Enter full path to php executable. You can leave this blank to continue the installation.')],
]);
$phpath = "";
}
self::addCheck($checks, L10n::t('Command line PHP').($passed?" (<tt>$phpath</tt>)":""), $passed, false, $help);
if ($passed) {
$cmd = "$phpath -v";
$result = trim(shell_exec($cmd));
$passed2 = (strpos($result, "(cli)") !== false);
list($result) = explode("\n", $result);
$help = "";
if (!$passed2) {
$help .= L10n::t("PHP executable is not the php cli binary \x28could be cgi-fgci version\x29") . EOL;
$help .= L10n::t('Found PHP version: ') . "<tt>$result</tt>";
}
self::addCheck($checks, L10n::t('PHP cli binary'), $passed2, true, $help);
}
if ($passed2) {
$str = autoname(8);
$cmd = "$phpath testargs.php $str";
$result = trim(shell_exec($cmd));
$passed3 = $result == $str;
$help = "";
if (!$passed3) {
$help .= L10n::t('The command line version of PHP on your system does not have "register_argc_argv" enabled.') . EOL;
$help .= L10n::t('This is required for message delivery to work.');
}
self::addCheck($checks, L10n::t('PHP register_argc_argv'), $passed3, true, $help);
}
}
/**
* OpenSSL Check
*
* Checks the OpenSSL Environment
*
* - Checks, if the command "openssl_pkey_new" is available
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkKeys(&$checks)
{
$help = '';
$res = false;
if (function_exists('openssl_pkey_new')) {
$res = openssl_pkey_new([
'digest_alg' => 'sha1',
'private_key_bits' => 4096,
'encrypt_key' => false
]);
}
// Get private key
if (!$res) {
$help .= L10n::t('Error: the "openssl_pkey_new" function on this system is not able to generate encryption keys') . EOL;
$help .= L10n::t('If running under Windows, please see "http://www.php.net/manual/en/openssl.installation.php".');
}
self::addCheck($checks, L10n::t('Generate encryption keys'), $res, true, $help);
}
/**
* PHP functions Check
*
* Checks the following PHP functions
* - libCurl
* - GD Graphics
* - OpenSSL
* - PDO or MySQLi
* - mb_string
* - XML
* - iconv
* - POSIX
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkFunctions(&$checks)
{
$ck_funcs = [];
self::addCheck($ck_funcs, L10n::t('libCurl PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('GD graphics PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('OpenSSL PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('PDO or MySQLi PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('mb_string PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('XML PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('iconv PHP module'), true, true, "");
self::addCheck($ck_funcs, L10n::t('POSIX PHP module'), true, true, "");
if (function_exists('apache_get_modules')) {
if (! in_array('mod_rewrite',apache_get_modules())) {
self::addCheck($ck_funcs, L10n::t('Apache mod_rewrite module'), false, true, L10n::t('Error: Apache webserver mod-rewrite module is required but not installed.'));
} else {
self::addCheck($ck_funcs, L10n::t('Apache mod_rewrite module'), true, true, "");
}
}
if (!function_exists('curl_init')) {
$ck_funcs[0]['status'] = false;
$ck_funcs[0]['help'] = L10n::t('Error: libCURL PHP module required but not installed.');
}
if (!function_exists('imagecreatefromjpeg')) {
$ck_funcs[1]['status'] = false;
$ck_funcs[1]['help'] = L10n::t('Error: GD graphics PHP module with JPEG support required but not installed.');
}
if (!function_exists('openssl_public_encrypt')) {
$ck_funcs[2]['status'] = false;
$ck_funcs[2]['help'] = L10n::t('Error: openssl PHP module required but not installed.');
}
if (!function_exists('mysqli_connect') && !class_exists('pdo')) {
$ck_funcs[3]['status'] = false;
$ck_funcs[3]['help'] = L10n::t('Error: PDO or MySQLi PHP module required but not installed.');
}
if (!function_exists('mysqli_connect') && class_exists('pdo') && !in_array('mysql', \PDO::getAvailableDrivers())) {
$ck_funcs[3]['status'] = false;
$ck_funcs[3]['help'] = L10n::t('Error: The MySQL driver for PDO is not installed.');
}
if (!function_exists('mb_strlen')) {
$ck_funcs[4]['status'] = false;
$ck_funcs[4]['help'] = L10n::t('Error: mb_string PHP module required but not installed.');
}
if (!function_exists('iconv_strlen')) {
$ck_funcs[6]['status'] = false;
$ck_funcs[6]['help'] = L10n::t('Error: iconv PHP module required but not installed.');
}
if (!function_exists('posix_kill')) {
$ck_funcs[7]['status'] = false;
$ck_funcs[7]['help'] = L10n::t('Error: POSIX PHP module required but not installed.');
}
$checks = array_merge($checks, $ck_funcs);
// check for XML DOM Documents being able to be generated
try {
$xml = new DOMDocument();
} catch (Exception $e) {
$ck_funcs[5]['status'] = false;
$ck_funcs[5]['help'] = L10n::t('Error, XML PHP module required but not installed.');
}
}
/**
* "config/local.ini.php" - Check
*
* Checks if it's possible to create the "config/local.ini.php"
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkLocalIni(&$checks)
{
$status = true;
$help = "";
if ((file_exists('config/local.ini.php') && !is_writable('config/local.ini.php')) ||
(!file_exists('config/local.ini.php') && !is_writable('.'))) {
$status = false;
$help = L10n::t('The web installer needs to be able to create a file called "local.ini.php" in the "config" folder of your web server and it is unable to do so.') . EOL;
$help .= L10n::t('This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can.') . EOL;
$help .= L10n::t('At the end of this procedure, we will give you a text to save in a file named local.ini.php in your Friendica "config" folder.') . EOL;
$help .= L10n::t('You can alternatively skip this procedure and perform a manual installation. Please see the file "INSTALL.txt" for instructions.') . EOL;
}
self::addCheck($checks, L10n::t('config/local.ini.php is writable'), $status, false, $help);
}
/**
* Smarty3 Template Check
*
* Checks, if the directory of Smarty3 is writable
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkSmarty3(&$checks)
{
$status = true;
$help = "";
if (!is_writable('view/smarty3')) {
$status = false;
$help = L10n::t('Friendica uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering.') . EOL;
$help .= L10n::t('In order to store these compiled templates, the web server needs to have write access to the directory view/smarty3/ under the Friendica top level folder.') . EOL;
$help .= L10n::t("Please ensure that the user that your web server runs as \x28e.g. www-data\x29 has write access to this folder.") . EOL;
$help .= L10n::t("Note: as a security measure, you should give the web server write access to view/smarty3/ only--not the template files \x28.tpl\x29 that it contains.") . EOL;
}
self::addCheck($checks, L10n::t('view/smarty3 is writable'), $status, true, $help);
}
/**
* ".htaccess" - Check
*
* Checks, if "url_rewrite" is enabled in the ".htaccess" file
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkHtAccess(&$checks)
{
$status = true;
$help = "";
$error_msg = "";
if (function_exists('curl_init')) {
$test = Network::fetchUrlFull(System::baseUrl() . "/install/testrewrite");
$url = normalise_link(System::baseUrl() . "/install/testrewrite");
if ($test['body'] != "ok") {
$test = Network::fetchUrlFull($url);
}
if ($test['body'] != "ok") {
$status = false;
$help = L10n::t('Url rewrite in .htaccess is not working. Check your server configuration.');
$error_msg = [];
$error_msg['head'] = L10n::t('Error message from Curl when fetching');
$error_msg['url'] = $test['redirect_url'];
$error_msg['msg'] = defaults($test, 'error', '');
}
self::addCheck($checks, L10n::t('Url rewrite is working'), $status, true, $help, $error_msg);
} else {
// cannot check modrewrite if libcurl is not installed
/// @TODO Maybe issue warning here?
}
}
/**
* Imagick Check
*
* Checks, if the imagick module is available
*
* @param array $checks The list of all checks (by-ref parameter!)
*/
public static function checkImagick(&$checks)
{
$imagick = false;
$gif = false;
if (class_exists('Imagick')) {
$imagick = true;
$supported = Image::supportedTypes();
if (array_key_exists('image/gif', $supported)) {
$gif = true;
}
}
if ($imagick == false) {
self::addCheck($checks, L10n::t('ImageMagick PHP extension is not installed'), $imagick, false, "");
} else {
self::addCheck($checks, L10n::t('ImageMagick PHP extension is installed'), $imagick, false, "");
if ($imagick) {
self::addCheck($checks, L10n::t('ImageMagick supports GIF'), $gif, false, "");
}
}
}
/**
* Installs the Database structure
*
* @return string A possible error
*/
public static function installDatabaseStructure()
{
$errors = DBStructure::update(false, true, true);
return $errors;
}
}

View file

@ -344,6 +344,10 @@ class NotificationsManager extends BaseObject
break;
case ACTIVITY_FRIEND:
if (!isset($it['object'])) {
logger('Incomplete data: ' . json_encode($it) . ' - ' . System::callstack(20), LOGGER_DEBUG);
}
$xmlhead = "<" . "?xml version='1.0' encoding='UTF-8' ?" . ">";
$obj = XML::parseString($xmlhead . $it['object']);
$it['fname'] = $obj->title;

View file

@ -65,7 +65,7 @@ class System extends BaseObject
while ($func = array_pop($trace)) {
if (!empty($func['class'])) {
// Don't show multiple calls from the "dba" class to show the essential parts of the callstack
if ((($previous['class'] != $func['class']) || ($func['class'] != 'dba')) && ($previous['function'] != 'q')) {
if ((($previous['class'] != $func['class']) || ($func['class'] != 'Friendica\Database\DBA')) && ($previous['function'] != 'q')) {
$classparts = explode("\\", $func['class']);
$callstack[] = array_pop($classparts).'::'.$func['function'];
$previous = $func;

View file

@ -372,7 +372,7 @@ class DBA
* @usage Example: $r = p("SELECT * FROM `item` WHERE `guid` = ?", $guid);
*
* Please only use it with complicated queries.
* For all regular queries please use dba::select or dba::exists
* For all regular queries please use DBA::select or DBA::exists
*
* @param string $sql SQL statement
* @return bool|object statement object or result object
@ -590,7 +590,7 @@ class DBA
/**
* @brief Executes a prepared statement like UPDATE or INSERT that doesn't return data
*
* Please use dba::delete, dba::insert, dba::update, ... instead
* Please use DBA::delete, DBA::insert, DBA::update, ... instead
*
* @param string $sql SQL statement
* @return boolean Was the query successfull? False is returned only if an error occurred
@ -685,7 +685,7 @@ class DBA
/**
* Fetches the first row
*
* Please use dba::selectFirst or dba::exists whenever this is possible.
* Please use DBA::selectFirst or DBA::exists whenever this is possible.
*
* @brief Fetches the first row
* @param string $sql SQL statement
@ -1303,7 +1303,7 @@ class DBA
*
* $params = array("order" => array("id", "received" => true), "limit" => 10);
*
* $data = dba::select($table, $fields, $condition, $params);
* $data = DBA::select($table, $fields, $condition, $params);
*/
public static function select($table, array $fields = [], array $condition = [], array $params = [])
{
@ -1345,7 +1345,7 @@ class DBA
* or:
* $condition = ["`uid` = ? AND `network` IN (?, ?)", 1, 'dfrn', 'dspr'];
*
* $count = dba::count($table, $condition);
* $count = DBA::count($table, $condition);
*/
public static function count($table, array $condition = [])
{
@ -1399,7 +1399,7 @@ class DBA
/* Workaround for MySQL Bug #64791.
* Never mix data types inside any IN() condition.
* In case of mixed types, cast all as string.
* Logic needs to be consistent with dba::p() data types.
* Logic needs to be consistent with DBA::p() data types.
*/
$is_int = false;
$is_alpha = false;
@ -1459,7 +1459,7 @@ class DBA
$limit_string = '';
if (isset($params['limit']) && is_int($params['limit'])) {
$limit_string = " LIMIT " . $params['limit'];
$limit_string = " LIMIT " . intval($params['limit']);
}
if (isset($params['limit']) && is_array($params['limit'])) {
@ -1530,7 +1530,7 @@ class DBA
case 'mysqli':
// MySQLi offers both a mysqli_stmt and a mysqli_result class.
// We should be careful not to assume the object type of $stmt
// because dba::p() has been able to return both types.
// because DBA::p() has been able to return both types.
if ($stmt instanceof mysqli_stmt) {
$stmt->free_result();
$ret = $stmt->close();

View file

@ -364,8 +364,13 @@ class Contact extends BaseObject
*/
public static function markForArchival(array $contact)
{
if (!isset($contact['url'])) {
if (!isset($contact['url']) && !empty($contact['id'])) {
$fields = ['id', 'url', 'archive', 'self', 'term-date'];
$contact = DBA::selectFirst('contact', [], ['id' => $contact['id']]);
if (!DBA::isResult($contact)) {
return;
}
} elseif (!isset($contact['url'])) {
logger('Empty contact: ' . json_encode($contact) . ' - ' . System::callstack(20), LOGGER_DEBUG);
}
@ -376,10 +381,7 @@ class Contact extends BaseObject
if ($contact['term-date'] <= NULL_DATE) {
DBA::update('contact', ['term-date' => DateTimeFormat::utcNow()], ['id' => $contact['id']]);
if ($contact['url'] != '') {
DBA::update('contact', ['term-date' => DateTimeFormat::utcNow()], ['`nurl` = ? AND `term-date` <= ? AND NOT `self`', normalise_link($contact['url']), NULL_DATE]);
}
DBA::update('contact', ['term-date' => DateTimeFormat::utcNow()], ['`nurl` = ? AND `term-date` <= ? AND NOT `self`', normalise_link($contact['url']), NULL_DATE]);
} else {
/* @todo
* We really should send a notification to the owner after 2-3 weeks
@ -397,10 +399,7 @@ class Contact extends BaseObject
* the whole process over again.
*/
DBA::update('contact', ['archive' => 1], ['id' => $contact['id']]);
if ($contact['url'] != '') {
DBA::update('contact', ['archive' => 1], ['nurl' => normalise_link($contact['url']), 'self' => false]);
}
DBA::update('contact', ['archive' => 1], ['nurl' => normalise_link($contact['url']), 'self' => false]);
}
}
}
@ -423,13 +422,18 @@ class Contact extends BaseObject
return;
}
if (!isset($contact['url']) && !empty($contact['id'])) {
$fields = ['id', 'url', 'batch'];
$contact = DBA::selectFirst('contact', [], ['id' => $contact['id']]);
if (!DBA::isResult($contact)) {
return;
}
}
// It's a miracle. Our dead contact has inexplicably come back to life.
$fields = ['term-date' => NULL_DATE, 'archive' => false];
DBA::update('contact', $fields, ['id' => $contact['id']]);
if (!empty($contact['url'])) {
DBA::update('contact', $fields, ['nurl' => normalise_link($contact['url'])]);
}
DBA::update('contact', $fields, ['nurl' => normalise_link($contact['url'])]);
if (!empty($contact['batch'])) {
$condition = ['batch' => $contact['batch'], 'contact-type' => self::ACCOUNT_TYPE_RELAY];

View file

@ -273,36 +273,25 @@ class Group extends BaseObject
*
* @param array $group_ids
* @param boolean $check_dead
* @param boolean $use_gcontact
* @return array
*/
public static function expand($group_ids, $check_dead = false, $use_gcontact = false)
public static function expand($group_ids, $check_dead = false)
{
if (!is_array($group_ids) || !count($group_ids)) {
return [];
}
$condition = '`gid` IN (' . substr(str_repeat("?, ", count($group_ids)), 0, -2) . ')';
if ($use_gcontact) {
$sql = 'SELECT `gcontact`.`id` AS `contact-id` FROM `group_member`
INNER JOIN `contact` ON `contact`.`id` = `group_member`.`contact-id`
INNER JOIN `gcontact` ON `gcontact`.`nurl` = `contact`.`nurl`
WHERE ' . $condition;
$param_arr = array_merge([$sql], $group_ids);
$stmt = call_user_func_array('dba::p', $param_arr);
} else {
$condition_array = array_merge([$condition], $group_ids);
$stmt = DBA::select('group_member', ['contact-id'], $condition_array);
}
$stmt = DBA::select('group_member', ['contact-id'], ['gid' => $group_ids]);
$return = [];
while($group_member = DBA::fetch($stmt)) {
$return[] = $group_member['contact-id'];
}
if ($check_dead && !$use_gcontact) {
if ($check_dead) {
Contact::pruneUnavailable($return);
}
return $return;
}

View file

@ -933,7 +933,12 @@ class Probe
}
$prof_data = [];
$prof_data["addr"] = $data["addr"];
// The "addr" is not always part of the fetched data
if (!empty($data["addr"])) {
$prof_data["addr"] = $data["addr"];
}
$prof_data["nick"] = $data["nick"];
$prof_data["dfrn-request"] = $data["request"];
$prof_data["dfrn-confirm"] = $data["confirm"];

View file

@ -1050,7 +1050,7 @@ class Diaspora
return false;
}
$contact = dba::selectFirst('contact', [], ['id' => $cid]);
$contact = DBA::selectFirst('contact', [], ['id' => $cid]);
if (!DBA::isResult($contact)) {
// This here shouldn't happen at all
logger("Haven't found a contact for user " . $uid . " and handle " . $handle, LOGGER_DEBUG);
@ -1079,7 +1079,7 @@ class Diaspora
// It is deactivated by now, due to side effects. See issue https://github.com/friendica/friendica/pull/4033
// It is not removed by now. Possibly the code is needed?
//if (!$is_comment && $contact["rel"] == Contact::FOLLOWER && in_array($importer["page-flags"], array(Contact::PAGE_FREELOVE))) {
// dba::update(
// DBA::update(
// 'contact',
// array('rel' => Contact::FRIEND, 'writable' => true),
// array('id' => $contact["id"], 'uid' => $contact["uid"])
@ -1821,10 +1821,10 @@ class Diaspora
"to_name" => $importer["username"],
"to_email" => $importer["email"],
"uid" =>$importer["uid"],
"item" => ["subject" => $subject, "body" => $body],
"item" => ["id" => $conversation["id"], "title" => $subject, "subject" => $subject, "body" => $body],
"source_name" => $person["name"],
"source_link" => $person["url"],
"source_photo" => $person["thumb"],
"source_photo" => $person["photo"],
"verb" => ACTIVITY_POST,
"otype" => "mail"]
);
@ -3075,7 +3075,7 @@ class Diaspora
logger("transmit: ".$logid."-".$guid." to ".$dest_url." returns: ".$return_code);
if (!$return_code || (($return_code == 503) && (stristr($a->get_curl_headers(), "retry-after")))) {
if (!$no_queue && ($contact['contact-type'] != Contact::ACCOUNT_TYPE_RELAY)) {
if (!$no_queue && !empty($contact['contact-type']) && ($contact['contact-type'] != Contact::ACCOUNT_TYPE_RELAY)) {
logger("queue message");
// queue message for redelivery
Queue::add($contact["id"], Protocol::DIASPORA, $envelope, $public_batch, $guid);

View file

@ -716,7 +716,7 @@ class Network
$url = self::stripTrackingQueryParams($url);
if ($depth > 10) {
return($url);
return $url;
}
$url = trim($url, "'");
@ -739,16 +739,14 @@ class Network
$a->save_timestamp($stamp1, "network");
if ($http_code == 0) {
return($url);
return $url;
}
if ((($curl_info['http_code'] == "301") || ($curl_info['http_code'] == "302"))
&& (($curl_info['redirect_url'] != "") || ($curl_info['location'] != ""))
) {
if ($curl_info['redirect_url'] != "") {
return(self::finalUrl($curl_info['redirect_url'], ++$depth, $fetchbody));
} else {
return(self::finalUrl($curl_info['location'], ++$depth, $fetchbody));
if (in_array($http_code, ['301', '302'])) {
if (!empty($curl_info['redirect_url'])) {
return self::finalUrl($curl_info['redirect_url'], ++$depth, $fetchbody);
} elseif (!empty($curl_info['location'])) {
return self::finalUrl($curl_info['location'], ++$depth, $fetchbody);
}
}
@ -759,12 +757,12 @@ class Network
// if the file is too large then exit
if ($curl_info["download_content_length"] > 1000000) {
return($url);
return $url;
}
// if it isn't a HTML file then exit
if (($curl_info["content_type"] != "") && !strstr(strtolower($curl_info["content_type"]), "html")) {
return($url);
if (!empty($curl_info["content_type"]) && !strstr(strtolower($curl_info["content_type"]), "html")) {
return $url;
}
$stamp1 = microtime(true);
@ -783,7 +781,7 @@ class Network
$a->save_timestamp($stamp1, "network");
if (trim($body) == "") {
return($url);
return $url;
}
// Check for redirect in meta elements
@ -806,7 +804,7 @@ class Network
$pathinfo = explode(";", $path);
foreach ($pathinfo as $value) {
if (substr(strtolower($value), 0, 4) == "url=") {
return(self::finalUrl(substr($value, 4), ++$depth));
return self::finalUrl(substr($value, 4), ++$depth);
}
}
}

View file

@ -84,7 +84,7 @@ class DBClean {
$r = DBA::p("SELECT `id` FROM `item` WHERE `uid` = 0 AND
NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0) AND
`received` < UTC_TIMESTAMP() - INTERVAL ? DAY AND `id` >= ?
ORDER BY `id` LIMIT ".intval($limit), $days_unclaimed, $last_id);
ORDER BY `id` LIMIT ?", $days_unclaimed, $last_id, $limit);
$count = DBA::numRows($r);
if ($count > 0) {
logger("found global item orphans: ".$count);
@ -106,7 +106,7 @@ class DBClean {
logger("Deleting items without parents. Last ID: ".$last_id);
$r = DBA::p("SELECT `id` FROM `item`
WHERE NOT EXISTS (SELECT `id` FROM `item` AS `i` WHERE `item`.`parent` = `i`.`id`)
AND `id` >= ? ORDER BY `id` LIMIT ".intval($limit), $last_id);
AND `id` >= ? ORDER BY `id` LIMIT ?", $last_id, $limit);
$count = DBA::numRows($r);
if ($count > 0) {
logger("found item orphans without parents: ".$count);
@ -132,7 +132,7 @@ class DBClean {
logger("Deleting orphaned data from thread table. Last ID: ".$last_id);
$r = DBA::p("SELECT `iid` FROM `thread`
WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `thread`.`iid`) AND `iid` >= ?
ORDER BY `iid` LIMIT ".intval($limit), $last_id);
ORDER BY `iid` LIMIT ?", $last_id, $limit);
$count = DBA::numRows($r);
if ($count > 0) {
logger("found thread orphans: ".$count);
@ -158,7 +158,7 @@ class DBClean {
logger("Deleting orphaned data from notify table. Last ID: ".$last_id);
$r = DBA::p("SELECT `iid`, `id` FROM `notify`
WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `notify`.`iid`) AND `id` >= ?
ORDER BY `id` LIMIT ".intval($limit), $last_id);
ORDER BY `id` LIMIT ?", $last_id, $limit);
$count = DBA::numRows($r);
if ($count > 0) {
logger("found notify orphans: ".$count);
@ -184,7 +184,7 @@ class DBClean {
logger("Deleting orphaned data from notify-threads table. Last ID: ".$last_id);
$r = DBA::p("SELECT `id` FROM `notify-threads`
WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`parent` = `notify-threads`.`master-parent-item`) AND `id` >= ?
ORDER BY `id` LIMIT ".intval($limit), $last_id);
ORDER BY `id` LIMIT ?", $last_id, $limit);
$count = DBA::numRows($r);
if ($count > 0) {
logger("found notify-threads orphans: ".$count);
@ -210,7 +210,7 @@ class DBClean {
logger("Deleting orphaned data from sign table. Last ID: ".$last_id);
$r = DBA::p("SELECT `iid`, `id` FROM `sign`
WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `sign`.`iid`) AND `id` >= ?
ORDER BY `id` LIMIT ".intval($limit), $last_id);
ORDER BY `id` LIMIT ?", $last_id, $limit);
$count = DBA::numRows($r);
if ($count > 0) {
logger("found sign orphans: ".$count);
@ -236,7 +236,7 @@ class DBClean {
logger("Deleting orphaned data from term table. Last ID: ".$last_id);
$r = DBA::p("SELECT `oid`, `tid` FROM `term`
WHERE NOT EXISTS (SELECT `id` FROM `item` WHERE `item`.`id` = `term`.`oid`) AND `tid` >= ?
ORDER BY `tid` LIMIT ".intval($limit), $last_id);
ORDER BY `tid` LIMIT ?", $last_id, $limit);
$count = DBA::numRows($r);
if ($count > 0) {
logger("found term orphans: ".$count);
@ -303,7 +303,7 @@ class DBClean {
$r = DBA::p("SELECT `id` FROM `item` WHERE `uid` = 0 AND
NOT EXISTS (SELECT `guid` FROM `item` AS `i` WHERE `item`.`guid` = `i`.`guid` AND `i`.`uid` != 0) AND
`received` < UTC_TIMESTAMP() - INTERVAL 90 DAY AND `id` >= ? AND `id` <= ?
ORDER BY `id` LIMIT ".intval($limit), $last_id, $till_id);
ORDER BY `id` LIMIT ?", $last_id, $till_id, $limit);
$count = DBA::numRows($r);
if ($count > 0) {
logger("found global item entries from expired threads: ".$count);
@ -326,7 +326,7 @@ class DBClean {
logger("Deleting old conversations. Last created: ".$last_id);
$r = DBA::p("SELECT `received`, `item-uri` FROM `conversation`
WHERE `received` < UTC_TIMESTAMP() - INTERVAL ? DAY
ORDER BY `received` LIMIT ".intval($limit), $days);
ORDER BY `received` LIMIT ?", $days, $limit);
$count = DBA::numRows($r);
if ($count > 0) {
logger("found old conversations: ".$count);

View file

@ -216,7 +216,7 @@ class DiscoverPoCo
$x = Network::fetchUrl(get_server()."/lsearch?p=1&n=500&search=".urlencode($search));
$j = json_decode($x);
if (count($j->results)) {
if (!empty($j->results)) {
foreach ($j->results as $jj) {
// Check if the contact already exists
$exists = q("SELECT `id`, `last_contact`, `last_failure`, `updated` FROM `gcontact` WHERE `nurl` = '%s'", normalise_link($jj->url));

View file

@ -380,7 +380,8 @@
'cursor' : 'pointer'
});
var div = document.createElement("div");
var div = document.createElement("div");
div.setAttribute('class', 'ajaxbutton-wrapper');
addStyles(div, {
'display' : 'block',
'position' : 'absolute',

View file

@ -439,8 +439,10 @@
<input type="hidden" name="religion" id="profile-edit-religion" value="{{$religion.2}}" />
<input type="hidden" id="likes-jot-text" name="likes" value="{{$likes.2}}" />
<input type="hidden" id="dislikes-jot-text" name="dislikes" value="{{$dislikes.2}}" />
<input type="hidden" name="marital" id="profile-edit-marital" value="{{$marital.2}}" />
<input type="hidden" name="with" id="profile-edit-with" value="{{$with.2}}" />
<input type="hidden" name="howlong" id="profile-edit-howlong" value="{{$howlong.2}}" />
<input type="hidden" name="sexual" id="profile-edit-sexual" value="{{$sexual.2}}" />
<input type="hidden" id="romance-jot-text" name="romance" value="{{$romance.2}}" />
<input type="hidden" id="work-jot-text" name="work" value="{{$work.2}}" />
<input type="hidden" id="education-jot-text" name="education" value="{{$education.2}}" />

View file

@ -15,14 +15,14 @@ function theme_post(App $a)
}
if (isset($_POST['frio-settings-submit'])) {
PConfig::set(local_user(), 'frio', 'scheme', defaults($_POST, 'frio_scheme'));
PConfig::set(local_user(), 'frio', 'nav_bg', defaults($_POST, 'frio_nav_bg'));
PConfig::set(local_user(), 'frio', 'nav_icon_color', defaults($_POST, 'frio_nav_icon_color'));
PConfig::set(local_user(), 'frio', 'link_color', defaults($_POST, 'frio_link_color'));
PConfig::set(local_user(), 'frio', 'background_color', defaults($_POST, 'frio_background_color'));
PConfig::set(local_user(), 'frio', 'contentbg_transp', defaults($_POST, 'frio_contentbg_transp'));
PConfig::set(local_user(), 'frio', 'background_image', defaults($_POST, 'frio_background_image'));
PConfig::set(local_user(), 'frio', 'bg_image_option', defaults($_POST, 'frio_bg_image_option'));
PConfig::set(local_user(), 'frio', 'scheme', defaults($_POST, 'frio_scheme', ''));
PConfig::set(local_user(), 'frio', 'nav_bg', defaults($_POST, 'frio_nav_bg', ''));
PConfig::set(local_user(), 'frio', 'nav_icon_color', defaults($_POST, 'frio_nav_icon_color', ''));
PConfig::set(local_user(), 'frio', 'link_color', defaults($_POST, 'frio_link_color', ''));
PConfig::set(local_user(), 'frio', 'background_color', defaults($_POST, 'frio_background_color', ''));
PConfig::set(local_user(), 'frio', 'contentbg_transp', defaults($_POST, 'frio_contentbg_transp', ''));
PConfig::set(local_user(), 'frio', 'background_image', defaults($_POST, 'frio_background_image', ''));
PConfig::set(local_user(), 'frio', 'bg_image_option', defaults($_POST, 'frio_bg_image_option', ''));
PConfig::set(local_user(), 'frio', 'css_modified', time());
}
}

View file

@ -958,6 +958,10 @@ nav.navbar a, nav.navbar .btn-link {
color: #fff!important;
background-color: $menu_background_hover_color !important;
}
#photo-edit-link-wrap {
color: #555;
margin-bottom: 15px;
}
.nav-pills.preferences .dropdown .dropdown-toggle,
.nav-pills.preferences > li > .btn {
color: #bebebe;
@ -1418,6 +1422,15 @@ section #jotOpen {
color: #fff;
}
.fa.lock:before {
font-family: FontAwesome;
content: "\f023";
}
.fa.unlock:before {
font-family: FontAwesome;
content: "\f09c";
}
/* Filebrowser */
.fbrowser .breadcrumb {
margin-bottom: 0px;

View file

@ -12,7 +12,7 @@ $(document).ready(function(){
// with AjaxUpload.
$(".fbrowser").remove();
// Remove the AjaxUpload element.
$("[name=userfile]").parent().remove();
$(".ajaxbutton-wrapper").remove();
});
// Clear bs modal on close.

View file

@ -44,7 +44,7 @@ if (!isset($minimal)) {
$uid = Profile::getThemeUid();
}
$scheme = PConfig::get($uid, 'frio', 'scheme', PConfig::get($uid, 'frio', 'schema'));
if (($scheme) && ($scheme != '---')) {
if ($scheme && ($scheme != '---')) {
if (file_exists('view/theme/frio/scheme/' . $scheme . '.php')) {
$schemefile = 'view/theme/frio/scheme/' . $scheme . '.php';
require_once $schemefile;
@ -52,7 +52,7 @@ if (!isset($minimal)) {
} else {
$nav_bg = PConfig::get($uid, 'frio', 'nav_bg');
}
if (!$nav_bg) {
if (empty($nav_bg)) {
$nav_bg = "#708fa0";
}
echo '

View file

@ -1,8 +1,13 @@
<div class="wall-item-actions" id="wall-item-like-buttons-{{$id}}">
<button type="button" class="btn-link button-likes" id="like-{{$id}}" title="{{$likethis}}" onclick="dolike({{$id}},'like'); return false;" data-toggle="button"><i class="fa fa-thumbs-up" aria-hidden="true"></i>&nbsp;</button>
<button type="button" class="btn-link button-likes" id="like-{{$id}}" title="{{$likethis}}" onclick="dolike({{$id}},'like'); return false;" data-toggle="button">
<i class="faded-icon page-action fa fa-thumbs-up" aria-hidden="true"></i>
</button>
{{if $nolike}}
<button type="button" class="btn-link button-likes" id="dislike-{{$id}}" title="{{$nolike}}" onclick="dolike({{$id}},'dislike'); return false;" data-toggle="button"><i class="fa fa-thumbs-down" aria-hidden="true"></i>&nbsp;</button>
<span class="icon-padding"> </span>
<button type="button" class="btn-link button-likes" id="dislike-{{$id}}" title="{{$nolike}}" onclick="dolike({{$id}},'dislike'); return false;" data-toggle="button">
<i class="faded-icon page-action fa fa-thumbs-down" aria-hidden="true"></i>
</button>
{{/if}}
<img id="like-rotator-{{$id}}" class="like-rotator" src="images/rotator.gif" alt="{{$wait}}" title="{{$wait}}" style="display: none;" />
</div>

View file

@ -4,16 +4,30 @@
<div id="live-photos"></div>
<div id="photo-view-{{$id}}" class="generic-page-wrapper">
<h3><a href="{{$album.0}}">{{$album.1}}</a></h3>
<div id="photo-edit-link-wrap">
{{if $tools}}
<a id="photo-edit-link" href="{{$tools.edit.0}}">{{$tools.edit.1}}</a>
|
<a id="photo-toprofile-link" href="{{$tools.profile.0}}">{{$tools.profile.1}}</a>
{{/if}}
{{if $lock}} | <img src="images/lock_icon.gif" class="lockview" alt="{{$lock}}" onclick="lockview(event,'photo/{{$id}}');" /> {{/if}}
<div class="pull-left" id="photo-edit-link-wrap">
<a class="page-action faded-icon" id="photo-album-link" href="{{$album.0}}" title="{{$album.1}}" data-toggle="tooltip">
<i class="fa fa-folder-open"></i>&nbsp;{{$album.1}}
</a>
</div>
<div class="pull-right" id="photo-edit-link-wrap">
{{if $tools}}
<span class="icon-padding"> </span>
<a id="photo-edit-link" href="{{$tools.edit.0}}" title="{{$tools.edit.1}}" data-toggle="tooltip">
<i class="page-action faded-icon fa fa-pencil"></i>
</a>
<span class="icon-padding"> </span>
<a id="photo-toprofile-link" href="{{$tools.profile.0}}" title="{{$tools.profile.1}}" data-toggle="tooltip">
<i class="page-action faded-icon fa fa-user"></i>
</a>
{{/if}}
{{if $lock}}
<span class="icon-padding"> </span>
<a id="photo-lock-link" onclick="lockview(event,'photo/{{$id}}');" title="{{$lock}}" data-toggle="tooltip">
<i class="page-action faded-icon fa fa-lock"></i>
</a>
{{/if}}
</div>
<div class="clear"></div>
<div id="photo-view-wrapper">
<div id="photo-photo">

View file

@ -0,0 +1 @@
<input id="photos-upload-choose" type="file" name="userfile" />

View file

@ -0,0 +1,2 @@
<button id="photos-upload-submit" class="btn btn-primary">{{$submit|escape:'html'}}</button>

View file

@ -5,49 +5,68 @@
<div id="photos-usage-message">{{$usage}}</div>
<form action="photos/{{$nickname}}" enctype="multipart/form-data" method="post" name="photos-upload-form" id="photos-upload-form">
<div id="photos-upload-new-wrapper" >
<div id="photos-upload-newalbum-div">
<label id="photos-upload-newalbum-text" for="photos-upload-newalbum" >{{$newalbum}}</label>
</div>
<input class="form-control" id="photos-upload-newalbum" type="text" name="newalbum" />
</div>
<div id="photos-upload-new-end"></div>
<div id="photos-upload-div" class="form-group">
<label id="photos-upload-text" for="photos-upload-newalbum" >{{$newalbum}}</label>
<div id="photos-upload-exist-wrapper">
<div id="photos-upload-existing-album-div">
<label id="photos-upload-existing-album-text" for="photos-upload-album-select">{{$existalbumtext}}</label>
</div>
<select class="form-control" id="photos-upload-album-select" name="album" size="4">
{{$albumselect}}
</select>
<input id="photos-upload-album-select" class="form-control" placeholder="{{$existalbumtext}}" list="dl-photo-upload" type="text" name="album" size="4">
<datalist id="dl-photo-upload">{{$albumselect}}</datalist>
</div>
<div id="photos-upload-exist-end"></div>
<div id="photos-upload-end" class="clearfix"></div>
<div id="photos-upload-noshare-div" class="photos-upload-noshare-div pull-left" >
<div id="photos-upload-noshare-div" class="photos-upload-noshare-div checkbox pull-left" >
<input id="photos-upload-noshare" type="checkbox" name="not_visible" value="1" checked/>
<label id="photos-upload-noshare-text" for="photos-upload-noshare" >{{$nosharetext}}</label>
</div>
<div id="photos-upload-perms" class="photos-upload-perms pull-right" >
<a href="#photos-upload-permissions-wrapper" id="photos-upload-perms-menu" class="button popupbox" />
<span id="jot-perms-icon" class="icon {{$lockstate}}" ></span>{{$permissions}}
</a>
</div>
<div id="photos-upload-perms-end" class="clear"></div>
{{if $alt_uploader}}
<div id="photos-upload-perms" class="pull-right">
<button class="btn btn-default btn-sm" data-toggle="modal" data-target="#aclModal" onclick="return false;">
<i id="jot-perms-icon" class="fa {{$lockstate}}"></i> {{$permissions}}
</button>
</div>
<div class="clearfix"></div>
<div style="display: none;">
<div id="photos-upload-permissions-wrapper">
{{$aclselect}}
<div id="photos-upload-spacer"></div>
{{$alt_uploader}}
{{/if}}
{{if $default_upload_submit}}
<div class="clearfix"></div>
<div id="photos-upload-spacer"></div>
<div class="photos-upload-wrapper">
<div id="photos-upload-perms" class="btn-group pull-right">
<button class="btn btn-default" data-toggle="modal" data-target="#aclModal" onclick="return false;">
<i id="jot-perms-icon" class="fa {{$lockstate}}"></i>
</button>
{{$default_upload_submit}}
</div>
{{$default_upload_box}}
</div>
<div class="clearfix"></div>
{{/if}}
<div class="photos-upload-end" class="clearfix"></div>
{{* The modal for advanced-expire *}}
<div id="aclModal" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header" class="modal-header">
<button id="modal-close" type="button" class="close" data-dismiss="modal" aria-hidden="true">
&times;
</button>
<h4 id="modal-title" class="modal-title">{{$permissions}}</h4>
</div>
<div id="photos-upload-permissions-wrapper" class="modal-body">
{{$aclselect}}
</div>
</div>
</div>
</div>
<div id="photos-upload-spacer"></div>
{{$alt_uploader}}
{{$default_upload_box}}
{{$default_upload_submit}}
<div class="photos-upload-end" ></div>
</form>
</div>

View file

@ -434,8 +434,10 @@
<input type="hidden" name="religion" id="profile-edit-religion" value="{{$religion.2}}" />
<input type="hidden" id="likes-jot-text" name="likes" value="{{$likes.2}}" />
<input type="hidden" id="dislikes-jot-text" name="dislikes" value="{{$dislikes.2}}" />
<input type="hidden" name="marital" id="profile-edit-marital" value="{{$marital.2}}" />
<input type="hidden" name="with" id="profile-edit-with" value="{{$with.2}}" />
<input type="hidden" name="howlong" id="profile-edit-howlong" value="{{$howlong.2}}" />
<input type="hidden" name="sexual" id="profile-edit-sexual" value="{{$sexual.2}}" />
<input type="hidden" id="romance-jot-text" name="romance" value="{{$romance.2}}" />
<input type="hidden" id="work-jot-text" name="work" value="{{$work.2}}" />
<input type="hidden" id="education-jot-text" name="education" value="{{$education.2}}" />