Merge remote-tracking branch 'github/latest' into myShaarli_commu
This commit is contained in:
commit
d923d1db2f
28 changed files with 730 additions and 290 deletions
2
.github/mailmap
vendored
2
.github/mailmap
vendored
|
@ -1,6 +1,8 @@
|
|||
ArthurHoaro <arthur@hoa.ro>
|
||||
Florian Eula <eula.florian@gmail.com> feula
|
||||
Florian Eula <eula.florian@gmail.com> <mr.pikzen@gmail.com>
|
||||
Immánuel Fodor <immanuelfactor+github@gmail.com>
|
||||
kalvn <kalvnthereal@gmail.com> <kalvn@users.noreply.github.com>
|
||||
Nicolas Danelon <hi@nicolasmd.com.ar> nicolasm
|
||||
Nicolas Danelon <hi@nicolasmd.com.ar> <nda@3818.com.ar>
|
||||
Nicolas Danelon <hi@nicolasmd.com.ar> <nicolasdanelon@gmail.com>
|
||||
|
|
13
AUTHORS
13
AUTHORS
|
@ -1,6 +1,6 @@
|
|||
537 ArthurHoaro <arthur@hoa.ro>
|
||||
252 VirtualTam <virtualtam@flibidi.net>
|
||||
148 nodiscc <nodiscc@gmail.com>
|
||||
588 ArthurHoaro <arthur@hoa.ro>
|
||||
283 VirtualTam <virtualtam@flibidi.net>
|
||||
179 nodiscc <nodiscc@gmail.com>
|
||||
56 Sébastien Sauvage <sebsauvage@sebsauvage.net>
|
||||
15 Florian Eula <eula.florian@gmail.com>
|
||||
13 Emilien Klein <emilien@klein.st>
|
||||
|
@ -11,8 +11,9 @@
|
|||
5 Lucas Cimon <lucas.cimon@gmail.com>
|
||||
4 Alexandre Alapetite <alexandre@alapetite.fr>
|
||||
4 David Sferruzza <david.sferruzza@gmail.com>
|
||||
4 Immánuel Fodor <immanuelfactor+github@gmail.com>
|
||||
4 kalvn <kalvnthereal@gmail.com>
|
||||
3 Teromene <teromene@teromene.fr>
|
||||
3 kalvn <kalvnthereal@gmail.com>
|
||||
2 Chris Kuethe <chris.kuethe@gmail.com>
|
||||
2 Knah Tsaeb <Knah-Tsaeb@knah-tsaeb.org>
|
||||
2 Mathieu Chabanon <git@matchab.fr>
|
||||
|
@ -27,11 +28,13 @@
|
|||
1 BoboTiG <bobotig@gmail.com>
|
||||
1 Bronco <bronco@warriordudimanche.net>
|
||||
1 D Low <daniellowtw@gmail.com>
|
||||
1 Daniel Jakots <vigdis@chown.me>
|
||||
1 Dimtion <zizou.xena@gmail.com>
|
||||
1 Fanch <fanch-github@qth.fr>
|
||||
1 Felix Bartels <felix@host-consultants.de>
|
||||
1 Felix Kästner <github.com-fpunktk@fpunktk.de>
|
||||
1 Florian Voigt <flvoigt@me.com>
|
||||
1 Franck Kerbiriou <FranckKe@users.noreply.github.com>
|
||||
1 Gary Marigliano <gmarigliano93@gmail.com>
|
||||
1 Guillaume Virlet <github@virlet.org>
|
||||
1 Jonathan Druart <jonathan.druart@gmail.com>
|
||||
|
@ -41,6 +44,8 @@
|
|||
1 Lionel Martin <renarddesmers@gmail.com>
|
||||
1 Mark Gerarts <mark.gerarts@gmail.com>
|
||||
1 Marsup <marsup@gmail.com>
|
||||
1 Neros <contact@neros.fr>
|
||||
1 Sbgodin <Sbgodin@users.noreply.github.com>
|
||||
1 TsT <tst2005@gmail.com>
|
||||
1 dimtion <zizou.xena@gmail.com>
|
||||
1 durcheinandr <jochen@durcheinandr.de>
|
||||
|
|
51
CHANGELOG.md
51
CHANGELOG.md
|
@ -4,6 +4,49 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [v0.10.0](https://github.com/shaarli/Shaarli/releases/tag/v0.10.0) - UNPUBLISHED
|
||||
|
||||
## [v0.9.5](https://github.com/shaarli/Shaarli/releases/tag/v0.9.5) - 2018-02-02
|
||||
### Fixed
|
||||
- Fix a warning happening when `php-intl` is not installed on the system
|
||||
- Fix warnings happening when updating from legacy SebSauvage version
|
||||
|
||||
## [v0.9.4](https://github.com/shaarli/Shaarli/releases/tag/v0.9.4) - 2018-01-30
|
||||
### Added
|
||||
- Enable translations: Shaarli is now also available in French. Other language translations are welcome!
|
||||
- Add EditorConfig configuration
|
||||
- Add favicons for mobile devices
|
||||
- Add Alpine Linux arm32v7 Dockerfiles (master, latest)
|
||||
|
||||
### Changed
|
||||
- Do not write bookmark edition history during file imports (performance)
|
||||
- Migrate Docker images (master, latest) to Alpine Linux
|
||||
- Improve unitary tests and code coverage
|
||||
- Improve thumbnail display
|
||||
- Improve theme ergonomics
|
||||
- Improve messages if there is no plugin or parameter available in the admin page
|
||||
- Increase buffer size for cURL download
|
||||
- Force HTTPS if the original port is 443 behind a reverse proxy (workaround)
|
||||
- Improve page title retrieval performances
|
||||
|
||||
### Removed
|
||||
- Remove redirector setting from Configure page
|
||||
|
||||
### Fixed
|
||||
- Fix broken links in the documentation
|
||||
- Enable access to `data/user.css` (Apache 2.2 & 2.4)
|
||||
- Don't URL encode description links if parameter `redirector.encode_url` is set to false
|
||||
- Fix an issue preventing the Save button to appear for plugin parameters
|
||||
|
||||
|
||||
## [v0.9.3](https://github.com/shaarli/Shaarli/releases/tag/v0.9.3) - 2018-01-04
|
||||
**XSS vulnerability fixed. Please update.**
|
||||
|
||||
## Security
|
||||
- Fix an XSS (cross-site-scripting) vulnerability in `index.php` -
|
||||
[CVE-2018-5249](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-5249)
|
||||
|
||||
|
||||
## [v0.9.2](https://github.com/shaarli/Shaarli/releases/tag/v0.9.2) - 2017-10-07
|
||||
|
||||
**Major security issue fixed. Please update.**
|
||||
|
@ -42,6 +85,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||
|
||||
- Fixed reflected XSS vulnerability introduced in v0.9.1, discovered by @chb9 ([CVE-2017-15215](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-15215)).
|
||||
|
||||
|
||||
## [v0.9.1](https://github.com/shaarli/Shaarli/releases/tag/v0.9.1) - 2017-08-23
|
||||
|
||||
The documentation has been migrated to ReadTheDocs:
|
||||
|
@ -187,6 +231,13 @@ Theming:
|
|||
|
||||
- Editing a link created before the new ID system would change its permalink.
|
||||
|
||||
## [v0.8.5](https://github.com/shaarli/Shaarli/releases/tag/v0.8.5) - 2018-01-04
|
||||
**XSS vulnerability fixed. Please update.**
|
||||
|
||||
## Security
|
||||
- Fix an XSS (cross-site-scripting) vulnerability in `index.php` -
|
||||
[CVE-2018-5249](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-5249)
|
||||
|
||||
## [v0.8.4](https://github.com/shaarli/Shaarli/releases/tag/v0.8.4) - 2017-03-04
|
||||
### Security
|
||||
- Markdown plugin: escape HTML entities by default
|
||||
|
|
|
@ -6,13 +6,13 @@ _Do you want to share the links you discover?_
|
|||
_Shaarli is a minimalist link sharing service that you can install on your own server._
|
||||
_It is designed to be personal (single-user), fast and handy._
|
||||
|
||||
[![](https://img.shields.io/badge/stable-v0.8.4-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.8.4)
|
||||
[![](https://img.shields.io/badge/stable-v0.8.5-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.8.5)
|
||||
[![](https://img.shields.io/travis/shaarli/Shaarli/stable.svg?label=stable)](https://travis-ci.org/shaarli/Shaarli)
|
||||
•
|
||||
[![](https://img.shields.io/badge/latest-v0.9.2-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.9.2)
|
||||
[![](https://img.shields.io/badge/latest-v0.9.4-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.9.4)
|
||||
[![](https://img.shields.io/travis/shaarli/Shaarli/latest.svg?label=latest)](https://travis-ci.org/shaarli/Shaarli)
|
||||
•
|
||||
[![](https://img.shields.io/badge/master-v0.9.x-blue.svg)](https://github.com/shaarli/Shaarli)
|
||||
[![](https://img.shields.io/badge/master-v0.10.x-blue.svg)](https://github.com/shaarli/Shaarli)
|
||||
[![](https://img.shields.io/travis/shaarli/Shaarli.svg?label=master)](https://travis-ci.org/shaarli/Shaarli)
|
||||
|
||||
[![Join the chat at https://gitter.im/shaarli/Shaarli](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/shaarli/Shaarli)
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* @param string $url URL to get (http://...)
|
||||
* @param int $timeout network timeout (in seconds)
|
||||
* @param int $maxBytes maximum downloaded bytes (default: 4 MiB)
|
||||
* @param callable|string $curlWriteFunction Optional callback called during the download (cURL CURLOPT_WRITEFUNCTION).
|
||||
* Can be used to add download conditions on the headers (response code, content type, etc.).
|
||||
*
|
||||
* @return array HTTP response headers, downloaded content
|
||||
*
|
||||
|
@ -29,7 +31,7 @@
|
|||
* @see http://stackoverflow.com/q/9183178
|
||||
* @see http://stackoverflow.com/q/1462720
|
||||
*/
|
||||
function get_http_response($url, $timeout = 30, $maxBytes = 4194304)
|
||||
function get_http_response($url, $timeout = 30, $maxBytes = 4194304, $curlWriteFunction = null)
|
||||
{
|
||||
$urlObj = new Url($url);
|
||||
$cleanUrl = $urlObj->idnToAscii();
|
||||
|
@ -75,6 +77,10 @@ function get_http_response($url, $timeout = 30, $maxBytes = 4194304)
|
|||
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
|
||||
|
||||
if (is_callable($curlWriteFunction)) {
|
||||
curl_setopt($ch, CURLOPT_WRITEFUNCTION, $curlWriteFunction);
|
||||
}
|
||||
|
||||
// Max download size management
|
||||
curl_setopt($ch, CURLOPT_BUFFERSIZE, 1024*16);
|
||||
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
|
||||
|
|
|
@ -69,6 +69,8 @@ public function __construct($language, $conf)
|
|||
{
|
||||
$this->conf = $conf;
|
||||
$confLanguage = $this->conf->get('translation.language', 'auto');
|
||||
// Auto mode or invalid parameter, use the detected language.
|
||||
// If the detected language is invalid, it doesn't matter, it will use English.
|
||||
if ($confLanguage === 'auto' || ! $this->isValidLanguage($confLanguage)) {
|
||||
$this->language = substr($language, 0, 5);
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,54 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Get cURL callback function for CURLOPT_WRITEFUNCTION
|
||||
*
|
||||
* @param string $charset to extract from the downloaded page (reference)
|
||||
* @param string $title to extract from the downloaded page (reference)
|
||||
* @param string $curlGetInfo Optionnaly overrides curl_getinfo function
|
||||
*
|
||||
* @return Closure
|
||||
*/
|
||||
function get_curl_download_callback(&$charset, &$title, $curlGetInfo = 'curl_getinfo')
|
||||
{
|
||||
/**
|
||||
* cURL callback function for CURLOPT_WRITEFUNCTION (called during the download).
|
||||
*
|
||||
* While downloading the remote page, we check that the HTTP code is 200 and content type is 'html/text'
|
||||
* Then we extract the title and the charset and stop the download when it's done.
|
||||
*
|
||||
* @param resource $ch cURL resource
|
||||
* @param string $data chunk of data being downloaded
|
||||
*
|
||||
* @return int|bool length of $data or false if we need to stop the download
|
||||
*/
|
||||
return function(&$ch, $data) use ($curlGetInfo, &$charset, &$title) {
|
||||
$responseCode = $curlGetInfo($ch, CURLINFO_RESPONSE_CODE);
|
||||
if (!empty($responseCode) && $responseCode != 200) {
|
||||
return false;
|
||||
}
|
||||
$contentType = $curlGetInfo($ch, CURLINFO_CONTENT_TYPE);
|
||||
if (!empty($contentType) && strpos($contentType, 'text/html') === false) {
|
||||
return false;
|
||||
}
|
||||
if (empty($charset)) {
|
||||
$charset = header_extract_charset($contentType);
|
||||
}
|
||||
if (empty($charset)) {
|
||||
$charset = html_extract_charset($data);
|
||||
}
|
||||
if (empty($title)) {
|
||||
$title = html_extract_title($data);
|
||||
}
|
||||
// We got everything we want, stop the download.
|
||||
if (!empty($responseCode) && !empty($contentType) && !empty($charset) && !empty($title)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strlen($data);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract title from an HTML document.
|
||||
*
|
||||
|
@ -16,46 +65,18 @@ function html_extract_title($html)
|
|||
}
|
||||
|
||||
/**
|
||||
* Determine charset from downloaded page.
|
||||
* Priority:
|
||||
* 1. HTTP headers (Content type).
|
||||
* 2. HTML content page (tag <meta charset>).
|
||||
* 3. Use a default charset (default: UTF-8).
|
||||
* Extract charset from HTTP header if it's defined.
|
||||
*
|
||||
* @param array $headers HTTP headers array.
|
||||
* @param string $htmlContent HTML content where to look for charset.
|
||||
* @param string $defaultCharset Default charset to apply if other methods failed.
|
||||
*
|
||||
* @return string Determined charset.
|
||||
*/
|
||||
function get_charset($headers, $htmlContent, $defaultCharset = 'utf-8')
|
||||
{
|
||||
if ($charset = headers_extract_charset($headers)) {
|
||||
return $charset;
|
||||
}
|
||||
|
||||
if ($charset = html_extract_charset($htmlContent)) {
|
||||
return $charset;
|
||||
}
|
||||
|
||||
return $defaultCharset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract charset from HTTP headers if it's defined.
|
||||
*
|
||||
* @param array $headers HTTP headers array.
|
||||
* @param string $header HTTP header Content-Type line.
|
||||
*
|
||||
* @return bool|string Charset string if found (lowercase), false otherwise.
|
||||
*/
|
||||
function headers_extract_charset($headers)
|
||||
function header_extract_charset($header)
|
||||
{
|
||||
if (! empty($headers['Content-Type']) && strpos($headers['Content-Type'], 'charset=') !== false) {
|
||||
preg_match('/charset="?([^; ]+)/i', $headers['Content-Type'], $match);
|
||||
preg_match('/charset="?([^; ]+)/i', $header, $match);
|
||||
if (! empty($match[1])) {
|
||||
return strtolower(trim($match[1]));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -83,10 +83,10 @@ public function read($filepath)
|
|||
|
||||
$out = array();
|
||||
foreach (self::$ROOT_KEYS as $key) {
|
||||
$out[$key] = $GLOBALS[$key];
|
||||
$out[$key] = isset($GLOBALS[$key]) ? $GLOBALS[$key] : '';
|
||||
}
|
||||
$out['config'] = $GLOBALS['config'];
|
||||
$out['plugins'] = !empty($GLOBALS['plugins']) ? $GLOBALS['plugins'] : array();
|
||||
$out['config'] = isset($GLOBALS['config']) ? $GLOBALS['config'] : [];
|
||||
$out['plugins'] = isset($GLOBALS['plugins']) ? $GLOBALS['plugins'] : [];
|
||||
return $out;
|
||||
}
|
||||
|
||||
|
|
178
composer.lock
generated
178
composer.lock
generated
|
@ -294,16 +294,16 @@
|
|||
},
|
||||
{
|
||||
"name": "pimple/pimple",
|
||||
"version": "v3.2.2",
|
||||
"version": "v3.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/silexphp/Pimple.git",
|
||||
"reference": "4d45fb62d96418396ec58ba76e6f065bca16e10a"
|
||||
"reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/silexphp/Pimple/zipball/4d45fb62d96418396ec58ba76e6f065bca16e10a",
|
||||
"reference": "4d45fb62d96418396ec58ba76e6f065bca16e10a",
|
||||
"url": "https://api.github.com/repos/silexphp/Pimple/zipball/9e403941ef9d65d20cba7d54e29fe906db42cf32",
|
||||
"reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -340,7 +340,7 @@
|
|||
"container",
|
||||
"dependency injection"
|
||||
],
|
||||
"time": "2017-07-23T07:32:15+00:00"
|
||||
"time": "2018-01-21T07:42:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
|
@ -533,16 +533,16 @@
|
|||
},
|
||||
{
|
||||
"name": "shaarli/netscape-bookmark-parser",
|
||||
"version": "v2.0.4",
|
||||
"version": "v2.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/shaarli/netscape-bookmark-parser.git",
|
||||
"reference": "81023979c981514f5dda5582e9c0be2ed6688a6b"
|
||||
"reference": "ea6911a0ea3dd372fa7002593c5aef9c15a49315"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/shaarli/netscape-bookmark-parser/zipball/81023979c981514f5dda5582e9c0be2ed6688a6b",
|
||||
"reference": "81023979c981514f5dda5582e9c0be2ed6688a6b",
|
||||
"url": "https://api.github.com/repos/shaarli/netscape-bookmark-parser/zipball/ea6911a0ea3dd372fa7002593c5aef9c15a49315",
|
||||
"reference": "ea6911a0ea3dd372fa7002593c5aef9c15a49315",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -584,20 +584,20 @@
|
|||
"netscape",
|
||||
"parse"
|
||||
],
|
||||
"time": "2017-07-30T21:08:03+00:00"
|
||||
"time": "2018-01-30T17:34:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "slim/slim",
|
||||
"version": "3.8.1",
|
||||
"version": "3.9.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/slimphp/Slim.git",
|
||||
"reference": "5385302707530b2bccee1769613ad769859b826d"
|
||||
"reference": "4086d0106cf5a7135c69fce4161fe355a8feb118"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/slimphp/Slim/zipball/5385302707530b2bccee1769613ad769859b826d",
|
||||
"reference": "5385302707530b2bccee1769613ad769859b826d",
|
||||
"url": "https://api.github.com/repos/slimphp/Slim/zipball/4086d0106cf5a7135c69fce4161fe355a8feb118",
|
||||
"reference": "4086d0106cf5a7135c69fce4161fe355a8feb118",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -655,7 +655,7 @@
|
|||
"micro",
|
||||
"router"
|
||||
],
|
||||
"time": "2017-03-19T17:55:20+00:00"
|
||||
"time": "2017-11-26T19:13:09+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
|
@ -715,26 +715,26 @@
|
|||
},
|
||||
{
|
||||
"name": "pdepend/pdepend",
|
||||
"version": "2.5.0",
|
||||
"version": "2.5.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pdepend/pdepend.git",
|
||||
"reference": "0c50874333149c0dad5a2877801aed148f2767ff"
|
||||
"reference": "9daf26d0368d4a12bed1cacae1a9f3a6f0adf239"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pdepend/pdepend/zipball/0c50874333149c0dad5a2877801aed148f2767ff",
|
||||
"reference": "0c50874333149c0dad5a2877801aed148f2767ff",
|
||||
"url": "https://api.github.com/repos/pdepend/pdepend/zipball/9daf26d0368d4a12bed1cacae1a9f3a6f0adf239",
|
||||
"reference": "9daf26d0368d4a12bed1cacae1a9f3a6f0adf239",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.7",
|
||||
"symfony/config": "^2.3.0|^3",
|
||||
"symfony/dependency-injection": "^2.3.0|^3",
|
||||
"symfony/filesystem": "^2.3.0|^3"
|
||||
"symfony/config": "^2.3.0|^3|^4",
|
||||
"symfony/dependency-injection": "^2.3.0|^3|^4",
|
||||
"symfony/filesystem": "^2.3.0|^3|^4"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.4.0,<4.8",
|
||||
"phpunit/phpunit": "^4.8|^5.7",
|
||||
"squizlabs/php_codesniffer": "^2.0.0"
|
||||
},
|
||||
"bin": [
|
||||
|
@ -751,7 +751,7 @@
|
|||
"BSD-3-Clause"
|
||||
],
|
||||
"description": "Official version of pdepend to be handled with Composer",
|
||||
"time": "2017-01-19T14:23:36+00:00"
|
||||
"time": "2017-12-13T13:21:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-common",
|
||||
|
@ -967,16 +967,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "v1.7.2",
|
||||
"version": "1.7.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6"
|
||||
"reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6",
|
||||
"reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf",
|
||||
"reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -988,7 +988,7 @@
|
|||
},
|
||||
"require-dev": {
|
||||
"phpspec/phpspec": "^2.5|^3.2",
|
||||
"phpunit/phpunit": "^4.8 || ^5.6.5"
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
|
@ -1026,7 +1026,7 @@
|
|||
"spy",
|
||||
"stub"
|
||||
],
|
||||
"time": "2017-09-04T11:05:03+00:00"
|
||||
"time": "2017-11-24T13:59:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
|
@ -1092,16 +1092,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
"version": "1.4.2",
|
||||
"version": "1.4.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
||||
"reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5"
|
||||
"reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
|
||||
"reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
|
||||
"reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1135,7 +1135,7 @@
|
|||
"filesystem",
|
||||
"iterator"
|
||||
],
|
||||
"time": "2016-10-03T07:40:28+00:00"
|
||||
"time": "2017-11-27T13:52:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-text-template",
|
||||
|
@ -1229,16 +1229,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/php-token-stream",
|
||||
"version": "1.4.11",
|
||||
"version": "1.4.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
|
||||
"reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7"
|
||||
"reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7",
|
||||
"reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16",
|
||||
"reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1274,7 +1274,7 @@
|
|||
"keywords": [
|
||||
"tokenizer"
|
||||
],
|
||||
"time": "2017-02-27T10:12:30+00:00"
|
||||
"time": "2017-12-04T08:55:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpcov",
|
||||
|
@ -1691,20 +1691,20 @@
|
|||
},
|
||||
{
|
||||
"name": "sebastian/finder-facade",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/finder-facade.git",
|
||||
"reference": "2a6f7f57efc0aa2d23297d9fd9e2a03111a8c0b9"
|
||||
"reference": "4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/2a6f7f57efc0aa2d23297d9fd9e2a03111a8c0b9",
|
||||
"reference": "2a6f7f57efc0aa2d23297d9fd9e2a03111a8c0b9",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f",
|
||||
"reference": "4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"symfony/finder": "~2.3|~3.0",
|
||||
"symfony/finder": "~2.3|~3.0|~4.0",
|
||||
"theseer/fdomdocument": "~1.3"
|
||||
},
|
||||
"type": "library",
|
||||
|
@ -1726,7 +1726,7 @@
|
|||
],
|
||||
"description": "FinderFacade is a convenience wrapper for Symfony's Finder component.",
|
||||
"homepage": "https://github.com/sebastianbergmann/finder-facade",
|
||||
"time": "2016-02-17T07:02:23+00:00"
|
||||
"time": "2017-11-18T17:31:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/global-state",
|
||||
|
@ -1998,30 +1998,30 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/config",
|
||||
"version": "v3.3.10",
|
||||
"version": "v3.4.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/config.git",
|
||||
"reference": "4ab62407bff9cd97c410a7feaef04c375aaa5cfd"
|
||||
"reference": "72689b934d6c6ecf73eca874e98933bf055313c9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/config/zipball/4ab62407bff9cd97c410a7feaef04c375aaa5cfd",
|
||||
"reference": "4ab62407bff9cd97c410a7feaef04c375aaa5cfd",
|
||||
"url": "https://api.github.com/repos/symfony/config/zipball/72689b934d6c6ecf73eca874e98933bf055313c9",
|
||||
"reference": "72689b934d6c6ecf73eca874e98933bf055313c9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.5.9|>=7.0.8",
|
||||
"symfony/filesystem": "~2.8|~3.0"
|
||||
"symfony/filesystem": "~2.8|~3.0|~4.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/dependency-injection": "<3.3",
|
||||
"symfony/finder": "<3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/dependency-injection": "~3.3",
|
||||
"symfony/finder": "~3.3",
|
||||
"symfony/yaml": "~3.0"
|
||||
"symfony/dependency-injection": "~3.3|~4.0",
|
||||
"symfony/finder": "~3.3|~4.0",
|
||||
"symfony/yaml": "~3.0|~4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/yaml": "To use the yaml reference dumper"
|
||||
|
@ -2029,7 +2029,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.3-dev"
|
||||
"dev-master": "3.4-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -2056,20 +2056,20 @@
|
|||
],
|
||||
"description": "Symfony Config Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-10-04T18:56:58+00:00"
|
||||
"time": "2018-01-21T19:05:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v2.8.28",
|
||||
"version": "v2.8.34",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853"
|
||||
"reference": "162ca7d0ea597599967aa63b23418e747da0896b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/f81549d2c5fdee8d711c9ab3c7e7362353ea5853",
|
||||
"reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/162ca7d0ea597599967aa63b23418e747da0896b",
|
||||
"reference": "162ca7d0ea597599967aa63b23418e747da0896b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2117,7 +2117,7 @@
|
|||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-10-01T21:00:16+00:00"
|
||||
"time": "2018-01-29T08:54:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/debug",
|
||||
|
@ -2178,16 +2178,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/dependency-injection",
|
||||
"version": "v3.3.10",
|
||||
"version": "v3.3.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dependency-injection.git",
|
||||
"reference": "8ebad929aee3ca185b05f55d9cc5521670821ad1"
|
||||
"reference": "54243abc4e1a1a15e274e391bd6f7090b44711f1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/8ebad929aee3ca185b05f55d9cc5521670821ad1",
|
||||
"reference": "8ebad929aee3ca185b05f55d9cc5521670821ad1",
|
||||
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/54243abc4e1a1a15e274e391bd6f7090b44711f1",
|
||||
"reference": "54243abc4e1a1a15e274e391bd6f7090b44711f1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2195,7 +2195,7 @@
|
|||
"psr/container": "^1.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/config": "<3.3.1",
|
||||
"symfony/config": "<3.3.7",
|
||||
"symfony/finder": "<3.3",
|
||||
"symfony/yaml": "<3.3"
|
||||
},
|
||||
|
@ -2244,20 +2244,20 @@
|
|||
],
|
||||
"description": "Symfony DependencyInjection Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-10-04T17:15:30+00:00"
|
||||
"time": "2018-01-29T09:02:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v3.3.10",
|
||||
"version": "v3.4.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1"
|
||||
"reference": "e078773ad6354af38169faf31c21df0f18ace03d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/90bc45abf02ae6b7deb43895c1052cb0038506f1",
|
||||
"reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/e078773ad6354af38169faf31c21df0f18ace03d",
|
||||
"reference": "e078773ad6354af38169faf31c21df0f18ace03d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2266,7 +2266,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.3-dev"
|
||||
"dev-master": "3.4-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -2293,20 +2293,20 @@
|
|||
],
|
||||
"description": "Symfony Filesystem Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-10-03T13:33:10+00:00"
|
||||
"time": "2018-01-03T07:37:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v3.3.10",
|
||||
"version": "v3.4.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "773e19a491d97926f236942484cb541560ce862d"
|
||||
"reference": "613e26310776f49a1773b6737c6bd554b8bc8c6f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/773e19a491d97926f236942484cb541560ce862d",
|
||||
"reference": "773e19a491d97926f236942484cb541560ce862d",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/613e26310776f49a1773b6737c6bd554b8bc8c6f",
|
||||
"reference": "613e26310776f49a1773b6737c6bd554b8bc8c6f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2315,7 +2315,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.3-dev"
|
||||
"dev-master": "3.4-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -2342,7 +2342,7 @@
|
|||
],
|
||||
"description": "Symfony Finder Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-10-02T06:42:24+00:00"
|
||||
"time": "2018-01-03T07:37:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
|
@ -2405,16 +2405,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v3.3.10",
|
||||
"version": "v3.3.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46"
|
||||
"reference": "af615970e265543a26ee712c958404eb9b7ac93d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46",
|
||||
"reference": "8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/af615970e265543a26ee712c958404eb9b7ac93d",
|
||||
"reference": "af615970e265543a26ee712c958404eb9b7ac93d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2456,7 +2456,7 @@
|
|||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-10-05T14:43:42+00:00"
|
||||
"time": "2018-01-20T15:04:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "theseer/fdomdocument",
|
||||
|
@ -2500,16 +2500,16 @@
|
|||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
"version": "1.2.0",
|
||||
"version": "1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/webmozart/assert.git",
|
||||
"reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f"
|
||||
"reference": "0df1908962e7a3071564e857d86874dad1ef204a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f",
|
||||
"reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f",
|
||||
"url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a",
|
||||
"reference": "0df1908962e7a3071564e857d86874dad1ef204a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2546,7 +2546,7 @@
|
|||
"check",
|
||||
"validate"
|
||||
],
|
||||
"time": "2016-11-23T20:04:58+00:00"
|
||||
"time": "2018-01-29T19:49:41+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
|
|
@ -45,6 +45,10 @@ Shaarli cannot import data directly from [Scuttle](https://github.com/scronide/s
|
|||
However, you can use the third-party [scuttle-to-shaarli](https://github.com/q2apro/scuttle-to-shaarli)
|
||||
tool to export the Scuttle database to the Netscape HTML format compatible with the Shaarli importer.
|
||||
|
||||
### Refind
|
||||
|
||||
You can use the third-party tool [Derefind](https://github.com/ShawnPConroy/Derefind) to convert refind.com bookmark exports to a format that can be imported into Shaarli.
|
||||
|
||||
## Import Shaarli links to Firefox
|
||||
|
||||
- Export your Shaarli links as described above.
|
||||
|
|
|
@ -21,7 +21,7 @@ _This bookmarklet button is compatible with Firefox, Opera, Chrome and Safari. U
|
|||
|
||||
Websites which enforce Content Security Policy (CSP), such as github.com, disallow usage of bookmarklets. Unfortunatly, there is nothing Shaarli can do about it.
|
||||
|
||||
See [#196](https://github.com/shaarli/Shaarli#196).
|
||||
See [#196](https://github.com/shaarli/Shaarli/issues/196).
|
||||
|
||||
There is an open bug for both Firefox and Chromium:
|
||||
|
||||
|
|
|
@ -14,10 +14,24 @@ Use the `Filter by tags` field to restrict displayed links to entries tagged wit
|
|||
|
||||
**Hidden tags:** Tags starting with a dot `.` (example `.secret`) are private. They can only be seen and searched when logged in.
|
||||
|
||||
Alternatively you can use the `Tag cloud` to discover all tags and click on any of them to display related links.
|
||||
### Tag cloud
|
||||
|
||||
To search for links that are not tagged, enter `""` in the tag search field.
|
||||
The `Tag cloud` page diplays a "cloud" view of all tags in your Shaarli.
|
||||
|
||||
* The most frequently used tags are displayed with a bigger font size.
|
||||
* When sorting by `Most used` or `Alphabetical`, tags are displayed as a _list_, along with counters and edit/delete buttons for each tag.
|
||||
* Clicking on any tag will display a list of all Shaares matching this tag.
|
||||
* Clicking on the counter next to a tag `example`, will filter the tag cloud to only display tags found in Shaares tagged `example`. Repeat this any number of times to further filter the tag cloud. Click `List all links with those tags` to display Shaares matching your current tag filter.
|
||||
|
||||
## Filtering RSS feeds/Picture wall
|
||||
|
||||
RSS feeds can also be restricted to only return items matching a text/tag search: see [RSS feeds](RSS-feeds).
|
||||
|
||||
## Filter buttons
|
||||
|
||||
Filter buttons can be found at the top left of the link list. They allow you to apply different filters to the list:
|
||||
|
||||
* **Private links:** When this toggle button is enabled, only shaares set to `private` will be shown.
|
||||
* **Untagged links:** When the this toggle button is enabled (top left of the link list), only shaares _without any tags_ will be shown in the link list.
|
||||
|
||||
Filter buttons are only available when logged in.
|
||||
|
|
|
@ -1,6 +1,59 @@
|
|||
_Unofficial but related work on Shaarli. If you maintain one of these,
|
||||
please get in touch with us to help us find a way to adapt your work to our fork._
|
||||
|
||||
## Related software
|
||||
|
||||
|
||||
### REST API clients
|
||||
See [REST API](REST-API) for a list of official and community clients.
|
||||
|
||||
|
||||
### Third party plugins
|
||||
- [autosave](https://github.com/kalvn/shaarli-plugin-autosave) by [@kalvn](https://github.com/kalvn): Automatically saves data when editing a link to avoid any loss in case of crash or unexpected shutdown.
|
||||
- [Code Coloration](https://github.com/ArthurHoaro/code-coloration) by [@ArthurHoaro](https://github.com/ArthurHoaro): client side code syntax highlighter.
|
||||
- [Disqus](https://github.com/kalvn/shaarli-plugin-disqus) by [@kalvn](https://github.com/kalvn): Adds Disqus comment system to your Shaarli.
|
||||
- [emojione](https://github.com/NerosTie/emojione) by [@NerosTie](https://github.com/NerosTie): Add colorful emojis to your Shaarli.
|
||||
- [twemoji](https://github.com/NerosTie/twemoji) by [@NerosTie](https://github.com/NerosTie): Add colorful emojis to your Shaarli (Twemoji version)
|
||||
- [google analytics](https://github.com/ericjuden/Shaarli-Google-Analytics-Plugin) by [@ericjuden](http://github.com/ericjuden): Adds Google Analytics tracking support
|
||||
- [launch](https://github.com/ArthurHoaro/launch-plugin) - Launch Plugin is a plugin designed to enhance and customize Launch Theme for Shaarli.
|
||||
- [markdown-toolbar](https://github.com/immanuelfodor/shaarli-markdown-toolbar) by [@immanuelfodor](https://github.com/immanuelfodor) - Easily insert markdown syntax into the Description field when editing a link.
|
||||
- [related](https://github.com/ilesinge/shaarli-related) by [@ilesinge](https://github.com/ilesinge) - Show related links based on the number of identical tags.
|
||||
- [social](https://github.com/alexisju/social) by [@alexisju](https://github.com/alexisju): share links to social networks.
|
||||
- [shaarli2twitter](https://github.com/ArthurHoaro/shaarli2twitter) by [@ArthurHoaro](https://github.com/ArthurHoaro) - Automatically tweet your shared links from Shaarli
|
||||
- [shaarli2mastodon](https://github.com/kalvn/shaarli2mastodon) by [@kalvn](https://github.com/kalvn) - This Shaarli plugin allows you to automatically publish links you post on your Mastodon timeline.
|
||||
- [shaarli-descriptor](https://github.com/immanuelfodor/shaarli-descriptor) by [@immanuelfodor](https://github.com/immanuelfodor) - Customize the default height/number of rows of the Description field when editing a link.
|
||||
|
||||
|
||||
### Third-party themes
|
||||
See [Theming](Theming) for a list of community-contributed themes, and an installation guide.
|
||||
|
||||
|
||||
### Integration with other platforms
|
||||
- [tt-rss-shaarli](https://github.com/jcsaaddupuy/tt-rss-shaarli) - [Tiny-Tiny RSS](http://tt-rss.org/) plugin that adds support for sharing articles with Shaarli
|
||||
- [octopress-shaarli](https://github.com/ahmet2mir/octopress-shaarli) - Octopress plugin to retrieve Shaarli links on the sidebar
|
||||
- [Scuttle to Shaarli](https://github.com/q2apro/scuttle-to-shaarli) - Import bookmarks from Scuttle
|
||||
|
||||
|
||||
### Mobile Apps
|
||||
- [ShaarliOS](https://github.com/mro/ShaarliOS) - Apple iOS share extension.
|
||||
- [Shaarli for Android](http://sebsauvage.net/links/?ZAyDzg) - Android application that adds Shaarli as a sharing provider
|
||||
- [Shaarlier for Android](https://github.com/dimtion/Shaarlier) - Android application to simply add links directly into your Shaarli
|
||||
|
||||
### Browser addons
|
||||
* [Shaarli Web Extension](https://github.com/ikipatang/shaarli-web-extension) - toolbar button to share your current tab with Shaarli.
|
||||
|
||||
### Server apps
|
||||
- [shaarchiver](https://github.com/nodiscc/shaarchiver) - Archive your Shaarli bookmarks and their content
|
||||
- [shaarli-river](https://github.com/mknexen/shaarli-river) - An aggregator for shaarlis with many features
|
||||
- [Shaarlo](https://github.com/DMeloni/shaarlo) - An aggregator for shaarlis with many features (a very popular running instance among French shaarliers: [shaarli.fr](http://shaarli.fr/))
|
||||
- [Shaarlimages](https://github.com/BoboTiG/shaarlimages) - An image-oriented aggregator for Shaarlis
|
||||
- [mknexen/shaarli-api](https://github.com/mknexen/shaarli-api) - A REST API for Shaarli
|
||||
- [Self dead link](https://github.com/qwertygc/shaarli-dev-code/blob/master/self-dead-link.php) - Detect dead links on shaarli. This version use the database of shaarli. [Another version](https://github.com/qwertygc/shaarli-dev-code/blob/master/dead-link.php), can be used for other shaarli instances (but is more resource consuming).
|
||||
- [Bookmark Archiver](https://github.com/pirate/bookmark-archiver) - Save an archived copy of all websites starred using browser bookmarks/Shaarli/Delicious/Instapaper/Unmark.it/Pocket/Pinboard. Outputs browseable html.
|
||||
|
||||
## Alternatives to Shaarli
|
||||
See [awesome-selfhosted: bookmarks & link sharing](https://github.com/Kickball/awesome-selfhosted/#bookmarks--link-sharing).
|
||||
|
||||
## Community
|
||||
- [Liens en vrac de sebsauvage](http://sebsauvage.net/links/) - the original Shaarli
|
||||
- [A large list of Shaarlis](http://porneia.free.fr/pub/links/ou-est-shaarli.html)
|
||||
|
@ -12,57 +65,8 @@ please get in touch with us to help us find a way to adapt your work to our fork
|
|||
- [Original revisions history](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history)
|
||||
- [Shaarli.fr/my](https://www.shaarli.fr/my.php) - Unofficial, unsupported (old fork) hosted Shaarlis provider, courtesy of [DMeloni](https://github.com/DMeloni)
|
||||
|
||||
|
||||
### Articles and social media discussions
|
||||
- 2016-09-22 - Hacker News - https://news.ycombinator.com/item?id=12552176
|
||||
- 2015-08-15 - Reddit - [Question about migrating from WordPress to Shaarli.](https://www.reddit.com/r/selfhosted/comments/3h3zwh/question_about_migrating_from_wordpress_to_shaarli/)
|
||||
- 2015-06-22 - Hacker News - https://news.ycombinator.com/item?id=9755366
|
||||
- 2015-05-12 - Reddit - [shaarli - Self hosted Bookmarking / Delicious (PHP, MySQL)](https://www.reddit.com/r/selfhosted/comments/35pkkc/shaarli_self_hosted_bookmarking_delicious_php/)
|
||||
|
||||
|
||||
### REST API clients
|
||||
See [REST API](REST-API) for a list of official and community clients.
|
||||
|
||||
|
||||
### Third party plugins
|
||||
- [autosave](https://github.com/kalvn/shaarli-plugin-autosave) by [@kalvn](https://github.com/kalvn): Automatically saves data when editing a link to avoid any loss in case of crash or unexpected shutdown.
|
||||
- [Code Coloration](https://github.com/ArthurHoaro/code-coloration) by [@ArthurHoaro](https://github.com/ArthurHoaro): client side code syntax highlighter.
|
||||
- [Disqus](https://github.com/kalvn/shaarli-plugin-disqus) by [@kalvn](https://github.com/kalvn): Adds Disqus comment system to your Shaarli.
|
||||
- [emojione](https://github.com/NerosTie/emojione) by [@NerosTie](https://github.com/NerosTie): Add colorful emojis to your Shaarli.
|
||||
- [google analytics](https://github.com/ericjuden/Shaarli-Google-Analytics-Plugin) by [@ericjuden](http://github.com/ericjuden): Adds Google Analytics tracking support
|
||||
- [launch](https://github.com/ArthurHoaro/launch-plugin) - Launch Plugin is a plugin designed to enhance and customize Launch Theme for Shaarli.
|
||||
- [related](https://github.com/ilesinge/shaarli-related) by [@ilesinge](https://github.com/ilesinge) - Show related links based on the number of identical tags.
|
||||
- [social](https://github.com/alexisju/social) by [@alexisju](https://github.com/alexisju): share links to social networks.
|
||||
- [shaarli2twitter](https://github.com/ArthurHoaro/shaarli2twitter) by [@ArthurHoaro](https://github.com/ArthurHoaro) - Automatically tweet your shared links from Shaarli
|
||||
- [shaarli2mastodon](https://github.com/kalvn/shaarli2mastodon) by [@kalvn](https://github.com/kalvn) - This Shaarli plugin allows you to automatically publish links you post on your Mastodon timeline.
|
||||
|
||||
|
||||
### Third-party themes
|
||||
See [Theming](Theming) for a list of community-contributed themes, and an installation guide.
|
||||
|
||||
|
||||
## Integration with other platforms
|
||||
- [tt-rss-shaarli](https://github.com/jcsaaddupuy/tt-rss-shaarli) - [Tiny-Tiny RSS](http://tt-rss.org/) plugin that adds support for sharing articles with Shaarli
|
||||
- [octopress-shaarli](https://github.com/ahmet2mir/octopress-shaarli) - Octopress plugin to retrieve Shaarli links on the sidebar
|
||||
- [Scuttle to Shaarli](https://github.com/q2apro/scuttle-to-shaarli) - Import bookmarks from Scuttle
|
||||
|
||||
|
||||
### Mobile Apps
|
||||
- [ShaarliOS](https://github.com/mro/ShaarliOS) iOS share extension - see [#308](https://github.com/shaarli/Shaarli/issues/308#issuecomment-184592070) for some promo codes,
|
||||
- [Shaarli for Android](http://sebsauvage.net/links/?ZAyDzg) - Android application that adds Shaarli as a sharing provider
|
||||
- [Shaarlier for Android](https://github.com/dimtion/Shaarlier) - Android application to simply add links directly into your Shaarli
|
||||
|
||||
|
||||
### Server apps
|
||||
- [shaarchiver](https://github.com/nodiscc/shaarchiver) - Archive your Shaarli bookmarks and their content
|
||||
- [shaarli-river](https://github.com/mknexen/shaarli-river) - An aggregator for shaarlis with many features
|
||||
- [Shaarlo](https://github.com/DMeloni/shaarlo) - An aggregator for shaarlis with many features (a very popular running instance among French shaarliers: [shaarli.fr](http://shaarli.fr/))
|
||||
- [Shaarlimages](https://github.com/BoboTiG/shaarlimages) - An image-oriented aggregator for Shaarlis
|
||||
- [mknexen/shaarli-api](https://github.com/mknexen/shaarli-api) - A REST API for Shaarli
|
||||
- [Self dead link](https://github.com/qwertygc/shaarli-dev-code/blob/master/self-dead-link.php) - Detect dead links on shaarli. This version use the database of shaarli. [Another version](https://github.com/qwertygc/shaarli-dev-code/blob/master/dead-link.php), can be used for other shaarli instances (but is more resource consuming).
|
||||
- [Bookmark Archiver](https://github.com/pirate/bookmark-archiver) - Save an archived copy of all websites starred using browser bookmarks/Shaarli/Delicious/Instapaper/Unmark.it/Pocket/Pinboard. Outputs browseable html.
|
||||
|
||||
|
||||
## Alternatives to Shaarli
|
||||
See the [bookmarks & link sharing](https://github.com/Kickball/awesome-selfhosted/#bookmarks--link-sharing)
|
||||
section on [awesome-selfhosted](https://github.com/Kickball/awesome-selfhosted/).
|
||||
|
|
|
@ -15,7 +15,7 @@ Using one of the following methods:
|
|||
- by downloading full release archives including all dependencies
|
||||
- by downloading Github archives
|
||||
- by cloning the Git repository
|
||||
- using Docker: [see the documentation](docker/shaarli-images)
|
||||
- using Docker: [see the documentation](docker/shaarli-images.md)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
@ -25,11 +25,11 @@ Using one of the following methods:
|
|||
|
||||
In most cases, you should download the latest Shaarli release from the [releases](https://github.com/shaarli/Shaarli/releases) page. **Download our *shaarli-full* archive** to include dependencies.
|
||||
|
||||
The current latest released version is `v0.9.1`
|
||||
The current latest released version is `v0.9.3`
|
||||
|
||||
```bash
|
||||
$ wget https://github.com/shaarli/Shaarli/releases/download/v0.9.1/shaarli-v0.9.1-full.zip
|
||||
$ unzip shaarli-v0.9.1-full.zip
|
||||
$ wget https://github.com/shaarli/Shaarli/releases/download/v0.9.3/shaarli-v0.9.3-full.zip
|
||||
$ unzip shaarli-v0.9.3-full.zip
|
||||
$ mv Shaarli /path/to/shaarli/
|
||||
```
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
| Note | Firefox Share is no longer available for Firefox 57 and later versions. |
|
||||
|---------|---------|
|
||||
|
||||
### Add Shaarli as a sharing service to Firefox
|
||||
|
||||
- Open your Shaarli and `Login`
|
||||
|
|
|
@ -35,7 +35,7 @@ Library | Required? | Usage
|
|||
Extension | Required? | Usage
|
||||
---|:---:|---
|
||||
[`openssl`](http://php.net/manual/en/book.openssl.php) | All | OpenSSL, HTTPS
|
||||
[`php-mbstring`](http://php.net/manual/en/book.mbstring.php) | CentOS, Fedora, RHEL, Windows | multibyte (Unicode) string support
|
||||
[`php-mbstring`](http://php.net/manual/en/book.mbstring.php) | CentOS, Fedora, RHEL, Windows, some hosting providers | multibyte (Unicode) string support
|
||||
[`php-gd`](http://php.net/manual/en/book.image.php) | optional | thumbnail resizing
|
||||
[`php-intl`](http://php.net/manual/en/book.intl.php) | optional | localized text sorting (e.g. `e->è->f`)
|
||||
[`php-curl`](http://php.net/manual/en/book.curl.php) | optional | using cURL for fetching webpages and thumbnails in a more robust way
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
A brief guide on getting starting using docker is given in [Docker 101](docker-101.md).
|
||||
To learn more about user data and how to keep it across versions, please see [Upgrade and Migration](../Upgrade-and-migration.md).
|
||||
|
||||
## Get and run a Shaarli image
|
||||
|
||||
### DockerHub repository
|
||||
|
@ -21,6 +24,7 @@ The `stable` image relies on:
|
|||
- [PHP5-FPM](http://php-fpm.org/)
|
||||
- [Nginx](http://nginx.org/)
|
||||
|
||||
Additional [Dockerfiles](https://github.com/shaarli/Shaarli/tree/master/docker) are provided for the `arm32v7` platform, relying on [Linuxserver.io Alpine armhf images](https://hub.docker.com/r/lsiobase/alpine.armhf/). These images must be built using [`docker build`](https://docs.docker.com/engine/reference/commandline/build/) on an `arm32v7` machine or using an emulator such as [qemu](https://resin.io/blog/building-arm-containers-on-any-x86-machine-even-dockerhub/).
|
||||
|
||||
### Download from DockerHub
|
||||
```bash
|
||||
|
@ -78,3 +82,14 @@ backstabbing_galileo
|
|||
$ docker ps -a
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
```
|
||||
|
||||
### Automatic builds
|
||||
|
||||
Docker users can start a personal instance from an [autobuild image](https://hub.docker.com/r/shaarli/shaarli/). For example to start a temporary Shaarli at ``localhost:8000``, and keep session data (config, storage):
|
||||
```
|
||||
MY_SHAARLI_VOLUME=$(cd /path/to/shaarli/data/ && pwd -P)
|
||||
docker run -ti --rm \
|
||||
-p 8000:80 \
|
||||
-v $MY_SHAARLI_VOLUME:/var/www/shaarli/data \
|
||||
shaarli/shaarli
|
||||
```
|
||||
|
|
|
@ -22,20 +22,25 @@ It runs the latest development version of Shaarli and is updated/reset daily.
|
|||
|
||||
Login: `demo`; Password: `demo`
|
||||
|
||||
Docker users can start a personal instance from an [autobuild image](https://hub.docker.com/r/shaarli/shaarli/). For example to start a temporary Shaarli at ``localhost:8000``, and keep session data (config, storage):
|
||||
```
|
||||
MY_SHAARLI_VOLUME=$(cd /path/to/shaarli/data/ && pwd -P)
|
||||
docker run -ti --rm \
|
||||
-p 8000:80 \
|
||||
-v $MY_SHAARLI_VOLUME:/var/www/shaarli/data \
|
||||
shaarli/shaarli
|
||||
```
|
||||
|
||||
A brief guide on getting starting using docker is given in [Docker 101](docker/docker-101).
|
||||
To learn more about user data and how to keep it across versions, please see [Upgrade and Migration](Upgrade-and-migration) documentation.
|
||||
|
||||
## Features
|
||||
|
||||
Shaarli can be used:
|
||||
|
||||
- to share, comment and save interesting links and news.
|
||||
- to bookmark useful/frequent personal links (as private links) and share them between computers.
|
||||
- as a minimal blog/microblog/writing platform (no character limit).
|
||||
- as a read-it-later list (for example items tagged `readlater`).
|
||||
- to draft and save articles/posts/ideas.
|
||||
- to keep code snippets.
|
||||
- to keep notes and documentation.
|
||||
- as a shared clipboard/notepad/pastebin between machines.
|
||||
- as a todo list.
|
||||
- to store playlists (e.g. with the `music` or `video` tags).
|
||||
- to keep extracts/comments from webpages that may disappear.
|
||||
- to keep track of ongoing discussions (for example items tagged `discussion`).
|
||||
- [to feed RSS aggregators](http://shaarli.chassegnouf.net/?9Efeiw) (planets) with specific tags.
|
||||
- to feed other social networks, blogs... using RSS feeds and external services (dlvr.it, ifttt.com ...).
|
||||
|
||||
### Interface
|
||||
- minimalist design (simple is beautiful)
|
||||
- FAST
|
||||
|
@ -89,14 +94,12 @@ Easily extensible by any client using the REST API exposed by Shaarli.
|
|||
|
||||
See the [API documentation](http://shaarli.github.io/api-documentation/).
|
||||
|
||||
### Other usages
|
||||
Though Shaarli is primarily a bookmarking application, it can serve other purposes
|
||||
(see [Features](Features)):
|
||||
|
||||
- micro-blogging
|
||||
- pastebin
|
||||
- online notepad
|
||||
- snippet archive
|
||||
### Using Shaarli as a blog, notepad, pastebin...
|
||||
- Go to your Shaarli setup and log in
|
||||
- Click the `Add Link` button
|
||||
- To share text only, do not enter any URL in the corresponding input field and click `Add Link`
|
||||
- Pick a title and enter your article, or note, in the description field; add a few tags; optionally check `Private` then click `Save`
|
||||
- Voilà! Your article is now published (privately if you selected that option) and accessible using its permalink.
|
||||
|
||||
## About
|
||||
### Shaarli community fork
|
||||
|
|
47
docker/alpine/Dockerfile.armhf.latest
Normal file
47
docker/alpine/Dockerfile.armhf.latest
Normal file
|
@ -0,0 +1,47 @@
|
|||
FROM lsiobase/alpine.armhf:3.6
|
||||
MAINTAINER Shaarli Community
|
||||
|
||||
RUN apk --update --no-cache add \
|
||||
ca-certificates \
|
||||
curl \
|
||||
nginx \
|
||||
php7 \
|
||||
php7-ctype \
|
||||
php7-curl \
|
||||
php7-fpm \
|
||||
php7-gd \
|
||||
php7-iconv \
|
||||
php7-intl \
|
||||
php7-json \
|
||||
php7-mbstring \
|
||||
php7-openssl \
|
||||
php7-phar \
|
||||
php7-session \
|
||||
php7-xml \
|
||||
php7-zlib \
|
||||
s6
|
||||
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
COPY php-fpm.conf /etc/php7/php-fpm.conf
|
||||
COPY services.d /etc/services.d
|
||||
|
||||
RUN curl -sS https://getcomposer.org/installer | php7 -- --install-dir=/usr/local/bin --filename=composer \
|
||||
&& rm -rf /etc/php7/php-fpm.d/www.conf \
|
||||
&& sed -i 's/post_max_size.*/post_max_size = 10M/' /etc/php7/php.ini \
|
||||
&& sed -i 's/upload_max_filesize.*/upload_max_filesize = 10M/' /etc/php7/php.ini
|
||||
|
||||
|
||||
WORKDIR /var/www
|
||||
RUN curl -L https://github.com/shaarli/Shaarli/archive/latest.tar.gz | tar xzf - \
|
||||
&& mv Shaarli-latest shaarli \
|
||||
&& cd shaarli \
|
||||
&& composer --prefer-dist --no-dev install \
|
||||
&& rm -rf ~/.composer \
|
||||
&& chown -R nginx:nginx .
|
||||
|
||||
VOLUME /var/www/shaarli/data
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
ENTRYPOINT ["/bin/s6-svscan", "/etc/services.d"]
|
||||
CMD []
|
47
docker/alpine/Dockerfile.armhf.master
Normal file
47
docker/alpine/Dockerfile.armhf.master
Normal file
|
@ -0,0 +1,47 @@
|
|||
FROM lsiobase/alpine.armhf:3.6
|
||||
MAINTAINER Shaarli Community
|
||||
|
||||
RUN apk --update --no-cache add \
|
||||
ca-certificates \
|
||||
curl \
|
||||
nginx \
|
||||
php7 \
|
||||
php7-ctype \
|
||||
php7-curl \
|
||||
php7-fpm \
|
||||
php7-gd \
|
||||
php7-iconv \
|
||||
php7-intl \
|
||||
php7-json \
|
||||
php7-mbstring \
|
||||
php7-openssl \
|
||||
php7-phar \
|
||||
php7-session \
|
||||
php7-xml \
|
||||
php7-zlib \
|
||||
s6
|
||||
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
COPY php-fpm.conf /etc/php7/php-fpm.conf
|
||||
COPY services.d /etc/services.d
|
||||
|
||||
RUN curl -sS https://getcomposer.org/installer | php7 -- --install-dir=/usr/local/bin --filename=composer \
|
||||
&& rm -rf /etc/php7/php-fpm.d/www.conf \
|
||||
&& sed -i 's/post_max_size.*/post_max_size = 10M/' /etc/php7/php.ini \
|
||||
&& sed -i 's/upload_max_filesize.*/upload_max_filesize = 10M/' /etc/php7/php.ini
|
||||
|
||||
|
||||
WORKDIR /var/www
|
||||
RUN curl -L https://github.com/shaarli/Shaarli/archive/master.tar.gz | tar xzf - \
|
||||
&& mv Shaarli-master shaarli \
|
||||
&& cd shaarli \
|
||||
&& composer --prefer-dist --no-dev install \
|
||||
&& rm -rf ~/.composer \
|
||||
&& chown -R nginx:nginx .
|
||||
|
||||
VOLUME /var/www/shaarli/data
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
ENTRYPOINT ["/bin/s6-svscan", "/etc/services.d"]
|
||||
CMD []
|
17
index.php
17
index.php
|
@ -124,6 +124,11 @@
|
|||
$conf = new ConfigManager();
|
||||
$sessionManager = new SessionManager($_SESSION, $conf);
|
||||
|
||||
// LC_MESSAGES isn't defined without php-intl, in this case use LC_COLLATE locale instead.
|
||||
if (! defined('LC_MESSAGES')) {
|
||||
define('LC_MESSAGES', LC_COLLATE);
|
||||
}
|
||||
|
||||
// Sniff browser language and set date format accordingly.
|
||||
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
|
||||
autoLocale($_SERVER['HTTP_ACCEPT_LANGUAGE']);
|
||||
|
@ -436,7 +441,7 @@ function ban_canLogin($conf)
|
|||
else
|
||||
{
|
||||
ban_loginFailed($conf);
|
||||
$redir = '&username='. $_POST['login'];
|
||||
$redir = '&username='. urlencode($_POST['login']);
|
||||
if (isset($_GET['post'])) {
|
||||
$redir .= '&post=' . urlencode($_GET['post']);
|
||||
foreach (array('description', 'source', 'title', 'tags') as $param) {
|
||||
|
@ -1443,18 +1448,12 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager)
|
|||
// If this is an HTTP(S) link, we try go get the page to extract the title (otherwise we will to straight to the edit form.)
|
||||
if (empty($title) && strpos(get_url_scheme($url), 'http') !== false) {
|
||||
// Short timeout to keep the application responsive
|
||||
list($headers, $content) = get_http_response($url, 4);
|
||||
if (strpos($headers[0], '200 OK') !== false) {
|
||||
// Retrieve charset.
|
||||
$charset = get_charset($headers, $content);
|
||||
// Extract title.
|
||||
$title = html_extract_title($content);
|
||||
// Re-encode title in utf-8 if necessary.
|
||||
// The callback will fill $charset and $title with data from the downloaded page.
|
||||
get_http_response($url, 25, 4194304, get_curl_download_callback($charset, $title));
|
||||
if (! empty($title) && strtolower($charset) != 'utf-8') {
|
||||
$title = mb_convert_encoding($title, 'utf-8', $charset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($url == '') {
|
||||
$url = '?' . smallHash($linkdate . $LINKSDB->getNextId());
|
||||
|
|
|
@ -22,16 +22,15 @@ pages:
|
|||
- Reverse proxy configuration: docker/reverse-proxy-configuration.md
|
||||
- Docker resources: docker/resources.md
|
||||
- Usage:
|
||||
- Features: Features.md
|
||||
- Bookmarklet: Bookmarklet.md
|
||||
- Browsing and searching: Browsing-and-searching.md
|
||||
- Firefox share: Firefox-share.md
|
||||
- RSS feeds: RSS-feeds.md
|
||||
- REST API: REST-API.md
|
||||
- Community & Related software: Community-&-Related-software.md
|
||||
- How To:
|
||||
- Backup, restore, import and export: Backup,-restore,-import-and-export.md
|
||||
- Various hacks: Various-hacks.md
|
||||
- Troubleshooting: Troubleshooting.md
|
||||
- Development:
|
||||
- Development guidelines: Development-guidelines.md
|
||||
- Continuous integration tools: Continuous-integration-tools.md
|
||||
|
@ -47,6 +46,5 @@ pages:
|
|||
- Theming: Theming.md
|
||||
- Unit tests: Unit-tests.md
|
||||
- Unit tests inside Docker: Unit-tests-Docker.md
|
||||
- About:
|
||||
- FAQ: FAQ.md
|
||||
- Community & Related software: Community-&-Related-software.md
|
||||
- FAQ: FAQ.md
|
||||
- Troubleshooting: Troubleshooting.md
|
||||
|
|
|
@ -1 +1 @@
|
|||
<?php /* 0.9.2 */ ?>
|
||||
<?php /* 0.9.5 */ ?>
|
||||
|
|
|
@ -28,28 +28,14 @@ public function testHtmlExtractNonExistentTitle()
|
|||
$this->assertFalse(html_extract_title($html));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_charset() with all priorities.
|
||||
*/
|
||||
public function testGetCharset()
|
||||
{
|
||||
$headers = array('Content-Type' => 'text/html; charset=Headers');
|
||||
$html = '<html><meta>stuff</meta><meta charset="Html"/></html>';
|
||||
$default = 'default';
|
||||
$this->assertEquals('headers', get_charset($headers, $html, $default));
|
||||
$this->assertEquals('html', get_charset(array(), $html, $default));
|
||||
$this->assertEquals($default, get_charset(array(), '', $default));
|
||||
$this->assertEquals('utf-8', get_charset(array(), ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test headers_extract_charset() when the charset is found.
|
||||
*/
|
||||
public function testHeadersExtractExistentCharset()
|
||||
{
|
||||
$charset = 'x-MacCroatian';
|
||||
$headers = array('Content-Type' => 'text/html; charset='. $charset);
|
||||
$this->assertEquals(strtolower($charset), headers_extract_charset($headers));
|
||||
$headers = 'text/html; charset='. $charset;
|
||||
$this->assertEquals(strtolower($charset), header_extract_charset($headers));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,11 +43,11 @@ public function testHeadersExtractExistentCharset()
|
|||
*/
|
||||
public function testHeadersExtractNonExistentCharset()
|
||||
{
|
||||
$headers = array();
|
||||
$this->assertFalse(headers_extract_charset($headers));
|
||||
$headers = '';
|
||||
$this->assertFalse(header_extract_charset($headers));
|
||||
|
||||
$headers = array('Content-Type' => 'text/html');
|
||||
$this->assertFalse(headers_extract_charset($headers));
|
||||
$headers = 'text/html';
|
||||
$this->assertFalse(header_extract_charset($headers));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,6 +71,131 @@ public function testHtmlExtractNonExistentCharset()
|
|||
$this->assertFalse(html_extract_charset($html));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the download callback with valid value
|
||||
*/
|
||||
public function testCurlDownloadCallbackOk()
|
||||
{
|
||||
$callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ok');
|
||||
$data = [
|
||||
'HTTP/1.1 200 OK',
|
||||
'Server: GitHub.com',
|
||||
'Date: Sat, 28 Oct 2017 12:01:33 GMT',
|
||||
'Content-Type: text/html; charset=utf-8',
|
||||
'Status: 200 OK',
|
||||
'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea',
|
||||
'<title>ignored</title>',
|
||||
];
|
||||
foreach ($data as $key => $line) {
|
||||
$ignore = null;
|
||||
$expected = $key !== 'end' ? strlen($line) : false;
|
||||
$this->assertEquals($expected, $callback($ignore, $line));
|
||||
if ($expected === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->assertEquals('utf-8', $charset);
|
||||
$this->assertEquals('Refactoring · GitHub', $title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the download callback with valid values and no charset
|
||||
*/
|
||||
public function testCurlDownloadCallbackOkNoCharset()
|
||||
{
|
||||
$callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_no_charset');
|
||||
$data = [
|
||||
'HTTP/1.1 200 OK',
|
||||
'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea',
|
||||
'<title>ignored</title>',
|
||||
];
|
||||
foreach ($data as $key => $line) {
|
||||
$ignore = null;
|
||||
$this->assertEquals(strlen($line), $callback($ignore, $line));
|
||||
}
|
||||
$this->assertEmpty($charset);
|
||||
$this->assertEquals('Refactoring · GitHub', $title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the download callback with valid values and no charset
|
||||
*/
|
||||
public function testCurlDownloadCallbackOkHtmlCharset()
|
||||
{
|
||||
$callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_no_charset');
|
||||
$data = [
|
||||
'HTTP/1.1 200 OK',
|
||||
'<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',
|
||||
'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea',
|
||||
'<title>ignored</title>',
|
||||
];
|
||||
foreach ($data as $key => $line) {
|
||||
$ignore = null;
|
||||
$expected = $key !== 'end' ? strlen($line) : false;
|
||||
$this->assertEquals($expected, $callback($ignore, $line));
|
||||
if ($expected === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->assertEquals('utf-8', $charset);
|
||||
$this->assertEquals('Refactoring · GitHub', $title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the download callback with valid values and no title
|
||||
*/
|
||||
public function testCurlDownloadCallbackOkNoTitle()
|
||||
{
|
||||
$callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ok');
|
||||
$data = [
|
||||
'HTTP/1.1 200 OK',
|
||||
'end' => 'th=device-width">Refactoring · GitHub<link rel="search" type="application/opensea',
|
||||
'ignored',
|
||||
];
|
||||
foreach ($data as $key => $line) {
|
||||
$ignore = null;
|
||||
$this->assertEquals(strlen($line), $callback($ignore, $line));
|
||||
}
|
||||
$this->assertEquals('utf-8', $charset);
|
||||
$this->assertEmpty($title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the download callback with an invalid content type.
|
||||
*/
|
||||
public function testCurlDownloadCallbackInvalidContentType()
|
||||
{
|
||||
$callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ct_ko');
|
||||
$ignore = null;
|
||||
$this->assertFalse($callback($ignore, ''));
|
||||
$this->assertEmpty($charset);
|
||||
$this->assertEmpty($title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the download callback with an invalid response code.
|
||||
*/
|
||||
public function testCurlDownloadCallbackInvalidResponseCode()
|
||||
{
|
||||
$callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_rc_ko');
|
||||
$ignore = null;
|
||||
$this->assertFalse($callback($ignore, ''));
|
||||
$this->assertEmpty($charset);
|
||||
$this->assertEmpty($title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the download callback with an invalid content type and response code.
|
||||
*/
|
||||
public function testCurlDownloadCallbackInvalidContentTypeAndResponseCode()
|
||||
{
|
||||
$callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_rs_ct_ko');
|
||||
$ignore = null;
|
||||
$this->assertFalse($callback($ignore, ''));
|
||||
$this->assertEmpty($charset);
|
||||
$this->assertEmpty($title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test count_private.
|
||||
*/
|
||||
|
@ -207,3 +318,96 @@ private function getHashtagLink($hashtag, $index = '')
|
|||
return str_replace('$1', $hashtag, $hashtagLink);
|
||||
}
|
||||
}
|
||||
|
||||
// old style mock: PHPUnit doesn't allow function mock
|
||||
|
||||
/**
|
||||
* Returns code 200 or html content type.
|
||||
*
|
||||
* @param resource $ch cURL resource
|
||||
* @param int $type cURL info type
|
||||
*
|
||||
* @return int|string 200 or 'text/html'
|
||||
*/
|
||||
function ut_curl_getinfo_ok($ch, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case CURLINFO_RESPONSE_CODE:
|
||||
return 200;
|
||||
case CURLINFO_CONTENT_TYPE:
|
||||
return 'text/html; charset=utf-8';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns code 200 or html content type without charset.
|
||||
*
|
||||
* @param resource $ch cURL resource
|
||||
* @param int $type cURL info type
|
||||
*
|
||||
* @return int|string 200 or 'text/html'
|
||||
*/
|
||||
function ut_curl_getinfo_no_charset($ch, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case CURLINFO_RESPONSE_CODE:
|
||||
return 200;
|
||||
case CURLINFO_CONTENT_TYPE:
|
||||
return 'text/html';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalid response code.
|
||||
*
|
||||
* @param resource $ch cURL resource
|
||||
* @param int $type cURL info type
|
||||
*
|
||||
* @return int|string 404 or 'text/html'
|
||||
*/
|
||||
function ut_curl_getinfo_rc_ko($ch, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case CURLINFO_RESPONSE_CODE:
|
||||
return 404;
|
||||
case CURLINFO_CONTENT_TYPE:
|
||||
return 'text/html; charset=utf-8';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalid content type.
|
||||
*
|
||||
* @param resource $ch cURL resource
|
||||
* @param int $type cURL info type
|
||||
*
|
||||
* @return int|string 200 or 'text/plain'
|
||||
*/
|
||||
function ut_curl_getinfo_ct_ko($ch, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case CURLINFO_RESPONSE_CODE:
|
||||
return 200;
|
||||
case CURLINFO_CONTENT_TYPE:
|
||||
return 'text/plain';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalid response code and content type.
|
||||
*
|
||||
* @param resource $ch cURL resource
|
||||
* @param int $type cURL info type
|
||||
*
|
||||
* @return int|string 404 or 'text/plain'
|
||||
*/
|
||||
function ut_curl_getinfo_rs_ct_ko($ch, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case CURLINFO_RESPONSE_CODE:
|
||||
return 404;
|
||||
case CURLINFO_CONTENT_TYPE:
|
||||
return 'text/plain';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,20 @@ public function testReadNonExistent()
|
|||
$this->assertEquals(array(), $this->configIO->read('nope'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an empty existent config file -> array with blank default values.
|
||||
*/
|
||||
public function testReadEmpty()
|
||||
{
|
||||
$dataFile = 'tests/utils/config/emptyConfigPhp.php';
|
||||
$conf = $this->configIO->read($dataFile);
|
||||
$this->assertEmpty($conf['login']);
|
||||
$this->assertEmpty($conf['title']);
|
||||
$this->assertEmpty($conf['titleLink']);
|
||||
$this->assertEmpty($conf['config']);
|
||||
$this->assertEmpty($conf['plugins']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a new config file.
|
||||
*/
|
||||
|
|
1
tests/utils/config/emptyConfigPhp.php
Normal file
1
tests/utils/config/emptyConfigPhp.php
Normal file
|
@ -0,0 +1 @@
|
|||
<?php
|
|
@ -1,7 +1,7 @@
|
|||
<div class="shaarli-menu pure-g" id="shaarli-menu">
|
||||
<div class="pure-u-lg-0 pure-u-1">
|
||||
<div class="pure-menu">
|
||||
<a href="{$titleLink}" class="pure-menu-link">
|
||||
<a href="{$titleLink}" class="pure-menu-link shaarli-title" id="shaarli-title-mobile">
|
||||
<img src="img/icon.png" width="16" height="16" class="head-logo" alt="logo" />
|
||||
{$shaarlititle}
|
||||
</a>
|
||||
|
@ -12,32 +12,32 @@
|
|||
<div class="pure-menu menu-transform pure-menu-horizontal pure-g">
|
||||
<ul class="pure-menu-list pure-u-lg-5-6 pure-u-1">
|
||||
<li class="pure-menu-item pure-u-0 pure-u-lg-visible">
|
||||
<a href="{$titleLink}" class="pure-menu-link">
|
||||
<a href="{$titleLink}" class="pure-menu-link shaarli-title" id="shaarli-title-desktop">
|
||||
<img src="img/icon.png" width="16" height="16" class="head-logo" alt="logo" />
|
||||
{$shaarlititle}
|
||||
</a>
|
||||
</li>
|
||||
{if="isLoggedIn() || $openshaarli"}
|
||||
<li class="pure-menu-item">
|
||||
<a href="?do=addlink" class="pure-menu-link">
|
||||
<a href="?do=addlink" class="pure-menu-link" id="shaarli-menu-shaare">
|
||||
<i class="fa fa-plus" ></i> {'Shaare'|t}
|
||||
</a>
|
||||
</li>
|
||||
<li class="pure-menu-item">
|
||||
<li class="pure-menu-item" id="shaarli-menu-tools">
|
||||
<a href="?do=tools" class="pure-menu-link">{'Tools'|t}</a>
|
||||
</li>
|
||||
{/if}
|
||||
<li class="pure-menu-item">
|
||||
<li class="pure-menu-item" id="shaarli-menu-tags">
|
||||
<a href="?do=tagcloud" class="pure-menu-link">{'Tag cloud'|t}</a>
|
||||
</li>
|
||||
<li class="pure-menu-item">
|
||||
<li class="pure-menu-item" id="shaarli-menu-picwall">
|
||||
<a href="?do=picwall{$searchcrits}" class="pure-menu-link">{'Picture wall'|t}</a>
|
||||
</li>
|
||||
<li class="pure-menu-item">
|
||||
<li class="pure-menu-item" id="shaarli-menu-daily">
|
||||
<a href="?do=daily" class="pure-menu-link">{'Daily'|t}</a>
|
||||
</li>
|
||||
{loop="$plugins_header.buttons_toolbar"}
|
||||
<li class="pure-menu-item">
|
||||
<li class="pure-menu-item shaarli-menu-plugin">
|
||||
<a
|
||||
{$value.attr.class=isset($value.class) ? $value.attr.class . ' pure-menu-link' : 'pure-menu-link'}
|
||||
{loop="$value.attr"}
|
||||
|
@ -47,35 +47,35 @@
|
|||
</a>
|
||||
</li>
|
||||
{/loop}
|
||||
<li class="pure-menu-item pure-u-lg-0">
|
||||
<li class="pure-menu-item pure-u-lg-0 shaarli-menu-mobile" id="shaarli-menu-mobile-rss">
|
||||
<a href="?do={$feed_type}{$searchcrits}" class="pure-menu-link">{'RSS Feed'|t}</a>
|
||||
</li>
|
||||
{if="isLoggedIn()"}
|
||||
<li class="pure-menu-item pure-u-lg-0">
|
||||
<li class="pure-menu-item pure-u-lg-0 shaarli-menu-mobile" id="shaarli-menu-mobile-logout">
|
||||
<a href="?do=logout" class="pure-menu-link">{'Logout'|t}</a>
|
||||
</li>
|
||||
{else}
|
||||
<li class="pure-menu-item pure-u-lg-0">
|
||||
<li class="pure-menu-item pure-u-lg-0 shaarli-menu-mobile" id="shaarli-menu-mobile-login">
|
||||
<a href="?do=login" class="pure-menu-link">{'Login'|t}</a>
|
||||
</li>
|
||||
{/if}
|
||||
</ul>
|
||||
<div class="header-buttons pure-u-lg-1-6 pure-u-0 pure-u-lg-visible">
|
||||
<ul class="pure-menu-list">
|
||||
<li class="pure-menu-item">
|
||||
<li class="pure-menu-item" id="shaarli-menu-desktop-search">
|
||||
<a href="#" class="pure-menu-link subheader-opener"
|
||||
data-open-id="search"
|
||||
id="search-button" title="{'Search'|t}">
|
||||
<i class="fa fa-search"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="pure-menu-item">
|
||||
<li class="pure-menu-item" id="shaarli-menu-desktop-rss">
|
||||
<a href="?do={$feed_type}{$searchcrits}" class="pure-menu-link" title="{'RSS Feed'|t}">
|
||||
<i class="fa fa-rss"></i>
|
||||
</a>
|
||||
</li>
|
||||
{if="!isLoggedIn()"}
|
||||
<li class="pure-menu-item">
|
||||
<li class="pure-menu-item" id="shaarli-menu-desktop-login">
|
||||
<a href="?do=login" class="pure-menu-link"
|
||||
data-open-id="header-login-form"
|
||||
id="login-button" title="{'Login'|t}">
|
||||
|
@ -83,7 +83,7 @@
|
|||
</a>
|
||||
</li>
|
||||
{else}
|
||||
<li class="pure-menu-item">
|
||||
<li class="pure-menu-item" id="shaarli-menu-desktop-logout">
|
||||
<a href="?do=logout" class="pure-menu-link" title="{'Logout'|t}">
|
||||
<i class="fa fa-sign-out"></i>
|
||||
</a>
|
||||
|
@ -156,7 +156,7 @@
|
|||
{/if}
|
||||
|
||||
{if="!empty($plugin_errors) && isLoggedIn()"}
|
||||
<div class="pure-g new-version-message pure-alert pure-alert-error pure-alert-closable">
|
||||
<div class="pure-g new-version-message pure-alert pure-alert-error pure-alert-closable" id="shaarli-errors-alert">
|
||||
<div class="pure-u-2-24"></div>
|
||||
<div class="pure-u-20-24">
|
||||
{loop="plugin_errors"}
|
||||
|
|
|
@ -137,9 +137,9 @@ <h2 class="window-title">{'Plugin configuration'|t}</h2>
|
|||
{if="count($enabledPlugins)==0"}
|
||||
<p class="center">{'No plugin enabled.'|t}</p>
|
||||
{else}
|
||||
{$counter=0}
|
||||
{$nbParameters=0}
|
||||
{loop="$enabledPlugins"}
|
||||
{$counter=$counter+count($value.parameters)}
|
||||
{$nbParameters=$nbParameters+count($value.parameters)}
|
||||
{if="count($value.parameters) > 0"}
|
||||
<div class="plugin_parameters">
|
||||
<h3 class="window-subtitle">{function="str_replace('_', ' ', $key)"}</h3>
|
||||
|
@ -161,7 +161,7 @@ <h3 class="window-subtitle">{function="str_replace('_', ' ', $key)"}</h3>
|
|||
</div>
|
||||
{/if}
|
||||
{/loop}
|
||||
{if="$counter===0"}
|
||||
{if="$nbParameters===0"}
|
||||
<p class="center">{'No parameter available.'|t}</p>
|
||||
{else}
|
||||
<div class="center">
|
||||
|
|
Loading…
Reference in a new issue