Merge pull request #4674 from annando/acl-fix

Fix the ACL problem issue 4616
This commit is contained in:
Hypolite Petovan 2018-03-24 15:48:02 -04:00 committed by GitHub
commit 641bd5eaa6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 2625 additions and 2614 deletions

View file

@ -1,358 +1,369 @@
<?php <?php
/** /**
* @file src/Core/Acl.php * @file src/Core/Acl.php
*/ */
namespace Friendica\Core; namespace Friendica\Core;
use dba; use dba;
use Friendica\BaseObject; use Friendica\BaseObject;
use Friendica\Content\Feature; use Friendica\Content\Feature;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\GContact; use Friendica\Model\GContact;
use Friendica\Util\Network; use Friendica\Util\Network;
use const CONTACT_IS_FRIEND; use const CONTACT_IS_FRIEND;
use const NETWORK_DFRN; use const NETWORK_DFRN;
use const NETWORK_DIASPORA; use const NETWORK_DIASPORA;
use const NETWORK_FACEBOOK; use const NETWORK_FACEBOOK;
use const NETWORK_MAIL; use const NETWORK_MAIL;
use const NETWORK_OSTATUS; use const NETWORK_OSTATUS;
use const PHP_EOL; use const PHP_EOL;
use function dbesc; use function dbesc;
use function defaults; use function defaults;
use function get_markup_template; use function get_markup_template;
use function get_server; use function get_server;
use function local_user; use function local_user;
use function remote_user; use function remote_user;
use function replace_macros; use function replace_macros;
/** /**
* Handle ACL management and display * Handle ACL management and display
* *
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class ACL extends BaseObject class ACL extends BaseObject
{ {
/** /**
* Returns a select input tag with all the contact of the local user * Returns a select input tag with all the contact of the local user
* *
* @param string $selname Name attribute of the select input tag * @param string $selname Name attribute of the select input tag
* @param string $selclass Class attribute of the select input tag * @param string $selclass Class attribute of the select input tag
* @param array $options Available options: * @param array $options Available options:
* - size: length of the select box * - size: length of the select box
* - mutual_friends: Only used for the hook * - mutual_friends: Only used for the hook
* - single: Only used for the hook * - single: Only used for the hook
* - exclude: Only used for the hook * - exclude: Only used for the hook
* @param array $preselected Contact ID that should be already selected * @param array $preselected Contact ID that should be already selected
* @return string * @return string
*/ */
public static function getSuggestContactSelectHTML($selname, $selclass, array $options = [], array $preselected = []) public static function getSuggestContactSelectHTML($selname, $selclass, array $options = [], array $preselected = [])
{ {
$a = self::getApp(); $a = self::getApp();
$networks = null; $networks = null;
$size = defaults($options, 'size', 4); $size = defaults($options, 'size', 4);
$mutual = !empty($options['mutual_friends']); $mutual = !empty($options['mutual_friends']);
$single = !empty($options['single']) && empty($options['multiple']); $single = !empty($options['single']) && empty($options['multiple']);
$exclude = defaults($options, 'exclude', false); $exclude = defaults($options, 'exclude', false);
switch (defaults($options, 'networks', Protocol::PHANTOM)) { switch (defaults($options, 'networks', Protocol::PHANTOM)) {
case 'DFRN_ONLY': case 'DFRN_ONLY':
$networks = [NETWORK_DFRN]; $networks = [NETWORK_DFRN];
break; break;
case 'PRIVATE': case 'PRIVATE':
if (!empty($a->user['prvnets'])) { if (!empty($a->user['prvnets'])) {
$networks = [NETWORK_DFRN, NETWORK_MAIL, NETWORK_DIASPORA]; $networks = [NETWORK_DFRN, NETWORK_MAIL, NETWORK_DIASPORA];
} else { } else {
$networks = [NETWORK_DFRN, NETWORK_FACEBOOK, NETWORK_MAIL, NETWORK_DIASPORA]; $networks = [NETWORK_DFRN, NETWORK_FACEBOOK, NETWORK_MAIL, NETWORK_DIASPORA];
} }
break; break;
case 'TWO_WAY': case 'TWO_WAY':
if (!empty($a->user['prvnets'])) { if (!empty($a->user['prvnets'])) {
$networks = [NETWORK_DFRN, NETWORK_MAIL, NETWORK_DIASPORA]; $networks = [NETWORK_DFRN, NETWORK_MAIL, NETWORK_DIASPORA];
} else { } else {
$networks = [NETWORK_DFRN, NETWORK_FACEBOOK, NETWORK_MAIL, NETWORK_DIASPORA, NETWORK_OSTATUS]; $networks = [NETWORK_DFRN, NETWORK_FACEBOOK, NETWORK_MAIL, NETWORK_DIASPORA, NETWORK_OSTATUS];
} }
break; break;
default: /// @TODO Maybe log this call? default: /// @TODO Maybe log this call?
break; break;
} }
$x = ['options' => $options, 'size' => $size, 'single' => $single, 'mutual' => $mutual, 'exclude' => $exclude, 'networks' => $networks]; $x = ['options' => $options, 'size' => $size, 'single' => $single, 'mutual' => $mutual, 'exclude' => $exclude, 'networks' => $networks];
Addon::callHooks('contact_select_options', $x); Addon::callHooks('contact_select_options', $x);
$o = ''; $o = '';
$sql_extra = ''; $sql_extra = '';
if (!empty($x['mutual'])) { if (!empty($x['mutual'])) {
$sql_extra .= sprintf(" AND `rel` = %d ", intval(CONTACT_IS_FRIEND)); $sql_extra .= sprintf(" AND `rel` = %d ", intval(CONTACT_IS_FRIEND));
} }
if (!empty($x['exclude'])) { if (!empty($x['exclude'])) {
$sql_extra .= sprintf(" AND `id` != %d ", intval($x['exclude'])); $sql_extra .= sprintf(" AND `id` != %d ", intval($x['exclude']));
} }
if (!empty($x['networks'])) { if (!empty($x['networks'])) {
/// @TODO rewrite to foreach() /// @TODO rewrite to foreach()
array_walk($x['networks'], function (&$value) { array_walk($x['networks'], function (&$value) {
$value = "'" . dbesc($value) . "'"; $value = "'" . dbesc($value) . "'";
}); });
$str_nets = implode(',', $x['networks']); $str_nets = implode(',', $x['networks']);
$sql_extra .= " AND `network` IN ( $str_nets ) "; $sql_extra .= " AND `network` IN ( $str_nets ) ";
} }
$tabindex = (!empty($options['tabindex']) ? 'tabindex="' . $options["tabindex"] . '"' : ''); $tabindex = (!empty($options['tabindex']) ? 'tabindex="' . $options["tabindex"] . '"' : '');
if (!empty($x['single'])) { if (!empty($x['single'])) {
$o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"" . $x['size'] . "\" $tabindex >\r\n"; $o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"" . $x['size'] . "\" $tabindex >\r\n";
} else { } else {
$o .= "<select name=\"{$selname}[]\" id=\"$selclass\" class=\"$selclass\" multiple=\"multiple\" size=\"" . $x['size'] . "$\" $tabindex >\r\n"; $o .= "<select name=\"{$selname}[]\" id=\"$selclass\" class=\"$selclass\" multiple=\"multiple\" size=\"" . $x['size'] . "$\" $tabindex >\r\n";
} }
$stmt = dba::p("SELECT `id`, `name`, `url`, `network` FROM `contact` $stmt = dba::p("SELECT `id`, `name`, `url`, `network` FROM `contact`
WHERE `uid` = ? AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != '' WHERE `uid` = ? AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
$sql_extra $sql_extra
ORDER BY `name` ASC ", intval(local_user()) ORDER BY `name` ASC ", intval(local_user())
); );
$contacts = dba::inArray($stmt); $contacts = dba::inArray($stmt);
$arr = ['contact' => $contacts, 'entry' => $o]; $arr = ['contact' => $contacts, 'entry' => $o];
// e.g. 'network_pre_contact_deny', 'profile_pre_contact_allow' // e.g. 'network_pre_contact_deny', 'profile_pre_contact_allow'
Addon::callHooks($a->module . '_pre_' . $selname, $arr); Addon::callHooks($a->module . '_pre_' . $selname, $arr);
if (DBM::is_result($contacts)) { if (DBM::is_result($contacts)) {
foreach ($contacts as $contact) { foreach ($contacts as $contact) {
if (in_array($contact['id'], $preselected)) { if (in_array($contact['id'], $preselected)) {
$selected = ' selected="selected" '; $selected = ' selected="selected" ';
} else { } else {
$selected = ''; $selected = '';
} }
$trimmed = mb_substr($contact['name'], 0, 20); $trimmed = mb_substr($contact['name'], 0, 20);
$o .= "<option value=\"{$contact['id']}\" $selected title=\"{$contact['name']}|{$contact['url']}\" >$trimmed</option>\r\n"; $o .= "<option value=\"{$contact['id']}\" $selected title=\"{$contact['name']}|{$contact['url']}\" >$trimmed</option>\r\n";
} }
} }
$o .= '</select>' . PHP_EOL; $o .= '</select>' . PHP_EOL;
Addon::callHooks($a->module . '_post_' . $selname, $o); Addon::callHooks($a->module . '_post_' . $selname, $o);
return $o; return $o;
} }
/** /**
* Returns a select input tag with all the contact of the local user * Returns a select input tag with all the contact of the local user
* *
* @param string $selname Name attribute of the select input tag * @param string $selname Name attribute of the select input tag
* @param string $selclass Class attribute of the select input tag * @param string $selclass Class attribute of the select input tag
* @param array $preselected Contact IDs that should be already selected * @param array $preselected Contact IDs that should be already selected
* @param int $size Length of the select box * @param int $size Length of the select box
* @param int $tabindex Select input tag tabindex attribute * @param int $tabindex Select input tag tabindex attribute
* @return string * @return string
*/ */
public static function getMessageContactSelectHTML($selname, $selclass, array $preselected = [], $size = 4, $tabindex = null) public static function getMessageContactSelectHTML($selname, $selclass, array $preselected = [], $size = 4, $tabindex = null)
{ {
$a = self::getApp(); $a = self::getApp();
$o = ''; $o = '';
// When used for private messages, we limit correspondence to mutual DFRN/Friendica friends and the selector // When used for private messages, we limit correspondence to mutual DFRN/Friendica friends and the selector
// to one recipient. By default our selector allows multiple selects amongst all contacts. // to one recipient. By default our selector allows multiple selects amongst all contacts.
$sql_extra = sprintf(" AND `rel` = %d ", intval(CONTACT_IS_FRIEND)); $sql_extra = sprintf(" AND `rel` = %d ", intval(CONTACT_IS_FRIEND));
$sql_extra .= sprintf(" AND `network` IN ('%s' , '%s') ", NETWORK_DFRN, NETWORK_DIASPORA); $sql_extra .= sprintf(" AND `network` IN ('%s' , '%s') ", NETWORK_DFRN, NETWORK_DIASPORA);
$tabindex_attr = !empty($tabindex) ? ' tabindex="' . intval($tabindex) . '"' : ''; $tabindex_attr = !empty($tabindex) ? ' tabindex="' . intval($tabindex) . '"' : '';
$hidepreselected = ''; $hidepreselected = '';
if ($preselected) { if ($preselected) {
$sql_extra .= " AND `id` IN (" . implode(",", $preselected) . ")"; $sql_extra .= " AND `id` IN (" . implode(",", $preselected) . ")";
$hidepreselected = ' style="display: none;"'; $hidepreselected = ' style="display: none;"';
} }
$o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"$size\"$tabindex_attr$hidepreselected>\r\n"; $o .= "<select name=\"$selname\" id=\"$selclass\" class=\"$selclass\" size=\"$size\"$tabindex_attr$hidepreselected>\r\n";
$stmt = dba::p("SELECT `id`, `name`, `url`, `network` FROM `contact` $stmt = dba::p("SELECT `id`, `name`, `url`, `network` FROM `contact`
WHERE `uid` = ? AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != '' WHERE `uid` = ? AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
$sql_extra $sql_extra
ORDER BY `name` ASC ", intval(local_user()) ORDER BY `name` ASC ", intval(local_user())
); );
$contacts = dba::inArray($stmt); $contacts = dba::inArray($stmt);
$arr = ['contact' => $contacts, 'entry' => $o]; $arr = ['contact' => $contacts, 'entry' => $o];
// e.g. 'network_pre_contact_deny', 'profile_pre_contact_allow' // e.g. 'network_pre_contact_deny', 'profile_pre_contact_allow'
Addon::callHooks($a->module . '_pre_' . $selname, $arr); Addon::callHooks($a->module . '_pre_' . $selname, $arr);
$receiverlist = []; $receiverlist = [];
if (DBM::is_result($contacts)) { if (DBM::is_result($contacts)) {
foreach ($contacts as $contact) { foreach ($contacts as $contact) {
if (in_array($contact['id'], $preselected)) { if (in_array($contact['id'], $preselected)) {
$selected = ' selected="selected"'; $selected = ' selected="selected"';
} else { } else {
$selected = ''; $selected = '';
} }
$trimmed = Protocol::formatMention($contact['url'], $contact['name']); $trimmed = Protocol::formatMention($contact['url'], $contact['name']);
$receiverlist[] = $trimmed; $receiverlist[] = $trimmed;
$o .= "<option value=\"{$contact['id']}\"$selected title=\"{$contact['name']}|{$contact['url']}\" >$trimmed</option>\r\n"; $o .= "<option value=\"{$contact['id']}\"$selected title=\"{$contact['name']}|{$contact['url']}\" >$trimmed</option>\r\n";
} }
} }
$o .= '</select>' . PHP_EOL; $o .= '</select>' . PHP_EOL;
if ($preselected) { if ($preselected) {
$o .= implode(', ', $receiverlist); $o .= implode(', ', $receiverlist);
} }
Addon::callHooks($a->module . '_post_' . $selname, $o); Addon::callHooks($a->module . '_post_' . $selname, $o);
return $o; return $o;
} }
/** private static function fixACL(&$item)
* Return the default permission of the provided user array {
* $item = intval(str_replace(['<', '>'], ['', ''], $item));
* @param array $user }
* @return array Hash of contact id lists
*/ /**
public static function getDefaultUserPermissions(array $user = null) * Return the default permission of the provided user array
{ *
$matches = []; * @param array $user
* @return array Hash of contact id lists
$acl_regex = '/<([0-9]+)>/i'; */
public static function getDefaultUserPermissions(array $user = null)
preg_match_all($acl_regex, defaults($user, 'allow_cid', ''), $matches); {
$allow_cid = $matches[1]; $matches = [];
preg_match_all($acl_regex, defaults($user, 'allow_gid', ''), $matches);
$allow_gid = $matches[1]; $acl_regex = '/<([0-9]+)>/i';
preg_match_all($acl_regex, defaults($user, 'deny_cid', ''), $matches);
$deny_cid = $matches[1]; preg_match_all($acl_regex, defaults($user, 'allow_cid', ''), $matches);
preg_match_all($acl_regex, defaults($user, 'deny_gid', ''), $matches); $allow_cid = $matches[1];
$deny_gid = $matches[1]; preg_match_all($acl_regex, defaults($user, 'allow_gid', ''), $matches);
$allow_gid = $matches[1];
Contact::pruneUnavailable($allow_cid); preg_match_all($acl_regex, defaults($user, 'deny_cid', ''), $matches);
$deny_cid = $matches[1];
return [ preg_match_all($acl_regex, defaults($user, 'deny_gid', ''), $matches);
'allow_cid' => $allow_cid, $deny_gid = $matches[1];
'allow_gid' => $allow_gid,
'deny_cid' => $deny_cid, // Reformats the ACL data so that it is accepted by the JS frontend
'deny_gid' => $deny_gid, array_walk($allow_cid, 'self::fixACL');
]; array_walk($allow_gid, 'self::fixACL');
} array_walk($deny_cid, 'self::fixACL');
array_walk($deny_gid, 'self::fixACL');
/**
* Return the full jot ACL selector HTML Contact::pruneUnavailable($allow_cid);
*
* @param array $user return [
* @param bool $show_jotnets 'allow_cid' => $allow_cid,
* @return string 'allow_gid' => $allow_gid,
*/ 'deny_cid' => $deny_cid,
public static function getFullSelectorHTML(array $user = null, $show_jotnets = false) 'deny_gid' => $deny_gid,
{ ];
$perms = self::getDefaultUserPermissions($user); }
$jotnets = ''; /**
if ($show_jotnets) { * Return the full jot ACL selector HTML
$imap_disabled = !function_exists('imap_open') || Config::get('system', 'imap_disabled'); *
* @param array $user
$mail_enabled = false; * @param bool $show_jotnets
$pubmail_enabled = false; * @return string
*/
if (!$imap_disabled) { public static function getFullSelectorHTML(array $user = null, $show_jotnets = false)
$mailacct = dba::selectFirst('mailacct', ['pubmail'], ['`uid` = ? AND `server` != ""', local_user()]); {
if (DBM::is_result($mailacct)) { $perms = self::getDefaultUserPermissions($user);
$mail_enabled = true;
$pubmail_enabled = !empty($mailacct['pubmail']); $jotnets = '';
} if ($show_jotnets) {
} $imap_disabled = !function_exists('imap_open') || Config::get('system', 'imap_disabled');
if (empty($user['hidewall'])) { $mail_enabled = false;
if ($mail_enabled) { $pubmail_enabled = false;
$selected = $pubmail_enabled ? ' checked="checked"' : '';
$jotnets .= '<div class="profile-jot-net"><input type="checkbox" name="pubmail_enable"' . $selected . ' value="1" /> ' . L10n::t("Post to Email") . '</div>'; if (!$imap_disabled) {
} $mailacct = dba::selectFirst('mailacct', ['pubmail'], ['`uid` = ? AND `server` != ""', local_user()]);
if (DBM::is_result($mailacct)) {
Addon::callHooks('jot_networks', $jotnets); $mail_enabled = true;
} else { $pubmail_enabled = !empty($mailacct['pubmail']);
$jotnets .= L10n::t('Connectors disabled, since "%s" is enabled.', }
L10n::t('Hide your profile details from unknown viewers?')); }
}
} if (empty($user['hidewall'])) {
if ($mail_enabled) {
$tpl = get_markup_template('acl_selector.tpl'); $selected = $pubmail_enabled ? ' checked="checked"' : '';
$o = replace_macros($tpl, [ $jotnets .= '<div class="profile-jot-net"><input type="checkbox" name="pubmail_enable"' . $selected . ' value="1" /> ' . L10n::t("Post to Email") . '</div>';
'$showall' => L10n::t('Visible to everybody'), }
'$show' => L10n::t('show'),
'$hide' => L10n::t('don\'t show'), Addon::callHooks('jot_networks', $jotnets);
'$allowcid' => json_encode($perms['allow_cid']), } else {
'$allowgid' => json_encode($perms['allow_gid']), $jotnets .= L10n::t('Connectors disabled, since "%s" is enabled.',
'$denycid' => json_encode($perms['deny_cid']), L10n::t('Hide your profile details from unknown viewers?'));
'$denygid' => json_encode($perms['deny_gid']), }
'$networks' => $show_jotnets, }
'$emailcc' => L10n::t('CC: email addresses'),
'$emtitle' => L10n::t('Example: bob@example.com, mary@example.com'), $tpl = get_markup_template('acl_selector.tpl');
'$jotnets' => $jotnets, $o = replace_macros($tpl, [
'$aclModalTitle' => L10n::t('Permissions'), '$showall' => L10n::t('Visible to everybody'),
'$aclModalDismiss' => L10n::t('Close'), '$show' => L10n::t('show'),
'$features' => [ '$hide' => L10n::t('don\'t show'),
'aclautomention' => Feature::isEnabled($user['uid'], 'aclautomention') ? 'true' : 'false' '$allowcid' => json_encode($perms['allow_cid']),
], '$allowgid' => json_encode($perms['allow_gid']),
]); '$denycid' => json_encode($perms['deny_cid']),
'$denygid' => json_encode($perms['deny_gid']),
return $o; '$networks' => $show_jotnets,
} '$emailcc' => L10n::t('CC: email addresses'),
'$emtitle' => L10n::t('Example: bob@example.com, mary@example.com'),
/** '$jotnets' => $jotnets,
* Searching for global contacts for autocompletion '$aclModalTitle' => L10n::t('Permissions'),
* '$aclModalDismiss' => L10n::t('Close'),
* @brief Searching for global contacts for autocompletion '$features' => [
* @param string $search Name or part of a name or nick 'aclautomention' => Feature::isEnabled($user['uid'], 'aclautomention') ? 'true' : 'false'
* @param string $mode Search mode (e.g. "community") ],
* @return array with the search results ]);
*/
public static function contactAutocomplete($search, $mode) return $o;
{ }
if ((Config::get('system', 'block_public')) && (!local_user()) && (!remote_user())) {
return []; /**
} * Searching for global contacts for autocompletion
*
// don't search if search term has less than 2 characters * @brief Searching for global contacts for autocompletion
if (!$search || mb_strlen($search) < 2) { * @param string $search Name or part of a name or nick
return []; * @param string $mode Search mode (e.g. "community")
} * @return array with the search results
*/
if (substr($search, 0, 1) === '@') { public static function contactAutocomplete($search, $mode)
$search = substr($search, 1); {
} if ((Config::get('system', 'block_public')) && (!local_user()) && (!remote_user())) {
return [];
// check if searching in the local global contact table is enabled }
if (Config::get('system', 'poco_local_search')) {
$return = GContact::searchByName($search, $mode); // don't search if search term has less than 2 characters
} else { if (!$search || mb_strlen($search) < 2) {
$a = self::getApp(); return [];
$p = $a->pager['page'] != 1 ? '&p=' . $a->pager['page'] : ''; }
$response = Network::curl(get_server() . '/lsearch?f=' . $p . '&search=' . urlencode($search)); if (substr($search, 0, 1) === '@') {
if ($response['success']) { $search = substr($search, 1);
$lsearch = json_decode($response['body'], true); }
if (!empty($lsearch['results'])) {
$return = $lsearch['results']; // check if searching in the local global contact table is enabled
} if (Config::get('system', 'poco_local_search')) {
} $return = GContact::searchByName($search, $mode);
} } else {
$a = self::getApp();
return defaults($return, []); $p = $a->pager['page'] != 1 ? '&p=' . $a->pager['page'] : '';
}
} $response = Network::curl(get_server() . '/lsearch?f=' . $p . '&search=' . urlencode($search));
if ($response['success']) {
$lsearch = json_decode($response['body'], true);
if (!empty($lsearch['results'])) {
$return = $lsearch['results'];
}
}
}
return defaults($return, []);
}
}

View file

@ -1,56 +1,56 @@
<?php <?php
namespace Friendica\Core\Cache; namespace Friendica\Core\Cache;
use dba; use dba;
use Friendica\Core\Cache; use Friendica\Core\Cache;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
/** /**
* Database Cache Driver * Database Cache Driver
* *
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class DatabaseCacheDriver implements ICacheDriver class DatabaseCacheDriver implements ICacheDriver
{ {
public function get($key) public function get($key)
{ {
$cache = dba::selectFirst('cache', ['v'], ['`k` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]); $cache = dba::selectFirst('cache', ['v'], ['`k` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]);
if (DBM::is_result($cache)) { if (DBM::is_result($cache)) {
$cached = $cache['v']; $cached = $cache['v'];
$value = @unserialize($cached); $value = @unserialize($cached);
// Only return a value if the serialized value is valid. // Only return a value if the serialized value is valid.
// We also check if the db entry is a serialized // We also check if the db entry is a serialized
// boolean 'false' value (which we want to return). // boolean 'false' value (which we want to return).
if ($cached === serialize(false) || $value !== false) { if ($cached === serialize(false) || $value !== false) {
return $value; return $value;
} }
} }
return null; return null;
} }
public function set($key, $value, $duration = Cache::MONTH) public function set($key, $value, $duration = Cache::MONTH)
{ {
$fields = [ $fields = [
'v' => serialize($value), 'v' => serialize($value),
'expires' => DateTimeFormat::utc('now + ' . $duration . ' seconds'), 'expires' => DateTimeFormat::utc('now + ' . $duration . ' seconds'),
'updated' => DateTimeFormat::utcNow() 'updated' => DateTimeFormat::utcNow()
]; ];
return dba::update('cache', $fields, ['k' => $key], true); return dba::update('cache', $fields, ['k' => $key], true);
} }
public function delete($key) public function delete($key)
{ {
return dba::delete('cache', ['k' => $key]); return dba::delete('cache', ['k' => $key]);
} }
public function clear() public function clear()
{ {
return dba::delete('cache', ['`expires` < NOW()']); return dba::delete('cache', ['`expires` < NOW()']);
} }
} }

View file

@ -1,50 +1,50 @@
<?php <?php
namespace Friendica\Core\Cache; namespace Friendica\Core\Cache;
use Friendica\Core\Cache; use Friendica\Core\Cache;
/** /**
* Cache Driver Interface * Cache Driver Interface
* *
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
interface ICacheDriver interface ICacheDriver
{ {
/** /**
* Fetches cached data according to the key * Fetches cached data according to the key
* *
* @param string $key The key to the cached data * @param string $key The key to the cached data
* *
* @return mixed Cached $value or "null" if not found * @return mixed Cached $value or "null" if not found
*/ */
public function get($key); public function get($key);
/** /**
* Stores data in the cache identified by the key. The input $value can have multiple formats. * Stores data in the cache identified by the key. The input $value can have multiple formats.
* *
* @param string $key The cache key * @param string $key The cache key
* @param mixed $value The value to store * @param mixed $value The value to store
* @param integer $duration The cache lifespan, must be one of the Cache constants * @param integer $duration The cache lifespan, must be one of the Cache constants
* *
* @return bool * @return bool
*/ */
public function set($key, $value, $duration = Cache::MONTH); public function set($key, $value, $duration = Cache::MONTH);
/** /**
* Delete a key from the cache * Delete a key from the cache
* *
* @param string $key * @param string $key
* *
* @return bool * @return bool
*/ */
public function delete($key); public function delete($key);
/** /**
* Remove outdated data from the cache * Remove outdated data from the cache
* *
* @return bool * @return bool
*/ */
public function clear(); public function clear();
} }

View file

@ -1,77 +1,77 @@
<?php <?php
namespace Friendica\Core\Cache; namespace Friendica\Core\Cache;
use Friendica\BaseObject; use Friendica\BaseObject;
use Friendica\Core\Cache; use Friendica\Core\Cache;
/** /**
* Memcache Cache Driver * Memcache Cache Driver
* *
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class MemcacheCacheDriver extends BaseObject implements ICacheDriver class MemcacheCacheDriver extends BaseObject implements ICacheDriver
{ {
/** /**
* @var Memcache * @var Memcache
*/ */
private $memcache; private $memcache;
public function __construct($memcache_host, $memcache_port) public function __construct($memcache_host, $memcache_port)
{ {
if (!class_exists('Memcache', false)) { if (!class_exists('Memcache', false)) {
throw new \Exception('Memcache class isn\'t available'); throw new \Exception('Memcache class isn\'t available');
} }
$this->memcache = new \Memcache(); $this->memcache = new \Memcache();
if (!$this->memcache->connect($memcache_host, $memcache_port)) { if (!$this->memcache->connect($memcache_host, $memcache_port)) {
throw new \Exception('Expected Memcache server at ' . $memcache_host . ':' . $memcache_port . ' isn\'t available'); throw new \Exception('Expected Memcache server at ' . $memcache_host . ':' . $memcache_port . ' isn\'t available');
} }
} }
public function get($key) public function get($key)
{ {
$return = null; $return = null;
// We fetch with the hostname as key to avoid problems with other applications // We fetch with the hostname as key to avoid problems with other applications
$cached = $this->memcache->get(self::getApp()->get_hostname() . ':' . $key); $cached = $this->memcache->get(self::getApp()->get_hostname() . ':' . $key);
// @see http://php.net/manual/en/memcache.get.php#84275 // @see http://php.net/manual/en/memcache.get.php#84275
if (is_bool($cached) || is_double($cached) || is_long($cached)) { if (is_bool($cached) || is_double($cached) || is_long($cached)) {
return $return; return $return;
} }
$value = @unserialize($cached); $value = @unserialize($cached);
// Only return a value if the serialized value is valid. // Only return a value if the serialized value is valid.
// We also check if the db entry is a serialized // We also check if the db entry is a serialized
// boolean 'false' value (which we want to return). // boolean 'false' value (which we want to return).
if ($cached === serialize(false) || $value !== false) { if ($cached === serialize(false) || $value !== false) {
$return = $value; $return = $value;
} }
return $return; return $return;
} }
public function set($key, $value, $duration = Cache::MONTH) public function set($key, $value, $duration = Cache::MONTH)
{ {
// We store with the hostname as key to avoid problems with other applications // We store with the hostname as key to avoid problems with other applications
return $this->memcache->set( return $this->memcache->set(
self::getApp()->get_hostname() . ":" . $key, self::getApp()->get_hostname() . ":" . $key,
serialize($value), serialize($value),
MEMCACHE_COMPRESSED, MEMCACHE_COMPRESSED,
time() + $duration time() + $duration
); );
} }
public function delete($key) public function delete($key)
{ {
return $this->memcache->delete($key); return $this->memcache->delete($key);
} }
public function clear() public function clear()
{ {
return true; return true;
} }
} }

View file

@ -1,68 +1,68 @@
<?php <?php
namespace Friendica\Core\Cache; namespace Friendica\Core\Cache;
use Friendica\BaseObject; use Friendica\BaseObject;
use Friendica\Core\Cache; use Friendica\Core\Cache;
/** /**
* Memcached Cache Driver * Memcached Cache Driver
* *
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class MemcachedCacheDriver extends BaseObject implements ICacheDriver class MemcachedCacheDriver extends BaseObject implements ICacheDriver
{ {
/** /**
* @var Memcached * @var Memcached
*/ */
private $memcached; private $memcached;
public function __construct(array $memcached_hosts) public function __construct(array $memcached_hosts)
{ {
if (!class_exists('Memcached', false)) { if (!class_exists('Memcached', false)) {
throw new \Exception('Memcached class isn\'t available'); throw new \Exception('Memcached class isn\'t available');
} }
$this->memcached = new \Memcached(); $this->memcached = new \Memcached();
$this->memcached->addServers($memcached_hosts); $this->memcached->addServers($memcached_hosts);
if (count($this->memcached->getServerList()) == 0) { if (count($this->memcached->getServerList()) == 0) {
throw new \Exception('Expected Memcached servers aren\'t available, config:' . var_export($memcached_hosts, true)); throw new \Exception('Expected Memcached servers aren\'t available, config:' . var_export($memcached_hosts, true));
} }
} }
public function get($key) public function get($key)
{ {
$return = null; $return = null;
// We fetch with the hostname as key to avoid problems with other applications // We fetch with the hostname as key to avoid problems with other applications
$value = $this->memcached->get(self::getApp()->get_hostname() . ':' . $key); $value = $this->memcached->get(self::getApp()->get_hostname() . ':' . $key);
if ($this->memcached->getResultCode() === \Memcached::RES_SUCCESS) { if ($this->memcached->getResultCode() === \Memcached::RES_SUCCESS) {
$return = $value; $return = $value;
} }
return $return; return $return;
} }
public function set($key, $value, $duration = Cache::MONTH) public function set($key, $value, $duration = Cache::MONTH)
{ {
// We store with the hostname as key to avoid problems with other applications // We store with the hostname as key to avoid problems with other applications
return $this->memcached->set( return $this->memcached->set(
self::getApp()->get_hostname() . ":" . $key, self::getApp()->get_hostname() . ":" . $key,
$value, $value,
time() + $duration time() + $duration
); );
} }
public function delete($key) public function delete($key)
{ {
return $this->memcached->delete($key); return $this->memcached->delete($key);
} }
public function clear() public function clear()
{ {
return true; return true;
} }
} }

View file

@ -1,72 +1,72 @@
<?php <?php
namespace Friendica\Core\Config; namespace Friendica\Core\Config;
/** /**
* *
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
interface IConfigAdapter interface IConfigAdapter
{ {
/** /**
* @brief Loads all configuration values into a cached storage. * @brief Loads all configuration values into a cached storage.
* *
* All configuration values of the system are stored in global cache * All configuration values of the system are stored in global cache
* which is available under the global variable $a->config * which is available under the global variable $a->config
* *
* @param string $cat The category of the configuration values to load * @param string $cat The category of the configuration values to load
* *
* @return void * @return void
*/ */
public function load($cat = "config"); public function load($cat = "config");
/** /**
* @brief Get a particular user's config variable given the category name * @brief Get a particular user's config variable given the category name
* ($family) and a key. * ($family) and a key.
* *
* Get a particular config value from the given category ($family) * Get a particular config value from the given category ($family)
* and the $key from a cached storage in $a->config[$uid]. * and the $key from a cached storage in $a->config[$uid].
* $instore is only used by the set_config function * $instore is only used by the set_config function
* to determine if the key already exists in the DB * to determine if the key already exists in the DB
* If a key is found in the DB but doesn't exist in * If a key is found in the DB but doesn't exist in
* local config cache, pull it into the cache so we don't have * local config cache, pull it into the cache so we don't have
* to hit the DB again for this item. * to hit the DB again for this item.
* *
* @param string $cat The category of the configuration value * @param string $cat The category of the configuration value
* @param string $k The configuration key to query * @param string $k The configuration key to query
* @param mixed $default_value optional, The value to return if key is not set (default: null) * @param mixed $default_value optional, The value to return if key is not set (default: null)
* @param boolean $refresh optional, If true the config is loaded from the db and not from the cache (default: false) * @param boolean $refresh optional, If true the config is loaded from the db and not from the cache (default: false)
* *
* @return mixed Stored value or null if it does not exist * @return mixed Stored value or null if it does not exist
*/ */
public function get($cat, $k, $default_value = null, $refresh = false); public function get($cat, $k, $default_value = null, $refresh = false);
/** /**
* @brief Sets a configuration value for system config * @brief Sets a configuration value for system config
* *
* Stores a config value ($value) in the category ($family) under the key ($key) * Stores a config value ($value) in the category ($family) under the key ($key)
* for the user_id $uid. * for the user_id $uid.
* *
* Note: Please do not store booleans - convert to 0/1 integer values! * Note: Please do not store booleans - convert to 0/1 integer values!
* *
* @param string $family The category of the configuration value * @param string $family The category of the configuration value
* @param string $key The configuration key to set * @param string $key The configuration key to set
* @param mixed $value The value to store * @param mixed $value The value to store
* *
* @return mixed Stored $value or false if the database update failed * @return mixed Stored $value or false if the database update failed
*/ */
public function set($cat, $k, $value); public function set($cat, $k, $value);
/** /**
* @brief Deletes the given key from the system configuration. * @brief Deletes the given key from the system configuration.
* *
* Removes the configured value from the stored cache in $a->config * Removes the configured value from the stored cache in $a->config
* and removes it from the database. * and removes it from the database.
* *
* @param string $cat The category of the configuration value * @param string $cat The category of the configuration value
* @param string $k The configuration key to delete * @param string $k The configuration key to delete
* *
* @return mixed * @return mixed
*/ */
public function delete($cat, $k); public function delete($cat, $k);
} }

View file

@ -1,77 +1,77 @@
<?php <?php
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates * To change this template file, choose Tools | Templates
* and open the template in the editor. * and open the template in the editor.
*/ */
namespace Friendica\Core\Config; namespace Friendica\Core\Config;
/** /**
* *
* @author benlo * @author benlo
*/ */
interface IPConfigAdapter interface IPConfigAdapter
{ {
/** /**
* @brief Loads all configuration values of a user's config family into a cached storage. * @brief Loads all configuration values of a user's config family into a cached storage.
* *
* All configuration values of the given user are stored in global cache * All configuration values of the given user are stored in global cache
* which is available under the global variable $a->config[$uid]. * which is available under the global variable $a->config[$uid].
* *
* @param string $uid The user_id * @param string $uid The user_id
* @param string $cat The category of the configuration value * @param string $cat The category of the configuration value
* *
* @return void * @return void
*/ */
public function load($uid, $cat); public function load($uid, $cat);
/** /**
* @brief Get a particular user's config variable given the category name * @brief Get a particular user's config variable given the category name
* ($family) and a key. * ($family) and a key.
* *
* Get a particular user's config value from the given category ($family) * Get a particular user's config value from the given category ($family)
* and the $key from a cached storage in $a->config[$uid]. * and the $key from a cached storage in $a->config[$uid].
* *
* @param string $uid The user_id * @param string $uid The user_id
* @param string $cat The category of the configuration value * @param string $cat The category of the configuration value
* @param string $k The configuration key to query * @param string $k The configuration key to query
* @param mixed $default_value optional, The value to return if key is not set (default: null) * @param mixed $default_value optional, The value to return if key is not set (default: null)
* @param boolean $refresh optional, If true the config is loaded from the db and not from the cache (default: false) * @param boolean $refresh optional, If true the config is loaded from the db and not from the cache (default: false)
* *
* @return mixed Stored value or null if it does not exist * @return mixed Stored value or null if it does not exist
*/ */
public function get($uid, $cat, $k, $default_value = null, $refresh = false); public function get($uid, $cat, $k, $default_value = null, $refresh = false);
/** /**
* @brief Sets a configuration value for a user * @brief Sets a configuration value for a user
* *
* Stores a config value ($value) in the category ($family) under the key ($key) * Stores a config value ($value) in the category ($family) under the key ($key)
* for the user_id $uid. * for the user_id $uid.
* *
* @note Please do not store booleans - convert to 0/1 integer values! * @note Please do not store booleans - convert to 0/1 integer values!
* *
* @param string $uid The user_id * @param string $uid The user_id
* @param string $cat The category of the configuration value * @param string $cat The category of the configuration value
* @param string $k The configuration key to set * @param string $k The configuration key to set
* @param string $value The value to store * @param string $value The value to store
* *
* @return mixed Stored $value or false * @return mixed Stored $value or false
*/ */
public function set($uid, $cat, $k, $value); public function set($uid, $cat, $k, $value);
/** /**
* @brief Deletes the given key from the users's configuration. * @brief Deletes the given key from the users's configuration.
* *
* Removes the configured value from the stored cache in $a->config[$uid] * Removes the configured value from the stored cache in $a->config[$uid]
* and removes it from the database. * and removes it from the database.
* *
* @param string $uid The user_id * @param string $uid The user_id
* @param string $cat The category of the configuration value * @param string $cat The category of the configuration value
* @param string $k The configuration key to delete * @param string $k The configuration key to delete
* *
* @return mixed * @return mixed
*/ */
public function delete($uid, $cat, $k); public function delete($uid, $cat, $k);
} }

View file

@ -1,90 +1,90 @@
<?php <?php
namespace Friendica\Core\Config; namespace Friendica\Core\Config;
use dba; use dba;
use Exception; use Exception;
use Friendica\App; use Friendica\App;
use Friendica\BaseObject; use Friendica\BaseObject;
use Friendica\Database\DBM; use Friendica\Database\DBM;
require_once 'include/dba.php'; require_once 'include/dba.php';
/** /**
* Preload Configuration Adapter * Preload Configuration Adapter
* *
* Minimizes the number of database queries to retrieve configuration values at the cost of memory. * Minimizes the number of database queries to retrieve configuration values at the cost of memory.
* *
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class PreloadConfigAdapter extends BaseObject implements IConfigAdapter class PreloadConfigAdapter extends BaseObject implements IConfigAdapter
{ {
private $config_loaded = false; private $config_loaded = false;
public function __construct() public function __construct()
{ {
$this->load(); $this->load();
} }
public function load($family = 'config') public function load($family = 'config')
{ {
if ($this->config_loaded) { if ($this->config_loaded) {
return; return;
} }
$configs = dba::select('config', ['cat', 'v', 'k']); $configs = dba::select('config', ['cat', 'v', 'k']);
while ($config = dba::fetch($configs)) { while ($config = dba::fetch($configs)) {
self::getApp()->setConfigValue($config['cat'], $config['k'], $config['v']); self::getApp()->setConfigValue($config['cat'], $config['k'], $config['v']);
} }
dba::close($configs); dba::close($configs);
$this->config_loaded = true; $this->config_loaded = true;
} }
public function get($cat, $k, $default_value = null, $refresh = false) public function get($cat, $k, $default_value = null, $refresh = false)
{ {
if ($refresh) { if ($refresh) {
$config = dba::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $k]); $config = dba::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $k]);
if (DBM::is_result($config)) { if (DBM::is_result($config)) {
self::getApp()->setConfigValue($cat, $k, $config['v']); self::getApp()->setConfigValue($cat, $k, $config['v']);
} }
} }
$return = self::getApp()->getConfigValue($cat, $k, $default_value); $return = self::getApp()->getConfigValue($cat, $k, $default_value);
return $return; return $return;
} }
public function set($cat, $k, $value) public function set($cat, $k, $value)
{ {
// We store our setting values as strings. // We store our setting values as strings.
// So we have to do the conversion here so that the compare below works. // So we have to do the conversion here so that the compare below works.
// The exception are array values. // The exception are array values.
$compare_value = !is_array($value) ? (string)$value : $value; $compare_value = !is_array($value) ? (string)$value : $value;
if (self::getApp()->getConfigValue($cat, $k) === $compare_value) { if (self::getApp()->getConfigValue($cat, $k) === $compare_value) {
return true; return true;
} }
self::getApp()->setConfigValue($cat, $k, $value); self::getApp()->setConfigValue($cat, $k, $value);
// manage array value // manage array value
$dbvalue = is_array($value) ? serialize($value) : $value; $dbvalue = is_array($value) ? serialize($value) : $value;
$result = dba::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $k], true); $result = dba::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $k], true);
if (!$result) { if (!$result) {
throw new Exception('Unable to store config value in [' . $cat . '][' . $k . ']'); throw new Exception('Unable to store config value in [' . $cat . '][' . $k . ']');
} }
return true; return true;
} }
public function delete($cat, $k) public function delete($cat, $k)
{ {
self::getApp()->deleteConfigValue($cat, $k); self::getApp()->deleteConfigValue($cat, $k);
$result = dba::delete('config', ['cat' => $cat, 'k' => $k]); $result = dba::delete('config', ['cat' => $cat, 'k' => $k]);
return $result; return $result;
} }
} }

View file

@ -1,92 +1,92 @@
<?php <?php
namespace Friendica\Core\Config; namespace Friendica\Core\Config;
use dba; use dba;
use Exception; use Exception;
use Friendica\App; use Friendica\App;
use Friendica\BaseObject; use Friendica\BaseObject;
use Friendica\Database\DBM; use Friendica\Database\DBM;
require_once 'include/dba.php'; require_once 'include/dba.php';
/** /**
* Preload User Configuration Adapter * Preload User Configuration Adapter
* *
* Minimizes the number of database queries to retrieve configuration values at the cost of memory. * Minimizes the number of database queries to retrieve configuration values at the cost of memory.
* *
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class PreloadPConfigAdapter extends BaseObject implements IPConfigAdapter class PreloadPConfigAdapter extends BaseObject implements IPConfigAdapter
{ {
private $config_loaded = false; private $config_loaded = false;
public function __construct($uid) public function __construct($uid)
{ {
$this->load($uid, 'config'); $this->load($uid, 'config');
} }
public function load($uid, $family) public function load($uid, $family)
{ {
if ($this->config_loaded) { if ($this->config_loaded) {
return; return;
} }
$pconfigs = dba::select('pconfig', ['cat', 'v', 'k'], ['uid' => $uid]); $pconfigs = dba::select('pconfig', ['cat', 'v', 'k'], ['uid' => $uid]);
while ($pconfig = dba::fetch($pconfigs)) { while ($pconfig = dba::fetch($pconfigs)) {
self::getApp()->setPConfigValue($uid, $pconfig['cat'], $pconfig['k'], $pconfig['v']); self::getApp()->setPConfigValue($uid, $pconfig['cat'], $pconfig['k'], $pconfig['v']);
} }
dba::close($pconfigs); dba::close($pconfigs);
$this->config_loaded = true; $this->config_loaded = true;
} }
public function get($uid, $cat, $k, $default_value = null, $refresh = false) public function get($uid, $cat, $k, $default_value = null, $refresh = false)
{ {
if ($refresh) { if ($refresh) {
$config = dba::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $k]); $config = dba::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $k]);
if (DBM::is_result($config)) { if (DBM::is_result($config)) {
self::getApp()->setPConfigValue($uid, $cat, $k, $config['v']); self::getApp()->setPConfigValue($uid, $cat, $k, $config['v']);
} else { } else {
self::getApp()->deletePConfigValue($uid, $cat, $k); self::getApp()->deletePConfigValue($uid, $cat, $k);
} }
} }
$return = self::getApp()->getPConfigValue($uid, $cat, $k, $default_value); $return = self::getApp()->getPConfigValue($uid, $cat, $k, $default_value);
return $return; return $return;
} }
public function set($uid, $cat, $k, $value) public function set($uid, $cat, $k, $value)
{ {
// We store our setting values as strings. // We store our setting values as strings.
// So we have to do the conversion here so that the compare below works. // So we have to do the conversion here so that the compare below works.
// The exception are array values. // The exception are array values.
$compare_value = !is_array($value) ? (string)$value : $value; $compare_value = !is_array($value) ? (string)$value : $value;
if (self::getApp()->getPConfigValue($uid, $cat, $k) === $compare_value) { if (self::getApp()->getPConfigValue($uid, $cat, $k) === $compare_value) {
return true; return true;
} }
self::getApp()->setPConfigValue($uid, $cat, $k, $value); self::getApp()->setPConfigValue($uid, $cat, $k, $value);
// manage array value // manage array value
$dbvalue = is_array($value) ? serialize($value) : $value; $dbvalue = is_array($value) ? serialize($value) : $value;
$result = dba::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $k], true); $result = dba::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $k], true);
if (!$result) { if (!$result) {
throw new Exception('Unable to store config value in [' . $uid . '][' . $cat . '][' . $k . ']'); throw new Exception('Unable to store config value in [' . $uid . '][' . $cat . '][' . $k . ']');
} }
return true; return true;
} }
public function delete($uid, $cat, $k) public function delete($uid, $cat, $k)
{ {
self::getApp()->deletePConfigValue($uid, $cat, $k); self::getApp()->deletePConfigValue($uid, $cat, $k);
$result = dba::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $k]); $result = dba::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $k]);
return $result; return $result;
} }
} }

View file

@ -1,123 +1,123 @@
<?php <?php
namespace Friendica\Core; namespace Friendica\Core;
/** /**
* Description of Console * Description of Console
* *
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class Console extends \Asika\SimpleConsole\Console class Console extends \Asika\SimpleConsole\Console
{ {
// Disables the default help handling // Disables the default help handling
protected $helpOptions = []; protected $helpOptions = [];
protected $customHelpOptions = ['h', 'help', '?']; protected $customHelpOptions = ['h', 'help', '?'];
protected $subConsoles = [ protected $subConsoles = [
'config' => __NAMESPACE__ . '\Console\Config', 'config' => __NAMESPACE__ . '\Console\Config',
'createdoxygen' => __NAMESPACE__ . '\Console\CreateDoxygen', 'createdoxygen' => __NAMESPACE__ . '\Console\CreateDoxygen',
'docbloxerrorchecker' => __NAMESPACE__ . '\Console\DocBloxErrorChecker', 'docbloxerrorchecker' => __NAMESPACE__ . '\Console\DocBloxErrorChecker',
'dbstructure' => __NAMESPACE__ . '\Console\DatabaseStructure', 'dbstructure' => __NAMESPACE__ . '\Console\DatabaseStructure',
'extract' => __NAMESPACE__ . '\Console\Extract', 'extract' => __NAMESPACE__ . '\Console\Extract',
'globalcommunityblock' => __NAMESPACE__ . '\Console\GlobalCommunityBlock', 'globalcommunityblock' => __NAMESPACE__ . '\Console\GlobalCommunityBlock',
'globalcommunitysilence' => __NAMESPACE__ . '\Console\GlobalCommunitySilence', 'globalcommunitysilence' => __NAMESPACE__ . '\Console\GlobalCommunitySilence',
'maintenance' => __NAMESPACE__ . '\Console\Maintenance', 'maintenance' => __NAMESPACE__ . '\Console\Maintenance',
'php2po' => __NAMESPACE__ . '\Console\PhpToPo', 'php2po' => __NAMESPACE__ . '\Console\PhpToPo',
'po2php' => __NAMESPACE__ . '\Console\PoToPhp', 'po2php' => __NAMESPACE__ . '\Console\PoToPhp',
'typo' => __NAMESPACE__ . '\Console\Typo', 'typo' => __NAMESPACE__ . '\Console\Typo',
]; ];
protected function getHelp() protected function getHelp()
{ {
$help = <<<HELP $help = <<<HELP
Usage: bin/console [--version] [-h|--help|-?] <command> [<args>] [-v] Usage: bin/console [--version] [-h|--help|-?] <command> [<args>] [-v]
Commands: Commands:
config Edit site config config Edit site config
createdoxygen Generate Doxygen headers createdoxygen Generate Doxygen headers
dbstructure Do database updates dbstructure Do database updates
docbloxerrorchecker Check the file tree for DocBlox errors docbloxerrorchecker Check the file tree for DocBlox errors
extract Generate translation string file for the Friendica project (deprecated) extract Generate translation string file for the Friendica project (deprecated)
globalcommunityblock Block remote profile from interacting with this node globalcommunityblock Block remote profile from interacting with this node
globalcommunitysilence Silence remote profile from global community page globalcommunitysilence Silence remote profile from global community page
help Show help about a command, e.g (bin/console help config) help Show help about a command, e.g (bin/console help config)
maintenance Set maintenance mode for this node maintenance Set maintenance mode for this node
php2po Generate a messages.po file from a strings.php file php2po Generate a messages.po file from a strings.php file
po2php Generate a strings.php file from a messages.po file po2php Generate a strings.php file from a messages.po file
typo Checks for parse errors in Friendica files typo Checks for parse errors in Friendica files
Options: Options:
-h|--help|-? Show help information -h|--help|-? Show help information
-v Show more debug information. -v Show more debug information.
HELP; HELP;
return $help; return $help;
} }
protected function doExecute() protected function doExecute()
{ {
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Executable: ' . $this->executable); $this->out('Executable: ' . $this->executable);
$this->out('Arguments: ' . var_export($this->args, true)); $this->out('Arguments: ' . var_export($this->args, true));
$this->out('Options: ' . var_export($this->options, true)); $this->out('Options: ' . var_export($this->options, true));
} }
$showHelp = false; $showHelp = false;
$subHelp = false; $subHelp = false;
$command = null; $command = null;
if ($this->getOption('version')) { if ($this->getOption('version')) {
$this->out('Friendica Console version ' . FRIENDICA_VERSION); $this->out('Friendica Console version ' . FRIENDICA_VERSION);
return 0; return 0;
} elseif ((count($this->options) === 0 || $this->getOption($this->customHelpOptions) === true || $this->getOption($this->customHelpOptions) === 1) && count($this->args) === 0 } elseif ((count($this->options) === 0 || $this->getOption($this->customHelpOptions) === true || $this->getOption($this->customHelpOptions) === 1) && count($this->args) === 0
) { ) {
$showHelp = true; $showHelp = true;
} elseif (count($this->args) >= 2 && $this->getArgument(0) == 'help') { } elseif (count($this->args) >= 2 && $this->getArgument(0) == 'help') {
$command = $this->getArgument(1); $command = $this->getArgument(1);
$subHelp = true; $subHelp = true;
array_shift($this->args); array_shift($this->args);
array_shift($this->args); array_shift($this->args);
} elseif (count($this->args) >= 1) { } elseif (count($this->args) >= 1) {
$command = $this->getArgument(0); $command = $this->getArgument(0);
array_shift($this->args); array_shift($this->args);
} }
if (is_null($command)) { if (is_null($command)) {
$this->out($this->getHelp()); $this->out($this->getHelp());
return 0; return 0;
} }
$console = $this->getSubConsole($command); $console = $this->getSubConsole($command);
if ($subHelp) { if ($subHelp) {
$console->setOption($this->customHelpOptions, true); $console->setOption($this->customHelpOptions, true);
} }
return $console->execute(); return $console->execute();
} }
private function getSubConsole($command) private function getSubConsole($command)
{ {
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Command: ' . $command); $this->out('Command: ' . $command);
} }
if (!isset($this->subConsoles[$command])) { if (!isset($this->subConsoles[$command])) {
throw new \Asika\SimpleConsole\CommandArgsException('Command ' . $command . ' doesn\'t exist'); throw new \Asika\SimpleConsole\CommandArgsException('Command ' . $command . ' doesn\'t exist');
} }
$subargs = $this->args; $subargs = $this->args;
array_unshift($subargs, $this->executable); array_unshift($subargs, $this->executable);
$className = $this->subConsoles[$command]; $className = $this->subConsoles[$command];
$subconsole = new $className($subargs); $subconsole = new $className($subargs);
foreach ($this->options as $name => $value) { foreach ($this->options as $name => $value) {
$subconsole->setOption($name, $value); $subconsole->setOption($name, $value);
} }
return $subconsole; return $subconsole;
} }
} }

View file

@ -1,135 +1,135 @@
<?php <?php
/* /*
* To change this license header, choose License Headers in Project Properties. * To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates * To change this template file, choose Tools | Templates
* and open the template in the editor. * and open the template in the editor.
*/ */
namespace Friendica\Core\Console; namespace Friendica\Core\Console;
use Asika\SimpleConsole\CommandArgsException; use Asika\SimpleConsole\CommandArgsException;
use dba; use dba;
use Friendica\Core; use Friendica\Core;
require_once 'include/dba.php'; require_once 'include/dba.php';
require_once 'include/text.php'; require_once 'include/text.php';
/** /**
* @brief tool to access the system config from the CLI * @brief tool to access the system config from the CLI
* *
* With this script you can access the system configuration of your node from * With this script you can access the system configuration of your node from
* the CLI. You can do both, reading current values stored in the database and * the CLI. You can do both, reading current values stored in the database and
* set new values to config variables. * set new values to config variables.
* *
* Usage: * Usage:
* If you specify no parameters at the CLI, the script will list all config * If you specify no parameters at the CLI, the script will list all config
* variables defined. * variables defined.
* *
* If you specify one parameter, the script will list all config variables * If you specify one parameter, the script will list all config variables
* defined in this section of the configuration (e.g. "system"). * defined in this section of the configuration (e.g. "system").
* *
* If you specify two parameters, the script will show you the current value * If you specify two parameters, the script will show you the current value
* of the named configuration setting. (e.g. "system loglevel") * of the named configuration setting. (e.g. "system loglevel")
* *
* If you specify three parameters, the named configuration setting will be * If you specify three parameters, the named configuration setting will be
* set to the value of the last parameter. (e.g. "system loglevel 0" will * set to the value of the last parameter. (e.g. "system loglevel 0" will
* disable logging) * disable logging)
* *
* @author Tobias Diekershoff * @author Tobias Diekershoff
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class Config extends \Asika\SimpleConsole\Console class Config extends \Asika\SimpleConsole\Console
{ {
protected $helpOptions = ['h', 'help', '?']; protected $helpOptions = ['h', 'help', '?'];
protected function getHelp() protected function getHelp()
{ {
$help = <<<HELP $help = <<<HELP
console config - Manage site configuration console config - Manage site configuration
Synopsis Synopsis
bin/console config [-h|--help|-?] [-v] bin/console config [-h|--help|-?] [-v]
bin/console config <category> [-h|--help|-?] [-v] bin/console config <category> [-h|--help|-?] [-v]
bin/console config <category> <key> [-h|--help|-?] [-v] bin/console config <category> <key> [-h|--help|-?] [-v]
bin/console config <category> <key> <value> [-h|--help|-?] [-v] bin/console config <category> <key> <value> [-h|--help|-?] [-v]
Description Description
bin/console config bin/console config
Lists all config values Lists all config values
bin/console config <category> bin/console config <category>
Lists all config values in the provided category Lists all config values in the provided category
bin/console config <category> <key> bin/console config <category> <key>
Shows the value of the provided key in the category Shows the value of the provided key in the category
bin/console config <category> <key> <value> bin/console config <category> <key> <value>
Sets the value of the provided key in the category Sets the value of the provided key in the category
Notes: Notes:
Setting config entries which are manually set in .htconfig.php may result in Setting config entries which are manually set in .htconfig.php may result in
conflict between database settings and the manual startup settings. conflict between database settings and the manual startup settings.
Options Options
-h|--help|-? Show help information -h|--help|-? Show help information
-v Show more debug information. -v Show more debug information.
HELP; HELP;
return $help; return $help;
} }
protected function doExecute() protected function doExecute()
{ {
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Executable: ' . $this->executable); $this->out('Executable: ' . $this->executable);
$this->out('Class: ' . __CLASS__); $this->out('Class: ' . __CLASS__);
$this->out('Arguments: ' . var_export($this->args, true)); $this->out('Arguments: ' . var_export($this->args, true));
$this->out('Options: ' . var_export($this->options, true)); $this->out('Options: ' . var_export($this->options, true));
} }
if (count($this->args) > 3) { if (count($this->args) > 3) {
throw new CommandArgsException('Too many arguments'); throw new CommandArgsException('Too many arguments');
} }
require_once '.htconfig.php'; require_once '.htconfig.php';
$result = dba::connect($db_host, $db_user, $db_pass, $db_data); $result = dba::connect($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data); unset($db_host, $db_user, $db_pass, $db_data);
if (!$result) { if (!$result) {
throw new \RuntimeException('Unable to connect to database'); throw new \RuntimeException('Unable to connect to database');
} }
if (count($this->args) == 3) { if (count($this->args) == 3) {
Core\Config::set($this->getArgument(0), $this->getArgument(1), $this->getArgument(2)); Core\Config::set($this->getArgument(0), $this->getArgument(1), $this->getArgument(2));
$this->out("config[{$this->getArgument(0)}][{$this->getArgument(1)}] = " . Core\Config::get($this->getArgument(0), $this->out("config[{$this->getArgument(0)}][{$this->getArgument(1)}] = " . Core\Config::get($this->getArgument(0),
$this->getArgument(1))); $this->getArgument(1)));
} }
if (count($this->args) == 2) { if (count($this->args) == 2) {
$this->out("config[{$this->getArgument(0)}][{$this->getArgument(1)}] = " . Core\Config::get($this->getArgument(0), $this->out("config[{$this->getArgument(0)}][{$this->getArgument(1)}] = " . Core\Config::get($this->getArgument(0),
$this->getArgument(1))); $this->getArgument(1)));
} }
if (count($this->args) == 1) { if (count($this->args) == 1) {
Core\Config::load($this->getArgument(0)); Core\Config::load($this->getArgument(0));
$a = get_app(); $a = get_app();
if (!is_null($a->config[$this->getArgument(0)])) { if (!is_null($a->config[$this->getArgument(0)])) {
foreach ($a->config[$this->getArgument(0)] as $k => $x) { foreach ($a->config[$this->getArgument(0)] as $k => $x) {
$this->out("config[{$this->getArgument(0)}][{$k}] = " . $x); $this->out("config[{$this->getArgument(0)}][{$k}] = " . $x);
} }
} else { } else {
$this->out('Config section ' . $this->getArgument(0) . ' returned nothing'); $this->out('Config section ' . $this->getArgument(0) . ' returned nothing');
} }
} }
if (count($this->args) == 0) { if (count($this->args) == 0) {
$configs = dba::select('config'); $configs = dba::select('config');
foreach ($configs as $config) { foreach ($configs as $config) {
$this->out("config[{$config['cat']}][{$config['k']}] = " . $config['v']); $this->out("config[{$config['cat']}][{$config['k']}] = " . $config['v']);
} }
} }
return 0; return 0;
} }
} }

View file

@ -1,148 +1,148 @@
<?php <?php
namespace Friendica\Core\Console; namespace Friendica\Core\Console;
/** /**
* Description of CreateDoxygen * Description of CreateDoxygen
* *
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class CreateDoxygen extends \Asika\SimpleConsole\Console class CreateDoxygen extends \Asika\SimpleConsole\Console
{ {
protected $helpOptions = ['h', 'help', '?']; protected $helpOptions = ['h', 'help', '?'];
protected function getHelp() protected function getHelp()
{ {
$help = <<<HELP $help = <<<HELP
console createdoxygen - Generate Doxygen headers console createdoxygen - Generate Doxygen headers
Usage Usage
bin/console createdoxygen <file> [-h|--help|-?] [-v] bin/console createdoxygen <file> [-h|--help|-?] [-v]
Description Description
Outputs the provided file with added Doxygen headers to functions Outputs the provided file with added Doxygen headers to functions
Options Options
-h|--help|-? Show help information -h|--help|-? Show help information
-v Show more debug information. -v Show more debug information.
HELP; HELP;
return $help; return $help;
} }
protected function doExecute() protected function doExecute()
{ {
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__); $this->out('Class: ' . __CLASS__);
$this->out('Arguments: ' . var_export($this->args, true)); $this->out('Arguments: ' . var_export($this->args, true));
$this->out('Options: ' . var_export($this->options, true)); $this->out('Options: ' . var_export($this->options, true));
} }
if (count($this->args) == 0) { if (count($this->args) == 0) {
$this->out($this->getHelp()); $this->out($this->getHelp());
return 0; return 0;
} }
if (count($this->args) > 1) { if (count($this->args) > 1) {
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
} }
$file = $this->getArgument(0); $file = $this->getArgument(0);
if (!file_exists($file)) { if (!file_exists($file)) {
throw new \RuntimeException('Unable to find specified file.'); throw new \RuntimeException('Unable to find specified file.');
} }
$data = file_get_contents($file); $data = file_get_contents($file);
$lines = explode("\n", $data); $lines = explode("\n", $data);
$previous = ""; $previous = "";
foreach ($lines AS $line) { foreach ($lines AS $line) {
$line = rtrim(trim($line, "\r")); $line = rtrim(trim($line, "\r"));
if (strstr(strtolower($line), "function")) { if (strstr(strtolower($line), "function")) {
$detect = strtolower(trim($line)); $detect = strtolower(trim($line));
$detect = implode(" ", explode(" ", $detect)); $detect = implode(" ", explode(" ", $detect));
$found = false; $found = false;
if (substr($detect, 0, 9) == "function ") { if (substr($detect, 0, 9) == "function ") {
$found = true; $found = true;
} }
if (substr($detect, 0, 19) == "protected function ") { if (substr($detect, 0, 19) == "protected function ") {
$found = true; $found = true;
} }
if (substr($detect, 0, 17) == "private function ") { if (substr($detect, 0, 17) == "private function ") {
$found = true; $found = true;
} }
if (substr($detect, 0, 23) == "public static function ") { if (substr($detect, 0, 23) == "public static function ") {
$found = true; $found = true;
} }
if (substr($detect, 0, 24) == "private static function ") { if (substr($detect, 0, 24) == "private static function ") {
$found = true; $found = true;
} }
if (substr($detect, 0, 10) == "function (") { if (substr($detect, 0, 10) == "function (") {
$found = false; $found = false;
} }
if ($found && ( trim($previous) == "*/")) { if ($found && ( trim($previous) == "*/")) {
$found = false; $found = false;
} }
if ($found) { if ($found) {
$this->out($this->addDocumentation($line)); $this->out($this->addDocumentation($line));
} }
} }
$this->out($line); $this->out($line);
$previous = $line; $previous = $line;
} }
return 0; return 0;
} }
/** /**
* @brief Adds a doxygen header * @brief Adds a doxygen header
* *
* @param string $line The current line of the document * @param string $line The current line of the document
* *
* @return string added doxygen header * @return string added doxygen header
*/ */
private function addDocumentation($line) private function addDocumentation($line)
{ {
$trimmed = ltrim($line); $trimmed = ltrim($line);
$length = strlen($line) - strlen($trimmed); $length = strlen($line) - strlen($trimmed);
$space = substr($line, 0, $length); $space = substr($line, 0, $length);
$block = $space . "/**\n" . $block = $space . "/**\n" .
$space . " * @brief \n" . $space . " * @brief \n" .
$space . " *\n"; /**/ $space . " *\n"; /**/
$left = strpos($line, "("); $left = strpos($line, "(");
$line = substr($line, $left + 1); $line = substr($line, $left + 1);
$right = strpos($line, ")"); $right = strpos($line, ")");
$line = trim(substr($line, 0, $right)); $line = trim(substr($line, 0, $right));
if ($line != "") { if ($line != "") {
$parameters = explode(",", $line); $parameters = explode(",", $line);
foreach ($parameters AS $parameter) { foreach ($parameters AS $parameter) {
$parameter = trim($parameter); $parameter = trim($parameter);
$splitted = explode("=", $parameter); $splitted = explode("=", $parameter);
$block .= $space . " * @param " . trim($splitted[0], "& ") . "\n"; $block .= $space . " * @param " . trim($splitted[0], "& ") . "\n";
} }
if (count($parameters) > 0) $block .= $space . " *\n"; if (count($parameters) > 0) $block .= $space . " *\n";
} }
$block .= $space . " * @return \n" . $block .= $space . " * @return \n" .
$space . " */\n"; $space . " */\n";
return $block; return $block;
} }
} }

View file

@ -1,110 +1,110 @@
<?php <?php
namespace Friendica\Core\Console; namespace Friendica\Core\Console;
use Friendica\Core; use Friendica\Core;
use Friendica\Database\DBStructure; use Friendica\Database\DBStructure;
require_once 'boot.php'; require_once 'boot.php';
require_once 'include/dba.php'; require_once 'include/dba.php';
/** /**
* @brief Does database updates from the command line * @brief Does database updates from the command line
* *
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class DatabaseStructure extends \Asika\SimpleConsole\Console class DatabaseStructure extends \Asika\SimpleConsole\Console
{ {
protected $helpOptions = ['h', 'help', '?']; protected $helpOptions = ['h', 'help', '?'];
protected function getHelp() protected function getHelp()
{ {
$help = <<<HELP $help = <<<HELP
console dbstructure - Does database updates console dbstructure - Does database updates
Usage Usage
bin/console dbstructure <command> [-h|--help|-?] [-v] bin/console dbstructure <command> [-h|--help|-?] [-v]
Commands Commands
dryrun Show database update schema queries without running them dryrun Show database update schema queries without running them
update Update database schema update Update database schema
dumpsql Dump database schema dumpsql Dump database schema
toinnodb Convert all tables from MyISAM to InnoDB toinnodb Convert all tables from MyISAM to InnoDB
Options Options
-h|--help|-? Show help information -h|--help|-? Show help information
-v Show more debug information. -v Show more debug information.
HELP; HELP;
return $help; return $help;
} }
protected function doExecute() protected function doExecute()
{ {
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__); $this->out('Class: ' . __CLASS__);
$this->out('Arguments: ' . var_export($this->args, true)); $this->out('Arguments: ' . var_export($this->args, true));
$this->out('Options: ' . var_export($this->options, true)); $this->out('Options: ' . var_export($this->options, true));
} }
if (count($this->args) == 0) { if (count($this->args) == 0) {
$this->out($this->getHelp()); $this->out($this->getHelp());
return 0; return 0;
} }
if (count($this->args) > 1) { if (count($this->args) > 1) {
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
} }
require_once '.htconfig.php'; require_once '.htconfig.php';
$result = \dba::connect($db_host, $db_user, $db_pass, $db_data); $result = \dba::connect($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data); unset($db_host, $db_user, $db_pass, $db_data);
if (!$result) { if (!$result) {
throw new \RuntimeException('Unable to connect to database'); throw new \RuntimeException('Unable to connect to database');
} }
Core\Config::load(); Core\Config::load();
switch ($this->getArgument(0)) { switch ($this->getArgument(0)) {
case "dryrun": case "dryrun":
$output = DBStructure::update(true, false); $output = DBStructure::update(true, false);
break; break;
case "update": case "update":
$output = DBStructure::update(true, true); $output = DBStructure::update(true, true);
$build = Core\Config::get('system', 'build'); $build = Core\Config::get('system', 'build');
if (empty($build)) { if (empty($build)) {
Core\Config::set('system', 'build', DB_UPDATE_VERSION); Core\Config::set('system', 'build', DB_UPDATE_VERSION);
$build = DB_UPDATE_VERSION; $build = DB_UPDATE_VERSION;
} }
$stored = intval($build); $stored = intval($build);
$current = intval(DB_UPDATE_VERSION); $current = intval(DB_UPDATE_VERSION);
// run any left update_nnnn functions in update.php // run any left update_nnnn functions in update.php
for ($x = $stored; $x < $current; $x ++) { for ($x = $stored; $x < $current; $x ++) {
$r = run_update_function($x); $r = run_update_function($x);
if (!$r) { if (!$r) {
break; break;
} }
} }
Core\Config::set('system', 'build', DB_UPDATE_VERSION); Core\Config::set('system', 'build', DB_UPDATE_VERSION);
break; break;
case "dumpsql": case "dumpsql":
ob_start(); ob_start();
DBStructure::printStructure(); DBStructure::printStructure();
$output = ob_get_clean(); $output = ob_get_clean();
break; break;
case "toinnodb": case "toinnodb":
ob_start(); ob_start();
DBStructure::convertToInnoDB(); DBStructure::convertToInnoDB();
$output = ob_get_clean(); $output = ob_get_clean();
break; break;
} }
$this->out($output); $this->out($output);
return 0; return 0;
} }
} }

View file

@ -1,192 +1,192 @@
<?php <?php
namespace Friendica\Core\Console; namespace Friendica\Core\Console;
/** /**
* When I installed docblox, I had the experience that it does not generate any output at all. * When I installed docblox, I had the experience that it does not generate any output at all.
* This script may be used to find that kind of problems with the documentation build process. * This script may be used to find that kind of problems with the documentation build process.
* If docblox generates output, use another approach for debugging. * If docblox generates output, use another approach for debugging.
* *
* Basically, docblox takes a list of files to build documentation from. This script assumes there is a file or set of files * Basically, docblox takes a list of files to build documentation from. This script assumes there is a file or set of files
* breaking the build when it is included in that list. It tries to calculate the smallest list containing these files. * breaking the build when it is included in that list. It tries to calculate the smallest list containing these files.
* Unfortunatly, the original problem is NP-complete, so what the script does is a best guess only. * Unfortunatly, the original problem is NP-complete, so what the script does is a best guess only.
* *
* So it starts with a list of all files in the project. * So it starts with a list of all files in the project.
* If that list can't be build, it cuts it in two parts and tries both parts independently. If only one of them breaks, * If that list can't be build, it cuts it in two parts and tries both parts independently. If only one of them breaks,
* it takes that one and tries the same independently. If both break, it assumes this is the smallest set. This assumption * it takes that one and tries the same independently. If both break, it assumes this is the smallest set. This assumption
* is not necessarily true. Maybe the smallest set consists of two files and both of them were in different parts when * is not necessarily true. Maybe the smallest set consists of two files and both of them were in different parts when
* the list was divided, but by now it is my best guess. To make this assumption better, the list is shuffled after every step. * the list was divided, but by now it is my best guess. To make this assumption better, the list is shuffled after every step.
* *
* After that, the script tries to remove a file from the list. It tests if the list breaks and if so, it * After that, the script tries to remove a file from the list. It tests if the list breaks and if so, it
* assumes that the file it removed belongs to the set of erroneous files. * assumes that the file it removed belongs to the set of erroneous files.
* This is done for all files, so, in the end removing one file leads to a working doc build. * This is done for all files, so, in the end removing one file leads to a working doc build.
* *
* @author Alexander Kampmann * @author Alexander Kampmann
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class DocBloxErrorChecker extends \Asika\SimpleConsole\Console class DocBloxErrorChecker extends \Asika\SimpleConsole\Console
{ {
protected $helpOptions = ['h', 'help', '?']; protected $helpOptions = ['h', 'help', '?'];
protected function getHelp() protected function getHelp()
{ {
$help = <<<HELP $help = <<<HELP
console docbloxerrorchecker - Checks the file tree for docblox errors console docbloxerrorchecker - Checks the file tree for docblox errors
Usage Usage
bin/console docbloxerrorchecker [-h|--help|-?] [-v] bin/console docbloxerrorchecker [-h|--help|-?] [-v]
Options Options
-h|--help|-? Show help information -h|--help|-? Show help information
-v Show more debug information. -v Show more debug information.
HELP; HELP;
return $help; return $help;
} }
protected function doExecute() protected function doExecute()
{ {
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__); $this->out('Class: ' . __CLASS__);
$this->out('Arguments: ' . var_export($this->args, true)); $this->out('Arguments: ' . var_export($this->args, true));
$this->out('Options: ' . var_export($this->options, true)); $this->out('Options: ' . var_export($this->options, true));
} }
if (count($this->args) > 0) { if (count($this->args) > 0) {
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
} }
if (!$this->commandExists('docblox')) { if (!$this->commandExists('docblox')) {
throw new \RuntimeException('DocBlox isn\'t available.'); throw new \RuntimeException('DocBlox isn\'t available.');
} }
//return from util folder to frindica base dir //return from util folder to frindica base dir
$dir = get_app()->get_basepath(); $dir = get_app()->get_basepath();
//stack for dirs to search //stack for dirs to search
$dirstack = []; $dirstack = [];
//list of source files //list of source files
$filelist = []; $filelist = [];
//loop over all files in $dir //loop over all files in $dir
while ($dh = opendir($dir)) { while ($dh = opendir($dir)) {
while ($file = readdir($dh)) { while ($file = readdir($dh)) {
if (is_dir($dir . "/" . $file)) { if (is_dir($dir . "/" . $file)) {
//add to directory stack //add to directory stack
if (strpos($file, '.') !== 0) { if (strpos($file, '.') !== 0) {
array_push($dirstack, $dir . "/" . $file); array_push($dirstack, $dir . "/" . $file);
$this->out('dir ' . $dir . '/' . $file); $this->out('dir ' . $dir . '/' . $file);
} }
} else { } else {
//test if it is a source file and add to filelist //test if it is a source file and add to filelist
if (substr($file, strlen($file) - 4) == ".php") { if (substr($file, strlen($file) - 4) == ".php") {
array_push($filelist, $dir . "/" . $file); array_push($filelist, $dir . "/" . $file);
$this->out($dir . '/' . $file); $this->out($dir . '/' . $file);
} }
} }
} }
//look at the next dir //look at the next dir
$dir = array_pop($dirstack); $dir = array_pop($dirstack);
} }
//check the entire set //check the entire set
if ($this->runs($filelist)) { if ($this->runs($filelist)) {
throw new \RuntimeException("I can not detect a problem."); throw new \RuntimeException("I can not detect a problem.");
} }
//check half of the set and discard if that half is okay //check half of the set and discard if that half is okay
$res = $filelist; $res = $filelist;
$i = count($res); $i = count($res);
do { do {
$this->out($i . '/' . count($filelist) . ' elements remaining.'); $this->out($i . '/' . count($filelist) . ' elements remaining.');
$res = $this->reduce($res, count($res) / 2); $res = $this->reduce($res, count($res) / 2);
shuffle($res); shuffle($res);
$i = count($res); $i = count($res);
} while (count($res) < $i); } while (count($res) < $i);
//check one file after another //check one file after another
$needed = []; $needed = [];
while (count($res) != 0) { while (count($res) != 0) {
$file = array_pop($res); $file = array_pop($res);
if ($this->runs(array_merge($res, $needed))) { if ($this->runs(array_merge($res, $needed))) {
$this->out('needs: ' . $file . ' and file count ' . count($needed)); $this->out('needs: ' . $file . ' and file count ' . count($needed));
array_push($needed, $file); array_push($needed, $file);
} }
} }
$this->out('Smallest Set is: ' . $this->namesList($needed) . ' with ' . count($needed) . ' files. '); $this->out('Smallest Set is: ' . $this->namesList($needed) . ' with ' . count($needed) . ' files. ');
return 0; return 0;
} }
private function commandExists($command) private function commandExists($command)
{ {
$prefix = strpos(strtolower(PHP_OS),'win') > -1 ? 'where' : 'which'; $prefix = strpos(strtolower(PHP_OS),'win') > -1 ? 'where' : 'which';
exec("{$prefix} {$command}", $output, $returnVal); exec("{$prefix} {$command}", $output, $returnVal);
return $returnVal === 0; return $returnVal === 0;
} }
/** /**
* This function generates a comma separated list of file names. * This function generates a comma separated list of file names.
* *
* @package util * @package util
* *
* @param array $fileset Set of file names * @param array $fileset Set of file names
* *
* @return string comma-separated list of the file names * @return string comma-separated list of the file names
*/ */
private function namesList($fileset) private function namesList($fileset)
{ {
return implode(',', $fileset); return implode(',', $fileset);
} }
/** /**
* This functions runs phpdoc on the provided list of files * This functions runs phpdoc on the provided list of files
* @package util * @package util
* *
* @param array $fileset Set of filenames * @param array $fileset Set of filenames
* *
* @return bool true, if that set can be built * @return bool true, if that set can be built
*/ */
private function runs($fileset) private function runs($fileset)
{ {
$fsParam = $this->namesList($fileset); $fsParam = $this->namesList($fileset);
$this->exec('docblox -t phpdoc_out -f ' . $fsParam); $this->exec('docblox -t phpdoc_out -f ' . $fsParam);
if (file_exists("phpdoc_out/index.html")) { if (file_exists("phpdoc_out/index.html")) {
$this->out('Subset ' . $fsParam . ' is okay.'); $this->out('Subset ' . $fsParam . ' is okay.');
$this->exec('rm -r phpdoc_out'); $this->exec('rm -r phpdoc_out');
return true; return true;
} else { } else {
$this->out('Subset ' . $fsParam . ' failed.'); $this->out('Subset ' . $fsParam . ' failed.');
return false; return false;
} }
} }
/** /**
* This functions cuts down a fileset by removing files until it finally works. * This functions cuts down a fileset by removing files until it finally works.
* it was meant to be recursive, but php's maximum stack size is to small. So it just simulates recursion. * it was meant to be recursive, but php's maximum stack size is to small. So it just simulates recursion.
* *
* In that version, it does not necessarily generate the smallest set, because it may not alter the elements order enough. * In that version, it does not necessarily generate the smallest set, because it may not alter the elements order enough.
* *
* @package util * @package util
* *
* @param array $fileset set of filenames * @param array $fileset set of filenames
* @param int $ps number of files in subsets * @param int $ps number of files in subsets
* *
* @return array a part of $fileset, that crashes * @return array a part of $fileset, that crashes
*/ */
private function reduce($fileset, $ps) private function reduce($fileset, $ps)
{ {
//split array... //split array...
$parts = array_chunk($fileset, $ps); $parts = array_chunk($fileset, $ps);
//filter working subsets... //filter working subsets...
$parts = array_filter($parts, [$this, 'runs']); $parts = array_filter($parts, [$this, 'runs']);
//melt remaining parts together //melt remaining parts together
if (is_array($parts)) { if (is_array($parts)) {
return array_reduce($parts, "array_merge", []); return array_reduce($parts, "array_merge", []);
} }
return []; return [];
} }
} }

View file

@ -1,140 +1,140 @@
<?php <?php
namespace Friendica\Core\Console; namespace Friendica\Core\Console;
/** /**
* Extracts translation strings from the Friendica project's files to be exported * Extracts translation strings from the Friendica project's files to be exported
* to Transifex for translation. * to Transifex for translation.
* *
* Outputs a PHP file with language strings used by Friendica * Outputs a PHP file with language strings used by Friendica
* *
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class Extract extends \Asika\SimpleConsole\Console class Extract extends \Asika\SimpleConsole\Console
{ {
protected $helpOptions = ['h', 'help', '?']; protected $helpOptions = ['h', 'help', '?'];
protected function getHelp() protected function getHelp()
{ {
$help = <<<HELP $help = <<<HELP
console extract - Generate translation string file for the Friendica project (deprecated) console extract - Generate translation string file for the Friendica project (deprecated)
Usage Usage
bin/console extract [-h|--help|-?] [-v] bin/console extract [-h|--help|-?] [-v]
Description Description
This script was used to generate the translation string file to be exported to Transifex, This script was used to generate the translation string file to be exported to Transifex,
please use bin/run_xgettext.sh instead please use bin/run_xgettext.sh instead
Options Options
-h|--help|-? Show help information -h|--help|-? Show help information
-v Show more debug information. -v Show more debug information.
HELP; HELP;
return $help; return $help;
} }
protected function doExecute() protected function doExecute()
{ {
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__); $this->out('Class: ' . __CLASS__);
$this->out('Arguments: ' . var_export($this->args, true)); $this->out('Arguments: ' . var_export($this->args, true));
$this->out('Options: ' . var_export($this->options, true)); $this->out('Options: ' . var_export($this->options, true));
} }
if (count($this->args) > 0) { if (count($this->args) > 0) {
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
} }
$s = '<?php' . PHP_EOL; $s = '<?php' . PHP_EOL;
$s .= ' $s .= '
function string_plural_select($n){ function string_plural_select($n){
return ($n != 1); return ($n != 1);
} }
'; ';
$arr = []; $arr = [];
$files = array_merge( $files = array_merge(
['index.php', 'boot.php'], ['index.php', 'boot.php'],
glob('mod/*'), glob('mod/*'),
glob('include/*'), glob('include/*'),
glob('addon/*/*'), glob('addon/*/*'),
$this->globRecursive('src') $this->globRecursive('src')
); );
foreach ($files as $file) { foreach ($files as $file) {
$str = file_get_contents($file); $str = file_get_contents($file);
$pat = '|L10n::t\(([^\)]*+)[\)]|'; $pat = '|L10n::t\(([^\)]*+)[\)]|';
$patt = '|L10n::tt\(([^\)]*+)[\)]|'; $patt = '|L10n::tt\(([^\)]*+)[\)]|';
$matches = []; $matches = [];
$matchestt = []; $matchestt = [];
preg_match_all($pat, $str, $matches); preg_match_all($pat, $str, $matches);
preg_match_all($patt, $str, $matchestt); preg_match_all($patt, $str, $matchestt);
if (count($matches) || count($matchestt)) { if (count($matches) || count($matchestt)) {
$s .= '// ' . $file . PHP_EOL; $s .= '// ' . $file . PHP_EOL;
} }
if (!empty($matches[1])) { if (!empty($matches[1])) {
foreach ($matches[1] as $long_match) { foreach ($matches[1] as $long_match) {
$match_arr = preg_split('/(?<=[\'"])\s*,/', $long_match); $match_arr = preg_split('/(?<=[\'"])\s*,/', $long_match);
$match = $match_arr[0]; $match = $match_arr[0];
if (!in_array($match, $arr)) { if (!in_array($match, $arr)) {
if (substr($match, 0, 1) == '$') { if (substr($match, 0, 1) == '$') {
continue; continue;
} }
$arr[] = $match; $arr[] = $match;
$s .= '$a->strings[' . $match . '] = ' . $match . ';' . "\n"; $s .= '$a->strings[' . $match . '] = ' . $match . ';' . "\n";
} }
} }
} }
if (!empty($matchestt[1])) { if (!empty($matchestt[1])) {
foreach ($matchestt[1] as $match) { foreach ($matchestt[1] as $match) {
$matchtkns = preg_split("|[ \t\r\n]*,[ \t\r\n]*|", $match); $matchtkns = preg_split("|[ \t\r\n]*,[ \t\r\n]*|", $match);
if (count($matchtkns) == 3 && !in_array($matchtkns[0], $arr)) { if (count($matchtkns) == 3 && !in_array($matchtkns[0], $arr)) {
if (substr($matchtkns[1], 0, 1) == '$') { if (substr($matchtkns[1], 0, 1) == '$') {
continue; continue;
} }
$arr[] = $matchtkns[0]; $arr[] = $matchtkns[0];
$s .= '$a->strings[' . $matchtkns[0] . "] = array(\n"; $s .= '$a->strings[' . $matchtkns[0] . "] = array(\n";
$s .= "\t0 => " . $matchtkns[0] . ",\n"; $s .= "\t0 => " . $matchtkns[0] . ",\n";
$s .= "\t1 => " . $matchtkns[1] . ",\n"; $s .= "\t1 => " . $matchtkns[1] . ",\n";
$s .= ");\n"; $s .= ");\n";
} }
} }
} }
} }
$s .= '// Timezones' . PHP_EOL; $s .= '// Timezones' . PHP_EOL;
$zones = timezone_identifiers_list(); $zones = timezone_identifiers_list();
foreach ($zones as $zone) { foreach ($zones as $zone) {
$s .= '$a->strings[\'' . $zone . '\'] = \'' . $zone . '\';' . "\n"; $s .= '$a->strings[\'' . $zone . '\'] = \'' . $zone . '\';' . "\n";
} }
$this->out($s); $this->out($s);
return 0; return 0;
} }
private function globRecursive($path) { private function globRecursive($path) {
$dir_iterator = new \RecursiveDirectoryIterator($path); $dir_iterator = new \RecursiveDirectoryIterator($path);
$iterator = new \RecursiveIteratorIterator($dir_iterator, \RecursiveIteratorIterator::SELF_FIRST); $iterator = new \RecursiveIteratorIterator($dir_iterator, \RecursiveIteratorIterator::SELF_FIRST);
$return = []; $return = [];
foreach ($iterator as $file) { foreach ($iterator as $file) {
if ($file->getBasename() != '.' && $file->getBasename() != '..') { if ($file->getBasename() != '.' && $file->getBasename() != '..') {
$return[] = $file->getPathname(); $return[] = $file->getPathname();
} }
} }
return $return; return $return;
} }
} }

View file

@ -1,77 +1,77 @@
<?php <?php
namespace Friendica\Core\Console; namespace Friendica\Core\Console;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Model\Contact; use Friendica\Model\Contact;
/** /**
* @brief tool to block an account from the node * @brief tool to block an account from the node
* *
* With this tool, you can block an account in such a way, that no postings * With this tool, you can block an account in such a way, that no postings
* or comments this account writes are accepted to the node. * or comments this account writes are accepted to the node.
* *
* License: AGPLv3 or later, same as Friendica * License: AGPLv3 or later, same as Friendica
* *
* @author Tobias Diekershoff <mrpetovan@gmail.com> * @author Tobias Diekershoff <mrpetovan@gmail.com>
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class GlobalCommunityBlock extends \Asika\SimpleConsole\Console class GlobalCommunityBlock extends \Asika\SimpleConsole\Console
{ {
protected $helpOptions = ['h', 'help', '?']; protected $helpOptions = ['h', 'help', '?'];
protected function getHelp() protected function getHelp()
{ {
$help = <<<HELP $help = <<<HELP
console globalcommunityblock - Block remote profile from interacting with this node console globalcommunityblock - Block remote profile from interacting with this node
Usage Usage
bin/console globalcommunityblock <profile_url> [-h|--help|-?] [-v] bin/console globalcommunityblock <profile_url> [-h|--help|-?] [-v]
Description Description
Blocks an account in such a way that no postings or comments this account writes are accepted to this node. Blocks an account in such a way that no postings or comments this account writes are accepted to this node.
Options Options
-h|--help|-? Show help information -h|--help|-? Show help information
-v Show more debug information. -v Show more debug information.
HELP; HELP;
return $help; return $help;
} }
protected function doExecute() protected function doExecute()
{ {
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__); $this->out('Class: ' . __CLASS__);
$this->out('Arguments: ' . var_export($this->args, true)); $this->out('Arguments: ' . var_export($this->args, true));
$this->out('Options: ' . var_export($this->options, true)); $this->out('Options: ' . var_export($this->options, true));
} }
if (count($this->args) == 0) { if (count($this->args) == 0) {
$this->out($this->getHelp()); $this->out($this->getHelp());
return 0; return 0;
} }
if (count($this->args) > 1) { if (count($this->args) > 1) {
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
} }
require_once '.htconfig.php'; require_once '.htconfig.php';
$result = \dba::connect($db_host, $db_user, $db_pass, $db_data); $result = \dba::connect($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data); unset($db_host, $db_user, $db_pass, $db_data);
if (!$result) { if (!$result) {
throw new \RuntimeException('Unable to connect to database'); throw new \RuntimeException('Unable to connect to database');
} }
$contact_id = Contact::getIdForURL($this->getArgument(0)); $contact_id = Contact::getIdForURL($this->getArgument(0));
if (!$contact_id) { if (!$contact_id) {
throw new \RuntimeException(L10n::t('Could not find any contact entry for this URL (%s)', $nurl)); throw new \RuntimeException(L10n::t('Could not find any contact entry for this URL (%s)', $nurl));
} }
if(Contact::block($contact_id)) { if(Contact::block($contact_id)) {
$this->out(L10n::t('The contact has been blocked from the node')); $this->out(L10n::t('The contact has been blocked from the node'));
} else { } else {
throw new \RuntimeException('The contact block failed.'); throw new \RuntimeException('The contact block failed.');
} }
return 0; return 0;
} }
} }

View file

@ -1,94 +1,94 @@
<?php <?php
namespace Friendica\Core\Console; namespace Friendica\Core\Console;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Network\Probe; use Friendica\Network\Probe;
require_once 'include/text.php'; require_once 'include/text.php';
/** /**
* @brief tool to silence accounts on the global community page * @brief tool to silence accounts on the global community page
* *
* With this tool, you can silence an account on the global community page. * With this tool, you can silence an account on the global community page.
* Postings from silenced accounts will not be displayed on the community * Postings from silenced accounts will not be displayed on the community
* page. This silencing does only affect the display on the community page, * page. This silencing does only affect the display on the community page,
* accounts following the silenced accounts will still get their postings. * accounts following the silenced accounts will still get their postings.
* *
* License: AGPLv3 or later, same as Friendica * License: AGPLv3 or later, same as Friendica
* *
* @author Tobias Diekershoff * @author Tobias Diekershoff
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class GlobalCommunitySilence extends \Asika\SimpleConsole\Console class GlobalCommunitySilence extends \Asika\SimpleConsole\Console
{ {
protected $helpOptions = ['h', 'help', '?']; protected $helpOptions = ['h', 'help', '?'];
protected function getHelp() protected function getHelp()
{ {
$help = <<<HELP $help = <<<HELP
console globalcommunitysilence - Silence remote profile from global community page console globalcommunitysilence - Silence remote profile from global community page
Usage Usage
bin/console globalcommunitysilence <profile_url> [-h|--help|-?] [-v] bin/console globalcommunitysilence <profile_url> [-h|--help|-?] [-v]
Description Description
With this tool, you can silence an account on the global community page. With this tool, you can silence an account on the global community page.
Postings from silenced accounts will not be displayed on the community page. Postings from silenced accounts will not be displayed on the community page.
This silencing does only affect the display on the community page, accounts This silencing does only affect the display on the community page, accounts
following the silenced accounts will still get their postings. following the silenced accounts will still get their postings.
Options Options
-h|--help|-? Show help information -h|--help|-? Show help information
-v Show more debug information. -v Show more debug information.
HELP; HELP;
return $help; return $help;
} }
protected function doExecute() protected function doExecute()
{ {
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__); $this->out('Class: ' . __CLASS__);
$this->out('Arguments: ' . var_export($this->args, true)); $this->out('Arguments: ' . var_export($this->args, true));
$this->out('Options: ' . var_export($this->options, true)); $this->out('Options: ' . var_export($this->options, true));
} }
if (count($this->args) == 0) { if (count($this->args) == 0) {
$this->out($this->getHelp()); $this->out($this->getHelp());
return 0; return 0;
} }
if (count($this->args) > 1) { if (count($this->args) > 1) {
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
} }
require_once '.htconfig.php'; require_once '.htconfig.php';
$result = \dba::connect($db_host, $db_user, $db_pass, $db_data); $result = \dba::connect($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data); unset($db_host, $db_user, $db_pass, $db_data);
if (!$result) { if (!$result) {
throw new \RuntimeException('Unable to connect to database'); throw new \RuntimeException('Unable to connect to database');
} }
/** /**
* 1. make nurl from last parameter * 1. make nurl from last parameter
* 2. check DB (contact) if there is a contact with uid=0 and that nurl, get the ID * 2. check DB (contact) if there is a contact with uid=0 and that nurl, get the ID
* 3. set the flag hidden=1 for the contact entry with the found ID * 3. set the flag hidden=1 for the contact entry with the found ID
* */ * */
$net = Probe::uri($this->getArgument(0)); $net = Probe::uri($this->getArgument(0));
if (in_array($net['network'], [Protocol::PHANTOM, Protocol::MAIL])) { if (in_array($net['network'], [Protocol::PHANTOM, Protocol::MAIL])) {
throw new \RuntimeException('This account seems not to exist.'); throw new \RuntimeException('This account seems not to exist.');
} }
$nurl = normalise_link($net['url']); $nurl = normalise_link($net['url']);
$contact = \dba::selectFirst("contact", ["id"], ["nurl" => $nurl, "uid" => 0]); $contact = \dba::selectFirst("contact", ["id"], ["nurl" => $nurl, "uid" => 0]);
if (DBM::is_result($contact)) { if (DBM::is_result($contact)) {
\dba::update("contact", ["hidden" => true], ["id" => $contact["id"]]); \dba::update("contact", ["hidden" => true], ["id" => $contact["id"]]);
$this->out('NOTICE: The account should be silenced from the global community page'); $this->out('NOTICE: The account should be silenced from the global community page');
} else { } else {
throw new \RuntimeException('NOTICE: Could not find any entry for this URL (' . $nurl . ')'); throw new \RuntimeException('NOTICE: Could not find any entry for this URL (' . $nurl . ')');
} }
return 0; return 0;
} }
} }

View file

@ -1,105 +1,105 @@
<?php <?php
namespace Friendica\Core\Console; namespace Friendica\Core\Console;
use Friendica\Core; use Friendica\Core;
require_once 'boot.php'; require_once 'boot.php';
require_once 'include/dba.php'; require_once 'include/dba.php';
/** /**
* @brief Sets maintenance mode for this node * @brief Sets maintenance mode for this node
* *
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class Maintenance extends \Asika\SimpleConsole\Console class Maintenance extends \Asika\SimpleConsole\Console
{ {
protected $helpOptions = ['h', 'help', '?']; protected $helpOptions = ['h', 'help', '?'];
protected function getHelp() protected function getHelp()
{ {
$help = <<<HELP $help = <<<HELP
console maintenance - Sets maintenance mode for this node console maintenance - Sets maintenance mode for this node
Usage Usage
bin/console maintenance <enable> [<reason>] [-h|--help|-?] [-v] bin/console maintenance <enable> [<reason>] [-h|--help|-?] [-v]
Description Description
<enable> cen be either 0 or 1 to disabled or enable the maintenance mode on this node. <enable> cen be either 0 or 1 to disabled or enable the maintenance mode on this node.
<reason> is a quote-enclosed string with the optional reason for the maintenance mode. <reason> is a quote-enclosed string with the optional reason for the maintenance mode.
Examples Examples
bin/console maintenance 1 bin/console maintenance 1
Enables the maintenance mode without setting a reason message Enables the maintenance mode without setting a reason message
bin/console maintenance 1 "SSL certification update" bin/console maintenance 1 "SSL certification update"
Enables the maintenance mode with setting a reason message Enables the maintenance mode with setting a reason message
bin/console maintenance 0 bin/console maintenance 0
Disables the maintenance mode Disables the maintenance mode
Options Options
-h|--help|-? Show help information -h|--help|-? Show help information
-v Show more debug information. -v Show more debug information.
HELP; HELP;
return $help; return $help;
} }
protected function doExecute() protected function doExecute()
{ {
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__); $this->out('Class: ' . __CLASS__);
$this->out('Arguments: ' . var_export($this->args, true)); $this->out('Arguments: ' . var_export($this->args, true));
$this->out('Options: ' . var_export($this->options, true)); $this->out('Options: ' . var_export($this->options, true));
} }
if (count($this->args) == 0) { if (count($this->args) == 0) {
$this->out($this->getHelp()); $this->out($this->getHelp());
return 0; return 0;
} }
if (count($this->args) > 2) { if (count($this->args) > 2) {
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
} }
require_once '.htconfig.php'; require_once '.htconfig.php';
$result = \dba::connect($db_host, $db_user, $db_pass, $db_data); $result = \dba::connect($db_host, $db_user, $db_pass, $db_data);
unset($db_host, $db_user, $db_pass, $db_data); unset($db_host, $db_user, $db_pass, $db_data);
if (!$result) { if (!$result) {
throw new \RuntimeException('Unable to connect to database'); throw new \RuntimeException('Unable to connect to database');
} }
Core\Config::load(); Core\Config::load();
$lang = Core\L10n::getBrowserLanguage(); $lang = Core\L10n::getBrowserLanguage();
Core\L10n::loadTranslationTable($lang); Core\L10n::loadTranslationTable($lang);
$enabled = intval($this->getArgument(0)); $enabled = intval($this->getArgument(0));
Core\Config::set('system', 'maintenance', $enabled); Core\Config::set('system', 'maintenance', $enabled);
$reason = $this->getArgument(1); $reason = $this->getArgument(1);
if ($enabled && $this->getArgument(1)) { if ($enabled && $this->getArgument(1)) {
Core\Config::set('system', 'maintenance_reason', $this->getArgument(1)); Core\Config::set('system', 'maintenance_reason', $this->getArgument(1));
} else { } else {
Core\Config::set('system', 'maintenance_reason', ''); Core\Config::set('system', 'maintenance_reason', '');
} }
if ($enabled) { if ($enabled) {
$mode_str = "maintenance mode"; $mode_str = "maintenance mode";
} else { } else {
$mode_str = "normal mode"; $mode_str = "normal mode";
} }
$this->out('System set in ' . $mode_str); $this->out('System set in ' . $mode_str);
if ($enabled && $reason != '') { if ($enabled && $reason != '') {
$this->out('Maintenance reason: ' . $reason); $this->out('Maintenance reason: ' . $reason);
} }
return 0; return 0;
} }
} }

View file

@ -1,234 +1,234 @@
<?php <?php
namespace Friendica\Core\Console; namespace Friendica\Core\Console;
/** /**
* Read a strings.php file and create messages.po in the same directory * Read a strings.php file and create messages.po in the same directory
* *
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class PhpToPo extends \Asika\SimpleConsole\Console class PhpToPo extends \Asika\SimpleConsole\Console
{ {
protected $helpOptions = ['h', 'help', '?']; protected $helpOptions = ['h', 'help', '?'];
private $normBaseMsgIds = []; private $normBaseMsgIds = [];
const NORM_REGEXP = "|[\\\]|"; const NORM_REGEXP = "|[\\\]|";
protected function getHelp() protected function getHelp()
{ {
$help = <<<HELP $help = <<<HELP
console php2po - Generate a messages.po file from a strings.php file console php2po - Generate a messages.po file from a strings.php file
Usage Usage
bin/console php2po [-p <n>] [--base <file>] <path/to/strings.php> [-h|--help|-?] [-v] bin/console php2po [-p <n>] [--base <file>] <path/to/strings.php> [-h|--help|-?] [-v]
Description Description
Read a strings.php file and create the according messages.po in the same directory Read a strings.php file and create the according messages.po in the same directory
Options Options
-p <n> Number of plural forms. Default: 2 -p <n> Number of plural forms. Default: 2
--base <file> Path to base messages.po file. Default: util/messages.po --base <file> Path to base messages.po file. Default: util/messages.po
-h|--help|-? Show help information -h|--help|-? Show help information
-v Show more debug information. -v Show more debug information.
HELP; HELP;
return $help; return $help;
} }
protected function doExecute() protected function doExecute()
{ {
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__); $this->out('Class: ' . __CLASS__);
$this->out('Arguments: ' . var_export($this->args, true)); $this->out('Arguments: ' . var_export($this->args, true));
$this->out('Options: ' . var_export($this->options, true)); $this->out('Options: ' . var_export($this->options, true));
} }
if (count($this->args) == 0) { if (count($this->args) == 0) {
$this->out($this->getHelp()); $this->out($this->getHelp());
return 0; return 0;
} }
if (count($this->args) > 1) { if (count($this->args) > 1) {
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
} }
$a = get_app(); $a = get_app();
$phpfile = realpath($this->getArgument(0)); $phpfile = realpath($this->getArgument(0));
if (!file_exists($phpfile)) { if (!file_exists($phpfile)) {
throw new \RuntimeException('Supplied file path doesn\'t exist.'); throw new \RuntimeException('Supplied file path doesn\'t exist.');
} }
if (!is_writable(dirname($phpfile))) { if (!is_writable(dirname($phpfile))) {
throw new \RuntimeException('Supplied directory isn\'t writable.'); throw new \RuntimeException('Supplied directory isn\'t writable.');
} }
$pofile = dirname($phpfile) . DIRECTORY_SEPARATOR . 'messages.po'; $pofile = dirname($phpfile) . DIRECTORY_SEPARATOR . 'messages.po';
// start ! // start !
include_once($phpfile); include_once($phpfile);
$out = ''; $out = '';
$out .= "# FRIENDICA Distributed Social Network\n"; $out .= "# FRIENDICA Distributed Social Network\n";
$out .= "# Copyright (C) 2010, 2011, 2012, 2013 the Friendica Project\n"; $out .= "# Copyright (C) 2010, 2011, 2012, 2013 the Friendica Project\n";
$out .= "# This file is distributed under the same license as the Friendica package.\n"; $out .= "# This file is distributed under the same license as the Friendica package.\n";
$out .= "# \n"; $out .= "# \n";
$out .= 'msgid ""' . "\n"; $out .= 'msgid ""' . "\n";
$out .= 'msgstr ""' . "\n"; $out .= 'msgstr ""' . "\n";
$out .= '"Project-Id-Version: friendica\n"' . "\n"; $out .= '"Project-Id-Version: friendica\n"' . "\n";
$out .= '"Report-Msgid-Bugs-To: \n"' . "\n"; $out .= '"Report-Msgid-Bugs-To: \n"' . "\n";
$out .= '"POT-Creation-Date: ' . date("Y-m-d H:i:sO") . '\n"' . "\n"; $out .= '"POT-Creation-Date: ' . date("Y-m-d H:i:sO") . '\n"' . "\n";
$out .= '"MIME-Version: 1.0\n"' . "\n"; $out .= '"MIME-Version: 1.0\n"' . "\n";
$out .= '"Content-Type: text/plain; charset=UTF-8\n"' . "\n"; $out .= '"Content-Type: text/plain; charset=UTF-8\n"' . "\n";
$out .= '"Content-Transfer-Encoding: 8bit\n"' . "\n"; $out .= '"Content-Transfer-Encoding: 8bit\n"' . "\n";
// search for plural info // search for plural info
$lang = ""; $lang = "";
$lang_logic = ""; $lang_logic = "";
$lang_pnum = $this->getOption('p', 2); $lang_pnum = $this->getOption('p', 2);
$infile = file($phpfile); $infile = file($phpfile);
foreach ($infile as $l) { foreach ($infile as $l) {
$l = trim($l); $l = trim($l);
if ($this->startsWith($l, 'function string_plural_select_')) { if ($this->startsWith($l, 'function string_plural_select_')) {
$lang = str_replace('function string_plural_select_', '', str_replace('($n){', '', $l)); $lang = str_replace('function string_plural_select_', '', str_replace('($n){', '', $l));
} }
if ($this->startsWith($l, 'return')) { if ($this->startsWith($l, 'return')) {
$lang_logic = str_replace('$', '', trim(str_replace('return ', '', $l), ';')); $lang_logic = str_replace('$', '', trim(str_replace('return ', '', $l), ';'));
break; break;
} }
} }
$this->out('Language: ' . $lang); $this->out('Language: ' . $lang);
$this->out('Plural forms: ' . $lang_pnum); $this->out('Plural forms: ' . $lang_pnum);
$this->out('Plural forms: ' . $lang_logic); $this->out('Plural forms: ' . $lang_logic);
$out .= sprintf('"Language: %s\n"', $lang) . "\n"; $out .= sprintf('"Language: %s\n"', $lang) . "\n";
$out .= sprintf('"Plural-Forms: nplurals=%s; plural=%s;\n"', $lang_pnum, $lang_logic) . "\n"; $out .= sprintf('"Plural-Forms: nplurals=%s; plural=%s;\n"', $lang_pnum, $lang_logic) . "\n";
$out .= "\n"; $out .= "\n";
$base_path = $this->getOption('base', 'util' . DIRECTORY_SEPARATOR . 'messages.po'); $base_path = $this->getOption('base', 'util' . DIRECTORY_SEPARATOR . 'messages.po');
// load base messages.po and extract msgids // load base messages.po and extract msgids
$base_msgids = []; $base_msgids = [];
$base_f = file($base_path); $base_f = file($base_path);
if (!$base_f) { if (!$base_f) {
throw new \RuntimeException('The base ' . $base_path . ' file is missing or unavailable to read.'); throw new \RuntimeException('The base ' . $base_path . ' file is missing or unavailable to read.');
} }
$this->out('Loading base file ' . $base_path . '...'); $this->out('Loading base file ' . $base_path . '...');
$_f = 0; $_f = 0;
$_mid = ""; $_mid = "";
$_mids = []; $_mids = [];
foreach ($base_f as $l) { foreach ($base_f as $l) {
$l = trim($l); $l = trim($l);
if ($this->startsWith($l, 'msgstr')) { if ($this->startsWith($l, 'msgstr')) {
if ($_mid != '""') { if ($_mid != '""') {
$base_msgids[$_mid] = $_mids; $base_msgids[$_mid] = $_mids;
$this->normBaseMsgIds[preg_replace(self::NORM_REGEXP, "", $_mid)] = $_mid; $this->normBaseMsgIds[preg_replace(self::NORM_REGEXP, "", $_mid)] = $_mid;
} }
$_f = 0; $_f = 0;
$_mid = ""; $_mid = "";
$_mids = []; $_mids = [];
} }
if ($this->startsWith($l, '"') && $_f == 2) { if ($this->startsWith($l, '"') && $_f == 2) {
$_mids[count($_mids) - 1] .= "\n" . $l; $_mids[count($_mids) - 1] .= "\n" . $l;
} }
if ($this->startsWith($l, 'msgid_plural ')) { if ($this->startsWith($l, 'msgid_plural ')) {
$_f = 2; $_f = 2;
$_mids[] = str_replace('msgid_plural ', '', $l); $_mids[] = str_replace('msgid_plural ', '', $l);
} }
if ($this->startsWith($l, '"') && $_f == 1) { if ($this->startsWith($l, '"') && $_f == 1) {
$_mid .= "\n" . $l; $_mid .= "\n" . $l;
$_mids[count($_mids) - 1] .= "\n" . $l; $_mids[count($_mids) - 1] .= "\n" . $l;
} }
if ($this->startsWith($l, 'msgid ')) { if ($this->startsWith($l, 'msgid ')) {
$_f = 1; $_f = 1;
$_mid = str_replace('msgid ', '', $l); $_mid = str_replace('msgid ', '', $l);
$_mids = [$_mid]; $_mids = [$_mid];
} }
} }
$this->out('Creating ' . $pofile . '...'); $this->out('Creating ' . $pofile . '...');
// create msgid and msgstr // create msgid and msgstr
$warnings = ""; $warnings = "";
foreach ($a->strings as $key => $str) { foreach ($a->strings as $key => $str) {
$msgid = $this->massageString($key); $msgid = $this->massageString($key);
if (preg_match("|%[sd0-9](\$[sn])*|", $msgid)) { if (preg_match("|%[sd0-9](\$[sn])*|", $msgid)) {
$out .= "#, php-format\n"; $out .= "#, php-format\n";
} }
$msgid = $this->findOriginalMsgId($msgid); $msgid = $this->findOriginalMsgId($msgid);
$out .= 'msgid ' . $msgid . "\n"; $out .= 'msgid ' . $msgid . "\n";
if (is_array($str)) { if (is_array($str)) {
if (array_key_exists($msgid, $base_msgids) && isset($base_msgids[$msgid][1])) { if (array_key_exists($msgid, $base_msgids) && isset($base_msgids[$msgid][1])) {
$out .= 'msgid_plural ' . $base_msgids[$msgid][1] . "\n"; $out .= 'msgid_plural ' . $base_msgids[$msgid][1] . "\n";
} else { } else {
$out .= 'msgid_plural ' . $msgid . "\n"; $out .= 'msgid_plural ' . $msgid . "\n";
$warnings .= "[W] No source plural form for msgid:\n" . str_replace("\n", "\n\t", $msgid) . "\n\n"; $warnings .= "[W] No source plural form for msgid:\n" . str_replace("\n", "\n\t", $msgid) . "\n\n";
} }
foreach ($str as $n => $msgstr) { foreach ($str as $n => $msgstr) {
$out .= 'msgstr[' . $n . '] ' . $this->massageString($msgstr) . "\n"; $out .= 'msgstr[' . $n . '] ' . $this->massageString($msgstr) . "\n";
} }
} else { } else {
$out .= 'msgstr ' . $this->massageString($str) . "\n"; $out .= 'msgstr ' . $this->massageString($str) . "\n";
} }
$out .= "\n"; $out .= "\n";
} }
if (!file_put_contents($pofile, $out)) { if (!file_put_contents($pofile, $out)) {
throw new \RuntimeException('Unable to write to ' . $pofile); throw new \RuntimeException('Unable to write to ' . $pofile);
} }
if ($warnings != '') { if ($warnings != '') {
$this->out($warnings); $this->out($warnings);
} }
return 0; return 0;
} }
private function startsWith($haystack, $needle) private function startsWith($haystack, $needle)
{ {
// search backwards starting from haystack length characters from the end // search backwards starting from haystack length characters from the end
return $needle === "" || strrpos($haystack, $needle, -strlen($haystack)) !== FALSE; return $needle === "" || strrpos($haystack, $needle, -strlen($haystack)) !== FALSE;
} }
/** /**
* Get a string and retun a message.po ready text * Get a string and retun a message.po ready text
* - replace " with \" * - replace " with \"
* - replace tab char with \t * - replace tab char with \t
* - manage multiline strings * - manage multiline strings
*/ */
private function massageString($str) private function massageString($str)
{ {
$str = str_replace('\\', '\\\\', $str); $str = str_replace('\\', '\\\\', $str);
$str = str_replace('"', '\"', $str); $str = str_replace('"', '\"', $str);
$str = str_replace("\t", '\t', $str); $str = str_replace("\t", '\t', $str);
$str = str_replace("\n", '\n"' . "\n" . '"', $str); $str = str_replace("\n", '\n"' . "\n" . '"', $str);
if (strpos($str, "\n") !== false && $str[0] !== '"') { if (strpos($str, "\n") !== false && $str[0] !== '"') {
$str = '"' . "\n" . $str; $str = '"' . "\n" . $str;
} }
$str = preg_replace("|\n([^\"])|", "\n\"$1", $str); $str = preg_replace("|\n([^\"])|", "\n\"$1", $str);
return sprintf('"%s"', $str); return sprintf('"%s"', $str);
} }
private function findOriginalMsgId($str) private function findOriginalMsgId($str)
{ {
$norm_str = preg_replace(self::NORM_REGEXP, "", $str); $norm_str = preg_replace(self::NORM_REGEXP, "", $str);
if (array_key_exists($norm_str, $this->normBaseMsgIds)) { if (array_key_exists($norm_str, $this->normBaseMsgIds)) {
return $this->normBaseMsgIds[$norm_str]; return $this->normBaseMsgIds[$norm_str];
} }
return $str; return $str;
} }
} }

View file

@ -1,197 +1,197 @@
<?php <?php
namespace Friendica\Core\Console; namespace Friendica\Core\Console;
/** /**
* Read a messages.po file and create strings.php in the same directory * Read a messages.po file and create strings.php in the same directory
* *
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class PoToPhp extends \Asika\SimpleConsole\Console class PoToPhp extends \Asika\SimpleConsole\Console
{ {
protected $helpOptions = ['h', 'help', '?']; protected $helpOptions = ['h', 'help', '?'];
const DQ_ESCAPE = "__DQ__"; const DQ_ESCAPE = "__DQ__";
protected function getHelp() protected function getHelp()
{ {
$help = <<<HELP $help = <<<HELP
console php2po - Generate a strings.php file from a messages.po file console php2po - Generate a strings.php file from a messages.po file
Usage Usage
bin/console php2po <path/to/messages.po> [-h|--help|-?] [-v] bin/console php2po <path/to/messages.po> [-h|--help|-?] [-v]
Description Description
Read a messages.po file and create the according strings.php in the same directory Read a messages.po file and create the according strings.php in the same directory
Options Options
-h|--help|-? Show help information -h|--help|-? Show help information
-v Show more debug information. -v Show more debug information.
HELP; HELP;
return $help; return $help;
} }
protected function doExecute() protected function doExecute()
{ {
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__); $this->out('Class: ' . __CLASS__);
$this->out('Arguments: ' . var_export($this->args, true)); $this->out('Arguments: ' . var_export($this->args, true));
$this->out('Options: ' . var_export($this->options, true)); $this->out('Options: ' . var_export($this->options, true));
} }
if (count($this->args) == 0) { if (count($this->args) == 0) {
$this->out($this->getHelp()); $this->out($this->getHelp());
return 0; return 0;
} }
if (count($this->args) > 1) { if (count($this->args) > 1) {
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
} }
$a = get_app(); $a = get_app();
$pofile = realpath($this->getArgument(0)); $pofile = realpath($this->getArgument(0));
if (!file_exists($pofile)) { if (!file_exists($pofile)) {
throw new \RuntimeException('Supplied file path doesn\'t exist.'); throw new \RuntimeException('Supplied file path doesn\'t exist.');
} }
if (!is_writable(dirname($pofile))) { if (!is_writable(dirname($pofile))) {
throw new \RuntimeException('Supplied directory isn\'t writable.'); throw new \RuntimeException('Supplied directory isn\'t writable.');
} }
$outfile = dirname($pofile) . DIRECTORY_SEPARATOR . 'strings.php'; $outfile = dirname($pofile) . DIRECTORY_SEPARATOR . 'strings.php';
if (strstr($outfile, 'util')) { if (strstr($outfile, 'util')) {
$lang = 'en'; $lang = 'en';
} else { } else {
$lang = str_replace('-', '_', basename(dirname($pofile))); $lang = str_replace('-', '_', basename(dirname($pofile)));
} }
$this->out('Out to ' . $outfile); $this->out('Out to ' . $outfile);
$out = "<?php\n\n"; $out = "<?php\n\n";
$infile = file($pofile); $infile = file($pofile);
$k = ''; $k = '';
$v = ''; $v = '';
$arr = false; $arr = false;
$ink = false; $ink = false;
$inv = false; $inv = false;
$escape_s_exp = '|[^\\\\]\$[a-z]|'; $escape_s_exp = '|[^\\\\]\$[a-z]|';
foreach ($infile as $l) { foreach ($infile as $l) {
$l = str_replace('\"', self::DQ_ESCAPE, $l); $l = str_replace('\"', self::DQ_ESCAPE, $l);
$len = strlen($l); $len = strlen($l);
if ($l[0] == "#") { if ($l[0] == "#") {
$l = ""; $l = "";
} }
if (substr($l, 0, 15) == '"Plural-Forms: ') { if (substr($l, 0, 15) == '"Plural-Forms: ') {
$match = []; $match = [];
preg_match("|nplurals=([0-9]*); *plural=(.*)[;\\\\]|", $l, $match); preg_match("|nplurals=([0-9]*); *plural=(.*)[;\\\\]|", $l, $match);
$cond = str_replace('n', '$n', $match[2]); $cond = str_replace('n', '$n', $match[2]);
// define plural select function if not already defined // define plural select function if not already defined
$fnname = 'string_plural_select_' . $lang; $fnname = 'string_plural_select_' . $lang;
$out .= 'if(! function_exists("' . $fnname . '")) {' . "\n"; $out .= 'if(! function_exists("' . $fnname . '")) {' . "\n";
$out .= 'function ' . $fnname . '($n){' . "\n"; $out .= 'function ' . $fnname . '($n){' . "\n";
$out .= ' return ' . $cond . ';' . "\n"; $out .= ' return ' . $cond . ';' . "\n";
$out .= '}}' . "\n"; $out .= '}}' . "\n";
} }
if ($k != "" && substr($l, 0, 7) == 'msgstr ') { if ($k != "" && substr($l, 0, 7) == 'msgstr ') {
if ($ink) { if ($ink) {
$ink = false; $ink = false;
$out .= '$a->strings["' . $k . '"] = '; $out .= '$a->strings["' . $k . '"] = ';
} }
if ($inv) { if ($inv) {
$inv = false; $inv = false;
$out .= '"' . $v . '"'; $out .= '"' . $v . '"';
} }
$v = substr($l, 8, $len - 11); $v = substr($l, 8, $len - 11);
$v = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $v); $v = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $v);
$inv = true; $inv = true;
} }
if ($k != "" && substr($l, 0, 7) == 'msgstr[') { if ($k != "" && substr($l, 0, 7) == 'msgstr[') {
if ($ink) { if ($ink) {
$ink = false; $ink = false;
$out .= '$a->strings["' . $k . '"] = '; $out .= '$a->strings["' . $k . '"] = ';
} }
if ($inv) { if ($inv) {
$inv = false; $inv = false;
$out .= '"' . $v . '"'; $out .= '"' . $v . '"';
} }
if (!$arr) { if (!$arr) {
$arr = True; $arr = True;
$out .= "[\n"; $out .= "[\n";
} }
$match = []; $match = [];
preg_match("|\[([0-9]*)\] (.*)|", $l, $match); preg_match("|\[([0-9]*)\] (.*)|", $l, $match);
$out .= "\t" $out .= "\t"
. preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $match[1]) . preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $match[1])
. ' => ' . ' => '
. preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $match[2]) . preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $match[2])
. ",\n"; . ",\n";
} }
if (substr($l, 0, 6) == 'msgid_') { if (substr($l, 0, 6) == 'msgid_') {
$ink = false; $ink = false;
$out .= '$a->strings["' . $k . '"] = '; $out .= '$a->strings["' . $k . '"] = ';
} }
if ($ink) { if ($ink) {
$k .= trim($l, "\"\r\n"); $k .= trim($l, "\"\r\n");
$k = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $k); $k = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $k);
} }
if (substr($l, 0, 6) == 'msgid ') { if (substr($l, 0, 6) == 'msgid ') {
if ($inv) { if ($inv) {
$inv = false; $inv = false;
$out .= '"' . $v . '"'; $out .= '"' . $v . '"';
} }
if ($k != "") { if ($k != "") {
$out .= ($arr) ? "];\n" : ";\n"; $out .= ($arr) ? "];\n" : ";\n";
} }
$arr = false; $arr = false;
$k = str_replace("msgid ", "", $l); $k = str_replace("msgid ", "", $l);
if ($k != '""') { if ($k != '""') {
$k = trim($k, "\"\r\n"); $k = trim($k, "\"\r\n");
} else { } else {
$k = ''; $k = '';
} }
$k = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $k); $k = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $k);
$ink = true; $ink = true;
} }
if ($inv && substr($l, 0, 6) != "msgstr") { if ($inv && substr($l, 0, 6) != "msgstr") {
$v .= trim($l, "\"\r\n"); $v .= trim($l, "\"\r\n");
$v = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $v); $v = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $v);
} }
} }
if ($inv) { if ($inv) {
$inv = false; $inv = false;
$out .= '"' . $v . '"'; $out .= '"' . $v . '"';
} }
if ($k != '') { if ($k != '') {
$out .= ($arr ? "];\n" : ";\n"); $out .= ($arr ? "];\n" : ";\n");
} }
$out = str_replace(self::DQ_ESCAPE, '\"', $out); $out = str_replace(self::DQ_ESCAPE, '\"', $out);
if (!file_put_contents($outfile, $out)) { if (!file_put_contents($outfile, $out)) {
throw new \RuntimeException('Unable to write to ' . $outfile); throw new \RuntimeException('Unable to write to ' . $outfile);
} }
return 0; return 0;
} }
private function escapeDollar($match) private function escapeDollar($match)
{ {
return str_replace('$', '\$', $match[0]); return str_replace('$', '\$', $match[0]);
} }
} }

View file

@ -1,119 +1,119 @@
<?php <?php
namespace Friendica\Core\Console; namespace Friendica\Core\Console;
/** /**
* Tired of chasing typos and finding them after a commit. * Tired of chasing typos and finding them after a commit.
* Run this and quickly see if we've got any parse errors in our application files. * Run this and quickly see if we've got any parse errors in our application files.
* *
* @author Hypolite Petovan <mrpetovan@gmail.com> * @author Hypolite Petovan <mrpetovan@gmail.com>
*/ */
class Typo extends \Asika\SimpleConsole\Console class Typo extends \Asika\SimpleConsole\Console
{ {
protected $helpOptions = ['h', 'help', '?']; protected $helpOptions = ['h', 'help', '?'];
protected function getHelp() protected function getHelp()
{ {
$help = <<<HELP $help = <<<HELP
console typo - Checks for parse errors in Friendica files console typo - Checks for parse errors in Friendica files
Usage Usage
bin/console typo [-h|--help|-?] [-v] bin/console typo [-h|--help|-?] [-v]
Description Description
Checks all PHP files in the Friendica file tree for parse errors Checks all PHP files in the Friendica file tree for parse errors
Options Options
-h|--help|-? Show help information -h|--help|-? Show help information
-v Show more debug information. -v Show more debug information.
HELP; HELP;
return $help; return $help;
} }
protected function doExecute() protected function doExecute()
{ {
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Class: ' . __CLASS__); $this->out('Class: ' . __CLASS__);
$this->out('Arguments: ' . var_export($this->args, true)); $this->out('Arguments: ' . var_export($this->args, true));
$this->out('Options: ' . var_export($this->options, true)); $this->out('Options: ' . var_export($this->options, true));
} }
if (count($this->args) > 0) { if (count($this->args) > 0) {
throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');
} }
$a = get_app(); $a = get_app();
$php_path = $a->getConfigValue('config', 'php_path', 'php'); $php_path = $a->getConfigValue('config', 'php_path', 'php');
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Directory: src'); $this->out('Directory: src');
} }
$Iterator = new \RecursiveDirectoryIterator('src'); $Iterator = new \RecursiveDirectoryIterator('src');
foreach (new \RecursiveIteratorIterator($Iterator) as $file) { foreach (new \RecursiveIteratorIterator($Iterator) as $file) {
if (substr($file, -4) === '.php') { if (substr($file, -4) === '.php') {
$this->checkFile($php_path, $file); $this->checkFile($php_path, $file);
} }
} }
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Directory: mod'); $this->out('Directory: mod');
} }
$files = glob('mod/*.php'); $files = glob('mod/*.php');
$this->checkFiles($php_path, $files); $this->checkFiles($php_path, $files);
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Directory: include'); $this->out('Directory: include');
} }
$files = glob('include/*.php'); $files = glob('include/*.php');
$this->checkFiles($php_path, $files); $this->checkFiles($php_path, $files);
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Directory: addon'); $this->out('Directory: addon');
} }
$dirs = glob('addon/*'); $dirs = glob('addon/*');
foreach ($dirs as $dir) { foreach ($dirs as $dir) {
$addon = basename($dir); $addon = basename($dir);
$files = glob($dir . '/' . $addon . '.php'); $files = glob($dir . '/' . $addon . '.php');
$this->checkFiles($php_path, $files); $this->checkFiles($php_path, $files);
} }
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('String files'); $this->out('String files');
} }
$this->checkFile($php_path, 'util/strings.php'); $this->checkFile($php_path, 'util/strings.php');
$files = glob('view/lang/*/strings.php'); $files = glob('view/lang/*/strings.php');
$this->checkFiles($php_path, $files); $this->checkFiles($php_path, $files);
$this->out('No errors.'); $this->out('No errors.');
return 0; return 0;
} }
private function checkFiles($php_path, array $files) private function checkFiles($php_path, array $files)
{ {
foreach ($files as $file) { foreach ($files as $file) {
$this->checkFile($php_path, $file); $this->checkFile($php_path, $file);
} }
} }
private function checkFile($php_path, $file) private function checkFile($php_path, $file)
{ {
if ($this->getOption('v')) { if ($this->getOption('v')) {
$this->out('Checking ' . $file); $this->out('Checking ' . $file);
} }
$output = []; $output = [];
$ret = 0; $ret = 0;
exec("$php_path -l $file", $output, $ret); exec("$php_path -l $file", $output, $ret);
if ($ret !== 0) { if ($ret !== 0) {
throw new \RuntimeException('Parse error found in ' . $file . ', scan stopped.'); throw new \RuntimeException('Parse error found in ' . $file . ', scan stopped.');
} }
} }
} }