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
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
@ -17,14 +15,6 @@ docker_%:
rsync -az /shaarli/ ~/shaarli/
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
# 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.reporting.php
##
PHPCS := $(BIN)/phpcs
code_sniffer: code_sniffer_full
code_sniffer:
@$(PHPCS)
### - errors filtered by coding standard: PEAR, PSR1, PSR2, Zend...
PHPCS_%:
@$(BIN)/phpcs $(PHP_SOURCE) --report-full --report-width=200 --standard=$*
@$(PHPCS) --report-full --report-width=200 --standard=$*
### - errors by Git author
code_sniffer_blame:
@$(BIN)/phpcs $(PHP_SOURCE) --report-gitblame
@$(PHPCS) --report-gitblame
### - all errors/warnings
code_sniffer_full:
@$(BIN)/phpcs $(PHP_SOURCE) --report-full --report-width=200
@$(PHPCS) --report-full --report-width=200
### - errors grouped by kind
code_sniffer_source:
@$(BIN)/phpcs $(PHP_SOURCE) --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;
@$(PHPCS) --report-source || exit 0
##
# Checks source file & script permissions

View file

@ -24,7 +24,7 @@ class ApplicationUtils
*
* @return mixed the version code from the repository if available, else 'false'
*/
public static function getLatestGitVersionCode($url, $timeout=2)
public static function getLatestGitVersionCode($url, $timeout = 2)
{
list($headers, $data) = get_http_response($url, $timeout);
@ -86,13 +86,14 @@ class ApplicationUtils
*
* @return mixed the new version code if available and greater, else 'false'
*/
public static function checkUpdate($currentVersion,
$updateFile,
$checkInterval,
$enableCheck,
$isLoggedIn,
$branch='stable')
{
public static function checkUpdate(
$currentVersion,
$updateFile,
$checkInterval,
$enableCheck,
$isLoggedIn,
$branch = 'stable'
) {
// Do not check versions for visitors
// Do not check if the user doesn't want to
// Do not check with dev version

View file

@ -2,7 +2,6 @@
namespace Shaarli;
/**
* URL-safe Base64 operations
*
@ -17,7 +16,8 @@ class Base64Url
*
* @return string Base64Url-encoded data
*/
public static function encode($data) {
public static function encode($data)
{
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
@ -28,7 +28,8 @@ class Base64Url
*
* @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));
}
}

View file

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

View file

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

View file

@ -92,7 +92,7 @@ class Languages
/**
* Initialize the translator using php gettext extension (gettext dependency act as a wrapper).
*/
protected function initGettextTranslator ()
protected function initGettextTranslator()
{
$this->translator = new GettextTranslator();
$this->translator->setLanguage($this->language);
@ -125,7 +125,8 @@ class Languages
$translations = $translations->addFromPoFile('inc/languages/'. $this->language .'/LC_MESSAGES/shaarli.po');
$translations->setDomain('shaarli');
$this->translator->loadTranslations($translations);
} catch (\InvalidArgumentException $e) {}
} catch (\InvalidArgumentException $e) {
}
// Default extension translation from the current theme
$theme = $this->conf->get('theme');
@ -137,7 +138,8 @@ class Languages
);
$translations->setDomain($theme);
$this->translator->loadTranslations($translations);
} catch (\InvalidArgumentException $e) {}
} catch (\InvalidArgumentException $e) {
}
}
// Extension translations (plugins, themes, etc.).
@ -147,10 +149,13 @@ class Languages
}
try {
$extension = Translations::fromPoFile($translationPath . $this->language .'/LC_MESSAGES/'. $domain .'.po');
$extension = Translations::fromPoFile(
$translationPath . $this->language .'/LC_MESSAGES/'. $domain .'.po'
);
$extension->setDomain($domain);
$this->translator->loadTranslations($extension);
} catch (\InvalidArgumentException $e) {}
} catch (\InvalidArgumentException $e) {
}
}
}

View file

@ -107,8 +107,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess
$hidePublicLinks,
$redirector = '',
$redirectorEncode = true
)
{
) {
$this->datastore = $datastore;
$this->loggedIn = $isLoggedIn;
$this->hidePublicLinks = $hidePublicLinks;
@ -250,11 +249,14 @@ class LinkDB implements Iterator, Countable, ArrayAccess
'id' => 1,
'title'=> t('The personal, minimalist, super-fast, database free, bookmarking service'),
'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.
You use the community supported version of the original Shaarli project, by Sebastien Sauvage.'),
You use the community supported version of the original Shaarli project, by Sebastien Sauvage.'
),
'private'=>0,
'created'=> new DateTime(),
'tags'=>'opensource software'
@ -317,8 +319,7 @@ You use the community supported version of the original Shaarli project, by Seba
} else {
$link['real_url'] .= $link['url'];
}
}
else {
} else {
$link['real_url'] = $link['url'];
}
@ -403,7 +404,8 @@ You use the community supported version of the original Shaarli project, by Seba
*
* @return array list of shaare found.
*/
public function filterDay($request) {
public function filterDay($request)
{
$linkFilter = new LinkFilter($this->links);
return $linkFilter->filter(LinkFilter::$FILTER_DAY, $request);
}
@ -420,8 +422,12 @@ You use the community supported version of the original Shaarli project, by Seba
*
* @return array filtered links, all links if no suitable filter was provided.
*/
public function filterSearch($filterRequest = array(), $casesensitive = false, $visibility = 'all', $untaggedonly = false)
{
public function filterSearch(
$filterRequest = array(),
$casesensitive = false,
$visibility = 'all',
$untaggedonly = false
) {
// Filter link database according to parameters.
$searchtags = isset($filterRequest['searchtags']) ? escape($filterRequest['searchtags']) : '';
$searchterm = isset($filterRequest['searchterm']) ? escape($filterRequest['searchterm']) : '';
@ -492,8 +498,7 @@ You use the community supported version of the original Shaarli project, by Seba
$delete = empty($to);
// True for case-sensitive tag search.
$linksToAlter = $this->filterSearch(['searchtags' => $from], true);
foreach($linksToAlter as $key => &$value)
{
foreach ($linksToAlter as $key => &$value) {
$tags = preg_split('/\s+/', trim($value['tags']));
if (($pos = array_search($from, $tags)) !== false) {
if ($delete) {
@ -536,7 +541,7 @@ You use the community supported version of the original Shaarli project, by Seba
{
$order = $order === 'ASC' ? -1 : 1;
// Reorder array by dates.
usort($this->links, function($a, $b) use ($order) {
usort($this->links, function ($a, $b) use ($order) {
if (isset($a['sticky']) && isset($b['sticky']) && $a['sticky'] !== $b['sticky']) {
return $a['sticky'] ? -1 : 1;
}

View file

@ -62,7 +62,7 @@ class LinkFilter
$visibility = 'all';
}
switch($type) {
switch ($type) {
case self::$FILTER_HASH:
return $this->filterSmallHash($request);
case self::$FILTER_TAG | self::$FILTER_TEXT: // == "vuotext"
@ -205,7 +205,6 @@ class LinkFilter
// Iterate over every stored link.
foreach ($this->links as $id => $link) {
// ignore non private links when 'privatonly' is on.
if ($visibility !== 'all') {
if (! $link['private'] && $visibility === 'private') {
@ -257,11 +256,11 @@ class LinkFilter
private static function tag2regex($tag)
{
$len = strlen($tag);
if(!$len || $tag === "-" || $tag === "*"){
if (!$len || $tag === "-" || $tag === "*") {
// nothing to search, return empty regex
return '';
}
if($tag[0] === "-") {
if ($tag[0] === "-") {
// query is negated
$i = 1; // use offset to start after '-' character
$regex = '(?!'; // create negative lookahead
@ -271,14 +270,14 @@ class LinkFilter
}
$regex .= '.*(?:^| )'; // before tag may only be a space or the beginning
// iterate over string, separating it into placeholder and content
for(; $i < $len; $i++){
if($tag[$i] === '*'){
for (; $i < $len; $i++) {
if ($tag[$i] === '*') {
// placeholder found
$regex .= '[^ ]*?';
} else {
// regular characters
$offset = strpos($tag, '*', $i);
if($offset === false){
if ($offset === false) {
// no placeholder found, set offset to end of string
$offset = $len;
}
@ -310,19 +309,19 @@ class LinkFilter
{
// get single tags (we may get passed an array, even though the docs say different)
$inputTags = $tags;
if(!is_array($tags)) {
if (!is_array($tags)) {
// we got an input string, split tags
$inputTags = preg_split('/(?:\s+)|,/', $inputTags, -1, PREG_SPLIT_NO_EMPTY);
}
if(!count($inputTags)){
if (!count($inputTags)) {
// no input tags
return $this->noFilter($visibility);
}
// build regex from all tags
$re = '/^' . implode(array_map("self::tag2regex", $inputTags)) . '.*$/';
if(!$casesensitive) {
if (!$casesensitive) {
// make regex case insensitive
$re .= 'i';
}
@ -342,7 +341,7 @@ class LinkFilter
}
}
$search = $link['tags']; // build search string, start with tags of current link
if(strlen(trim($link['description'])) && strpos($link['description'], '#') !== false){
if (strlen(trim($link['description'])) && strpos($link['description'], '#') !== false) {
// description given and at least one possible tag found
$descTags = array();
// find all tags in the form of #tag in the description
@ -351,13 +350,13 @@ class LinkFilter
$link['description'],
$descTags
);
if(count($descTags[1])){
if (count($descTags[1])) {
// there were some tags in the description, add them to the search string
$search .= ' ' . implode(' ', $descTags[1]);
}
};
// match regular expression with search string
if(!preg_match($re, $search)){
if (!preg_match($re, $search)) {
// this entry does _not_ match our regex
continue;
}

View file

@ -23,7 +23,7 @@ function get_curl_download_callback(&$charset, &$title, $curlGetInfo = 'curl_get
*
* @return int|bool length of $data or false if we need to stop the download
*/
return function(&$ch, $data) use ($curlGetInfo, &$charset, &$title, &$isRedirected) {
return function (&$ch, $data) use ($curlGetInfo, &$charset, &$title, &$isRedirected) {
$responseCode = $curlGetInfo($ch, CURLINFO_RESPONSE_CODE);
if (!empty($responseCode) && in_array($responseCode, [301, 302])) {
$isRedirected = true;
@ -201,7 +201,8 @@ function space2nbsp($text)
* @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)));
}

View file

@ -72,18 +72,20 @@ class NetscapeBookmarkUtils
private static function importStatus(
$filename,
$filesize,
$importCount=0,
$overwriteCount=0,
$skipCount=0,
$duration=0
)
{
$importCount = 0,
$overwriteCount = 0,
$skipCount = 0,
$duration = 0
) {
$status = sprintf(t('File %s (%d bytes) '), $filename, $filesize);
if ($importCount == 0 && $overwriteCount == 0 && $skipCount == 0) {
$status .= t('has an unknown file format. Nothing was imported.');
} else {
$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]
);
}

View file

@ -78,7 +78,6 @@ class PageBuilder
);
$this->tpl->assign('newVersion', escape($version));
$this->tpl->assign('versionError', '');
} catch (Exception $exc) {
logm($this->conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], $exc->getMessage());
$this->tpl->assign('newVersion', '');
@ -163,7 +162,7 @@ class PageBuilder
$this->initialize();
}
if (empty($data) || !is_array($data)){
if (empty($data) || !is_array($data)) {
return false;
}

View file

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

View file

@ -58,7 +58,10 @@ class Thumbnailer
$this->conf->set('thumbnails.enabled', false);
$this->conf->write(true);
// 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();

View file

@ -183,7 +183,7 @@ class Updater
}
}
try{
try {
$this->conf->write($this->isLoggedIn);
return true;
} catch (IOException $e) {

View file

@ -34,8 +34,8 @@ function unparse_url($parsedUrl)
*/
function cleanup_url($url)
{
$obj_url = new Url($url);
return $obj_url->cleanup();
$obj_url = new Url($url);
return $obj_url->cleanup();
}
/**
@ -47,8 +47,8 @@ function cleanup_url($url)
*/
function get_url_scheme($url)
{
$obj_url = new Url($url);
return $obj_url->getScheme();
$obj_url = new Url($url);
return $obj_url->getScheme();
}
/**
@ -217,7 +217,7 @@ class Url
}
$this->parts['query'] = implode('&', $queryParams);
}
}
/**
* Removes undesired fragments
@ -269,7 +269,8 @@ class Url
*
* @return string the URL scheme or false if none is provided.
*/
public function getScheme() {
public function getScheme()
{
if (!isset($this->parts['scheme'])) {
return false;
}
@ -281,7 +282,8 @@ class Url
*
* @return string the URL host or false if none is provided.
*/
public function getHost() {
public function getHost()
{
if (empty($this->parts['host'])) {
return false;
}
@ -293,7 +295,8 @@ class Url
*
* @return true is HTTP, false otherwise.
*/
public function isHttp() {
public function isHttp()
{
return strpos(strtolower($this->parts['scheme']), 'http') !== false;
}
}

View file

@ -97,7 +97,7 @@ function escape($input)
if (is_array($input)) {
$out = array();
foreach($input as $key => $value) {
foreach ($input as $key => $value) {
$out[$key] = escape($value);
}
return $out;
@ -355,10 +355,13 @@ function return_bytes($val)
$val = trim($val);
$last = strtolower($val[strlen($val)-1]);
$val = intval(substr($val, 0, -1));
switch($last) {
case 'g': $val *= 1024;
case 'm': $val *= 1024;
case 'k': $val *= 1024;
switch ($last) {
case 'g':
$val *= 1024;
case 'm':
$val *= 1024;
case 'k':
$val *= 1024;
}
return $val;
}
@ -452,6 +455,7 @@ function alphabetical_sort(&$data, $reverse = false, $byKeys = false)
*
* @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);
}

View file

@ -65,7 +65,7 @@ class ApiMiddleware
try {
$this->checkRequest($request);
$response = $next($request, $response);
} catch(ApiException $e) {
} catch (ApiException $e) {
$e->setResponse($response);
$e->setDebug($this->conf->get('dev.debug', false));
$response = $e->getApiResponse();
@ -98,7 +98,8 @@ class ApiMiddleware
*
* @throws ApiAuthorizationException The token couldn't be validated.
*/
protected function checkToken($request) {
protected function checkToken($request)
{
if (! $request->hasHeader('Authorization')) {
throw new ApiAuthorizationException('JWT token not provided');
}

View file

@ -41,7 +41,7 @@ abstract class ApiController
/**
* ApiController constructor.
*
*
* Note: enabling debug mode displays JSON with readable formatting.
*
* @param Container $ci Slim container.

View file

@ -35,8 +35,7 @@ class History extends ApiController
$offset = $request->getParam('offset');
if (empty($offset)) {
$offset = 0;
}
elseif (ctype_digit($offset)) {
} elseif (ctype_digit($offset)) {
$offset = (int) $offset;
} else {
throw new ApiBadParametersException('Invalid offset');

View file

@ -7,7 +7,7 @@ use Slim\Http\Response;
/**
* Class Info
*
*
* REST API Controller: /info
*
* @package Api\Controllers
@ -17,7 +17,7 @@ class Info extends ApiController
{
/**
* Service providing various information about Shaarli instance.
*
*
* @param Request $request Slim request.
* @param Response $response Slim response.
*

View file

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

View file

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

View file

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

View file

@ -104,12 +104,20 @@ class ConfigPhp implements ConfigIO
// Store all $conf['config']
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'])) {
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 (isset($formData['order_' . $key])) {
$plugins[(int) $formData['order_' . $key]] = $key;
}
else {
} else {
$newEnabledPlugins[] = $key;
}
}

View file

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

View file

@ -24,11 +24,9 @@
"gettext/gettext": "^4.4"
},
"require-dev": {
"phpmd/phpmd" : "@stable",
"phpunit/phpcov": "*",
"phpunit/phpunit": "^5.0",
"sebastian/phpcpd": "*",
"squizlabs/php_codesniffer": "2.*",
"phpunit/phpcov": "*"
"squizlabs/php_codesniffer": "2.*"
},
"autoload": {
"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",
"This file is @generated automatically"
],
"content-hash": "0dc33ee0b7d9f47868d4fa961f0d13b4",
"content-hash": "3876b34296fedb365517b785af8384de",
"packages": [
{
"name": "arthurhoaro/web-thumbnailer",
@ -593,12 +593,12 @@
"source": {
"type": "git",
"url": "https://github.com/pubsubhubbub/php-publisher.git",
"reference": "e8a7cf52a2c86b0c364da56f7192ec020c83b8f7"
"reference": "047b0faf6219071527a45942d6fef4dbc6d1d884"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pubsubhubbub/php-publisher/zipball/e8a7cf52a2c86b0c364da56f7192ec020c83b8f7",
"reference": "e8a7cf52a2c86b0c364da56f7192ec020c83b8f7",
"url": "https://api.github.com/repos/pubsubhubbub/php-publisher/zipball/047b0faf6219071527a45942d6fef4dbc6d1d884",
"reference": "047b0faf6219071527a45942d6fef4dbc6d1d884",
"shasum": ""
},
"require": {
@ -627,9 +627,10 @@
"data",
"feeds",
"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",
@ -858,46 +859,6 @@
],
"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",
"version": "1.0.1",
@ -1044,72 +1005,6 @@
],
"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",
"version": "1.8.0",
@ -1988,56 +1883,6 @@
"homepage": "https://github.com/sebastianbergmann/object-enumerator/",
"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",
"version": "2.0.0",
@ -2254,70 +2099,6 @@
],
"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",
"version": "v3.4.17",
@ -2443,127 +2224,6 @@
"homepage": "https://symfony.com",
"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",
"version": "v3.4.17",
@ -2883,8 +2543,7 @@
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"pubsubhubbub/publisher": 20,
"phpmd/phpmd": 0
"pubsubhubbub/publisher": 20
},
"prefer-stable": false,
"prefer-lowest": false,

278
index.php
View file

@ -28,7 +28,7 @@ if (date_default_timezone_get() == '') {
define('WEB_PATH', substr($_SERVER['REQUEST_URI'], 0, 1+strrpos($_SERVER['REQUEST_URI'], '/', 0)));
// High execution time in case of problematic imports/exports.
ini_set('max_input_time','60');
ini_set('max_input_time', '60');
// Try to set max upload file size and read
ini_set('memory_limit', '128M');
@ -85,7 +85,7 @@ use \Shaarli\Thumbnailer;
// Ensure the PHP version is supported
try {
ApplicationUtils::checkPHPVersion('5.5', PHP_VERSION);
} catch(Exception $exc) {
} catch (Exception $exc) {
header('Content-Type: text/plain; charset=utf-8');
echo $exc->getMessage();
exit;
@ -223,7 +223,6 @@ if (isset($_POST['login'])) {
$expirationTime,
WEB_PATH
);
} else {
// Standard session expiration (=when browser closes)
$expirationTime = 0;
@ -257,7 +256,8 @@ if (isset($_POST['login'])) {
exit;
}
}
header('Location: ?'); exit;
header('Location: ?');
exit;
} else {
$loginManager->handleFailedLogin($_SERVER);
$redir = '&username='. urlencode($_POST['login']);
@ -278,7 +278,9 @@ if (isset($_POST['login'])) {
// ------------------------------------------------------------------------------------------
// Token management for XSRF protection
// 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.
@ -288,13 +290,14 @@ if (!isset($_SESSION['tokens'])) $_SESSION['tokens']=array(); // Token are atta
* @param ConfigManager $conf Configuration Manager instance
* @param LoginManager $loginManager LoginManager instance
*/
function showDailyRSS($conf, $loginManager) {
function showDailyRSS($conf, $loginManager)
{
// Cache system
$query = $_SERVER['QUERY_STRING'];
$cache = new CachedPage(
$conf->get('config.PAGE_CACHE'),
page_url($_SERVER),
startsWith($query,'do=dailyrss') && !$loginManager->isLoggedIn()
startsWith($query, 'do=dailyrss') && !$loginManager->isLoggedIn()
);
$cached = $cache->cachedVersion();
if (!empty($cached)) {
@ -395,7 +398,7 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager, $loginManager)
{
$day = date('Ymd', strtotime('-1 day')); // Yesterday, in format YYYYMMDD.
if (isset($_GET['day'])) {
$day = $_GET['day'];
$day = $_GET['day'];
}
$days = $LINKSDB->days();
@ -413,7 +416,7 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager, $loginManager)
$previousday=$days[$i - 1];
}
if ($i < count($days) - 1) {
$nextday = $days[$i + 1];
$nextday = $days[$i + 1];
}
}
try {
@ -424,8 +427,8 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager, $loginManager)
}
// We pre-format some fields for proper output.
foreach($linksToDisplay as $key => $link) {
$taglist = explode(' ',$link['tags']);
foreach ($linksToDisplay as $key => $link) {
$taglist = explode(' ', $link['tags']);
uasort($taglist, 'strcasecmp');
$linksToDisplay[$key]['taglist']=$taglist;
$linksToDisplay[$key]['formatedDescription'] = format_description(
@ -457,14 +460,14 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager, $loginManager)
*/
$columns = array(array(), array(), array()); // Entries to display, for each column.
$fill = array(0, 0, 0); // Rough estimate of columns fill.
foreach($data['linksToDisplay'] as $key => $link) {
foreach ($data['linksToDisplay'] as $key => $link) {
// Roughly estimate length of entry (by counting characters)
// Title: 30 chars = 1 line. 1 line is 30 pixels height.
// Description: 836 characters gives roughly 342 pixel height.
// This is not perfect, but it's usually OK.
$length = strlen($link['title']) + (342 * strlen($link['description'])) / 836;
if ($link['thumbnail']) {
$length += 100; // 1 thumbnails roughly takes 100 pixels height.
$length += 100; // 1 thumbnails roughly takes 100 pixels height.
}
// Then put in column which is the less filled:
$smallest = min($fill); // find smallest value in array.
@ -492,8 +495,9 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager, $loginManager)
* @param ConfigManager $conf Configuration Manager instance.
* @param PluginManager $pluginManager Plugin Manager instance.
*/
function showLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager) {
buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager, $loginManager);
function showLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager)
{
buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager);
$PAGE->renderPage('linklist');
}
@ -524,8 +528,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
$updater->getDoneUpdates()
);
}
}
catch(Exception $e) {
} catch (Exception $e) {
die($e->getMessage());
}
@ -538,8 +541,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
$query = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : '';
$targetPage = Router::findPage($query, $_GET, $loginManager->isLoggedIn());
if (
// if the user isn't logged in
if (// if the user isn't logged in
!$loginManager->isLoggedIn() &&
// and Shaarli doesn't have public content...
$conf->get('privacy.hide_public_links') &&
@ -563,9 +565,11 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
'footer',
);
foreach($common_hooks as $name) {
foreach ($common_hooks as $name) {
$plugin_data = array();
$pluginManager->executeHooks('render_' . $name, $plugin_data,
$pluginManager->executeHooks(
'render_' . $name,
$plugin_data,
array(
'target' => $targetPage,
'loggedin' => $loginManager->isLoggedIn()
@ -575,13 +579,15 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
}
// -------- Display login form.
if ($targetPage == Router::$PAGE_LOGIN)
{
if ($conf->get('security.open_shaarli')) { header('Location: ?'); exit; } // No need to login for open Shaarli
if ($targetPage == Router::$PAGE_LOGIN) {
if ($conf->get('security.open_shaarli')) {
header('Location: ?');
exit;
} // No need to login for open Shaarli
if (isset($_GET['username'])) {
$PAGE->assign('username', escape($_GET['username']));
}
$PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']):''));
$PAGE->assign('returnurl', (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']):''));
// add default state of the 'remember me' checkbox
$PAGE->assign('remember_user_default', $conf->get('privacy.remember_user_default'));
$PAGE->assign('user_can_login', $loginManager->canLogin($_SERVER));
@ -590,8 +596,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
exit;
}
// -------- 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'));
$sessionManager->logout();
setcookie(LoginManager::$STAY_SIGNED_IN_COOKIE, 'false', 0, WEB_PATH);
@ -600,8 +605,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
}
// -------- Picture wall
if ($targetPage == Router::$PAGE_PICWALL)
{
if ($targetPage == Router::$PAGE_PICWALL) {
$PAGE->assign('pagetitle', t('Picture wall') .' - '. $conf->get('general.title', 'Shaarli'));
if (! $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) === Thumbnailer::MODE_NONE) {
$PAGE->assign('linksToDisplay', []);
@ -615,8 +619,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
// Get only links which have a thumbnail.
// 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) {
$linksToDisplay[] = $link; // Add to array.
}
@ -637,8 +640,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
}
// -------- Tag cloud
if ($targetPage == Router::$PAGE_TAGCLOUD)
{
if ($targetPage == Router::$PAGE_TAGCLOUD) {
$visibility = ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : '';
$filteringTags = isset($_GET['searchtags']) ? explode(' ', $_GET['searchtags']) : [];
$tags = $LINKSDB->linksCountPerTag($filteringTags, $visibility);
@ -653,7 +655,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
alphabetical_sort($tags, false, true);
$tagList = array();
foreach($tags as $key => $value) {
foreach ($tags as $key => $value) {
if (in_array($key, $filteringTags)) {
continue;
}
@ -685,8 +687,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
}
// -------- Tag list
if ($targetPage == Router::$PAGE_TAGLIST)
{
if ($targetPage == Router::$PAGE_TAGLIST) {
$visibility = ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : '';
$filteringTags = isset($_GET['searchtags']) ? explode(' ', $_GET['searchtags']) : [];
$tags = $LINKSDB->linksCountPerTag($filteringTags, $visibility);
@ -732,7 +733,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
$cache = new CachedPage(
$conf->get('resource.page_cache'),
page_url($_SERVER),
startsWith($query,'do='. $targetPage) && !$loginManager->isLoggedIn()
startsWith($query, 'do='. $targetPage) && !$loginManager->isLoggedIn()
);
$cached = $cache->cachedVersion();
if (!empty($cached)) {
@ -770,11 +771,14 @@ 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=...)
if (isset($_GET['addtag']))
{
if (isset($_GET['addtag'])) {
// 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
parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params);
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);
// Prevent redirection loop
if (isset($params['addtag'])) {
@ -798,12 +802,14 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
// Append the tag if necessary
if (empty($params['searchtags'])) {
$params['searchtags'] = trim($_GET['addtag']);
}
elseif ($addtag) {
} elseif ($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));
exit;
}
@ -828,13 +834,15 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
$tags = explode(' ', $params['searchtags']);
// Remove value from array $tags.
$tags = array_diff($tags, array($_GET['removetag']));
$params['searchtags'] = implode(' ',$tags);
$params['searchtags'] = implode(' ', $tags);
if (empty($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));
exit;
@ -897,12 +905,10 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
}
// -------- 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:
// 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.
'Location: ?do=login&post='.urlencode($_GET['post']).
(!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:
// -------- Display the Tools menu if requested (import/export/bookmarklet...)
if ($targetPage == Router::$PAGE_TOOLS)
{
if ($targetPage == Router::$PAGE_TOOLS) {
$data = [
'pageabsaddr' => index_url($_SERVER),
'sslenabled' => is_https($_SERVER),
@ -943,30 +948,40 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
}
// -------- User wants to change his/her password.
if ($targetPage == Router::$PAGE_CHANGEPASSWORD)
{
if ($targetPage == Router::$PAGE_CHANGEPASSWORD) {
if ($conf->get('security.open_shaarli')) {
die(t('You are not supposed to change a password on an Open Shaarli.'));
}
if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword']))
{
if (!$sessionManager->checkToken($_POST['token'])) die(t('Wrong token.')); // Go away!
if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) {
if (!$sessionManager->checkToken($_POST['token'])) {
die(t('Wrong token.')); // Go away!
}
// Make sure old password is correct.
$oldhash = sha1($_POST['oldpassword'].$conf->get('credentials.login').$conf->get('credentials.salt'));
if ($oldhash!= $conf->get('credentials.hash')) {
echo '<script>alert("'. t('The old password is not correct.') .'");document.location=\'?do=changepasswd\';</script>';
$oldhash = sha1(
$_POST['oldpassword'].$conf->get('credentials.login').$conf->get('credentials.salt')
);
if ($oldhash != $conf->get('credentials.hash')) {
echo '<script>alert("'
. t('The old password is not correct.')
.'");document.location=\'?do=changepasswd\';</script>';
exit;
}
// Save new password
// Salt renders rainbow-tables attacks useless.
$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 {
$conf->write($loginManager->isLoggedIn());
}
catch(Exception $e) {
} catch (Exception $e) {
error_log(
'ERROR while writing config file after changing password.' . PHP_EOL .
$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>';
exit;
}
else // show the change password form.
{
} else {
// show the change password form.
$PAGE->assign('pagetitle', t('Change password') .' - '. $conf->get('general.title', 'Shaarli'));
$PAGE->renderPage('changepassword');
exit;
@ -988,10 +1002,8 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
}
// -------- User wants to change configuration
if ($targetPage == Router::$PAGE_CONFIGURE)
{
if (!empty($_POST['title']) )
{
if ($targetPage == Router::$PAGE_CONFIGURE) {
if (!empty($_POST['title'])) {
if (!$sessionManager->checkToken($_POST['token'])) {
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)
) {
$_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);
@ -1028,8 +1041,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
$conf->write($loginManager->isLoggedIn());
$history->updateSettings();
invalidateCaches($conf->get('resource.page_cache'));
}
catch(Exception $e) {
} catch (Exception $e) {
error_log(
'ERROR while writing config file after configuration update.' . PHP_EOL .
$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>';
exit;
}
else // Show the configuration form.
{
} else {
// Show the configuration form.
$PAGE->assign('title', $conf->get('general.title'));
$PAGE->assign('theme', $conf->get('resource.theme'));
$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
if ($targetPage == Router::$PAGE_CHANGETAG)
{
if ($targetPage == Router::$PAGE_CHANGETAG) {
if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) {
$PAGE->assign('fromtag', ! empty($_GET['fromtag']) ? escape($_GET['fromtag']) : '');
$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.
if ($targetPage == Router::$PAGE_ADDLINK)
{
if ($targetPage == Router::$PAGE_ADDLINK) {
$PAGE->assign('pagetitle', t('Shaare a new link') .' - '. $conf->get('general.title', 'Shaarli'));
$PAGE->renderPage('addlink');
exit;
}
// -------- 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!
if (! $sessionManager->checkToken($_POST['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.
if (isset($_POST['cancel_edit']))
{
if (isset($_POST['cancel_edit'])) {
$id = isset($_POST['lf_id']) ? (int) escape($_POST['lf_id']) : false;
if (! isset($LINKSDB[$id])) {
header('Location: ?');
}
// 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];
$returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' );
// 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.
if ($targetPage == Router::$PAGE_DELETELINK)
{
if ($targetPage == Router::$PAGE_DELETELINK) {
if (! $sessionManager->checkToken($_GET['token'])) {
die(t('Wrong token.'));
}
@ -1230,7 +1239,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
$ids = [$ids];
}
// assert at least one id is given
if(!count($ids)){
if (!count($ids)) {
die('no id provided');
}
foreach ($ids as $id) {
@ -1243,15 +1252,18 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
$LINKSDB->save($conf->get('resource.page_cache')); // save to disk
// 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 = '?';
if (isset($_SERVER['HTTP_REFERER'])) {
// Don't redirect to where we were previously if it was a permalink or an edit_link, because it would 404.
$location = generateLocation(
$_SERVER['HTTP_REFERER'],
$_SERVER['HTTP_HOST'],
['delete_link', 'edit_link', $link['shorturl']]
$_SERVER['HTTP_REFERER'],
$_SERVER['HTTP_HOST'],
['delete_link', 'edit_link', $link['shorturl']]
);
}
@ -1260,11 +1272,13 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
}
// -------- 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']);
$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);
$data = array(
'link' => $link,
@ -1290,8 +1304,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
$link_is_new = false;
// Check if URL is not already in database (in this case, we will edit the existing link)
$link = $LINKSDB->getLinkFromUrl($url);
if (! $link)
{
if (! $link) {
$link_is_new = true;
$linkdate = strval(date(LinkDB::LINK_DATE_FORMAT));
// 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']);
$tags = empty($_GET['tags']) ? '' : escape($_GET['tags']);
$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) {
// Short timeout to keep the application responsive
// The callback will fill $charset and $title with data from the downloaded page.
@ -1408,7 +1423,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
header('Content-Type: text/html; charset=utf-8');
header(
'Content-disposition: attachment; filename=bookmarks_'
.$selection.'_'.$now->format(LinkDB::LINK_DATE_FORMAT).'.html'
.$selection.'_'.$now->format(LinkDB::LINK_DATE_FORMAT).'.html'
);
$PAGE->assign('date', $now->format(DateTime::RFC822));
$PAGE->assign('eol', PHP_EOL);
@ -1476,14 +1491,20 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
$pluginMeta = $pluginManager->getPluginsMeta();
// 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.
$enabledPlugins = load_plugin_parameter_values($enabledPlugins, $conf->get('plugins', array()));
uasort(
$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('disabledPlugins', $disabledPlugins);
@ -1500,21 +1521,23 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
foreach ($_POST as $param => $value) {
$conf->set('plugins.'. $param, escape($value));
}
}
else {
} else {
$conf->set('general.enabled_plugins', save_plugin_config($_POST));
}
$conf->write($loginManager->isLoggedIn());
$history->updateSettings();
}
catch (Exception $e) {
} catch (Exception $e) {
error_log(
'ERROR while saving plugin configuration:.' . PHP_EOL .
$e->getMessage()
);
// 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;
}
header('Location: ?do='. Router::$PAGE_PLUGINSADMIN);
@ -1635,8 +1658,7 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager)
}
$linkDisp = array();
while ($i<$end && $i<count($keys))
{
while ($i<$end && $i<count($keys)) {
$link = $linksToDisplay[$keys[$i]];
$link['description'] = format_description(
$link['description'],
@ -1739,16 +1761,19 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager)
* @param SessionManager $sessionManager SessionManager 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.
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.
// (Because on some hosts, session.save_path may not be set correctly,
// 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.
$msg = t(
'<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>';
die;
}
if (!isset($_SESSION['session_tested']))
{ // Step 1 : Try to store data in session and reload page.
if (!isset($_SESSION['session_tested'])) {
// Step 1 : Try to store data in session and reload page.
$_SESSION['session_tested'] = 'Working'; // Try to set a variable in session.
header('Location: '.index_url($_SERVER).'?test_session'); // Redirect to check stored data.
}
if (isset($_GET['test_session']))
{ // Step 3: Sessions are OK. Remove test parameter from URL.
if (isset($_GET['test_session'])) {
// Step 3: Sessions are OK. Remove test parameter from URL.
header('Location: '.index_url($_SERVER));
}
if (!empty($_POST['setlogin']) && !empty($_POST['setpassword']))
{
if (!empty($_POST['setlogin']) && !empty($_POST['setpassword'])) {
$tz = 'UTC';
if (!empty($_POST['continent']) && !empty($_POST['city'])
&& isTimeZoneValid($_POST['continent'], $_POST['city'])
@ -1807,18 +1831,20 @@ function install($conf, $sessionManager, $loginManager) {
try {
// Everything is ok, let's create config file.
$conf->write($loginManager->isLoggedIn());
}
catch(Exception $e) {
} catch (Exception $e) {
error_log(
'ERROR while writing config file after installation.' . PHP_EOL .
'ERROR while writing config file after installation.' . PHP_EOL .
$e->getMessage()
);
);
// TODO: do not handle exceptions/errors in JS.
echo '<script>alert("'. $e->getMessage() .'");document.location=\'?\';</script>';
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;
}
@ -1842,7 +1868,7 @@ if (!isset($_SESSION['LINKS_PER_PAGE'])) {
try {
$history = new History($conf->get('resource.history'));
} catch(Exception $e) {
} catch (Exception $e) {
die($e->getMessage());
}
@ -1861,7 +1887,7 @@ $container['history'] = $history;
$app = new \Slim\App($container);
// REST API routes
$app->group('/api/v1', function() {
$app->group('/api/v1', function () {
$this->get('/info', '\Shaarli\Api\Controllers\Info:getInfo')->setName('getInfo');
$this->get('/links', '\Shaarli\Api\Controllers\Links:getLinks')->setName('getLinks');
$this->get('/links/{id:[\d]+}', '\Shaarli\Api\Controllers\Links:getLink')->setName('getLink');

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

@ -17,7 +17,7 @@ function hook_archiveorg_render_linklist($data)
$archive_html = file_get_contents(PluginManager::$PLUGINS_PATH . '/archiveorg/archiveorg.html');
foreach ($data['links'] as &$value) {
if($value['private'] && preg_match('/^\?[a-zA-Z0-9-_@]{6}($|&|#)/', $value['real_url'])) {
if ($value['private'] && preg_match('/^\?[a-zA-Z0-9-_@]{6}($|&|#)/', $value['real_url'])) {
continue;
}
$archive = sprintf($archive_html, $value['url'], t('View on archive.org'));

View file

@ -73,7 +73,6 @@ function hook_demo_plugin_render_header($data)
{
// Only execute when linklist is rendered.
if ($data['_PAGE_'] == Router::$PAGE_LINKLIST) {
// If loggedin
if ($data['_LOGGEDIN_'] === true) {
/*
@ -109,10 +108,10 @@ function hook_demo_plugin_render_header($data)
* ],
* ]
* This example renders as:
* <form form-attribute-1="form attribute 1 value" form-attribute-2="form attribute 2 value">
* <input input-1-attribute-1="input 1 attribute 1 value" input-1-attribute-2="input 1 attribute 2 value">
* <input input-2-attribute-1="input 2 attribute 1 value">
* </form>
* <form form-attribute-1="form attribute 1 value" form-attribute-2="form attribute 2 value">
* <input input-1-attribute-1="input 1 attribute 1 value" input-1-attribute-2="input 1 attribute 2 value">
* <input input-2-attribute-1="input 2 attribute 1 value">
* </form>
*/
$form = array(
'attr' => array(
@ -448,8 +447,7 @@ function hook_demo_plugin_render_feed($data)
foreach ($data['links'] as &$link) {
if ($data['_PAGE_'] == Router::$PAGE_FEED_ATOM) {
$link['description'] .= ' - ATOM Feed' ;
}
elseif ($data['_PAGE_'] == Router::$PAGE_FEED_RSS) {
} elseif ($data['_PAGE_'] == Router::$PAGE_FEED_RSS) {
$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_EDITLINK
) {
$data['css_files'][] = PluginManager::$PLUGINS_PATH . '/markdown/markdown.css';
}
@ -195,8 +194,7 @@ function reverse_text2clickable($description)
// Detect and toggle block of code
if (!$codeBlockOn) {
$codeBlockOn = preg_match('/^```/', $descriptionLine) > 0;
}
elseif (preg_match('/^```/', $descriptionLine) > 0) {
} elseif (preg_match('/^```/', $descriptionLine) > 0) {
$codeBlockOn = false;
}
@ -302,13 +300,17 @@ function sanitize_html($description)
foreach ($escapeTags as $tag) {
$description = preg_replace_callback(
'#<\s*'. $tag .'[^>]*>(.*</\s*'. $tag .'[^>]*>)?#is',
function ($match) { return escape($match[0]); },
$description);
function ($match) {
return escape($match[0]);
},
$description
);
}
$description = preg_replace(
'#(<[^>]+\s)on[a-z]*="?[^ "]*"?#is',
'$1',
$description);
$description
);
return $description;
}
@ -341,7 +343,7 @@ function process_markdown($description, $escape = true, $allowedProtocols = [])
->text($processedDescription);
$processedDescription = sanitize_html($processedDescription);
if(!empty($processedDescription)){
if (!empty($processedDescription)) {
$processedDescription = '<div class="markdown">'. $processedDescription . '</div>';
}

View file

@ -6,7 +6,7 @@
* PubSub is a protocol which fasten up RSS fetching:
* - Every time a new link is posted, Shaarli notify the hub.
* - The hub notify all feed subscribers that a new link has been posted.
* - Subscribers retrieve the new link.
* - Subscribers retrieve the new link.
*/
use pubsubhubbub\publisher\Publisher;
@ -82,7 +82,8 @@ function hook_pubsubhubbub_save_link($data, $conf)
*
* @throws Exception An error occurred.
*/
function nocurl_http_post($url, $postString) {
function nocurl_http_post($url, $postString)
{
$params = array('http' => array(
'method' => 'POST',
'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');
foreach ($data['links'] as &$value) {
$qrcode = sprintf($qrcode_html,
$qrcode = sprintf(
$qrcode_html,
urlencode($value['url']),
$value['url'],
PluginManager::$PLUGINS_PATH

View file

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

View file

@ -17,7 +17,7 @@ class FakeApplicationUtils extends ApplicationUtils
/**
* Toggle HTTP requests, allow overriding the version code
*/
public static function getVersion($url, $timeout=0)
public static function getVersion($url, $timeout = 0)
{
return self::$VERSION_CODE;
}
@ -67,7 +67,7 @@ class ApplicationUtilsTest extends PHPUnit_Framework_TestCase
'0.5.4',
ApplicationUtils::getVersion(
'https://raw.githubusercontent.com/shaarli/Shaarli/'
.'v0.5.4/shaarli_version.php',
.'v0.5.4/shaarli_version.php',
$testTimeout
)
);
@ -75,7 +75,7 @@ class ApplicationUtilsTest extends PHPUnit_Framework_TestCase
self::$versionPattern,
ApplicationUtils::getVersion(
'https://raw.githubusercontent.com/shaarli/Shaarli/'
.'latest/shaarli_version.php',
.'latest/shaarli_version.php',
$testTimeout
)
);

View file

@ -84,7 +84,7 @@ class CacheTest extends PHPUnit_Framework_TestCase
invalidateCaches(self::$testCacheDir);
foreach (self::$pages as $page) {
$this->assertFileNotExists(self::$testCacheDir.'/'.$page.'.cache');
}
}
$this->assertArrayNotHasKey('tags', $_SESSION);
}

View file

@ -5,7 +5,8 @@ require_once 'application/HttpUtils.php';
/**
* Unitary tests for getIpAddressFromProxy()
*/
class GetIpAdressFromProxyTest extends PHPUnit_Framework_TestCase {
class GetIpAdressFromProxyTest extends PHPUnit_Framework_TestCase
{
/**
* Test without proxy

View file

@ -362,7 +362,7 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
public function testLinkRealUrlWithoutRedirector()
{
$db = new LinkDB(self::$testDatastore, false, false);
foreach($db as $link) {
foreach ($db as $link) {
$this->assertEquals($link['url'], $link['real_url']);
}
}
@ -374,13 +374,13 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
{
$redirector = 'http://redirector.to?';
$db = new LinkDB(self::$testDatastore, false, false, $redirector);
foreach($db as $link) {
foreach ($db as $link) {
$this->assertStringStartsWith($redirector, $link['real_url']);
$this->assertNotFalse(strpos($link['real_url'], urlencode('://')));
}
$db = new LinkDB(self::$testDatastore, false, false, $redirector, false);
foreach($db as $link) {
foreach ($db as $link) {
$this->assertStringStartsWith($redirector, $link['real_url']);
$this->assertFalse(strpos($link['real_url'], urlencode('://')));
}

View file

@ -76,7 +76,15 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
$this->assertEquals(
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(
@ -246,7 +254,7 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
2,
count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'ars.userfriendly.org'))
);
$this->assertEquals(
2,
count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'ars org'))
@ -288,16 +296,16 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
1,
count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'publishing media'))
);
$this->assertEquals(
1,
count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'mercurial w3c'))
);
$this->assertEquals(
3,
count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, '"free software"'))
);
);
}
/**

View file

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

View file

@ -218,7 +218,6 @@ class RouterTest extends PHPUnit_Framework_TestCase
Router::$PAGE_CHANGEPASSWORD,
Router::findPage('do=changepasswd&stuff', array(), true)
);
}
/**

View file

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

View file

@ -31,7 +31,7 @@ class DummyUpdater extends Updater
*
* @return bool true.
*/
private final function updateMethodDummy1()
final private function updateMethodDummy1()
{
return true;
}
@ -41,7 +41,7 @@ class DummyUpdater extends Updater
*
* @return bool true.
*/
private final function updateMethodDummy2()
final private function updateMethodDummy2()
{
return true;
}
@ -51,7 +51,7 @@ class DummyUpdater extends Updater
*
* @return bool true.
*/
private final function updateMethodDummy3()
final private function updateMethodDummy3()
{
return true;
}
@ -61,7 +61,7 @@ class DummyUpdater extends Updater
*
* @throws Exception error.
*/
private final function updateMethodException()
final private function updateMethodException()
{
throw new Exception('whatever');
}

View file

@ -393,20 +393,32 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
$this->assertEquals('Naming conventions... #private', $linkDB[0]['description']);
$this->assertEquals('samba cartoon web', $linkDB[0]['tags']);
$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->assertFalse(isset($linkDB[1]['linkdate']));
$this->assertEquals(1, $linkDB[1]['id']);
$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->assertFalse(isset($linkDB[2]['linkdate']));
$this->assertEquals(2, $linkDB[2]['id']);
$this->assertEquals('Geek and Poke', $linkDB[2]['title']);
$this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_182539'), $linkDB[2]['created']);
$this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_190301'), $linkDB[2]['updated']);
$this->assertEquals(
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 @@ class CleanupUrlTest extends PHPUnit_Framework_TestCase
);
}
}

View file

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

View file

@ -28,4 +28,3 @@ class UnparseUrlTest extends PHPUnit_Framework_TestCase
$this->assertEquals($ref, unparse_url(parse_url($ref)));
}
}

View file

@ -16,7 +16,7 @@ class UrlTest extends PHPUnit_Framework_TestCase
/**
* Helper method
*/
private function assertUrlIsCleaned($query='', $fragment='')
private function assertUrlIsCleaned($query = '', $fragment = '')
{
$url = new Url(self::$baseUrl.$query.$fragment);
$url->cleanup();
@ -135,13 +135,13 @@ class UrlTest extends PHPUnit_Framework_TestCase
'about://reader?url=' . urlencode(self::$baseUrl .'?my=stuff&is=kept')
);
$this->assertEquals(self::$baseUrl.'?my=stuff&is=kept', $url->cleanup());
}
/**
* Test default http scheme.
*/
public function testDefaultScheme() {
public function testDefaultScheme()
{
$url = new Url(self::$baseUrl);
$this->assertEquals('http', $url->getScheme());
$url = new Url('domain.tld');

View file

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

View file

@ -4,7 +4,6 @@ namespace Shaarli\Api;
use Shaarli\Base64Url;
/**
* Class ApiUtilsTest
*/
@ -34,7 +33,7 @@ class ApiUtilsTest extends \PHPUnit_Framework_TestCase
$payload = Base64Url::encode('{
"iat": '. time() .'
}');
$signature = Base64Url::encode(hash_hmac('sha512', $header .'.'. $payload , $secret, true));
$signature = Base64Url::encode(hash_hmac('sha512', $header .'.'. $payload, $secret, true));
return $header .'.'. $payload .'.'. $signature;
}

View file

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

View file

@ -10,9 +10,9 @@ use Slim\Http\Response;
/**
* Class InfoTest
*
*
* Test REST API controller Info.
*
*
* @package Api\Controllers
*/
class InfoTest extends \PHPUnit_Framework_TestCase

View file

@ -2,7 +2,6 @@
namespace Shaarli\Api\Controllers;
use PHPUnit\Framework\TestCase;
use Shaarli\Config\ConfigManager;
use Slim\Container;
@ -128,7 +127,9 @@ class PostLinkTest extends TestCase
$this->assertEquals('', $data['description']);
$this->assertEquals([], $data['tags']);
$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']);
$historyEntry = $this->history->getHistory()[0];
@ -171,7 +172,9 @@ class PostLinkTest extends TestCase
$this->assertEquals($link['description'], $data['description']);
$this->assertEquals($link['tags'], $data['tags']);
$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']);
}

View file

@ -3,7 +3,6 @@
namespace Shaarli\Api\Controllers;
use Shaarli\Config\ConfigManager;
use Slim\Container;
use Slim\Http\Environment;
@ -115,7 +114,9 @@ class PutLinkTest extends \PHPUnit_Framework_TestCase
\DateTime::createFromFormat('Ymd_His', '20150310_114651'),
\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];
$this->assertEquals(\History::UPDATED, $historyEntry['event']);
@ -160,7 +161,9 @@ class PutLinkTest extends \PHPUnit_Framework_TestCase
\DateTime::createFromFormat('Ymd_His', '20150310_114651'),
\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;
use Shaarli\Api\Exceptions\ApiBadParametersException;
use Shaarli\Config\ConfigManager;
use Slim\Container;

View file

@ -20,7 +20,7 @@ class UtilsDeTest extends UtilsTest
public function testDateFormatNoTime()
{
$date = DateTime::createFromFormat('Ymd_His', '20170101_101112');
$this->assertRegExp('/1\. Januar 2017/', format_date($date, false,true));
$this->assertRegExp('/1\. Januar 2017/', format_date($date, false, true));
}
/**

View file

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

View file

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

View file

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

View file

@ -150,8 +150,8 @@ class ReferenceLinkDB
$tags,
$updated = '',
$shorturl = '',
$pinned = false)
{
$pinned = false
) {
$link = array(
'id' => $id,
'title' => $title,
@ -201,7 +201,7 @@ class ReferenceLinkDB
$order = $order === 'ASC' ? -1 : 1;
// Reorder array by dates.
usort($this->_links, function($a, $b) use ($order) {
usort($this->_links, function ($a, $b) use ($order) {
if (isset($a['sticky']) && isset($b['sticky']) && $a['sticky'] !== $b['sticky']) {
return $a['sticky'] ? -1 : 1;
}

View file

@ -1,4 +1,4 @@
<?php
<?php
$GLOBALS['login'] = 'root';
$GLOBALS['hash'] = 'hash';
$GLOBALS['salt'] = 'salt';