aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.github/mailmap2
-rw-r--r--.travis.yml2
-rw-r--r--AUTHORS13
-rw-r--r--CHANGELOG.md69
-rw-r--r--README.md6
-rw-r--r--application/HttpUtils.php21
-rw-r--r--application/Languages.php2
-rw-r--r--application/LinkUtils.php89
-rw-r--r--application/Url.php2
-rw-r--r--application/config/ConfigPhp.php6
-rw-r--r--composer.json6
-rw-r--r--composer.lock670
-rw-r--r--doc/md/Backup,-restore,-import-and-export.md4
-rw-r--r--doc/md/Bookmarklet.md2
-rw-r--r--doc/md/Browsing-and-searching.md20
-rw-r--r--doc/md/Community-&-Related-software.md48
-rw-r--r--doc/md/Download-and-Installation.md10
-rw-r--r--doc/md/Features.md25
-rw-r--r--doc/md/Firefox-share.md3
-rw-r--r--doc/md/Server-requirements.md2
-rw-r--r--doc/md/docker/shaarli-images.md15
-rw-r--r--doc/md/index.md43
-rw-r--r--docker/alpine/Dockerfile.armhf.latest47
-rw-r--r--docker/alpine/Dockerfile.armhf.master47
-rw-r--r--index.php21
-rw-r--r--mkdocs.yml8
-rw-r--r--tests/HttpUtils/ServerUrlTest.php32
-rw-r--r--tests/LinkUtilsTest.php244
-rw-r--r--tests/api/controllers/PostLinkTest.php6
-rw-r--r--tests/config/ConfigPhpTest.php14
-rw-r--r--tests/utils/config/emptyConfigPhp.php1
-rw-r--r--tpl/default/page.header.html52
-rw-r--r--tpl/default/pluginsadmin.html6
33 files changed, 1102 insertions, 436 deletions
diff --git a/.github/mailmap b/.github/mailmap
index bbdb7908..7633afcf 100644
--- a/.github/mailmap
+++ b/.github/mailmap
@@ -1,6 +1,8 @@
1ArthurHoaro <arthur@hoa.ro> 1ArthurHoaro <arthur@hoa.ro>
2Florian Eula <eula.florian@gmail.com> feula 2Florian Eula <eula.florian@gmail.com> feula
3Florian Eula <eula.florian@gmail.com> <mr.pikzen@gmail.com> 3Florian Eula <eula.florian@gmail.com> <mr.pikzen@gmail.com>
4Immánuel Fodor <immanuelfactor+github@gmail.com>
5kalvn <kalvnthereal@gmail.com> <kalvn@users.noreply.github.com>
4Nicolas Danelon <hi@nicolasmd.com.ar> nicolasm 6Nicolas Danelon <hi@nicolasmd.com.ar> nicolasm
5Nicolas Danelon <hi@nicolasmd.com.ar> <nda@3818.com.ar> 7Nicolas Danelon <hi@nicolasmd.com.ar> <nda@3818.com.ar>
6Nicolas Danelon <hi@nicolasmd.com.ar> <nicolasdanelon@gmail.com> 8Nicolas Danelon <hi@nicolasmd.com.ar> <nicolasdanelon@gmail.com>
diff --git a/.travis.yml b/.travis.yml
index 322e4337..758aa9f4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,10 +5,10 @@ cache:
5 directories: 5 directories:
6 - $HOME/.composer/cache 6 - $HOME/.composer/cache
7php: 7php:
8 - 7.2
8 - 7.1 9 - 7.1
9 - 7.0 10 - 7.0
10 - 5.6 11 - 5.6
11 - 5.5
12install: 12install:
13 - composer self-update 13 - composer self-update
14 - composer install --prefer-dist 14 - composer install --prefer-dist
diff --git a/AUTHORS b/AUTHORS
index 105561c1..c0414c0e 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,6 +1,6 @@
1 537 ArthurHoaro <arthur@hoa.ro> 1 588 ArthurHoaro <arthur@hoa.ro>
2 252 VirtualTam <virtualtam@flibidi.net> 2 283 VirtualTam <virtualtam@flibidi.net>
3 148 nodiscc <nodiscc@gmail.com> 3 179 nodiscc <nodiscc@gmail.com>
4 56 Sébastien Sauvage <sebsauvage@sebsauvage.net> 4 56 Sébastien Sauvage <sebsauvage@sebsauvage.net>
5 15 Florian Eula <eula.florian@gmail.com> 5 15 Florian Eula <eula.florian@gmail.com>
6 13 Emilien Klein <emilien@klein.st> 6 13 Emilien Klein <emilien@klein.st>
@@ -11,8 +11,9 @@
11 5 Lucas Cimon <lucas.cimon@gmail.com> 11 5 Lucas Cimon <lucas.cimon@gmail.com>
12 4 Alexandre Alapetite <alexandre@alapetite.fr> 12 4 Alexandre Alapetite <alexandre@alapetite.fr>
13 4 David Sferruzza <david.sferruzza@gmail.com> 13 4 David Sferruzza <david.sferruzza@gmail.com>
14 4 Immánuel Fodor <immanuelfactor+github@gmail.com>
15 4 kalvn <kalvnthereal@gmail.com>
14 3 Teromene <teromene@teromene.fr> 16 3 Teromene <teromene@teromene.fr>
15 3 kalvn <kalvnthereal@gmail.com>
16 2 Chris Kuethe <chris.kuethe@gmail.com> 17 2 Chris Kuethe <chris.kuethe@gmail.com>
17 2 Knah Tsaeb <Knah-Tsaeb@knah-tsaeb.org> 18 2 Knah Tsaeb <Knah-Tsaeb@knah-tsaeb.org>
18 2 Mathieu Chabanon <git@matchab.fr> 19 2 Mathieu Chabanon <git@matchab.fr>
@@ -27,11 +28,13 @@
27 1 BoboTiG <bobotig@gmail.com> 28 1 BoboTiG <bobotig@gmail.com>
28 1 Bronco <bronco@warriordudimanche.net> 29 1 Bronco <bronco@warriordudimanche.net>
29 1 D Low <daniellowtw@gmail.com> 30 1 D Low <daniellowtw@gmail.com>
31 1 Daniel Jakots <vigdis@chown.me>
30 1 Dimtion <zizou.xena@gmail.com> 32 1 Dimtion <zizou.xena@gmail.com>
31 1 Fanch <fanch-github@qth.fr> 33 1 Fanch <fanch-github@qth.fr>
32 1 Felix Bartels <felix@host-consultants.de> 34 1 Felix Bartels <felix@host-consultants.de>
33 1 Felix Kästner <github.com-fpunktk@fpunktk.de> 35 1 Felix Kästner <github.com-fpunktk@fpunktk.de>
34 1 Florian Voigt <flvoigt@me.com> 36 1 Florian Voigt <flvoigt@me.com>
37 1 Franck Kerbiriou <FranckKe@users.noreply.github.com>
35 1 Gary Marigliano <gmarigliano93@gmail.com> 38 1 Gary Marigliano <gmarigliano93@gmail.com>
36 1 Guillaume Virlet <github@virlet.org> 39 1 Guillaume Virlet <github@virlet.org>
37 1 Jonathan Druart <jonathan.druart@gmail.com> 40 1 Jonathan Druart <jonathan.druart@gmail.com>
@@ -41,6 +44,8 @@
41 1 Lionel Martin <renarddesmers@gmail.com> 44 1 Lionel Martin <renarddesmers@gmail.com>
42 1 Mark Gerarts <mark.gerarts@gmail.com> 45 1 Mark Gerarts <mark.gerarts@gmail.com>
43 1 Marsup <marsup@gmail.com> 46 1 Marsup <marsup@gmail.com>
47 1 Neros <contact@neros.fr>
44 1 Sbgodin <Sbgodin@users.noreply.github.com> 48 1 Sbgodin <Sbgodin@users.noreply.github.com>
45 1 TsT <tst2005@gmail.com> 49 1 TsT <tst2005@gmail.com>
46 1 dimtion <zizou.xena@gmail.com> 50 1 dimtion <zizou.xena@gmail.com>
51 1 durcheinandr <jochen@durcheinandr.de>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 33feac20..0e737d8c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,49 @@ All notable changes to this project will be documented in this file.
4The format is based on [Keep a Changelog](http://keepachangelog.com/) 4The format is based on [Keep a Changelog](http://keepachangelog.com/)
5and this project adheres to [Semantic Versioning](http://semver.org/). 5and this project adheres to [Semantic Versioning](http://semver.org/).
6 6
7## [v0.10.0](https://github.com/shaarli/Shaarli/releases/tag/v0.10.0) - UNPUBLISHED
8
9## [v0.9.5](https://github.com/shaarli/Shaarli/releases/tag/v0.9.5) - 2018-02-02
10### Fixed
11- Fix a warning happening when `php-intl` is not installed on the system
12- Fix warnings happening when updating from legacy SebSauvage version
13
14## [v0.9.4](https://github.com/shaarli/Shaarli/releases/tag/v0.9.4) - 2018-01-30
15### Added
16- Enable translations: Shaarli is now also available in French. Other language translations are welcome!
17- Add EditorConfig configuration
18- Add favicons for mobile devices
19- Add Alpine Linux arm32v7 Dockerfiles (master, latest)
20
21### Changed
22- Do not write bookmark edition history during file imports (performance)
23- Migrate Docker images (master, latest) to Alpine Linux
24- Improve unitary tests and code coverage
25- Improve thumbnail display
26- Improve theme ergonomics
27- Improve messages if there is no plugin or parameter available in the admin page
28- Increase buffer size for cURL download
29- Force HTTPS if the original port is 443 behind a reverse proxy (workaround)
30- Improve page title retrieval performances
31
32### Removed
33- Remove redirector setting from Configure page
34
35### Fixed
36- Fix broken links in the documentation
37- Enable access to `data/user.css` (Apache 2.2 & 2.4)
38- Don't URL encode description links if parameter `redirector.encode_url` is set to false
39- Fix an issue preventing the Save button to appear for plugin parameters
40
41
42## [v0.9.3](https://github.com/shaarli/Shaarli/releases/tag/v0.9.3) - 2018-01-04
43**XSS vulnerability fixed. Please update.**
44
45## Security
46- Fix an XSS (cross-site-scripting) vulnerability in `index.php` -
47 [CVE-2018-5249](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-5249)
48
49
7## [v0.9.2](https://github.com/shaarli/Shaarli/releases/tag/v0.9.2) - 2017-10-07 50## [v0.9.2](https://github.com/shaarli/Shaarli/releases/tag/v0.9.2) - 2017-10-07
8 51
9**Major security issue fixed. Please update.** 52**Major security issue fixed. Please update.**
@@ -42,6 +85,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
42 85
43- 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)). 86- 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)).
44 87
88
45## [v0.9.1](https://github.com/shaarli/Shaarli/releases/tag/v0.9.1) - 2017-08-23 89## [v0.9.1](https://github.com/shaarli/Shaarli/releases/tag/v0.9.1) - 2017-08-23
46 90
47The documentation has been migrated to ReadTheDocs: 91The documentation has been migrated to ReadTheDocs:
@@ -115,7 +159,7 @@ Theming:
115 - Introduce a new theme 159 - Introduce a new theme
116 - Allow selecting themes/templates from the configuration page 160 - Allow selecting themes/templates from the configuration page
117 - New/Edit link form can be submitted using CTRL+Enter in the textarea 161 - New/Edit link form can be submitted using CTRL+Enter in the textarea
118 - Shaarli version is displayed in the footer when logged in 162 - Shaarli version is displayed in the footer when logged in
119- Add plugin placeholders to Atom/RSS feed templates 163- Add plugin placeholders to Atom/RSS feed templates
120- Add OpenSearch to feed templates 164- Add OpenSearch to feed templates
121- Add `campaign_` to the URL cleanup pattern list 165- Add `campaign_` to the URL cleanup pattern list
@@ -145,7 +189,7 @@ Theming:
145- Improved date time display depending on the locale 189- Improved date time display depending on the locale
146- Partial namespace support for Shaarli classes 190- Partial namespace support for Shaarli classes
147- Shaarli version is now only present in `shaarli_version.php` 191- Shaarli version is now only present in `shaarli_version.php`
148- Human readable maximum file size upload 192- Human readable maximum file size upload
149 193
150 194
151### Removed 195### Removed
@@ -171,6 +215,13 @@ Theming:
171- Markdown plugin: escape HTML entities by default 215- Markdown plugin: escape HTML entities by default
172 216
173 217
218## [v0.8.5](https://github.com/shaarli/Shaarli/releases/tag/v0.8.5) - 2018-01-04
219**XSS vulnerability fixed. Please update.**
220
221## Security
222- Fix an XSS (cross-site-scripting) vulnerability in `index.php` -
223 [CVE-2018-5249](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-5249)
224
174## [v0.8.4](https://github.com/shaarli/Shaarli/releases/tag/v0.8.4) - 2017-03-04 225## [v0.8.4](https://github.com/shaarli/Shaarli/releases/tag/v0.8.4) - 2017-03-04
175### Security 226### Security
176- Markdown plugin: escape HTML entities by default 227- Markdown plugin: escape HTML entities by default
@@ -186,7 +237,7 @@ Theming:
186 237
187## [v0.8.1](https://github.com/shaarli/Shaarli/releases/tag/v0.8.1) - 2016-12-12 238## [v0.8.1](https://github.com/shaarli/Shaarli/releases/tag/v0.8.1) - 2016-12-12
188 239
189> Note: this version will create an automatic backup of your database if anything goes wrong. 240> Note: this version will create an automatic backup of your database if anything goes wrong.
190 241
191### Added 242### Added
192- Add CHANGELOG.md to track the whole project's history 243- Add CHANGELOG.md to track the whole project's history
@@ -203,7 +254,7 @@ Theming:
203- Link ID complete refactoring: 254- Link ID complete refactoring:
204 - Links now have a numeric ID instead of dates 255 - Links now have a numeric ID instead of dates
205 - Short URLs are now created once and can't change over time (previous URL are kept) 256 - Short URLs are now created once and can't change over time (previous URL are kept)
206- Templates: 257- Templates:
207 - Changed placeholder behaviour for: `buttons_toolbar`, `fields_toolbar` and `action_plugin` 258 - Changed placeholder behaviour for: `buttons_toolbar`, `fields_toolbar` and `action_plugin`
208 - Cleanup `{loop}` declarations in templates 259 - Cleanup `{loop}` declarations in templates
209 - Tools: hide Firefox Social button when not in HTTPS 260 - Tools: hide Firefox Social button when not in HTTPS
@@ -221,7 +272,7 @@ Theming:
221- Plugins: 272- Plugins:
222 - Tools: only display parameter description when it exists 273 - Tools: only display parameter description when it exists
223 - archive.org: do not propose archival of private notes 274 - archive.org: do not propose archival of private notes
224 - Markdown: 275 - Markdown:
225 - render links properly in code blocks 276 - render links properly in code blocks
226 - bug regarding the `nomarkdown` tag 277 - bug regarding the `nomarkdown` tag
227 - W3C compliance 278 - W3C compliance
@@ -360,7 +411,7 @@ Please use our release archives, or follow the
360### Fixed 411### Fixed
361- Fix a bug where renaming a tag was causing a 404 412- Fix a bug where renaming a tag was causing a 404
362- Fix a bug allowing to search blank terms 413- Fix a bug allowing to search blank terms
363- Fix a bug preventing to remove a tag with special chars when searching 414- Fix a bug preventing to remove a tag with special chars when searching
364 415
365 416
366## [v0.6.2](https://github.com/shaarli/Shaarli/releases/tag/v0.6.2) - 2015-12-23 417## [v0.6.2](https://github.com/shaarli/Shaarli/releases/tag/v0.6.2) - 2015-12-23
@@ -666,7 +717,7 @@ Initial release on GitHub.
666- When you click the key to see only private links, it turns yellow 717- When you click the key to see only private links, it turns yellow
667 718
668### Changed 719### Changed
669- The "Daily" page now automatically skips empty days. 720- The "Daily" page now automatically skips empty days.
670 721
671### Fixed 722### Fixed
672- Corrected the tag encoding (there was a bug when selecting a second tag which contains accented characters) 723- Corrected the tag encoding (there was a bug when selecting a second tag which contains accented characters)
@@ -964,7 +1015,7 @@ Initial release on GitHub.
964- Nicer timezone selection patch by killruana 1015- Nicer timezone selection patch by killruana
965 1016
966### Fixed 1017### Fixed
967- New lines now appear correctly in the RSS feed descriptions. 1018- New lines now appear correctly in the RSS feed descriptions.
968 1019
969 1020
970## [v0.0.17beta](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history) 1021## [v0.0.17beta](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history)
@@ -1018,7 +1069,7 @@ Initial release on GitHub.
1018## [v0.0.14beta](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history) 1069## [v0.0.14beta](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history)
1019### Added 1070### Added
1020- You no longer need to disable `magic_quotes` on your host. 1071- You no longer need to disable `magic_quotes` on your host.
1021 Shaarli will cope with this option beeing activated. 1072 Shaarli will cope with this option beeing activated.
1022 1073
1023 1074
1024## [v0.0.13beta](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history) 1075## [v0.0.13beta](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history)
diff --git a/README.md b/README.md
index c1050027..da324abc 100644
--- a/README.md
+++ b/README.md
@@ -6,13 +6,13 @@ _Do you want to share the links you discover?_
6_Shaarli is a minimalist link sharing service that you can install on your own server._ 6_Shaarli is a minimalist link sharing service that you can install on your own server._
7_It is designed to be personal (single-user), fast and handy._ 7_It is designed to be personal (single-user), fast and handy._
8 8
9[![](https://img.shields.io/badge/stable-v0.8.4-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.8.4) 9[![](https://img.shields.io/badge/stable-v0.8.5-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.8.5)
10[![](https://img.shields.io/travis/shaarli/Shaarli/stable.svg?label=stable)](https://travis-ci.org/shaarli/Shaarli) 10[![](https://img.shields.io/travis/shaarli/Shaarli/stable.svg?label=stable)](https://travis-ci.org/shaarli/Shaarli)
11&bull; 11&bull;
12[![](https://img.shields.io/badge/latest-v0.9.2-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.9.2) 12[![](https://img.shields.io/badge/latest-v0.9.5-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.9.5)
13[![](https://img.shields.io/travis/shaarli/Shaarli/latest.svg?label=latest)](https://travis-ci.org/shaarli/Shaarli) 13[![](https://img.shields.io/travis/shaarli/Shaarli/latest.svg?label=latest)](https://travis-ci.org/shaarli/Shaarli)
14&bull; 14&bull;
15[![](https://img.shields.io/badge/master-v0.9.x-blue.svg)](https://github.com/shaarli/Shaarli) 15[![](https://img.shields.io/badge/master-v0.10.x-blue.svg)](https://github.com/shaarli/Shaarli)
16[![](https://img.shields.io/travis/shaarli/Shaarli.svg?label=master)](https://travis-ci.org/shaarli/Shaarli) 16[![](https://img.shields.io/travis/shaarli/Shaarli.svg?label=master)](https://travis-ci.org/shaarli/Shaarli)
17 17
18[![Join the chat at https://gitter.im/shaarli/Shaarli](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/shaarli/Shaarli) 18[![Join the chat at https://gitter.im/shaarli/Shaarli](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/shaarli/Shaarli)
diff --git a/application/HttpUtils.php b/application/HttpUtils.php
index ec54dcd4..83a4c5e2 100644
--- a/application/HttpUtils.php
+++ b/application/HttpUtils.php
@@ -3,9 +3,11 @@
3 * GET an HTTP URL to retrieve its content 3 * GET an HTTP URL to retrieve its content
4 * Uses the cURL library or a fallback method 4 * Uses the cURL library or a fallback method
5 * 5 *
6 * @param string $url URL to get (http://...) 6 * @param string $url URL to get (http://...)
7 * @param int $timeout network timeout (in seconds) 7 * @param int $timeout network timeout (in seconds)
8 * @param int $maxBytes maximum downloaded bytes (default: 4 MiB) 8 * @param int $maxBytes maximum downloaded bytes (default: 4 MiB)
9 * @param callable|string $curlWriteFunction Optional callback called during the download (cURL CURLOPT_WRITEFUNCTION).
10 * Can be used to add download conditions on the headers (response code, content type, etc.).
9 * 11 *
10 * @return array HTTP response headers, downloaded content 12 * @return array HTTP response headers, downloaded content
11 * 13 *
@@ -29,7 +31,7 @@
29 * @see http://stackoverflow.com/q/9183178 31 * @see http://stackoverflow.com/q/9183178
30 * @see http://stackoverflow.com/q/1462720 32 * @see http://stackoverflow.com/q/1462720
31 */ 33 */
32function get_http_response($url, $timeout = 30, $maxBytes = 4194304) 34function get_http_response($url, $timeout = 30, $maxBytes = 4194304, $curlWriteFunction = null)
33{ 35{
34 $urlObj = new Url($url); 36 $urlObj = new Url($url);
35 $cleanUrl = $urlObj->idnToAscii(); 37 $cleanUrl = $urlObj->idnToAscii();
@@ -75,6 +77,10 @@ function get_http_response($url, $timeout = 30, $maxBytes = 4194304)
75 curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); 77 curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
76 curl_setopt($ch, CURLOPT_USERAGENT, $userAgent); 78 curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
77 79
80 if (is_callable($curlWriteFunction)) {
81 curl_setopt($ch, CURLOPT_WRITEFUNCTION, $curlWriteFunction);
82 }
83
78 // Max download size management 84 // Max download size management
79 curl_setopt($ch, CURLOPT_BUFFERSIZE, 1024*16); 85 curl_setopt($ch, CURLOPT_BUFFERSIZE, 1024*16);
80 curl_setopt($ch, CURLOPT_NOPROGRESS, false); 86 curl_setopt($ch, CURLOPT_NOPROGRESS, false);
@@ -302,6 +308,13 @@ function server_url($server)
302 $port = $server['HTTP_X_FORWARDED_PORT']; 308 $port = $server['HTTP_X_FORWARDED_PORT'];
303 } 309 }
304 310
311 // This is a workaround for proxies that don't forward the scheme properly.
312 // Connecting over port 443 has to be in HTTPS.
313 // See https://github.com/shaarli/Shaarli/issues/1022
314 if ($port == '443') {
315 $scheme = 'https';
316 }
317
305 if (($scheme == 'http' && $port != '80') 318 if (($scheme == 'http' && $port != '80')
306 || ($scheme == 'https' && $port != '443') 319 || ($scheme == 'https' && $port != '443')
307 ) { 320 ) {
diff --git a/application/Languages.php b/application/Languages.php
index 357c7524..3eb3388f 100644
--- a/application/Languages.php
+++ b/application/Languages.php
@@ -69,6 +69,8 @@ class Languages
69 { 69 {
70 $this->conf = $conf; 70 $this->conf = $conf;
71 $confLanguage = $this->conf->get('translation.language', 'auto'); 71 $confLanguage = $this->conf->get('translation.language', 'auto');
72 // Auto mode or invalid parameter, use the detected language.
73 // If the detected language is invalid, it doesn't matter, it will use English.
72 if ($confLanguage === 'auto' || ! $this->isValidLanguage($confLanguage)) { 74 if ($confLanguage === 'auto' || ! $this->isValidLanguage($confLanguage)) {
73 $this->language = substr($language, 0, 5); 75 $this->language = substr($language, 0, 5);
74 } else { 76 } else {
diff --git a/application/LinkUtils.php b/application/LinkUtils.php
index e3d95d08..3705f7e9 100644
--- a/application/LinkUtils.php
+++ b/application/LinkUtils.php
@@ -1,60 +1,81 @@
1<?php 1<?php
2 2
3/** 3/**
4 * Extract title from an HTML document. 4 * Get cURL callback function for CURLOPT_WRITEFUNCTION
5 * 5 *
6 * @param string $html HTML content where to look for a title. 6 * @param string $charset to extract from the downloaded page (reference)
7 * @param string $title to extract from the downloaded page (reference)
8 * @param string $curlGetInfo Optionnaly overrides curl_getinfo function
7 * 9 *
8 * @return bool|string Extracted title if found, false otherwise. 10 * @return Closure
9 */ 11 */
10function html_extract_title($html) 12function get_curl_download_callback(&$charset, &$title, $curlGetInfo = 'curl_getinfo')
11{ 13{
12 if (preg_match('!<title.*?>(.*?)</title>!is', $html, $matches)) { 14 /**
13 return trim(str_replace("\n", '', $matches[1])); 15 * cURL callback function for CURLOPT_WRITEFUNCTION (called during the download).
14 } 16 *
15 return false; 17 * While downloading the remote page, we check that the HTTP code is 200 and content type is 'html/text'
18 * Then we extract the title and the charset and stop the download when it's done.
19 *
20 * @param resource $ch cURL resource
21 * @param string $data chunk of data being downloaded
22 *
23 * @return int|bool length of $data or false if we need to stop the download
24 */
25 return function(&$ch, $data) use ($curlGetInfo, &$charset, &$title) {
26 $responseCode = $curlGetInfo($ch, CURLINFO_RESPONSE_CODE);
27 if (!empty($responseCode) && $responseCode != 200) {
28 return false;
29 }
30 $contentType = $curlGetInfo($ch, CURLINFO_CONTENT_TYPE);
31 if (!empty($contentType) && strpos($contentType, 'text/html') === false) {
32 return false;
33 }
34 if (empty($charset)) {
35 $charset = header_extract_charset($contentType);
36 }
37 if (empty($charset)) {
38 $charset = html_extract_charset($data);
39 }
40 if (empty($title)) {
41 $title = html_extract_title($data);
42 }
43 // We got everything we want, stop the download.
44 if (!empty($responseCode) && !empty($contentType) && !empty($charset) && !empty($title)) {
45 return false;
46 }
47
48 return strlen($data);
49 };
16} 50}
17 51
18/** 52/**
19 * Determine charset from downloaded page. 53 * Extract title from an HTML document.
20 * Priority:
21 * 1. HTTP headers (Content type).
22 * 2. HTML content page (tag <meta charset>).
23 * 3. Use a default charset (default: UTF-8).
24 * 54 *
25 * @param array $headers HTTP headers array. 55 * @param string $html HTML content where to look for a title.
26 * @param string $htmlContent HTML content where to look for charset.
27 * @param string $defaultCharset Default charset to apply if other methods failed.
28 * 56 *
29 * @return string Determined charset. 57 * @return bool|string Extracted title if found, false otherwise.
30 */ 58 */
31function get_charset($headers, $htmlContent, $defaultCharset = 'utf-8') 59function html_extract_title($html)
32{ 60{
33 if ($charset = headers_extract_charset($headers)) { 61 if (preg_match('!<title.*?>(.*?)</title>!is', $html, $matches)) {
34 return $charset; 62 return trim(str_replace("\n", '', $matches[1]));
35 }
36
37 if ($charset = html_extract_charset($htmlContent)) {
38 return $charset;
39 } 63 }
40 64 return false;
41 return $defaultCharset;
42} 65}
43 66
44/** 67/**
45 * Extract charset from HTTP headers if it's defined. 68 * Extract charset from HTTP header if it's defined.
46 * 69 *
47 * @param array $headers HTTP headers array. 70 * @param string $header HTTP header Content-Type line.
48 * 71 *
49 * @return bool|string Charset string if found (lowercase), false otherwise. 72 * @return bool|string Charset string if found (lowercase), false otherwise.
50 */ 73 */
51function headers_extract_charset($headers) 74function header_extract_charset($header)
52{ 75{
53 if (! empty($headers['Content-Type']) && strpos($headers['Content-Type'], 'charset=') !== false) { 76 preg_match('/charset="?([^; ]+)/i', $header, $match);
54 preg_match('/charset="?([^; ]+)/i', $headers['Content-Type'], $match); 77 if (! empty($match[1])) {
55 if (! empty($match[1])) { 78 return strtolower(trim($match[1]));
56 return strtolower(trim($match[1]));
57 }
58 } 79 }
59 80
60 return false; 81 return false;
diff --git a/application/Url.php b/application/Url.php
index b3759377..21c17ecc 100644
--- a/application/Url.php
+++ b/application/Url.php
@@ -260,7 +260,7 @@ class Url
260 if (! function_exists('idn_to_ascii') || ! isset($this->parts['host'])) { 260 if (! function_exists('idn_to_ascii') || ! isset($this->parts['host'])) {
261 return $out; 261 return $out;
262 } 262 }
263 $asciiHost = idn_to_ascii($this->parts['host']); 263 $asciiHost = idn_to_ascii($this->parts['host'], 0, INTL_IDNA_VARIANT_UTS46);
264 return str_replace($this->parts['host'], $asciiHost, $out); 264 return str_replace($this->parts['host'], $asciiHost, $out);
265 } 265 }
266 266
diff --git a/application/config/ConfigPhp.php b/application/config/ConfigPhp.php
index 2f66e8e0..8add8bcd 100644
--- a/application/config/ConfigPhp.php
+++ b/application/config/ConfigPhp.php
@@ -83,10 +83,10 @@ class ConfigPhp implements ConfigIO
83 83
84 $out = array(); 84 $out = array();
85 foreach (self::$ROOT_KEYS as $key) { 85 foreach (self::$ROOT_KEYS as $key) {
86 $out[$key] = $GLOBALS[$key]; 86 $out[$key] = isset($GLOBALS[$key]) ? $GLOBALS[$key] : '';
87 } 87 }
88 $out['config'] = $GLOBALS['config']; 88 $out['config'] = isset($GLOBALS['config']) ? $GLOBALS['config'] : [];
89 $out['plugins'] = !empty($GLOBALS['plugins']) ? $GLOBALS['plugins'] : array(); 89 $out['plugins'] = isset($GLOBALS['plugins']) ? $GLOBALS['plugins'] : [];
90 return $out; 90 return $out;
91 } 91 }
92 92
diff --git a/composer.json b/composer.json
index f331d6ca..bbef28af 100644
--- a/composer.json
+++ b/composer.json
@@ -11,11 +11,11 @@
11 "keywords": ["bookmark", "link", "share", "web"], 11 "keywords": ["bookmark", "link", "share", "web"],
12 "config": { 12 "config": {
13 "platform": { 13 "platform": {
14 "php": "5.5.38" 14 "php": "5.6.31"
15 } 15 }
16 }, 16 },
17 "require": { 17 "require": {
18 "php": ">=5.5", 18 "php": ">=5.6",
19 "shaarli/netscape-bookmark-parser": "^2.0", 19 "shaarli/netscape-bookmark-parser": "^2.0",
20 "erusev/parsedown": "1.6", 20 "erusev/parsedown": "1.6",
21 "slim/slim": "^3.0", 21 "slim/slim": "^3.0",
@@ -24,7 +24,7 @@
24 }, 24 },
25 "require-dev": { 25 "require-dev": {
26 "phpmd/phpmd" : "@stable", 26 "phpmd/phpmd" : "@stable",
27 "phpunit/phpunit": "4.8.*", 27 "phpunit/phpunit": "^5.0",
28 "sebastian/phpcpd": "*", 28 "sebastian/phpcpd": "*",
29 "squizlabs/php_codesniffer": "2.*", 29 "squizlabs/php_codesniffer": "2.*",
30 "phpunit/phpcov": "*" 30 "phpunit/phpcov": "*"
diff --git a/composer.lock b/composer.lock
index 39909b8f..0a3fbd83 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
4 "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 4 "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5 "This file is @generated automatically" 5 "This file is @generated automatically"
6 ], 6 ],
7 "content-hash": "13b7e1e474fe9264b098ba86face0feb", 7 "content-hash": "bc39afd7f6d37c76509f96bea69f6131",
8 "packages": [ 8 "packages": [
9 { 9 {
10 "name": "container-interop/container-interop", 10 "name": "container-interop/container-interop",
@@ -294,16 +294,16 @@
294 }, 294 },
295 { 295 {
296 "name": "pimple/pimple", 296 "name": "pimple/pimple",
297 "version": "v3.2.2", 297 "version": "v3.2.3",
298 "source": { 298 "source": {
299 "type": "git", 299 "type": "git",
300 "url": "https://github.com/silexphp/Pimple.git", 300 "url": "https://github.com/silexphp/Pimple.git",
301 "reference": "4d45fb62d96418396ec58ba76e6f065bca16e10a" 301 "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32"
302 }, 302 },
303 "dist": { 303 "dist": {
304 "type": "zip", 304 "type": "zip",
305 "url": "https://api.github.com/repos/silexphp/Pimple/zipball/4d45fb62d96418396ec58ba76e6f065bca16e10a", 305 "url": "https://api.github.com/repos/silexphp/Pimple/zipball/9e403941ef9d65d20cba7d54e29fe906db42cf32",
306 "reference": "4d45fb62d96418396ec58ba76e6f065bca16e10a", 306 "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32",
307 "shasum": "" 307 "shasum": ""
308 }, 308 },
309 "require": { 309 "require": {
@@ -340,7 +340,7 @@
340 "container", 340 "container",
341 "dependency injection" 341 "dependency injection"
342 ], 342 ],
343 "time": "2017-07-23T07:32:15+00:00" 343 "time": "2018-01-21T07:42:36+00:00"
344 }, 344 },
345 { 345 {
346 "name": "psr/container", 346 "name": "psr/container",
@@ -533,16 +533,16 @@
533 }, 533 },
534 { 534 {
535 "name": "shaarli/netscape-bookmark-parser", 535 "name": "shaarli/netscape-bookmark-parser",
536 "version": "v2.0.4", 536 "version": "v2.0.5",
537 "source": { 537 "source": {
538 "type": "git", 538 "type": "git",
539 "url": "https://github.com/shaarli/netscape-bookmark-parser.git", 539 "url": "https://github.com/shaarli/netscape-bookmark-parser.git",
540 "reference": "81023979c981514f5dda5582e9c0be2ed6688a6b" 540 "reference": "ea6911a0ea3dd372fa7002593c5aef9c15a49315"
541 }, 541 },
542 "dist": { 542 "dist": {
543 "type": "zip", 543 "type": "zip",
544 "url": "https://api.github.com/repos/shaarli/netscape-bookmark-parser/zipball/81023979c981514f5dda5582e9c0be2ed6688a6b", 544 "url": "https://api.github.com/repos/shaarli/netscape-bookmark-parser/zipball/ea6911a0ea3dd372fa7002593c5aef9c15a49315",
545 "reference": "81023979c981514f5dda5582e9c0be2ed6688a6b", 545 "reference": "ea6911a0ea3dd372fa7002593c5aef9c15a49315",
546 "shasum": "" 546 "shasum": ""
547 }, 547 },
548 "require": { 548 "require": {
@@ -584,20 +584,20 @@
584 "netscape", 584 "netscape",
585 "parse" 585 "parse"
586 ], 586 ],
587 "time": "2017-07-30T21:08:03+00:00" 587 "time": "2018-01-30T17:34:48+00:00"
588 }, 588 },
589 { 589 {
590 "name": "slim/slim", 590 "name": "slim/slim",
591 "version": "3.8.1", 591 "version": "3.9.2",
592 "source": { 592 "source": {
593 "type": "git", 593 "type": "git",
594 "url": "https://github.com/slimphp/Slim.git", 594 "url": "https://github.com/slimphp/Slim.git",
595 "reference": "5385302707530b2bccee1769613ad769859b826d" 595 "reference": "4086d0106cf5a7135c69fce4161fe355a8feb118"
596 }, 596 },
597 "dist": { 597 "dist": {
598 "type": "zip", 598 "type": "zip",
599 "url": "https://api.github.com/repos/slimphp/Slim/zipball/5385302707530b2bccee1769613ad769859b826d", 599 "url": "https://api.github.com/repos/slimphp/Slim/zipball/4086d0106cf5a7135c69fce4161fe355a8feb118",
600 "reference": "5385302707530b2bccee1769613ad769859b826d", 600 "reference": "4086d0106cf5a7135c69fce4161fe355a8feb118",
601 "shasum": "" 601 "shasum": ""
602 }, 602 },
603 "require": { 603 "require": {
@@ -655,7 +655,7 @@
655 "micro", 655 "micro",
656 "router" 656 "router"
657 ], 657 ],
658 "time": "2017-03-19T17:55:20+00:00" 658 "time": "2017-11-26T19:13:09+00:00"
659 } 659 }
660 ], 660 ],
661 "packages-dev": [ 661 "packages-dev": [
@@ -714,27 +714,72 @@
714 "time": "2015-06-14T21:17:01+00:00" 714 "time": "2015-06-14T21:17:01+00:00"
715 }, 715 },
716 { 716 {
717 "name": "myclabs/deep-copy",
718 "version": "1.7.0",
719 "source": {
720 "type": "git",
721 "url": "https://github.com/myclabs/DeepCopy.git",
722 "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e"
723 },
724 "dist": {
725 "type": "zip",
726 "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e",
727 "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e",
728 "shasum": ""
729 },
730 "require": {
731 "php": "^5.6 || ^7.0"
732 },
733 "require-dev": {
734 "doctrine/collections": "^1.0",
735 "doctrine/common": "^2.6",
736 "phpunit/phpunit": "^4.1"
737 },
738 "type": "library",
739 "autoload": {
740 "psr-4": {
741 "DeepCopy\\": "src/DeepCopy/"
742 },
743 "files": [
744 "src/DeepCopy/deep_copy.php"
745 ]
746 },
747 "notification-url": "https://packagist.org/downloads/",
748 "license": [
749 "MIT"
750 ],
751 "description": "Create deep copies (clones) of your objects",
752 "keywords": [
753 "clone",
754 "copy",
755 "duplicate",
756 "object",
757 "object graph"
758 ],
759 "time": "2017-10-19T19:58:43+00:00"
760 },
761 {
717 "name": "pdepend/pdepend", 762 "name": "pdepend/pdepend",
718 "version": "2.5.0", 763 "version": "2.5.2",
719 "source": { 764 "source": {
720 "type": "git", 765 "type": "git",
721 "url": "https://github.com/pdepend/pdepend.git", 766 "url": "https://github.com/pdepend/pdepend.git",
722 "reference": "0c50874333149c0dad5a2877801aed148f2767ff" 767 "reference": "9daf26d0368d4a12bed1cacae1a9f3a6f0adf239"
723 }, 768 },
724 "dist": { 769 "dist": {
725 "type": "zip", 770 "type": "zip",
726 "url": "https://api.github.com/repos/pdepend/pdepend/zipball/0c50874333149c0dad5a2877801aed148f2767ff", 771 "url": "https://api.github.com/repos/pdepend/pdepend/zipball/9daf26d0368d4a12bed1cacae1a9f3a6f0adf239",
727 "reference": "0c50874333149c0dad5a2877801aed148f2767ff", 772 "reference": "9daf26d0368d4a12bed1cacae1a9f3a6f0adf239",
728 "shasum": "" 773 "shasum": ""
729 }, 774 },
730 "require": { 775 "require": {
731 "php": ">=5.3.7", 776 "php": ">=5.3.7",
732 "symfony/config": "^2.3.0|^3", 777 "symfony/config": "^2.3.0|^3|^4",
733 "symfony/dependency-injection": "^2.3.0|^3", 778 "symfony/dependency-injection": "^2.3.0|^3|^4",
734 "symfony/filesystem": "^2.3.0|^3" 779 "symfony/filesystem": "^2.3.0|^3|^4"
735 }, 780 },
736 "require-dev": { 781 "require-dev": {
737 "phpunit/phpunit": "^4.4.0,<4.8", 782 "phpunit/phpunit": "^4.8|^5.7",
738 "squizlabs/php_codesniffer": "^2.0.0" 783 "squizlabs/php_codesniffer": "^2.0.0"
739 }, 784 },
740 "bin": [ 785 "bin": [
@@ -751,7 +796,7 @@
751 "BSD-3-Clause" 796 "BSD-3-Clause"
752 ], 797 ],
753 "description": "Official version of pdepend to be handled with Composer", 798 "description": "Official version of pdepend to be handled with Composer",
754 "time": "2017-01-19T14:23:36+00:00" 799 "time": "2017-12-13T13:21:38+00:00"
755 }, 800 },
756 { 801 {
757 "name": "phpdocumentor/reflection-common", 802 "name": "phpdocumentor/reflection-common",
@@ -809,22 +854,22 @@
809 }, 854 },
810 { 855 {
811 "name": "phpdocumentor/reflection-docblock", 856 "name": "phpdocumentor/reflection-docblock",
812 "version": "3.2.2", 857 "version": "3.3.2",
813 "source": { 858 "source": {
814 "type": "git", 859 "type": "git",
815 "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 860 "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
816 "reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157" 861 "reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2"
817 }, 862 },
818 "dist": { 863 "dist": {
819 "type": "zip", 864 "type": "zip",
820 "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/4aada1f93c72c35e22fb1383b47fee43b8f1d157", 865 "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bf329f6c1aadea3299f08ee804682b7c45b326a2",
821 "reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157", 866 "reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2",
822 "shasum": "" 867 "shasum": ""
823 }, 868 },
824 "require": { 869 "require": {
825 "php": ">=5.5", 870 "php": "^5.6 || ^7.0",
826 "phpdocumentor/reflection-common": "^1.0@dev", 871 "phpdocumentor/reflection-common": "^1.0.0",
827 "phpdocumentor/type-resolver": "^0.3.0", 872 "phpdocumentor/type-resolver": "^0.4.0",
828 "webmozart/assert": "^1.0" 873 "webmozart/assert": "^1.0"
829 }, 874 },
830 "require-dev": { 875 "require-dev": {
@@ -850,20 +895,20 @@
850 } 895 }
851 ], 896 ],
852 "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", 897 "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
853 "time": "2017-08-08T06:39:58+00:00" 898 "time": "2017-11-10T14:09:06+00:00"
854 }, 899 },
855 { 900 {
856 "name": "phpdocumentor/type-resolver", 901 "name": "phpdocumentor/type-resolver",
857 "version": "0.3.0", 902 "version": "0.4.0",
858 "source": { 903 "source": {
859 "type": "git", 904 "type": "git",
860 "url": "https://github.com/phpDocumentor/TypeResolver.git", 905 "url": "https://github.com/phpDocumentor/TypeResolver.git",
861 "reference": "fb3933512008d8162b3cdf9e18dba9309b7c3773" 906 "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7"
862 }, 907 },
863 "dist": { 908 "dist": {
864 "type": "zip", 909 "type": "zip",
865 "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/fb3933512008d8162b3cdf9e18dba9309b7c3773", 910 "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7",
866 "reference": "fb3933512008d8162b3cdf9e18dba9309b7c3773", 911 "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7",
867 "shasum": "" 912 "shasum": ""
868 }, 913 },
869 "require": { 914 "require": {
@@ -897,7 +942,7 @@
897 "email": "me@mikevanriel.com" 942 "email": "me@mikevanriel.com"
898 } 943 }
899 ], 944 ],
900 "time": "2017-06-03T08:32:36+00:00" 945 "time": "2017-07-14T14:27:02+00:00"
901 }, 946 },
902 { 947 {
903 "name": "phpmd/phpmd", 948 "name": "phpmd/phpmd",
@@ -967,16 +1012,16 @@
967 }, 1012 },
968 { 1013 {
969 "name": "phpspec/prophecy", 1014 "name": "phpspec/prophecy",
970 "version": "v1.7.2", 1015 "version": "1.7.3",
971 "source": { 1016 "source": {
972 "type": "git", 1017 "type": "git",
973 "url": "https://github.com/phpspec/prophecy.git", 1018 "url": "https://github.com/phpspec/prophecy.git",
974 "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6" 1019 "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf"
975 }, 1020 },
976 "dist": { 1021 "dist": {
977 "type": "zip", 1022 "type": "zip",
978 "url": "https://api.github.com/repos/phpspec/prophecy/zipball/c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6", 1023 "url": "https://api.github.com/repos/phpspec/prophecy/zipball/e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf",
979 "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6", 1024 "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf",
980 "shasum": "" 1025 "shasum": ""
981 }, 1026 },
982 "require": { 1027 "require": {
@@ -988,7 +1033,7 @@
988 }, 1033 },
989 "require-dev": { 1034 "require-dev": {
990 "phpspec/phpspec": "^2.5|^3.2", 1035 "phpspec/phpspec": "^2.5|^3.2",
991 "phpunit/phpunit": "^4.8 || ^5.6.5" 1036 "phpunit/phpunit": "^4.8.35 || ^5.7"
992 }, 1037 },
993 "type": "library", 1038 "type": "library",
994 "extra": { 1039 "extra": {
@@ -1026,43 +1071,44 @@
1026 "spy", 1071 "spy",
1027 "stub" 1072 "stub"
1028 ], 1073 ],
1029 "time": "2017-09-04T11:05:03+00:00" 1074 "time": "2017-11-24T13:59:53+00:00"
1030 }, 1075 },
1031 { 1076 {
1032 "name": "phpunit/php-code-coverage", 1077 "name": "phpunit/php-code-coverage",
1033 "version": "2.2.4", 1078 "version": "4.0.8",
1034 "source": { 1079 "source": {
1035 "type": "git", 1080 "type": "git",
1036 "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 1081 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
1037 "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" 1082 "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d"
1038 }, 1083 },
1039 "dist": { 1084 "dist": {
1040 "type": "zip", 1085 "type": "zip",
1041 "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", 1086 "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d",
1042 "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", 1087 "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d",
1043 "shasum": "" 1088 "shasum": ""
1044 }, 1089 },
1045 "require": { 1090 "require": {
1046 "php": ">=5.3.3", 1091 "ext-dom": "*",
1047 "phpunit/php-file-iterator": "~1.3", 1092 "ext-xmlwriter": "*",
1048 "phpunit/php-text-template": "~1.2", 1093 "php": "^5.6 || ^7.0",
1049 "phpunit/php-token-stream": "~1.3", 1094 "phpunit/php-file-iterator": "^1.3",
1050 "sebastian/environment": "^1.3.2", 1095 "phpunit/php-text-template": "^1.2",
1051 "sebastian/version": "~1.0" 1096 "phpunit/php-token-stream": "^1.4.2 || ^2.0",
1097 "sebastian/code-unit-reverse-lookup": "^1.0",
1098 "sebastian/environment": "^1.3.2 || ^2.0",
1099 "sebastian/version": "^1.0 || ^2.0"
1052 }, 1100 },
1053 "require-dev": { 1101 "require-dev": {
1054 "ext-xdebug": ">=2.1.4", 1102 "ext-xdebug": "^2.1.4",
1055 "phpunit/phpunit": "~4" 1103 "phpunit/phpunit": "^5.7"
1056 }, 1104 },
1057 "suggest": { 1105 "suggest": {
1058 "ext-dom": "*", 1106 "ext-xdebug": "^2.5.1"
1059 "ext-xdebug": ">=2.2.1",
1060 "ext-xmlwriter": "*"
1061 }, 1107 },
1062 "type": "library", 1108 "type": "library",
1063 "extra": { 1109 "extra": {
1064 "branch-alias": { 1110 "branch-alias": {
1065 "dev-master": "2.2.x-dev" 1111 "dev-master": "4.0.x-dev"
1066 } 1112 }
1067 }, 1113 },
1068 "autoload": { 1114 "autoload": {
@@ -1088,20 +1134,20 @@
1088 "testing", 1134 "testing",
1089 "xunit" 1135 "xunit"
1090 ], 1136 ],
1091 "time": "2015-10-06T15:47:00+00:00" 1137 "time": "2017-04-02T07:44:40+00:00"
1092 }, 1138 },
1093 { 1139 {
1094 "name": "phpunit/php-file-iterator", 1140 "name": "phpunit/php-file-iterator",
1095 "version": "1.4.2", 1141 "version": "1.4.5",
1096 "source": { 1142 "source": {
1097 "type": "git", 1143 "type": "git",
1098 "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 1144 "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
1099 "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" 1145 "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
1100 }, 1146 },
1101 "dist": { 1147 "dist": {
1102 "type": "zip", 1148 "type": "zip",
1103 "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", 1149 "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
1104 "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", 1150 "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
1105 "shasum": "" 1151 "shasum": ""
1106 }, 1152 },
1107 "require": { 1153 "require": {
@@ -1135,7 +1181,7 @@
1135 "filesystem", 1181 "filesystem",
1136 "iterator" 1182 "iterator"
1137 ], 1183 ],
1138 "time": "2016-10-03T07:40:28+00:00" 1184 "time": "2017-11-27T13:52:08+00:00"
1139 }, 1185 },
1140 { 1186 {
1141 "name": "phpunit/php-text-template", 1187 "name": "phpunit/php-text-template",
@@ -1229,16 +1275,16 @@
1229 }, 1275 },
1230 { 1276 {
1231 "name": "phpunit/php-token-stream", 1277 "name": "phpunit/php-token-stream",
1232 "version": "1.4.11", 1278 "version": "1.4.12",
1233 "source": { 1279 "source": {
1234 "type": "git", 1280 "type": "git",
1235 "url": "https://github.com/sebastianbergmann/php-token-stream.git", 1281 "url": "https://github.com/sebastianbergmann/php-token-stream.git",
1236 "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7" 1282 "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16"
1237 }, 1283 },
1238 "dist": { 1284 "dist": {
1239 "type": "zip", 1285 "type": "zip",
1240 "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7", 1286 "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16",
1241 "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7", 1287 "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16",
1242 "shasum": "" 1288 "shasum": ""
1243 }, 1289 },
1244 "require": { 1290 "require": {
@@ -1274,30 +1320,30 @@
1274 "keywords": [ 1320 "keywords": [
1275 "tokenizer" 1321 "tokenizer"
1276 ], 1322 ],
1277 "time": "2017-02-27T10:12:30+00:00" 1323 "time": "2017-12-04T08:55:13+00:00"
1278 }, 1324 },
1279 { 1325 {
1280 "name": "phpunit/phpcov", 1326 "name": "phpunit/phpcov",
1281 "version": "2.0.2", 1327 "version": "3.1.0",
1282 "source": { 1328 "source": {
1283 "type": "git", 1329 "type": "git",
1284 "url": "https://github.com/sebastianbergmann/phpcov.git", 1330 "url": "https://github.com/sebastianbergmann/phpcov.git",
1285 "reference": "9ef291483ff65eefd8639584d61bbfb044d747f3" 1331 "reference": "2005bd90c2c8aae6d93ec82d9cda9d55dca96c3d"
1286 }, 1332 },
1287 "dist": { 1333 "dist": {
1288 "type": "zip", 1334 "type": "zip",
1289 "url": "https://api.github.com/repos/sebastianbergmann/phpcov/zipball/9ef291483ff65eefd8639584d61bbfb044d747f3", 1335 "url": "https://api.github.com/repos/sebastianbergmann/phpcov/zipball/2005bd90c2c8aae6d93ec82d9cda9d55dca96c3d",
1290 "reference": "9ef291483ff65eefd8639584d61bbfb044d747f3", 1336 "reference": "2005bd90c2c8aae6d93ec82d9cda9d55dca96c3d",
1291 "shasum": "" 1337 "shasum": ""
1292 }, 1338 },
1293 "require": { 1339 "require": {
1294 "php": ">=5.3.3", 1340 "php": "^5.6 || ^7.0",
1295 "phpunit/php-code-coverage": "~2.0", 1341 "phpunit/php-code-coverage": "^4.0",
1296 "phpunit/phpunit": ">=4.1", 1342 "phpunit/phpunit": "^5.0",
1297 "sebastian/diff": "~1.1", 1343 "sebastian/diff": "^1.1",
1298 "sebastian/finder-facade": "~1.1", 1344 "sebastian/finder-facade": "^1.1",
1299 "sebastian/version": "~1.0", 1345 "sebastian/version": "^1.0|^2.0",
1300 "symfony/console": "~2.2" 1346 "symfony/console": "^2|^3"
1301 }, 1347 },
1302 "bin": [ 1348 "bin": [
1303 "phpcov" 1349 "phpcov"
@@ -1305,7 +1351,7 @@
1305 "type": "library", 1351 "type": "library",
1306 "extra": { 1352 "extra": {
1307 "branch-alias": { 1353 "branch-alias": {
1308 "dev-master": "2.0.x-dev" 1354 "dev-master": "3.1.x-dev"
1309 } 1355 }
1310 }, 1356 },
1311 "autoload": { 1357 "autoload": {
@@ -1326,44 +1372,54 @@
1326 ], 1372 ],
1327 "description": "CLI frontend for PHP_CodeCoverage", 1373 "description": "CLI frontend for PHP_CodeCoverage",
1328 "homepage": "https://github.com/sebastianbergmann/phpcov", 1374 "homepage": "https://github.com/sebastianbergmann/phpcov",
1329 "time": "2015-10-05T09:24:23+00:00" 1375 "time": "2016-06-03T07:01:55+00:00"
1330 }, 1376 },
1331 { 1377 {
1332 "name": "phpunit/phpunit", 1378 "name": "phpunit/phpunit",
1333 "version": "4.8.36", 1379 "version": "5.7.27",
1334 "source": { 1380 "source": {
1335 "type": "git", 1381 "type": "git",
1336 "url": "https://github.com/sebastianbergmann/phpunit.git", 1382 "url": "https://github.com/sebastianbergmann/phpunit.git",
1337 "reference": "46023de9a91eec7dfb06cc56cb4e260017298517" 1383 "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c"
1338 }, 1384 },
1339 "dist": { 1385 "dist": {
1340 "type": "zip", 1386 "type": "zip",
1341 "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517", 1387 "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c",
1342 "reference": "46023de9a91eec7dfb06cc56cb4e260017298517", 1388 "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c",
1343 "shasum": "" 1389 "shasum": ""
1344 }, 1390 },
1345 "require": { 1391 "require": {
1346 "ext-dom": "*", 1392 "ext-dom": "*",
1347 "ext-json": "*", 1393 "ext-json": "*",
1348 "ext-pcre": "*", 1394 "ext-libxml": "*",
1349 "ext-reflection": "*", 1395 "ext-mbstring": "*",
1350 "ext-spl": "*", 1396 "ext-xml": "*",
1351 "php": ">=5.3.3", 1397 "myclabs/deep-copy": "~1.3",
1352 "phpspec/prophecy": "^1.3.1", 1398 "php": "^5.6 || ^7.0",
1353 "phpunit/php-code-coverage": "~2.1", 1399 "phpspec/prophecy": "^1.6.2",
1400 "phpunit/php-code-coverage": "^4.0.4",
1354 "phpunit/php-file-iterator": "~1.4", 1401 "phpunit/php-file-iterator": "~1.4",
1355 "phpunit/php-text-template": "~1.2", 1402 "phpunit/php-text-template": "~1.2",
1356 "phpunit/php-timer": "^1.0.6", 1403 "phpunit/php-timer": "^1.0.6",
1357 "phpunit/phpunit-mock-objects": "~2.3", 1404 "phpunit/phpunit-mock-objects": "^3.2",
1358 "sebastian/comparator": "~1.2.2", 1405 "sebastian/comparator": "^1.2.4",
1359 "sebastian/diff": "~1.2", 1406 "sebastian/diff": "^1.4.3",
1360 "sebastian/environment": "~1.3", 1407 "sebastian/environment": "^1.3.4 || ^2.0",
1361 "sebastian/exporter": "~1.2", 1408 "sebastian/exporter": "~2.0",
1362 "sebastian/global-state": "~1.0", 1409 "sebastian/global-state": "^1.1",
1363 "sebastian/version": "~1.0", 1410 "sebastian/object-enumerator": "~2.0",
1364 "symfony/yaml": "~2.1|~3.0" 1411 "sebastian/resource-operations": "~1.0",
1412 "sebastian/version": "^1.0.6|^2.0.1",
1413 "symfony/yaml": "~2.1|~3.0|~4.0"
1414 },
1415 "conflict": {
1416 "phpdocumentor/reflection-docblock": "3.0.2"
1417 },
1418 "require-dev": {
1419 "ext-pdo": "*"
1365 }, 1420 },
1366 "suggest": { 1421 "suggest": {
1422 "ext-xdebug": "*",
1367 "phpunit/php-invoker": "~1.1" 1423 "phpunit/php-invoker": "~1.1"
1368 }, 1424 },
1369 "bin": [ 1425 "bin": [
@@ -1372,7 +1428,7 @@
1372 "type": "library", 1428 "type": "library",
1373 "extra": { 1429 "extra": {
1374 "branch-alias": { 1430 "branch-alias": {
1375 "dev-master": "4.8.x-dev" 1431 "dev-master": "5.7.x-dev"
1376 } 1432 }
1377 }, 1433 },
1378 "autoload": { 1434 "autoload": {
@@ -1398,30 +1454,33 @@
1398 "testing", 1454 "testing",
1399 "xunit" 1455 "xunit"
1400 ], 1456 ],
1401 "time": "2017-06-21T08:07:12+00:00" 1457 "time": "2018-02-01T05:50:59+00:00"
1402 }, 1458 },
1403 { 1459 {
1404 "name": "phpunit/phpunit-mock-objects", 1460 "name": "phpunit/phpunit-mock-objects",
1405 "version": "2.3.8", 1461 "version": "3.4.4",
1406 "source": { 1462 "source": {
1407 "type": "git", 1463 "type": "git",
1408 "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 1464 "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
1409 "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" 1465 "reference": "a23b761686d50a560cc56233b9ecf49597cc9118"
1410 }, 1466 },
1411 "dist": { 1467 "dist": {
1412 "type": "zip", 1468 "type": "zip",
1413 "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", 1469 "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118",
1414 "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", 1470 "reference": "a23b761686d50a560cc56233b9ecf49597cc9118",
1415 "shasum": "" 1471 "shasum": ""
1416 }, 1472 },
1417 "require": { 1473 "require": {
1418 "doctrine/instantiator": "^1.0.2", 1474 "doctrine/instantiator": "^1.0.2",
1419 "php": ">=5.3.3", 1475 "php": "^5.6 || ^7.0",
1420 "phpunit/php-text-template": "~1.2", 1476 "phpunit/php-text-template": "^1.2",
1421 "sebastian/exporter": "~1.2" 1477 "sebastian/exporter": "^1.2 || ^2.0"
1478 },
1479 "conflict": {
1480 "phpunit/phpunit": "<5.4.0"
1422 }, 1481 },
1423 "require-dev": { 1482 "require-dev": {
1424 "phpunit/phpunit": "~4.4" 1483 "phpunit/phpunit": "^5.4"
1425 }, 1484 },
1426 "suggest": { 1485 "suggest": {
1427 "ext-soap": "*" 1486 "ext-soap": "*"
@@ -1429,7 +1488,7 @@
1429 "type": "library", 1488 "type": "library",
1430 "extra": { 1489 "extra": {
1431 "branch-alias": { 1490 "branch-alias": {
1432 "dev-master": "2.3.x-dev" 1491 "dev-master": "3.2.x-dev"
1433 } 1492 }
1434 }, 1493 },
1435 "autoload": { 1494 "autoload": {
@@ -1454,7 +1513,52 @@
1454 "mock", 1513 "mock",
1455 "xunit" 1514 "xunit"
1456 ], 1515 ],
1457 "time": "2015-10-02T06:51:40+00:00" 1516 "time": "2017-06-30T09:13:00+00:00"
1517 },
1518 {
1519 "name": "sebastian/code-unit-reverse-lookup",
1520 "version": "1.0.1",
1521 "source": {
1522 "type": "git",
1523 "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
1524 "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18"
1525 },
1526 "dist": {
1527 "type": "zip",
1528 "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
1529 "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
1530 "shasum": ""
1531 },
1532 "require": {
1533 "php": "^5.6 || ^7.0"
1534 },
1535 "require-dev": {
1536 "phpunit/phpunit": "^5.7 || ^6.0"
1537 },
1538 "type": "library",
1539 "extra": {
1540 "branch-alias": {
1541 "dev-master": "1.0.x-dev"
1542 }
1543 },
1544 "autoload": {
1545 "classmap": [
1546 "src/"
1547 ]
1548 },
1549 "notification-url": "https://packagist.org/downloads/",
1550 "license": [
1551 "BSD-3-Clause"
1552 ],
1553 "authors": [
1554 {
1555 "name": "Sebastian Bergmann",
1556 "email": "sebastian@phpunit.de"
1557 }
1558 ],
1559 "description": "Looks up which function or method a line of code belongs to",
1560 "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
1561 "time": "2017-03-04T06:30:41+00:00"
1458 }, 1562 },
1459 { 1563 {
1460 "name": "sebastian/comparator", 1564 "name": "sebastian/comparator",
@@ -1574,28 +1678,28 @@
1574 }, 1678 },
1575 { 1679 {
1576 "name": "sebastian/environment", 1680 "name": "sebastian/environment",
1577 "version": "1.3.8", 1681 "version": "2.0.0",
1578 "source": { 1682 "source": {
1579 "type": "git", 1683 "type": "git",
1580 "url": "https://github.com/sebastianbergmann/environment.git", 1684 "url": "https://github.com/sebastianbergmann/environment.git",
1581 "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea" 1685 "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac"
1582 }, 1686 },
1583 "dist": { 1687 "dist": {
1584 "type": "zip", 1688 "type": "zip",
1585 "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea", 1689 "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac",
1586 "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea", 1690 "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac",
1587 "shasum": "" 1691 "shasum": ""
1588 }, 1692 },
1589 "require": { 1693 "require": {
1590 "php": "^5.3.3 || ^7.0" 1694 "php": "^5.6 || ^7.0"
1591 }, 1695 },
1592 "require-dev": { 1696 "require-dev": {
1593 "phpunit/phpunit": "^4.8 || ^5.0" 1697 "phpunit/phpunit": "^5.0"
1594 }, 1698 },
1595 "type": "library", 1699 "type": "library",
1596 "extra": { 1700 "extra": {
1597 "branch-alias": { 1701 "branch-alias": {
1598 "dev-master": "1.3.x-dev" 1702 "dev-master": "2.0.x-dev"
1599 } 1703 }
1600 }, 1704 },
1601 "autoload": { 1705 "autoload": {
@@ -1620,25 +1724,25 @@
1620 "environment", 1724 "environment",
1621 "hhvm" 1725 "hhvm"
1622 ], 1726 ],
1623 "time": "2016-08-18T05:49:44+00:00" 1727 "time": "2016-11-26T07:53:53+00:00"
1624 }, 1728 },
1625 { 1729 {
1626 "name": "sebastian/exporter", 1730 "name": "sebastian/exporter",
1627 "version": "1.2.2", 1731 "version": "2.0.0",
1628 "source": { 1732 "source": {
1629 "type": "git", 1733 "type": "git",
1630 "url": "https://github.com/sebastianbergmann/exporter.git", 1734 "url": "https://github.com/sebastianbergmann/exporter.git",
1631 "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" 1735 "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4"
1632 }, 1736 },
1633 "dist": { 1737 "dist": {
1634 "type": "zip", 1738 "type": "zip",
1635 "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", 1739 "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
1636 "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", 1740 "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
1637 "shasum": "" 1741 "shasum": ""
1638 }, 1742 },
1639 "require": { 1743 "require": {
1640 "php": ">=5.3.3", 1744 "php": ">=5.3.3",
1641 "sebastian/recursion-context": "~1.0" 1745 "sebastian/recursion-context": "~2.0"
1642 }, 1746 },
1643 "require-dev": { 1747 "require-dev": {
1644 "ext-mbstring": "*", 1748 "ext-mbstring": "*",
@@ -1647,7 +1751,7 @@
1647 "type": "library", 1751 "type": "library",
1648 "extra": { 1752 "extra": {
1649 "branch-alias": { 1753 "branch-alias": {
1650 "dev-master": "1.3.x-dev" 1754 "dev-master": "2.0.x-dev"
1651 } 1755 }
1652 }, 1756 },
1653 "autoload": { 1757 "autoload": {
@@ -1687,24 +1791,24 @@
1687 "export", 1791 "export",
1688 "exporter" 1792 "exporter"
1689 ], 1793 ],
1690 "time": "2016-06-17T09:04:28+00:00" 1794 "time": "2016-11-19T08:54:04+00:00"
1691 }, 1795 },
1692 { 1796 {
1693 "name": "sebastian/finder-facade", 1797 "name": "sebastian/finder-facade",
1694 "version": "1.2.1", 1798 "version": "1.2.2",
1695 "source": { 1799 "source": {
1696 "type": "git", 1800 "type": "git",
1697 "url": "https://github.com/sebastianbergmann/finder-facade.git", 1801 "url": "https://github.com/sebastianbergmann/finder-facade.git",
1698 "reference": "2a6f7f57efc0aa2d23297d9fd9e2a03111a8c0b9" 1802 "reference": "4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f"
1699 }, 1803 },
1700 "dist": { 1804 "dist": {
1701 "type": "zip", 1805 "type": "zip",
1702 "url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/2a6f7f57efc0aa2d23297d9fd9e2a03111a8c0b9", 1806 "url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f",
1703 "reference": "2a6f7f57efc0aa2d23297d9fd9e2a03111a8c0b9", 1807 "reference": "4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f",
1704 "shasum": "" 1808 "shasum": ""
1705 }, 1809 },
1706 "require": { 1810 "require": {
1707 "symfony/finder": "~2.3|~3.0", 1811 "symfony/finder": "~2.3|~3.0|~4.0",
1708 "theseer/fdomdocument": "~1.3" 1812 "theseer/fdomdocument": "~1.3"
1709 }, 1813 },
1710 "type": "library", 1814 "type": "library",
@@ -1726,7 +1830,7 @@
1726 ], 1830 ],
1727 "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.", 1831 "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.",
1728 "homepage": "https://github.com/sebastianbergmann/finder-facade", 1832 "homepage": "https://github.com/sebastianbergmann/finder-facade",
1729 "time": "2016-02-17T07:02:23+00:00" 1833 "time": "2017-11-18T17:31:49+00:00"
1730 }, 1834 },
1731 { 1835 {
1732 "name": "sebastian/global-state", 1836 "name": "sebastian/global-state",
@@ -1780,26 +1884,71 @@
1780 "time": "2015-10-12T03:26:01+00:00" 1884 "time": "2015-10-12T03:26:01+00:00"
1781 }, 1885 },
1782 { 1886 {
1887 "name": "sebastian/object-enumerator",
1888 "version": "2.0.1",
1889 "source": {
1890 "type": "git",
1891 "url": "https://github.com/sebastianbergmann/object-enumerator.git",
1892 "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7"
1893 },
1894 "dist": {
1895 "type": "zip",
1896 "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7",
1897 "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7",
1898 "shasum": ""
1899 },
1900 "require": {
1901 "php": ">=5.6",
1902 "sebastian/recursion-context": "~2.0"
1903 },
1904 "require-dev": {
1905 "phpunit/phpunit": "~5"
1906 },
1907 "type": "library",
1908 "extra": {
1909 "branch-alias": {
1910 "dev-master": "2.0.x-dev"
1911 }
1912 },
1913 "autoload": {
1914 "classmap": [
1915 "src/"
1916 ]
1917 },
1918 "notification-url": "https://packagist.org/downloads/",
1919 "license": [
1920 "BSD-3-Clause"
1921 ],
1922 "authors": [
1923 {
1924 "name": "Sebastian Bergmann",
1925 "email": "sebastian@phpunit.de"
1926 }
1927 ],
1928 "description": "Traverses array structures and object graphs to enumerate all referenced objects",
1929 "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
1930 "time": "2017-02-18T15:18:39+00:00"
1931 },
1932 {
1783 "name": "sebastian/phpcpd", 1933 "name": "sebastian/phpcpd",
1784 "version": "2.0.4", 1934 "version": "3.0.1",
1785 "source": { 1935 "source": {
1786 "type": "git", 1936 "type": "git",
1787 "url": "https://github.com/sebastianbergmann/phpcpd.git", 1937 "url": "https://github.com/sebastianbergmann/phpcpd.git",
1788 "reference": "24d9a880deadb0b8c9680e9cfe78e30b704225db" 1938 "reference": "dfed51c1288790fc957c9433e2f49ab152e8a564"
1789 }, 1939 },
1790 "dist": { 1940 "dist": {
1791 "type": "zip", 1941 "type": "zip",
1792 "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/24d9a880deadb0b8c9680e9cfe78e30b704225db", 1942 "url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/dfed51c1288790fc957c9433e2f49ab152e8a564",
1793 "reference": "24d9a880deadb0b8c9680e9cfe78e30b704225db", 1943 "reference": "dfed51c1288790fc957c9433e2f49ab152e8a564",
1794 "shasum": "" 1944 "shasum": ""
1795 }, 1945 },
1796 "require": { 1946 "require": {
1797 "php": ">=5.3.3", 1947 "php": "^5.6|^7.0",
1798 "phpunit/php-timer": ">=1.0.6", 1948 "phpunit/php-timer": "^1.0.6",
1799 "sebastian/finder-facade": "~1.1", 1949 "sebastian/finder-facade": "^1.1",
1800 "sebastian/version": "~1.0|~2.0", 1950 "sebastian/version": "^1.0|^2.0",
1801 "symfony/console": "~2.7|^3.0", 1951 "symfony/console": "^2.7|^3.0|^4.0"
1802 "theseer/fdomdocument": "~1.4"
1803 }, 1952 },
1804 "bin": [ 1953 "bin": [
1805 "phpcpd" 1954 "phpcpd"
@@ -1807,7 +1956,7 @@
1807 "type": "library", 1956 "type": "library",
1808 "extra": { 1957 "extra": {
1809 "branch-alias": { 1958 "branch-alias": {
1810 "dev-master": "2.0-dev" 1959 "dev-master": "3.0-dev"
1811 } 1960 }
1812 }, 1961 },
1813 "autoload": { 1962 "autoload": {
@@ -1828,20 +1977,20 @@
1828 ], 1977 ],
1829 "description": "Copy/Paste Detector (CPD) for PHP code.", 1978 "description": "Copy/Paste Detector (CPD) for PHP code.",
1830 "homepage": "https://github.com/sebastianbergmann/phpcpd", 1979 "homepage": "https://github.com/sebastianbergmann/phpcpd",
1831 "time": "2016-04-17T19:32:49+00:00" 1980 "time": "2017-11-16T08:49:28+00:00"
1832 }, 1981 },
1833 { 1982 {
1834 "name": "sebastian/recursion-context", 1983 "name": "sebastian/recursion-context",
1835 "version": "1.0.5", 1984 "version": "2.0.0",
1836 "source": { 1985 "source": {
1837 "type": "git", 1986 "type": "git",
1838 "url": "https://github.com/sebastianbergmann/recursion-context.git", 1987 "url": "https://github.com/sebastianbergmann/recursion-context.git",
1839 "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7" 1988 "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a"
1840 }, 1989 },
1841 "dist": { 1990 "dist": {
1842 "type": "zip", 1991 "type": "zip",
1843 "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7", 1992 "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a",
1844 "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7", 1993 "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a",
1845 "shasum": "" 1994 "shasum": ""
1846 }, 1995 },
1847 "require": { 1996 "require": {
@@ -1853,7 +2002,7 @@
1853 "type": "library", 2002 "type": "library",
1854 "extra": { 2003 "extra": {
1855 "branch-alias": { 2004 "branch-alias": {
1856 "dev-master": "1.0.x-dev" 2005 "dev-master": "2.0.x-dev"
1857 } 2006 }
1858 }, 2007 },
1859 "autoload": { 2008 "autoload": {
@@ -1881,23 +2030,73 @@
1881 ], 2030 ],
1882 "description": "Provides functionality to recursively process PHP variables", 2031 "description": "Provides functionality to recursively process PHP variables",
1883 "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 2032 "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
1884 "time": "2016-10-03T07:41:43+00:00" 2033 "time": "2016-11-19T07:33:16+00:00"
2034 },
2035 {
2036 "name": "sebastian/resource-operations",
2037 "version": "1.0.0",
2038 "source": {
2039 "type": "git",
2040 "url": "https://github.com/sebastianbergmann/resource-operations.git",
2041 "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52"
2042 },
2043 "dist": {
2044 "type": "zip",
2045 "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
2046 "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
2047 "shasum": ""
2048 },
2049 "require": {
2050 "php": ">=5.6.0"
2051 },
2052 "type": "library",
2053 "extra": {
2054 "branch-alias": {
2055 "dev-master": "1.0.x-dev"
2056 }
2057 },
2058 "autoload": {
2059 "classmap": [
2060 "src/"
2061 ]
2062 },
2063 "notification-url": "https://packagist.org/downloads/",
2064 "license": [
2065 "BSD-3-Clause"
2066 ],
2067 "authors": [
2068 {
2069 "name": "Sebastian Bergmann",
2070 "email": "sebastian@phpunit.de"
2071 }
2072 ],
2073 "description": "Provides a list of PHP built-in functions that operate on resources",
2074 "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
2075 "time": "2015-07-28T20:34:47+00:00"
1885 }, 2076 },
1886 { 2077 {
1887 "name": "sebastian/version", 2078 "name": "sebastian/version",
1888 "version": "1.0.6", 2079 "version": "2.0.1",
1889 "source": { 2080 "source": {
1890 "type": "git", 2081 "type": "git",
1891 "url": "https://github.com/sebastianbergmann/version.git", 2082 "url": "https://github.com/sebastianbergmann/version.git",
1892 "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" 2083 "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
1893 }, 2084 },
1894 "dist": { 2085 "dist": {
1895 "type": "zip", 2086 "type": "zip",
1896 "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", 2087 "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
1897 "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", 2088 "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
1898 "shasum": "" 2089 "shasum": ""
1899 }, 2090 },
2091 "require": {
2092 "php": ">=5.6"
2093 },
1900 "type": "library", 2094 "type": "library",
2095 "extra": {
2096 "branch-alias": {
2097 "dev-master": "2.0.x-dev"
2098 }
2099 },
1901 "autoload": { 2100 "autoload": {
1902 "classmap": [ 2101 "classmap": [
1903 "src/" 2102 "src/"
@@ -1916,7 +2115,7 @@
1916 ], 2115 ],
1917 "description": "Library that helps with managing the version number of Git-hosted PHP projects", 2116 "description": "Library that helps with managing the version number of Git-hosted PHP projects",
1918 "homepage": "https://github.com/sebastianbergmann/version", 2117 "homepage": "https://github.com/sebastianbergmann/version",
1919 "time": "2015-06-21T13:59:46+00:00" 2118 "time": "2016-10-03T07:35:21+00:00"
1920 }, 2119 },
1921 { 2120 {
1922 "name": "squizlabs/php_codesniffer", 2121 "name": "squizlabs/php_codesniffer",
@@ -1998,30 +2197,30 @@
1998 }, 2197 },
1999 { 2198 {
2000 "name": "symfony/config", 2199 "name": "symfony/config",
2001 "version": "v3.3.10", 2200 "version": "v3.4.4",
2002 "source": { 2201 "source": {
2003 "type": "git", 2202 "type": "git",
2004 "url": "https://github.com/symfony/config.git", 2203 "url": "https://github.com/symfony/config.git",
2005 "reference": "4ab62407bff9cd97c410a7feaef04c375aaa5cfd" 2204 "reference": "72689b934d6c6ecf73eca874e98933bf055313c9"
2006 }, 2205 },
2007 "dist": { 2206 "dist": {
2008 "type": "zip", 2207 "type": "zip",
2009 "url": "https://api.github.com/repos/symfony/config/zipball/4ab62407bff9cd97c410a7feaef04c375aaa5cfd", 2208 "url": "https://api.github.com/repos/symfony/config/zipball/72689b934d6c6ecf73eca874e98933bf055313c9",
2010 "reference": "4ab62407bff9cd97c410a7feaef04c375aaa5cfd", 2209 "reference": "72689b934d6c6ecf73eca874e98933bf055313c9",
2011 "shasum": "" 2210 "shasum": ""
2012 }, 2211 },
2013 "require": { 2212 "require": {
2014 "php": "^5.5.9|>=7.0.8", 2213 "php": "^5.5.9|>=7.0.8",
2015 "symfony/filesystem": "~2.8|~3.0" 2214 "symfony/filesystem": "~2.8|~3.0|~4.0"
2016 }, 2215 },
2017 "conflict": { 2216 "conflict": {
2018 "symfony/dependency-injection": "<3.3", 2217 "symfony/dependency-injection": "<3.3",
2019 "symfony/finder": "<3.3" 2218 "symfony/finder": "<3.3"
2020 }, 2219 },
2021 "require-dev": { 2220 "require-dev": {
2022 "symfony/dependency-injection": "~3.3", 2221 "symfony/dependency-injection": "~3.3|~4.0",
2023 "symfony/finder": "~3.3", 2222 "symfony/finder": "~3.3|~4.0",
2024 "symfony/yaml": "~3.0" 2223 "symfony/yaml": "~3.0|~4.0"
2025 }, 2224 },
2026 "suggest": { 2225 "suggest": {
2027 "symfony/yaml": "To use the yaml reference dumper" 2226 "symfony/yaml": "To use the yaml reference dumper"
@@ -2029,7 +2228,7 @@
2029 "type": "library", 2228 "type": "library",
2030 "extra": { 2229 "extra": {
2031 "branch-alias": { 2230 "branch-alias": {
2032 "dev-master": "3.3-dev" 2231 "dev-master": "3.4-dev"
2033 } 2232 }
2034 }, 2233 },
2035 "autoload": { 2234 "autoload": {
@@ -2056,41 +2255,49 @@
2056 ], 2255 ],
2057 "description": "Symfony Config Component", 2256 "description": "Symfony Config Component",
2058 "homepage": "https://symfony.com", 2257 "homepage": "https://symfony.com",
2059 "time": "2017-10-04T18:56:58+00:00" 2258 "time": "2018-01-21T19:05:02+00:00"
2060 }, 2259 },
2061 { 2260 {
2062 "name": "symfony/console", 2261 "name": "symfony/console",
2063 "version": "v2.8.28", 2262 "version": "v3.4.4",
2064 "source": { 2263 "source": {
2065 "type": "git", 2264 "type": "git",
2066 "url": "https://github.com/symfony/console.git", 2265 "url": "https://github.com/symfony/console.git",
2067 "reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853" 2266 "reference": "26b6f419edda16c19775211987651cb27baea7f1"
2068 }, 2267 },
2069 "dist": { 2268 "dist": {
2070 "type": "zip", 2269 "type": "zip",
2071 "url": "https://api.github.com/repos/symfony/console/zipball/f81549d2c5fdee8d711c9ab3c7e7362353ea5853", 2270 "url": "https://api.github.com/repos/symfony/console/zipball/26b6f419edda16c19775211987651cb27baea7f1",
2072 "reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853", 2271 "reference": "26b6f419edda16c19775211987651cb27baea7f1",
2073 "shasum": "" 2272 "shasum": ""
2074 }, 2273 },
2075 "require": { 2274 "require": {
2076 "php": ">=5.3.9", 2275 "php": "^5.5.9|>=7.0.8",
2077 "symfony/debug": "^2.7.2|~3.0.0", 2276 "symfony/debug": "~2.8|~3.0|~4.0",
2078 "symfony/polyfill-mbstring": "~1.0" 2277 "symfony/polyfill-mbstring": "~1.0"
2079 }, 2278 },
2279 "conflict": {
2280 "symfony/dependency-injection": "<3.4",
2281 "symfony/process": "<3.3"
2282 },
2080 "require-dev": { 2283 "require-dev": {
2081 "psr/log": "~1.0", 2284 "psr/log": "~1.0",
2082 "symfony/event-dispatcher": "~2.1|~3.0.0", 2285 "symfony/config": "~3.3|~4.0",
2083 "symfony/process": "~2.1|~3.0.0" 2286 "symfony/dependency-injection": "~3.4|~4.0",
2287 "symfony/event-dispatcher": "~2.8|~3.0|~4.0",
2288 "symfony/lock": "~3.4|~4.0",
2289 "symfony/process": "~3.3|~4.0"
2084 }, 2290 },
2085 "suggest": { 2291 "suggest": {
2086 "psr/log": "For using the console logger", 2292 "psr/log": "For using the console logger",
2087 "symfony/event-dispatcher": "", 2293 "symfony/event-dispatcher": "",
2294 "symfony/lock": "",
2088 "symfony/process": "" 2295 "symfony/process": ""
2089 }, 2296 },
2090 "type": "library", 2297 "type": "library",
2091 "extra": { 2298 "extra": {
2092 "branch-alias": { 2299 "branch-alias": {
2093 "dev-master": "2.8-dev" 2300 "dev-master": "3.4-dev"
2094 } 2301 }
2095 }, 2302 },
2096 "autoload": { 2303 "autoload": {
@@ -2117,37 +2324,36 @@
2117 ], 2324 ],
2118 "description": "Symfony Console Component", 2325 "description": "Symfony Console Component",
2119 "homepage": "https://symfony.com", 2326 "homepage": "https://symfony.com",
2120 "time": "2017-10-01T21:00:16+00:00" 2327 "time": "2018-01-29T09:03:43+00:00"
2121 }, 2328 },
2122 { 2329 {
2123 "name": "symfony/debug", 2330 "name": "symfony/debug",
2124 "version": "v3.0.9", 2331 "version": "v3.4.4",
2125 "source": { 2332 "source": {
2126 "type": "git", 2333 "type": "git",
2127 "url": "https://github.com/symfony/debug.git", 2334 "url": "https://github.com/symfony/debug.git",
2128 "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a" 2335 "reference": "53f6af2805daf52a43b393b93d2f24925d35c937"
2129 }, 2336 },
2130 "dist": { 2337 "dist": {
2131 "type": "zip", 2338 "type": "zip",
2132 "url": "https://api.github.com/repos/symfony/debug/zipball/697c527acd9ea1b2d3efac34d9806bf255278b0a", 2339 "url": "https://api.github.com/repos/symfony/debug/zipball/53f6af2805daf52a43b393b93d2f24925d35c937",
2133 "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a", 2340 "reference": "53f6af2805daf52a43b393b93d2f24925d35c937",
2134 "shasum": "" 2341 "shasum": ""
2135 }, 2342 },
2136 "require": { 2343 "require": {
2137 "php": ">=5.5.9", 2344 "php": "^5.5.9|>=7.0.8",
2138 "psr/log": "~1.0" 2345 "psr/log": "~1.0"
2139 }, 2346 },
2140 "conflict": { 2347 "conflict": {
2141 "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" 2348 "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2"
2142 }, 2349 },
2143 "require-dev": { 2350 "require-dev": {
2144 "symfony/class-loader": "~2.8|~3.0", 2351 "symfony/http-kernel": "~2.8|~3.0|~4.0"
2145 "symfony/http-kernel": "~2.8|~3.0"
2146 }, 2352 },
2147 "type": "library", 2353 "type": "library",
2148 "extra": { 2354 "extra": {
2149 "branch-alias": { 2355 "branch-alias": {
2150 "dev-master": "3.0-dev" 2356 "dev-master": "3.4-dev"
2151 } 2357 }
2152 }, 2358 },
2153 "autoload": { 2359 "autoload": {
@@ -2174,20 +2380,20 @@
2174 ], 2380 ],
2175 "description": "Symfony Debug Component", 2381 "description": "Symfony Debug Component",
2176 "homepage": "https://symfony.com", 2382 "homepage": "https://symfony.com",
2177 "time": "2016-07-30T07:22:48+00:00" 2383 "time": "2018-01-18T22:16:57+00:00"
2178 }, 2384 },
2179 { 2385 {
2180 "name": "symfony/dependency-injection", 2386 "name": "symfony/dependency-injection",
2181 "version": "v3.3.10", 2387 "version": "v3.4.4",
2182 "source": { 2388 "source": {
2183 "type": "git", 2389 "type": "git",
2184 "url": "https://github.com/symfony/dependency-injection.git", 2390 "url": "https://github.com/symfony/dependency-injection.git",
2185 "reference": "8ebad929aee3ca185b05f55d9cc5521670821ad1" 2391 "reference": "4b2717ee2499390e371e1fc7abaf886c1c83e83d"
2186 }, 2392 },
2187 "dist": { 2393 "dist": {
2188 "type": "zip", 2394 "type": "zip",
2189 "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/8ebad929aee3ca185b05f55d9cc5521670821ad1", 2395 "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/4b2717ee2499390e371e1fc7abaf886c1c83e83d",
2190 "reference": "8ebad929aee3ca185b05f55d9cc5521670821ad1", 2396 "reference": "4b2717ee2499390e371e1fc7abaf886c1c83e83d",
2191 "shasum": "" 2397 "shasum": ""
2192 }, 2398 },
2193 "require": { 2399 "require": {
@@ -2195,17 +2401,18 @@
2195 "psr/container": "^1.0" 2401 "psr/container": "^1.0"
2196 }, 2402 },
2197 "conflict": { 2403 "conflict": {
2198 "symfony/config": "<3.3.1", 2404 "symfony/config": "<3.3.7",
2199 "symfony/finder": "<3.3", 2405 "symfony/finder": "<3.3",
2200 "symfony/yaml": "<3.3" 2406 "symfony/proxy-manager-bridge": "<3.4",
2407 "symfony/yaml": "<3.4"
2201 }, 2408 },
2202 "provide": { 2409 "provide": {
2203 "psr/container-implementation": "1.0" 2410 "psr/container-implementation": "1.0"
2204 }, 2411 },
2205 "require-dev": { 2412 "require-dev": {
2206 "symfony/config": "~3.3", 2413 "symfony/config": "~3.3|~4.0",
2207 "symfony/expression-language": "~2.8|~3.0", 2414 "symfony/expression-language": "~2.8|~3.0|~4.0",
2208 "symfony/yaml": "~3.3" 2415 "symfony/yaml": "~3.4|~4.0"
2209 }, 2416 },
2210 "suggest": { 2417 "suggest": {
2211 "symfony/config": "", 2418 "symfony/config": "",
@@ -2217,7 +2424,7 @@
2217 "type": "library", 2424 "type": "library",
2218 "extra": { 2425 "extra": {
2219 "branch-alias": { 2426 "branch-alias": {
2220 "dev-master": "3.3-dev" 2427 "dev-master": "3.4-dev"
2221 } 2428 }
2222 }, 2429 },
2223 "autoload": { 2430 "autoload": {
@@ -2244,20 +2451,20 @@
2244 ], 2451 ],
2245 "description": "Symfony DependencyInjection Component", 2452 "description": "Symfony DependencyInjection Component",
2246 "homepage": "https://symfony.com", 2453 "homepage": "https://symfony.com",
2247 "time": "2017-10-04T17:15:30+00:00" 2454 "time": "2018-01-29T09:16:57+00:00"
2248 }, 2455 },
2249 { 2456 {
2250 "name": "symfony/filesystem", 2457 "name": "symfony/filesystem",
2251 "version": "v3.3.10", 2458 "version": "v3.4.4",
2252 "source": { 2459 "source": {
2253 "type": "git", 2460 "type": "git",
2254 "url": "https://github.com/symfony/filesystem.git", 2461 "url": "https://github.com/symfony/filesystem.git",
2255 "reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1" 2462 "reference": "e078773ad6354af38169faf31c21df0f18ace03d"
2256 }, 2463 },
2257 "dist": { 2464 "dist": {
2258 "type": "zip", 2465 "type": "zip",
2259 "url": "https://api.github.com/repos/symfony/filesystem/zipball/90bc45abf02ae6b7deb43895c1052cb0038506f1", 2466 "url": "https://api.github.com/repos/symfony/filesystem/zipball/e078773ad6354af38169faf31c21df0f18ace03d",
2260 "reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1", 2467 "reference": "e078773ad6354af38169faf31c21df0f18ace03d",
2261 "shasum": "" 2468 "shasum": ""
2262 }, 2469 },
2263 "require": { 2470 "require": {
@@ -2266,7 +2473,7 @@
2266 "type": "library", 2473 "type": "library",
2267 "extra": { 2474 "extra": {
2268 "branch-alias": { 2475 "branch-alias": {
2269 "dev-master": "3.3-dev" 2476 "dev-master": "3.4-dev"
2270 } 2477 }
2271 }, 2478 },
2272 "autoload": { 2479 "autoload": {
@@ -2293,20 +2500,20 @@
2293 ], 2500 ],
2294 "description": "Symfony Filesystem Component", 2501 "description": "Symfony Filesystem Component",
2295 "homepage": "https://symfony.com", 2502 "homepage": "https://symfony.com",
2296 "time": "2017-10-03T13:33:10+00:00" 2503 "time": "2018-01-03T07:37:34+00:00"
2297 }, 2504 },
2298 { 2505 {
2299 "name": "symfony/finder", 2506 "name": "symfony/finder",
2300 "version": "v3.3.10", 2507 "version": "v3.4.4",
2301 "source": { 2508 "source": {
2302 "type": "git", 2509 "type": "git",
2303 "url": "https://github.com/symfony/finder.git", 2510 "url": "https://github.com/symfony/finder.git",
2304 "reference": "773e19a491d97926f236942484cb541560ce862d" 2511 "reference": "613e26310776f49a1773b6737c6bd554b8bc8c6f"
2305 }, 2512 },
2306 "dist": { 2513 "dist": {
2307 "type": "zip", 2514 "type": "zip",
2308 "url": "https://api.github.com/repos/symfony/finder/zipball/773e19a491d97926f236942484cb541560ce862d", 2515 "url": "https://api.github.com/repos/symfony/finder/zipball/613e26310776f49a1773b6737c6bd554b8bc8c6f",
2309 "reference": "773e19a491d97926f236942484cb541560ce862d", 2516 "reference": "613e26310776f49a1773b6737c6bd554b8bc8c6f",
2310 "shasum": "" 2517 "shasum": ""
2311 }, 2518 },
2312 "require": { 2519 "require": {
@@ -2315,7 +2522,7 @@
2315 "type": "library", 2522 "type": "library",
2316 "extra": { 2523 "extra": {
2317 "branch-alias": { 2524 "branch-alias": {
2318 "dev-master": "3.3-dev" 2525 "dev-master": "3.4-dev"
2319 } 2526 }
2320 }, 2527 },
2321 "autoload": { 2528 "autoload": {
@@ -2342,20 +2549,20 @@
2342 ], 2549 ],
2343 "description": "Symfony Finder Component", 2550 "description": "Symfony Finder Component",
2344 "homepage": "https://symfony.com", 2551 "homepage": "https://symfony.com",
2345 "time": "2017-10-02T06:42:24+00:00" 2552 "time": "2018-01-03T07:37:34+00:00"
2346 }, 2553 },
2347 { 2554 {
2348 "name": "symfony/polyfill-mbstring", 2555 "name": "symfony/polyfill-mbstring",
2349 "version": "v1.6.0", 2556 "version": "v1.7.0",
2350 "source": { 2557 "source": {
2351 "type": "git", 2558 "type": "git",
2352 "url": "https://github.com/symfony/polyfill-mbstring.git", 2559 "url": "https://github.com/symfony/polyfill-mbstring.git",
2353 "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296" 2560 "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b"
2354 }, 2561 },
2355 "dist": { 2562 "dist": {
2356 "type": "zip", 2563 "type": "zip",
2357 "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", 2564 "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b",
2358 "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", 2565 "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b",
2359 "shasum": "" 2566 "shasum": ""
2360 }, 2567 },
2361 "require": { 2568 "require": {
@@ -2367,7 +2574,7 @@
2367 "type": "library", 2574 "type": "library",
2368 "extra": { 2575 "extra": {
2369 "branch-alias": { 2576 "branch-alias": {
2370 "dev-master": "1.6-dev" 2577 "dev-master": "1.7-dev"
2371 } 2578 }
2372 }, 2579 },
2373 "autoload": { 2580 "autoload": {
@@ -2401,27 +2608,30 @@
2401 "portable", 2608 "portable",
2402 "shim" 2609 "shim"
2403 ], 2610 ],
2404 "time": "2017-10-11T12:05:26+00:00" 2611 "time": "2018-01-30T19:27:44+00:00"
2405 }, 2612 },
2406 { 2613 {
2407 "name": "symfony/yaml", 2614 "name": "symfony/yaml",
2408 "version": "v3.3.10", 2615 "version": "v3.4.4",
2409 "source": { 2616 "source": {
2410 "type": "git", 2617 "type": "git",
2411 "url": "https://github.com/symfony/yaml.git", 2618 "url": "https://github.com/symfony/yaml.git",
2412 "reference": "8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46" 2619 "reference": "eab73b6c21d27ae4cd037c417618dfd4befb0bfe"
2413 }, 2620 },
2414 "dist": { 2621 "dist": {
2415 "type": "zip", 2622 "type": "zip",
2416 "url": "https://api.github.com/repos/symfony/yaml/zipball/8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46", 2623 "url": "https://api.github.com/repos/symfony/yaml/zipball/eab73b6c21d27ae4cd037c417618dfd4befb0bfe",
2417 "reference": "8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46", 2624 "reference": "eab73b6c21d27ae4cd037c417618dfd4befb0bfe",
2418 "shasum": "" 2625 "shasum": ""
2419 }, 2626 },
2420 "require": { 2627 "require": {
2421 "php": "^5.5.9|>=7.0.8" 2628 "php": "^5.5.9|>=7.0.8"
2422 }, 2629 },
2630 "conflict": {
2631 "symfony/console": "<3.4"
2632 },
2423 "require-dev": { 2633 "require-dev": {
2424 "symfony/console": "~2.8|~3.0" 2634 "symfony/console": "~3.4|~4.0"
2425 }, 2635 },
2426 "suggest": { 2636 "suggest": {
2427 "symfony/console": "For validating YAML files using the lint command" 2637 "symfony/console": "For validating YAML files using the lint command"
@@ -2429,7 +2639,7 @@
2429 "type": "library", 2639 "type": "library",
2430 "extra": { 2640 "extra": {
2431 "branch-alias": { 2641 "branch-alias": {
2432 "dev-master": "3.3-dev" 2642 "dev-master": "3.4-dev"
2433 } 2643 }
2434 }, 2644 },
2435 "autoload": { 2645 "autoload": {
@@ -2456,7 +2666,7 @@
2456 ], 2666 ],
2457 "description": "Symfony Yaml Component", 2667 "description": "Symfony Yaml Component",
2458 "homepage": "https://symfony.com", 2668 "homepage": "https://symfony.com",
2459 "time": "2017-10-05T14:43:42+00:00" 2669 "time": "2018-01-21T19:05:02+00:00"
2460 }, 2670 },
2461 { 2671 {
2462 "name": "theseer/fdomdocument", 2672 "name": "theseer/fdomdocument",
@@ -2500,16 +2710,16 @@
2500 }, 2710 },
2501 { 2711 {
2502 "name": "webmozart/assert", 2712 "name": "webmozart/assert",
2503 "version": "1.2.0", 2713 "version": "1.3.0",
2504 "source": { 2714 "source": {
2505 "type": "git", 2715 "type": "git",
2506 "url": "https://github.com/webmozart/assert.git", 2716 "url": "https://github.com/webmozart/assert.git",
2507 "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" 2717 "reference": "0df1908962e7a3071564e857d86874dad1ef204a"
2508 }, 2718 },
2509 "dist": { 2719 "dist": {
2510 "type": "zip", 2720 "type": "zip",
2511 "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", 2721 "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a",
2512 "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", 2722 "reference": "0df1908962e7a3071564e857d86874dad1ef204a",
2513 "shasum": "" 2723 "shasum": ""
2514 }, 2724 },
2515 "require": { 2725 "require": {
@@ -2546,7 +2756,7 @@
2546 "check", 2756 "check",
2547 "validate" 2757 "validate"
2548 ], 2758 ],
2549 "time": "2016-11-23T20:04:58+00:00" 2759 "time": "2018-01-29T19:49:41+00:00"
2550 } 2760 }
2551 ], 2761 ],
2552 "aliases": [], 2762 "aliases": [],
@@ -2558,10 +2768,10 @@
2558 "prefer-stable": false, 2768 "prefer-stable": false,
2559 "prefer-lowest": false, 2769 "prefer-lowest": false,
2560 "platform": { 2770 "platform": {
2561 "php": ">=5.5" 2771 "php": ">=5.6"
2562 }, 2772 },
2563 "platform-dev": [], 2773 "platform-dev": [],
2564 "platform-overrides": { 2774 "platform-overrides": {
2565 "php": "5.5.38" 2775 "php": "5.6.31"
2566 } 2776 }
2567} 2777}
diff --git a/doc/md/Backup,-restore,-import-and-export.md b/doc/md/Backup,-restore,-import-and-export.md
index 89724857..bb790074 100644
--- a/doc/md/Backup,-restore,-import-and-export.md
+++ b/doc/md/Backup,-restore,-import-and-export.md
@@ -45,6 +45,10 @@ Shaarli cannot import data directly from [Scuttle](https://github.com/scronide/s
45However, you can use the third-party [scuttle-to-shaarli](https://github.com/q2apro/scuttle-to-shaarli) 45However, you can use the third-party [scuttle-to-shaarli](https://github.com/q2apro/scuttle-to-shaarli)
46tool to export the Scuttle database to the Netscape HTML format compatible with the Shaarli importer. 46tool to export the Scuttle database to the Netscape HTML format compatible with the Shaarli importer.
47 47
48### Refind
49
50You 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.
51
48## Import Shaarli links to Firefox 52## Import Shaarli links to Firefox
49 53
50- Export your Shaarli links as described above. 54- Export your Shaarli links as described above.
diff --git a/doc/md/Bookmarklet.md b/doc/md/Bookmarklet.md
index e53e3261..c899e3cf 100644
--- a/doc/md/Bookmarklet.md
+++ b/doc/md/Bookmarklet.md
@@ -21,7 +21,7 @@ _This bookmarklet button is compatible with Firefox, Opera, Chrome and Safari. U
21 21
22Websites which enforce Content Security Policy (CSP), such as github.com, disallow usage of bookmarklets. Unfortunatly, there is nothing Shaarli can do about it. 22Websites which enforce Content Security Policy (CSP), such as github.com, disallow usage of bookmarklets. Unfortunatly, there is nothing Shaarli can do about it.
23 23
24See [#196](https://github.com/shaarli/Shaarli#196). 24See [#196](https://github.com/shaarli/Shaarli/issues/196).
25 25
26There is an open bug for both Firefox and Chromium: 26There is an open bug for both Firefox and Chromium:
27 27
diff --git a/doc/md/Browsing-and-searching.md b/doc/md/Browsing-and-searching.md
index 35707482..16c69855 100644
--- a/doc/md/Browsing-and-searching.md
+++ b/doc/md/Browsing-and-searching.md
@@ -14,10 +14,24 @@ Use the `Filter by tags` field to restrict displayed links to entries tagged wit
14 14
15**Hidden tags:** Tags starting with a dot `.` (example `.secret`) are private. They can only be seen and searched when logged in. 15**Hidden tags:** Tags starting with a dot `.` (example `.secret`) are private. They can only be seen and searched when logged in.
16 16
17Alternatively you can use the `Tag cloud` to discover all tags and click on any of them to display related links. 17### Tag cloud
18 18
19To search for links that are not tagged, enter `""` in the tag search field. 19The `Tag cloud` page diplays a "cloud" view of all tags in your Shaarli.
20
21 * The most frequently used tags are displayed with a bigger font size.
22 * When sorting by `Most used` or `Alphabetical`, tags are displayed as a _list_, along with counters and edit/delete buttons for each tag.
23 * Clicking on any tag will display a list of all Shaares matching this tag.
24 * 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.
20 25
21## Filtering RSS feeds/Picture wall 26## Filtering RSS feeds/Picture wall
22 27
23RSS feeds can also be restricted to only return items matching a text/tag search: see [RSS feeds](RSS feeds). 28RSS feeds can also be restricted to only return items matching a text/tag search: see [RSS feeds](RSS-feeds).
29
30## Filter buttons
31
32Filter buttons can be found at the top left of the link list. They allow you to apply different filters to the list:
33
34 * **Private links:** When this toggle button is enabled, only shaares set to `private` will be shown.
35 * **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.
36
37Filter buttons are only available when logged in.
diff --git a/doc/md/Community-&-Related-software.md b/doc/md/Community-&-Related-software.md
index 2b7c6599..207153b6 100644
--- a/doc/md/Community-&-Related-software.md
+++ b/doc/md/Community-&-Related-software.md
@@ -1,23 +1,7 @@
1_Unofficial but related work on Shaarli. If you maintain one of these, 1_Unofficial but related work on Shaarli. If you maintain one of these,
2please get in touch with us to help us find a way to adapt your work to our fork._ 2please get in touch with us to help us find a way to adapt your work to our fork._
3 3
4## Community 4## Related software
5- [Liens en vrac de sebsauvage](http://sebsauvage.net/links/) - the original Shaarli
6- [A large list of Shaarlis](http://porneia.free.fr/pub/links/ou-est-shaarli.html)
7- [A list of working Shaarli aggregators](https://raw.githubusercontent.com/Oros42/find_shaarlis/master/annuaires.json)
8- [A list of some known Shaarlis](https://github.com/Oros42/shaarlis_list)
9- [Adieu Delicious, Diigo et StumbleUpon. Salut Shaarli ! - sebsauvage.net](http://sebsauvage.net/rhaa/index.php?2011/09/16/09/29/58-adieu-delicious-diigo-et-stumbleupon-salut-shaarli-) (fr) _16/09/2011 - the original post about Shaarli_
10- [Original ideas/fixme/TODO page](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:ideas)
11- [Original discussion page](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:discussion) (fr)
12- [Original revisions history](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history)
13- [Shaarli.fr/my](https://www.shaarli.fr/my.php) - Unofficial, unsupported (old fork) hosted Shaarlis provider, courtesy of [DMeloni](https://github.com/DMeloni)
14
15
16### Articles and social media discussions
17- 2016-09-22 - Hacker News - https://news.ycombinator.com/item?id=12552176
18- 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/)
19- 2015-06-22 - Hacker News - https://news.ycombinator.com/item?id=9755366
20- 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/)
21 5
22 6
23### REST API clients 7### REST API clients
@@ -29,29 +13,34 @@ See [REST API](REST-API) for a list of official and community clients.
29- [Code Coloration](https://github.com/ArthurHoaro/code-coloration) by [@ArthurHoaro](https://github.com/ArthurHoaro): client side code syntax highlighter. 13- [Code Coloration](https://github.com/ArthurHoaro/code-coloration) by [@ArthurHoaro](https://github.com/ArthurHoaro): client side code syntax highlighter.
30- [Disqus](https://github.com/kalvn/shaarli-plugin-disqus) by [@kalvn](https://github.com/kalvn): Adds Disqus comment system to your Shaarli. 14- [Disqus](https://github.com/kalvn/shaarli-plugin-disqus) by [@kalvn](https://github.com/kalvn): Adds Disqus comment system to your Shaarli.
31- [emojione](https://github.com/NerosTie/emojione) by [@NerosTie](https://github.com/NerosTie): Add colorful emojis to your Shaarli. 15- [emojione](https://github.com/NerosTie/emojione) by [@NerosTie](https://github.com/NerosTie): Add colorful emojis to your Shaarli.
16- [twemoji](https://github.com/NerosTie/twemoji) by [@NerosTie](https://github.com/NerosTie): Add colorful emojis to your Shaarli (Twemoji version)
32- [google analytics](https://github.com/ericjuden/Shaarli-Google-Analytics-Plugin) by [@ericjuden](http://github.com/ericjuden): Adds Google Analytics tracking support 17- [google analytics](https://github.com/ericjuden/Shaarli-Google-Analytics-Plugin) by [@ericjuden](http://github.com/ericjuden): Adds Google Analytics tracking support
33- [launch](https://github.com/ArthurHoaro/launch-plugin) - Launch Plugin is a plugin designed to enhance and customize Launch Theme for Shaarli. 18- [launch](https://github.com/ArthurHoaro/launch-plugin) - Launch Plugin is a plugin designed to enhance and customize Launch Theme for Shaarli.
19- [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.
34- [related](https://github.com/ilesinge/shaarli-related) by [@ilesinge](https://github.com/ilesinge) - Show related links based on the number of identical tags. 20- [related](https://github.com/ilesinge/shaarli-related) by [@ilesinge](https://github.com/ilesinge) - Show related links based on the number of identical tags.
35- [social](https://github.com/alexisju/social) by [@alexisju](https://github.com/alexisju): share links to social networks. 21- [social](https://github.com/alexisju/social) by [@alexisju](https://github.com/alexisju): share links to social networks.
36- [shaarli2twitter](https://github.com/ArthurHoaro/shaarli2twitter) by [@ArthurHoaro](https://github.com/ArthurHoaro) - Automatically tweet your shared links from Shaarli 22- [shaarli2twitter](https://github.com/ArthurHoaro/shaarli2twitter) by [@ArthurHoaro](https://github.com/ArthurHoaro) - Automatically tweet your shared links from Shaarli
37- [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. 23- [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.
24- [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.
38 25
39 26
40### Third-party themes 27### Third-party themes
41See [Theming](Theming) for a list of community-contributed themes, and an installation guide. 28See [Theming](Theming) for a list of community-contributed themes, and an installation guide.
42 29
43 30
44## Integration with other platforms 31### Integration with other platforms
45- [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 32- [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
46- [octopress-shaarli](https://github.com/ahmet2mir/octopress-shaarli) - Octopress plugin to retrieve Shaarli links on the sidebar 33- [octopress-shaarli](https://github.com/ahmet2mir/octopress-shaarli) - Octopress plugin to retrieve Shaarli links on the sidebar
47- [Scuttle to Shaarli](https://github.com/q2apro/scuttle-to-shaarli) - Import bookmarks from Scuttle 34- [Scuttle to Shaarli](https://github.com/q2apro/scuttle-to-shaarli) - Import bookmarks from Scuttle
48 35
49 36
50### Mobile Apps 37### Mobile Apps
51- [ShaarliOS](https://github.com/mro/ShaarliOS) iOS share extension - see [#308](https://github.com/shaarli/Shaarli/issues/308#issuecomment-184592070) for some promo codes, 38- [ShaarliOS](https://github.com/mro/ShaarliOS) - Apple iOS share extension.
52- [Shaarli for Android](http://sebsauvage.net/links/?ZAyDzg) - Android application that adds Shaarli as a sharing provider 39- [Shaarli for Android](http://sebsauvage.net/links/?ZAyDzg) - Android application that adds Shaarli as a sharing provider
53- [Shaarlier for Android](https://github.com/dimtion/Shaarlier) - Android application to simply add links directly into your Shaarli 40- [Shaarlier for Android](https://github.com/dimtion/Shaarlier) - Android application to simply add links directly into your Shaarli
54 41
42### Browser addons
43 * [Shaarli Web Extension](https://github.com/ikipatang/shaarli-web-extension) - toolbar button to share your current tab with Shaarli.
55 44
56### Server apps 45### Server apps
57- [shaarchiver](https://github.com/nodiscc/shaarchiver) - Archive your Shaarli bookmarks and their content 46- [shaarchiver](https://github.com/nodiscc/shaarchiver) - Archive your Shaarli bookmarks and their content
@@ -62,7 +51,22 @@ See [Theming](Theming) for a list of community-contributed themes, and an instal
62- [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). 51- [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).
63- [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. 52- [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.
64 53
65
66## Alternatives to Shaarli 54## Alternatives to Shaarli
67See the [bookmarks & link sharing](https://github.com/Kickball/awesome-selfhosted/#bookmarks--link-sharing) 55See [awesome-selfhosted: bookmarks & link sharing](https://github.com/Kickball/awesome-selfhosted/#bookmarks--link-sharing).
68section on [awesome-selfhosted](https://github.com/Kickball/awesome-selfhosted/). 56
57## Community
58- [Liens en vrac de sebsauvage](http://sebsauvage.net/links/) - the original Shaarli
59- [A large list of Shaarlis](http://porneia.free.fr/pub/links/ou-est-shaarli.html)
60- [A list of working Shaarli aggregators](https://raw.githubusercontent.com/Oros42/find_shaarlis/master/annuaires.json)
61- [A list of some known Shaarlis](https://github.com/Oros42/shaarlis_list)
62- [Adieu Delicious, Diigo et StumbleUpon. Salut Shaarli ! - sebsauvage.net](http://sebsauvage.net/rhaa/index.php?2011/09/16/09/29/58-adieu-delicious-diigo-et-stumbleupon-salut-shaarli-) (fr) _16/09/2011 - the original post about Shaarli_
63- [Original ideas/fixme/TODO page](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:ideas)
64- [Original discussion page](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:discussion) (fr)
65- [Original revisions history](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history)
66- [Shaarli.fr/my](https://www.shaarli.fr/my.php) - Unofficial, unsupported (old fork) hosted Shaarlis provider, courtesy of [DMeloni](https://github.com/DMeloni)
67
68### Articles and social media discussions
69- 2016-09-22 - Hacker News - https://news.ycombinator.com/item?id=12552176
70- 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/)
71- 2015-06-22 - Hacker News - https://news.ycombinator.com/item?id=9755366
72- 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/)
diff --git a/doc/md/Download-and-Installation.md b/doc/md/Download-and-Installation.md
index e64d1a43..0fdbd27d 100644
--- a/doc/md/Download-and-Installation.md
+++ b/doc/md/Download-and-Installation.md
@@ -15,7 +15,7 @@ Using one of the following methods:
15- by downloading full release archives including all dependencies 15- by downloading full release archives including all dependencies
16- by downloading Github archives 16- by downloading Github archives
17- by cloning the Git repository 17- by cloning the Git repository
18- using Docker: [see the documentation](docker/shaarli-images) 18- using Docker: [see the documentation](docker/shaarli-images.md)
19 19
20-------------------------------------------------------------------------------- 20--------------------------------------------------------------------------------
21 21
@@ -25,11 +25,11 @@ Using one of the following methods:
25 25
26In 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. 26In 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.
27 27
28The current latest released version is `v0.9.1` 28The current latest released version is `v0.9.3`
29 29
30```bash 30```bash
31$ wget https://github.com/shaarli/Shaarli/releases/download/v0.9.1/shaarli-v0.9.1-full.zip 31$ wget https://github.com/shaarli/Shaarli/releases/download/v0.9.3/shaarli-v0.9.3-full.zip
32$ unzip shaarli-v0.9.1-full.zip 32$ unzip shaarli-v0.9.3-full.zip
33$ mv Shaarli /path/to/shaarli/ 33$ mv Shaarli /path/to/shaarli/
34``` 34```
35 35
@@ -96,7 +96,7 @@ Install [Composer](Unit-tests.md#install_composer) to manage Shaarli dependencie
96To get the latest changes from the `master` branch: 96To get the latest changes from the `master` branch:
97 97
98```bash 98```bash
99# clone the repository 99# clone the repository
100$ git clone https://github.com/shaarli/Shaarli.git -b master /path/to/shaarli/ 100$ git clone https://github.com/shaarli/Shaarli.git -b master /path/to/shaarli/
101# install/update third-party dependencies 101# install/update third-party dependencies
102$ cd /path/to/shaarli 102$ cd /path/to/shaarli
diff --git a/doc/md/Features.md b/doc/md/Features.md
deleted file mode 100644
index eef88d03..00000000
--- a/doc/md/Features.md
+++ /dev/null
@@ -1,25 +0,0 @@
1### Main features
2Shaarli is intended:
3
4- to share, comment and save interesting links and news
5- to bookmark useful/frequent personal links (as private links) and share them between computers
6- as a minimal blog/microblog/writing platform (no character limit)
7- as a read-it-later list (for example items tagged `readlater`)
8- to draft and save articles/ideas
9- to keep code snippets
10- to keep notes and documentation
11- as a shared clipboard between machines
12- as a todo list
13- to store playlists (e.g. with the `music` or `video` tags)
14- to keep extracts/comments from webpages that may disappear
15- to keep track of ongoing discussions (for example items tagged `discussion`)
16- [to feed RSS aggregators](http://shaarli.chassegnouf.net/?9Efeiw) (planets) with specific tags
17- to feed other social networks, blogs... using RSS feeds and external services (dlvr.it, ifttt.com ...)
18
19### Using Shaarli as a blog, notepad, pastebin...
20
21- Go to your Shaarli setup and log in
22- Click the `Add Link` button
23- To share text only, do not enter any URL in the corresponding input field and click `Add Link`
24- Pick a title and enter your article, or note, in the description field; add a few tags; optionally check `Private` then click `Save`
25- Voilà! Your article is now published (privately if you selected that option) and accessible using its permalink.
diff --git a/doc/md/Firefox-share.md b/doc/md/Firefox-share.md
index 878884a4..9a46b185 100644
--- a/doc/md/Firefox-share.md
+++ b/doc/md/Firefox-share.md
@@ -1,3 +1,6 @@
1| Note | Firefox Share is no longer available for Firefox 57 and later versions. |
2|---------|---------|
3
1### Add Shaarli as a sharing service to Firefox 4### Add Shaarli as a sharing service to Firefox
2 5
3- Open your Shaarli and `Login` 6- Open your Shaarli and `Login`
diff --git a/doc/md/Server-requirements.md b/doc/md/Server-requirements.md
index 400b85a9..2dc442df 100644
--- a/doc/md/Server-requirements.md
+++ b/doc/md/Server-requirements.md
@@ -35,7 +35,7 @@ Library | Required? | Usage
35Extension | Required? | Usage 35Extension | Required? | Usage
36---|:---:|--- 36---|:---:|---
37[`openssl`](http://php.net/manual/en/book.openssl.php) | All | OpenSSL, HTTPS 37[`openssl`](http://php.net/manual/en/book.openssl.php) | All | OpenSSL, HTTPS
38[`php-mbstring`](http://php.net/manual/en/book.mbstring.php) | CentOS, Fedora, RHEL, Windows | multibyte (Unicode) string support 38[`php-mbstring`](http://php.net/manual/en/book.mbstring.php) | CentOS, Fedora, RHEL, Windows, some hosting providers | multibyte (Unicode) string support
39[`php-gd`](http://php.net/manual/en/book.image.php) | optional | thumbnail resizing 39[`php-gd`](http://php.net/manual/en/book.image.php) | optional | thumbnail resizing
40[`php-intl`](http://php.net/manual/en/book.intl.php) | optional | localized text sorting (e.g. `e->è->f`) 40[`php-intl`](http://php.net/manual/en/book.intl.php) | optional | localized text sorting (e.g. `e->è->f`)
41[`php-curl`](http://php.net/manual/en/book.curl.php) | optional | using cURL for fetching webpages and thumbnails in a more robust way 41[`php-curl`](http://php.net/manual/en/book.curl.php) | optional | using cURL for fetching webpages and thumbnails in a more robust way
diff --git a/doc/md/docker/shaarli-images.md b/doc/md/docker/shaarli-images.md
index 1d19510a..12f7b5d1 100644
--- a/doc/md/docker/shaarli-images.md
+++ b/doc/md/docker/shaarli-images.md
@@ -1,3 +1,6 @@
1A brief guide on getting starting using docker is given in [Docker 101](docker-101.md).
2To learn more about user data and how to keep it across versions, please see [Upgrade and Migration](../Upgrade-and-migration.md).
3
1## Get and run a Shaarli image 4## Get and run a Shaarli image
2 5
3### DockerHub repository 6### DockerHub repository
@@ -21,6 +24,7 @@ The `stable` image relies on:
21- [PHP5-FPM](http://php-fpm.org/) 24- [PHP5-FPM](http://php-fpm.org/)
22- [Nginx](http://nginx.org/) 25- [Nginx](http://nginx.org/)
23 26
27Additional [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/).
24 28
25### Download from DockerHub 29### Download from DockerHub
26```bash 30```bash
@@ -78,3 +82,14 @@ backstabbing_galileo
78$ docker ps -a 82$ docker ps -a
79CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 83CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
80``` 84```
85
86### Automatic builds
87
88Docker 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):
89```
90MY_SHAARLI_VOLUME=$(cd /path/to/shaarli/data/ && pwd -P)
91docker run -ti --rm \
92 -p 8000:80 \
93 -v $MY_SHAARLI_VOLUME:/var/www/shaarli/data \
94 shaarli/shaarli
95```
diff --git a/doc/md/index.md b/doc/md/index.md
index 2b7d0f00..e77b4d3a 100644
--- a/doc/md/index.md
+++ b/doc/md/index.md
@@ -22,20 +22,25 @@ It runs the latest development version of Shaarli and is updated/reset daily.
22 22
23Login: `demo`; Password: `demo` 23Login: `demo`; Password: `demo`
24 24
25Docker 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):
26```
27MY_SHAARLI_VOLUME=$(cd /path/to/shaarli/data/ && pwd -P)
28docker run -ti --rm \
29 -p 8000:80 \
30 -v $MY_SHAARLI_VOLUME:/var/www/shaarli/data \
31 shaarli/shaarli
32```
33
34A brief guide on getting starting using docker is given in [Docker 101](docker/docker-101).
35To learn more about user data and how to keep it across versions, please see [Upgrade and Migration](Upgrade-and-migration) documentation.
36
37## Features 25## Features
38 26
27Shaarli can be used:
28
29- to share, comment and save interesting links and news.
30- to bookmark useful/frequent personal links (as private links) and share them between computers.
31- as a minimal blog/microblog/writing platform (no character limit).
32- as a read-it-later list (for example items tagged `readlater`).
33- to draft and save articles/posts/ideas.
34- to keep code snippets.
35- to keep notes and documentation.
36- as a shared clipboard/notepad/pastebin between machines.
37- as a todo list.
38- to store playlists (e.g. with the `music` or `video` tags).
39- to keep extracts/comments from webpages that may disappear.
40- to keep track of ongoing discussions (for example items tagged `discussion`).
41- [to feed RSS aggregators](http://shaarli.chassegnouf.net/?9Efeiw) (planets) with specific tags.
42- to feed other social networks, blogs... using RSS feeds and external services (dlvr.it, ifttt.com ...).
43
39### Interface 44### Interface
40- minimalist design (simple is beautiful) 45- minimalist design (simple is beautiful)
41- FAST 46- FAST
@@ -89,14 +94,12 @@ Easily extensible by any client using the REST API exposed by Shaarli.
89 94
90See the [API documentation](http://shaarli.github.io/api-documentation/). 95See the [API documentation](http://shaarli.github.io/api-documentation/).
91 96
92### Other usages 97### Using Shaarli as a blog, notepad, pastebin...
93Though Shaarli is primarily a bookmarking application, it can serve other purposes 98- Go to your Shaarli setup and log in
94(see [Features](Features)): 99- Click the `Add Link` button
95 100- To share text only, do not enter any URL in the corresponding input field and click `Add Link`
96- micro-blogging 101- Pick a title and enter your article, or note, in the description field; add a few tags; optionally check `Private` then click `Save`
97- pastebin 102- Voilà! Your article is now published (privately if you selected that option) and accessible using its permalink.
98- online notepad
99- snippet archive
100 103
101## About 104## About
102### Shaarli community fork 105### Shaarli community fork
diff --git a/docker/alpine/Dockerfile.armhf.latest b/docker/alpine/Dockerfile.armhf.latest
new file mode 100644
index 00000000..c923834a
--- /dev/null
+++ b/docker/alpine/Dockerfile.armhf.latest
@@ -0,0 +1,47 @@
1FROM lsiobase/alpine.armhf:3.6
2MAINTAINER Shaarli Community
3
4RUN apk --update --no-cache add \
5 ca-certificates \
6 curl \
7 nginx \
8 php7 \
9 php7-ctype \
10 php7-curl \
11 php7-fpm \
12 php7-gd \
13 php7-iconv \
14 php7-intl \
15 php7-json \
16 php7-mbstring \
17 php7-openssl \
18 php7-phar \
19 php7-session \
20 php7-xml \
21 php7-zlib \
22 s6
23
24COPY nginx.conf /etc/nginx/nginx.conf
25COPY php-fpm.conf /etc/php7/php-fpm.conf
26COPY services.d /etc/services.d
27
28RUN curl -sS https://getcomposer.org/installer | php7 -- --install-dir=/usr/local/bin --filename=composer \
29 && rm -rf /etc/php7/php-fpm.d/www.conf \
30 && sed -i 's/post_max_size.*/post_max_size = 10M/' /etc/php7/php.ini \
31 && sed -i 's/upload_max_filesize.*/upload_max_filesize = 10M/' /etc/php7/php.ini
32
33
34WORKDIR /var/www
35RUN curl -L https://github.com/shaarli/Shaarli/archive/latest.tar.gz | tar xzf - \
36 && mv Shaarli-latest shaarli \
37 && cd shaarli \
38 && composer --prefer-dist --no-dev install \
39 && rm -rf ~/.composer \
40 && chown -R nginx:nginx .
41
42VOLUME /var/www/shaarli/data
43
44EXPOSE 80
45
46ENTRYPOINT ["/bin/s6-svscan", "/etc/services.d"]
47CMD []
diff --git a/docker/alpine/Dockerfile.armhf.master b/docker/alpine/Dockerfile.armhf.master
new file mode 100644
index 00000000..7f1bdf85
--- /dev/null
+++ b/docker/alpine/Dockerfile.armhf.master
@@ -0,0 +1,47 @@
1FROM lsiobase/alpine.armhf:3.6
2MAINTAINER Shaarli Community
3
4RUN apk --update --no-cache add \
5 ca-certificates \
6 curl \
7 nginx \
8 php7 \
9 php7-ctype \
10 php7-curl \
11 php7-fpm \
12 php7-gd \
13 php7-iconv \
14 php7-intl \
15 php7-json \
16 php7-mbstring \
17 php7-openssl \
18 php7-phar \
19 php7-session \
20 php7-xml \
21 php7-zlib \
22 s6
23
24COPY nginx.conf /etc/nginx/nginx.conf
25COPY php-fpm.conf /etc/php7/php-fpm.conf
26COPY services.d /etc/services.d
27
28RUN curl -sS https://getcomposer.org/installer | php7 -- --install-dir=/usr/local/bin --filename=composer \
29 && rm -rf /etc/php7/php-fpm.d/www.conf \
30 && sed -i 's/post_max_size.*/post_max_size = 10M/' /etc/php7/php.ini \
31 && sed -i 's/upload_max_filesize.*/upload_max_filesize = 10M/' /etc/php7/php.ini
32
33
34WORKDIR /var/www
35RUN curl -L https://github.com/shaarli/Shaarli/archive/master.tar.gz | tar xzf - \
36 && mv Shaarli-master shaarli \
37 && cd shaarli \
38 && composer --prefer-dist --no-dev install \
39 && rm -rf ~/.composer \
40 && chown -R nginx:nginx .
41
42VOLUME /var/www/shaarli/data
43
44EXPOSE 80
45
46ENTRYPOINT ["/bin/s6-svscan", "/etc/services.d"]
47CMD []
diff --git a/index.php b/index.php
index 8770b669..c2aaf84a 100644
--- a/index.php
+++ b/index.php
@@ -124,6 +124,11 @@ if (isset($_COOKIE['shaarli']) && !SessionManager::checkId($_COOKIE['shaarli']))
124$conf = new ConfigManager(); 124$conf = new ConfigManager();
125$sessionManager = new SessionManager($_SESSION, $conf); 125$sessionManager = new SessionManager($_SESSION, $conf);
126 126
127// LC_MESSAGES isn't defined without php-intl, in this case use LC_COLLATE locale instead.
128if (! defined('LC_MESSAGES')) {
129 define('LC_MESSAGES', LC_COLLATE);
130}
131
127// Sniff browser language and set date format accordingly. 132// Sniff browser language and set date format accordingly.
128if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { 133if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
129 autoLocale($_SERVER['HTTP_ACCEPT_LANGUAGE']); 134 autoLocale($_SERVER['HTTP_ACCEPT_LANGUAGE']);
@@ -436,7 +441,7 @@ if (isset($_POST['login']))
436 else 441 else
437 { 442 {
438 ban_loginFailed($conf); 443 ban_loginFailed($conf);
439 $redir = '&username='. $_POST['login']; 444 $redir = '&username='. urlencode($_POST['login']);
440 if (isset($_GET['post'])) { 445 if (isset($_GET['post'])) {
441 $redir .= '&post=' . urlencode($_GET['post']); 446 $redir .= '&post=' . urlencode($_GET['post']);
442 foreach (array('description', 'source', 'title', 'tags') as $param) { 447 foreach (array('description', 'source', 'title', 'tags') as $param) {
@@ -1436,16 +1441,10 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager)
1436 // 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.) 1441 // 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.)
1437 if (empty($title) && strpos(get_url_scheme($url), 'http') !== false) { 1442 if (empty($title) && strpos(get_url_scheme($url), 'http') !== false) {
1438 // Short timeout to keep the application responsive 1443 // Short timeout to keep the application responsive
1439 list($headers, $content) = get_http_response($url, 4); 1444 // The callback will fill $charset and $title with data from the downloaded page.
1440 if (strpos($headers[0], '200 OK') !== false) { 1445 get_http_response($url, 25, 4194304, get_curl_download_callback($charset, $title));
1441 // Retrieve charset. 1446 if (! empty($title) && strtolower($charset) != 'utf-8') {
1442 $charset = get_charset($headers, $content); 1447 $title = mb_convert_encoding($title, 'utf-8', $charset);
1443 // Extract title.
1444 $title = html_extract_title($content);
1445 // Re-encode title in utf-8 if necessary.
1446 if (! empty($title) && strtolower($charset) != 'utf-8') {
1447 $title = mb_convert_encoding($title, 'utf-8', $charset);
1448 }
1449 } 1448 }
1450 } 1449 }
1451 1450
diff --git a/mkdocs.yml b/mkdocs.yml
index 8617ea45..443c3a08 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -22,16 +22,15 @@ pages:
22 - Reverse proxy configuration: docker/reverse-proxy-configuration.md 22 - Reverse proxy configuration: docker/reverse-proxy-configuration.md
23 - Docker resources: docker/resources.md 23 - Docker resources: docker/resources.md
24- Usage: 24- Usage:
25 - Features: Features.md
26 - Bookmarklet: Bookmarklet.md 25 - Bookmarklet: Bookmarklet.md
27 - Browsing and searching: Browsing-and-searching.md 26 - Browsing and searching: Browsing-and-searching.md
28 - Firefox share: Firefox-share.md 27 - Firefox share: Firefox-share.md
29 - RSS feeds: RSS-feeds.md 28 - RSS feeds: RSS-feeds.md
30 - REST API: REST-API.md 29 - REST API: REST-API.md
30 - Community & Related software: Community-&-Related-software.md
31- How To: 31- How To:
32 - Backup, restore, import and export: Backup,-restore,-import-and-export.md 32 - Backup, restore, import and export: Backup,-restore,-import-and-export.md
33 - Various hacks: Various-hacks.md 33 - Various hacks: Various-hacks.md
34- Troubleshooting: Troubleshooting.md
35- Development: 34- Development:
36 - Development guidelines: Development-guidelines.md 35 - Development guidelines: Development-guidelines.md
37 - Continuous integration tools: Continuous-integration-tools.md 36 - Continuous integration tools: Continuous-integration-tools.md
@@ -47,6 +46,5 @@ pages:
47 - Theming: Theming.md 46 - Theming: Theming.md
48 - Unit tests: Unit-tests.md 47 - Unit tests: Unit-tests.md
49 - Unit tests inside Docker: Unit-tests-Docker.md 48 - Unit tests inside Docker: Unit-tests-Docker.md
50- About: 49- FAQ: FAQ.md
51 - FAQ: FAQ.md 50- Troubleshooting: Troubleshooting.md
52 - Community & Related software: Community-&-Related-software.md
diff --git a/tests/HttpUtils/ServerUrlTest.php b/tests/HttpUtils/ServerUrlTest.php
index dac02b3e..324b827a 100644
--- a/tests/HttpUtils/ServerUrlTest.php
+++ b/tests/HttpUtils/ServerUrlTest.php
@@ -186,4 +186,36 @@ class ServerUrlTest extends PHPUnit_Framework_TestCase
186 ) 186 )
187 ); 187 );
188 } 188 }
189
190 /**
191 * Misconfigured server (see #1022): Proxy HTTP but 443
192 */
193 public function testHttpWithPort433()
194 {
195 $this->assertEquals(
196 'https://host.tld',
197 server_url(
198 array(
199 'HTTPS' => 'Off',
200 'SERVER_NAME' => 'host.tld',
201 'SERVER_PORT' => '80',
202 'HTTP_X_FORWARDED_PROTO' => 'http',
203 'HTTP_X_FORWARDED_PORT' => '443'
204 )
205 )
206 );
207
208 $this->assertEquals(
209 'https://host.tld',
210 server_url(
211 array(
212 'HTTPS' => 'Off',
213 'SERVER_NAME' => 'host.tld',
214 'SERVER_PORT' => '80',
215 'HTTP_X_FORWARDED_PROTO' => 'https, http',
216 'HTTP_X_FORWARDED_PORT' => '443, 80'
217 )
218 )
219 );
220 }
189} 221}
diff --git a/tests/LinkUtilsTest.php b/tests/LinkUtilsTest.php
index 99679320..7fbd59b0 100644
--- a/tests/LinkUtilsTest.php
+++ b/tests/LinkUtilsTest.php
@@ -29,27 +29,13 @@ class LinkUtilsTest extends PHPUnit_Framework_TestCase
29 } 29 }
30 30
31 /** 31 /**
32 * Test get_charset() with all priorities.
33 */
34 public function testGetCharset()
35 {
36 $headers = array('Content-Type' => 'text/html; charset=Headers');
37 $html = '<html><meta>stuff</meta><meta charset="Html"/></html>';
38 $default = 'default';
39 $this->assertEquals('headers', get_charset($headers, $html, $default));
40 $this->assertEquals('html', get_charset(array(), $html, $default));
41 $this->assertEquals($default, get_charset(array(), '', $default));
42 $this->assertEquals('utf-8', get_charset(array(), ''));
43 }
44
45 /**
46 * Test headers_extract_charset() when the charset is found. 32 * Test headers_extract_charset() when the charset is found.
47 */ 33 */
48 public function testHeadersExtractExistentCharset() 34 public function testHeadersExtractExistentCharset()
49 { 35 {
50 $charset = 'x-MacCroatian'; 36 $charset = 'x-MacCroatian';
51 $headers = array('Content-Type' => 'text/html; charset='. $charset); 37 $headers = 'text/html; charset='. $charset;
52 $this->assertEquals(strtolower($charset), headers_extract_charset($headers)); 38 $this->assertEquals(strtolower($charset), header_extract_charset($headers));
53 } 39 }
54 40
55 /** 41 /**
@@ -57,11 +43,11 @@ class LinkUtilsTest extends PHPUnit_Framework_TestCase
57 */ 43 */
58 public function testHeadersExtractNonExistentCharset() 44 public function testHeadersExtractNonExistentCharset()
59 { 45 {
60 $headers = array(); 46 $headers = '';
61 $this->assertFalse(headers_extract_charset($headers)); 47 $this->assertFalse(header_extract_charset($headers));
62 48
63 $headers = array('Content-Type' => 'text/html'); 49 $headers = 'text/html';
64 $this->assertFalse(headers_extract_charset($headers)); 50 $this->assertFalse(header_extract_charset($headers));
65 } 51 }
66 52
67 /** 53 /**
@@ -86,6 +72,131 @@ class LinkUtilsTest extends PHPUnit_Framework_TestCase
86 } 72 }
87 73
88 /** 74 /**
75 * Test the download callback with valid value
76 */
77 public function testCurlDownloadCallbackOk()
78 {
79 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ok');
80 $data = [
81 'HTTP/1.1 200 OK',
82 'Server: GitHub.com',
83 'Date: Sat, 28 Oct 2017 12:01:33 GMT',
84 'Content-Type: text/html; charset=utf-8',
85 'Status: 200 OK',
86 'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea',
87 '<title>ignored</title>',
88 ];
89 foreach ($data as $key => $line) {
90 $ignore = null;
91 $expected = $key !== 'end' ? strlen($line) : false;
92 $this->assertEquals($expected, $callback($ignore, $line));
93 if ($expected === false) {
94 break;
95 }
96 }
97 $this->assertEquals('utf-8', $charset);
98 $this->assertEquals('Refactoring · GitHub', $title);
99 }
100
101 /**
102 * Test the download callback with valid values and no charset
103 */
104 public function testCurlDownloadCallbackOkNoCharset()
105 {
106 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_no_charset');
107 $data = [
108 'HTTP/1.1 200 OK',
109 'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea',
110 '<title>ignored</title>',
111 ];
112 foreach ($data as $key => $line) {
113 $ignore = null;
114 $this->assertEquals(strlen($line), $callback($ignore, $line));
115 }
116 $this->assertEmpty($charset);
117 $this->assertEquals('Refactoring · GitHub', $title);
118 }
119
120 /**
121 * Test the download callback with valid values and no charset
122 */
123 public function testCurlDownloadCallbackOkHtmlCharset()
124 {
125 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_no_charset');
126 $data = [
127 'HTTP/1.1 200 OK',
128 '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',
129 'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea',
130 '<title>ignored</title>',
131 ];
132 foreach ($data as $key => $line) {
133 $ignore = null;
134 $expected = $key !== 'end' ? strlen($line) : false;
135 $this->assertEquals($expected, $callback($ignore, $line));
136 if ($expected === false) {
137 break;
138 }
139 }
140 $this->assertEquals('utf-8', $charset);
141 $this->assertEquals('Refactoring · GitHub', $title);
142 }
143
144 /**
145 * Test the download callback with valid values and no title
146 */
147 public function testCurlDownloadCallbackOkNoTitle()
148 {
149 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ok');
150 $data = [
151 'HTTP/1.1 200 OK',
152 'end' => 'th=device-width">Refactoring · GitHub<link rel="search" type="application/opensea',
153 'ignored',
154 ];
155 foreach ($data as $key => $line) {
156 $ignore = null;
157 $this->assertEquals(strlen($line), $callback($ignore, $line));
158 }
159 $this->assertEquals('utf-8', $charset);
160 $this->assertEmpty($title);
161 }
162
163 /**
164 * Test the download callback with an invalid content type.
165 */
166 public function testCurlDownloadCallbackInvalidContentType()
167 {
168 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ct_ko');
169 $ignore = null;
170 $this->assertFalse($callback($ignore, ''));
171 $this->assertEmpty($charset);
172 $this->assertEmpty($title);
173 }
174
175 /**
176 * Test the download callback with an invalid response code.
177 */
178 public function testCurlDownloadCallbackInvalidResponseCode()
179 {
180 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_rc_ko');
181 $ignore = null;
182 $this->assertFalse($callback($ignore, ''));
183 $this->assertEmpty($charset);
184 $this->assertEmpty($title);
185 }
186
187 /**
188 * Test the download callback with an invalid content type and response code.
189 */
190 public function testCurlDownloadCallbackInvalidContentTypeAndResponseCode()
191 {
192 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_rs_ct_ko');
193 $ignore = null;
194 $this->assertFalse($callback($ignore, ''));
195 $this->assertEmpty($charset);
196 $this->assertEmpty($title);
197 }
198
199 /**
89 * Test count_private. 200 * Test count_private.
90 */ 201 */
91 public function testCountPrivateLinks() 202 public function testCountPrivateLinks()
@@ -207,3 +318,96 @@ class LinkUtilsTest extends PHPUnit_Framework_TestCase
207 return str_replace('$1', $hashtag, $hashtagLink); 318 return str_replace('$1', $hashtag, $hashtagLink);
208 } 319 }
209} 320}
321
322// old style mock: PHPUnit doesn't allow function mock
323
324/**
325 * Returns code 200 or html content type.
326 *
327 * @param resource $ch cURL resource
328 * @param int $type cURL info type
329 *
330 * @return int|string 200 or 'text/html'
331 */
332function ut_curl_getinfo_ok($ch, $type)
333{
334 switch ($type) {
335 case CURLINFO_RESPONSE_CODE:
336 return 200;
337 case CURLINFO_CONTENT_TYPE:
338 return 'text/html; charset=utf-8';
339 }
340}
341
342/**
343 * Returns code 200 or html content type without charset.
344 *
345 * @param resource $ch cURL resource
346 * @param int $type cURL info type
347 *
348 * @return int|string 200 or 'text/html'
349 */
350function ut_curl_getinfo_no_charset($ch, $type)
351{
352 switch ($type) {
353 case CURLINFO_RESPONSE_CODE:
354 return 200;
355 case CURLINFO_CONTENT_TYPE:
356 return 'text/html';
357 }
358}
359
360/**
361 * Invalid response code.
362 *
363 * @param resource $ch cURL resource
364 * @param int $type cURL info type
365 *
366 * @return int|string 404 or 'text/html'
367 */
368function ut_curl_getinfo_rc_ko($ch, $type)
369{
370 switch ($type) {
371 case CURLINFO_RESPONSE_CODE:
372 return 404;
373 case CURLINFO_CONTENT_TYPE:
374 return 'text/html; charset=utf-8';
375 }
376}
377
378/**
379 * Invalid content type.
380 *
381 * @param resource $ch cURL resource
382 * @param int $type cURL info type
383 *
384 * @return int|string 200 or 'text/plain'
385 */
386function ut_curl_getinfo_ct_ko($ch, $type)
387{
388 switch ($type) {
389 case CURLINFO_RESPONSE_CODE:
390 return 200;
391 case CURLINFO_CONTENT_TYPE:
392 return 'text/plain';
393 }
394}
395
396/**
397 * Invalid response code and content type.
398 *
399 * @param resource $ch cURL resource
400 * @param int $type cURL info type
401 *
402 * @return int|string 404 or 'text/plain'
403 */
404function ut_curl_getinfo_rs_ct_ko($ch, $type)
405{
406 switch ($type) {
407 case CURLINFO_RESPONSE_CODE:
408 return 404;
409 case CURLINFO_CONTENT_TYPE:
410 return 'text/plain';
411 }
412}
413
diff --git a/tests/api/controllers/PostLinkTest.php b/tests/api/controllers/PostLinkTest.php
index 31954e39..100a9170 100644
--- a/tests/api/controllers/PostLinkTest.php
+++ b/tests/api/controllers/PostLinkTest.php
@@ -3,11 +3,13 @@
3namespace Shaarli\Api\Controllers; 3namespace Shaarli\Api\Controllers;
4 4
5 5
6use PHPUnit\Framework\TestCase;
6use Shaarli\Config\ConfigManager; 7use Shaarli\Config\ConfigManager;
7use Slim\Container; 8use Slim\Container;
8use Slim\Http\Environment; 9use Slim\Http\Environment;
9use Slim\Http\Request; 10use Slim\Http\Request;
10use Slim\Http\Response; 11use Slim\Http\Response;
12use Slim\Router;
11 13
12/** 14/**
13 * Class PostLinkTest 15 * Class PostLinkTest
@@ -16,7 +18,7 @@ use Slim\Http\Response;
16 * 18 *
17 * @package Shaarli\Api\Controllers 19 * @package Shaarli\Api\Controllers
18 */ 20 */
19class PostLinkTest extends \PHPUnit_Framework_TestCase 21class PostLinkTest extends TestCase
20{ 22{
21 /** 23 /**
22 * @var string datastore to test write operations 24 * @var string datastore to test write operations
@@ -78,7 +80,7 @@ class PostLinkTest extends \PHPUnit_Framework_TestCase
78 80
79 $this->controller = new Links($this->container); 81 $this->controller = new Links($this->container);
80 82
81 $mock = $this->getMock('\Slim\Router', ['relativePathFor']); 83 $mock = $this->createMock(Router::class);
82 $mock->expects($this->any()) 84 $mock->expects($this->any())
83 ->method('relativePathFor') 85 ->method('relativePathFor')
84 ->willReturn('api/v1/links/1'); 86 ->willReturn('api/v1/links/1');
diff --git a/tests/config/ConfigPhpTest.php b/tests/config/ConfigPhpTest.php
index abfbb305..be23eea1 100644
--- a/tests/config/ConfigPhpTest.php
+++ b/tests/config/ConfigPhpTest.php
@@ -37,6 +37,20 @@ class ConfigPhpTest extends \PHPUnit_Framework_TestCase
37 } 37 }
38 38
39 /** 39 /**
40 * Read an empty existent config file -> array with blank default values.
41 */
42 public function testReadEmpty()
43 {
44 $dataFile = 'tests/utils/config/emptyConfigPhp.php';
45 $conf = $this->configIO->read($dataFile);
46 $this->assertEmpty($conf['login']);
47 $this->assertEmpty($conf['title']);
48 $this->assertEmpty($conf['titleLink']);
49 $this->assertEmpty($conf['config']);
50 $this->assertEmpty($conf['plugins']);
51 }
52
53 /**
40 * Write a new config file. 54 * Write a new config file.
41 */ 55 */
42 public function testWriteNew() 56 public function testWriteNew()
diff --git a/tests/utils/config/emptyConfigPhp.php b/tests/utils/config/emptyConfigPhp.php
new file mode 100644
index 00000000..b3d9bbc7
--- /dev/null
+++ b/tests/utils/config/emptyConfigPhp.php
@@ -0,0 +1 @@
<?php
diff --git a/tpl/default/page.header.html b/tpl/default/page.header.html
index 2411703c..6f15c1c5 100644
--- a/tpl/default/page.header.html
+++ b/tpl/default/page.header.html
@@ -1,7 +1,7 @@
1<div class="shaarli-menu pure-g" id="shaarli-menu"> 1<div class="shaarli-menu pure-g" id="shaarli-menu">
2 <div class="pure-u-lg-0 pure-u-1"> 2 <div class="pure-u-lg-0 pure-u-1">
3 <div class="pure-menu"> 3 <div class="pure-menu">
4 <a href="{$titleLink}" class="pure-menu-link"> 4 <a href="{$titleLink}" class="pure-menu-link shaarli-title" id="shaarli-title-mobile">
5 <img src="img/icon.png" width="16" height="16" class="head-logo" alt="logo" /> 5 <img src="img/icon.png" width="16" height="16" class="head-logo" alt="logo" />
6 {$shaarlititle} 6 {$shaarlititle}
7 </a> 7 </a>
@@ -12,32 +12,32 @@
12 <div class="pure-menu menu-transform pure-menu-horizontal pure-g"> 12 <div class="pure-menu menu-transform pure-menu-horizontal pure-g">
13 <ul class="pure-menu-list pure-u-lg-5-6 pure-u-1"> 13 <ul class="pure-menu-list pure-u-lg-5-6 pure-u-1">
14 <li class="pure-menu-item pure-u-0 pure-u-lg-visible"> 14 <li class="pure-menu-item pure-u-0 pure-u-lg-visible">
15 <a href="{$titleLink}" class="pure-menu-link"> 15 <a href="{$titleLink}" class="pure-menu-link shaarli-title" id="shaarli-title-desktop">
16 <img src="img/icon.png" width="16" height="16" class="head-logo" alt="logo" /> 16 <img src="img/icon.png" width="16" height="16" class="head-logo" alt="logo" />
17 {$shaarlititle} 17 {$shaarlititle}
18 </a> 18 </a>
19 </li> 19 </li>
20 {if="isLoggedIn() || $openshaarli"} 20 {if="isLoggedIn() || $openshaarli"}
21 <li class="pure-menu-item"> 21 <li class="pure-menu-item">
22 <a href="?do=addlink" class="pure-menu-link"> 22 <a href="?do=addlink" class="pure-menu-link" id="shaarli-menu-shaare">
23 <i class="fa fa-plus" ></i> {'Shaare'|t} 23 <i class="fa fa-plus" ></i> {'Shaare'|t}
24 </a> 24 </a>
25 </li> 25 </li>
26 <li class="pure-menu-item"> 26 <li class="pure-menu-item" id="shaarli-menu-tools">
27 <a href="?do=tools" class="pure-menu-link">{'Tools'|t}</a> 27 <a href="?do=tools" class="pure-menu-link">{'Tools'|t}</a>
28 </li> 28 </li>
29 {/if} 29 {/if}
30 <li class="pure-menu-item"> 30 <li class="pure-menu-item" id="shaarli-menu-tags">
31 <a href="?do=tagcloud" class="pure-menu-link">{'Tag cloud'|t}</a> 31 <a href="?do=tagcloud" class="pure-menu-link">{'Tag cloud'|t}</a>
32 </li> 32 </li>
33 <li class="pure-menu-item"> 33 <li class="pure-menu-item" id="shaarli-menu-picwall">
34 <a href="?do=picwall{$searchcrits}" class="pure-menu-link">{'Picture wall'|t}</a> 34 <a href="?do=picwall{$searchcrits}" class="pure-menu-link">{'Picture wall'|t}</a>
35 </li> 35 </li>
36 <li class="pure-menu-item"> 36 <li class="pure-menu-item" id="shaarli-menu-daily">
37 <a href="?do=daily" class="pure-menu-link">{'Daily'|t}</a> 37 <a href="?do=daily" class="pure-menu-link">{'Daily'|t}</a>
38 </li> 38 </li>
39 {loop="$plugins_header.buttons_toolbar"} 39 {loop="$plugins_header.buttons_toolbar"}
40 <li class="pure-menu-item"> 40 <li class="pure-menu-item shaarli-menu-plugin">
41 <a 41 <a
42 {$value.attr.class=isset($value.class) ? $value.attr.class . ' pure-menu-link' : 'pure-menu-link'} 42 {$value.attr.class=isset($value.class) ? $value.attr.class . ' pure-menu-link' : 'pure-menu-link'}
43 {loop="$value.attr"} 43 {loop="$value.attr"}
@@ -47,47 +47,47 @@
47 </a> 47 </a>
48 </li> 48 </li>
49 {/loop} 49 {/loop}
50 <li class="pure-menu-item pure-u-lg-0"> 50 <li class="pure-menu-item pure-u-lg-0 shaarli-menu-mobile" id="shaarli-menu-mobile-rss">
51 <a href="?do={$feed_type}{$searchcrits}" class="pure-menu-link">{'RSS Feed'|t}</a> 51 <a href="?do={$feed_type}{$searchcrits}" class="pure-menu-link">{'RSS Feed'|t}</a>
52 </li> 52 </li>
53 {if="isLoggedIn()"} 53 {if="isLoggedIn()"}
54 <li class="pure-menu-item pure-u-lg-0"> 54 <li class="pure-menu-item pure-u-lg-0 shaarli-menu-mobile" id="shaarli-menu-mobile-logout">
55 <a href="?do=logout" class="pure-menu-link">{'Logout'|t}</a> 55 <a href="?do=logout" class="pure-menu-link">{'Logout'|t}</a>
56 </li> 56 </li>
57 {else} 57 {else}
58 <li class="pure-menu-item pure-u-lg-0"> 58 <li class="pure-menu-item pure-u-lg-0 shaarli-menu-mobile" id="shaarli-menu-mobile-login">
59 <a href="?do=login" class="pure-menu-link">{'Login'|t}</a> 59 <a href="?do=login" class="pure-menu-link">{'Login'|t}</a>
60 </li> 60 </li>
61 {/if} 61 {/if}
62 </ul> 62 </ul>
63 <div class="header-buttons pure-u-lg-1-6 pure-u-0 pure-u-lg-visible"> 63 <div class="header-buttons pure-u-lg-1-6 pure-u-0 pure-u-lg-visible">
64 <ul class="pure-menu-list"> 64 <ul class="pure-menu-list">
65 <li class="pure-menu-item"> 65 <li class="pure-menu-item" id="shaarli-menu-desktop-search">
66 <a href="#" class="pure-menu-link subheader-opener" 66 <a href="#" class="pure-menu-link subheader-opener"
67 data-open-id="search" 67 data-open-id="search"
68 id="search-button" title="{'Search'|t}"> 68 id="search-button" title="{'Search'|t}">
69 <i class="fa fa-search"></i> 69 <i class="fa fa-search"></i>
70 </a> 70 </a>
71 </li> 71 </li>
72 <li class="pure-menu-item"> 72 <li class="pure-menu-item" id="shaarli-menu-desktop-rss">
73 <a href="?do={$feed_type}{$searchcrits}" class="pure-menu-link" title="{'RSS Feed'|t}"> 73 <a href="?do={$feed_type}{$searchcrits}" class="pure-menu-link" title="{'RSS Feed'|t}">
74 <i class="fa fa-rss"></i> 74 <i class="fa fa-rss"></i>
75 </a> 75 </a>
76 </li> 76 </li>
77 {if="!isLoggedIn()"} 77 {if="!isLoggedIn()"}
78 <li class="pure-menu-item"> 78 <li class="pure-menu-item" id="shaarli-menu-desktop-login">
79 <a href="?do=login" class="pure-menu-link" 79 <a href="?do=login" class="pure-menu-link"
80 data-open-id="header-login-form" 80 data-open-id="header-login-form"
81 id="login-button" title="{'Login'|t}"> 81 id="login-button" title="{'Login'|t}">
82 <i class="fa fa-user"></i> 82 <i class="fa fa-user"></i>
83 </a> 83 </a>
84 </li> 84 </li>
85 {else} 85 {else}
86 <li class="pure-menu-item"> 86 <li class="pure-menu-item" id="shaarli-menu-desktop-logout">
87 <a href="?do=logout" class="pure-menu-link" title="{'Logout'|t}"> 87 <a href="?do=logout" class="pure-menu-link" title="{'Logout'|t}">
88 <i class="fa fa-sign-out"></i> 88 <i class="fa fa-sign-out"></i>
89 </a> 89 </a>
90 </li> 90 </li>
91 {/if} 91 {/if}
92 </ul> 92 </ul>
93 </div> 93 </div>
@@ -156,7 +156,7 @@
156{/if} 156{/if}
157 157
158{if="!empty($plugin_errors) && isLoggedIn()"} 158{if="!empty($plugin_errors) && isLoggedIn()"}
159 <div class="pure-g new-version-message pure-alert pure-alert-error pure-alert-closable"> 159 <div class="pure-g new-version-message pure-alert pure-alert-error pure-alert-closable" id="shaarli-errors-alert">
160 <div class="pure-u-2-24"></div> 160 <div class="pure-u-2-24"></div>
161 <div class="pure-u-20-24"> 161 <div class="pure-u-20-24">
162 {loop="plugin_errors"} 162 {loop="plugin_errors"}
diff --git a/tpl/default/pluginsadmin.html b/tpl/default/pluginsadmin.html
index ca17b435..b2d7cdc5 100644
--- a/tpl/default/pluginsadmin.html
+++ b/tpl/default/pluginsadmin.html
@@ -137,9 +137,9 @@
137 {if="count($enabledPlugins)==0"} 137 {if="count($enabledPlugins)==0"}
138 <p class="center">{'No plugin enabled.'|t}</p> 138 <p class="center">{'No plugin enabled.'|t}</p>
139 {else} 139 {else}
140 {$counter=0} 140 {$nbParameters=0}
141 {loop="$enabledPlugins"} 141 {loop="$enabledPlugins"}
142 {$counter=$counter+count($value.parameters)} 142 {$nbParameters=$nbParameters+count($value.parameters)}
143 {if="count($value.parameters) > 0"} 143 {if="count($value.parameters) > 0"}
144 <div class="plugin_parameters"> 144 <div class="plugin_parameters">
145 <h3 class="window-subtitle">{function="str_replace('_', ' ', $key)"}</h3> 145 <h3 class="window-subtitle">{function="str_replace('_', ' ', $key)"}</h3>
@@ -161,7 +161,7 @@
161 </div> 161 </div>
162 {/if} 162 {/if}
163 {/loop} 163 {/loop}
164 {if="$counter===0"} 164 {if="$nbParameters===0"}
165 <p class="center">{'No parameter available.'|t}</p> 165 <p class="center">{'No parameter available.'|t}</p>
166 {else} 166 {else}
167 <div class="center"> 167 <div class="center">