diff --git a/src/Core/ACL.php b/src/Core/ACL.php index c258e0d0bf..4e8bf6abde 100644 --- a/src/Core/ACL.php +++ b/src/Core/ACL.php @@ -1,358 +1,369 @@ - - */ -class ACL extends BaseObject -{ - /** - * 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 $selclass Class attribute of the select input tag - * @param array $options Available options: - * - size: length of the select box - * - mutual_friends: Only used for the hook - * - single: Only used for the hook - * - exclude: Only used for the hook - * @param array $preselected Contact ID that should be already selected - * @return string - */ - public static function getSuggestContactSelectHTML($selname, $selclass, array $options = [], array $preselected = []) - { - $a = self::getApp(); - - $networks = null; - - $size = defaults($options, 'size', 4); - $mutual = !empty($options['mutual_friends']); - $single = !empty($options['single']) && empty($options['multiple']); - $exclude = defaults($options, 'exclude', false); - - switch (defaults($options, 'networks', Protocol::PHANTOM)) { - case 'DFRN_ONLY': - $networks = [NETWORK_DFRN]; - break; - case 'PRIVATE': - if (!empty($a->user['prvnets'])) { - $networks = [NETWORK_DFRN, NETWORK_MAIL, NETWORK_DIASPORA]; - } else { - $networks = [NETWORK_DFRN, NETWORK_FACEBOOK, NETWORK_MAIL, NETWORK_DIASPORA]; - } - break; - case 'TWO_WAY': - if (!empty($a->user['prvnets'])) { - $networks = [NETWORK_DFRN, NETWORK_MAIL, NETWORK_DIASPORA]; - } else { - $networks = [NETWORK_DFRN, NETWORK_FACEBOOK, NETWORK_MAIL, NETWORK_DIASPORA, NETWORK_OSTATUS]; - } - break; - default: /// @TODO Maybe log this call? - break; - } - - $x = ['options' => $options, 'size' => $size, 'single' => $single, 'mutual' => $mutual, 'exclude' => $exclude, 'networks' => $networks]; - - Addon::callHooks('contact_select_options', $x); - - $o = ''; - - $sql_extra = ''; - - if (!empty($x['mutual'])) { - $sql_extra .= sprintf(" AND `rel` = %d ", intval(CONTACT_IS_FRIEND)); - } - - if (!empty($x['exclude'])) { - $sql_extra .= sprintf(" AND `id` != %d ", intval($x['exclude'])); - } - - if (!empty($x['networks'])) { - /// @TODO rewrite to foreach() - array_walk($x['networks'], function (&$value) { - $value = "'" . dbesc($value) . "'"; - }); - $str_nets = implode(',', $x['networks']); - $sql_extra .= " AND `network` IN ( $str_nets ) "; - } - - $tabindex = (!empty($options['tabindex']) ? 'tabindex="' . $options["tabindex"] . '"' : ''); - - if (!empty($x['single'])) { - $o .= "\r\n"; - } - - $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` != '' - $sql_extra - ORDER BY `name` ASC ", intval(local_user()) - ); - - $contacts = dba::inArray($stmt); - - $arr = ['contact' => $contacts, 'entry' => $o]; - - // e.g. 'network_pre_contact_deny', 'profile_pre_contact_allow' - Addon::callHooks($a->module . '_pre_' . $selname, $arr); - - if (DBM::is_result($contacts)) { - foreach ($contacts as $contact) { - if (in_array($contact['id'], $preselected)) { - $selected = ' selected="selected" '; - } else { - $selected = ''; - } - - $trimmed = mb_substr($contact['name'], 0, 20); - - $o .= "\r\n"; - } - } - - $o .= '' . PHP_EOL; - - Addon::callHooks($a->module . '_post_' . $selname, $o); - - return $o; - } - - /** - * 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 $selclass Class attribute of the select input tag - * @param array $preselected Contact IDs that should be already selected - * @param int $size Length of the select box - * @param int $tabindex Select input tag tabindex attribute - * @return string - */ - public static function getMessageContactSelectHTML($selname, $selclass, array $preselected = [], $size = 4, $tabindex = null) - { - $a = self::getApp(); - - $o = ''; - - // 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. - $sql_extra = sprintf(" AND `rel` = %d ", intval(CONTACT_IS_FRIEND)); - $sql_extra .= sprintf(" AND `network` IN ('%s' , '%s') ", NETWORK_DFRN, NETWORK_DIASPORA); - - $tabindex_attr = !empty($tabindex) ? ' tabindex="' . intval($tabindex) . '"' : ''; - - $hidepreselected = ''; - if ($preselected) { - $sql_extra .= " AND `id` IN (" . implode(",", $preselected) . ")"; - $hidepreselected = ' style="display: none;"'; - } - - $o .= "' . PHP_EOL; - - if ($preselected) { - $o .= implode(', ', $receiverlist); - } - - Addon::callHooks($a->module . '_post_' . $selname, $o); - - return $o; - } - - /** - * Return the default permission of the provided user array - * - * @param array $user - * @return array Hash of contact id lists - */ - public static function getDefaultUserPermissions(array $user = null) - { - $matches = []; - - $acl_regex = '/<([0-9]+)>/i'; - - preg_match_all($acl_regex, defaults($user, 'allow_cid', ''), $matches); - $allow_cid = $matches[1]; - preg_match_all($acl_regex, defaults($user, 'allow_gid', ''), $matches); - $allow_gid = $matches[1]; - preg_match_all($acl_regex, defaults($user, 'deny_cid', ''), $matches); - $deny_cid = $matches[1]; - preg_match_all($acl_regex, defaults($user, 'deny_gid', ''), $matches); - $deny_gid = $matches[1]; - - Contact::pruneUnavailable($allow_cid); - - return [ - 'allow_cid' => $allow_cid, - 'allow_gid' => $allow_gid, - 'deny_cid' => $deny_cid, - 'deny_gid' => $deny_gid, - ]; - } - - /** - * Return the full jot ACL selector HTML - * - * @param array $user - * @param bool $show_jotnets - * @return string - */ - public static function getFullSelectorHTML(array $user = null, $show_jotnets = false) - { - $perms = self::getDefaultUserPermissions($user); - - $jotnets = ''; - if ($show_jotnets) { - $imap_disabled = !function_exists('imap_open') || Config::get('system', 'imap_disabled'); - - $mail_enabled = false; - $pubmail_enabled = false; - - if (!$imap_disabled) { - $mailacct = dba::selectFirst('mailacct', ['pubmail'], ['`uid` = ? AND `server` != ""', local_user()]); - if (DBM::is_result($mailacct)) { - $mail_enabled = true; - $pubmail_enabled = !empty($mailacct['pubmail']); - } - } - - if (empty($user['hidewall'])) { - if ($mail_enabled) { - $selected = $pubmail_enabled ? ' checked="checked"' : ''; - $jotnets .= '
' . L10n::t("Post to Email") . '
'; - } - - Addon::callHooks('jot_networks', $jotnets); - } else { - $jotnets .= L10n::t('Connectors disabled, since "%s" is enabled.', - L10n::t('Hide your profile details from unknown viewers?')); - } - } - - $tpl = get_markup_template('acl_selector.tpl'); - $o = replace_macros($tpl, [ - '$showall' => L10n::t('Visible to everybody'), - '$show' => L10n::t('show'), - '$hide' => L10n::t('don\'t show'), - '$allowcid' => json_encode($perms['allow_cid']), - '$allowgid' => json_encode($perms['allow_gid']), - '$denycid' => json_encode($perms['deny_cid']), - '$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'), - '$jotnets' => $jotnets, - '$aclModalTitle' => L10n::t('Permissions'), - '$aclModalDismiss' => L10n::t('Close'), - '$features' => [ - 'aclautomention' => Feature::isEnabled($user['uid'], 'aclautomention') ? 'true' : 'false' - ], - ]); - - return $o; - } - - /** - * Searching for global contacts for autocompletion - * - * @brief Searching for global contacts for autocompletion - * @param string $search Name or part of a name or nick - * @param string $mode Search mode (e.g. "community") - * @return array with the search results - */ - public static function contactAutocomplete($search, $mode) - { - if ((Config::get('system', 'block_public')) && (!local_user()) && (!remote_user())) { - return []; - } - - // don't search if search term has less than 2 characters - if (!$search || mb_strlen($search) < 2) { - return []; - } - - if (substr($search, 0, 1) === '@') { - $search = substr($search, 1); - } - - // 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(); - $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, []); - } -} + + */ +class ACL extends BaseObject +{ + /** + * 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 $selclass Class attribute of the select input tag + * @param array $options Available options: + * - size: length of the select box + * - mutual_friends: Only used for the hook + * - single: Only used for the hook + * - exclude: Only used for the hook + * @param array $preselected Contact ID that should be already selected + * @return string + */ + public static function getSuggestContactSelectHTML($selname, $selclass, array $options = [], array $preselected = []) + { + $a = self::getApp(); + + $networks = null; + + $size = defaults($options, 'size', 4); + $mutual = !empty($options['mutual_friends']); + $single = !empty($options['single']) && empty($options['multiple']); + $exclude = defaults($options, 'exclude', false); + + switch (defaults($options, 'networks', Protocol::PHANTOM)) { + case 'DFRN_ONLY': + $networks = [NETWORK_DFRN]; + break; + case 'PRIVATE': + if (!empty($a->user['prvnets'])) { + $networks = [NETWORK_DFRN, NETWORK_MAIL, NETWORK_DIASPORA]; + } else { + $networks = [NETWORK_DFRN, NETWORK_FACEBOOK, NETWORK_MAIL, NETWORK_DIASPORA]; + } + break; + case 'TWO_WAY': + if (!empty($a->user['prvnets'])) { + $networks = [NETWORK_DFRN, NETWORK_MAIL, NETWORK_DIASPORA]; + } else { + $networks = [NETWORK_DFRN, NETWORK_FACEBOOK, NETWORK_MAIL, NETWORK_DIASPORA, NETWORK_OSTATUS]; + } + break; + default: /// @TODO Maybe log this call? + break; + } + + $x = ['options' => $options, 'size' => $size, 'single' => $single, 'mutual' => $mutual, 'exclude' => $exclude, 'networks' => $networks]; + + Addon::callHooks('contact_select_options', $x); + + $o = ''; + + $sql_extra = ''; + + if (!empty($x['mutual'])) { + $sql_extra .= sprintf(" AND `rel` = %d ", intval(CONTACT_IS_FRIEND)); + } + + if (!empty($x['exclude'])) { + $sql_extra .= sprintf(" AND `id` != %d ", intval($x['exclude'])); + } + + if (!empty($x['networks'])) { + /// @TODO rewrite to foreach() + array_walk($x['networks'], function (&$value) { + $value = "'" . dbesc($value) . "'"; + }); + $str_nets = implode(',', $x['networks']); + $sql_extra .= " AND `network` IN ( $str_nets ) "; + } + + $tabindex = (!empty($options['tabindex']) ? 'tabindex="' . $options["tabindex"] . '"' : ''); + + if (!empty($x['single'])) { + $o .= "\r\n"; + } + + $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` != '' + $sql_extra + ORDER BY `name` ASC ", intval(local_user()) + ); + + $contacts = dba::inArray($stmt); + + $arr = ['contact' => $contacts, 'entry' => $o]; + + // e.g. 'network_pre_contact_deny', 'profile_pre_contact_allow' + Addon::callHooks($a->module . '_pre_' . $selname, $arr); + + if (DBM::is_result($contacts)) { + foreach ($contacts as $contact) { + if (in_array($contact['id'], $preselected)) { + $selected = ' selected="selected" '; + } else { + $selected = ''; + } + + $trimmed = mb_substr($contact['name'], 0, 20); + + $o .= "\r\n"; + } + } + + $o .= '' . PHP_EOL; + + Addon::callHooks($a->module . '_post_' . $selname, $o); + + return $o; + } + + /** + * 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 $selclass Class attribute of the select input tag + * @param array $preselected Contact IDs that should be already selected + * @param int $size Length of the select box + * @param int $tabindex Select input tag tabindex attribute + * @return string + */ + public static function getMessageContactSelectHTML($selname, $selclass, array $preselected = [], $size = 4, $tabindex = null) + { + $a = self::getApp(); + + $o = ''; + + // 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. + $sql_extra = sprintf(" AND `rel` = %d ", intval(CONTACT_IS_FRIEND)); + $sql_extra .= sprintf(" AND `network` IN ('%s' , '%s') ", NETWORK_DFRN, NETWORK_DIASPORA); + + $tabindex_attr = !empty($tabindex) ? ' tabindex="' . intval($tabindex) . '"' : ''; + + $hidepreselected = ''; + if ($preselected) { + $sql_extra .= " AND `id` IN (" . implode(",", $preselected) . ")"; + $hidepreselected = ' style="display: none;"'; + } + + $o .= "' . PHP_EOL; + + if ($preselected) { + $o .= implode(', ', $receiverlist); + } + + Addon::callHooks($a->module . '_post_' . $selname, $o); + + return $o; + } + + private static function fixACL(&$item) + { + $item = intval(str_replace(['<', '>'], ['', ''], $item)); + } + + /** + * Return the default permission of the provided user array + * + * @param array $user + * @return array Hash of contact id lists + */ + public static function getDefaultUserPermissions(array $user = null) + { + $matches = []; + + $acl_regex = '/<([0-9]+)>/i'; + + preg_match_all($acl_regex, defaults($user, 'allow_cid', ''), $matches); + $allow_cid = $matches[1]; + preg_match_all($acl_regex, defaults($user, 'allow_gid', ''), $matches); + $allow_gid = $matches[1]; + preg_match_all($acl_regex, defaults($user, 'deny_cid', ''), $matches); + $deny_cid = $matches[1]; + preg_match_all($acl_regex, defaults($user, 'deny_gid', ''), $matches); + $deny_gid = $matches[1]; + + // Reformats the ACL data so that it is accepted by the JS frontend + array_walk($allow_cid, 'self::fixACL'); + array_walk($allow_gid, 'self::fixACL'); + array_walk($deny_cid, 'self::fixACL'); + array_walk($deny_gid, 'self::fixACL'); + + Contact::pruneUnavailable($allow_cid); + + return [ + 'allow_cid' => $allow_cid, + 'allow_gid' => $allow_gid, + 'deny_cid' => $deny_cid, + 'deny_gid' => $deny_gid, + ]; + } + + /** + * Return the full jot ACL selector HTML + * + * @param array $user + * @param bool $show_jotnets + * @return string + */ + public static function getFullSelectorHTML(array $user = null, $show_jotnets = false) + { + $perms = self::getDefaultUserPermissions($user); + + $jotnets = ''; + if ($show_jotnets) { + $imap_disabled = !function_exists('imap_open') || Config::get('system', 'imap_disabled'); + + $mail_enabled = false; + $pubmail_enabled = false; + + if (!$imap_disabled) { + $mailacct = dba::selectFirst('mailacct', ['pubmail'], ['`uid` = ? AND `server` != ""', local_user()]); + if (DBM::is_result($mailacct)) { + $mail_enabled = true; + $pubmail_enabled = !empty($mailacct['pubmail']); + } + } + + if (empty($user['hidewall'])) { + if ($mail_enabled) { + $selected = $pubmail_enabled ? ' checked="checked"' : ''; + $jotnets .= '
' . L10n::t("Post to Email") . '
'; + } + + Addon::callHooks('jot_networks', $jotnets); + } else { + $jotnets .= L10n::t('Connectors disabled, since "%s" is enabled.', + L10n::t('Hide your profile details from unknown viewers?')); + } + } + + $tpl = get_markup_template('acl_selector.tpl'); + $o = replace_macros($tpl, [ + '$showall' => L10n::t('Visible to everybody'), + '$show' => L10n::t('show'), + '$hide' => L10n::t('don\'t show'), + '$allowcid' => json_encode($perms['allow_cid']), + '$allowgid' => json_encode($perms['allow_gid']), + '$denycid' => json_encode($perms['deny_cid']), + '$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'), + '$jotnets' => $jotnets, + '$aclModalTitle' => L10n::t('Permissions'), + '$aclModalDismiss' => L10n::t('Close'), + '$features' => [ + 'aclautomention' => Feature::isEnabled($user['uid'], 'aclautomention') ? 'true' : 'false' + ], + ]); + + return $o; + } + + /** + * Searching for global contacts for autocompletion + * + * @brief Searching for global contacts for autocompletion + * @param string $search Name or part of a name or nick + * @param string $mode Search mode (e.g. "community") + * @return array with the search results + */ + public static function contactAutocomplete($search, $mode) + { + if ((Config::get('system', 'block_public')) && (!local_user()) && (!remote_user())) { + return []; + } + + // don't search if search term has less than 2 characters + if (!$search || mb_strlen($search) < 2) { + return []; + } + + if (substr($search, 0, 1) === '@') { + $search = substr($search, 1); + } + + // 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(); + $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, []); + } +} diff --git a/src/Core/Cache/DatabaseCacheDriver.php b/src/Core/Cache/DatabaseCacheDriver.php index 17ae310074..7248e0b349 100644 --- a/src/Core/Cache/DatabaseCacheDriver.php +++ b/src/Core/Cache/DatabaseCacheDriver.php @@ -1,56 +1,56 @@ - - */ -class DatabaseCacheDriver implements ICacheDriver -{ - public function get($key) - { - $cache = dba::selectFirst('cache', ['v'], ['`k` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]); - - if (DBM::is_result($cache)) { - $cached = $cache['v']; - $value = @unserialize($cached); - - // Only return a value if the serialized value is valid. - // We also check if the db entry is a serialized - // boolean 'false' value (which we want to return). - if ($cached === serialize(false) || $value !== false) { - return $value; - } - } - - return null; - } - - public function set($key, $value, $duration = Cache::MONTH) - { - $fields = [ - 'v' => serialize($value), - 'expires' => DateTimeFormat::utc('now + ' . $duration . ' seconds'), - 'updated' => DateTimeFormat::utcNow() - ]; - - return dba::update('cache', $fields, ['k' => $key], true); - } - - public function delete($key) - { - return dba::delete('cache', ['k' => $key]); - } - - public function clear() - { - return dba::delete('cache', ['`expires` < NOW()']); - } -} + + */ +class DatabaseCacheDriver implements ICacheDriver +{ + public function get($key) + { + $cache = dba::selectFirst('cache', ['v'], ['`k` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]); + + if (DBM::is_result($cache)) { + $cached = $cache['v']; + $value = @unserialize($cached); + + // Only return a value if the serialized value is valid. + // We also check if the db entry is a serialized + // boolean 'false' value (which we want to return). + if ($cached === serialize(false) || $value !== false) { + return $value; + } + } + + return null; + } + + public function set($key, $value, $duration = Cache::MONTH) + { + $fields = [ + 'v' => serialize($value), + 'expires' => DateTimeFormat::utc('now + ' . $duration . ' seconds'), + 'updated' => DateTimeFormat::utcNow() + ]; + + return dba::update('cache', $fields, ['k' => $key], true); + } + + public function delete($key) + { + return dba::delete('cache', ['k' => $key]); + } + + public function clear() + { + return dba::delete('cache', ['`expires` < NOW()']); + } +} diff --git a/src/Core/Cache/ICacheDriver.php b/src/Core/Cache/ICacheDriver.php index 9ed622693c..be896edf7f 100644 --- a/src/Core/Cache/ICacheDriver.php +++ b/src/Core/Cache/ICacheDriver.php @@ -1,50 +1,50 @@ - - */ -interface ICacheDriver -{ - /** - * Fetches cached data according to the key - * - * @param string $key The key to the cached data - * - * @return mixed Cached $value or "null" if not found - */ - public function get($key); - - /** - * Stores data in the cache identified by the key. The input $value can have multiple formats. - * - * @param string $key The cache key - * @param mixed $value The value to store - * @param integer $duration The cache lifespan, must be one of the Cache constants - * - * @return bool - */ - public function set($key, $value, $duration = Cache::MONTH); - - - /** - * Delete a key from the cache - * - * @param string $key - * - * @return bool - */ - public function delete($key); - - /** - * Remove outdated data from the cache - * - * @return bool - */ - public function clear(); -} + + */ +interface ICacheDriver +{ + /** + * Fetches cached data according to the key + * + * @param string $key The key to the cached data + * + * @return mixed Cached $value or "null" if not found + */ + public function get($key); + + /** + * Stores data in the cache identified by the key. The input $value can have multiple formats. + * + * @param string $key The cache key + * @param mixed $value The value to store + * @param integer $duration The cache lifespan, must be one of the Cache constants + * + * @return bool + */ + public function set($key, $value, $duration = Cache::MONTH); + + + /** + * Delete a key from the cache + * + * @param string $key + * + * @return bool + */ + public function delete($key); + + /** + * Remove outdated data from the cache + * + * @return bool + */ + public function clear(); +} diff --git a/src/Core/Cache/MemcacheCacheDriver.php b/src/Core/Cache/MemcacheCacheDriver.php index 563447ef1e..1537be25b2 100644 --- a/src/Core/Cache/MemcacheCacheDriver.php +++ b/src/Core/Cache/MemcacheCacheDriver.php @@ -1,77 +1,77 @@ - - */ -class MemcacheCacheDriver extends BaseObject implements ICacheDriver -{ - /** - * @var Memcache - */ - private $memcache; - - public function __construct($memcache_host, $memcache_port) - { - if (!class_exists('Memcache', false)) { - throw new \Exception('Memcache class isn\'t available'); - } - - $this->memcache = new \Memcache(); - - if (!$this->memcache->connect($memcache_host, $memcache_port)) { - throw new \Exception('Expected Memcache server at ' . $memcache_host . ':' . $memcache_port . ' isn\'t available'); - } - } - - public function get($key) - { - $return = null; - - // We fetch with the hostname as key to avoid problems with other applications - $cached = $this->memcache->get(self::getApp()->get_hostname() . ':' . $key); - - // @see http://php.net/manual/en/memcache.get.php#84275 - if (is_bool($cached) || is_double($cached) || is_long($cached)) { - return $return; - } - - $value = @unserialize($cached); - - // Only return a value if the serialized value is valid. - // We also check if the db entry is a serialized - // boolean 'false' value (which we want to return). - if ($cached === serialize(false) || $value !== false) { - $return = $value; - } - - return $return; - } - - public function set($key, $value, $duration = Cache::MONTH) - { - // We store with the hostname as key to avoid problems with other applications - return $this->memcache->set( - self::getApp()->get_hostname() . ":" . $key, - serialize($value), - MEMCACHE_COMPRESSED, - time() + $duration - ); - } - - public function delete($key) - { - return $this->memcache->delete($key); - } - - public function clear() - { - return true; - } -} + + */ +class MemcacheCacheDriver extends BaseObject implements ICacheDriver +{ + /** + * @var Memcache + */ + private $memcache; + + public function __construct($memcache_host, $memcache_port) + { + if (!class_exists('Memcache', false)) { + throw new \Exception('Memcache class isn\'t available'); + } + + $this->memcache = new \Memcache(); + + if (!$this->memcache->connect($memcache_host, $memcache_port)) { + throw new \Exception('Expected Memcache server at ' . $memcache_host . ':' . $memcache_port . ' isn\'t available'); + } + } + + public function get($key) + { + $return = null; + + // We fetch with the hostname as key to avoid problems with other applications + $cached = $this->memcache->get(self::getApp()->get_hostname() . ':' . $key); + + // @see http://php.net/manual/en/memcache.get.php#84275 + if (is_bool($cached) || is_double($cached) || is_long($cached)) { + return $return; + } + + $value = @unserialize($cached); + + // Only return a value if the serialized value is valid. + // We also check if the db entry is a serialized + // boolean 'false' value (which we want to return). + if ($cached === serialize(false) || $value !== false) { + $return = $value; + } + + return $return; + } + + public function set($key, $value, $duration = Cache::MONTH) + { + // We store with the hostname as key to avoid problems with other applications + return $this->memcache->set( + self::getApp()->get_hostname() . ":" . $key, + serialize($value), + MEMCACHE_COMPRESSED, + time() + $duration + ); + } + + public function delete($key) + { + return $this->memcache->delete($key); + } + + public function clear() + { + return true; + } +} diff --git a/src/Core/Cache/MemcachedCacheDriver.php b/src/Core/Cache/MemcachedCacheDriver.php index 1a8bdc9503..d6b8d4ad58 100644 --- a/src/Core/Cache/MemcachedCacheDriver.php +++ b/src/Core/Cache/MemcachedCacheDriver.php @@ -1,68 +1,68 @@ - - */ -class MemcachedCacheDriver extends BaseObject implements ICacheDriver -{ - /** - * @var Memcached - */ - private $memcached; - - public function __construct(array $memcached_hosts) - { - if (!class_exists('Memcached', false)) { - throw new \Exception('Memcached class isn\'t available'); - } - - $this->memcached = new \Memcached(); - - $this->memcached->addServers($memcached_hosts); - - if (count($this->memcached->getServerList()) == 0) { - throw new \Exception('Expected Memcached servers aren\'t available, config:' . var_export($memcached_hosts, true)); - } - } - - public function get($key) - { - $return = null; - - // We fetch with the hostname as key to avoid problems with other applications - $value = $this->memcached->get(self::getApp()->get_hostname() . ':' . $key); - - if ($this->memcached->getResultCode() === \Memcached::RES_SUCCESS) { - $return = $value; - } - - return $return; - } - - public function set($key, $value, $duration = Cache::MONTH) - { - // We store with the hostname as key to avoid problems with other applications - return $this->memcached->set( - self::getApp()->get_hostname() . ":" . $key, - $value, - time() + $duration - ); - } - - public function delete($key) - { - return $this->memcached->delete($key); - } - - public function clear() - { - return true; - } -} + + */ +class MemcachedCacheDriver extends BaseObject implements ICacheDriver +{ + /** + * @var Memcached + */ + private $memcached; + + public function __construct(array $memcached_hosts) + { + if (!class_exists('Memcached', false)) { + throw new \Exception('Memcached class isn\'t available'); + } + + $this->memcached = new \Memcached(); + + $this->memcached->addServers($memcached_hosts); + + if (count($this->memcached->getServerList()) == 0) { + throw new \Exception('Expected Memcached servers aren\'t available, config:' . var_export($memcached_hosts, true)); + } + } + + public function get($key) + { + $return = null; + + // We fetch with the hostname as key to avoid problems with other applications + $value = $this->memcached->get(self::getApp()->get_hostname() . ':' . $key); + + if ($this->memcached->getResultCode() === \Memcached::RES_SUCCESS) { + $return = $value; + } + + return $return; + } + + public function set($key, $value, $duration = Cache::MONTH) + { + // We store with the hostname as key to avoid problems with other applications + return $this->memcached->set( + self::getApp()->get_hostname() . ":" . $key, + $value, + time() + $duration + ); + } + + public function delete($key) + { + return $this->memcached->delete($key); + } + + public function clear() + { + return true; + } +} diff --git a/src/Core/Config/IConfigAdapter.php b/src/Core/Config/IConfigAdapter.php index ee5ca3ca54..d1bb600331 100644 --- a/src/Core/Config/IConfigAdapter.php +++ b/src/Core/Config/IConfigAdapter.php @@ -1,72 +1,72 @@ - - */ -interface IConfigAdapter -{ - /** - * @brief Loads all configuration values into a cached storage. - * - * All configuration values of the system are stored in global cache - * which is available under the global variable $a->config - * - * @param string $cat The category of the configuration values to load - * - * @return void - */ - public function load($cat = "config"); - - /** - * @brief Get a particular user's config variable given the category name - * ($family) and a key. - * - * Get a particular config value from the given category ($family) - * and the $key from a cached storage in $a->config[$uid]. - * $instore is only used by the set_config function - * to determine if the key already exists in the DB - * 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 - * to hit the DB again for this item. - * - * @param string $cat The category of the configuration value - * @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 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 - */ - public function get($cat, $k, $default_value = null, $refresh = false); - - /** - * @brief Sets a configuration value for system config - * - * Stores a config value ($value) in the category ($family) under the key ($key) - * for the user_id $uid. - * - * Note: Please do not store booleans - convert to 0/1 integer values! - * - * @param string $family The category of the configuration value - * @param string $key The configuration key to set - * @param mixed $value The value to store - * - * @return mixed Stored $value or false if the database update failed - */ - public function set($cat, $k, $value); - - /** - * @brief Deletes the given key from the system configuration. - * - * Removes the configured value from the stored cache in $a->config - * and removes it from the database. - * - * @param string $cat The category of the configuration value - * @param string $k The configuration key to delete - * - * @return mixed - */ - public function delete($cat, $k); -} + + */ +interface IConfigAdapter +{ + /** + * @brief Loads all configuration values into a cached storage. + * + * All configuration values of the system are stored in global cache + * which is available under the global variable $a->config + * + * @param string $cat The category of the configuration values to load + * + * @return void + */ + public function load($cat = "config"); + + /** + * @brief Get a particular user's config variable given the category name + * ($family) and a key. + * + * Get a particular config value from the given category ($family) + * and the $key from a cached storage in $a->config[$uid]. + * $instore is only used by the set_config function + * to determine if the key already exists in the DB + * 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 + * to hit the DB again for this item. + * + * @param string $cat The category of the configuration value + * @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 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 + */ + public function get($cat, $k, $default_value = null, $refresh = false); + + /** + * @brief Sets a configuration value for system config + * + * Stores a config value ($value) in the category ($family) under the key ($key) + * for the user_id $uid. + * + * Note: Please do not store booleans - convert to 0/1 integer values! + * + * @param string $family The category of the configuration value + * @param string $key The configuration key to set + * @param mixed $value The value to store + * + * @return mixed Stored $value or false if the database update failed + */ + public function set($cat, $k, $value); + + /** + * @brief Deletes the given key from the system configuration. + * + * Removes the configured value from the stored cache in $a->config + * and removes it from the database. + * + * @param string $cat The category of the configuration value + * @param string $k The configuration key to delete + * + * @return mixed + */ + public function delete($cat, $k); +} diff --git a/src/Core/Config/IPConfigAdapter.php b/src/Core/Config/IPConfigAdapter.php index f78654d39c..a0f0c9a94c 100644 --- a/src/Core/Config/IPConfigAdapter.php +++ b/src/Core/Config/IPConfigAdapter.php @@ -1,77 +1,77 @@ -config[$uid]. - * - * @param string $uid The user_id - * @param string $cat The category of the configuration value - * - * @return void - */ - public function load($uid, $cat); - - /** - * @brief Get a particular user's config variable given the category name - * ($family) and a key. - * - * Get a particular user's config value from the given category ($family) - * and the $key from a cached storage in $a->config[$uid]. - * - * @param string $uid The user_id - * @param string $cat The category of the configuration value - * @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 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 - */ - public function get($uid, $cat, $k, $default_value = null, $refresh = false); - - /** - * @brief Sets a configuration value for a user - * - * Stores a config value ($value) in the category ($family) under the key ($key) - * for the user_id $uid. - * - * @note Please do not store booleans - convert to 0/1 integer values! - * - * @param string $uid The user_id - * @param string $cat The category of the configuration value - * @param string $k The configuration key to set - * @param string $value The value to store - * - * @return mixed Stored $value or false - */ - public function set($uid, $cat, $k, $value); - - /** - * @brief Deletes the given key from the users's configuration. - * - * Removes the configured value from the stored cache in $a->config[$uid] - * and removes it from the database. - * - * @param string $uid The user_id - * @param string $cat The category of the configuration value - * @param string $k The configuration key to delete - * - * @return mixed - */ - public function delete($uid, $cat, $k); -} +config[$uid]. + * + * @param string $uid The user_id + * @param string $cat The category of the configuration value + * + * @return void + */ + public function load($uid, $cat); + + /** + * @brief Get a particular user's config variable given the category name + * ($family) and a key. + * + * Get a particular user's config value from the given category ($family) + * and the $key from a cached storage in $a->config[$uid]. + * + * @param string $uid The user_id + * @param string $cat The category of the configuration value + * @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 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 + */ + public function get($uid, $cat, $k, $default_value = null, $refresh = false); + + /** + * @brief Sets a configuration value for a user + * + * Stores a config value ($value) in the category ($family) under the key ($key) + * for the user_id $uid. + * + * @note Please do not store booleans - convert to 0/1 integer values! + * + * @param string $uid The user_id + * @param string $cat The category of the configuration value + * @param string $k The configuration key to set + * @param string $value The value to store + * + * @return mixed Stored $value or false + */ + public function set($uid, $cat, $k, $value); + + /** + * @brief Deletes the given key from the users's configuration. + * + * Removes the configured value from the stored cache in $a->config[$uid] + * and removes it from the database. + * + * @param string $uid The user_id + * @param string $cat The category of the configuration value + * @param string $k The configuration key to delete + * + * @return mixed + */ + public function delete($uid, $cat, $k); +} diff --git a/src/Core/Config/PreloadConfigAdapter.php b/src/Core/Config/PreloadConfigAdapter.php index f87b47f16c..204e462948 100644 --- a/src/Core/Config/PreloadConfigAdapter.php +++ b/src/Core/Config/PreloadConfigAdapter.php @@ -1,90 +1,90 @@ - - */ -class PreloadConfigAdapter extends BaseObject implements IConfigAdapter -{ - private $config_loaded = false; - - public function __construct() - { - $this->load(); - } - - public function load($family = 'config') - { - if ($this->config_loaded) { - return; - } - - $configs = dba::select('config', ['cat', 'v', 'k']); - while ($config = dba::fetch($configs)) { - self::getApp()->setConfigValue($config['cat'], $config['k'], $config['v']); - } - dba::close($configs); - - $this->config_loaded = true; - } - - public function get($cat, $k, $default_value = null, $refresh = false) - { - if ($refresh) { - $config = dba::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $k]); - if (DBM::is_result($config)) { - self::getApp()->setConfigValue($cat, $k, $config['v']); - } - } - - $return = self::getApp()->getConfigValue($cat, $k, $default_value); - - return $return; - } - - public function set($cat, $k, $value) - { - // We store our setting values as strings. - // So we have to do the conversion here so that the compare below works. - // The exception are array values. - $compare_value = !is_array($value) ? (string)$value : $value; - - if (self::getApp()->getConfigValue($cat, $k) === $compare_value) { - return true; - } - - self::getApp()->setConfigValue($cat, $k, $value); - - // manage array value - $dbvalue = is_array($value) ? serialize($value) : $value; - - $result = dba::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $k], true); - if (!$result) { - throw new Exception('Unable to store config value in [' . $cat . '][' . $k . ']'); - } - - return true; - } - - public function delete($cat, $k) - { - self::getApp()->deleteConfigValue($cat, $k); - - $result = dba::delete('config', ['cat' => $cat, 'k' => $k]); - - return $result; - } -} + + */ +class PreloadConfigAdapter extends BaseObject implements IConfigAdapter +{ + private $config_loaded = false; + + public function __construct() + { + $this->load(); + } + + public function load($family = 'config') + { + if ($this->config_loaded) { + return; + } + + $configs = dba::select('config', ['cat', 'v', 'k']); + while ($config = dba::fetch($configs)) { + self::getApp()->setConfigValue($config['cat'], $config['k'], $config['v']); + } + dba::close($configs); + + $this->config_loaded = true; + } + + public function get($cat, $k, $default_value = null, $refresh = false) + { + if ($refresh) { + $config = dba::selectFirst('config', ['v'], ['cat' => $cat, 'k' => $k]); + if (DBM::is_result($config)) { + self::getApp()->setConfigValue($cat, $k, $config['v']); + } + } + + $return = self::getApp()->getConfigValue($cat, $k, $default_value); + + return $return; + } + + public function set($cat, $k, $value) + { + // We store our setting values as strings. + // So we have to do the conversion here so that the compare below works. + // The exception are array values. + $compare_value = !is_array($value) ? (string)$value : $value; + + if (self::getApp()->getConfigValue($cat, $k) === $compare_value) { + return true; + } + + self::getApp()->setConfigValue($cat, $k, $value); + + // manage array value + $dbvalue = is_array($value) ? serialize($value) : $value; + + $result = dba::update('config', ['v' => $dbvalue], ['cat' => $cat, 'k' => $k], true); + if (!$result) { + throw new Exception('Unable to store config value in [' . $cat . '][' . $k . ']'); + } + + return true; + } + + public function delete($cat, $k) + { + self::getApp()->deleteConfigValue($cat, $k); + + $result = dba::delete('config', ['cat' => $cat, 'k' => $k]); + + return $result; + } +} diff --git a/src/Core/Config/PreloadPConfigAdapter.php b/src/Core/Config/PreloadPConfigAdapter.php index d235410339..af77598389 100644 --- a/src/Core/Config/PreloadPConfigAdapter.php +++ b/src/Core/Config/PreloadPConfigAdapter.php @@ -1,92 +1,92 @@ - - */ -class PreloadPConfigAdapter extends BaseObject implements IPConfigAdapter -{ - private $config_loaded = false; - - public function __construct($uid) - { - $this->load($uid, 'config'); - } - - public function load($uid, $family) - { - if ($this->config_loaded) { - return; - } - - $pconfigs = dba::select('pconfig', ['cat', 'v', 'k'], ['uid' => $uid]); - while ($pconfig = dba::fetch($pconfigs)) { - self::getApp()->setPConfigValue($uid, $pconfig['cat'], $pconfig['k'], $pconfig['v']); - } - dba::close($pconfigs); - - $this->config_loaded = true; - } - - public function get($uid, $cat, $k, $default_value = null, $refresh = false) - { - if ($refresh) { - $config = dba::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $k]); - if (DBM::is_result($config)) { - self::getApp()->setPConfigValue($uid, $cat, $k, $config['v']); - } else { - self::getApp()->deletePConfigValue($uid, $cat, $k); - } - } - - $return = self::getApp()->getPConfigValue($uid, $cat, $k, $default_value); - - return $return; - } - - public function set($uid, $cat, $k, $value) - { - // We store our setting values as strings. - // So we have to do the conversion here so that the compare below works. - // The exception are array values. - $compare_value = !is_array($value) ? (string)$value : $value; - - if (self::getApp()->getPConfigValue($uid, $cat, $k) === $compare_value) { - return true; - } - - self::getApp()->setPConfigValue($uid, $cat, $k, $value); - - // manage array value - $dbvalue = is_array($value) ? serialize($value) : $value; - - $result = dba::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $k], true); - if (!$result) { - throw new Exception('Unable to store config value in [' . $uid . '][' . $cat . '][' . $k . ']'); - } - - return true; - } - - public function delete($uid, $cat, $k) - { - self::getApp()->deletePConfigValue($uid, $cat, $k); - - $result = dba::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $k]); - - return $result; - } -} + + */ +class PreloadPConfigAdapter extends BaseObject implements IPConfigAdapter +{ + private $config_loaded = false; + + public function __construct($uid) + { + $this->load($uid, 'config'); + } + + public function load($uid, $family) + { + if ($this->config_loaded) { + return; + } + + $pconfigs = dba::select('pconfig', ['cat', 'v', 'k'], ['uid' => $uid]); + while ($pconfig = dba::fetch($pconfigs)) { + self::getApp()->setPConfigValue($uid, $pconfig['cat'], $pconfig['k'], $pconfig['v']); + } + dba::close($pconfigs); + + $this->config_loaded = true; + } + + public function get($uid, $cat, $k, $default_value = null, $refresh = false) + { + if ($refresh) { + $config = dba::selectFirst('pconfig', ['v'], ['uid' => $uid, 'cat' => $cat, 'k' => $k]); + if (DBM::is_result($config)) { + self::getApp()->setPConfigValue($uid, $cat, $k, $config['v']); + } else { + self::getApp()->deletePConfigValue($uid, $cat, $k); + } + } + + $return = self::getApp()->getPConfigValue($uid, $cat, $k, $default_value); + + return $return; + } + + public function set($uid, $cat, $k, $value) + { + // We store our setting values as strings. + // So we have to do the conversion here so that the compare below works. + // The exception are array values. + $compare_value = !is_array($value) ? (string)$value : $value; + + if (self::getApp()->getPConfigValue($uid, $cat, $k) === $compare_value) { + return true; + } + + self::getApp()->setPConfigValue($uid, $cat, $k, $value); + + // manage array value + $dbvalue = is_array($value) ? serialize($value) : $value; + + $result = dba::update('pconfig', ['v' => $dbvalue], ['uid' => $uid, 'cat' => $cat, 'k' => $k], true); + if (!$result) { + throw new Exception('Unable to store config value in [' . $uid . '][' . $cat . '][' . $k . ']'); + } + + return true; + } + + public function delete($uid, $cat, $k) + { + self::getApp()->deletePConfigValue($uid, $cat, $k); + + $result = dba::delete('pconfig', ['uid' => $uid, 'cat' => $cat, 'k' => $k]); + + return $result; + } +} diff --git a/src/Core/Console.php b/src/Core/Console.php index 63aca9301c..eb6e08057a 100644 --- a/src/Core/Console.php +++ b/src/Core/Console.php @@ -1,123 +1,123 @@ - - */ -class Console extends \Asika\SimpleConsole\Console -{ - // Disables the default help handling - protected $helpOptions = []; - protected $customHelpOptions = ['h', 'help', '?']; - - protected $subConsoles = [ - 'config' => __NAMESPACE__ . '\Console\Config', - 'createdoxygen' => __NAMESPACE__ . '\Console\CreateDoxygen', - 'docbloxerrorchecker' => __NAMESPACE__ . '\Console\DocBloxErrorChecker', - 'dbstructure' => __NAMESPACE__ . '\Console\DatabaseStructure', - 'extract' => __NAMESPACE__ . '\Console\Extract', - 'globalcommunityblock' => __NAMESPACE__ . '\Console\GlobalCommunityBlock', - 'globalcommunitysilence' => __NAMESPACE__ . '\Console\GlobalCommunitySilence', - 'maintenance' => __NAMESPACE__ . '\Console\Maintenance', - 'php2po' => __NAMESPACE__ . '\Console\PhpToPo', - 'po2php' => __NAMESPACE__ . '\Console\PoToPhp', - 'typo' => __NAMESPACE__ . '\Console\Typo', - ]; - - protected function getHelp() - { - $help = << [] [-v] - -Commands: - config Edit site config - createdoxygen Generate Doxygen headers - dbstructure Do database updates - docbloxerrorchecker Check the file tree for DocBlox errors - extract Generate translation string file for the Friendica project (deprecated) - globalcommunityblock Block remote profile from interacting with this node - globalcommunitysilence Silence remote profile from global community page - help Show help about a command, e.g (bin/console help config) - maintenance Set maintenance mode for this node - php2po Generate a messages.po file from a strings.php file - po2php Generate a strings.php file from a messages.po file - typo Checks for parse errors in Friendica files - -Options: - -h|--help|-? Show help information - -v Show more debug information. -HELP; - return $help; - } - - protected function doExecute() - { - if ($this->getOption('v')) { - $this->out('Executable: ' . $this->executable); - $this->out('Arguments: ' . var_export($this->args, true)); - $this->out('Options: ' . var_export($this->options, true)); - } - - $showHelp = false; - $subHelp = false; - $command = null; - - if ($this->getOption('version')) { - $this->out('Friendica Console version ' . FRIENDICA_VERSION); - - return 0; - } elseif ((count($this->options) === 0 || $this->getOption($this->customHelpOptions) === true || $this->getOption($this->customHelpOptions) === 1) && count($this->args) === 0 - ) { - $showHelp = true; - } elseif (count($this->args) >= 2 && $this->getArgument(0) == 'help') { - $command = $this->getArgument(1); - $subHelp = true; - array_shift($this->args); - array_shift($this->args); - } elseif (count($this->args) >= 1) { - $command = $this->getArgument(0); - array_shift($this->args); - } - - if (is_null($command)) { - $this->out($this->getHelp()); - return 0; - } - - $console = $this->getSubConsole($command); - - if ($subHelp) { - $console->setOption($this->customHelpOptions, true); - } - - return $console->execute(); - } - - private function getSubConsole($command) - { - if ($this->getOption('v')) { - $this->out('Command: ' . $command); - } - - if (!isset($this->subConsoles[$command])) { - throw new \Asika\SimpleConsole\CommandArgsException('Command ' . $command . ' doesn\'t exist'); - } - - $subargs = $this->args; - array_unshift($subargs, $this->executable); - - $className = $this->subConsoles[$command]; - - $subconsole = new $className($subargs); - - foreach ($this->options as $name => $value) { - $subconsole->setOption($name, $value); - } - - return $subconsole; - } - -} + + */ +class Console extends \Asika\SimpleConsole\Console +{ + // Disables the default help handling + protected $helpOptions = []; + protected $customHelpOptions = ['h', 'help', '?']; + + protected $subConsoles = [ + 'config' => __NAMESPACE__ . '\Console\Config', + 'createdoxygen' => __NAMESPACE__ . '\Console\CreateDoxygen', + 'docbloxerrorchecker' => __NAMESPACE__ . '\Console\DocBloxErrorChecker', + 'dbstructure' => __NAMESPACE__ . '\Console\DatabaseStructure', + 'extract' => __NAMESPACE__ . '\Console\Extract', + 'globalcommunityblock' => __NAMESPACE__ . '\Console\GlobalCommunityBlock', + 'globalcommunitysilence' => __NAMESPACE__ . '\Console\GlobalCommunitySilence', + 'maintenance' => __NAMESPACE__ . '\Console\Maintenance', + 'php2po' => __NAMESPACE__ . '\Console\PhpToPo', + 'po2php' => __NAMESPACE__ . '\Console\PoToPhp', + 'typo' => __NAMESPACE__ . '\Console\Typo', + ]; + + protected function getHelp() + { + $help = << [] [-v] + +Commands: + config Edit site config + createdoxygen Generate Doxygen headers + dbstructure Do database updates + docbloxerrorchecker Check the file tree for DocBlox errors + extract Generate translation string file for the Friendica project (deprecated) + globalcommunityblock Block remote profile from interacting with this node + globalcommunitysilence Silence remote profile from global community page + help Show help about a command, e.g (bin/console help config) + maintenance Set maintenance mode for this node + php2po Generate a messages.po file from a strings.php file + po2php Generate a strings.php file from a messages.po file + typo Checks for parse errors in Friendica files + +Options: + -h|--help|-? Show help information + -v Show more debug information. +HELP; + return $help; + } + + protected function doExecute() + { + if ($this->getOption('v')) { + $this->out('Executable: ' . $this->executable); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + $showHelp = false; + $subHelp = false; + $command = null; + + if ($this->getOption('version')) { + $this->out('Friendica Console version ' . FRIENDICA_VERSION); + + return 0; + } elseif ((count($this->options) === 0 || $this->getOption($this->customHelpOptions) === true || $this->getOption($this->customHelpOptions) === 1) && count($this->args) === 0 + ) { + $showHelp = true; + } elseif (count($this->args) >= 2 && $this->getArgument(0) == 'help') { + $command = $this->getArgument(1); + $subHelp = true; + array_shift($this->args); + array_shift($this->args); + } elseif (count($this->args) >= 1) { + $command = $this->getArgument(0); + array_shift($this->args); + } + + if (is_null($command)) { + $this->out($this->getHelp()); + return 0; + } + + $console = $this->getSubConsole($command); + + if ($subHelp) { + $console->setOption($this->customHelpOptions, true); + } + + return $console->execute(); + } + + private function getSubConsole($command) + { + if ($this->getOption('v')) { + $this->out('Command: ' . $command); + } + + if (!isset($this->subConsoles[$command])) { + throw new \Asika\SimpleConsole\CommandArgsException('Command ' . $command . ' doesn\'t exist'); + } + + $subargs = $this->args; + array_unshift($subargs, $this->executable); + + $className = $this->subConsoles[$command]; + + $subconsole = new $className($subargs); + + foreach ($this->options as $name => $value) { + $subconsole->setOption($name, $value); + } + + return $subconsole; + } + +} diff --git a/src/Core/Console/Config.php b/src/Core/Console/Config.php index a199fb3afb..9905e473c7 100644 --- a/src/Core/Console/Config.php +++ b/src/Core/Console/Config.php @@ -1,135 +1,135 @@ - - */ -class Config extends \Asika\SimpleConsole\Console -{ - protected $helpOptions = ['h', 'help', '?']; - - protected function getHelp() - { - $help = << [-h|--help|-?] [-v] - bin/console config [-h|--help|-?] [-v] - bin/console config [-h|--help|-?] [-v] - -Description - bin/console config - Lists all config values - - bin/console config - Lists all config values in the provided category - - bin/console config - Shows the value of the provided key in the category - - bin/console config - Sets the value of the provided key in the category - -Notes: - Setting config entries which are manually set in .htconfig.php may result in - conflict between database settings and the manual startup settings. - -Options - -h|--help|-? Show help information - -v Show more debug information. -HELP; - return $help; - } - - protected function doExecute() - { - if ($this->getOption('v')) { - $this->out('Executable: ' . $this->executable); - $this->out('Class: ' . __CLASS__); - $this->out('Arguments: ' . var_export($this->args, true)); - $this->out('Options: ' . var_export($this->options, true)); - } - - if (count($this->args) > 3) { - throw new CommandArgsException('Too many arguments'); - } - - require_once '.htconfig.php'; - $result = dba::connect($db_host, $db_user, $db_pass, $db_data); - unset($db_host, $db_user, $db_pass, $db_data); - - if (!$result) { - throw new \RuntimeException('Unable to connect to database'); - } - - if (count($this->args) == 3) { - 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->getArgument(1))); - } - - if (count($this->args) == 2) { - $this->out("config[{$this->getArgument(0)}][{$this->getArgument(1)}] = " . Core\Config::get($this->getArgument(0), - $this->getArgument(1))); - } - - if (count($this->args) == 1) { - Core\Config::load($this->getArgument(0)); - - $a = get_app(); - if (!is_null($a->config[$this->getArgument(0)])) { - foreach ($a->config[$this->getArgument(0)] as $k => $x) { - $this->out("config[{$this->getArgument(0)}][{$k}] = " . $x); - } - } else { - $this->out('Config section ' . $this->getArgument(0) . ' returned nothing'); - } - } - - if (count($this->args) == 0) { - $configs = dba::select('config'); - foreach ($configs as $config) { - $this->out("config[{$config['cat']}][{$config['k']}] = " . $config['v']); - } - } - - return 0; - } - -} + + */ +class Config extends \Asika\SimpleConsole\Console +{ + protected $helpOptions = ['h', 'help', '?']; + + protected function getHelp() + { + $help = << [-h|--help|-?] [-v] + bin/console config [-h|--help|-?] [-v] + bin/console config [-h|--help|-?] [-v] + +Description + bin/console config + Lists all config values + + bin/console config + Lists all config values in the provided category + + bin/console config + Shows the value of the provided key in the category + + bin/console config + Sets the value of the provided key in the category + +Notes: + Setting config entries which are manually set in .htconfig.php may result in + conflict between database settings and the manual startup settings. + +Options + -h|--help|-? Show help information + -v Show more debug information. +HELP; + return $help; + } + + protected function doExecute() + { + if ($this->getOption('v')) { + $this->out('Executable: ' . $this->executable); + $this->out('Class: ' . __CLASS__); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + if (count($this->args) > 3) { + throw new CommandArgsException('Too many arguments'); + } + + require_once '.htconfig.php'; + $result = dba::connect($db_host, $db_user, $db_pass, $db_data); + unset($db_host, $db_user, $db_pass, $db_data); + + if (!$result) { + throw new \RuntimeException('Unable to connect to database'); + } + + if (count($this->args) == 3) { + 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->getArgument(1))); + } + + if (count($this->args) == 2) { + $this->out("config[{$this->getArgument(0)}][{$this->getArgument(1)}] = " . Core\Config::get($this->getArgument(0), + $this->getArgument(1))); + } + + if (count($this->args) == 1) { + Core\Config::load($this->getArgument(0)); + + $a = get_app(); + if (!is_null($a->config[$this->getArgument(0)])) { + foreach ($a->config[$this->getArgument(0)] as $k => $x) { + $this->out("config[{$this->getArgument(0)}][{$k}] = " . $x); + } + } else { + $this->out('Config section ' . $this->getArgument(0) . ' returned nothing'); + } + } + + if (count($this->args) == 0) { + $configs = dba::select('config'); + foreach ($configs as $config) { + $this->out("config[{$config['cat']}][{$config['k']}] = " . $config['v']); + } + } + + return 0; + } + +} diff --git a/src/Core/Console/CreateDoxygen.php b/src/Core/Console/CreateDoxygen.php index 17da9922ee..b60116db3c 100644 --- a/src/Core/Console/CreateDoxygen.php +++ b/src/Core/Console/CreateDoxygen.php @@ -1,148 +1,148 @@ - - */ -class CreateDoxygen extends \Asika\SimpleConsole\Console -{ - protected $helpOptions = ['h', 'help', '?']; - - protected function getHelp() - { - $help = << [-h|--help|-?] [-v] - -Description - Outputs the provided file with added Doxygen headers to functions - -Options - -h|--help|-? Show help information - -v Show more debug information. -HELP; - return $help; - } - - protected function doExecute() - { - if ($this->getOption('v')) { - $this->out('Class: ' . __CLASS__); - $this->out('Arguments: ' . var_export($this->args, true)); - $this->out('Options: ' . var_export($this->options, true)); - } - - if (count($this->args) == 0) { - $this->out($this->getHelp()); - return 0; - } - - if (count($this->args) > 1) { - throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); - } - - $file = $this->getArgument(0); - if (!file_exists($file)) { - throw new \RuntimeException('Unable to find specified file.'); - } - - $data = file_get_contents($file); - - $lines = explode("\n", $data); - - $previous = ""; - - foreach ($lines AS $line) { - $line = rtrim(trim($line, "\r")); - - if (strstr(strtolower($line), "function")) { - $detect = strtolower(trim($line)); - $detect = implode(" ", explode(" ", $detect)); - - $found = false; - - if (substr($detect, 0, 9) == "function ") { - $found = true; - } - - if (substr($detect, 0, 19) == "protected function ") { - $found = true; - } - - if (substr($detect, 0, 17) == "private function ") { - $found = true; - } - - if (substr($detect, 0, 23) == "public static function ") { - $found = true; - } - - if (substr($detect, 0, 24) == "private static function ") { - $found = true; - } - - if (substr($detect, 0, 10) == "function (") { - $found = false; - } - - if ($found && ( trim($previous) == "*/")) { - $found = false; - } - - if ($found) { - $this->out($this->addDocumentation($line)); - } - } - $this->out($line); - $previous = $line; - } - - return 0; - } - - /** - * @brief Adds a doxygen header - * - * @param string $line The current line of the document - * - * @return string added doxygen header - */ - private function addDocumentation($line) - { - $trimmed = ltrim($line); - $length = strlen($line) - strlen($trimmed); - $space = substr($line, 0, $length); - - $block = $space . "/**\n" . - $space . " * @brief \n" . - $space . " *\n"; /**/ - - - $left = strpos($line, "("); - $line = substr($line, $left + 1); - - $right = strpos($line, ")"); - $line = trim(substr($line, 0, $right)); - - if ($line != "") { - $parameters = explode(",", $line); - foreach ($parameters AS $parameter) { - $parameter = trim($parameter); - $splitted = explode("=", $parameter); - - $block .= $space . " * @param " . trim($splitted[0], "& ") . "\n"; - } - if (count($parameters) > 0) $block .= $space . " *\n"; - } - - $block .= $space . " * @return \n" . - $space . " */\n"; - - return $block; - } - -} + + */ +class CreateDoxygen extends \Asika\SimpleConsole\Console +{ + protected $helpOptions = ['h', 'help', '?']; + + protected function getHelp() + { + $help = << [-h|--help|-?] [-v] + +Description + Outputs the provided file with added Doxygen headers to functions + +Options + -h|--help|-? Show help information + -v Show more debug information. +HELP; + return $help; + } + + protected function doExecute() + { + if ($this->getOption('v')) { + $this->out('Class: ' . __CLASS__); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + if (count($this->args) == 0) { + $this->out($this->getHelp()); + return 0; + } + + if (count($this->args) > 1) { + throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); + } + + $file = $this->getArgument(0); + if (!file_exists($file)) { + throw new \RuntimeException('Unable to find specified file.'); + } + + $data = file_get_contents($file); + + $lines = explode("\n", $data); + + $previous = ""; + + foreach ($lines AS $line) { + $line = rtrim(trim($line, "\r")); + + if (strstr(strtolower($line), "function")) { + $detect = strtolower(trim($line)); + $detect = implode(" ", explode(" ", $detect)); + + $found = false; + + if (substr($detect, 0, 9) == "function ") { + $found = true; + } + + if (substr($detect, 0, 19) == "protected function ") { + $found = true; + } + + if (substr($detect, 0, 17) == "private function ") { + $found = true; + } + + if (substr($detect, 0, 23) == "public static function ") { + $found = true; + } + + if (substr($detect, 0, 24) == "private static function ") { + $found = true; + } + + if (substr($detect, 0, 10) == "function (") { + $found = false; + } + + if ($found && ( trim($previous) == "*/")) { + $found = false; + } + + if ($found) { + $this->out($this->addDocumentation($line)); + } + } + $this->out($line); + $previous = $line; + } + + return 0; + } + + /** + * @brief Adds a doxygen header + * + * @param string $line The current line of the document + * + * @return string added doxygen header + */ + private function addDocumentation($line) + { + $trimmed = ltrim($line); + $length = strlen($line) - strlen($trimmed); + $space = substr($line, 0, $length); + + $block = $space . "/**\n" . + $space . " * @brief \n" . + $space . " *\n"; /**/ + + + $left = strpos($line, "("); + $line = substr($line, $left + 1); + + $right = strpos($line, ")"); + $line = trim(substr($line, 0, $right)); + + if ($line != "") { + $parameters = explode(",", $line); + foreach ($parameters AS $parameter) { + $parameter = trim($parameter); + $splitted = explode("=", $parameter); + + $block .= $space . " * @param " . trim($splitted[0], "& ") . "\n"; + } + if (count($parameters) > 0) $block .= $space . " *\n"; + } + + $block .= $space . " * @return \n" . + $space . " */\n"; + + return $block; + } + +} diff --git a/src/Core/Console/DatabaseStructure.php b/src/Core/Console/DatabaseStructure.php index 709b9724e8..4e64dc6121 100644 --- a/src/Core/Console/DatabaseStructure.php +++ b/src/Core/Console/DatabaseStructure.php @@ -1,110 +1,110 @@ - - */ -class DatabaseStructure extends \Asika\SimpleConsole\Console -{ - protected $helpOptions = ['h', 'help', '?']; - - protected function getHelp() - { - $help = << [-h|--help|-?] [-v] - -Commands - dryrun Show database update schema queries without running them - update Update database schema - dumpsql Dump database schema - toinnodb Convert all tables from MyISAM to InnoDB - -Options - -h|--help|-? Show help information - -v Show more debug information. -HELP; - return $help; - } - - protected function doExecute() - { - if ($this->getOption('v')) { - $this->out('Class: ' . __CLASS__); - $this->out('Arguments: ' . var_export($this->args, true)); - $this->out('Options: ' . var_export($this->options, true)); - } - - if (count($this->args) == 0) { - $this->out($this->getHelp()); - return 0; - } - - if (count($this->args) > 1) { - throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); - } - - require_once '.htconfig.php'; - $result = \dba::connect($db_host, $db_user, $db_pass, $db_data); - unset($db_host, $db_user, $db_pass, $db_data); - - if (!$result) { - throw new \RuntimeException('Unable to connect to database'); - } - - Core\Config::load(); - - switch ($this->getArgument(0)) { - case "dryrun": - $output = DBStructure::update(true, false); - break; - case "update": - $output = DBStructure::update(true, true); - - $build = Core\Config::get('system', 'build'); - if (empty($build)) { - Core\Config::set('system', 'build', DB_UPDATE_VERSION); - $build = DB_UPDATE_VERSION; - } - - $stored = intval($build); - $current = intval(DB_UPDATE_VERSION); - - // run any left update_nnnn functions in update.php - for ($x = $stored; $x < $current; $x ++) { - $r = run_update_function($x); - if (!$r) { - break; - } - } - - Core\Config::set('system', 'build', DB_UPDATE_VERSION); - break; - case "dumpsql": - ob_start(); - DBStructure::printStructure(); - $output = ob_get_clean(); - break; - case "toinnodb": - ob_start(); - DBStructure::convertToInnoDB(); - $output = ob_get_clean(); - break; - } - - $this->out($output); - - return 0; - } - -} + + */ +class DatabaseStructure extends \Asika\SimpleConsole\Console +{ + protected $helpOptions = ['h', 'help', '?']; + + protected function getHelp() + { + $help = << [-h|--help|-?] [-v] + +Commands + dryrun Show database update schema queries without running them + update Update database schema + dumpsql Dump database schema + toinnodb Convert all tables from MyISAM to InnoDB + +Options + -h|--help|-? Show help information + -v Show more debug information. +HELP; + return $help; + } + + protected function doExecute() + { + if ($this->getOption('v')) { + $this->out('Class: ' . __CLASS__); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + if (count($this->args) == 0) { + $this->out($this->getHelp()); + return 0; + } + + if (count($this->args) > 1) { + throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); + } + + require_once '.htconfig.php'; + $result = \dba::connect($db_host, $db_user, $db_pass, $db_data); + unset($db_host, $db_user, $db_pass, $db_data); + + if (!$result) { + throw new \RuntimeException('Unable to connect to database'); + } + + Core\Config::load(); + + switch ($this->getArgument(0)) { + case "dryrun": + $output = DBStructure::update(true, false); + break; + case "update": + $output = DBStructure::update(true, true); + + $build = Core\Config::get('system', 'build'); + if (empty($build)) { + Core\Config::set('system', 'build', DB_UPDATE_VERSION); + $build = DB_UPDATE_VERSION; + } + + $stored = intval($build); + $current = intval(DB_UPDATE_VERSION); + + // run any left update_nnnn functions in update.php + for ($x = $stored; $x < $current; $x ++) { + $r = run_update_function($x); + if (!$r) { + break; + } + } + + Core\Config::set('system', 'build', DB_UPDATE_VERSION); + break; + case "dumpsql": + ob_start(); + DBStructure::printStructure(); + $output = ob_get_clean(); + break; + case "toinnodb": + ob_start(); + DBStructure::convertToInnoDB(); + $output = ob_get_clean(); + break; + } + + $this->out($output); + + return 0; + } + +} diff --git a/src/Core/Console/DocBloxErrorChecker.php b/src/Core/Console/DocBloxErrorChecker.php index 922a5ed056..50d44d114d 100644 --- a/src/Core/Console/DocBloxErrorChecker.php +++ b/src/Core/Console/DocBloxErrorChecker.php @@ -1,192 +1,192 @@ - - */ -class DocBloxErrorChecker extends \Asika\SimpleConsole\Console -{ - - protected $helpOptions = ['h', 'help', '?']; - - protected function getHelp() - { - $help = <<getOption('v')) { - $this->out('Class: ' . __CLASS__); - $this->out('Arguments: ' . var_export($this->args, true)); - $this->out('Options: ' . var_export($this->options, true)); - } - - if (count($this->args) > 0) { - throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); - } - - if (!$this->commandExists('docblox')) { - throw new \RuntimeException('DocBlox isn\'t available.'); - } - - //return from util folder to frindica base dir - $dir = get_app()->get_basepath(); - - //stack for dirs to search - $dirstack = []; - //list of source files - $filelist = []; - - //loop over all files in $dir - while ($dh = opendir($dir)) { - while ($file = readdir($dh)) { - if (is_dir($dir . "/" . $file)) { - //add to directory stack - if (strpos($file, '.') !== 0) { - array_push($dirstack, $dir . "/" . $file); - $this->out('dir ' . $dir . '/' . $file); - } - } else { - //test if it is a source file and add to filelist - if (substr($file, strlen($file) - 4) == ".php") { - array_push($filelist, $dir . "/" . $file); - $this->out($dir . '/' . $file); - } - } - } - //look at the next dir - $dir = array_pop($dirstack); - } - - //check the entire set - if ($this->runs($filelist)) { - throw new \RuntimeException("I can not detect a problem."); - } - - //check half of the set and discard if that half is okay - $res = $filelist; - $i = count($res); - do { - $this->out($i . '/' . count($filelist) . ' elements remaining.'); - $res = $this->reduce($res, count($res) / 2); - shuffle($res); - $i = count($res); - } while (count($res) < $i); - - //check one file after another - $needed = []; - - while (count($res) != 0) { - $file = array_pop($res); - - if ($this->runs(array_merge($res, $needed))) { - $this->out('needs: ' . $file . ' and file count ' . count($needed)); - array_push($needed, $file); - } - } - - $this->out('Smallest Set is: ' . $this->namesList($needed) . ' with ' . count($needed) . ' files. '); - - return 0; - } - - private function commandExists($command) - { - $prefix = strpos(strtolower(PHP_OS),'win') > -1 ? 'where' : 'which'; - exec("{$prefix} {$command}", $output, $returnVal); - return $returnVal === 0; - } - - /** - * This function generates a comma separated list of file names. - * - * @package util - * - * @param array $fileset Set of file names - * - * @return string comma-separated list of the file names - */ - private function namesList($fileset) - { - return implode(',', $fileset); - } - - /** - * This functions runs phpdoc on the provided list of files - * @package util - * - * @param array $fileset Set of filenames - * - * @return bool true, if that set can be built - */ - private function runs($fileset) - { - $fsParam = $this->namesList($fileset); - $this->exec('docblox -t phpdoc_out -f ' . $fsParam); - if (file_exists("phpdoc_out/index.html")) { - $this->out('Subset ' . $fsParam . ' is okay.'); - $this->exec('rm -r phpdoc_out'); - return true; - } else { - $this->out('Subset ' . $fsParam . ' failed.'); - return false; - } - } - - /** - * 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. - * - * In that version, it does not necessarily generate the smallest set, because it may not alter the elements order enough. - * - * @package util - * - * @param array $fileset set of filenames - * @param int $ps number of files in subsets - * - * @return array a part of $fileset, that crashes - */ - private function reduce($fileset, $ps) - { - //split array... - $parts = array_chunk($fileset, $ps); - //filter working subsets... - $parts = array_filter($parts, [$this, 'runs']); - //melt remaining parts together - if (is_array($parts)) { - return array_reduce($parts, "array_merge", []); - } - return []; - } - -} + + */ +class DocBloxErrorChecker extends \Asika\SimpleConsole\Console +{ + + protected $helpOptions = ['h', 'help', '?']; + + protected function getHelp() + { + $help = <<getOption('v')) { + $this->out('Class: ' . __CLASS__); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + if (count($this->args) > 0) { + throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); + } + + if (!$this->commandExists('docblox')) { + throw new \RuntimeException('DocBlox isn\'t available.'); + } + + //return from util folder to frindica base dir + $dir = get_app()->get_basepath(); + + //stack for dirs to search + $dirstack = []; + //list of source files + $filelist = []; + + //loop over all files in $dir + while ($dh = opendir($dir)) { + while ($file = readdir($dh)) { + if (is_dir($dir . "/" . $file)) { + //add to directory stack + if (strpos($file, '.') !== 0) { + array_push($dirstack, $dir . "/" . $file); + $this->out('dir ' . $dir . '/' . $file); + } + } else { + //test if it is a source file and add to filelist + if (substr($file, strlen($file) - 4) == ".php") { + array_push($filelist, $dir . "/" . $file); + $this->out($dir . '/' . $file); + } + } + } + //look at the next dir + $dir = array_pop($dirstack); + } + + //check the entire set + if ($this->runs($filelist)) { + throw new \RuntimeException("I can not detect a problem."); + } + + //check half of the set and discard if that half is okay + $res = $filelist; + $i = count($res); + do { + $this->out($i . '/' . count($filelist) . ' elements remaining.'); + $res = $this->reduce($res, count($res) / 2); + shuffle($res); + $i = count($res); + } while (count($res) < $i); + + //check one file after another + $needed = []; + + while (count($res) != 0) { + $file = array_pop($res); + + if ($this->runs(array_merge($res, $needed))) { + $this->out('needs: ' . $file . ' and file count ' . count($needed)); + array_push($needed, $file); + } + } + + $this->out('Smallest Set is: ' . $this->namesList($needed) . ' with ' . count($needed) . ' files. '); + + return 0; + } + + private function commandExists($command) + { + $prefix = strpos(strtolower(PHP_OS),'win') > -1 ? 'where' : 'which'; + exec("{$prefix} {$command}", $output, $returnVal); + return $returnVal === 0; + } + + /** + * This function generates a comma separated list of file names. + * + * @package util + * + * @param array $fileset Set of file names + * + * @return string comma-separated list of the file names + */ + private function namesList($fileset) + { + return implode(',', $fileset); + } + + /** + * This functions runs phpdoc on the provided list of files + * @package util + * + * @param array $fileset Set of filenames + * + * @return bool true, if that set can be built + */ + private function runs($fileset) + { + $fsParam = $this->namesList($fileset); + $this->exec('docblox -t phpdoc_out -f ' . $fsParam); + if (file_exists("phpdoc_out/index.html")) { + $this->out('Subset ' . $fsParam . ' is okay.'); + $this->exec('rm -r phpdoc_out'); + return true; + } else { + $this->out('Subset ' . $fsParam . ' failed.'); + return false; + } + } + + /** + * 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. + * + * In that version, it does not necessarily generate the smallest set, because it may not alter the elements order enough. + * + * @package util + * + * @param array $fileset set of filenames + * @param int $ps number of files in subsets + * + * @return array a part of $fileset, that crashes + */ + private function reduce($fileset, $ps) + { + //split array... + $parts = array_chunk($fileset, $ps); + //filter working subsets... + $parts = array_filter($parts, [$this, 'runs']); + //melt remaining parts together + if (is_array($parts)) { + return array_reduce($parts, "array_merge", []); + } + return []; + } + +} diff --git a/src/Core/Console/Extract.php b/src/Core/Console/Extract.php index e6cab0654a..810d5be41b 100644 --- a/src/Core/Console/Extract.php +++ b/src/Core/Console/Extract.php @@ -1,140 +1,140 @@ - - */ -class Extract extends \Asika\SimpleConsole\Console -{ - protected $helpOptions = ['h', 'help', '?']; - - protected function getHelp() - { - $help = <<getOption('v')) { - $this->out('Class: ' . __CLASS__); - $this->out('Arguments: ' . var_export($this->args, true)); - $this->out('Options: ' . var_export($this->options, true)); - } - - if (count($this->args) > 0) { - throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); - } - - $s = 'globRecursive('src') - ); - - foreach ($files as $file) { - $str = file_get_contents($file); - - $pat = '|L10n::t\(([^\)]*+)[\)]|'; - $patt = '|L10n::tt\(([^\)]*+)[\)]|'; - - $matches = []; - $matchestt = []; - - preg_match_all($pat, $str, $matches); - preg_match_all($patt, $str, $matchestt); - - if (count($matches) || count($matchestt)) { - $s .= '// ' . $file . PHP_EOL; - } - - if (!empty($matches[1])) { - foreach ($matches[1] as $long_match) { - $match_arr = preg_split('/(?<=[\'"])\s*,/', $long_match); - $match = $match_arr[0]; - if (!in_array($match, $arr)) { - if (substr($match, 0, 1) == '$') { - continue; - } - - $arr[] = $match; - - $s .= '$a->strings[' . $match . '] = ' . $match . ';' . "\n"; - } - } - } - if (!empty($matchestt[1])) { - foreach ($matchestt[1] as $match) { - $matchtkns = preg_split("|[ \t\r\n]*,[ \t\r\n]*|", $match); - if (count($matchtkns) == 3 && !in_array($matchtkns[0], $arr)) { - if (substr($matchtkns[1], 0, 1) == '$') { - continue; - } - - $arr[] = $matchtkns[0]; - - $s .= '$a->strings[' . $matchtkns[0] . "] = array(\n"; - $s .= "\t0 => " . $matchtkns[0] . ",\n"; - $s .= "\t1 => " . $matchtkns[1] . ",\n"; - $s .= ");\n"; - } - } - } - } - - $s .= '// Timezones' . PHP_EOL; - - $zones = timezone_identifiers_list(); - foreach ($zones as $zone) { - $s .= '$a->strings[\'' . $zone . '\'] = \'' . $zone . '\';' . "\n"; - } - - $this->out($s); - - return 0; - } - - private function globRecursive($path) { - $dir_iterator = new \RecursiveDirectoryIterator($path); - $iterator = new \RecursiveIteratorIterator($dir_iterator, \RecursiveIteratorIterator::SELF_FIRST); - - $return = []; - foreach ($iterator as $file) { - if ($file->getBasename() != '.' && $file->getBasename() != '..') { - $return[] = $file->getPathname(); - } - } - - return $return; - } -} + + */ +class Extract extends \Asika\SimpleConsole\Console +{ + protected $helpOptions = ['h', 'help', '?']; + + protected function getHelp() + { + $help = <<getOption('v')) { + $this->out('Class: ' . __CLASS__); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + if (count($this->args) > 0) { + throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); + } + + $s = 'globRecursive('src') + ); + + foreach ($files as $file) { + $str = file_get_contents($file); + + $pat = '|L10n::t\(([^\)]*+)[\)]|'; + $patt = '|L10n::tt\(([^\)]*+)[\)]|'; + + $matches = []; + $matchestt = []; + + preg_match_all($pat, $str, $matches); + preg_match_all($patt, $str, $matchestt); + + if (count($matches) || count($matchestt)) { + $s .= '// ' . $file . PHP_EOL; + } + + if (!empty($matches[1])) { + foreach ($matches[1] as $long_match) { + $match_arr = preg_split('/(?<=[\'"])\s*,/', $long_match); + $match = $match_arr[0]; + if (!in_array($match, $arr)) { + if (substr($match, 0, 1) == '$') { + continue; + } + + $arr[] = $match; + + $s .= '$a->strings[' . $match . '] = ' . $match . ';' . "\n"; + } + } + } + if (!empty($matchestt[1])) { + foreach ($matchestt[1] as $match) { + $matchtkns = preg_split("|[ \t\r\n]*,[ \t\r\n]*|", $match); + if (count($matchtkns) == 3 && !in_array($matchtkns[0], $arr)) { + if (substr($matchtkns[1], 0, 1) == '$') { + continue; + } + + $arr[] = $matchtkns[0]; + + $s .= '$a->strings[' . $matchtkns[0] . "] = array(\n"; + $s .= "\t0 => " . $matchtkns[0] . ",\n"; + $s .= "\t1 => " . $matchtkns[1] . ",\n"; + $s .= ");\n"; + } + } + } + } + + $s .= '// Timezones' . PHP_EOL; + + $zones = timezone_identifiers_list(); + foreach ($zones as $zone) { + $s .= '$a->strings[\'' . $zone . '\'] = \'' . $zone . '\';' . "\n"; + } + + $this->out($s); + + return 0; + } + + private function globRecursive($path) { + $dir_iterator = new \RecursiveDirectoryIterator($path); + $iterator = new \RecursiveIteratorIterator($dir_iterator, \RecursiveIteratorIterator::SELF_FIRST); + + $return = []; + foreach ($iterator as $file) { + if ($file->getBasename() != '.' && $file->getBasename() != '..') { + $return[] = $file->getPathname(); + } + } + + return $return; + } +} diff --git a/src/Core/Console/GlobalCommunityBlock.php b/src/Core/Console/GlobalCommunityBlock.php index 1516a8325c..aebb0a2d7c 100644 --- a/src/Core/Console/GlobalCommunityBlock.php +++ b/src/Core/Console/GlobalCommunityBlock.php @@ -1,77 +1,77 @@ - - * @author Hypolite Petovan - */ -class GlobalCommunityBlock extends \Asika\SimpleConsole\Console -{ - protected $helpOptions = ['h', 'help', '?']; - - protected function getHelp() - { - $help = << [-h|--help|-?] [-v] - -Description - Blocks an account in such a way that no postings or comments this account writes are accepted to this node. - -Options - -h|--help|-? Show help information - -v Show more debug information. -HELP; - return $help; - } - - protected function doExecute() - { - if ($this->getOption('v')) { - $this->out('Class: ' . __CLASS__); - $this->out('Arguments: ' . var_export($this->args, true)); - $this->out('Options: ' . var_export($this->options, true)); - } - - if (count($this->args) == 0) { - $this->out($this->getHelp()); - return 0; - } - - if (count($this->args) > 1) { - throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); - } - - require_once '.htconfig.php'; - $result = \dba::connect($db_host, $db_user, $db_pass, $db_data); - unset($db_host, $db_user, $db_pass, $db_data); - - if (!$result) { - throw new \RuntimeException('Unable to connect to database'); - } - - $contact_id = Contact::getIdForURL($this->getArgument(0)); - if (!$contact_id) { - throw new \RuntimeException(L10n::t('Could not find any contact entry for this URL (%s)', $nurl)); - } - if(Contact::block($contact_id)) { - $this->out(L10n::t('The contact has been blocked from the node')); - } else { - throw new \RuntimeException('The contact block failed.'); - } - - return 0; - } -} + + * @author Hypolite Petovan + */ +class GlobalCommunityBlock extends \Asika\SimpleConsole\Console +{ + protected $helpOptions = ['h', 'help', '?']; + + protected function getHelp() + { + $help = << [-h|--help|-?] [-v] + +Description + Blocks an account in such a way that no postings or comments this account writes are accepted to this node. + +Options + -h|--help|-? Show help information + -v Show more debug information. +HELP; + return $help; + } + + protected function doExecute() + { + if ($this->getOption('v')) { + $this->out('Class: ' . __CLASS__); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + if (count($this->args) == 0) { + $this->out($this->getHelp()); + return 0; + } + + if (count($this->args) > 1) { + throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); + } + + require_once '.htconfig.php'; + $result = \dba::connect($db_host, $db_user, $db_pass, $db_data); + unset($db_host, $db_user, $db_pass, $db_data); + + if (!$result) { + throw new \RuntimeException('Unable to connect to database'); + } + + $contact_id = Contact::getIdForURL($this->getArgument(0)); + if (!$contact_id) { + throw new \RuntimeException(L10n::t('Could not find any contact entry for this URL (%s)', $nurl)); + } + if(Contact::block($contact_id)) { + $this->out(L10n::t('The contact has been blocked from the node')); + } else { + throw new \RuntimeException('The contact block failed.'); + } + + return 0; + } +} diff --git a/src/Core/Console/GlobalCommunitySilence.php b/src/Core/Console/GlobalCommunitySilence.php index 069750afc6..958c445934 100644 --- a/src/Core/Console/GlobalCommunitySilence.php +++ b/src/Core/Console/GlobalCommunitySilence.php @@ -1,94 +1,94 @@ - - */ -class GlobalCommunitySilence extends \Asika\SimpleConsole\Console -{ - protected $helpOptions = ['h', 'help', '?']; - - protected function getHelp() - { - $help = << [-h|--help|-?] [-v] - -Description - 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. - This silencing does only affect the display on the community page, accounts - following the silenced accounts will still get their postings. - -Options - -h|--help|-? Show help information - -v Show more debug information. -HELP; - return $help; - } - - protected function doExecute() - { - if ($this->getOption('v')) { - $this->out('Class: ' . __CLASS__); - $this->out('Arguments: ' . var_export($this->args, true)); - $this->out('Options: ' . var_export($this->options, true)); - } - - if (count($this->args) == 0) { - $this->out($this->getHelp()); - return 0; - } - - if (count($this->args) > 1) { - throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); - } - - require_once '.htconfig.php'; - $result = \dba::connect($db_host, $db_user, $db_pass, $db_data); - unset($db_host, $db_user, $db_pass, $db_data); - - if (!$result) { - throw new \RuntimeException('Unable to connect to database'); - } - - /** - * 1. make nurl from last parameter - * 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 - * */ - $net = Probe::uri($this->getArgument(0)); - if (in_array($net['network'], [Protocol::PHANTOM, Protocol::MAIL])) { - throw new \RuntimeException('This account seems not to exist.'); - } - - $nurl = normalise_link($net['url']); - $contact = \dba::selectFirst("contact", ["id"], ["nurl" => $nurl, "uid" => 0]); - if (DBM::is_result($contact)) { - \dba::update("contact", ["hidden" => true], ["id" => $contact["id"]]); - $this->out('NOTICE: The account should be silenced from the global community page'); - } else { - throw new \RuntimeException('NOTICE: Could not find any entry for this URL (' . $nurl . ')'); - } - - return 0; - } -} + + */ +class GlobalCommunitySilence extends \Asika\SimpleConsole\Console +{ + protected $helpOptions = ['h', 'help', '?']; + + protected function getHelp() + { + $help = << [-h|--help|-?] [-v] + +Description + 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. + This silencing does only affect the display on the community page, accounts + following the silenced accounts will still get their postings. + +Options + -h|--help|-? Show help information + -v Show more debug information. +HELP; + return $help; + } + + protected function doExecute() + { + if ($this->getOption('v')) { + $this->out('Class: ' . __CLASS__); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + if (count($this->args) == 0) { + $this->out($this->getHelp()); + return 0; + } + + if (count($this->args) > 1) { + throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); + } + + require_once '.htconfig.php'; + $result = \dba::connect($db_host, $db_user, $db_pass, $db_data); + unset($db_host, $db_user, $db_pass, $db_data); + + if (!$result) { + throw new \RuntimeException('Unable to connect to database'); + } + + /** + * 1. make nurl from last parameter + * 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 + * */ + $net = Probe::uri($this->getArgument(0)); + if (in_array($net['network'], [Protocol::PHANTOM, Protocol::MAIL])) { + throw new \RuntimeException('This account seems not to exist.'); + } + + $nurl = normalise_link($net['url']); + $contact = \dba::selectFirst("contact", ["id"], ["nurl" => $nurl, "uid" => 0]); + if (DBM::is_result($contact)) { + \dba::update("contact", ["hidden" => true], ["id" => $contact["id"]]); + $this->out('NOTICE: The account should be silenced from the global community page'); + } else { + throw new \RuntimeException('NOTICE: Could not find any entry for this URL (' . $nurl . ')'); + } + + return 0; + } +} diff --git a/src/Core/Console/Maintenance.php b/src/Core/Console/Maintenance.php index 19067940d1..cf0a468ff6 100644 --- a/src/Core/Console/Maintenance.php +++ b/src/Core/Console/Maintenance.php @@ -1,105 +1,105 @@ - - */ -class Maintenance extends \Asika\SimpleConsole\Console -{ - protected $helpOptions = ['h', 'help', '?']; - - protected function getHelp() - { - $help = << [] [-h|--help|-?] [-v] - -Description - cen be either 0 or 1 to disabled or enable the maintenance mode on this node. - - is a quote-enclosed string with the optional reason for the maintenance mode. - -Examples - bin/console maintenance 1 - Enables the maintenance mode without setting a reason message - - bin/console maintenance 1 "SSL certification update" - Enables the maintenance mode with setting a reason message - - bin/console maintenance 0 - Disables the maintenance mode - -Options - -h|--help|-? Show help information - -v Show more debug information. -HELP; - return $help; - } - - protected function doExecute() - { - if ($this->getOption('v')) { - $this->out('Class: ' . __CLASS__); - $this->out('Arguments: ' . var_export($this->args, true)); - $this->out('Options: ' . var_export($this->options, true)); - } - - if (count($this->args) == 0) { - $this->out($this->getHelp()); - return 0; - } - - if (count($this->args) > 2) { - throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); - } - - require_once '.htconfig.php'; - $result = \dba::connect($db_host, $db_user, $db_pass, $db_data); - unset($db_host, $db_user, $db_pass, $db_data); - - if (!$result) { - throw new \RuntimeException('Unable to connect to database'); - } - - Core\Config::load(); - - $lang = Core\L10n::getBrowserLanguage(); - Core\L10n::loadTranslationTable($lang); - - $enabled = intval($this->getArgument(0)); - - Core\Config::set('system', 'maintenance', $enabled); - - $reason = $this->getArgument(1); - - if ($enabled && $this->getArgument(1)) { - Core\Config::set('system', 'maintenance_reason', $this->getArgument(1)); - } else { - Core\Config::set('system', 'maintenance_reason', ''); - } - - if ($enabled) { - $mode_str = "maintenance mode"; - } else { - $mode_str = "normal mode"; - } - - $this->out('System set in ' . $mode_str); - - if ($enabled && $reason != '') { - $this->out('Maintenance reason: ' . $reason); - } - - return 0; - } - -} + + */ +class Maintenance extends \Asika\SimpleConsole\Console +{ + protected $helpOptions = ['h', 'help', '?']; + + protected function getHelp() + { + $help = << [] [-h|--help|-?] [-v] + +Description + cen be either 0 or 1 to disabled or enable the maintenance mode on this node. + + is a quote-enclosed string with the optional reason for the maintenance mode. + +Examples + bin/console maintenance 1 + Enables the maintenance mode without setting a reason message + + bin/console maintenance 1 "SSL certification update" + Enables the maintenance mode with setting a reason message + + bin/console maintenance 0 + Disables the maintenance mode + +Options + -h|--help|-? Show help information + -v Show more debug information. +HELP; + return $help; + } + + protected function doExecute() + { + if ($this->getOption('v')) { + $this->out('Class: ' . __CLASS__); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + if (count($this->args) == 0) { + $this->out($this->getHelp()); + return 0; + } + + if (count($this->args) > 2) { + throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); + } + + require_once '.htconfig.php'; + $result = \dba::connect($db_host, $db_user, $db_pass, $db_data); + unset($db_host, $db_user, $db_pass, $db_data); + + if (!$result) { + throw new \RuntimeException('Unable to connect to database'); + } + + Core\Config::load(); + + $lang = Core\L10n::getBrowserLanguage(); + Core\L10n::loadTranslationTable($lang); + + $enabled = intval($this->getArgument(0)); + + Core\Config::set('system', 'maintenance', $enabled); + + $reason = $this->getArgument(1); + + if ($enabled && $this->getArgument(1)) { + Core\Config::set('system', 'maintenance_reason', $this->getArgument(1)); + } else { + Core\Config::set('system', 'maintenance_reason', ''); + } + + if ($enabled) { + $mode_str = "maintenance mode"; + } else { + $mode_str = "normal mode"; + } + + $this->out('System set in ' . $mode_str); + + if ($enabled && $reason != '') { + $this->out('Maintenance reason: ' . $reason); + } + + return 0; + } + +} diff --git a/src/Core/Console/PhpToPo.php b/src/Core/Console/PhpToPo.php index 105e6ea35b..76cf164344 100644 --- a/src/Core/Console/PhpToPo.php +++ b/src/Core/Console/PhpToPo.php @@ -1,234 +1,234 @@ - - */ -class PhpToPo extends \Asika\SimpleConsole\Console -{ - - protected $helpOptions = ['h', 'help', '?']; - - private $normBaseMsgIds = []; - const NORM_REGEXP = "|[\\\]|"; - - protected function getHelp() - { - $help = <<] [--base ] [-h|--help|-?] [-v] - -Description - Read a strings.php file and create the according messages.po in the same directory - -Options - -p Number of plural forms. Default: 2 - --base Path to base messages.po file. Default: util/messages.po - -h|--help|-? Show help information - -v Show more debug information. -HELP; - return $help; - } - - protected function doExecute() - { - if ($this->getOption('v')) { - $this->out('Class: ' . __CLASS__); - $this->out('Arguments: ' . var_export($this->args, true)); - $this->out('Options: ' . var_export($this->options, true)); - } - - if (count($this->args) == 0) { - $this->out($this->getHelp()); - return 0; - } - - if (count($this->args) > 1) { - throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); - } - - $a = get_app(); - - $phpfile = realpath($this->getArgument(0)); - - if (!file_exists($phpfile)) { - throw new \RuntimeException('Supplied file path doesn\'t exist.'); - } - - if (!is_writable(dirname($phpfile))) { - throw new \RuntimeException('Supplied directory isn\'t writable.'); - } - - $pofile = dirname($phpfile) . DIRECTORY_SEPARATOR . 'messages.po'; - - // start ! - include_once($phpfile); - - $out = ''; - $out .= "# FRIENDICA Distributed Social Network\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 .= "# \n"; - $out .= 'msgid ""' . "\n"; - $out .= 'msgstr ""' . "\n"; - $out .= '"Project-Id-Version: friendica\n"' . "\n"; - $out .= '"Report-Msgid-Bugs-To: \n"' . "\n"; - $out .= '"POT-Creation-Date: ' . date("Y-m-d H:i:sO") . '\n"' . "\n"; - $out .= '"MIME-Version: 1.0\n"' . "\n"; - $out .= '"Content-Type: text/plain; charset=UTF-8\n"' . "\n"; - $out .= '"Content-Transfer-Encoding: 8bit\n"' . "\n"; - - // search for plural info - $lang = ""; - $lang_logic = ""; - $lang_pnum = $this->getOption('p', 2); - - $infile = file($phpfile); - foreach ($infile as $l) { - $l = trim($l); - if ($this->startsWith($l, 'function string_plural_select_')) { - $lang = str_replace('function string_plural_select_', '', str_replace('($n){', '', $l)); - } - if ($this->startsWith($l, 'return')) { - $lang_logic = str_replace('$', '', trim(str_replace('return ', '', $l), ';')); - break; - } - } - - $this->out('Language: ' . $lang); - $this->out('Plural forms: ' . $lang_pnum); - $this->out('Plural forms: ' . $lang_logic); - - $out .= sprintf('"Language: %s\n"', $lang) . "\n"; - $out .= sprintf('"Plural-Forms: nplurals=%s; plural=%s;\n"', $lang_pnum, $lang_logic) . "\n"; - $out .= "\n"; - - $base_path = $this->getOption('base', 'util' . DIRECTORY_SEPARATOR . 'messages.po'); - - // load base messages.po and extract msgids - $base_msgids = []; - $base_f = file($base_path); - if (!$base_f) { - throw new \RuntimeException('The base ' . $base_path . ' file is missing or unavailable to read.'); - } - - $this->out('Loading base file ' . $base_path . '...'); - - $_f = 0; - $_mid = ""; - $_mids = []; - foreach ($base_f as $l) { - $l = trim($l); - - if ($this->startsWith($l, 'msgstr')) { - if ($_mid != '""') { - $base_msgids[$_mid] = $_mids; - $this->normBaseMsgIds[preg_replace(self::NORM_REGEXP, "", $_mid)] = $_mid; - } - - $_f = 0; - $_mid = ""; - $_mids = []; - } - - if ($this->startsWith($l, '"') && $_f == 2) { - $_mids[count($_mids) - 1] .= "\n" . $l; - } - if ($this->startsWith($l, 'msgid_plural ')) { - $_f = 2; - $_mids[] = str_replace('msgid_plural ', '', $l); - } - - if ($this->startsWith($l, '"') && $_f == 1) { - $_mid .= "\n" . $l; - $_mids[count($_mids) - 1] .= "\n" . $l; - } - if ($this->startsWith($l, 'msgid ')) { - $_f = 1; - $_mid = str_replace('msgid ', '', $l); - $_mids = [$_mid]; - } - } - - $this->out('Creating ' . $pofile . '...'); - - // create msgid and msgstr - $warnings = ""; - foreach ($a->strings as $key => $str) { - $msgid = $this->massageString($key); - - if (preg_match("|%[sd0-9](\$[sn])*|", $msgid)) { - $out .= "#, php-format\n"; - } - $msgid = $this->findOriginalMsgId($msgid); - $out .= 'msgid ' . $msgid . "\n"; - - if (is_array($str)) { - if (array_key_exists($msgid, $base_msgids) && isset($base_msgids[$msgid][1])) { - $out .= 'msgid_plural ' . $base_msgids[$msgid][1] . "\n"; - } else { - $out .= 'msgid_plural ' . $msgid . "\n"; - $warnings .= "[W] No source plural form for msgid:\n" . str_replace("\n", "\n\t", $msgid) . "\n\n"; - } - foreach ($str as $n => $msgstr) { - $out .= 'msgstr[' . $n . '] ' . $this->massageString($msgstr) . "\n"; - } - } else { - $out .= 'msgstr ' . $this->massageString($str) . "\n"; - } - - $out .= "\n"; - } - - if (!file_put_contents($pofile, $out)) { - throw new \RuntimeException('Unable to write to ' . $pofile); - } - - if ($warnings != '') { - $this->out($warnings); - } - - return 0; - } - - private function startsWith($haystack, $needle) - { - // search backwards starting from haystack length characters from the end - return $needle === "" || strrpos($haystack, $needle, -strlen($haystack)) !== FALSE; - } - - /** - * Get a string and retun a message.po ready text - * - replace " with \" - * - replace tab char with \t - * - manage multiline strings - */ - private function massageString($str) - { - $str = str_replace('\\', '\\\\', $str); - $str = str_replace('"', '\"', $str); - $str = str_replace("\t", '\t', $str); - $str = str_replace("\n", '\n"' . "\n" . '"', $str); - if (strpos($str, "\n") !== false && $str[0] !== '"') { - $str = '"' . "\n" . $str; - } - - $str = preg_replace("|\n([^\"])|", "\n\"$1", $str); - return sprintf('"%s"', $str); - } - - private function findOriginalMsgId($str) - { - $norm_str = preg_replace(self::NORM_REGEXP, "", $str); - if (array_key_exists($norm_str, $this->normBaseMsgIds)) { - return $this->normBaseMsgIds[$norm_str]; - } - - return $str; - } - -} + + */ +class PhpToPo extends \Asika\SimpleConsole\Console +{ + + protected $helpOptions = ['h', 'help', '?']; + + private $normBaseMsgIds = []; + const NORM_REGEXP = "|[\\\]|"; + + protected function getHelp() + { + $help = <<] [--base ] [-h|--help|-?] [-v] + +Description + Read a strings.php file and create the according messages.po in the same directory + +Options + -p Number of plural forms. Default: 2 + --base Path to base messages.po file. Default: util/messages.po + -h|--help|-? Show help information + -v Show more debug information. +HELP; + return $help; + } + + protected function doExecute() + { + if ($this->getOption('v')) { + $this->out('Class: ' . __CLASS__); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + if (count($this->args) == 0) { + $this->out($this->getHelp()); + return 0; + } + + if (count($this->args) > 1) { + throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); + } + + $a = get_app(); + + $phpfile = realpath($this->getArgument(0)); + + if (!file_exists($phpfile)) { + throw new \RuntimeException('Supplied file path doesn\'t exist.'); + } + + if (!is_writable(dirname($phpfile))) { + throw new \RuntimeException('Supplied directory isn\'t writable.'); + } + + $pofile = dirname($phpfile) . DIRECTORY_SEPARATOR . 'messages.po'; + + // start ! + include_once($phpfile); + + $out = ''; + $out .= "# FRIENDICA Distributed Social Network\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 .= "# \n"; + $out .= 'msgid ""' . "\n"; + $out .= 'msgstr ""' . "\n"; + $out .= '"Project-Id-Version: friendica\n"' . "\n"; + $out .= '"Report-Msgid-Bugs-To: \n"' . "\n"; + $out .= '"POT-Creation-Date: ' . date("Y-m-d H:i:sO") . '\n"' . "\n"; + $out .= '"MIME-Version: 1.0\n"' . "\n"; + $out .= '"Content-Type: text/plain; charset=UTF-8\n"' . "\n"; + $out .= '"Content-Transfer-Encoding: 8bit\n"' . "\n"; + + // search for plural info + $lang = ""; + $lang_logic = ""; + $lang_pnum = $this->getOption('p', 2); + + $infile = file($phpfile); + foreach ($infile as $l) { + $l = trim($l); + if ($this->startsWith($l, 'function string_plural_select_')) { + $lang = str_replace('function string_plural_select_', '', str_replace('($n){', '', $l)); + } + if ($this->startsWith($l, 'return')) { + $lang_logic = str_replace('$', '', trim(str_replace('return ', '', $l), ';')); + break; + } + } + + $this->out('Language: ' . $lang); + $this->out('Plural forms: ' . $lang_pnum); + $this->out('Plural forms: ' . $lang_logic); + + $out .= sprintf('"Language: %s\n"', $lang) . "\n"; + $out .= sprintf('"Plural-Forms: nplurals=%s; plural=%s;\n"', $lang_pnum, $lang_logic) . "\n"; + $out .= "\n"; + + $base_path = $this->getOption('base', 'util' . DIRECTORY_SEPARATOR . 'messages.po'); + + // load base messages.po and extract msgids + $base_msgids = []; + $base_f = file($base_path); + if (!$base_f) { + throw new \RuntimeException('The base ' . $base_path . ' file is missing or unavailable to read.'); + } + + $this->out('Loading base file ' . $base_path . '...'); + + $_f = 0; + $_mid = ""; + $_mids = []; + foreach ($base_f as $l) { + $l = trim($l); + + if ($this->startsWith($l, 'msgstr')) { + if ($_mid != '""') { + $base_msgids[$_mid] = $_mids; + $this->normBaseMsgIds[preg_replace(self::NORM_REGEXP, "", $_mid)] = $_mid; + } + + $_f = 0; + $_mid = ""; + $_mids = []; + } + + if ($this->startsWith($l, '"') && $_f == 2) { + $_mids[count($_mids) - 1] .= "\n" . $l; + } + if ($this->startsWith($l, 'msgid_plural ')) { + $_f = 2; + $_mids[] = str_replace('msgid_plural ', '', $l); + } + + if ($this->startsWith($l, '"') && $_f == 1) { + $_mid .= "\n" . $l; + $_mids[count($_mids) - 1] .= "\n" . $l; + } + if ($this->startsWith($l, 'msgid ')) { + $_f = 1; + $_mid = str_replace('msgid ', '', $l); + $_mids = [$_mid]; + } + } + + $this->out('Creating ' . $pofile . '...'); + + // create msgid and msgstr + $warnings = ""; + foreach ($a->strings as $key => $str) { + $msgid = $this->massageString($key); + + if (preg_match("|%[sd0-9](\$[sn])*|", $msgid)) { + $out .= "#, php-format\n"; + } + $msgid = $this->findOriginalMsgId($msgid); + $out .= 'msgid ' . $msgid . "\n"; + + if (is_array($str)) { + if (array_key_exists($msgid, $base_msgids) && isset($base_msgids[$msgid][1])) { + $out .= 'msgid_plural ' . $base_msgids[$msgid][1] . "\n"; + } else { + $out .= 'msgid_plural ' . $msgid . "\n"; + $warnings .= "[W] No source plural form for msgid:\n" . str_replace("\n", "\n\t", $msgid) . "\n\n"; + } + foreach ($str as $n => $msgstr) { + $out .= 'msgstr[' . $n . '] ' . $this->massageString($msgstr) . "\n"; + } + } else { + $out .= 'msgstr ' . $this->massageString($str) . "\n"; + } + + $out .= "\n"; + } + + if (!file_put_contents($pofile, $out)) { + throw new \RuntimeException('Unable to write to ' . $pofile); + } + + if ($warnings != '') { + $this->out($warnings); + } + + return 0; + } + + private function startsWith($haystack, $needle) + { + // search backwards starting from haystack length characters from the end + return $needle === "" || strrpos($haystack, $needle, -strlen($haystack)) !== FALSE; + } + + /** + * Get a string and retun a message.po ready text + * - replace " with \" + * - replace tab char with \t + * - manage multiline strings + */ + private function massageString($str) + { + $str = str_replace('\\', '\\\\', $str); + $str = str_replace('"', '\"', $str); + $str = str_replace("\t", '\t', $str); + $str = str_replace("\n", '\n"' . "\n" . '"', $str); + if (strpos($str, "\n") !== false && $str[0] !== '"') { + $str = '"' . "\n" . $str; + } + + $str = preg_replace("|\n([^\"])|", "\n\"$1", $str); + return sprintf('"%s"', $str); + } + + private function findOriginalMsgId($str) + { + $norm_str = preg_replace(self::NORM_REGEXP, "", $str); + if (array_key_exists($norm_str, $this->normBaseMsgIds)) { + return $this->normBaseMsgIds[$norm_str]; + } + + return $str; + } + +} diff --git a/src/Core/Console/PoToPhp.php b/src/Core/Console/PoToPhp.php index 3a58d9fed4..0a7224503a 100644 --- a/src/Core/Console/PoToPhp.php +++ b/src/Core/Console/PoToPhp.php @@ -1,197 +1,197 @@ - - */ -class PoToPhp extends \Asika\SimpleConsole\Console -{ - protected $helpOptions = ['h', 'help', '?']; - - const DQ_ESCAPE = "__DQ__"; - - protected function getHelp() - { - $help = << [-h|--help|-?] [-v] - -Description - Read a messages.po file and create the according strings.php in the same directory - -Options - -h|--help|-? Show help information - -v Show more debug information. -HELP; - return $help; - } - - protected function doExecute() - { - if ($this->getOption('v')) { - $this->out('Class: ' . __CLASS__); - $this->out('Arguments: ' . var_export($this->args, true)); - $this->out('Options: ' . var_export($this->options, true)); - } - - if (count($this->args) == 0) { - $this->out($this->getHelp()); - return 0; - } - - if (count($this->args) > 1) { - throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); - } - - $a = get_app(); - - $pofile = realpath($this->getArgument(0)); - - if (!file_exists($pofile)) { - throw new \RuntimeException('Supplied file path doesn\'t exist.'); - } - - if (!is_writable(dirname($pofile))) { - throw new \RuntimeException('Supplied directory isn\'t writable.'); - } - - $outfile = dirname($pofile) . DIRECTORY_SEPARATOR . 'strings.php'; - - if (strstr($outfile, 'util')) { - $lang = 'en'; - } else { - $lang = str_replace('-', '_', basename(dirname($pofile))); - } - - $this->out('Out to ' . $outfile); - - $out = "strings["' . $k . '"] = '; - } - - if ($inv) { - $inv = false; - $out .= '"' . $v . '"'; - } - - $v = substr($l, 8, $len - 11); - $v = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $v); - - $inv = true; - } - if ($k != "" && substr($l, 0, 7) == 'msgstr[') { - if ($ink) { - $ink = false; - $out .= '$a->strings["' . $k . '"] = '; - } - if ($inv) { - $inv = false; - $out .= '"' . $v . '"'; - } - - if (!$arr) { - $arr = True; - $out .= "[\n"; - } - $match = []; - preg_match("|\[([0-9]*)\] (.*)|", $l, $match); - $out .= "\t" - . preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $match[1]) - . ' => ' - . preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $match[2]) - . ",\n"; - } - - if (substr($l, 0, 6) == 'msgid_') { - $ink = false; - $out .= '$a->strings["' . $k . '"] = '; - } - - if ($ink) { - $k .= trim($l, "\"\r\n"); - $k = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $k); - } - - if (substr($l, 0, 6) == 'msgid ') { - if ($inv) { - $inv = false; - $out .= '"' . $v . '"'; - } - if ($k != "") { - $out .= ($arr) ? "];\n" : ";\n"; - } - $arr = false; - $k = str_replace("msgid ", "", $l); - if ($k != '""') { - $k = trim($k, "\"\r\n"); - } else { - $k = ''; - } - - $k = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $k); - $ink = true; - } - - if ($inv && substr($l, 0, 6) != "msgstr") { - $v .= trim($l, "\"\r\n"); - $v = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $v); - } - } - - if ($inv) { - $inv = false; - $out .= '"' . $v . '"'; - } - - if ($k != '') { - $out .= ($arr ? "];\n" : ";\n"); - } - - $out = str_replace(self::DQ_ESCAPE, '\"', $out); - if (!file_put_contents($outfile, $out)) { - throw new \RuntimeException('Unable to write to ' . $outfile); - } - - return 0; - } - - private function escapeDollar($match) - { - return str_replace('$', '\$', $match[0]); - } -} + + */ +class PoToPhp extends \Asika\SimpleConsole\Console +{ + protected $helpOptions = ['h', 'help', '?']; + + const DQ_ESCAPE = "__DQ__"; + + protected function getHelp() + { + $help = << [-h|--help|-?] [-v] + +Description + Read a messages.po file and create the according strings.php in the same directory + +Options + -h|--help|-? Show help information + -v Show more debug information. +HELP; + return $help; + } + + protected function doExecute() + { + if ($this->getOption('v')) { + $this->out('Class: ' . __CLASS__); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + if (count($this->args) == 0) { + $this->out($this->getHelp()); + return 0; + } + + if (count($this->args) > 1) { + throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); + } + + $a = get_app(); + + $pofile = realpath($this->getArgument(0)); + + if (!file_exists($pofile)) { + throw new \RuntimeException('Supplied file path doesn\'t exist.'); + } + + if (!is_writable(dirname($pofile))) { + throw new \RuntimeException('Supplied directory isn\'t writable.'); + } + + $outfile = dirname($pofile) . DIRECTORY_SEPARATOR . 'strings.php'; + + if (strstr($outfile, 'util')) { + $lang = 'en'; + } else { + $lang = str_replace('-', '_', basename(dirname($pofile))); + } + + $this->out('Out to ' . $outfile); + + $out = "strings["' . $k . '"] = '; + } + + if ($inv) { + $inv = false; + $out .= '"' . $v . '"'; + } + + $v = substr($l, 8, $len - 11); + $v = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $v); + + $inv = true; + } + if ($k != "" && substr($l, 0, 7) == 'msgstr[') { + if ($ink) { + $ink = false; + $out .= '$a->strings["' . $k . '"] = '; + } + if ($inv) { + $inv = false; + $out .= '"' . $v . '"'; + } + + if (!$arr) { + $arr = True; + $out .= "[\n"; + } + $match = []; + preg_match("|\[([0-9]*)\] (.*)|", $l, $match); + $out .= "\t" + . preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $match[1]) + . ' => ' + . preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $match[2]) + . ",\n"; + } + + if (substr($l, 0, 6) == 'msgid_') { + $ink = false; + $out .= '$a->strings["' . $k . '"] = '; + } + + if ($ink) { + $k .= trim($l, "\"\r\n"); + $k = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $k); + } + + if (substr($l, 0, 6) == 'msgid ') { + if ($inv) { + $inv = false; + $out .= '"' . $v . '"'; + } + if ($k != "") { + $out .= ($arr) ? "];\n" : ";\n"; + } + $arr = false; + $k = str_replace("msgid ", "", $l); + if ($k != '""') { + $k = trim($k, "\"\r\n"); + } else { + $k = ''; + } + + $k = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $k); + $ink = true; + } + + if ($inv && substr($l, 0, 6) != "msgstr") { + $v .= trim($l, "\"\r\n"); + $v = preg_replace_callback($escape_s_exp, [$this, 'escapeDollar'], $v); + } + } + + if ($inv) { + $inv = false; + $out .= '"' . $v . '"'; + } + + if ($k != '') { + $out .= ($arr ? "];\n" : ";\n"); + } + + $out = str_replace(self::DQ_ESCAPE, '\"', $out); + if (!file_put_contents($outfile, $out)) { + throw new \RuntimeException('Unable to write to ' . $outfile); + } + + return 0; + } + + private function escapeDollar($match) + { + return str_replace('$', '\$', $match[0]); + } +} diff --git a/src/Core/Console/Typo.php b/src/Core/Console/Typo.php index 4213fc8325..e3ae52263b 100644 --- a/src/Core/Console/Typo.php +++ b/src/Core/Console/Typo.php @@ -1,119 +1,119 @@ - - */ -class Typo extends \Asika\SimpleConsole\Console -{ - protected $helpOptions = ['h', 'help', '?']; - - protected function getHelp() - { - $help = <<getOption('v')) { - $this->out('Class: ' . __CLASS__); - $this->out('Arguments: ' . var_export($this->args, true)); - $this->out('Options: ' . var_export($this->options, true)); - } - - if (count($this->args) > 0) { - throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); - } - - $a = get_app(); - - $php_path = $a->getConfigValue('config', 'php_path', 'php'); - - if ($this->getOption('v')) { - $this->out('Directory: src'); - } - - $Iterator = new \RecursiveDirectoryIterator('src'); - - foreach (new \RecursiveIteratorIterator($Iterator) as $file) { - if (substr($file, -4) === '.php') { - $this->checkFile($php_path, $file); - } - } - - if ($this->getOption('v')) { - $this->out('Directory: mod'); - } - - $files = glob('mod/*.php'); - $this->checkFiles($php_path, $files); - - if ($this->getOption('v')) { - $this->out('Directory: include'); - } - - $files = glob('include/*.php'); - $this->checkFiles($php_path, $files); - - if ($this->getOption('v')) { - $this->out('Directory: addon'); - } - - $dirs = glob('addon/*'); - foreach ($dirs as $dir) { - $addon = basename($dir); - $files = glob($dir . '/' . $addon . '.php'); - $this->checkFiles($php_path, $files); - } - - if ($this->getOption('v')) { - $this->out('String files'); - } - - $this->checkFile($php_path, 'util/strings.php'); - - $files = glob('view/lang/*/strings.php'); - $this->checkFiles($php_path, $files); - - $this->out('No errors.'); - - return 0; - } - - private function checkFiles($php_path, array $files) - { - foreach ($files as $file) { - $this->checkFile($php_path, $file); - } - } - - private function checkFile($php_path, $file) - { - if ($this->getOption('v')) { - $this->out('Checking ' . $file); - } - - $output = []; - $ret = 0; - exec("$php_path -l $file", $output, $ret); - if ($ret !== 0) { - throw new \RuntimeException('Parse error found in ' . $file . ', scan stopped.'); - } - } -} + + */ +class Typo extends \Asika\SimpleConsole\Console +{ + protected $helpOptions = ['h', 'help', '?']; + + protected function getHelp() + { + $help = <<getOption('v')) { + $this->out('Class: ' . __CLASS__); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + if (count($this->args) > 0) { + throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); + } + + $a = get_app(); + + $php_path = $a->getConfigValue('config', 'php_path', 'php'); + + if ($this->getOption('v')) { + $this->out('Directory: src'); + } + + $Iterator = new \RecursiveDirectoryIterator('src'); + + foreach (new \RecursiveIteratorIterator($Iterator) as $file) { + if (substr($file, -4) === '.php') { + $this->checkFile($php_path, $file); + } + } + + if ($this->getOption('v')) { + $this->out('Directory: mod'); + } + + $files = glob('mod/*.php'); + $this->checkFiles($php_path, $files); + + if ($this->getOption('v')) { + $this->out('Directory: include'); + } + + $files = glob('include/*.php'); + $this->checkFiles($php_path, $files); + + if ($this->getOption('v')) { + $this->out('Directory: addon'); + } + + $dirs = glob('addon/*'); + foreach ($dirs as $dir) { + $addon = basename($dir); + $files = glob($dir . '/' . $addon . '.php'); + $this->checkFiles($php_path, $files); + } + + if ($this->getOption('v')) { + $this->out('String files'); + } + + $this->checkFile($php_path, 'util/strings.php'); + + $files = glob('view/lang/*/strings.php'); + $this->checkFiles($php_path, $files); + + $this->out('No errors.'); + + return 0; + } + + private function checkFiles($php_path, array $files) + { + foreach ($files as $file) { + $this->checkFile($php_path, $file); + } + } + + private function checkFile($php_path, $file) + { + if ($this->getOption('v')) { + $this->out('Checking ' . $file); + } + + $output = []; + $ret = 0; + exec("$php_path -l $file", $output, $ret); + if ($ret !== 0) { + throw new \RuntimeException('Parse error found in ' . $file . ', scan stopped.'); + } + } +}