# Prevent accessing subdirectories not managed by SCM
RewriteRule ^(.git|doxygen|vendor) - [F]
+# Forward the "Authorization" HTTP header
+RewriteCond %{HTTP:Authorization} ^(.*)
+RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
+
# REST API
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
## [v0.10.0](https://github.com/shaarli/Shaarli/releases/tag/v0.10.0) - UNPUBLISHED
+
+## [v0.9.6](https://github.com/shaarli/Shaarli/releases/tag/v0.9.6) - 2018-03-25
+## Changed
+- htaccess: prevent accessing resources not managed by SCM
+- htaccess: always forward the 'Authorization' HTTP header
+
+
## [v0.9.5](https://github.com/shaarli/Shaarli/releases/tag/v0.9.5) - 2018-02-02
### Fixed
- Fix a warning happening when `php-intl` is not installed on the system
# run.
EXCLUDE = vendor \
+ data \
tpl \
inc \
doc \
### generate Doxygen documentation
doxygen: clean
@rm -rf doxygen
- @( cat Doxyfile ; echo "PROJECT_NUMBER=`git describe`" ) | doxygen -
+ @doxygen Doxyfile
### generate HTML documentation from Markdown pages with MkDocs
htmldoc:
### Generate Shaarli's translation compiled file (.mo)
translate:
- @find inc/languages/ -name shaarli.po -execdir msgfmt shaarli.po -o shaarli.mo \;
\ No newline at end of file
+ @find inc/languages/ -name shaarli.po -execdir msgfmt shaarli.po -o shaarli.mo \;
[![](https://img.shields.io/badge/stable-v0.8.6-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.8.6)
[![](https://img.shields.io/travis/shaarli/Shaarli/stable.svg?label=stable)](https://travis-ci.org/shaarli/Shaarli)
•
-[![](https://img.shields.io/badge/latest-v0.9.5-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.9.5)
+[![](https://img.shields.io/badge/latest-v0.9.6-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.9.6)
[![](https://img.shields.io/travis/shaarli/Shaarli/latest.svg?label=latest)](https://travis-ci.org/shaarli/Shaarli)
•
[![](https://img.shields.io/badge/master-v0.10.x-blue.svg)](https://github.com/shaarli/Shaarli)
if (is_file($file) && !is_writeable($file)) {
// The datastore exists but is not writeable
throw new IOException($file);
- } else if (!is_file($file) && !is_writeable(dirname($file))) {
+ } elseif (!is_file($file) && !is_writeable(dirname($file))) {
// The datastore does not exist and its parent directory is not writeable
throw new IOException(dirname($file));
}
foreach ($this->links as $key => $value) {
if ($value['private'] && $visibility === 'private') {
$out[$key] = $value;
- } else if (! $value['private'] && $visibility === 'public') {
+ } elseif (! $value['private'] && $visibility === 'public') {
$out[$key] = $value;
}
}
if ($visibility !== 'all') {
if (! $link['private'] && $visibility === 'private') {
continue;
- } else if ($link['private'] && $visibility === 'public') {
+ } elseif ($link['private'] && $visibility === 'public') {
continue;
}
}
if ($visibility !== 'all') {
if (! $link['private'] && $visibility === 'private') {
continue;
- } else if ($link['private'] && $visibility === 'public') {
+ } elseif ($link['private'] && $visibility === 'public') {
continue;
}
}
if ($visibility !== 'all') {
if (! $link['private'] && $visibility === 'private') {
continue;
- } else if ($link['private'] && $visibility === 'public') {
+ } elseif ($link['private'] && $visibility === 'public') {
continue;
}
}
if (empty($post['privacy']) || $post['privacy'] == 'default') {
// use value from the imported file
$private = $bkm['pub'] == '1' ? 0 : 1;
- } else if ($post['privacy'] == 'private') {
+ } elseif ($post['privacy'] == 'private') {
// all imported links are private
$private = 1;
- } else if ($post['privacy'] == 'public') {
+ } elseif ($post['privacy'] == 'public') {
// all imported links are public
$private = 0;
}
}
return true;
}
+
+ /**
+ * Add download size and timeout to the configuration file
+ *
+ * @return bool true if the update is successful, false otherwise.
+ */
+ public function updateMethodDownloadSizeAndTimeoutConf()
+ {
+ if ($this->conf->exists('general.download_max_size')
+ && $this->conf->exists('general.download_timeout')
+ ) {
+ return true;
+ }
+
+ if (! $this->conf->exists('general.download_max_size')) {
+ $this->conf->set('general.download_max_size', 1024*1024*4);
+ }
+
+ if (! $this->conf->exists('general.download_timeout')) {
+ $this->conf->set('general.download_timeout', 30);
+ }
+
+ $this->conf->write($this->isLoggedIn);
+
+ return true;
+ }
}
/**
// Protocol not allowed: we remove it and replace it with http
if ($protocol === 1 && ! in_array($match[1], $protocols)) {
$url = str_replace($match[0], 'http://', $url);
- } else if ($protocol !== 1) {
+ } elseif ($protocol !== 1) {
$url = 'http://' . $url;
}
return $url;
if (empty($offset)) {
$offset = 0;
}
- else if (ctype_digit($offset)) {
+ elseif (ctype_digit($offset)) {
$offset = (int) $offset;
} else {
throw new ApiBadParametersException('Invalid offset');
$limit = $request->getParam('limit');
if (empty($limit)) {
$limit = count($history);
- } else if (ctype_digit($limit)) {
+ } elseif (ctype_digit($limit)) {
$limit = (int) $limit;
} else {
throw new ApiBadParametersException('Invalid limit');
$limit = $request->getParam('limit');
if (empty($limit)) {
$limit = self::$DEFAULT_LIMIT;
- } else if (ctype_digit($limit)) {
+ } elseif (ctype_digit($limit)) {
$limit = intval($limit);
- } else if ($limit === 'all') {
+ } elseif ($limit === 'all') {
$limit = count($links);
} else {
throw new ApiBadParametersException('Invalid limit');
In most cases, you should download the latest Shaarli release from the [releases](https://github.com/shaarli/Shaarli/releases) page. **Download our *shaarli-full* archive** to include dependencies.
-The current latest released version is `v0.9.3`
+The current latest released version is `v0.9.6`
```bash
-$ wget https://github.com/shaarli/Shaarli/releases/download/v0.9.3/shaarli-v0.9.3-full.zip
-$ unzip shaarli-v0.9.3-full.zip
+$ wget https://github.com/shaarli/Shaarli/releases/download/v0.9.6/shaarli-v0.9.6-full.zip
+$ unzip shaarli-v0.9.6-full.zip
$ mv Shaarli /path/to/shaarli/
```
### Note your current version
If anything goes wrong, it's important for us to know which version you're upgrading from.
-The current version is present in the `version.php` file.
+The current version is present in the `shaarli_version.php` file.
### Backup your data
&& cd shaarli \
&& composer --prefer-dist --no-dev install \
&& rm -rf ~/.composer \
- && chown -R nginx:nginx .
+ && chown -R nginx:nginx . \
+ && ln -sf /dev/stdout /var/log/nginx/shaarli.access.log \
+ && ln -sf /dev/stderr /var/log/nginx/shaarli.error.log
VOLUME /var/www/shaarli/data
&& cd shaarli \
&& composer --prefer-dist --no-dev install \
&& rm -rf ~/.composer \
- && chown -R nginx:nginx .
+ && chown -R nginx:nginx . \
+ && ln -sf /dev/stdout /var/log/nginx/shaarli.access.log \
+ && ln -sf /dev/stderr /var/log/nginx/shaarli.error.log
VOLUME /var/www/shaarli/data
WORKDIR /var/www
COPY --from=composer /app/shaarli shaarli
+RUN chown -R nginx:nginx . \
+ && ln -sf /dev/stdout /var/log/nginx/shaarli.access.log \
+ && ln -sf /dev/stderr /var/log/nginx/shaarli.error.log
+
VOLUME /var/www/shaarli/data
+
EXPOSE 80
ENTRYPOINT ["/bin/s6-svscan", "/etc/services.d"]
WORKDIR /var/www
COPY --from=composer /app/shaarli shaarli
-RUN chown -R nginx:nginx .
+RUN chown -R nginx:nginx . \
+ && ln -sf /dev/stdout /var/log/nginx/shaarli.access.log \
+ && ln -sf /dev/stderr /var/log/nginx/shaarli.error.log
+
VOLUME /var/www/shaarli/data
EXPOSE 80
if (empty($params['searchtags'])) {
$params['searchtags'] = trim($_GET['addtag']);
}
- else if ($addtag) {
+ elseif ($addtag) {
$params['searchtags'] = trim($params['searchtags']).' '.trim($_GET['addtag']);
}
} else {
unset($_SESSION['visibility']);
}
- } else if ($_GET['visibility'] === 'public') {
+ } elseif ($_GET['visibility'] === 'public') {
if (empty($_SESSION['visibility']) || $_SESSION['visibility'] !== 'public') {
// See only public links
$_SESSION['visibility'] = 'public';
$conf->set('general.title', escape($_POST['title']));
$conf->set('general.header_link', escape($_POST['titleLink']));
$conf->set('resource.theme', escape($_POST['theme']));
- $conf->set('redirector.url', escape($_POST['redirector']));
$conf->set('security.session_protection_disabled', !empty($_POST['disablesessionprotection']));
$conf->set('privacy.default_private_links', !empty($_POST['privateLinkByDefault']));
$conf->set('feed.rss_permalinks', !empty($_POST['enableRssPermalinks']));
$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')));
- $PAGE->assign('redirector', $conf->get('redirector.url'));
list($continents, $cities) = generateTimeZoneData(
timezone_identifiers_list(),
$conf->get('general.timezone')
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.
- get_http_response($url, 25, 4194304, get_curl_download_callback($charset, $title));
+ get_http_response(
+ $url,
+ $conf->get('general.download_max_size', 4194304),
+ $conf->get('general.download_timeout', 30),
+ get_curl_download_callback($charset, $title)
+ );
if (! empty($title) && strtolower($charset) != 'utf-8') {
$title = mb_convert_encoding($title, 'utf-8', $charset);
}
$description);
}
$description = preg_replace(
- '#(<[^>]+)on[a-z]*="?[^ "]*"?#is',
+ '#(<[^>]+\s)on[a-z]*="?[^ "]*"?#is',
'$1',
$description);
return $description;
$this->assertTrue($updater->updateMethodAtomDefault());
$this->assertTrue($this->conf->get('feed.show_atom'));
}
+
+ /**
+ * Test updateMethodDownloadSizeAndTimeoutConf, it should be set if none is already defined.
+ */
+ public function testUpdateMethodDownloadSizeAndTimeoutConf()
+ {
+ $sandboxConf = 'sandbox/config';
+ copy(self::$configFile . '.json.php', $sandboxConf . '.json.php');
+ $this->conf = new ConfigManager($sandboxConf);
+ $updater = new Updater([], [], $this->conf, true);
+ $this->assertTrue($updater->updateMethodDownloadSizeAndTimeoutConf());
+ $this->assertEquals(4194304, $this->conf->get('general.download_max_size'));
+ $this->assertEquals(30, $this->conf->get('general.download_timeout'));
+
+ $this->conf = new ConfigManager($sandboxConf);
+ $this->assertEquals(4194304, $this->conf->get('general.download_max_size'));
+ $this->assertEquals(30, $this->conf->get('general.download_timeout'));
+ }
+
+ /**
+ * Test updateMethodDownloadSizeAndTimeoutConf, it shouldn't be set if it is already defined.
+ */
+ public function testUpdateMethodDownloadSizeAndTimeoutConfIgnore()
+ {
+ $sandboxConf = 'sandbox/config';
+ copy(self::$configFile . '.json.php', $sandboxConf . '.json.php');
+ $this->conf = new ConfigManager($sandboxConf);
+ $this->conf->set('general.download_max_size', 38);
+ $this->conf->set('general.download_timeout', 70);
+ $updater = new Updater([], [], $this->conf, true);
+ $this->assertTrue($updater->updateMethodDownloadSizeAndTimeoutConf());
+ $this->assertEquals(38, $this->conf->get('general.download_max_size'));
+ $this->assertEquals(70, $this->conf->get('general.download_timeout'));
+ }
+
+ /**
+ * Test updateMethodDownloadSizeAndTimeoutConf, only the maz size should be set here.
+ */
+ public function testUpdateMethodDownloadSizeAndTimeoutConfOnlySize()
+ {
+ $sandboxConf = 'sandbox/config';
+ copy(self::$configFile . '.json.php', $sandboxConf . '.json.php');
+ $this->conf = new ConfigManager($sandboxConf);
+ $this->conf->set('general.download_max_size', 38);
+ $updater = new Updater([], [], $this->conf, true);
+ $this->assertTrue($updater->updateMethodDownloadSizeAndTimeoutConf());
+ $this->assertEquals(38, $this->conf->get('general.download_max_size'));
+ $this->assertEquals(30, $this->conf->get('general.download_timeout'));
+ }
+
+ /**
+ * Test updateMethodDownloadSizeAndTimeoutConf, only the time out should be set here.
+ */
+ public function testUpdateMethodDownloadSizeAndTimeoutConfOnlyTimeout()
+ {
+ $sandboxConf = 'sandbox/config';
+ copy(self::$configFile . '.json.php', $sandboxConf . '.json.php');
+ $this->conf = new ConfigManager($sandboxConf);
+ $this->conf->set('general.download_timeout', 3);
+ $updater = new Updater([], [], $this->conf, true);
+ $this->assertTrue($updater->updateMethodDownloadSizeAndTimeoutConf());
+ $this->assertEquals(4194304, $this->conf->get('general.download_max_size'));
+ $this->assertEquals(3, $this->conf->get('general.download_timeout'));
+ }
}
{
if (isset($data['_PAGE_']) && $data['_PAGE_'] == 'test') {
$data[1] = 'page test';
- } else if (isset($data['_LOGGEDIN_']) && $data['_LOGGEDIN_'] === true) {
+ } elseif (isset($data['_LOGGEDIN_']) && $data['_LOGGEDIN_'] === true) {
$data[1] = 'loggedin';
} else {
$data[1] = $data[0];
{include="page.header"}
<div id="headerform">
- {if="!ban_canLogin($conf)"}
+ {if="!$user_can_login"}
You have been banned from login after too many failed attempts. Try later.
{else}
<form method="post" name="loginform">