$hidePublicLinks,
$redirector = '',
$redirectorEncode = true
- )
- {
+ ) {
$this->datastore = $datastore;
$this->loggedIn = $isLoggedIn;
$this->hidePublicLinks = $hidePublicLinks;
{
// TODO: use exceptions instead of "die"
if (!$this->loggedIn) {
- die('You are not authorized to add a link.');
+ die(t('You are not authorized to add a link.'));
}
if (!isset($value['id']) || empty($value['url'])) {
- die('Internal Error: A link should always have an id and URL.');
+ die(t('Internal Error: A link should always have an id and URL.'));
}
if (($offset !== null && ! is_int($offset)) || ! is_int($value['id'])) {
- die('You must specify an integer as a key.');
+ die(t('You must specify an integer as a key.'));
}
if ($offset !== null && $offset !== $value['id']) {
- die('Array offset and link ID must be equal.');
+ die(t('Array offset and link ID must be equal.'));
}
// If the link exists, we reuse the real offset, otherwise new entry
$this->links = array();
$link = array(
'id' => 1,
- 'title'=>' Shaarli: the personal, minimalist, super-fast, no-database delicious clone',
+ 'title'=> t('The personal, minimalist, super-fast, database free, bookmarking service'),
'url'=>'https://shaarli.readthedocs.io',
- 'description'=>'Welcome to Shaarli! This is your first public bookmark. To edit or delete me, you must first login.
+ 'description'=>t(
+ 'Welcome to Shaarli! This is your first public bookmark. '
+ .'To edit or delete me, you must first login.
-To learn how to use Shaarli, consult the link "Help/documentation" at the bottom of this page.
+To learn how to use Shaarli, consult the link "Documentation" at the bottom of this page.
-You use the community supported version of the original Shaarli project, by Sebastien Sauvage.',
+You use the community supported version of the original Shaarli project, by Sebastien Sauvage.'
+ ),
'private'=>0,
'created'=> new DateTime(),
- 'tags'=>'opensource software'
+ 'tags'=>'opensource software',
+ 'sticky' => false,
);
$link['shorturl'] = link_small_hash($link['created'], $link['id']);
$this->links[1] = $link;
$link = array(
'id' => 0,
- 'title'=>'My secret stuff... - Pastebin.com',
+ 'title'=> t('My secret stuff... - Pastebin.com'),
'url'=>'http://sebsauvage.net/paste/?8434b27936c09649#bR7XsXhoTiLcqCpQbmOpBi3rq2zzQUC5hBI7ZT1O3x8=',
- 'description'=>'Shhhh! I\'m a private link only YOU can see. You can delete me too.',
+ 'description'=> t('Shhhh! I\'m a private link only YOU can see. You can delete me too.'),
'private'=>1,
'created'=> new DateTime('1 minute ago'),
'tags'=>'secretstuff',
+ 'sticky' => false,
);
$link['shorturl'] = link_small_hash($link['created'], $link['id']);
$this->links[0] = $link;
return;
}
+ $this->urls = [];
+ $this->ids = [];
$this->links = FileUtils::readFlatDB($this->datastore, []);
$toremove = array();
foreach ($this->links as $key => &$link) {
if (! $this->loggedIn && $link['private'] != 0) {
// Transition for not upgraded databases.
- $toremove[] = $key;
+ unset($this->links[$key]);
continue;
}
} else {
$link['real_url'] .= $link['url'];
}
- }
- else {
+ } else {
$link['real_url'] = $link['url'];
}
+ $link['sticky'] = isset($link['sticky']) ? $link['sticky'] : false;
+
// To be able to load links before running the update, and prepare the update
if (! isset($link['created'])) {
$link['id'] = $link['linkdate'];
}
$link['shorturl'] = smallHash($link['linkdate']);
}
- }
- // If user is not logged in, filter private links.
- foreach ($toremove as $offset) {
- unset($this->links[$offset]);
+ $this->urls[$link['url']] = $key;
+ $this->ids[$link['id']] = $key;
}
-
- $this->reorder();
}
/**
*/
private function write()
{
+ $this->reorder();
FileUtils::writeFlatDB($this->datastore, $this->links);
}
*
* @return array list of shaare found.
*/
- public function filterDay($request) {
+ public function filterDay($request)
+ {
$linkFilter = new LinkFilter($this->links);
return $linkFilter->filter(LinkFilter::$FILTER_DAY, $request);
}
*
* @return array filtered links, all links if no suitable filter was provided.
*/
- public function filterSearch($filterRequest = array(), $casesensitive = false, $visibility = 'all', $untaggedonly = false)
- {
+ public function filterSearch(
+ $filterRequest = array(),
+ $casesensitive = false,
+ $visibility = 'all',
+ $untaggedonly = false
+ ) {
// Filter link database according to parameters.
$searchtags = isset($filterRequest['searchtags']) ? escape($filterRequest['searchtags']) : '';
$searchterm = isset($filterRequest['searchterm']) ? escape($filterRequest['searchterm']) : '';
/**
* Returns the list tags appearing in the links with the given tags
- * @param $filteringTags: tags selecting the links to consider
- * @param $visibility: process only all/private/public links
- * @return: a tag=>linksCount array
+ *
+ * @param array $filteringTags tags selecting the links to consider
+ * @param string $visibility process only all/private/public links
+ *
+ * @return array tag => linksCount
*/
public function linksCountPerTag($filteringTags = [], $visibility = 'all')
{
- $links = empty($filteringTags) ? $this->links : $this->filterSearch(['searchtags' => $filteringTags], false, $visibility);
- $tags = array();
- $caseMapping = array();
+ $links = $this->filterSearch(['searchtags' => $filteringTags], false, $visibility);
+ $tags = [];
+ $caseMapping = [];
foreach ($links as $link) {
foreach (preg_split('/\s+/', $link['tags'], 0, PREG_SPLIT_NO_EMPTY) as $tag) {
if (empty($tag)) {
$tags[$caseMapping[strtolower($tag)]]++;
}
}
- // Sort tags by usage (most used tag first)
- arsort($tags);
+
+ /*
+ * Formerly used arsort(), which doesn't define the sort behaviour for equal values.
+ * Also, this function doesn't produce the same result between PHP 5.6 and 7.
+ *
+ * So we now use array_multisort() to sort tags by DESC occurrences,
+ * then ASC alphabetically for equal values.
+ *
+ * @see https://github.com/shaarli/Shaarli/issues/1142
+ */
+ $keys = array_keys($tags);
+ $tmpTags = array_combine($keys, $keys);
+ array_multisort($tags, SORT_DESC, $tmpTags, SORT_ASC, $tags);
return $tags;
}
$delete = empty($to);
// True for case-sensitive tag search.
$linksToAlter = $this->filterSearch(['searchtags' => $from], true);
- foreach($linksToAlter as $key => &$value)
- {
+ foreach ($linksToAlter as $key => &$value) {
$tags = preg_split('/\s+/', trim($value['tags']));
if (($pos = array_search($from, $tags)) !== false) {
if ($delete) {
{
$order = $order === 'ASC' ? -1 : 1;
// Reorder array by dates.
- usort($this->links, function($a, $b) use ($order) {
+ usort($this->links, function ($a, $b) use ($order) {
+ if (isset($a['sticky']) && isset($b['sticky']) && $a['sticky'] !== $b['sticky']) {
+ return $a['sticky'] ? -1 : 1;
+ }
return $a['created'] < $b['created'] ? 1 * $order : -1 * $order;
});
- $this->urls = array();
- $this->ids = array();
+ $this->urls = [];
+ $this->ids = [];
foreach ($this->links as $key => $link) {
$this->urls[$link['url']] = $key;
$this->ids[$link['id']] = $key;