Merge pull request #1234 from virtualtam/lint

Setup PHPCS and cleanup linter configuration
This commit is contained in:
Aurélien Tamisier 2018-12-02 22:47:41 +01:00 committed by GitHub
commit 1004742f09
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
63 changed files with 432 additions and 724 deletions

View file

@ -2,8 +2,6 @@
# Makefile for PHP code analysis & testing, documentation and release generation # Makefile for PHP code analysis & testing, documentation and release generation
BIN = vendor/bin BIN = vendor/bin
PHP_SOURCE = index.php application tests plugins
PHP_COMMA_SOURCE = index.php,application,tests,plugins
all: static_analysis_summary check_permissions test all: static_analysis_summary check_permissions test
@ -17,14 +15,6 @@ docker_%:
rsync -az /shaarli/ ~/shaarli/ rsync -az /shaarli/ ~/shaarli/
cd ~/shaarli && make $* cd ~/shaarli && make $*
##
# Concise status of the project
# These targets are non-blocking: || exit 0
##
static_analysis_summary: code_sniffer_source copy_paste mess_detector_summary
@echo
## ##
# PHP_CodeSniffer # PHP_CodeSniffer
# Detects PHP syntax errors # Detects PHP syntax errors
@ -32,70 +22,26 @@ static_analysis_summary: code_sniffer_source copy_paste mess_detector_summary
# - http://pear.php.net/manual/en/package.php.php-codesniffer.usage.php # - http://pear.php.net/manual/en/package.php.php-codesniffer.usage.php
# - http://pear.php.net/manual/en/package.php.php-codesniffer.reporting.php # - http://pear.php.net/manual/en/package.php.php-codesniffer.reporting.php
## ##
PHPCS := $(BIN)/phpcs
code_sniffer: code_sniffer_full code_sniffer:
@$(PHPCS)
### - errors filtered by coding standard: PEAR, PSR1, PSR2, Zend... ### - errors filtered by coding standard: PEAR, PSR1, PSR2, Zend...
PHPCS_%: PHPCS_%:
@$(BIN)/phpcs $(PHP_SOURCE) --report-full --report-width=200 --standard=$* @$(PHPCS) --report-full --report-width=200 --standard=$*
### - errors by Git author ### - errors by Git author
code_sniffer_blame: code_sniffer_blame:
@$(BIN)/phpcs $(PHP_SOURCE) --report-gitblame @$(PHPCS) --report-gitblame
### - all errors/warnings ### - all errors/warnings
code_sniffer_full: code_sniffer_full:
@$(BIN)/phpcs $(PHP_SOURCE) --report-full --report-width=200 @$(PHPCS) --report-full --report-width=200
### - errors grouped by kind ### - errors grouped by kind
code_sniffer_source: code_sniffer_source:
@$(BIN)/phpcs $(PHP_SOURCE) --report-source || exit 0 @$(PHPCS) --report-source || exit 0
##
# PHP Copy/Paste Detector
# Detects code redundancy
# Documentation: https://github.com/sebastianbergmann/phpcpd
##
copy_paste:
@echo "-----------------------"
@echo "PHP COPY/PASTE DETECTOR"
@echo "-----------------------"
@$(BIN)/phpcpd $(PHP_SOURCE) || exit 0
@echo
##
# PHP Mess Detector
# Detects PHP syntax errors, sorted by category
# Rules documentation: http://phpmd.org/rules/index.html
##
MESS_DETECTOR_RULES = cleancode,codesize,controversial,design,naming,unusedcode
mess_title:
@echo "-----------------"
@echo "PHP MESS DETECTOR"
@echo "-----------------"
### - all warnings
mess_detector: mess_title
@$(BIN)/phpmd $(PHP_COMMA_SOURCE) text $(MESS_DETECTOR_RULES) | sed 's_.*\/__'
### - all warnings + HTML output contains links to PHPMD's documentation
mess_detector_html:
@$(BIN)/phpmd $(PHP_COMMA_SOURCE) html $(MESS_DETECTOR_RULES) \
--reportfile phpmd.html || exit 0
### - warnings grouped by message, sorted by descending frequency order
mess_detector_grouped: mess_title
@$(BIN)/phpmd $(PHP_SOURCE) text $(MESS_DETECTOR_RULES) \
| cut -f 2 | sort | uniq -c | sort -nr
### - summary: number of warnings by rule set
mess_detector_summary: mess_title
@for rule in $$(echo $(MESS_DETECTOR_RULES) | tr ',' ' '); do \
warnings=$$($(BIN)/phpmd $(PHP_COMMA_SOURCE) text $$rule | wc -l); \
printf "$$warnings\t$$rule\n"; \
done;
## ##
# Checks source file & script permissions # Checks source file & script permissions

View file

@ -86,13 +86,14 @@ public static function getVersion($remote, $timeout = 2)
* *
* @return mixed the new version code if available and greater, else 'false' * @return mixed the new version code if available and greater, else 'false'
*/ */
public static function checkUpdate($currentVersion, public static function checkUpdate(
$currentVersion,
$updateFile, $updateFile,
$checkInterval, $checkInterval,
$enableCheck, $enableCheck,
$isLoggedIn, $isLoggedIn,
$branch='stable') $branch = 'stable'
{ ) {
// Do not check versions for visitors // Do not check versions for visitors
// Do not check if the user doesn't want to // Do not check if the user doesn't want to
// Do not check with dev version // Do not check with dev version

View file

@ -2,7 +2,6 @@
namespace Shaarli; namespace Shaarli;
/** /**
* URL-safe Base64 operations * URL-safe Base64 operations
* *
@ -17,7 +16,8 @@ class Base64Url
* *
* @return string Base64Url-encoded data * @return string Base64Url-encoded data
*/ */
public static function encode($data) { public static function encode($data)
{
return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
} }
@ -28,7 +28,8 @@ public static function encode($data) {
* *
* @return string Decoded data * @return string Decoded data
*/ */
public static function decode($data) { public static function decode($data)
{
return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT)); return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
} }
} }

View file

@ -163,7 +163,8 @@ protected function buildItem($link, $pageaddr)
$upDate = $link['updated']; $upDate = $link['updated'];
$link['up_iso_date'] = $this->getIsoDate($upDate, DateTime::ATOM); $link['up_iso_date'] = $this->getIsoDate($upDate, DateTime::ATOM);
} else { } else {
$link['up_iso_date'] = $this->getIsoDate($pubDate, DateTime::ATOM);; $link['up_iso_date'] = $this->getIsoDate($pubDate, DateTime::ATOM);
;
} }
// Save the more recent item. // Save the more recent item.
@ -261,7 +262,6 @@ protected function getIsoDate(DateTime $date, $format = false)
} }
if ($this->feedType == self::$FEED_RSS) { if ($this->feedType == self::$FEED_RSS) {
return $date->format(DateTime::RSS); return $date->format(DateTime::RSS);
} }
return $date->format(DateTime::ATOM); return $date->format(DateTime::ATOM);
} }

View file

@ -7,7 +7,8 @@
* @param int $timeout network timeout (in seconds) * @param int $timeout network timeout (in seconds)
* @param int $maxBytes maximum downloaded bytes (default: 4 MiB) * @param int $maxBytes maximum downloaded bytes (default: 4 MiB)
* @param callable|string $curlWriteFunction Optional callback called during the download (cURL CURLOPT_WRITEFUNCTION). * @param callable|string $curlWriteFunction Optional callback called during the download (cURL CURLOPT_WRITEFUNCTION).
* Can be used to add download conditions on the headers (response code, content type, etc.). * Can be used to add download conditions on the
* headers (response code, content type, etc.).
* *
* @return array HTTP response headers, downloaded content * @return array HTTP response headers, downloaded content
* *
@ -84,9 +85,10 @@ function get_http_response($url, $timeout = 30, $maxBytes = 4194304, $curlWriteF
// Max download size management // Max download size management
curl_setopt($ch, CURLOPT_BUFFERSIZE, 1024*16); curl_setopt($ch, CURLOPT_BUFFERSIZE, 1024*16);
curl_setopt($ch, CURLOPT_NOPROGRESS, false); curl_setopt($ch, CURLOPT_NOPROGRESS, false);
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, curl_setopt(
function($arg0, $arg1, $arg2, $arg3, $arg4 = 0) use ($maxBytes) $ch,
{ CURLOPT_PROGRESSFUNCTION,
function ($arg0, $arg1, $arg2, $arg3, $arg4 = 0) use ($maxBytes) {
if (version_compare(phpversion(), '5.5', '<')) { if (version_compare(phpversion(), '5.5', '<')) {
// PHP version lower than 5.5 // PHP version lower than 5.5
// Callback has 4 arguments // Callback has 4 arguments
@ -232,7 +234,6 @@ function get_redirected_headers($url, $redirectionLimit = 3)
&& !empty($headers) && !empty($headers)
&& (strpos($headers[0], '301') !== false || strpos($headers[0], '302') !== false) && (strpos($headers[0], '301') !== false || strpos($headers[0], '302') !== false)
&& !empty($headers['Location'])) { && !empty($headers['Location'])) {
$redirection = is_array($headers['Location']) ? end($headers['Location']) : $headers['Location']; $redirection = is_array($headers['Location']) ? end($headers['Location']) : $headers['Location'];
if ($redirection != $url) { if ($redirection != $url) {
$redirection = getAbsoluteUrl($url, $redirection); $redirection = getAbsoluteUrl($url, $redirection);

View file

@ -125,7 +125,8 @@ protected function initPhpTranslator()
$translations = $translations->addFromPoFile('inc/languages/'. $this->language .'/LC_MESSAGES/shaarli.po'); $translations = $translations->addFromPoFile('inc/languages/'. $this->language .'/LC_MESSAGES/shaarli.po');
$translations->setDomain('shaarli'); $translations->setDomain('shaarli');
$this->translator->loadTranslations($translations); $this->translator->loadTranslations($translations);
} catch (\InvalidArgumentException $e) {} } catch (\InvalidArgumentException $e) {
}
// Default extension translation from the current theme // Default extension translation from the current theme
$theme = $this->conf->get('theme'); $theme = $this->conf->get('theme');
@ -137,7 +138,8 @@ protected function initPhpTranslator()
); );
$translations->setDomain($theme); $translations->setDomain($theme);
$this->translator->loadTranslations($translations); $this->translator->loadTranslations($translations);
} catch (\InvalidArgumentException $e) {} } catch (\InvalidArgumentException $e) {
}
} }
// Extension translations (plugins, themes, etc.). // Extension translations (plugins, themes, etc.).
@ -147,10 +149,13 @@ protected function initPhpTranslator()
} }
try { try {
$extension = Translations::fromPoFile($translationPath . $this->language .'/LC_MESSAGES/'. $domain .'.po'); $extension = Translations::fromPoFile(
$translationPath . $this->language .'/LC_MESSAGES/'. $domain .'.po'
);
$extension->setDomain($domain); $extension->setDomain($domain);
$this->translator->loadTranslations($extension); $this->translator->loadTranslations($extension);
} catch (\InvalidArgumentException $e) {} } catch (\InvalidArgumentException $e) {
}
} }
} }

View file

@ -107,8 +107,7 @@ public function __construct(
$hidePublicLinks, $hidePublicLinks,
$redirector = '', $redirector = '',
$redirectorEncode = true $redirectorEncode = true
) ) {
{
$this->datastore = $datastore; $this->datastore = $datastore;
$this->loggedIn = $isLoggedIn; $this->loggedIn = $isLoggedIn;
$this->hidePublicLinks = $hidePublicLinks; $this->hidePublicLinks = $hidePublicLinks;
@ -250,11 +249,14 @@ private function check()
'id' => 1, 'id' => 1,
'title'=> t('The personal, minimalist, super-fast, database free, bookmarking service'), 'title'=> t('The personal, minimalist, super-fast, database free, bookmarking service'),
'url'=>'https://shaarli.readthedocs.io', 'url'=>'https://shaarli.readthedocs.io',
'description'=>t('Welcome to Shaarli! This is your first public bookmark. To edit or delete me, you must first login. 'description'=>t(
'Welcome to Shaarli! This is your first public bookmark. '
.'To edit or delete me, you must first login.
To learn how to use Shaarli, consult the link "Documentation" at the bottom of this page. To learn how to use Shaarli, consult the link "Documentation" at the bottom of this page.
You use the community supported version of the original Shaarli project, by Sebastien Sauvage.'), You use the community supported version of the original Shaarli project, by Sebastien Sauvage.'
),
'private'=>0, 'private'=>0,
'created'=> new DateTime(), 'created'=> new DateTime(),
'tags'=>'opensource software' 'tags'=>'opensource software'
@ -317,8 +319,7 @@ private function read()
} else { } else {
$link['real_url'] .= $link['url']; $link['real_url'] .= $link['url'];
} }
} } else {
else {
$link['real_url'] = $link['url']; $link['real_url'] = $link['url'];
} }
@ -403,7 +404,8 @@ public function filterHash($request)
* *
* @return array list of shaare found. * @return array list of shaare found.
*/ */
public function filterDay($request) { public function filterDay($request)
{
$linkFilter = new LinkFilter($this->links); $linkFilter = new LinkFilter($this->links);
return $linkFilter->filter(LinkFilter::$FILTER_DAY, $request); return $linkFilter->filter(LinkFilter::$FILTER_DAY, $request);
} }
@ -420,8 +422,12 @@ public function filterDay($request) {
* *
* @return array filtered links, all links if no suitable filter was provided. * @return array filtered links, all links if no suitable filter was provided.
*/ */
public function filterSearch($filterRequest = array(), $casesensitive = false, $visibility = 'all', $untaggedonly = false) public function filterSearch(
{ $filterRequest = array(),
$casesensitive = false,
$visibility = 'all',
$untaggedonly = false
) {
// Filter link database according to parameters. // Filter link database according to parameters.
$searchtags = isset($filterRequest['searchtags']) ? escape($filterRequest['searchtags']) : ''; $searchtags = isset($filterRequest['searchtags']) ? escape($filterRequest['searchtags']) : '';
$searchterm = isset($filterRequest['searchterm']) ? escape($filterRequest['searchterm']) : ''; $searchterm = isset($filterRequest['searchterm']) ? escape($filterRequest['searchterm']) : '';
@ -492,8 +498,7 @@ public function renameTag($from, $to)
$delete = empty($to); $delete = empty($to);
// True for case-sensitive tag search. // True for case-sensitive tag search.
$linksToAlter = $this->filterSearch(['searchtags' => $from], true); $linksToAlter = $this->filterSearch(['searchtags' => $from], true);
foreach($linksToAlter as $key => &$value) foreach ($linksToAlter as $key => &$value) {
{
$tags = preg_split('/\s+/', trim($value['tags'])); $tags = preg_split('/\s+/', trim($value['tags']));
if (($pos = array_search($from, $tags)) !== false) { if (($pos = array_search($from, $tags)) !== false) {
if ($delete) { if ($delete) {

View file

@ -205,7 +205,6 @@ private function filterFulltext($searchterms, $visibility = 'all')
// Iterate over every stored link. // Iterate over every stored link.
foreach ($this->links as $id => $link) { foreach ($this->links as $id => $link) {
// ignore non private links when 'privatonly' is on. // ignore non private links when 'privatonly' is on.
if ($visibility !== 'all') { if ($visibility !== 'all') {
if (! $link['private'] && $visibility === 'private') { if (! $link['private'] && $visibility === 'private') {

View file

@ -201,7 +201,8 @@ function space2nbsp($text)
* @return string formatted description. * @return string formatted description.
*/ */
function format_description($description, $redirector = '', $urlEncode = true, $indexUrl = '') { function format_description($description, $redirector = '', $urlEncode = true, $indexUrl = '')
{
return nl2br(space2nbsp(hashtag_autolink(text2clickable($description, $redirector, $urlEncode), $indexUrl))); return nl2br(space2nbsp(hashtag_autolink(text2clickable($description, $redirector, $urlEncode), $indexUrl)));
} }

View file

@ -76,14 +76,16 @@ private static function importStatus(
$overwriteCount = 0, $overwriteCount = 0,
$skipCount = 0, $skipCount = 0,
$duration = 0 $duration = 0
) ) {
{
$status = sprintf(t('File %s (%d bytes) '), $filename, $filesize); $status = sprintf(t('File %s (%d bytes) '), $filename, $filesize);
if ($importCount == 0 && $overwriteCount == 0 && $skipCount == 0) { if ($importCount == 0 && $overwriteCount == 0 && $skipCount == 0) {
$status .= t('has an unknown file format. Nothing was imported.'); $status .= t('has an unknown file format. Nothing was imported.');
} else { } else {
$status .= vsprintf( $status .= vsprintf(
t('was successfully processed in %d seconds: %d links imported, %d links overwritten, %d links skipped.'), t(
'was successfully processed in %d seconds: '
.'%d links imported, %d links overwritten, %d links skipped.'
),
[$duration, $importCount, $overwriteCount, $skipCount] [$duration, $importCount, $overwriteCount, $skipCount]
); );
} }

View file

@ -78,7 +78,6 @@ private function initialize()
); );
$this->tpl->assign('newVersion', escape($version)); $this->tpl->assign('newVersion', escape($version));
$this->tpl->assign('versionError', ''); $this->tpl->assign('versionError', '');
} catch (Exception $exc) { } catch (Exception $exc) {
logm($this->conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], $exc->getMessage()); logm($this->conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], $exc->getMessage());
$this->tpl->assign('newVersion', ''); $this->tpl->assign('newVersion', '');

View file

@ -75,8 +75,7 @@ public function load($authorizedPlugins)
try { try {
$this->loadPlugin($dirs[$index], $plugin); $this->loadPlugin($dirs[$index], $plugin);
} } catch (PluginFileNotFoundException $e) {
catch (PluginFileNotFoundException $e) {
error_log($e->getMessage()); error_log($e->getMessage());
} }
} }

View file

@ -58,7 +58,10 @@ public function __construct($conf)
$this->conf->set('thumbnails.enabled', false); $this->conf->set('thumbnails.enabled', false);
$this->conf->write(true); $this->conf->write(true);
// TODO: create a proper error handling system able to catch exceptions... // TODO: create a proper error handling system able to catch exceptions...
die(t('php-gd extension must be loaded to use thumbnails. Thumbnails are now disabled. Please reload the page.')); die(t(
'php-gd extension must be loaded to use thumbnails. '
.'Thumbnails are now disabled. Please reload the page.'
));
} }
$this->wt = new WebThumbnailer(); $this->wt = new WebThumbnailer();

View file

@ -269,7 +269,8 @@ public function idnToAscii()
* *
* @return string the URL scheme or false if none is provided. * @return string the URL scheme or false if none is provided.
*/ */
public function getScheme() { public function getScheme()
{
if (!isset($this->parts['scheme'])) { if (!isset($this->parts['scheme'])) {
return false; return false;
} }
@ -281,7 +282,8 @@ public function getScheme() {
* *
* @return string the URL host or false if none is provided. * @return string the URL host or false if none is provided.
*/ */
public function getHost() { public function getHost()
{
if (empty($this->parts['host'])) { if (empty($this->parts['host'])) {
return false; return false;
} }
@ -293,7 +295,8 @@ public function getHost() {
* *
* @return true is HTTP, false otherwise. * @return true is HTTP, false otherwise.
*/ */
public function isHttp() { public function isHttp()
{
return strpos(strtolower($this->parts['scheme']), 'http') !== false; return strpos(strtolower($this->parts['scheme']), 'http') !== false;
} }
} }

View file

@ -356,9 +356,12 @@ function return_bytes($val)
$last = strtolower($val[strlen($val)-1]); $last = strtolower($val[strlen($val)-1]);
$val = intval(substr($val, 0, -1)); $val = intval(substr($val, 0, -1));
switch ($last) { switch ($last) {
case 'g': $val *= 1024; case 'g':
case 'm': $val *= 1024; $val *= 1024;
case 'k': $val *= 1024; case 'm':
$val *= 1024;
case 'k':
$val *= 1024;
} }
return $val; return $val;
} }
@ -452,6 +455,7 @@ function alphabetical_sort(&$data, $reverse = false, $byKeys = false)
* *
* @return string Text translated. * @return string Text translated.
*/ */
function t($text, $nText = '', $nb = 1, $domain = 'shaarli') { function t($text, $nText = '', $nb = 1, $domain = 'shaarli')
{
return dn__($domain, $text, $nText, $nb); return dn__($domain, $text, $nText, $nb);
} }

View file

@ -98,7 +98,8 @@ protected function checkRequest($request)
* *
* @throws ApiAuthorizationException The token couldn't be validated. * @throws ApiAuthorizationException The token couldn't be validated.
*/ */
protected function checkToken($request) { protected function checkToken($request)
{
if (! $request->hasHeader('Authorization')) { if (! $request->hasHeader('Authorization')) {
throw new ApiAuthorizationException('JWT token not provided'); throw new ApiAuthorizationException('JWT token not provided');
} }

View file

@ -35,8 +35,7 @@ public function getHistory($request, $response)
$offset = $request->getParam('offset'); $offset = $request->getParam('offset');
if (empty($offset)) { if (empty($offset)) {
$offset = 0; $offset = 0;
} } elseif (ctype_digit($offset)) {
elseif (ctype_digit($offset)) {
$offset = (int) $offset; $offset = (int) $offset;
} else { } else {
throw new ApiBadParametersException('Invalid offset'); throw new ApiBadParametersException('Invalid offset');

View file

@ -10,7 +10,8 @@
* Parent Exception related to the API, able to generate a valid Response (ResponseInterface). * Parent Exception related to the API, able to generate a valid Response (ResponseInterface).
* Also can include various information in debug mode. * Also can include various information in debug mode.
*/ */
abstract class ApiException extends \Exception { abstract class ApiException extends \Exception
{
/** /**
* @var Response instance from Slim. * @var Response instance from Slim.
@ -27,7 +28,7 @@ abstract class ApiException extends \Exception {
* *
* @return Response Final response to give. * @return Response Final response to give.
*/ */
public abstract function getApiResponse(); abstract public function getApiResponse();
/** /**
* Creates ApiResponse body. * Creates ApiResponse body.
@ -36,7 +37,8 @@ public abstract function getApiResponse();
* *
* @return array|string response body * @return array|string response body
*/ */
protected function getApiResponseBody() { protected function getApiResponseBody()
{
if ($this->debug !== true) { if ($this->debug !== true) {
return $this->getMessage(); return $this->getMessage();
} }

View file

@ -2,7 +2,6 @@
namespace Shaarli\Api\Exceptions; namespace Shaarli\Api\Exceptions;
use Slim\Http\Response; use Slim\Http\Response;
/** /**

View file

@ -2,7 +2,6 @@
namespace Shaarli\Api\Exceptions; namespace Shaarli\Api\Exceptions;
use Slim\Http\Response; use Slim\Http\Response;
/** /**

View file

@ -104,12 +104,20 @@ public function write($filepath, $conf)
// Store all $conf['config'] // Store all $conf['config']
foreach ($conf['config'] as $key => $value) { foreach ($conf['config'] as $key => $value) {
$configStr .= '$GLOBALS[\'config\'][\''. $key .'\'] = '.var_export($conf['config'][$key], true).';'. PHP_EOL; $configStr .= '$GLOBALS[\'config\'][\''
. $key
.'\'] = '
.var_export($conf['config'][$key], true).';'
. PHP_EOL;
} }
if (isset($conf['plugins'])) { if (isset($conf['plugins'])) {
foreach ($conf['plugins'] as $key => $value) { foreach ($conf['plugins'] as $key => $value) {
$configStr .= '$GLOBALS[\'plugins\'][\''. $key .'\'] = '.var_export($conf['plugins'][$key], true).';'. PHP_EOL; $configStr .= '$GLOBALS[\'plugins\'][\''
. $key
.'\'] = '
.var_export($conf['plugins'][$key], true).';'
. PHP_EOL;
} }
} }

View file

@ -34,8 +34,7 @@ function save_plugin_config($formData)
// If there is no order, it means a disabled plugin has been enabled. // If there is no order, it means a disabled plugin has been enabled.
if (isset($formData['order_' . $key])) { if (isset($formData['order_' . $key])) {
$plugins[(int) $formData['order_' . $key]] = $key; $plugins[(int) $formData['order_' . $key]] = $key;
} } else {
else {
$newEnabledPlugins[] = $key; $newEnabledPlugins[] = $key;
} }
} }

View file

@ -95,7 +95,6 @@ public function checkLoginState($cookie, $clientIpId)
// The user client has a valid stay-signed-in cookie // The user client has a valid stay-signed-in cookie
// Session information is updated with the current client information // Session information is updated with the current client information
$this->sessionManager->storeLoginInfo($clientIpId); $this->sessionManager->storeLoginInfo($clientIpId);
} elseif ($this->sessionManager->hasSessionExpired() } elseif ($this->sessionManager->hasSessionExpired()
|| $this->sessionManager->hasClientIpChanged($clientIpId) || $this->sessionManager->hasClientIpChanged($clientIpId)
) { ) {

View file

@ -24,11 +24,9 @@
"gettext/gettext": "^4.4" "gettext/gettext": "^4.4"
}, },
"require-dev": { "require-dev": {
"phpmd/phpmd" : "@stable", "phpunit/phpcov": "*",
"phpunit/phpunit": "^5.0", "phpunit/phpunit": "^5.0",
"sebastian/phpcpd": "*", "squizlabs/php_codesniffer": "2.*"
"squizlabs/php_codesniffer": "2.*",
"phpunit/phpcov": "*"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {

357
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "0dc33ee0b7d9f47868d4fa961f0d13b4", "content-hash": "3876b34296fedb365517b785af8384de",
"packages": [ "packages": [
{ {
"name": "arthurhoaro/web-thumbnailer", "name": "arthurhoaro/web-thumbnailer",
@ -593,12 +593,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/pubsubhubbub/php-publisher.git", "url": "https://github.com/pubsubhubbub/php-publisher.git",
"reference": "e8a7cf52a2c86b0c364da56f7192ec020c83b8f7" "reference": "047b0faf6219071527a45942d6fef4dbc6d1d884"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/pubsubhubbub/php-publisher/zipball/e8a7cf52a2c86b0c364da56f7192ec020c83b8f7", "url": "https://api.github.com/repos/pubsubhubbub/php-publisher/zipball/047b0faf6219071527a45942d6fef4dbc6d1d884",
"reference": "e8a7cf52a2c86b0c364da56f7192ec020c83b8f7", "reference": "047b0faf6219071527a45942d6fef4dbc6d1d884",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -627,9 +627,10 @@
"data", "data",
"feeds", "feeds",
"publishers", "publishers",
"pubsubhubbub" "pubsubhubbub",
"websub"
], ],
"time": "2018-10-05T12:31:04+00:00" "time": "2018-10-09T05:20:28+00:00"
}, },
{ {
"name": "shaarli/netscape-bookmark-parser", "name": "shaarli/netscape-bookmark-parser",
@ -858,46 +859,6 @@
], ],
"time": "2017-10-19T19:58:43+00:00" "time": "2017-10-19T19:58:43+00:00"
}, },
{
"name": "pdepend/pdepend",
"version": "2.5.2",
"source": {
"type": "git",
"url": "https://github.com/pdepend/pdepend.git",
"reference": "9daf26d0368d4a12bed1cacae1a9f3a6f0adf239"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pdepend/pdepend/zipball/9daf26d0368d4a12bed1cacae1a9f3a6f0adf239",
"reference": "9daf26d0368d4a12bed1cacae1a9f3a6f0adf239",
"shasum": ""
},
"require": {
"php": ">=5.3.7",
"symfony/config": "^2.3.0|^3|^4",
"symfony/dependency-injection": "^2.3.0|^3|^4",
"symfony/filesystem": "^2.3.0|^3|^4"
},
"require-dev": {
"phpunit/phpunit": "^4.8|^5.7",
"squizlabs/php_codesniffer": "^2.0.0"
},
"bin": [
"src/bin/pdepend"
],
"type": "library",
"autoload": {
"psr-4": {
"PDepend\\": "src/main/php/PDepend"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Official version of pdepend to be handled with Composer",
"time": "2017-12-13T13:21:38+00:00"
},
{ {
"name": "phpdocumentor/reflection-common", "name": "phpdocumentor/reflection-common",
"version": "1.0.1", "version": "1.0.1",
@ -1044,72 +1005,6 @@
], ],
"time": "2017-07-14T14:27:02+00:00" "time": "2017-07-14T14:27:02+00:00"
}, },
{
"name": "phpmd/phpmd",
"version": "2.6.0",
"source": {
"type": "git",
"url": "https://github.com/phpmd/phpmd.git",
"reference": "4e9924b2c157a3eb64395460fcf56b31badc8374"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpmd/phpmd/zipball/4e9924b2c157a3eb64395460fcf56b31badc8374",
"reference": "4e9924b2c157a3eb64395460fcf56b31badc8374",
"shasum": ""
},
"require": {
"ext-xml": "*",
"pdepend/pdepend": "^2.5",
"php": ">=5.3.9"
},
"require-dev": {
"phpunit/phpunit": "^4.0",
"squizlabs/php_codesniffer": "^2.0"
},
"bin": [
"src/bin/phpmd"
],
"type": "project",
"autoload": {
"psr-0": {
"PHPMD\\": "src/main/php"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Manuel Pichler",
"email": "github@manuel-pichler.de",
"homepage": "https://github.com/manuelpichler",
"role": "Project Founder"
},
{
"name": "Other contributors",
"homepage": "https://github.com/phpmd/phpmd/graphs/contributors",
"role": "Contributors"
},
{
"name": "Marc Würth",
"email": "ravage@bluewin.ch",
"homepage": "https://github.com/ravage84",
"role": "Project Maintainer"
}
],
"description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.",
"homepage": "http://phpmd.org/",
"keywords": [
"mess detection",
"mess detector",
"pdepend",
"phpmd",
"pmd"
],
"time": "2017-01-20T14:41:10+00:00"
},
{ {
"name": "phpspec/prophecy", "name": "phpspec/prophecy",
"version": "1.8.0", "version": "1.8.0",
@ -1988,56 +1883,6 @@
"homepage": "https://github.com/sebastianbergmann/object-enumerator/", "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
"time": "2017-02-18T15:18:39+00:00" "time": "2017-02-18T15:18:39+00:00"
}, },
{
"name": "sebastian/phpcpd",
"version": "3.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpcpd.git",
"reference": "dfed51c1288790fc957c9433e2f49ab152e8a564"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpcpd/zipball/dfed51c1288790fc957c9433e2f49ab152e8a564",
"reference": "dfed51c1288790fc957c9433e2f49ab152e8a564",
"shasum": ""
},
"require": {
"php": "^5.6|^7.0",
"phpunit/php-timer": "^1.0.6",
"sebastian/finder-facade": "^1.1",
"sebastian/version": "^1.0|^2.0",
"symfony/console": "^2.7|^3.0|^4.0"
},
"bin": [
"phpcpd"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Copy/Paste Detector (CPD) for PHP code.",
"homepage": "https://github.com/sebastianbergmann/phpcpd",
"time": "2017-11-16T08:49:28+00:00"
},
{ {
"name": "sebastian/recursion-context", "name": "sebastian/recursion-context",
"version": "2.0.0", "version": "2.0.0",
@ -2254,70 +2099,6 @@
], ],
"time": "2017-05-22T02:43:20+00:00" "time": "2017-05-22T02:43:20+00:00"
}, },
{
"name": "symfony/config",
"version": "v3.4.17",
"source": {
"type": "git",
"url": "https://github.com/symfony/config.git",
"reference": "e5389132dc6320682de3643091121c048ff796b3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/config/zipball/e5389132dc6320682de3643091121c048ff796b3",
"reference": "e5389132dc6320682de3643091121c048ff796b3",
"shasum": ""
},
"require": {
"php": "^5.5.9|>=7.0.8",
"symfony/filesystem": "~2.8|~3.0|~4.0",
"symfony/polyfill-ctype": "~1.8"
},
"conflict": {
"symfony/dependency-injection": "<3.3",
"symfony/finder": "<3.3"
},
"require-dev": {
"symfony/dependency-injection": "~3.3|~4.0",
"symfony/event-dispatcher": "~3.3|~4.0",
"symfony/finder": "~3.3|~4.0",
"symfony/yaml": "~3.0|~4.0"
},
"suggest": {
"symfony/yaml": "To use the yaml reference dumper"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Config\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com",
"time": "2018-09-08T13:15:14+00:00"
},
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v3.4.17", "version": "v3.4.17",
@ -2443,127 +2224,6 @@
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2018-10-02T16:33:53+00:00" "time": "2018-10-02T16:33:53+00:00"
}, },
{
"name": "symfony/dependency-injection",
"version": "v3.4.17",
"source": {
"type": "git",
"url": "https://github.com/symfony/dependency-injection.git",
"reference": "aea20fef4e92396928b5db175788b90234c0270d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/aea20fef4e92396928b5db175788b90234c0270d",
"reference": "aea20fef4e92396928b5db175788b90234c0270d",
"shasum": ""
},
"require": {
"php": "^5.5.9|>=7.0.8",
"psr/container": "^1.0"
},
"conflict": {
"symfony/config": "<3.3.7",
"symfony/finder": "<3.3",
"symfony/proxy-manager-bridge": "<3.4",
"symfony/yaml": "<3.4"
},
"provide": {
"psr/container-implementation": "1.0"
},
"require-dev": {
"symfony/config": "~3.3|~4.0",
"symfony/expression-language": "~2.8|~3.0|~4.0",
"symfony/yaml": "~3.4|~4.0"
},
"suggest": {
"symfony/config": "",
"symfony/expression-language": "For using expressions in service container configuration",
"symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required",
"symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
"symfony/yaml": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\DependencyInjection\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony DependencyInjection Component",
"homepage": "https://symfony.com",
"time": "2018-10-02T12:28:39+00:00"
},
{
"name": "symfony/filesystem",
"version": "v3.4.17",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "d69930fc337d767607267d57c20a7403d0a822a4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/d69930fc337d767607267d57c20a7403d0a822a4",
"reference": "d69930fc337d767607267d57c20a7403d0a822a4",
"shasum": ""
},
"require": {
"php": "^5.5.9|>=7.0.8",
"symfony/polyfill-ctype": "~1.8"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Filesystem\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
"time": "2018-10-02T12:28:39+00:00"
},
{ {
"name": "symfony/finder", "name": "symfony/finder",
"version": "v3.4.17", "version": "v3.4.17",
@ -2883,8 +2543,7 @@
"aliases": [], "aliases": [],
"minimum-stability": "stable", "minimum-stability": "stable",
"stability-flags": { "stability-flags": {
"pubsubhubbub/publisher": 20, "pubsubhubbub/publisher": 20
"phpmd/phpmd": 0
}, },
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,

226
index.php
View file

@ -223,7 +223,6 @@ function isLoggedIn()
$expirationTime, $expirationTime,
WEB_PATH WEB_PATH
); );
} else { } else {
// Standard session expiration (=when browser closes) // Standard session expiration (=when browser closes)
$expirationTime = 0; $expirationTime = 0;
@ -257,7 +256,8 @@ function isLoggedIn()
exit; exit;
} }
} }
header('Location: ?'); exit; header('Location: ?');
exit;
} else { } else {
$loginManager->handleFailedLogin($_SERVER); $loginManager->handleFailedLogin($_SERVER);
$redir = '&username='. urlencode($_POST['login']); $redir = '&username='. urlencode($_POST['login']);
@ -278,7 +278,9 @@ function isLoggedIn()
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
// Token management for XSRF protection // Token management for XSRF protection
// Token should be used in any form which acts on data (create,update,delete,import...). // Token should be used in any form which acts on data (create,update,delete,import...).
if (!isset($_SESSION['tokens'])) $_SESSION['tokens']=array(); // Token are attached to the session. if (!isset($_SESSION['tokens'])) {
$_SESSION['tokens']=array(); // Token are attached to the session.
}
/** /**
* Daily RSS feed: 1 RSS entry per day giving all the links on that day. * Daily RSS feed: 1 RSS entry per day giving all the links on that day.
@ -288,7 +290,8 @@ function isLoggedIn()
* @param ConfigManager $conf Configuration Manager instance * @param ConfigManager $conf Configuration Manager instance
* @param LoginManager $loginManager LoginManager instance * @param LoginManager $loginManager LoginManager instance
*/ */
function showDailyRSS($conf, $loginManager) { function showDailyRSS($conf, $loginManager)
{
// Cache system // Cache system
$query = $_SERVER['QUERY_STRING']; $query = $_SERVER['QUERY_STRING'];
$cache = new CachedPage( $cache = new CachedPage(
@ -492,7 +495,8 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager, $loginManager)
* @param ConfigManager $conf Configuration Manager instance. * @param ConfigManager $conf Configuration Manager instance.
* @param PluginManager $pluginManager Plugin Manager instance. * @param PluginManager $pluginManager Plugin Manager instance.
*/ */
function showLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager) { function showLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager)
{
buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager); buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager);
$PAGE->renderPage('linklist'); $PAGE->renderPage('linklist');
} }
@ -524,8 +528,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
$updater->getDoneUpdates() $updater->getDoneUpdates()
); );
} }
} } catch (Exception $e) {
catch(Exception $e) {
die($e->getMessage()); die($e->getMessage());
} }
@ -538,8 +541,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
$query = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : ''; $query = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : '';
$targetPage = Router::findPage($query, $_GET, $loginManager->isLoggedIn()); $targetPage = Router::findPage($query, $_GET, $loginManager->isLoggedIn());
if ( if (// if the user isn't logged in
// if the user isn't logged in
!$loginManager->isLoggedIn() && !$loginManager->isLoggedIn() &&
// and Shaarli doesn't have public content... // and Shaarli doesn't have public content...
$conf->get('privacy.hide_public_links') && $conf->get('privacy.hide_public_links') &&
@ -565,7 +567,9 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
foreach ($common_hooks as $name) { foreach ($common_hooks as $name) {
$plugin_data = array(); $plugin_data = array();
$pluginManager->executeHooks('render_' . $name, $plugin_data, $pluginManager->executeHooks(
'render_' . $name,
$plugin_data,
array( array(
'target' => $targetPage, 'target' => $targetPage,
'loggedin' => $loginManager->isLoggedIn() 'loggedin' => $loginManager->isLoggedIn()
@ -575,9 +579,11 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
} }
// -------- Display login form. // -------- Display login form.
if ($targetPage == Router::$PAGE_LOGIN) if ($targetPage == Router::$PAGE_LOGIN) {
{ if ($conf->get('security.open_shaarli')) {
if ($conf->get('security.open_shaarli')) { header('Location: ?'); exit; } // No need to login for open Shaarli header('Location: ?');
exit;
} // No need to login for open Shaarli
if (isset($_GET['username'])) { if (isset($_GET['username'])) {
$PAGE->assign('username', escape($_GET['username'])); $PAGE->assign('username', escape($_GET['username']));
} }
@ -590,8 +596,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
exit; exit;
} }
// -------- User wants to logout. // -------- User wants to logout.
if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=logout')) if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=logout')) {
{
invalidateCaches($conf->get('resource.page_cache')); invalidateCaches($conf->get('resource.page_cache'));
$sessionManager->logout(); $sessionManager->logout();
setcookie(LoginManager::$STAY_SIGNED_IN_COOKIE, 'false', 0, WEB_PATH); setcookie(LoginManager::$STAY_SIGNED_IN_COOKIE, 'false', 0, WEB_PATH);
@ -600,8 +605,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
} }
// -------- Picture wall // -------- Picture wall
if ($targetPage == Router::$PAGE_PICWALL) if ($targetPage == Router::$PAGE_PICWALL) {
{
$PAGE->assign('pagetitle', t('Picture wall') .' - '. $conf->get('general.title', 'Shaarli')); $PAGE->assign('pagetitle', t('Picture wall') .' - '. $conf->get('general.title', 'Shaarli'));
if (! $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) === Thumbnailer::MODE_NONE) { if (! $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) === Thumbnailer::MODE_NONE) {
$PAGE->assign('linksToDisplay', []); $PAGE->assign('linksToDisplay', []);
@ -615,8 +619,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
// Get only links which have a thumbnail. // Get only links which have a thumbnail.
// Note: we do not retrieve thumbnails here, the request is too heavy. // Note: we do not retrieve thumbnails here, the request is too heavy.
foreach($links as $key => $link) foreach ($links as $key => $link) {
{
if (isset($link['thumbnail']) && $link['thumbnail'] !== false) { if (isset($link['thumbnail']) && $link['thumbnail'] !== false) {
$linksToDisplay[] = $link; // Add to array. $linksToDisplay[] = $link; // Add to array.
} }
@ -637,8 +640,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
} }
// -------- Tag cloud // -------- Tag cloud
if ($targetPage == Router::$PAGE_TAGCLOUD) if ($targetPage == Router::$PAGE_TAGCLOUD) {
{
$visibility = ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : ''; $visibility = ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : '';
$filteringTags = isset($_GET['searchtags']) ? explode(' ', $_GET['searchtags']) : []; $filteringTags = isset($_GET['searchtags']) ? explode(' ', $_GET['searchtags']) : [];
$tags = $LINKSDB->linksCountPerTag($filteringTags, $visibility); $tags = $LINKSDB->linksCountPerTag($filteringTags, $visibility);
@ -685,8 +687,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
} }
// -------- Tag list // -------- Tag list
if ($targetPage == Router::$PAGE_TAGLIST) if ($targetPage == Router::$PAGE_TAGLIST) {
{
$visibility = ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : ''; $visibility = ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : '';
$filteringTags = isset($_GET['searchtags']) ? explode(' ', $_GET['searchtags']) : []; $filteringTags = isset($_GET['searchtags']) ? explode(' ', $_GET['searchtags']) : [];
$tags = $LINKSDB->linksCountPerTag($filteringTags, $visibility); $tags = $LINKSDB->linksCountPerTag($filteringTags, $visibility);
@ -770,10 +771,13 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
} }
// -------- User clicks on a tag in a link: The tag is added to the list of searched tags (searchtags=...) // -------- User clicks on a tag in a link: The tag is added to the list of searched tags (searchtags=...)
if (isset($_GET['addtag'])) if (isset($_GET['addtag'])) {
{
// Get previous URL (http_referer) and add the tag to the searchtags parameters in query. // Get previous URL (http_referer) and add the tag to the searchtags parameters in query.
if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?searchtags='.urlencode($_GET['addtag'])); exit; } // In case browser does not send HTTP_REFERER if (empty($_SERVER['HTTP_REFERER'])) {
// In case browser does not send HTTP_REFERER
header('Location: ?searchtags='.urlencode($_GET['addtag']));
exit;
}
parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $params); parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $params);
// Prevent redirection loop // Prevent redirection loop
@ -798,12 +802,14 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
// Append the tag if necessary // Append the tag if necessary
if (empty($params['searchtags'])) { if (empty($params['searchtags'])) {
$params['searchtags'] = trim($_GET['addtag']); $params['searchtags'] = trim($_GET['addtag']);
} } elseif ($addtag) {
elseif ($addtag) {
$params['searchtags'] = trim($params['searchtags']).' '.trim($_GET['addtag']); $params['searchtags'] = trim($params['searchtags']).' '.trim($_GET['addtag']);
} }
unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different) // We also remove page (keeping the same page has no sense, since the
// results are different)
unset($params['page']);
header('Location: ?'.http_build_query($params)); header('Location: ?'.http_build_query($params));
exit; exit;
} }
@ -834,7 +840,9 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
unset($params['searchtags']); unset($params['searchtags']);
} }
unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different) // We also remove page (keeping the same page has no sense, since
// the results are different)
unset($params['page']);
} }
header('Location: ?'.http_build_query($params)); header('Location: ?'.http_build_query($params));
exit; exit;
@ -897,12 +905,10 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
} }
// -------- Handle other actions allowed for non-logged in users: // -------- Handle other actions allowed for non-logged in users:
if (!$loginManager->isLoggedIn()) if (!$loginManager->isLoggedIn()) {
{
// User tries to post new link but is not logged in: // User tries to post new link but is not logged in:
// Show login screen, then redirect to ?post=... // Show login screen, then redirect to ?post=...
if (isset($_GET['post'])) if (isset($_GET['post'])) {
{
header( // Redirect to login page, then back to post link. header( // Redirect to login page, then back to post link.
'Location: ?do=login&post='.urlencode($_GET['post']). 'Location: ?do=login&post='.urlencode($_GET['post']).
(!empty($_GET['title'])?'&title='.urlencode($_GET['title']):''). (!empty($_GET['title'])?'&title='.urlencode($_GET['title']):'').
@ -925,8 +931,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
// -------- All other functions are reserved for the registered user: // -------- All other functions are reserved for the registered user:
// -------- Display the Tools menu if requested (import/export/bookmarklet...) // -------- Display the Tools menu if requested (import/export/bookmarklet...)
if ($targetPage == Router::$PAGE_TOOLS) if ($targetPage == Router::$PAGE_TOOLS) {
{
$data = [ $data = [
'pageabsaddr' => index_url($_SERVER), 'pageabsaddr' => index_url($_SERVER),
'sslenabled' => is_https($_SERVER), 'sslenabled' => is_https($_SERVER),
@ -943,30 +948,40 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
} }
// -------- User wants to change his/her password. // -------- User wants to change his/her password.
if ($targetPage == Router::$PAGE_CHANGEPASSWORD) if ($targetPage == Router::$PAGE_CHANGEPASSWORD) {
{
if ($conf->get('security.open_shaarli')) { if ($conf->get('security.open_shaarli')) {
die(t('You are not supposed to change a password on an Open Shaarli.')); die(t('You are not supposed to change a password on an Open Shaarli.'));
} }
if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) {
{ if (!$sessionManager->checkToken($_POST['token'])) {
if (!$sessionManager->checkToken($_POST['token'])) die(t('Wrong token.')); // Go away! die(t('Wrong token.')); // Go away!
}
// Make sure old password is correct. // Make sure old password is correct.
$oldhash = sha1($_POST['oldpassword'].$conf->get('credentials.login').$conf->get('credentials.salt')); $oldhash = sha1(
$_POST['oldpassword'].$conf->get('credentials.login').$conf->get('credentials.salt')
);
if ($oldhash != $conf->get('credentials.hash')) { if ($oldhash != $conf->get('credentials.hash')) {
echo '<script>alert("'. t('The old password is not correct.') .'");document.location=\'?do=changepasswd\';</script>'; echo '<script>alert("'
. t('The old password is not correct.')
.'");document.location=\'?do=changepasswd\';</script>';
exit; exit;
} }
// Save new password // Save new password
// Salt renders rainbow-tables attacks useless. // Salt renders rainbow-tables attacks useless.
$conf->set('credentials.salt', sha1(uniqid('', true) .'_'. mt_rand())); $conf->set('credentials.salt', sha1(uniqid('', true) .'_'. mt_rand()));
$conf->set('credentials.hash', sha1($_POST['setpassword'] . $conf->get('credentials.login') . $conf->get('credentials.salt'))); $conf->set(
'credentials.hash',
sha1(
$_POST['setpassword']
. $conf->get('credentials.login')
. $conf->get('credentials.salt')
)
);
try { try {
$conf->write($loginManager->isLoggedIn()); $conf->write($loginManager->isLoggedIn());
} } catch (Exception $e) {
catch(Exception $e) {
error_log( error_log(
'ERROR while writing config file after changing password.' . PHP_EOL . 'ERROR while writing config file after changing password.' . PHP_EOL .
$e->getMessage() $e->getMessage()
@ -978,9 +993,8 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
} }
echo '<script>alert("'. t('Your password has been changed') .'");document.location=\'?do=tools\';</script>'; echo '<script>alert("'. t('Your password has been changed') .'");document.location=\'?do=tools\';</script>';
exit; exit;
} } else {
else // show the change password form. // show the change password form.
{
$PAGE->assign('pagetitle', t('Change password') .' - '. $conf->get('general.title', 'Shaarli')); $PAGE->assign('pagetitle', t('Change password') .' - '. $conf->get('general.title', 'Shaarli'));
$PAGE->renderPage('changepassword'); $PAGE->renderPage('changepassword');
exit; exit;
@ -988,10 +1002,8 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
} }
// -------- User wants to change configuration // -------- User wants to change configuration
if ($targetPage == Router::$PAGE_CONFIGURE) if ($targetPage == Router::$PAGE_CONFIGURE) {
{ if (!empty($_POST['title'])) {
if (!empty($_POST['title']) )
{
if (!$sessionManager->checkToken($_POST['token'])) { if (!$sessionManager->checkToken($_POST['token'])) {
die(t('Wrong token.')); // Go away! die(t('Wrong token.')); // Go away!
} }
@ -1019,7 +1031,8 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
&& $thumbnailsMode !== $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) && $thumbnailsMode !== $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE)
) { ) {
$_SESSION['warnings'][] = t( $_SESSION['warnings'][] = t(
'You have enabled or changed thumbnails mode. <a href="?do=thumbs_update">Please synchronize them</a>.' 'You have enabled or changed thumbnails mode. '
.'<a href="?do=thumbs_update">Please synchronize them</a>.'
); );
} }
$conf->set('thumbnails.mode', $thumbnailsMode); $conf->set('thumbnails.mode', $thumbnailsMode);
@ -1028,8 +1041,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
$conf->write($loginManager->isLoggedIn()); $conf->write($loginManager->isLoggedIn());
$history->updateSettings(); $history->updateSettings();
invalidateCaches($conf->get('resource.page_cache')); invalidateCaches($conf->get('resource.page_cache'));
} } catch (Exception $e) {
catch(Exception $e) {
error_log( error_log(
'ERROR while writing config file after configuration update.' . PHP_EOL . 'ERROR while writing config file after configuration update.' . PHP_EOL .
$e->getMessage() $e->getMessage()
@ -1041,9 +1053,8 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
} }
echo '<script>alert("'. t('Configuration was saved.') .'");document.location=\'?do=configure\';</script>'; echo '<script>alert("'. t('Configuration was saved.') .'");document.location=\'?do=configure\';</script>';
exit; exit;
} } else {
else // Show the configuration form. // Show the configuration form.
{
$PAGE->assign('title', $conf->get('general.title')); $PAGE->assign('title', $conf->get('general.title'));
$PAGE->assign('theme', $conf->get('resource.theme')); $PAGE->assign('theme', $conf->get('resource.theme'));
$PAGE->assign('theme_available', ThemeUtils::getThemes($conf->get('resource.raintpl_tpl'))); $PAGE->assign('theme_available', ThemeUtils::getThemes($conf->get('resource.raintpl_tpl')));
@ -1071,8 +1082,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
} }
// -------- User wants to rename a tag or delete it // -------- User wants to rename a tag or delete it
if ($targetPage == Router::$PAGE_CHANGETAG) if ($targetPage == Router::$PAGE_CHANGETAG) {
{
if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) { if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) {
$PAGE->assign('fromtag', ! empty($_GET['fromtag']) ? escape($_GET['fromtag']) : ''); $PAGE->assign('fromtag', ! empty($_GET['fromtag']) ? escape($_GET['fromtag']) : '');
$PAGE->assign('pagetitle', t('Manage tags') .' - '. $conf->get('general.title', 'Shaarli')); $PAGE->assign('pagetitle', t('Manage tags') .' - '. $conf->get('general.title', 'Shaarli'));
@ -1101,16 +1111,14 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
} }
// -------- User wants to add a link without using the bookmarklet: Show form. // -------- User wants to add a link without using the bookmarklet: Show form.
if ($targetPage == Router::$PAGE_ADDLINK) if ($targetPage == Router::$PAGE_ADDLINK) {
{
$PAGE->assign('pagetitle', t('Shaare a new link') .' - '. $conf->get('general.title', 'Shaarli')); $PAGE->assign('pagetitle', t('Shaare a new link') .' - '. $conf->get('general.title', 'Shaarli'));
$PAGE->renderPage('addlink'); $PAGE->renderPage('addlink');
exit; exit;
} }
// -------- User clicked the "Save" button when editing a link: Save link to database. // -------- User clicked the "Save" button when editing a link: Save link to database.
if (isset($_POST['save_edit'])) if (isset($_POST['save_edit'])) {
{
// Go away! // Go away!
if (! $sessionManager->checkToken($_POST['token'])) { if (! $sessionManager->checkToken($_POST['token'])) {
die(t('Wrong token.')); die(t('Wrong token.'));
@ -1197,14 +1205,16 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
} }
// -------- User clicked the "Cancel" button when editing a link. // -------- User clicked the "Cancel" button when editing a link.
if (isset($_POST['cancel_edit'])) if (isset($_POST['cancel_edit'])) {
{
$id = isset($_POST['lf_id']) ? (int) escape($_POST['lf_id']) : false; $id = isset($_POST['lf_id']) ? (int) escape($_POST['lf_id']) : false;
if (! isset($LINKSDB[$id])) { if (! isset($LINKSDB[$id])) {
header('Location: ?'); header('Location: ?');
} }
// If we are called from the bookmarklet, we must close the popup: // If we are called from the bookmarklet, we must close the popup:
if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) {
echo '<script>self.close();</script>';
exit;
}
$link = $LINKSDB[$id]; $link = $LINKSDB[$id];
$returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' );
// Scroll to the link which has been edited. // Scroll to the link which has been edited.
@ -1215,8 +1225,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
} }
// -------- User clicked the "Delete" button when editing a link: Delete link from database. // -------- User clicked the "Delete" button when editing a link: Delete link from database.
if ($targetPage == Router::$PAGE_DELETELINK) if ($targetPage == Router::$PAGE_DELETELINK) {
{
if (! $sessionManager->checkToken($_GET['token'])) { if (! $sessionManager->checkToken($_GET['token'])) {
die(t('Wrong token.')); die(t('Wrong token.'));
} }
@ -1243,7 +1252,10 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
$LINKSDB->save($conf->get('resource.page_cache')); // save to disk $LINKSDB->save($conf->get('resource.page_cache')); // save to disk
// If we are called from the bookmarklet, we must close the popup: // If we are called from the bookmarklet, we must close the popup:
if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) {
echo '<script>self.close();</script>';
exit;
}
$location = '?'; $location = '?';
if (isset($_SERVER['HTTP_REFERER'])) { if (isset($_SERVER['HTTP_REFERER'])) {
@ -1260,11 +1272,13 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
} }
// -------- User clicked the "EDIT" button on a link: Display link edit form. // -------- User clicked the "EDIT" button on a link: Display link edit form.
if (isset($_GET['edit_link'])) if (isset($_GET['edit_link'])) {
{
$id = (int) escape($_GET['edit_link']); $id = (int) escape($_GET['edit_link']);
$link = $LINKSDB[$id]; // Read database $link = $LINKSDB[$id]; // Read database
if (!$link) { header('Location: ?'); exit; } // Link not found in database. if (!$link) {
header('Location: ?');
exit;
} // Link not found in database.
$link['linkdate'] = $link['created']->format(LinkDB::LINK_DATE_FORMAT); $link['linkdate'] = $link['created']->format(LinkDB::LINK_DATE_FORMAT);
$data = array( $data = array(
'link' => $link, 'link' => $link,
@ -1290,8 +1304,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
$link_is_new = false; $link_is_new = false;
// Check if URL is not already in database (in this case, we will edit the existing link) // Check if URL is not already in database (in this case, we will edit the existing link)
$link = $LINKSDB->getLinkFromUrl($url); $link = $LINKSDB->getLinkFromUrl($url);
if (! $link) if (! $link) {
{
$link_is_new = true; $link_is_new = true;
$linkdate = strval(date(LinkDB::LINK_DATE_FORMAT)); $linkdate = strval(date(LinkDB::LINK_DATE_FORMAT));
// Get title if it was provided in URL (by the bookmarklet). // Get title if it was provided in URL (by the bookmarklet).
@ -1300,7 +1313,9 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
$description = empty($_GET['description']) ? '' : escape($_GET['description']); $description = empty($_GET['description']) ? '' : escape($_GET['description']);
$tags = empty($_GET['tags']) ? '' : escape($_GET['tags']); $tags = empty($_GET['tags']) ? '' : escape($_GET['tags']);
$private = !empty($_GET['private']) && $_GET['private'] === "1" ? 1 : 0; $private = !empty($_GET['private']) && $_GET['private'] === "1" ? 1 : 0;
// If this is an HTTP(S) link, we try go get the page to extract the title (otherwise we will to straight to the edit form.)
// If this is an HTTP(S) link, we try go get the page to extract
// the title (otherwise we will to straight to the edit form.)
if (empty($title) && strpos(get_url_scheme($url), 'http') !== false) { if (empty($title) && strpos(get_url_scheme($url), 'http') !== false) {
// Short timeout to keep the application responsive // Short timeout to keep the application responsive
// The callback will fill $charset and $title with data from the downloaded page. // The callback will fill $charset and $title with data from the downloaded page.
@ -1476,14 +1491,20 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
$pluginMeta = $pluginManager->getPluginsMeta(); $pluginMeta = $pluginManager->getPluginsMeta();
// Split plugins into 2 arrays: ordered enabled plugins and disabled. // Split plugins into 2 arrays: ordered enabled plugins and disabled.
$enabledPlugins = array_filter($pluginMeta, function($v) { return $v['order'] !== false; }); $enabledPlugins = array_filter($pluginMeta, function ($v) {
return $v['order'] !== false;
});
// Load parameters. // Load parameters.
$enabledPlugins = load_plugin_parameter_values($enabledPlugins, $conf->get('plugins', array())); $enabledPlugins = load_plugin_parameter_values($enabledPlugins, $conf->get('plugins', array()));
uasort( uasort(
$enabledPlugins, $enabledPlugins,
function($a, $b) { return $a['order'] - $b['order']; } function ($a, $b) {
return $a['order'] - $b['order'];
}
); );
$disabledPlugins = array_filter($pluginMeta, function($v) { return $v['order'] === false; }); $disabledPlugins = array_filter($pluginMeta, function ($v) {
return $v['order'] === false;
});
$PAGE->assign('enabledPlugins', $enabledPlugins); $PAGE->assign('enabledPlugins', $enabledPlugins);
$PAGE->assign('disabledPlugins', $disabledPlugins); $PAGE->assign('disabledPlugins', $disabledPlugins);
@ -1500,21 +1521,23 @@ function($a, $b) { return $a['order'] - $b['order']; }
foreach ($_POST as $param => $value) { foreach ($_POST as $param => $value) {
$conf->set('plugins.'. $param, escape($value)); $conf->set('plugins.'. $param, escape($value));
} }
} } else {
else {
$conf->set('general.enabled_plugins', save_plugin_config($_POST)); $conf->set('general.enabled_plugins', save_plugin_config($_POST));
} }
$conf->write($loginManager->isLoggedIn()); $conf->write($loginManager->isLoggedIn());
$history->updateSettings(); $history->updateSettings();
} } catch (Exception $e) {
catch (Exception $e) {
error_log( error_log(
'ERROR while saving plugin configuration:.' . PHP_EOL . 'ERROR while saving plugin configuration:.' . PHP_EOL .
$e->getMessage() $e->getMessage()
); );
// TODO: do not handle exceptions/errors in JS. // TODO: do not handle exceptions/errors in JS.
echo '<script>alert("'. $e->getMessage() .'");document.location=\'?do='. Router::$PAGE_PLUGINSADMIN .'\';</script>'; echo '<script>alert("'
. $e->getMessage()
.'");document.location=\'?do='
. Router::$PAGE_PLUGINSADMIN
.'\';</script>';
exit; exit;
} }
header('Location: ?do='. Router::$PAGE_PLUGINSADMIN); header('Location: ?do='. Router::$PAGE_PLUGINSADMIN);
@ -1635,8 +1658,7 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager)
} }
$linkDisp = array(); $linkDisp = array();
while ($i<$end && $i<count($keys)) while ($i<$end && $i<count($keys)) {
{
$link = $linksToDisplay[$keys[$i]]; $link = $linksToDisplay[$keys[$i]];
$link['description'] = format_description( $link['description'] = format_description(
$link['description'], $link['description'],
@ -1739,16 +1761,19 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager)
* @param SessionManager $sessionManager SessionManager instance * @param SessionManager $sessionManager SessionManager instance
* @param LoginManager $loginManager LoginManager instance * @param LoginManager $loginManager LoginManager instance
*/ */
function install($conf, $sessionManager, $loginManager) { function install($conf, $sessionManager, $loginManager)
{
// On free.fr host, make sure the /sessions directory exists, otherwise login will not work. // On free.fr host, make sure the /sessions directory exists, otherwise login will not work.
if (endsWith($_SERVER['HTTP_HOST'],'.free.fr') && !is_dir($_SERVER['DOCUMENT_ROOT'].'/sessions')) mkdir($_SERVER['DOCUMENT_ROOT'].'/sessions',0705); if (endsWith($_SERVER['HTTP_HOST'], '.free.fr') && !is_dir($_SERVER['DOCUMENT_ROOT'].'/sessions')) {
mkdir($_SERVER['DOCUMENT_ROOT'].'/sessions', 0705);
}
// This part makes sure sessions works correctly. // This part makes sure sessions works correctly.
// (Because on some hosts, session.save_path may not be set correctly, // (Because on some hosts, session.save_path may not be set correctly,
// or we may not have write access to it.) // or we may not have write access to it.)
if (isset($_GET['test_session']) && ( !isset($_SESSION) || !isset($_SESSION['session_tested']) || $_SESSION['session_tested']!='Working')) if (isset($_GET['test_session'])
{ && ( !isset($_SESSION) || !isset($_SESSION['session_tested']) || $_SESSION['session_tested']!='Working')) {
// Step 2: Check if data in session is correct. // Step 2: Check if data in session is correct.
$msg = t( $msg = t(
'<pre>Sessions do not seem to work correctly on your server.<br>'. '<pre>Sessions do not seem to work correctly on your server.<br>'.
@ -1764,19 +1789,18 @@ function install($conf, $sessionManager, $loginManager) {
echo '<br><a href="?">'. t('Click to try again.') .'</a></pre>'; echo '<br><a href="?">'. t('Click to try again.') .'</a></pre>';
die; die;
} }
if (!isset($_SESSION['session_tested'])) if (!isset($_SESSION['session_tested'])) {
{ // Step 1 : Try to store data in session and reload page. // Step 1 : Try to store data in session and reload page.
$_SESSION['session_tested'] = 'Working'; // Try to set a variable in session. $_SESSION['session_tested'] = 'Working'; // Try to set a variable in session.
header('Location: '.index_url($_SERVER).'?test_session'); // Redirect to check stored data. header('Location: '.index_url($_SERVER).'?test_session'); // Redirect to check stored data.
} }
if (isset($_GET['test_session'])) if (isset($_GET['test_session'])) {
{ // Step 3: Sessions are OK. Remove test parameter from URL. // Step 3: Sessions are OK. Remove test parameter from URL.
header('Location: '.index_url($_SERVER)); header('Location: '.index_url($_SERVER));
} }
if (!empty($_POST['setlogin']) && !empty($_POST['setpassword'])) if (!empty($_POST['setlogin']) && !empty($_POST['setpassword'])) {
{
$tz = 'UTC'; $tz = 'UTC';
if (!empty($_POST['continent']) && !empty($_POST['city']) if (!empty($_POST['continent']) && !empty($_POST['city'])
&& isTimeZoneValid($_POST['continent'], $_POST['city']) && isTimeZoneValid($_POST['continent'], $_POST['city'])
@ -1807,8 +1831,7 @@ function install($conf, $sessionManager, $loginManager) {
try { try {
// Everything is ok, let's create config file. // Everything is ok, let's create config file.
$conf->write($loginManager->isLoggedIn()); $conf->write($loginManager->isLoggedIn());
} } catch (Exception $e) {
catch(Exception $e) {
error_log( error_log(
'ERROR while writing config file after installation.' . PHP_EOL . 'ERROR while writing config file after installation.' . PHP_EOL .
$e->getMessage() $e->getMessage()
@ -1818,7 +1841,10 @@ function install($conf, $sessionManager, $loginManager) {
echo '<script>alert("'. $e->getMessage() .'");document.location=\'?\';</script>'; echo '<script>alert("'. $e->getMessage() .'");document.location=\'?\';</script>';
exit; exit;
} }
echo '<script>alert("Shaarli is now configured. Please enter your login/password and start shaaring your links!");document.location=\'?do=login\';</script>'; echo '<script>alert('
.'"Shaarli is now configured. '
.'Please enter your login/password and start shaaring your links!"'
.');document.location=\'?do=login\';</script>';
exit; exit;
} }

17
phpcs.xml Normal file
View file

@ -0,0 +1,17 @@
<?xml version="1.0"?>
<ruleset name="Shaarli">
<description>The Shaarli coding standards</description>
<file>index.php</file>
<file>application</file>
<file>plugins</file>
<file>tests</file>
<exclude-pattern>*/*.css</exclude-pattern>
<exclude-pattern>*/*.js</exclude-pattern>
<arg name="colors"/>
<rule ref="PSR1"/>
<rule ref="PSR2"/>
</ruleset>

View file

@ -73,7 +73,6 @@ function hook_demo_plugin_render_header($data)
{ {
// Only execute when linklist is rendered. // Only execute when linklist is rendered.
if ($data['_PAGE_'] == Router::$PAGE_LINKLIST) { if ($data['_PAGE_'] == Router::$PAGE_LINKLIST) {
// If loggedin // If loggedin
if ($data['_LOGGEDIN_'] === true) { if ($data['_LOGGEDIN_'] === true) {
/* /*
@ -448,8 +447,7 @@ function hook_demo_plugin_render_feed($data)
foreach ($data['links'] as &$link) { foreach ($data['links'] as &$link) {
if ($data['_PAGE_'] == Router::$PAGE_FEED_ATOM) { if ($data['_PAGE_'] == Router::$PAGE_FEED_ATOM) {
$link['description'] .= ' - ATOM Feed' ; $link['description'] .= ' - ATOM Feed' ;
} } elseif ($data['_PAGE_'] == Router::$PAGE_FEED_RSS) {
elseif ($data['_PAGE_'] == Router::$PAGE_FEED_RSS) {
$link['description'] .= ' - RSS Feed'; $link['description'] .= ' - RSS Feed';
} }
} }

View file

@ -139,7 +139,6 @@ function hook_markdown_render_includes($data)
|| $data['_PAGE_'] == Router::$PAGE_DAILY || $data['_PAGE_'] == Router::$PAGE_DAILY
|| $data['_PAGE_'] == Router::$PAGE_EDITLINK || $data['_PAGE_'] == Router::$PAGE_EDITLINK
) { ) {
$data['css_files'][] = PluginManager::$PLUGINS_PATH . '/markdown/markdown.css'; $data['css_files'][] = PluginManager::$PLUGINS_PATH . '/markdown/markdown.css';
} }
@ -195,8 +194,7 @@ function reverse_text2clickable($description)
// Detect and toggle block of code // Detect and toggle block of code
if (!$codeBlockOn) { if (!$codeBlockOn) {
$codeBlockOn = preg_match('/^```/', $descriptionLine) > 0; $codeBlockOn = preg_match('/^```/', $descriptionLine) > 0;
} } elseif (preg_match('/^```/', $descriptionLine) > 0) {
elseif (preg_match('/^```/', $descriptionLine) > 0) {
$codeBlockOn = false; $codeBlockOn = false;
} }
@ -302,13 +300,17 @@ function sanitize_html($description)
foreach ($escapeTags as $tag) { foreach ($escapeTags as $tag) {
$description = preg_replace_callback( $description = preg_replace_callback(
'#<\s*'. $tag .'[^>]*>(.*</\s*'. $tag .'[^>]*>)?#is', '#<\s*'. $tag .'[^>]*>(.*</\s*'. $tag .'[^>]*>)?#is',
function ($match) { return escape($match[0]); }, function ($match) {
$description); return escape($match[0]);
},
$description
);
} }
$description = preg_replace( $description = preg_replace(
'#(<[^>]+\s)on[a-z]*="?[^ "]*"?#is', '#(<[^>]+\s)on[a-z]*="?[^ "]*"?#is',
'$1', '$1',
$description); $description
);
return $description; return $description;
} }

View file

@ -82,7 +82,8 @@ function hook_pubsubhubbub_save_link($data, $conf)
* *
* @throws Exception An error occurred. * @throws Exception An error occurred.
*/ */
function nocurl_http_post($url, $postString) { function nocurl_http_post($url, $postString)
{
$params = array('http' => array( $params = array('http' => array(
'method' => 'POST', 'method' => 'POST',
'content' => $postString, 'content' => $postString,

View file

@ -17,7 +17,8 @@ function hook_qrcode_render_linklist($data)
$qrcode_html = file_get_contents(PluginManager::$PLUGINS_PATH . '/qrcode/qrcode.html'); $qrcode_html = file_get_contents(PluginManager::$PLUGINS_PATH . '/qrcode/qrcode.html');
foreach ($data['links'] as &$value) { foreach ($data['links'] as &$value) {
$qrcode = sprintf($qrcode_html, $qrcode = sprintf(
$qrcode_html,
urlencode($value['url']), urlencode($value['url']),
$value['url'], $value['url'],
PluginManager::$PLUGINS_PATH PluginManager::$PLUGINS_PATH

View file

@ -69,4 +69,3 @@ function wallabag_dummy_translation()
t('Wallabag API URL'); t('Wallabag API URL');
t('Wallabag API version (1 or 2)'); t('Wallabag API version (1 or 2)');
} }

View file

@ -5,7 +5,8 @@
/** /**
* Unitary tests for getIpAddressFromProxy() * Unitary tests for getIpAddressFromProxy()
*/ */
class GetIpAdressFromProxyTest extends PHPUnit_Framework_TestCase { class GetIpAdressFromProxyTest extends PHPUnit_Framework_TestCase
{
/** /**
* Test without proxy * Test without proxy

View file

@ -76,7 +76,15 @@ public function testFilter()
$this->assertEquals( $this->assertEquals(
self::$refDB->countUntaggedLinks(), self::$refDB->countUntaggedLinks(),
count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, /*$request=*/'', /*$casesensitive=*/false, /*$visibility=*/'all', /*$untaggedonly=*/true)) count(
self::$linkFilter->filter(
LinkFilter::$FILTER_TAG,
/*$request=*/'',
/*$casesensitive=*/false,
/*$visibility=*/'all',
/*$untaggedonly=*/true
)
)
); );
$this->assertEquals( $this->assertEquals(

View file

@ -83,7 +83,9 @@ public function testCurlDownloadCallbackOk()
'Date: Sat, 28 Oct 2017 12:01:33 GMT', 'Date: Sat, 28 Oct 2017 12:01:33 GMT',
'Content-Type: text/html; charset=utf-8', 'Content-Type: text/html; charset=utf-8',
'Status: 200 OK', 'Status: 200 OK',
'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea', 'end' => 'th=device-width">'
.'<title>Refactoring · GitHub</title>'
.'<link rel="search" type="application/opensea',
'<title>ignored</title>', '<title>ignored</title>',
]; ];
foreach ($data as $key => $line) { foreach ($data as $key => $line) {
@ -106,7 +108,9 @@ public function testCurlDownloadCallbackOkNoCharset()
$callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_no_charset'); $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_no_charset');
$data = [ $data = [
'HTTP/1.1 200 OK', 'HTTP/1.1 200 OK',
'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea', 'end' => 'th=device-width">'
.'<title>Refactoring · GitHub</title>'
.'<link rel="search" type="application/opensea',
'<title>ignored</title>', '<title>ignored</title>',
]; ];
foreach ($data as $key => $line) { foreach ($data as $key => $line) {
@ -126,7 +130,9 @@ public function testCurlDownloadCallbackOkHtmlCharset()
$data = [ $data = [
'HTTP/1.1 200 OK', 'HTTP/1.1 200 OK',
'<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />', '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',
'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea', 'end' => 'th=device-width">'
.'<title>Refactoring · GitHub</title>'
.'<link rel="search" type="application/opensea',
'<title>ignored</title>', '<title>ignored</title>',
]; ];
foreach ($data as $key => $line) { foreach ($data as $key => $line) {
@ -211,23 +217,26 @@ public function testCountPrivateLinks()
public function testText2clickableWithoutRedirector() public function testText2clickableWithoutRedirector()
{ {
$text = 'stuff http://hello.there/is=someone#here otherstuff'; $text = 'stuff http://hello.there/is=someone#here otherstuff';
$expectedText = 'stuff <a href="http://hello.there/is=someone#here">http://hello.there/is=someone#here</a> otherstuff'; $expectedText = 'stuff <a href="http://hello.there/is=someone#here">'
.'http://hello.there/is=someone#here</a> otherstuff';
$processedText = text2clickable($text, ''); $processedText = text2clickable($text, '');
$this->assertEquals($expectedText, $processedText); $this->assertEquals($expectedText, $processedText);
$text = 'stuff http://hello.there/is=someone#here(please) otherstuff'; $text = 'stuff http://hello.there/is=someone#here(please) otherstuff';
$expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)">http://hello.there/is=someone#here(please)</a> otherstuff'; $expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)">'
.'http://hello.there/is=someone#here(please)</a> otherstuff';
$processedText = text2clickable($text, ''); $processedText = text2clickable($text, '');
$this->assertEquals($expectedText, $processedText); $this->assertEquals($expectedText, $processedText);
$text = 'stuff http://hello.there/is=someone#here(please)&no otherstuff'; $text = 'stuff http://hello.there/is=someone#here(please)&no otherstuff';
$expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)&no">http://hello.there/is=someone#here(please)&no</a> otherstuff'; $expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)&no">'
.'http://hello.there/is=someone#here(please)&no</a> otherstuff';
$processedText = text2clickable($text, ''); $processedText = text2clickable($text, '');
$this->assertEquals($expectedText, $processedText); $this->assertEquals($expectedText, $processedText);
} }
/** /**
* Test text2clickable a redirector set. * Test text2clickable with a redirector set.
*/ */
public function testText2clickableWithRedirector() public function testText2clickableWithRedirector()
{ {
@ -410,4 +419,3 @@ function ut_curl_getinfo_rs_ct_ko($ch, $type)
return 'text/plain'; return 'text/plain';
} }
} }

View file

@ -218,7 +218,6 @@ public function testFindPageChangepasswdValid()
Router::$PAGE_CHANGEPASSWORD, Router::$PAGE_CHANGEPASSWORD,
Router::findPage('do=changepasswd&stuff', array(), true) Router::findPage('do=changepasswd&stuff', array(), true)
); );
} }
/** /**

View file

@ -98,17 +98,19 @@ public function testThumbnailNotValid()
ini_set('error_log', $oldlog); ini_set('error_log', $oldlog);
} }
protected function rrmdirContent($dir) { protected function rrmdirContent($dir)
{
if (is_dir($dir)) { if (is_dir($dir)) {
$objects = scandir($dir); $objects = scandir($dir);
foreach ($objects as $object) { foreach ($objects as $object) {
if ($object != "." && $object != "..") { if ($object != "." && $object != "..") {
if (is_dir($dir."/".$object)) if (is_dir($dir."/".$object)) {
$this->rrmdirContent($dir."/".$object); $this->rrmdirContent($dir."/".$object);
else } else {
unlink($dir."/".$object); unlink($dir."/".$object);
} }
} }
} }
} }
} }
}

View file

@ -31,7 +31,7 @@ public function __construct($doneUpdates, $linkDB, $conf, $isLoggedIn)
* *
* @return bool true. * @return bool true.
*/ */
private final function updateMethodDummy1() final private function updateMethodDummy1()
{ {
return true; return true;
} }
@ -41,7 +41,7 @@ private final function updateMethodDummy1()
* *
* @return bool true. * @return bool true.
*/ */
private final function updateMethodDummy2() final private function updateMethodDummy2()
{ {
return true; return true;
} }
@ -51,7 +51,7 @@ private final function updateMethodDummy2()
* *
* @return bool true. * @return bool true.
*/ */
private final function updateMethodDummy3() final private function updateMethodDummy3()
{ {
return true; return true;
} }
@ -61,7 +61,7 @@ private final function updateMethodDummy3()
* *
* @throws Exception error. * @throws Exception error.
*/ */
private final function updateMethodException() final private function updateMethodException()
{ {
throw new Exception('whatever'); throw new Exception('whatever');
} }

View file

@ -393,20 +393,32 @@ public function testDatastoreIds()
$this->assertEquals('Naming conventions... #private', $linkDB[0]['description']); $this->assertEquals('Naming conventions... #private', $linkDB[0]['description']);
$this->assertEquals('samba cartoon web', $linkDB[0]['tags']); $this->assertEquals('samba cartoon web', $linkDB[0]['tags']);
$this->assertTrue($linkDB[0]['private']); $this->assertTrue($linkDB[0]['private']);
$this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_142300'), $linkDB[0]['created']); $this->assertEquals(
DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_142300'),
$linkDB[0]['created']
);
$this->assertTrue(isset($linkDB[1])); $this->assertTrue(isset($linkDB[1]));
$this->assertFalse(isset($linkDB[1]['linkdate'])); $this->assertFalse(isset($linkDB[1]['linkdate']));
$this->assertEquals(1, $linkDB[1]['id']); $this->assertEquals(1, $linkDB[1]['id']);
$this->assertEquals('UserFriendly - Samba', $linkDB[1]['title']); $this->assertEquals('UserFriendly - Samba', $linkDB[1]['title']);
$this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_172539'), $linkDB[1]['created']); $this->assertEquals(
DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_172539'),
$linkDB[1]['created']
);
$this->assertTrue(isset($linkDB[2])); $this->assertTrue(isset($linkDB[2]));
$this->assertFalse(isset($linkDB[2]['linkdate'])); $this->assertFalse(isset($linkDB[2]['linkdate']));
$this->assertEquals(2, $linkDB[2]['id']); $this->assertEquals(2, $linkDB[2]['id']);
$this->assertEquals('Geek and Poke', $linkDB[2]['title']); $this->assertEquals('Geek and Poke', $linkDB[2]['title']);
$this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_182539'), $linkDB[2]['created']); $this->assertEquals(
$this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_190301'), $linkDB[2]['updated']); DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_182539'),
$linkDB[2]['created']
);
$this->assertEquals(
DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_190301'),
$linkDB[2]['updated']
);
} }
/** /**

View file

@ -107,4 +107,3 @@ public function testCleanupUrlQueryFragment()
); );
} }
} }

View file

@ -28,4 +28,3 @@ public function testGetUrlScheme()
$this->assertEquals('git', get_url_scheme('git://domain.tld/push?pull=clone#checkout')); $this->assertEquals('git', get_url_scheme('git://domain.tld/push?pull=clone#checkout'));
} }
} }

View file

@ -28,4 +28,3 @@ public function testUnparseFull()
$this->assertEquals($ref, unparse_url(parse_url($ref))); $this->assertEquals($ref, unparse_url(parse_url($ref)));
} }
} }

View file

@ -135,13 +135,13 @@ public function testCleanupMixedContent()
'about://reader?url=' . urlencode(self::$baseUrl .'?my=stuff&is=kept') 'about://reader?url=' . urlencode(self::$baseUrl .'?my=stuff&is=kept')
); );
$this->assertEquals(self::$baseUrl.'?my=stuff&is=kept', $url->cleanup()); $this->assertEquals(self::$baseUrl.'?my=stuff&is=kept', $url->cleanup());
} }
/** /**
* Test default http scheme. * Test default http scheme.
*/ */
public function testDefaultScheme() { public function testDefaultScheme()
{
$url = new Url(self::$baseUrl); $url = new Url(self::$baseUrl);
$this->assertEquals('http', $url->getScheme()); $this->assertEquals('http', $url->getScheme());
$url = new Url('domain.tld'); $url = new Url('domain.tld');

View file

@ -187,7 +187,8 @@ public function testCheckInvalidDateFormat()
/** /**
* Test generate location with valid data. * Test generate location with valid data.
*/ */
public function testGenerateLocation() { public function testGenerateLocation()
{
$ref = 'http://localhost/?test'; $ref = 'http://localhost/?test';
$this->assertEquals($ref, generateLocation($ref, 'localhost')); $this->assertEquals($ref, generateLocation($ref, 'localhost'));
$ref = 'http://localhost:8080/?test'; $ref = 'http://localhost:8080/?test';
@ -199,7 +200,8 @@ public function testGenerateLocation() {
/** /**
* Test generate location - anti loop. * Test generate location - anti loop.
*/ */
public function testGenerateLocationLoop() { public function testGenerateLocationLoop()
{
$ref = 'http://localhost/?test'; $ref = 'http://localhost/?test';
$this->assertEquals('?', generateLocation($ref, 'localhost', array('test'))); $this->assertEquals('?', generateLocation($ref, 'localhost', array('test')));
} }
@ -207,7 +209,8 @@ public function testGenerateLocationLoop() {
/** /**
* Test generate location - from other domain. * Test generate location - from other domain.
*/ */
public function testGenerateLocationOut() { public function testGenerateLocationOut()
{
$ref = 'http://somewebsite.com/?test'; $ref = 'http://somewebsite.com/?test';
$this->assertEquals('?', generateLocation($ref, 'localhost')); $this->assertEquals('?', generateLocation($ref, 'localhost'));
} }

View file

@ -4,7 +4,6 @@
use Shaarli\Base64Url; use Shaarli\Base64Url;
/** /**
* Class ApiUtilsTest * Class ApiUtilsTest
*/ */

View file

@ -3,7 +3,6 @@
namespace Shaarli\Api\Controllers; namespace Shaarli\Api\Controllers;
use Shaarli\Config\ConfigManager; use Shaarli\Config\ConfigManager;
use Slim\Container; use Slim\Container;
use Slim\Http\Environment; use Slim\Http\Environment;

View file

@ -2,7 +2,6 @@
namespace Shaarli\Api\Controllers; namespace Shaarli\Api\Controllers;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shaarli\Config\ConfigManager; use Shaarli\Config\ConfigManager;
use Slim\Container; use Slim\Container;
@ -128,7 +127,9 @@ public function testPostLinkMinimal()
$this->assertEquals('', $data['description']); $this->assertEquals('', $data['description']);
$this->assertEquals([], $data['tags']); $this->assertEquals([], $data['tags']);
$this->assertEquals(false, $data['private']); $this->assertEquals(false, $data['private']);
$this->assertTrue(new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])); $this->assertTrue(
new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
);
$this->assertEquals('', $data['updated']); $this->assertEquals('', $data['updated']);
$historyEntry = $this->history->getHistory()[0]; $historyEntry = $this->history->getHistory()[0];
@ -171,7 +172,9 @@ public function testPostLinkFull()
$this->assertEquals($link['description'], $data['description']); $this->assertEquals($link['description'], $data['description']);
$this->assertEquals($link['tags'], $data['tags']); $this->assertEquals($link['tags'], $data['tags']);
$this->assertEquals(true, $data['private']); $this->assertEquals(true, $data['private']);
$this->assertTrue(new \DateTime('2 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])); $this->assertTrue(
new \DateTime('2 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
);
$this->assertEquals('', $data['updated']); $this->assertEquals('', $data['updated']);
} }

View file

@ -3,7 +3,6 @@
namespace Shaarli\Api\Controllers; namespace Shaarli\Api\Controllers;
use Shaarli\Config\ConfigManager; use Shaarli\Config\ConfigManager;
use Slim\Container; use Slim\Container;
use Slim\Http\Environment; use Slim\Http\Environment;
@ -115,7 +114,9 @@ public function testPutLinkMinimal()
\DateTime::createFromFormat('Ymd_His', '20150310_114651'), \DateTime::createFromFormat('Ymd_His', '20150310_114651'),
\DateTime::createFromFormat(\DateTime::ATOM, $data['created']) \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
); );
$this->assertTrue(new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])); $this->assertTrue(
new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])
);
$historyEntry = $this->history->getHistory()[0]; $historyEntry = $this->history->getHistory()[0];
$this->assertEquals(\History::UPDATED, $historyEntry['event']); $this->assertEquals(\History::UPDATED, $historyEntry['event']);
@ -160,7 +161,9 @@ public function testPutLinkWithValues()
\DateTime::createFromFormat('Ymd_His', '20150310_114651'), \DateTime::createFromFormat('Ymd_His', '20150310_114651'),
\DateTime::createFromFormat(\DateTime::ATOM, $data['created']) \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
); );
$this->assertTrue(new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])); $this->assertTrue(
new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])
);
} }
/** /**

View file

@ -3,7 +3,6 @@
namespace Shaarli\Api\Controllers; namespace Shaarli\Api\Controllers;
use Shaarli\Api\Exceptions\ApiBadParametersException; use Shaarli\Api\Exceptions\ApiBadParametersException;
use Shaarli\Config\ConfigManager; use Shaarli\Config\ConfigManager;
use Slim\Container; use Slim\Container;

View file

@ -3,7 +3,6 @@
namespace Shaarli; namespace Shaarli;
use Shaarli\Config\ConfigManager; use Shaarli\Config\ConfigManager;
/** /**

View file

@ -15,7 +15,8 @@ class PluginQrcodeTest extends PHPUnit_Framework_TestCase
/** /**
* Reset plugin path * Reset plugin path
*/ */
public function setUp() { public function setUp()
{
PluginManager::$PLUGINS_PATH = 'plugins'; PluginManager::$PLUGINS_PATH = 'plugins';
} }

View file

@ -8,7 +8,6 @@
use \Shaarli\Security\SessionManager; use \Shaarli\Security\SessionManager;
use \PHPUnit\Framework\TestCase; use \PHPUnit\Framework\TestCase;
/** /**
* Test coverage for SessionManager * Test coverage for SessionManager
*/ */

View file

@ -150,8 +150,8 @@ protected function addLink(
$tags, $tags,
$updated = '', $updated = '',
$shorturl = '', $shorturl = '',
$pinned = false) $pinned = false
{ ) {
$link = array( $link = array(
'id' => $id, 'id' => $id,
'title' => $title, 'title' => $title,