aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.htaccess18
-rw-r--r--application/feed/FeedBuilder.php6
-rw-r--r--application/front/controller/visitor/DailyController.php2
-rw-r--r--application/http/HttpUtils.php8
-rw-r--r--doc/md/Shaarli-configuration.md71
-rw-r--r--index.php3
-rw-r--r--tests/feed/FeedBuilderTest.php13
-rw-r--r--tests/front/controller/admin/ExportControllerTest.php2
-rw-r--r--tests/front/controller/admin/ToolsControllerTest.php6
-rw-r--r--tests/front/controller/visitor/DailyControllerTest.php12
-rw-r--r--tests/front/controller/visitor/FrontControllerMockHelper.php3
-rw-r--r--tests/front/controller/visitor/InstallControllerTest.php35
-rw-r--r--tests/front/controller/visitor/OpenSearchControllerTest.php2
-rw-r--r--tests/http/HttpUtils/IndexUrlTest.php36
-rw-r--r--tests/http/HttpUtils/IndexUrlTestWithConstant.php51
15 files changed, 190 insertions, 78 deletions
diff --git a/.htaccess b/.htaccess
index 8876e346..af2dc5a7 100644
--- a/.htaccess
+++ b/.htaccess
@@ -16,23 +16,7 @@ RewriteCond %{REQUEST_FILENAME} !-f
16RewriteCond %{REQUEST_FILENAME} !-d 16RewriteCond %{REQUEST_FILENAME} !-d
17RewriteRule ^ index.php [QSA,L] 17RewriteRule ^ index.php [QSA,L]
18 18
19<Limit GET POST PUT DELETE OPTIONS> 19<LimitExcept GET POST PUT DELETE PATCH OPTIONS>
20 <IfModule version_module>
21 <IfVersion >= 2.4>
22 Require all granted
23 </IfVersion>
24 <IfVersion < 2.4>
25 Allow from all
26 Deny from none
27 </IfVersion>
28 </IfModule>
29
30 <IfModule !version_module>
31 Require all granted
32 </IfModule>
33</Limit>
34
35<LimitExcept GET POST PUT DELETE OPTIONS>
36 <IfModule version_module> 20 <IfModule version_module>
37 <IfVersion >= 2.4> 21 <IfVersion >= 2.4>
38 Require all denied 22 Require all denied
diff --git a/application/feed/FeedBuilder.php b/application/feed/FeedBuilder.php
index 3653c32f..f6def630 100644
--- a/application/feed/FeedBuilder.php
+++ b/application/feed/FeedBuilder.php
@@ -122,9 +122,9 @@ class FeedBuilder
122 $data['language'] = $this->getTypeLanguage($feedType); 122 $data['language'] = $this->getTypeLanguage($feedType);
123 $data['last_update'] = $this->getLatestDateFormatted($feedType); 123 $data['last_update'] = $this->getLatestDateFormatted($feedType);
124 $data['show_dates'] = !$this->hideDates || $this->isLoggedIn; 124 $data['show_dates'] = !$this->hideDates || $this->isLoggedIn;
125 // Remove leading slash from REQUEST_URI. 125 // Remove leading path from REQUEST_URI (already contained in $pageaddr).
126 $data['self_link'] = escape(server_url($this->serverInfo)) 126 $requestUri = preg_replace('#(.*?/)(feed.*)#', '$2', escape($this->serverInfo['REQUEST_URI']));
127 . escape($this->serverInfo['REQUEST_URI']); 127 $data['self_link'] = $pageaddr . $requestUri;
128 $data['index_url'] = $pageaddr; 128 $data['index_url'] = $pageaddr;
129 $data['usepermalinks'] = $this->usePermalinks === true; 129 $data['usepermalinks'] = $this->usePermalinks === true;
130 $data['links'] = $linkDisplayed; 130 $data['links'] = $linkDisplayed;
diff --git a/application/front/controller/visitor/DailyController.php b/application/front/controller/visitor/DailyController.php
index 54a4778f..07617cf1 100644
--- a/application/front/controller/visitor/DailyController.php
+++ b/application/front/controller/visitor/DailyController.php
@@ -132,7 +132,7 @@ class DailyController extends ShaarliVisitorController
132 'date' => $dayDatetime, 132 'date' => $dayDatetime,
133 'date_rss' => $dayDatetime->format(DateTime::RSS), 133 'date_rss' => $dayDatetime->format(DateTime::RSS),
134 'date_human' => format_date($dayDatetime, false, true), 134 'date_human' => format_date($dayDatetime, false, true),
135 'absolute_url' => $indexUrl . '/daily?day=' . $day, 135 'absolute_url' => $indexUrl . 'daily?day=' . $day,
136 'links' => [], 136 'links' => [],
137 ]; 137 ];
138 138
diff --git a/application/http/HttpUtils.php b/application/http/HttpUtils.php
index 4fc4e3dc..9f414073 100644
--- a/application/http/HttpUtils.php
+++ b/application/http/HttpUtils.php
@@ -369,7 +369,11 @@ function server_url($server)
369 */ 369 */
370function index_url($server) 370function index_url($server)
371{ 371{
372 $scriptname = $server['SCRIPT_NAME'] ?? ''; 372 if (defined('SHAARLI_ROOT_URL') && null !== SHAARLI_ROOT_URL) {
373 return rtrim(SHAARLI_ROOT_URL, '/') . '/';
374 }
375
376 $scriptname = !empty($server['SCRIPT_NAME']) ? $server['SCRIPT_NAME'] : '/';
373 if (endsWith($scriptname, 'index.php')) { 377 if (endsWith($scriptname, 'index.php')) {
374 $scriptname = substr($scriptname, 0, -9); 378 $scriptname = substr($scriptname, 0, -9);
375 } 379 }
@@ -392,7 +396,7 @@ function page_url($server)
392 $scriptname = substr($scriptname, 0, -9); 396 $scriptname = substr($scriptname, 0, -9);
393 } 397 }
394 398
395 $route = ltrim($server['REQUEST_URI'] ?? '', $scriptname); 399 $route = preg_replace('@^' . $scriptname . '@', '', $server['REQUEST_URI'] ?? '');
396 if (! empty($server['QUERY_STRING'])) { 400 if (! empty($server['QUERY_STRING'])) {
397 return index_url($server) . $route . '?' . $server['QUERY_STRING']; 401 return index_url($server) . $route . '?' . $server['QUERY_STRING'];
398 } 402 }
diff --git a/doc/md/Shaarli-configuration.md b/doc/md/Shaarli-configuration.md
index 14eec7b2..263fb761 100644
--- a/doc/md/Shaarli-configuration.md
+++ b/doc/md/Shaarli-configuration.md
@@ -7,7 +7,7 @@ Once your Shaarli instance is installed, the file `data/config.json.php` is gene
7- its values override those defined in `index.php` 7- its values override those defined in `index.php`
8- it is wrapped in a PHP comment so that its contents are never served by the web server, regardless of configuration 8- it is wrapped in a PHP comment so that its contents are never served by the web server, regardless of configuration
9 9
10**Do not edit configuration options in index.php! Your changes would be lost.** 10**Do not edit configuration options in index.php! Your changes would be lost.**
11 11
12## Tools menu 12## Tools menu
13 13
@@ -135,71 +135,72 @@ Some settings can be configured directly from a web browser by accesing the `Too
135## Settings 135## Settings
136 136
137### Credentials 137### Credentials
138 138
139_These settings should not be edited_ 139_These settings should not be edited_
140 140
141- **login**: Login username. 141- **login**: Login username.
142- **hash**: Generated password hash. 142- **hash**: Generated password hash.
143- **salt**: Password salt. 143- **salt**: Password salt.
144 144
145### General 145### General
146 146
147- **title**: Shaarli's instance title. 147- **title**: Shaarli's instance title.
148- **header_link**: Link to the homepage. 148- **header_link**: Link to the homepage.
149- **links_per_page**: Number of Shaares displayed per page. 149- **links_per_page**: Number of Shaares displayed per page.
150- **timezone**: See [the list of supported timezones](http://php.net/manual/en/timezones.php). 150- **timezone**: See [the list of supported timezones](http://php.net/manual/en/timezones.php).
151- **enabled_plugins**: List of enabled plugins. 151- **enabled_plugins**: List of enabled plugins.
152- **default_note_title**: Default title of a new note. 152- **default_note_title**: Default title of a new note.
153- **retrieve_description** (boolean): If set to true, for every new Shaare Shaarli will try to retrieve the description and keywords from the HTML meta tags. 153- **retrieve_description** (boolean): If set to true, for every new Shaare Shaarli will try to retrieve the description and keywords from the HTML meta tags.
154- **root_url**: Overrides automatic discovery of Shaarli instance's URL (e.g.) `https://sub.domain.tld/shaarli-folder/`.
154 155
155### Security 156### Security
156 157
157- **session_protection_disabled**: Disable session cookie hijacking protection (not recommended). 158- **session_protection_disabled**: Disable session cookie hijacking protection (not recommended).
158 It might be useful if your IP adress often changes. 159 It might be useful if your IP adress often changes.
159- **ban_after**: Failed login attempts before being IP banned. 160- **ban_after**: Failed login attempts before being IP banned.
160- **ban_duration**: IP ban duration in seconds. 161- **ban_duration**: IP ban duration in seconds.
161- **open_shaarli**: Anyone can add a new Shaare while logged out if enabled. 162- **open_shaarli**: Anyone can add a new Shaare while logged out if enabled.
162- **trusted_proxies**: List of trusted IP which won't be banned after failed login attemps. Useful if Shaarli is behind a reverse proxy. 163- **trusted_proxies**: List of trusted IP which won't be banned after failed login attemps. Useful if Shaarli is behind a reverse proxy.
163- **allowed_protocols**: List of allowed protocols in shaare URLs or markdown-rendered descriptions. Useful if you want to store `javascript:` links (bookmarklets) in Shaarli (default: `["ftp", "ftps", "magnet"]`). 164- **allowed_protocols**: List of allowed protocols in shaare URLs or markdown-rendered descriptions. Useful if you want to store `javascript:` links (bookmarklets) in Shaarli (default: `["ftp", "ftps", "magnet"]`).
164 165
165### Resources 166### Resources
166 167
167- **data_dir**: Data directory. 168- **data_dir**: Data directory.
168- **datastore**: Shaarli's Shaares database file path. 169- **datastore**: Shaarli's Shaares database file path.
169- **history**: Shaarli's operation history file path. 170- **history**: Shaarli's operation history file path.
170- **updates**: File path for the ran updates file. 171- **updates**: File path for the ran updates file.
171- **log**: Log file path. 172- **log**: Log file path.
172- **update_check**: Last update check file path. 173- **update_check**: Last update check file path.
173- **raintpl_tpl**: Templates directory. 174- **raintpl_tpl**: Templates directory.
174- **raintpl_tmp**: Template engine cache directory. 175- **raintpl_tmp**: Template engine cache directory.
175- **thumbnails_cache**: Thumbnails cache directory. 176- **thumbnails_cache**: Thumbnails cache directory.
176- **page_cache**: Shaarli's internal cache directory. 177- **page_cache**: Shaarli's internal cache directory.
177- **ban_file**: Banned IP file path. 178- **ban_file**: Banned IP file path.
178 179
179### Translation 180### Translation
180 181
181- **language**: translation language (also see [Translations](Translations)) 182- **language**: translation language (also see [Translations](Translations))
182 - **auto** (default): The translation language is chosen from the browser locale. 183 - **auto** (default): The translation language is chosen from the browser locale.
183 It means that the language can be different for 2 different visitors depending on their locale. 184 It means that the language can be different for 2 different visitors depending on their locale.
184 - **en**: Use the English translation. 185 - **en**: Use the English translation.
185 - **fr**: Use the French translation. 186 - **fr**: Use the French translation.
186- **mode**: 187- **mode**:
187 - **auto** or **php** (default): Use the PHP implementation of gettext (slower) 188 - **auto** or **php** (default): Use the PHP implementation of gettext (slower)
188 - **gettext**: Use PHP builtin gettext extension 189 - **gettext**: Use PHP builtin gettext extension
189 (faster, but requires `php-gettext` to be installed and to reload the web server on update) 190 (faster, but requires `php-gettext` to be installed and to reload the web server on update)
190- **extension**: Translation extensions for custom themes or plugins. 191- **extension**: Translation extensions for custom themes or plugins.
191Must be an associative array: `translation domain => translation path`. 192Must be an associative array: `translation domain => translation path`.
192 193
193### Updates 194### Updates
194 195
195- **check_updates**: Enable or disable update check to the git repository. 196- **check_updates**: Enable or disable update check to the git repository.
196- **check_updates_branch**: Git branch used to check updates (e.g. `stable` or `master`). 197- **check_updates_branch**: Git branch used to check updates (e.g. `stable` or `master`).
197- **check_updates_interval**: Look for new version every N seconds (default: every day). 198- **check_updates_interval**: Look for new version every N seconds (default: every day).
198 199
199### Privacy 200### Privacy
200 201
201- **default_private_links**: Check the private checkbox by default for every new Shaare. 202- **default_private_links**: Check the private checkbox by default for every new Shaare.
202- **hide_public_links**: All Shaares are hidden while logged out. 203- **hide_public_links**: All Shaares are hidden while logged out.
203- **force_login**: if **hide_public_links** and this are set to `true`, all anonymous users are redirected to the login page. 204- **force_login**: if **hide_public_links** and this are set to `true`, all anonymous users are redirected to the login page.
204- **hide_timestamps**: Timestamps are hidden. 205- **hide_timestamps**: Timestamps are hidden.
205- **remember_user_default**: Default state of the login page's *remember me* checkbox 206- **remember_user_default**: Default state of the login page's *remember me* checkbox
@@ -207,14 +208,14 @@ Must be an associative array: `translation domain => translation path`.
207 208
208### Feed 209### Feed
209 210
210- **rss_permalinks**: Enable this to redirect RSS links to Shaarli's permalinks instead of shaared URL. 211- **rss_permalinks**: Enable this to redirect RSS links to Shaarli's permalinks instead of shaared URL.
211- **show_atom**: Display ATOM feed button. 212- **show_atom**: Display ATOM feed button.
212 213
213### Thumbnail 214### Thumbnail
214 215
215- **enable_thumbnails**: Enable or disable thumbnail display. 216- **enable_thumbnails**: Enable or disable thumbnail display.
216- **enable_localcache**: Enable or disable local cache. 217- **enable_localcache**: Enable or disable local cache.
217 218
218## Plugins configuration 219## Plugins configuration
219 220
220See [Plugins](Plugins.md) \ No newline at end of file 221See [Plugins](Plugins.md)
diff --git a/index.php b/index.php
index 869f42de..b10397dd 100644
--- a/index.php
+++ b/index.php
@@ -35,6 +35,9 @@ use Slim\App;
35 35
36$conf = new ConfigManager(); 36$conf = new ConfigManager();
37 37
38// Manually override root URL for complex server configurations
39define('SHAARLI_ROOT_URL', $conf->get('general.root_url', null));
40
38// In dev mode, throw exception on any warning 41// In dev mode, throw exception on any warning
39if ($conf->get('dev.debug', false)) { 42if ($conf->get('dev.debug', false)) {
40 // See all errors (for debugging only) 43 // See all errors (for debugging only)
diff --git a/tests/feed/FeedBuilderTest.php b/tests/feed/FeedBuilderTest.php
index fe37d5f2..5dfe73aa 100644
--- a/tests/feed/FeedBuilderTest.php
+++ b/tests/feed/FeedBuilderTest.php
@@ -3,6 +3,7 @@
3namespace Shaarli\Feed; 3namespace Shaarli\Feed;
4 4
5use DateTime; 5use DateTime;
6use PHPUnit\Framework\TestCase;
6use ReferenceLinkDB; 7use ReferenceLinkDB;
7use Shaarli\Bookmark\Bookmark; 8use Shaarli\Bookmark\Bookmark;
8use Shaarli\Bookmark\BookmarkFileService; 9use Shaarli\Bookmark\BookmarkFileService;
@@ -16,7 +17,7 @@ use Shaarli\History;
16 * 17 *
17 * Unit tests for FeedBuilder. 18 * Unit tests for FeedBuilder.
18 */ 19 */
19class FeedBuilderTest extends \PHPUnit\Framework\TestCase 20class FeedBuilderTest extends TestCase
20{ 21{
21 /** 22 /**
22 * @var string locale Basque (Spain). 23 * @var string locale Basque (Spain).
@@ -44,7 +45,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
44 /** 45 /**
45 * Called before every test method. 46 * Called before every test method.
46 */ 47 */
47 public static function setUpBeforeClass() 48 public static function setUpBeforeClass(): void
48 { 49 {
49 $conf = new ConfigManager('tests/utils/config/configJson'); 50 $conf = new ConfigManager('tests/utils/config/configJson');
50 $conf->set('resource.datastore', self::$testDatastore); 51 $conf->set('resource.datastore', self::$testDatastore);
@@ -60,7 +61,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
60 'SERVER_NAME' => 'host.tld', 61 'SERVER_NAME' => 'host.tld',
61 'SERVER_PORT' => '80', 62 'SERVER_PORT' => '80',
62 'SCRIPT_NAME' => '/index.php', 63 'SCRIPT_NAME' => '/index.php',
63 'REQUEST_URI' => '/index.php?do=feed', 64 'REQUEST_URI' => '/feed/atom',
64 ); 65 );
65 } 66 }
66 67
@@ -81,7 +82,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
81 $this->assertEquals(self::$RSS_LANGUAGE, $data['language']); 82 $this->assertEquals(self::$RSS_LANGUAGE, $data['language']);
82 $this->assertRegExp('/Wed, 03 Aug 2016 09:30:33 \+\d{4}/', $data['last_update']); 83 $this->assertRegExp('/Wed, 03 Aug 2016 09:30:33 \+\d{4}/', $data['last_update']);
83 $this->assertEquals(true, $data['show_dates']); 84 $this->assertEquals(true, $data['show_dates']);
84 $this->assertEquals('http://host.tld/index.php?do=feed', $data['self_link']); 85 $this->assertEquals('http://host.tld/feed/atom', $data['self_link']);
85 $this->assertEquals('http://host.tld/', $data['index_url']); 86 $this->assertEquals('http://host.tld/', $data['index_url']);
86 $this->assertFalse($data['usepermalinks']); 87 $this->assertFalse($data['usepermalinks']);
87 $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); 88 $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
@@ -253,7 +254,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
253 'SERVER_NAME' => 'host.tld', 254 'SERVER_NAME' => 'host.tld',
254 'SERVER_PORT' => '8080', 255 'SERVER_PORT' => '8080',
255 'SCRIPT_NAME' => '/~user/shaarli/index.php', 256 'SCRIPT_NAME' => '/~user/shaarli/index.php',
256 'REQUEST_URI' => '/~user/shaarli/index.php?do=feed', 257 'REQUEST_URI' => '/~user/shaarli/feed/atom',
257 ); 258 );
258 $feedBuilder = new FeedBuilder( 259 $feedBuilder = new FeedBuilder(
259 self::$bookmarkService, 260 self::$bookmarkService,
@@ -265,7 +266,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
265 $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null); 266 $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null);
266 267
267 $this->assertEquals( 268 $this->assertEquals(
268 'http://host.tld:8080/~user/shaarli/index.php?do=feed', 269 'http://host.tld:8080/~user/shaarli/feed/atom',
269 $data['self_link'] 270 $data['self_link']
270 ); 271 );
271 272
diff --git a/tests/front/controller/admin/ExportControllerTest.php b/tests/front/controller/admin/ExportControllerTest.php
index 50d9e378..12d26f4a 100644
--- a/tests/front/controller/admin/ExportControllerTest.php
+++ b/tests/front/controller/admin/ExportControllerTest.php
@@ -84,7 +84,7 @@ class ExportControllerTest extends TestCase
84 static::assertInstanceOf(BookmarkRawFormatter::class, $formatter); 84 static::assertInstanceOf(BookmarkRawFormatter::class, $formatter);
85 static::assertSame($parameters['selection'], $selection); 85 static::assertSame($parameters['selection'], $selection);
86 static::assertTrue($prependNoteUrl); 86 static::assertTrue($prependNoteUrl);
87 static::assertSame('http://shaarli', $indexUrl); 87 static::assertSame('http://shaarli/subfolder/', $indexUrl);
88 88
89 return $bookmarks; 89 return $bookmarks;
90 } 90 }
diff --git a/tests/front/controller/admin/ToolsControllerTest.php b/tests/front/controller/admin/ToolsControllerTest.php
index fc756f0f..39144d2f 100644
--- a/tests/front/controller/admin/ToolsControllerTest.php
+++ b/tests/front/controller/admin/ToolsControllerTest.php
@@ -8,7 +8,7 @@ use PHPUnit\Framework\TestCase;
8use Slim\Http\Request; 8use Slim\Http\Request;
9use Slim\Http\Response; 9use Slim\Http\Response;
10 10
11class ToolsControllerTestControllerTest extends TestCase 11class ToolsControllerTest extends TestCase
12{ 12{
13 use FrontAdminControllerMockHelper; 13 use FrontAdminControllerMockHelper;
14 14
@@ -41,7 +41,7 @@ class ToolsControllerTestControllerTest extends TestCase
41 41
42 static::assertSame(200, $result->getStatusCode()); 42 static::assertSame(200, $result->getStatusCode());
43 static::assertSame('tools', (string) $result->getBody()); 43 static::assertSame('tools', (string) $result->getBody());
44 static::assertSame('https://shaarli', $assignedVariables['pageabsaddr']); 44 static::assertSame('https://shaarli/', $assignedVariables['pageabsaddr']);
45 static::assertTrue($assignedVariables['sslenabled']); 45 static::assertTrue($assignedVariables['sslenabled']);
46 } 46 }
47 47
@@ -63,7 +63,7 @@ class ToolsControllerTestControllerTest extends TestCase
63 63
64 static::assertSame(200, $result->getStatusCode()); 64 static::assertSame(200, $result->getStatusCode());
65 static::assertSame('tools', (string) $result->getBody()); 65 static::assertSame('tools', (string) $result->getBody());
66 static::assertSame('http://shaarli', $assignedVariables['pageabsaddr']); 66 static::assertSame('http://shaarli/', $assignedVariables['pageabsaddr']);
67 static::assertFalse($assignedVariables['sslenabled']); 67 static::assertFalse($assignedVariables['sslenabled']);
68 } 68 }
69} 69}
diff --git a/tests/front/controller/visitor/DailyControllerTest.php b/tests/front/controller/visitor/DailyControllerTest.php
index b802c62c..cb5b96f3 100644
--- a/tests/front/controller/visitor/DailyControllerTest.php
+++ b/tests/front/controller/visitor/DailyControllerTest.php
@@ -392,8 +392,8 @@ class DailyControllerTest extends TestCase
392 static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); 392 static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
393 static::assertSame('dailyrss', (string) $result->getBody()); 393 static::assertSame('dailyrss', (string) $result->getBody());
394 static::assertSame('Shaarli', $assignedVariables['title']); 394 static::assertSame('Shaarli', $assignedVariables['title']);
395 static::assertSame('http://shaarli', $assignedVariables['index_url']); 395 static::assertSame('http://shaarli/subfolder/', $assignedVariables['index_url']);
396 static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']); 396 static::assertSame('http://shaarli/subfolder/daily-rss', $assignedVariables['page_url']);
397 static::assertFalse($assignedVariables['hide_timestamps']); 397 static::assertFalse($assignedVariables['hide_timestamps']);
398 static::assertCount(2, $assignedVariables['days']); 398 static::assertCount(2, $assignedVariables['days']);
399 399
@@ -402,7 +402,7 @@ class DailyControllerTest extends TestCase
402 static::assertEquals($dates[0], $day['date']); 402 static::assertEquals($dates[0], $day['date']);
403 static::assertSame($dates[0]->format(\DateTime::RSS), $day['date_rss']); 403 static::assertSame($dates[0]->format(\DateTime::RSS), $day['date_rss']);
404 static::assertSame(format_date($dates[0], false), $day['date_human']); 404 static::assertSame(format_date($dates[0], false), $day['date_human']);
405 static::assertSame('http://shaarli/daily?day='. $dates[0]->format('Ymd'), $day['absolute_url']); 405 static::assertSame('http://shaarli/subfolder/daily?day='. $dates[0]->format('Ymd'), $day['absolute_url']);
406 static::assertCount(1, $day['links']); 406 static::assertCount(1, $day['links']);
407 static::assertSame(1, $day['links'][0]['id']); 407 static::assertSame(1, $day['links'][0]['id']);
408 static::assertSame('http://domain.tld/1', $day['links'][0]['url']); 408 static::assertSame('http://domain.tld/1', $day['links'][0]['url']);
@@ -413,7 +413,7 @@ class DailyControllerTest extends TestCase
413 static::assertEquals($dates[1], $day['date']); 413 static::assertEquals($dates[1], $day['date']);
414 static::assertSame($dates[1]->format(\DateTime::RSS), $day['date_rss']); 414 static::assertSame($dates[1]->format(\DateTime::RSS), $day['date_rss']);
415 static::assertSame(format_date($dates[1], false), $day['date_human']); 415 static::assertSame(format_date($dates[1], false), $day['date_human']);
416 static::assertSame('http://shaarli/daily?day='. $dates[1]->format('Ymd'), $day['absolute_url']); 416 static::assertSame('http://shaarli/subfolder/daily?day='. $dates[1]->format('Ymd'), $day['absolute_url']);
417 static::assertCount(2, $day['links']); 417 static::assertCount(2, $day['links']);
418 418
419 static::assertSame(2, $day['links'][0]['id']); 419 static::assertSame(2, $day['links'][0]['id']);
@@ -468,8 +468,8 @@ class DailyControllerTest extends TestCase
468 static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); 468 static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
469 static::assertSame('dailyrss', (string) $result->getBody()); 469 static::assertSame('dailyrss', (string) $result->getBody());
470 static::assertSame('Shaarli', $assignedVariables['title']); 470 static::assertSame('Shaarli', $assignedVariables['title']);
471 static::assertSame('http://shaarli', $assignedVariables['index_url']); 471 static::assertSame('http://shaarli/subfolder/', $assignedVariables['index_url']);
472 static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']); 472 static::assertSame('http://shaarli/subfolder/daily-rss', $assignedVariables['page_url']);
473 static::assertFalse($assignedVariables['hide_timestamps']); 473 static::assertFalse($assignedVariables['hide_timestamps']);
474 static::assertCount(0, $assignedVariables['days']); 474 static::assertCount(0, $assignedVariables['days']);
475 } 475 }
diff --git a/tests/front/controller/visitor/FrontControllerMockHelper.php b/tests/front/controller/visitor/FrontControllerMockHelper.php
index 927e7f0a..6c53289b 100644
--- a/tests/front/controller/visitor/FrontControllerMockHelper.php
+++ b/tests/front/controller/visitor/FrontControllerMockHelper.php
@@ -79,8 +79,9 @@ trait FrontControllerMockHelper
79 $this->container->environment = [ 79 $this->container->environment = [
80 'SERVER_NAME' => 'shaarli', 80 'SERVER_NAME' => 'shaarli',
81 'SERVER_PORT' => '80', 81 'SERVER_PORT' => '80',
82 'REQUEST_URI' => '/daily-rss', 82 'REQUEST_URI' => '/subfolder/daily-rss',
83 'REMOTE_ADDR' => '1.2.3.4', 83 'REMOTE_ADDR' => '1.2.3.4',
84 'SCRIPT_NAME' => '/subfolder/index.php',
84 ]; 85 ];
85 86
86 $this->container->basePath = '/subfolder'; 87 $this->container->basePath = '/subfolder';
diff --git a/tests/front/controller/visitor/InstallControllerTest.php b/tests/front/controller/visitor/InstallControllerTest.php
index 3b855365..994d3f33 100644
--- a/tests/front/controller/visitor/InstallControllerTest.php
+++ b/tests/front/controller/visitor/InstallControllerTest.php
@@ -257,6 +257,39 @@ class InstallControllerTest extends TestCase
257 static::assertSame('/subfolder/login', $result->getHeader('location')[0]); 257 static::assertSame('/subfolder/login', $result->getHeader('location')[0]);
258 258
259 static::assertSame('UTC', $confSettings['general.timezone']); 259 static::assertSame('UTC', $confSettings['general.timezone']);
260 static::assertSame('Shared bookmarks on http://shaarli', $confSettings['general.title']); 260 static::assertSame('Shared bookmarks on http://shaarli/subfolder/', $confSettings['general.title']);
261 }
262
263 /**
264 * Same test as testSaveInstallDefaultValues() but for an instance install in root directory.
265 */
266 public function testSaveInstallDefaultValuesWithoutSubfolder(): void
267 {
268 $confSettings = [];
269
270 $this->container->environment = [
271 'SERVER_NAME' => 'shaarli',
272 'SERVER_PORT' => '80',
273 'REQUEST_URI' => '/install',
274 'REMOTE_ADDR' => '1.2.3.4',
275 'SCRIPT_NAME' => '/index.php',
276 ];
277
278 $this->container->basePath = '';
279
280 $request = $this->createMock(Request::class);
281 $response = new Response();
282
283 $this->container->conf->method('set')->willReturnCallback(function (string $key, $value) use (&$confSettings) {
284 $confSettings[$key] = $value;
285 });
286
287 $result = $this->controller->save($request, $response);
288
289 static::assertSame(302, $result->getStatusCode());
290 static::assertSame('/login', $result->getHeader('location')[0]);
291
292 static::assertSame('UTC', $confSettings['general.timezone']);
293 static::assertSame('Shared bookmarks on http://shaarli/', $confSettings['general.title']);
261 } 294 }
262} 295}
diff --git a/tests/front/controller/visitor/OpenSearchControllerTest.php b/tests/front/controller/visitor/OpenSearchControllerTest.php
index 5f9f5b12..9609a377 100644
--- a/tests/front/controller/visitor/OpenSearchControllerTest.php
+++ b/tests/front/controller/visitor/OpenSearchControllerTest.php
@@ -39,6 +39,6 @@ class OpenSearchControllerTest extends TestCase
39 $result->getHeader('Content-Type')[0] 39 $result->getHeader('Content-Type')[0]
40 ); 40 );
41 static::assertSame('opensearch', (string) $result->getBody()); 41 static::assertSame('opensearch', (string) $result->getBody());
42 static::assertSame('http://shaarli', $assignedVariables['serverurl']); 42 static::assertSame('http://shaarli/subfolder/', $assignedVariables['serverurl']);
43 } 43 }
44} 44}
diff --git a/tests/http/HttpUtils/IndexUrlTest.php b/tests/http/HttpUtils/IndexUrlTest.php
index 73d33cd4..cce45c51 100644
--- a/tests/http/HttpUtils/IndexUrlTest.php
+++ b/tests/http/HttpUtils/IndexUrlTest.php
@@ -5,12 +5,14 @@
5 5
6namespace Shaarli\Http; 6namespace Shaarli\Http;
7 7
8use PHPUnit\Framework\TestCase;
9
8require_once 'application/http/HttpUtils.php'; 10require_once 'application/http/HttpUtils.php';
9 11
10/** 12/**
11 * Unitary tests for index_url() 13 * Unitary tests for index_url()
12 */ 14 */
13class IndexUrlTest extends \PHPUnit\Framework\TestCase 15class IndexUrlTest extends TestCase
14{ 16{
15 /** 17 /**
16 * If on the main page, remove "index.php" from the URL resource 18 * If on the main page, remove "index.php" from the URL resource
@@ -103,4 +105,36 @@ class IndexUrlTest extends \PHPUnit\Framework\TestCase
103 ) 105 )
104 ); 106 );
105 } 107 }
108
109 /**
110 * The route is stored in REQUEST_URI and subfolder
111 */
112 public function testPageUrlWithRouteUnderSubfolder()
113 {
114 $this->assertEquals(
115 'http://host.tld/subfolder/picture-wall',
116 page_url(
117 array(
118 'HTTPS' => 'Off',
119 'SERVER_NAME' => 'host.tld',
120 'SERVER_PORT' => '80',
121 'SCRIPT_NAME' => '/subfolder/index.php',
122 'REQUEST_URI' => '/subfolder/picture-wall',
123 )
124 )
125 );
126
127 $this->assertEquals(
128 'http://host.tld/subfolder/admin/picture-wall',
129 page_url(
130 array(
131 'HTTPS' => 'Off',
132 'SERVER_NAME' => 'host.tld',
133 'SERVER_PORT' => '80',
134 'SCRIPT_NAME' => '/subfolder/admin/index.php',
135 'REQUEST_URI' => '/subfolder/admin/picture-wall',
136 )
137 )
138 );
139 }
106} 140}
diff --git a/tests/http/HttpUtils/IndexUrlTestWithConstant.php b/tests/http/HttpUtils/IndexUrlTestWithConstant.php
new file mode 100644
index 00000000..15ca3d72
--- /dev/null
+++ b/tests/http/HttpUtils/IndexUrlTestWithConstant.php
@@ -0,0 +1,51 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Http;
6
7use PHPUnit\Framework\TestCase;
8
9/**
10 * Test index_url with SHAARLI_ROOT_URL defined to override automatic retrieval.
11 * This should stay in its dedicated class to make sure to not alter other tests of the suite.
12 */
13class IndexUrlTestWithConstant extends TestCase
14{
15 public static function setUpBeforeClass(): void
16 {
17 define('SHAARLI_ROOT_URL', 'http://other-host.tld/subfolder/');
18 }
19
20 /**
21 * The route is stored in REQUEST_URI and subfolder
22 */
23 public function testIndexUrlWithConstantDefined()
24 {
25 $this->assertEquals(
26 'http://other-host.tld/subfolder/',
27 index_url(
28 array(
29 'HTTPS' => 'Off',
30 'SERVER_NAME' => 'host.tld',
31 'SERVER_PORT' => '80',
32 'SCRIPT_NAME' => '/index.php',
33 'REQUEST_URI' => '/picture-wall',
34 )
35 )
36 );
37
38 $this->assertEquals(
39 'http://other-host.tld/subfolder/',
40 index_url(
41 array(
42 'HTTPS' => 'Off',
43 'SERVER_NAME' => 'host.tld',
44 'SERVER_PORT' => '80',
45 'SCRIPT_NAME' => '/admin/index.php',
46 'REQUEST_URI' => '/admin/picture-wall',
47 )
48 )
49 );
50 }
51}