aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorVirtualTam <virtualtam@flibidi.net>2015-07-22 05:02:10 +0200
committerVirtualTam <virtualtam@flibidi.net>2015-08-04 16:02:21 +0200
commit992af0b9d77cb4fbac2c37ef8d5896042d67a2a3 (patch)
tree4726baf18e7057eac3f9b6bdb5991fe6117814fc
parent96db105e4c0833324f7168edb5673278de8ccd54 (diff)
downloadShaarli-992af0b9d77cb4fbac2c37ef8d5896042d67a2a3.tar.gz
Shaarli-992af0b9d77cb4fbac2c37ef8d5896042d67a2a3.tar.zst
Shaarli-992af0b9d77cb4fbac2c37ef8d5896042d67a2a3.zip
Doc: sync from Wiki, generate HTML
Closes #291 Fixes #227 Modifications - HTML content: match the new Wiki structure - Makefile - generate a custom HTML sidebar - include the sidebar on all pages - infer and prepend page titles - handle relative links - add title metadata, e.g. Shaarli - <Page Name> Signed-off-by: VirtualTam <virtualtam@flibidi.net>
-rw-r--r--Makefile36
-rw-r--r--doc/3rd-party-libraries.html77
-rw-r--r--doc/3rd-party-libraries.md13
-rw-r--r--doc/Backup,-restore,-import-and-export.html102
-rw-r--r--doc/Backup,-restore,-import-and-export.md35
-rw-r--r--doc/Coding-guidelines.html65
-rw-r--r--doc/Coding-guidelines.md5
-rw-r--r--doc/Community-&-Related-software.html101
-rw-r--r--doc/Community-&-Related-software.md40
-rw-r--r--doc/Copy-a-Shaarli-installation-over-SSH-SCP,-serve-it-locally-with-php-cli.html75
-rw-r--r--doc/Copy-an-existing-installation-over-SSH-and-serve-it-locally.html137
-rw-r--r--doc/Copy-an-existing-installation-over-SSH-and-serve-it-locally.md (renamed from doc/Copy-a-Shaarli-installation-over-SSH-SCP,-serve-it-locally-with-php-cli.md)13
-rw-r--r--doc/Datastore-hacks.html94
-rw-r--r--doc/Datastore-hacks.md19
-rw-r--r--doc/Development.html102
-rw-r--r--doc/Development.md35
-rw-r--r--doc/Directory-structure.html107
-rw-r--r--doc/Directory-structure.md33
-rw-r--r--doc/Download-CSS-styles-for-shaarlis-listed-in-an-opml-file.html167
-rw-r--r--doc/Download-CSS-styles-from-an-OPML-list.html229
-rw-r--r--doc/Download-CSS-styles-from-an-OPML-list.md (renamed from doc/Download-CSS-styles-for-shaarlis-listed-in-an-opml-file.md)13
-rw-r--r--doc/Example-patch---add-new-via-field-for-links.html141
-rw-r--r--doc/Example-patch---add-new-via-field-for-links.md97
-rw-r--r--doc/FAQ.html97
-rw-r--r--doc/FAQ.md44
-rw-r--r--doc/Firefox-share.html72
-rw-r--r--doc/Firefox-share.md16
-rw-r--r--doc/GnuPG-signature.html199
-rw-r--r--doc/GnuPG-signature.md141
-rw-r--r--doc/Home.html429
-rw-r--r--doc/Home.md449
-rw-r--r--doc/Plugin-System.html499
-rw-r--r--doc/Plugin-System.md590
-rw-r--r--doc/RSS-feeds.html75
-rw-r--r--doc/RSS-feeds.md15
-rw-r--r--doc/Security.html107
-rw-r--r--doc/Security.md28
-rw-r--r--doc/Server-configuration.html371
-rw-r--r--doc/Server-configuration.md321
-rw-r--r--doc/Server-requirements.html132
-rw-r--r--doc/Server-requirements.md30
-rw-r--r--doc/Shaarli-configuration.html221
-rw-r--r--doc/Shaarli-configuration.md137
-rw-r--r--doc/Sharing-button.html76
-rw-r--r--doc/Sharing-button.md19
-rw-r--r--doc/Static-analysis.html72
-rw-r--r--doc/Static-analysis.md12
-rw-r--r--doc/TODO.html64
-rw-r--r--doc/TODO.md4
-rw-r--r--doc/Theming.html138
-rw-r--r--doc/Theming.md63
-rw-r--r--doc/Troubleshooting.html122
-rw-r--r--doc/Troubleshooting.md60
-rw-r--r--doc/Unit-tests.html (renamed from doc/Running-unit-tests.html)69
-rw-r--r--doc/Unit-tests.md (renamed from doc/Running-unit-tests.md)7
-rw-r--r--doc/Usage.html85
-rw-r--r--doc/Usage.md25
-rw-r--r--doc/_Sidebar.html99
-rw-r--r--doc/_Sidebar.md29
-rw-r--r--doc/github-markdown.css10
-rw-r--r--doc/sidebar.html42
61 files changed, 5504 insertions, 1201 deletions
diff --git a/Makefile b/Makefile
index d69fac46..05578525 100644
--- a/Makefile
+++ b/Makefile
@@ -126,8 +126,38 @@ doc: clean
126 @git clone https://github.com/shaarli/Shaarli.wiki.git doc 126 @git clone https://github.com/shaarli/Shaarli.wiki.git doc
127 @rm -rf doc/.git 127 @rm -rf doc/.git
128 128
129### Generate a custom sidebar
130#
131# Sidebar content:
132# - convert GitHub-flavoured relative links to standard Markdown
133# - trim HTML, only keep the list (<ul>[...]</ul>) part
134htmlsidebar:
135 @echo '<div id="local-sidebar">' > doc/sidebar.html
136 @awk 'BEGIN { FS = "[\\[\\]]{2}" }'\
137 'm = /\[/ { t=$$2; gsub(/ /, "-", $$2); print $$1"["t"]("$$2".html)"$$3 }'\
138 '!m { print $$0 }' doc/_Sidebar.md > doc/tmp.md
139 @pandoc -f markdown -t html5 -s doc/tmp.md | awk '/(ul>|li>)/' >> doc/sidebar.html
140 @echo '</div>' >> doc/sidebar.html
141 @rm doc/tmp.md
142
129### Convert local markdown documentation to HTML 143### Convert local markdown documentation to HTML
130htmldoc: 144#
131 for file in `find doc/ -maxdepth 1 -name "*.md"`; do \ 145# For all pages:
132 pandoc -f markdown_github -t html5 -s -c "github-markdown.css" -o doc/`basename $$file .md`.html "$$file"; \ 146# - infer title from the file name
147# - convert GitHub-flavoured relative links to standard Markdown
148# - insert the sidebar menu
149htmlpages:
150 @for file in `find doc/ -maxdepth 1 -name "*.md"`; do \
151 base=`basename $$file .md`; \
152 sed -i "1i #$${base//-/ }" $$file; \
153 awk 'BEGIN { FS = "[\\[\\]]{2}" }'\
154 'm = /\[/ { t=$$2; gsub(/ /, "-", $$2); print $$1"["t"]("$$2".html)"$$3 }'\
155 '!m { print $$0 }' $$file > doc/tmp.md; \
156 mv doc/tmp.md $$file; \
157 pandoc -f markdown_github -t html5 -s \
158 -c "github-markdown.css" \
159 -T Shaarli -M pagetitle:"$${base//-/ }" -B doc/sidebar.html \
160 -o doc/$$base.html $$file; \
133 done; 161 done;
162
163htmldoc: doc htmlsidebar htmlpages
diff --git a/doc/3rd-party-libraries.html b/doc/3rd-party-libraries.html
new file mode 100644
index 00000000..a9c3a88e
--- /dev/null
+++ b/doc/3rd-party-libraries.html
@@ -0,0 +1,77 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - 3rd party libraries</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <link rel="stylesheet" href="github-markdown.css">
13</head>
14<body>
15<div id="local-sidebar">
16<ul>
17<li><a href="Home.html">Home</a></li>
18<li>Installation
19<ul>
20<li><a href="Server-requirements.html">Server requirements</a></li>
21<li><a href="Server-configuration.html">Server configuration</a></li>
22<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
23</ul></li>
24<li><a href="Usage.html">Usage</a>
25<ul>
26<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
27<li><a href="Firefox-share.html">Firefox share</a></li>
28<li><a href="RSS-feeds.html">RSS feeds</a></li>
29</ul></li>
30<li>How To
31<ul>
32<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
33<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
34<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
35</ul></li>
36<li><a href="Troubleshooting.html">Troubleshooting</a></li>
37<li><a href="Development.html">Development</a>
38<ul>
39<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
40<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
41<li><a href="Directory-structure.html">Directory structure</a></li>
42<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
43<li><a href="Plugin-System.html">Plugin System</a></li>
44<li><a href="Security.html">Security</a></li>
45<li><a href="Static-analysis.html">Static analysis</a></li>
46<li><a href="Theming.html">Theming</a></li>
47<li><a href="Unit-tests.html">Unit tests</a></li>
48</ul></li>
49<li>About
50<ul>
51<li><a href="FAQ.html">FAQ</a></li>
52<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
53<li><a href="TODO.html">TODO</a></li>
54</ul></li>
55</ul>
56</div>
57<h1 id="rd-party-libraries">3rd party libraries</h1>
58<h2 id="css">CSS</h2>
59<ul>
60<li>Yahoo UI <a href="http://yuilibrary.com/yui/docs/cssreset/">CSS Reset</a><a href=".html"></a>
61<ul>
62<li>resets default CSS properties for all HTML elements (overriding browsers' default values)</li>
63<li>ensures custom CSS stylessheets will provide the same results on all browsers</li>
64</ul></li>
65</ul>
66<h2 id="javascript">Javascript</h2>
67<ul>
68<li><a href="https://leaverou.github.io/awesomplete/">Awesomeplete</a> (<a href="https://github.com/LeaVerou/awesomplete">GitHub</a>) - autocompletion in input forms<a href=".html"></a></li>
69<li><a href="http://dinbror.dk/blazy/">bLazy</a> (<a href="https://github.com/dinbror/blazy">GitHub</a>) - lazy loading for thumbnails<a href=".html"></a></li>
70<li><a href="http://neocotic.com/qr.js/">qr.js</a> (<a href="https://github.com/neocotic/qr.js">GitHub</a>) - QR code generation<a href=".html"></a></li>
71</ul>
72<h2 id="php">PHP</h2>
73<ul>
74<li><a href="https://github.com/rainphp/raintpl">RainTPL</a> - HTML templating for PHP<a href=".html"></a></li>
75</ul>
76</body>
77</html>
diff --git a/doc/3rd-party-libraries.md b/doc/3rd-party-libraries.md
new file mode 100644
index 00000000..3101c90a
--- /dev/null
+++ b/doc/3rd-party-libraries.md
@@ -0,0 +1,13 @@
1#3rd party libraries
2## CSS
3- Yahoo UI [CSS Reset](http://yuilibrary.com/yui/docs/cssreset/)[](.html)
4 - resets default CSS properties for all HTML elements (overriding browsers' default values)
5 - ensures custom CSS stylessheets will provide the same results on all browsers
6
7## Javascript
8- [Awesomeplete](https://leaverou.github.io/awesomplete/) ([GitHub](https://github.com/LeaVerou/awesomplete)) - autocompletion in input forms[](.html)
9- [bLazy](http://dinbror.dk/blazy/) ([GitHub](https://github.com/dinbror/blazy)) - lazy loading for thumbnails[](.html)
10- [qr.js](http://neocotic.com/qr.js/) ([GitHub](https://github.com/neocotic/qr.js)) - QR code generation[](.html)
11
12## PHP
13- [RainTPL](https://github.com/rainphp/raintpl) - HTML templating for PHP[](.html)
diff --git a/doc/Backup,-restore,-import-and-export.html b/doc/Backup,-restore,-import-and-export.html
new file mode 100644
index 00000000..183a5ed4
--- /dev/null
+++ b/doc/Backup,-restore,-import-and-export.html
@@ -0,0 +1,102 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Backup, restore, import and export</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <style type="text/css">
13table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
14 margin: 0; padding: 0; vertical-align: baseline; border: none; }
15table.sourceCode { width: 100%; line-height: 100%; }
16td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
17td.sourceCode { padding-left: 5px; }
18code > span.kw { color: #007020; font-weight: bold; }
19code > span.dt { color: #902000; }
20code > span.dv { color: #40a070; }
21code > span.bn { color: #40a070; }
22code > span.fl { color: #40a070; }
23code > span.ch { color: #4070a0; }
24code > span.st { color: #4070a0; }
25code > span.co { color: #60a0b0; font-style: italic; }
26code > span.ot { color: #007020; }
27code > span.al { color: #ff0000; font-weight: bold; }
28code > span.fu { color: #06287e; }
29code > span.er { color: #ff0000; font-weight: bold; }
30 </style>
31 <link rel="stylesheet" href="github-markdown.css">
32</head>
33<body>
34<div id="local-sidebar">
35<ul>
36<li><a href="Home.html">Home</a></li>
37<li>Installation
38<ul>
39<li><a href="Server-requirements.html">Server requirements</a></li>
40<li><a href="Server-configuration.html">Server configuration</a></li>
41<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
42</ul></li>
43<li><a href="Usage.html">Usage</a>
44<ul>
45<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
46<li><a href="Firefox-share.html">Firefox share</a></li>
47<li><a href="RSS-feeds.html">RSS feeds</a></li>
48</ul></li>
49<li>How To
50<ul>
51<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
52<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
53<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
54</ul></li>
55<li><a href="Troubleshooting.html">Troubleshooting</a></li>
56<li><a href="Development.html">Development</a>
57<ul>
58<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
59<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
60<li><a href="Directory-structure.html">Directory structure</a></li>
61<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
62<li><a href="Plugin-System.html">Plugin System</a></li>
63<li><a href="Security.html">Security</a></li>
64<li><a href="Static-analysis.html">Static analysis</a></li>
65<li><a href="Theming.html">Theming</a></li>
66<li><a href="Unit-tests.html">Unit tests</a></li>
67</ul></li>
68<li>About
69<ul>
70<li><a href="FAQ.html">FAQ</a></li>
71<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
72<li><a href="TODO.html">TODO</a></li>
73</ul></li>
74</ul>
75</div>
76<h1 id="backup-restore-import-and-export">Backup, restore, import and export</h1>
77<h2 id="backup-and-restore-the-datastore-file">Backup and restore the datastore file</h2>
78<p>Backup the file <code>data/datastore.php</code> (by FTP or SSH). Restore by putting the file back in place.</p>
79<p>Example command:</p>
80<pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">rsync</span> -avzP my.server.com:/var/www/shaarli/data/datastore.php datastore-<span class="ot">$(</span><span class="kw">date</span> +%Y-%m-%d_%H%M<span class="ot">)</span>.php</code></pre>
81<h2 id="export-links-as...">Export links as...</h2>
82<p>To export links as an HTML file, under <em>Tools &gt; Export</em>, choose:</p>
83<ul>
84<li><em>Export all</em> to export both public and private links</li>
85<li><em>Export public</em> to export public links only</li>
86<li><em>Export private</em> to export private links only</li>
87</ul>
88<p>Restore by using the <code>Import</code> feature.</p>
89<ul>
90<li>This can be done using the <a href="https://github.com/nodiscc/shaarchiver">shaarchiver</a> tool.<a href=".html"></a></li>
91</ul>
92<p>Example command:</p>
93<pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">./export-bookmarks.py</span> --url=https://my.server.com/shaarli --username=myusername --password=mysupersecretpassword --download-dir=./ --type=all</code></pre>
94<h2 id="import-links-from...">Import links from...</h2>
95<h3 id="diigo">Diigo</h3>
96<p>If you export your bookmark from Diigo, make sure you use the Delicious export, not the Netscape export. (Their Netscape export is broken, and they don't seem to be interested in fixing it.)</p>
97<h3 id="mister-wong">Mister Wong</h3>
98<p>See <a href="https://github.com/sebsauvage/Shaarli/issues/146">this issue</a> for import tweaks.<a href=".html"></a></p>
99<h3 id="semanticscuttle">SemanticScuttle</h3>
100<p>To correctly import the tags from a <a href="http://semanticscuttle.sourceforge.net/">SemanticScuttle</a> HTML export, edit the HTML file before importing and replace all occurences of <code>tags=</code> (lowercase) to <code>TAGS=</code> (uppercase).<a href=".html"></a></p>
101</body>
102</html>
diff --git a/doc/Backup,-restore,-import-and-export.md b/doc/Backup,-restore,-import-and-export.md
new file mode 100644
index 00000000..cf6b9f48
--- /dev/null
+++ b/doc/Backup,-restore,-import-and-export.md
@@ -0,0 +1,35 @@
1#Backup, restore, import and export
2## Backup and restore the datastore file
3
4Backup the file `data/datastore.php` (by FTP or SSH). Restore by putting the file back in place.
5
6Example command:
7```bash
8rsync -avzP my.server.com:/var/www/shaarli/data/datastore.php datastore-$(date +%Y-%m-%d_%H%M).php
9```
10
11## Export links as...
12To export links as an HTML file, under _Tools > Export_, choose:
13- _Export all_ to export both public and private links
14- _Export public_ to export public links only
15- _Export private_ to export private links only
16
17Restore by using the `Import` feature.
18* This can be done using the [shaarchiver](https://github.com/nodiscc/shaarchiver) tool.[](.html)
19
20Example command:
21```bash
22./export-bookmarks.py --url=https://my.server.com/shaarli --username=myusername --password=mysupersecretpassword --download-dir=./ --type=all
23```
24
25## Import links from...
26### Diigo
27
28If you export your bookmark from Diigo, make sure you use the Delicious export, not the Netscape export. (Their Netscape export is broken, and they don't seem to be interested in fixing it.)
29
30### Mister Wong
31See [this issue](https://github.com/sebsauvage/Shaarli/issues/146) for import tweaks.[](.html)
32
33### SemanticScuttle
34
35To correctly import the tags from a [SemanticScuttle](http://semanticscuttle.sourceforge.net/) HTML export, edit the HTML file before importing and replace all occurences of `tags=` (lowercase) to `TAGS=` (uppercase).[](.html)
diff --git a/doc/Coding-guidelines.html b/doc/Coding-guidelines.html
new file mode 100644
index 00000000..0f071a5a
--- /dev/null
+++ b/doc/Coding-guidelines.html
@@ -0,0 +1,65 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Coding guidelines</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <link rel="stylesheet" href="github-markdown.css">
13</head>
14<body>
15<div id="local-sidebar">
16<ul>
17<li><a href="Home.html">Home</a></li>
18<li>Installation
19<ul>
20<li><a href="Server-requirements.html">Server requirements</a></li>
21<li><a href="Server-configuration.html">Server configuration</a></li>
22<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
23</ul></li>
24<li><a href="Usage.html">Usage</a>
25<ul>
26<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
27<li><a href="Firefox-share.html">Firefox share</a></li>
28<li><a href="RSS-feeds.html">RSS feeds</a></li>
29</ul></li>
30<li>How To
31<ul>
32<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
33<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
34<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
35</ul></li>
36<li><a href="Troubleshooting.html">Troubleshooting</a></li>
37<li><a href="Development.html">Development</a>
38<ul>
39<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
40<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
41<li><a href="Directory-structure.html">Directory structure</a></li>
42<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
43<li><a href="Plugin-System.html">Plugin System</a></li>
44<li><a href="Security.html">Security</a></li>
45<li><a href="Static-analysis.html">Static analysis</a></li>
46<li><a href="Theming.html">Theming</a></li>
47<li><a href="Unit-tests.html">Unit tests</a></li>
48</ul></li>
49<li>About
50<ul>
51<li><a href="FAQ.html">FAQ</a></li>
52<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
53<li><a href="TODO.html">TODO</a></li>
54</ul></li>
55</ul>
56</div>
57<h1 id="coding-guidelines">Coding guidelines</h1>
58<h2 id="wip">WIP</h2>
59<p>This topic is currently being discussed here:</p>
60<ul>
61<li><a href="https://github.com/shaarli/Shaarli/issues/95">Fix coding style (static analysis)</a> (#95)<a href=".html"></a></li>
62<li><a href="https://github.com/shaarli/Shaarli/issues/130">Continuous Integration tools &amp; features</a> (#130)<a href=".html"></a></li>
63</ul>
64</body>
65</html>
diff --git a/doc/Coding-guidelines.md b/doc/Coding-guidelines.md
new file mode 100644
index 00000000..1fb28a5b
--- /dev/null
+++ b/doc/Coding-guidelines.md
@@ -0,0 +1,5 @@
1#Coding guidelines
2## WIP
3This topic is currently being discussed here:
4- [Fix coding style (static analysis)](https://github.com/shaarli/Shaarli/issues/95) (#95)[](.html)
5- [Continuous Integration tools & features](https://github.com/shaarli/Shaarli/issues/130) (#130)[](.html)
diff --git a/doc/Community-&-Related-software.html b/doc/Community-&-Related-software.html
new file mode 100644
index 00000000..5468379c
--- /dev/null
+++ b/doc/Community-&-Related-software.html
@@ -0,0 +1,101 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Community & Related software</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <link rel="stylesheet" href="github-markdown.css">
13</head>
14<body>
15<div id="local-sidebar">
16<ul>
17<li><a href="Home.html">Home</a></li>
18<li>Installation
19<ul>
20<li><a href="Server-requirements.html">Server requirements</a></li>
21<li><a href="Server-configuration.html">Server configuration</a></li>
22<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
23</ul></li>
24<li><a href="Usage.html">Usage</a>
25<ul>
26<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
27<li><a href="Firefox-share.html">Firefox share</a></li>
28<li><a href="RSS-feeds.html">RSS feeds</a></li>
29</ul></li>
30<li>How To
31<ul>
32<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
33<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
34<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
35</ul></li>
36<li><a href="Troubleshooting.html">Troubleshooting</a></li>
37<li><a href="Development.html">Development</a>
38<ul>
39<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
40<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
41<li><a href="Directory-structure.html">Directory structure</a></li>
42<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
43<li><a href="Plugin-System.html">Plugin System</a></li>
44<li><a href="Security.html">Security</a></li>
45<li><a href="Static-analysis.html">Static analysis</a></li>
46<li><a href="Theming.html">Theming</a></li>
47<li><a href="Unit-tests.html">Unit tests</a></li>
48</ul></li>
49<li>About
50<ul>
51<li><a href="FAQ.html">FAQ</a></li>
52<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
53<li><a href="TODO.html">TODO</a></li>
54</ul></li>
55</ul>
56</div>
57<h1 id="community-related-software">Community &amp; Related software</h1>
58<p><em>Unofficial but related work on Shaarli. If you maintain one of these, please get in touch with us to help us find a way to adapt your work to our fork.</em></p>
59<p><em>TODO: contact repos owners to see if they'd like to standardize their work with the community fork.</em></p>
60<h2 id="community">Community</h2>
61<ul>
62<li><a href="http://sebsauvage.net/links/">Liens en vrac de sebsauvage</a> - the original Shaarli<a href=".html"></a></li>
63<li><a href="http://porneia.free.fr/pub/links/ou-est-shaarli.html">A large list of Shaarlis</a><a href=".html"></a></li>
64<li><a href="https://raw.githubusercontent.com/Oros42/find_shaarlis/master/annuaires.json">A list of working Shaarli aggregators</a><a href=".html"></a></li>
65<li><a href="https://github.com/Oros42/shaarlis_list">A list of some known Shaarlis</a><a href=".html"></a></li>
66<li><a href="http://sebsauvage.net/rhaa/index.php?2011/09/16/09/29/58-adieu-delicious-diigo-et-stumbleupon-salut-shaarli-">Adieu Delicious, Diigo et StumbleUpon. Salut Shaarli ! - sebsauvage.net</a> (fr) <em>16/09/2011 - the original post about Shaarli</em><a href=".html"></a></li>
67<li><a href="http://sebsauvage.net/wiki/doku.php?id=php:shaarli:ideas">Original ideas/fixme/TODO page</a><a href=".html"></a></li>
68<li><a href="http://sebsauvage.net/wiki/doku.php?id=php:shaarli:discussion">Original discussion page</a> (fr)<a href=".html"></a></li>
69<li><a href="http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history">Original revisions history</a><a href=".html"></a></li>
70<li><a href="https://www.shaarli.fr/my.php">Shaarli.fr/my</a> - Unofficial, unsupported (old fork) hosted Shaarlis provider, courtesy of <a href="https://github.com/DMeloni">DMeloni</a><a href=".html"></a></li>
71<li><a href="http://shaarferme.etudiant-libre.fr.nf/index.php">Shaarli Community</a> - Unknown Shaarli hoster (unsupported, old fork)<a href=".html"></a></li>
72</ul>
73<h3 id="themes">Themes</h3>
74<p>See <a href="Theming.html">Theming</a> for the list of community-contributed themes, and an installation guide.</p>
75<h3 id="server-apps">Server apps</h3>
76<ul>
77<li><a href="https://github.com/nodiscc/shaarchiver">shaarchiver</a> - Archive your Shaarli bookmarks and their content<a href=".html"></a></li>
78<li><a href="https://github.com/mknexen/shaarli-river">shaarli-river</a> - An aggregator for shaarlis with many features <a href=".html"></a></li>
79<li><a href="https://github.com/DMeloni/shaarlo">Shaarlo</a> - An aggregator for shaarlis with many features (a very popular running instance among french shaarliers: <a href="http://shaarli.fr/">shaarli.fr</a>)<a href=".html"></a></li>
80<li><a href="https://github.com/BoboTiG/shaarlimages">Shaarlimages</a> - An image-oriented aggregator for Shaarlis<a href=".html"></a></li>
81<li><a href="https://github.com/mknexen/shaarli-api">mknexen/shaarli-api</a> - A REST API for Shaarli<a href=".html"></a></li>
82<li><a href="https://github.com/qwertygc/shaarli-dev-code/blob/master/self-dead-link.php">Self dead link</a> - Detect dead links on shaarli. This version use the database of shaarli. An <a href="https://github.com/qwertygc/shaarli-dev-code/blob/master/dead-link.php">another version</a>, can be used for others shaarli (but use most ressources).<a href=".html"></a></li>
83</ul>
84<h3 id="android-apps">Android apps</h3>
85<ul>
86<li><a href="http://sebsauvage.net/links/?ZAyDzg">Shaarli for Android</a> - Android application that adds Shaarli as a sharing provider<a href=".html"></a></li>
87<li><a href="https://github.com/dimtion/Shaarlier">Shaarlier for Android</a> - Android application to simply add links directly into your Shaarli<a href=".html"></a></li>
88</ul>
89<h2 id="integration-with-other-platforms">Integration with other platforms</h2>
90<ul>
91<li><a href="https://github.com/jcsaaddupuy/tt-rss-shaarli">tt-rss-shaarli</a> - <a href="http://tt-rss.org/">TinyTiny RSS</a> plugin that adds support for sharing articles with Shaarli<a href=".html"></a></li>
92<li><a href="https://github.com/ahmet2mir/octopress-shaarli">octopress-shaarli</a> - Octopress plugin to retrieve Shaarli links on the sidebara<a href=".html"></a></li>
93</ul>
94<h2 id="alternatives-to-shaarli">Alternatives to Shaarli</h2>
95<ul>
96<li><a href="http://alternativeto.net/software/shaarli/">Shaarli alternatives</a> (alternativeto.net)<a href=".html"></a></li>
97<li><a href="https://github.com/bookieio/bookie">Bookie</a> - Another self-hostable, free bookmark sharing software, written in Python<a href=".html"></a></li>
98<li><a href="https://github.com/plainmade/unmark">Unmark</a> - An open source todo app for bookmarks (<a href="https://unmark.it/">Homepage</a>)<a href=".html"></a></li>
99</ul>
100</body>
101</html>
diff --git a/doc/Community-&-Related-software.md b/doc/Community-&-Related-software.md
new file mode 100644
index 00000000..9cf47935
--- /dev/null
+++ b/doc/Community-&-Related-software.md
@@ -0,0 +1,40 @@
1#Community & Related software
2*Unofficial but related work on Shaarli. If you maintain one of these, please get in touch with us to help us find a way to adapt your work to our fork.*
3
4*TODO: contact repos owners to see if they'd like to standardize their work with the community fork.*
5
6## Community
7* [Liens en vrac de sebsauvage](http://sebsauvage.net/links/) - the original Shaarli[](.html)
8* [A large list of Shaarlis](http://porneia.free.fr/pub/links/ou-est-shaarli.html)[](.html)
9* [A list of working Shaarli aggregators](https://raw.githubusercontent.com/Oros42/find_shaarlis/master/annuaires.json)[](.html)
10* [A list of some known Shaarlis](https://github.com/Oros42/shaarlis_list)[](.html)
11* [Adieu Delicious, Diigo et StumbleUpon. Salut Shaarli ! - sebsauvage.net](http://sebsauvage.net/rhaa/index.php?2011/09/16/09/29/58-adieu-delicious-diigo-et-stumbleupon-salut-shaarli-) (fr) _16/09/2011 - the original post about Shaarli_[](.html)
12* [Original ideas/fixme/TODO page](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:ideas)[](.html)
13* [Original discussion page](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:discussion) (fr)[](.html)
14* [Original revisions history](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history)[](.html)
15* [Shaarli.fr/my](https://www.shaarli.fr/my.php) - Unofficial, unsupported (old fork) hosted Shaarlis provider, courtesy of [DMeloni](https://github.com/DMeloni)[](.html)
16* [Shaarli Community](http://shaarferme.etudiant-libre.fr.nf/index.php) - Unknown Shaarli hoster (unsupported, old fork)[](.html)
17
18### Themes
19See [Theming](Theming.html) for the list of community-contributed themes, and an installation guide.
20
21### Server apps
22 * [shaarchiver](https://github.com/nodiscc/shaarchiver) - Archive your Shaarli bookmarks and their content[](.html)
23 * [shaarli-river](https://github.com/mknexen/shaarli-river) - An aggregator for shaarlis with many features [](.html)
24 * [Shaarlo](https://github.com/DMeloni/shaarlo) - An aggregator for shaarlis with many features (a very popular running instance among french shaarliers: [shaarli.fr](http://shaarli.fr/))[](.html)
25 * [Shaarlimages](https://github.com/BoboTiG/shaarlimages) - An image-oriented aggregator for Shaarlis[](.html)
26 * [mknexen/shaarli-api](https://github.com/mknexen/shaarli-api) - A REST API for Shaarli[](.html)
27 * [Self dead link](https://github.com/qwertygc/shaarli-dev-code/blob/master/self-dead-link.php) - Detect dead links on shaarli. This version use the database of shaarli. An [another version](https://github.com/qwertygc/shaarli-dev-code/blob/master/dead-link.php), can be used for others shaarli (but use most ressources).[](.html)
28
29### Android apps
30 * [Shaarli for Android](http://sebsauvage.net/links/?ZAyDzg) - Android application that adds Shaarli as a sharing provider[](.html)
31 * [Shaarlier for Android](https://github.com/dimtion/Shaarlier) - Android application to simply add links directly into your Shaarli[](.html)
32
33## Integration with other platforms
34 * [tt-rss-shaarli](https://github.com/jcsaaddupuy/tt-rss-shaarli) - [TinyTiny RSS](http://tt-rss.org/) plugin that adds support for sharing articles with Shaarli[](.html)
35 * [octopress-shaarli](https://github.com/ahmet2mir/octopress-shaarli) - Octopress plugin to retrieve Shaarli links on the sidebara[](.html)
36
37## Alternatives to Shaarli
38* [Shaarli alternatives](http://alternativeto.net/software/shaarli/) (alternativeto.net)[](.html)
39* [Bookie](https://github.com/bookieio/bookie) - Another self-hostable, free bookmark sharing software, written in Python[](.html)
40* [Unmark](https://github.com/plainmade/unmark) - An open source todo app for bookmarks ([Homepage](https://unmark.it/))[](.html)
diff --git a/doc/Copy-a-Shaarli-installation-over-SSH-SCP,-serve-it-locally-with-php-cli.html b/doc/Copy-a-Shaarli-installation-over-SSH-SCP,-serve-it-locally-with-php-cli.html
deleted file mode 100644
index 25e4bc6b..00000000
--- a/doc/Copy-a-Shaarli-installation-over-SSH-SCP,-serve-it-locally-with-php-cli.html
+++ /dev/null
@@ -1,75 +0,0 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title></title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <link rel="stylesheet" href="github-markdown.css">
13</head>
14<body>
15<p>Example bash script:</p>
16<pre><code>#!/bin/bash
17#Description: Copy a Shaarli installation over SSH/SCP, serve it locally with php-cli
18#Will create a local-shaarli/ directory when you run it, backup your Shaarli there, and serve it locally.
19#Will NOT download linked pages. It&#39;s just a directly usable backup/copy/mirror of your Shaarli
20#Requires: ssh, scp and a working SSH access to the server where your Shaarli is installed
21#Usage: ./local-shaarli.sh
22#Author: nodiscc (nodiscc@gmail.com)
23#License: MIT (http://opensource.org/licenses/MIT)
24set -o errexit
25set -o nounset
26
27##### CONFIG #################
28#The port used by php&#39;s local server
29php_local_port=7431
30
31#Name of the SSH server and path where Shaarli is installed
32#TODO: pass these as command-line arguments
33remotehost=&quot;my.ssh.server&quot;
34remote_shaarli_dir=&quot;/var/www/shaarli&quot;
35
36
37###### FUNCTIONS #############
38_main() {
39 _CBSyncShaarli
40 _CBServeShaarli
41}
42
43_CBSyncShaarli() {
44 remote_temp_dir=$(ssh $remotehost mktemp -d)
45 remote_ssh_user=$(ssh $remotehost whoami)
46 ssh -t &quot;$remotehost&quot; sudo cp -r &quot;$remote_shaarli_dir&quot; &quot;$remote_temp_dir&quot;
47 ssh -t &quot;$remotehost&quot; sudo chown -R &quot;$remote_ssh_user&quot;:&quot;$remote_ssh_user&quot; &quot;$remote_temp_dir&quot;
48 scp -rq &quot;$remotehost&quot;:&quot;$remote_temp_dir&quot; local-shaarli
49 ssh &quot;$remotehost&quot; rm -r &quot;$remote_temp_dir&quot;
50}
51
52_CBServeShaarli() {
53 #TODO: allow serving a previously downloaded Shaarli
54 #TODO: ask before overwriting local copy, if it exists
55 cd local-shaarli/
56 php -S localhost:${php_local_port}
57 echo &quot;Please go to http://localhost:${php_local_port}&quot;
58}
59
60
61##### MAIN #################
62
63_main</code></pre>
64<p>This outputs:</p>
65<pre><code>$ ./local-shaarli.sh
66PHP 5.6.0RC4 Development Server started at Mon Sep 1 21:56:19 2014
67Listening on http://localhost:7431
68Document root is /home/user/local-shaarli/shaarli
69Press Ctrl-C to quit.
70
71[Mon Sep 1 21:56:27 2014] ::1:57868 [200]: /
72[Mon Sep 1 21:56:27 2014] ::1:57869 [200]: /index.html
73[Mon Sep 1 21:56:37 2014] ::1:57881 [200]: /...</code></pre>
74</body>
75</html>
diff --git a/doc/Copy-an-existing-installation-over-SSH-and-serve-it-locally.html b/doc/Copy-an-existing-installation-over-SSH-and-serve-it-locally.html
new file mode 100644
index 00000000..9e930e52
--- /dev/null
+++ b/doc/Copy-an-existing-installation-over-SSH-and-serve-it-locally.html
@@ -0,0 +1,137 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Copy an existing installation over SSH and serve it locally</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <style type="text/css">
13table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
14 margin: 0; padding: 0; vertical-align: baseline; border: none; }
15table.sourceCode { width: 100%; line-height: 100%; }
16td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
17td.sourceCode { padding-left: 5px; }
18code > span.kw { color: #007020; font-weight: bold; }
19code > span.dt { color: #902000; }
20code > span.dv { color: #40a070; }
21code > span.bn { color: #40a070; }
22code > span.fl { color: #40a070; }
23code > span.ch { color: #4070a0; }
24code > span.st { color: #4070a0; }
25code > span.co { color: #60a0b0; font-style: italic; }
26code > span.ot { color: #007020; }
27code > span.al { color: #ff0000; font-weight: bold; }
28code > span.fu { color: #06287e; }
29code > span.er { color: #ff0000; font-weight: bold; }
30 </style>
31 <link rel="stylesheet" href="github-markdown.css">
32</head>
33<body>
34<div id="local-sidebar">
35<ul>
36<li><a href="Home.html">Home</a></li>
37<li>Installation
38<ul>
39<li><a href="Server-requirements.html">Server requirements</a></li>
40<li><a href="Server-configuration.html">Server configuration</a></li>
41<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
42</ul></li>
43<li><a href="Usage.html">Usage</a>
44<ul>
45<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
46<li><a href="Firefox-share.html">Firefox share</a></li>
47<li><a href="RSS-feeds.html">RSS feeds</a></li>
48</ul></li>
49<li>How To
50<ul>
51<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
52<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
53<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
54</ul></li>
55<li><a href="Troubleshooting.html">Troubleshooting</a></li>
56<li><a href="Development.html">Development</a>
57<ul>
58<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
59<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
60<li><a href="Directory-structure.html">Directory structure</a></li>
61<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
62<li><a href="Plugin-System.html">Plugin System</a></li>
63<li><a href="Security.html">Security</a></li>
64<li><a href="Static-analysis.html">Static analysis</a></li>
65<li><a href="Theming.html">Theming</a></li>
66<li><a href="Unit-tests.html">Unit tests</a></li>
67</ul></li>
68<li>About
69<ul>
70<li><a href="FAQ.html">FAQ</a></li>
71<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
72<li><a href="TODO.html">TODO</a></li>
73</ul></li>
74</ul>
75</div>
76<h1 id="copy-an-existing-installation-over-ssh-and-serve-it-locally">Copy an existing installation over SSH and serve it locally</h1>
77<p>Example bash script:</p>
78<pre class="sourceCode bash"><code class="sourceCode bash"><span class="co">#!/bin/bash</span>
79<span class="co">#Description: Copy a Shaarli installation over SSH/SCP, serve it locally with php-cli</span>
80<span class="co">#Will create a local-shaarli/ directory when you run it, backup your Shaarli there, and serve it locally.</span>
81<span class="co">#Will NOT download linked pages. It&#39;s just a directly usable backup/copy/mirror of your Shaarli</span>
82<span class="co">#Requires: ssh, scp and a working SSH access to the server where your Shaarli is installed</span>
83<span class="co">#Usage: ./local-shaarli.sh</span>
84<span class="co">#Author: nodiscc (nodiscc@gmail.com)</span>
85<span class="co">#License: MIT (http://opensource.org/licenses/MIT)</span>
86<span class="kw">set</span> <span class="kw">-o</span> errexit
87<span class="kw">set</span> <span class="kw">-o</span> nounset
88
89<span class="co">##### CONFIG #################</span>
90<span class="co">#The port used by php&#39;s local server</span>
91<span class="ot">php_local_port=</span>7431
92
93<span class="co">#Name of the SSH server and path where Shaarli is installed</span>
94<span class="co">#TODO: pass these as command-line arguments</span>
95<span class="ot">remotehost=</span><span class="st">&quot;my.ssh.server&quot;</span>
96<span class="ot">remote_shaarli_dir=</span><span class="st">&quot;/var/www/shaarli&quot;</span>
97
98
99<span class="co">###### FUNCTIONS #############</span>
100<span class="fu">_main()</span> <span class="kw">{</span>
101 <span class="kw">_CBSyncShaarli</span>
102 <span class="kw">_CBServeShaarli</span>
103<span class="kw">}</span>
104
105<span class="fu">_CBSyncShaarli()</span> <span class="kw">{</span>
106 <span class="ot">remote_temp_dir=$(</span><span class="kw">ssh</span> <span class="ot">$remotehost</span> mktemp -d<span class="ot">)</span>
107 <span class="ot">remote_ssh_user=$(</span><span class="kw">ssh</span> <span class="ot">$remotehost</span> whoami<span class="ot">)</span>
108 <span class="kw">ssh</span> -t <span class="st">&quot;</span><span class="ot">$remotehost</span><span class="st">&quot;</span> sudo cp -r <span class="st">&quot;</span><span class="ot">$remote_shaarli_dir</span><span class="st">&quot;</span> <span class="st">&quot;</span><span class="ot">$remote_temp_dir</span><span class="st">&quot;</span>
109 <span class="kw">ssh</span> -t <span class="st">&quot;</span><span class="ot">$remotehost</span><span class="st">&quot;</span> sudo chown -R <span class="st">&quot;</span><span class="ot">$remote_ssh_user</span><span class="st">&quot;</span>:<span class="st">&quot;</span><span class="ot">$remote_ssh_user</span><span class="st">&quot;</span> <span class="st">&quot;</span><span class="ot">$remote_temp_dir</span><span class="st">&quot;</span>
110 <span class="kw">scp</span> -rq <span class="st">&quot;</span><span class="ot">$remotehost</span><span class="st">&quot;</span>:<span class="st">&quot;</span><span class="ot">$remote_temp_dir</span><span class="st">&quot;</span> local-shaarli
111 <span class="kw">ssh</span> <span class="st">&quot;</span><span class="ot">$remotehost</span><span class="st">&quot;</span> rm -r <span class="st">&quot;</span><span class="ot">$remote_temp_dir</span><span class="st">&quot;</span>
112<span class="kw">}</span>
113
114<span class="fu">_CBServeShaarli()</span> <span class="kw">{</span>
115 <span class="co">#TODO: allow serving a previously downloaded Shaarli</span>
116 <span class="co">#TODO: ask before overwriting local copy, if it exists</span>
117 <span class="kw">cd</span> local-shaarli/
118 <span class="kw">php</span> -S localhost:<span class="ot">${php_local_port}</span>
119 <span class="kw">echo</span> <span class="st">&quot;Please go to http://localhost:</span><span class="ot">${php_local_port}</span><span class="st">&quot;</span>
120<span class="kw">}</span>
121
122
123<span class="co">##### MAIN #################</span>
124
125<span class="kw">_main</span></code></pre>
126<p>This outputs:</p>
127<pre class="sourceCode bash"><code class="sourceCode bash">$ <span class="kw">./local-shaarli.sh</span>
128<span class="kw">PHP</span> 5.6.0RC4 Development Server started at Mon Sep 1 21:56:19 2014
129<span class="kw">Listening</span> on http://localhost:7431
130<span class="kw">Document</span> root is /home/user/local-shaarli/shaarli
131<span class="kw">Press</span> Ctrl-C to quit.
132
133[<span class="kw">Mon</span> Sep 1 21:56:27 2014] ::1:57868 [200]: /[](.html)
134[<span class="kw">Mon</span> Sep 1 21:56:27 2014] ::1:57869 [200]: /index.html[](.html)
135[<span class="kw">Mon</span> Sep 1 21:56:37 2014] ::1:57881 [200]: /...[](.html)</code></pre>
136</body>
137</html>
diff --git a/doc/Copy-a-Shaarli-installation-over-SSH-SCP,-serve-it-locally-with-php-cli.md b/doc/Copy-an-existing-installation-over-SSH-and-serve-it-locally.md
index 5b0aec6f..88d191da 100644
--- a/doc/Copy-a-Shaarli-installation-over-SSH-SCP,-serve-it-locally-with-php-cli.md
+++ b/doc/Copy-an-existing-installation-over-SSH-and-serve-it-locally.md
@@ -1,6 +1,7 @@
1#Copy an existing installation over SSH and serve it locally
1Example bash script: 2Example bash script:
2 3
3``` 4```bash
4#!/bin/bash 5#!/bin/bash
5#Description: Copy a Shaarli installation over SSH/SCP, serve it locally with php-cli 6#Description: Copy a Shaarli installation over SSH/SCP, serve it locally with php-cli
6#Will create a local-shaarli/ directory when you run it, backup your Shaarli there, and serve it locally. 7#Will create a local-shaarli/ directory when you run it, backup your Shaarli there, and serve it locally.
@@ -53,14 +54,14 @@ _main
53 54
54This outputs: 55This outputs:
55 56
56``` 57```bash
57$ ./local-shaarli.sh 58$ ./local-shaarli.sh
58PHP 5.6.0RC4 Development Server started at Mon Sep 1 21:56:19 2014 59PHP 5.6.0RC4 Development Server started at Mon Sep 1 21:56:19 2014
59Listening on http://localhost:7431 60Listening on http://localhost:7431
60Document root is /home/user/local-shaarli/shaarli 61Document root is /home/user/local-shaarli/shaarli
61Press Ctrl-C to quit. 62Press Ctrl-C to quit.
62 63
63[Mon Sep 1 21:56:27 2014] ::1:57868 [200]: / 64[Mon Sep 1 21:56:27 2014] ::1:57868 [200]: /[](.html)
64[Mon Sep 1 21:56:27 2014] ::1:57869 [200]: /index.html 65[Mon Sep 1 21:56:27 2014] ::1:57869 [200]: /index.html[](.html)
65[Mon Sep 1 21:56:37 2014] ::1:57881 [200]: /... 66[Mon Sep 1 21:56:37 2014] ::1:57881 [200]: /...[](.html)
66``` \ No newline at end of file 67```
diff --git a/doc/Datastore-hacks.html b/doc/Datastore-hacks.html
new file mode 100644
index 00000000..4677ae91
--- /dev/null
+++ b/doc/Datastore-hacks.html
@@ -0,0 +1,94 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Datastore hacks</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <style type="text/css">
13table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
14 margin: 0; padding: 0; vertical-align: baseline; border: none; }
15table.sourceCode { width: 100%; line-height: 100%; }
16td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
17td.sourceCode { padding-left: 5px; }
18code > span.kw { color: #007020; font-weight: bold; }
19code > span.dt { color: #902000; }
20code > span.dv { color: #40a070; }
21code > span.bn { color: #40a070; }
22code > span.fl { color: #40a070; }
23code > span.ch { color: #4070a0; }
24code > span.st { color: #4070a0; }
25code > span.co { color: #60a0b0; font-style: italic; }
26code > span.ot { color: #007020; }
27code > span.al { color: #ff0000; font-weight: bold; }
28code > span.fu { color: #06287e; }
29code > span.er { color: #ff0000; font-weight: bold; }
30 </style>
31 <link rel="stylesheet" href="github-markdown.css">
32</head>
33<body>
34<div id="local-sidebar">
35<ul>
36<li><a href="Home.html">Home</a></li>
37<li>Installation
38<ul>
39<li><a href="Server-requirements.html">Server requirements</a></li>
40<li><a href="Server-configuration.html">Server configuration</a></li>
41<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
42</ul></li>
43<li><a href="Usage.html">Usage</a>
44<ul>
45<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
46<li><a href="Firefox-share.html">Firefox share</a></li>
47<li><a href="RSS-feeds.html">RSS feeds</a></li>
48</ul></li>
49<li>How To
50<ul>
51<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
52<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
53<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
54</ul></li>
55<li><a href="Troubleshooting.html">Troubleshooting</a></li>
56<li><a href="Development.html">Development</a>
57<ul>
58<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
59<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
60<li><a href="Directory-structure.html">Directory structure</a></li>
61<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
62<li><a href="Plugin-System.html">Plugin System</a></li>
63<li><a href="Security.html">Security</a></li>
64<li><a href="Static-analysis.html">Static analysis</a></li>
65<li><a href="Theming.html">Theming</a></li>
66<li><a href="Unit-tests.html">Unit tests</a></li>
67</ul></li>
68<li>About
69<ul>
70<li><a href="FAQ.html">FAQ</a></li>
71<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
72<li><a href="TODO.html">TODO</a></li>
73</ul></li>
74</ul>
75</div>
76<h1 id="datastore-hacks">Datastore hacks</h1>
77<h3 id="decode-datastore-content">Decode datastore content</h3>
78<p>To display the array representing the data saved in <code>data/datastore.php</code>, use the following snippet:</p>
79<pre class="sourceCode php"><code class="sourceCode php"><span class="kw">$data</span> = <span class="st">&quot;tZNdb9MwFIb... &lt;Commented content inside datastore.php&gt;&quot;</span><span class="ot">;</span>
80<span class="kw">$out</span> = <span class="fu">unserialize</span><span class="ot">(</span><span class="fu">gzinflate</span><span class="ot">(</span><span class="fu">base64_decode</span><span class="ot">(</span><span class="kw">$data</span><span class="ot">)));</span>
81<span class="fu">echo</span> <span class="st">&quot;&lt;pre&gt;&quot;</span><span class="ot">;</span> <span class="co">// Pretty printing is love, pretty printing is life</span>
82<span class="fu">print_r</span><span class="ot">(</span><span class="kw">$out</span><span class="ot">);</span>
83<span class="fu">echo</span> <span class="st">&quot;&lt;/pre&gt;&quot;</span><span class="ot">;</span>
84<span class="fu">exit</span><span class="ot">;</span></code></pre>
85<p>This will output the internal representation of the datastore, &quot;unobfuscated&quot; (if this can really be considered obfuscation).</p>
86<h3 id="changing-the-timestamp-for-a-link">Changing the timestamp for a link</h3>
87<ul>
88<li>Look for <code>&lt;input type=&quot;hidden&quot; name=&quot;lf_linkdate&quot; value=&quot;{$link.linkdate}&quot;&gt;</code> in <code>tpl/editlink.tpl</code> (line 14)</li>
89<li>Remove <code>type=&quot;hidden&quot;</code> from this line</li>
90<li>A new date/time field becomes available in the edit/new link dialog.</li>
91<li>You can set the timestamp manually by entering it in the format <code>YYYMMDD_HHMMS</code>.</li>
92</ul>
93</body>
94</html>
diff --git a/doc/Datastore-hacks.md b/doc/Datastore-hacks.md
new file mode 100644
index 00000000..33aa2223
--- /dev/null
+++ b/doc/Datastore-hacks.md
@@ -0,0 +1,19 @@
1#Datastore hacks
2### Decode datastore content
3To display the array representing the data saved in `data/datastore.php`, use the following snippet:
4
5```php
6$data = "tZNdb9MwFIb... <Commented content inside datastore.php>";
7$out = unserialize(gzinflate(base64_decode($data)));
8echo "<pre>"; // Pretty printing is love, pretty printing is life
9print_r($out);
10echo "</pre>";
11exit;
12```
13This will output the internal representation of the datastore, "unobfuscated" (if this can really be considered obfuscation).
14
15### Changing the timestamp for a link
16* Look for `<input type="hidden" name="lf_linkdate" value="{$link.linkdate}">` in `tpl/editlink.tpl` (line 14)
17* Remove `type="hidden"` from this line
18* A new date/time field becomes available in the edit/new link dialog.
19* You can set the timestamp manually by entering it in the format `YYYMMDD_HHMMS`.
diff --git a/doc/Development.html b/doc/Development.html
new file mode 100644
index 00000000..1e33eff4
--- /dev/null
+++ b/doc/Development.html
@@ -0,0 +1,102 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Development</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <link rel="stylesheet" href="github-markdown.css">
13</head>
14<body>
15<div id="local-sidebar">
16<ul>
17<li><a href="Home.html">Home</a></li>
18<li>Installation
19<ul>
20<li><a href="Server-requirements.html">Server requirements</a></li>
21<li><a href="Server-configuration.html">Server configuration</a></li>
22<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
23</ul></li>
24<li><a href="Usage.html">Usage</a>
25<ul>
26<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
27<li><a href="Firefox-share.html">Firefox share</a></li>
28<li><a href="RSS-feeds.html">RSS feeds</a></li>
29</ul></li>
30<li>How To
31<ul>
32<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
33<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
34<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
35</ul></li>
36<li><a href="Troubleshooting.html">Troubleshooting</a></li>
37<li><a href="Development.html">Development</a>
38<ul>
39<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
40<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
41<li><a href="Directory-structure.html">Directory structure</a></li>
42<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
43<li><a href="Plugin-System.html">Plugin System</a></li>
44<li><a href="Security.html">Security</a></li>
45<li><a href="Static-analysis.html">Static analysis</a></li>
46<li><a href="Theming.html">Theming</a></li>
47<li><a href="Unit-tests.html">Unit tests</a></li>
48</ul></li>
49<li>About
50<ul>
51<li><a href="FAQ.html">FAQ</a></li>
52<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
53<li><a href="TODO.html">TODO</a></li>
54</ul></li>
55</ul>
56</div>
57<h1 id="development">Development</h1>
58<h2 id="guidelines">Guidelines</h2>
59<p>Please have a look at the following pages:</p>
60<ul>
61<li><a href="https://github.com/shaarli/Shaarli/tree/master/CONTRIBUTING.md">Contributing to Shaarli</a><a href=".html"></a></li>
62<li><a href="Static-analysis.html">Static analysis</a> - patches should try to stick to the <a href="http://www.php-fig.org/psr/">PHP Standard Recommendations</a> (PSR), especially:
63<ul>
64<li><a href="http://www.php-fig.org/psr/psr-1/">PSR-1</a> - Basic Coding Standard<a href=".html"></a></li>
65<li><a href="http://www.php-fig.org/psr/psr-2/">PSR-2</a> - Coding Style Guide<a href=".html"></a></li>
66</ul></li>
67<li><a href="Unit-tests.html">Unit tests</a></li>
68<li><a href="GnuPG-signature.html">GnuPG signature</a> for tags/releases</li>
69</ul>
70<h2 id="continuous-integration-tools">Continuous integration tools</h2>
71<h3 id="local-development">Local development</h3>
72<p>A <a href="https://github.com/shaarli/Shaarli/blob/master/Makefile"><code>Makefile</code></a> is available to perform project-related operations:<a href=".html"></a></p>
73<ul>
74<li>Documentation - generate a local HTML copy of the GitHub wiki</li>
75<li><a href="Static-analysis.html">Static analysis</a> - check that the code is compliant to PHP conventions</li>
76<li><a href="Unit-tests.html">Unit tests</a> - ensure there are no regressions introduced by new commits</li>
77</ul>
78<h3 id="automatic-builds">Automatic builds</h3>
79<p><a href="http://docs.travis-ci.com/">Travis CI</a> is a Continuous Integration build server, that runs a build:<a href=".html"></a></p>
80<ul>
81<li>each time a commit is merged to the mainline (<code>master</code> branch)</li>
82<li>each time a Pull Request is submitted or updated</li>
83</ul>
84<p>A build is composed of several jobs: one for each supported PHP version (see <a href="Server-requirements.html">Server requirements</a>).</p>
85<p>Each build job:</p>
86<ul>
87<li>updates Composer</li>
88<li>installs 3rd-party test dependencies with Composer</li>
89<li>runs <a href="Unit-tests.html">Unit tests</a></li>
90</ul>
91<p>After all jobs have finished, Travis returns the results to GitHub:</p>
92<ul>
93<li>a status icon represents the result for the <code>master</code> branch: <a href="(https://api.travis-ci.org/shaarli/Shaarli.svg)](https://travis-ci.org/shaarli/Shaarli).html"><img src="https://travis-ci.org/shaarli/Shaarli" alt="(https://api.travis-ci.org/shaarli/Shaarli.svg)" /></a></li>
94<li>Pull Requests are updated with the Travis result
95<ul>
96<li>Green: all tests have passed</li>
97<li>Red: some tests failed</li>
98<li>Orange: tests are pending</li>
99</ul></li>
100</ul>
101</body>
102</html>
diff --git a/doc/Development.md b/doc/Development.md
new file mode 100644
index 00000000..6cfcb683
--- /dev/null
+++ b/doc/Development.md
@@ -0,0 +1,35 @@
1#Development
2## Guidelines
3Please have a look at the following pages:
4- [Contributing to Shaarli](https://github.com/shaarli/Shaarli/tree/master/CONTRIBUTING.md)[](.html)
5- [Static analysis](Static-analysis.html) - patches should try to stick to the [PHP Standard Recommendations](http://www.php-fig.org/psr/) (PSR), especially:
6 - [PSR-1](http://www.php-fig.org/psr/psr-1/) - Basic Coding Standard[](.html)
7 - [PSR-2](http://www.php-fig.org/psr/psr-2/) - Coding Style Guide[](.html)
8- [Unit tests](Unit-tests.html)
9- [GnuPG signature](GnuPG-signature.html) for tags/releases
10
11## Continuous integration tools
12### Local development
13A [`Makefile`](https://github.com/shaarli/Shaarli/blob/master/Makefile) is available to perform project-related operations:[](.html)
14- Documentation - generate a local HTML copy of the GitHub wiki
15- [Static analysis](Static-analysis.html) - check that the code is compliant to PHP conventions
16- [Unit tests](Unit-tests.html) - ensure there are no regressions introduced by new commits
17
18### Automatic builds
19[Travis CI](http://docs.travis-ci.com/) is a Continuous Integration build server, that runs a build:[](.html)
20- each time a commit is merged to the mainline (`master` branch)
21- each time a Pull Request is submitted or updated
22
23A build is composed of several jobs: one for each supported PHP version (see [Server requirements](Server-requirements.html)).
24
25Each build job:
26- updates Composer
27- installs 3rd-party test dependencies with Composer
28- runs [Unit tests](Unit-tests.html)
29
30After all jobs have finished, Travis returns the results to GitHub:
31- a status icon represents the result for the `master` branch: [![(https://api.travis-ci.org/shaarli/Shaarli.svg)](https://travis-ci.org/shaarli/Shaarli)]((https://api.travis-ci.org/shaarli/Shaarli.svg)](https://travis-ci.org/shaarli/Shaarli).html)
32- Pull Requests are updated with the Travis result
33 - Green: all tests have passed
34 - Red: some tests failed
35 - Orange: tests are pending
diff --git a/doc/Directory-structure.html b/doc/Directory-structure.html
new file mode 100644
index 00000000..4ea5e249
--- /dev/null
+++ b/doc/Directory-structure.html
@@ -0,0 +1,107 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Directory structure</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <style type="text/css">
13table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
14 margin: 0; padding: 0; vertical-align: baseline; border: none; }
15table.sourceCode { width: 100%; line-height: 100%; }
16td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
17td.sourceCode { padding-left: 5px; }
18code > span.kw { color: #007020; font-weight: bold; }
19code > span.dt { color: #902000; }
20code > span.dv { color: #40a070; }
21code > span.bn { color: #40a070; }
22code > span.fl { color: #40a070; }
23code > span.ch { color: #4070a0; }
24code > span.st { color: #4070a0; }
25code > span.co { color: #60a0b0; font-style: italic; }
26code > span.ot { color: #007020; }
27code > span.al { color: #ff0000; font-weight: bold; }
28code > span.fu { color: #06287e; }
29code > span.er { color: #ff0000; font-weight: bold; }
30 </style>
31 <link rel="stylesheet" href="github-markdown.css">
32</head>
33<body>
34<div id="local-sidebar">
35<ul>
36<li><a href="Home.html">Home</a></li>
37<li>Installation
38<ul>
39<li><a href="Server-requirements.html">Server requirements</a></li>
40<li><a href="Server-configuration.html">Server configuration</a></li>
41<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
42</ul></li>
43<li><a href="Usage.html">Usage</a>
44<ul>
45<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
46<li><a href="Firefox-share.html">Firefox share</a></li>
47<li><a href="RSS-feeds.html">RSS feeds</a></li>
48</ul></li>
49<li>How To
50<ul>
51<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
52<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
53<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
54</ul></li>
55<li><a href="Troubleshooting.html">Troubleshooting</a></li>
56<li><a href="Development.html">Development</a>
57<ul>
58<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
59<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
60<li><a href="Directory-structure.html">Directory structure</a></li>
61<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
62<li><a href="Plugin-System.html">Plugin System</a></li>
63<li><a href="Security.html">Security</a></li>
64<li><a href="Static-analysis.html">Static analysis</a></li>
65<li><a href="Theming.html">Theming</a></li>
66<li><a href="Unit-tests.html">Unit tests</a></li>
67</ul></li>
68<li>About
69<ul>
70<li><a href="FAQ.html">FAQ</a></li>
71<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
72<li><a href="TODO.html">TODO</a></li>
73</ul></li>
74</ul>
75</div>
76<h1 id="directory-structure">Directory structure</h1>
77<p>Here is the directory structure of Shaarli and the purpose of the different files:</p>
78<pre class="sourceCode bash"><code class="sourceCode bash"> <span class="kw">index.php</span> <span class="co"># Main program</span>
79 <span class="kw">application/</span> <span class="co"># Shaarli classes</span>
80 ├── <span class="kw">LinkDB.php</span>
81 └── <span class="kw">Utils.php</span>
82 <span class="kw">tests/</span> <span class="co"># Shaarli unitary &amp; functional tests</span>
83 ├── <span class="kw">LinkDBTest.php</span>
84 ├── <span class="kw">utils</span> <span class="co"># utilities to ease testing</span>
85 │ └── <span class="kw">ReferenceLinkDB.php</span>
86 └── <span class="kw">UtilsTest.php</span>
87 <span class="kw">COPYING</span> <span class="co"># Shaarli license</span>
88 <span class="kw">inc/</span> <span class="co"># static assets and 3rd party libraries</span>
89 ├── <span class="kw">awesomplete.*</span> <span class="co"># tags autocompletion library</span>
90 ├── <span class="kw">blazy.*</span> <span class="co"># picture wall lazy image loading library</span>
91 ├── <span class="kw">shaarli.css</span>, reset.css <span class="co"># Shaarli stylesheet.</span>
92 ├── <span class="kw">qr.*</span> <span class="co"># qr code generation library</span>
93 └──<span class="kw">rain.tpl.class.php</span> <span class="co"># RainTPL templating library</span>
94 <span class="kw">tpl/</span> <span class="co"># RainTPL templates for Shaarli. They are used to build the pages.</span>
95 <span class="kw">images/</span> <span class="co"># Images and icons used in Shaarli</span>
96 <span class="kw">data/</span> <span class="co"># data storage: bookmark database, configuration, logs, banlist…</span>
97 ├── <span class="kw">config.php</span> <span class="co"># Shaarli configuration (login, password, timezone, title…)</span>
98 ├── <span class="kw">datastore.php</span> <span class="co"># Your link database (compressed).</span>
99 ├── <span class="kw">ipban.php</span> <span class="co"># IP address ban system data</span>
100 ├── <span class="kw">lastupdatecheck.txt</span> <span class="co"># Update check timestamp file</span>
101 └──<span class="kw">log.txt</span> <span class="co"># login/IPban log.</span>
102 <span class="kw">cache/</span> <span class="co"># thumbnails cache</span>
103 <span class="co"># This directory is automatically created. You can erase it anytime you want.</span>
104 <span class="kw">tmp/</span> <span class="co"># Temporary directory for compiled RainTPL templates.</span>
105 <span class="co"># This directory is automatically created. You can erase it anytime you want.</span></code></pre>
106</body>
107</html>
diff --git a/doc/Directory-structure.md b/doc/Directory-structure.md
new file mode 100644
index 00000000..3a1c4309
--- /dev/null
+++ b/doc/Directory-structure.md
@@ -0,0 +1,33 @@
1#Directory structure
2Here is the directory structure of Shaarli and the purpose of the different files:
3
4```bash
5 index.php # Main program
6 application/ # Shaarli classes
7 ├── LinkDB.php
8 └── Utils.php
9 tests/ # Shaarli unitary & functional tests
10 ├── LinkDBTest.php
11 ├── utils # utilities to ease testing
12 │ └── ReferenceLinkDB.php
13 └── UtilsTest.php
14 COPYING # Shaarli license
15 inc/ # static assets and 3rd party libraries
16 ├── awesomplete.* # tags autocompletion library
17 ├── blazy.* # picture wall lazy image loading library
18 ├── shaarli.css, reset.css # Shaarli stylesheet.
19 ├── qr.* # qr code generation library
20 └──rain.tpl.class.php # RainTPL templating library
21 tpl/ # RainTPL templates for Shaarli. They are used to build the pages.
22 images/ # Images and icons used in Shaarli
23 data/ # data storage: bookmark database, configuration, logs, banlist…
24 ├── config.php # Shaarli configuration (login, password, timezone, title…)
25 ├── datastore.php # Your link database (compressed).
26 ├── ipban.php # IP address ban system data
27 ├── lastupdatecheck.txt # Update check timestamp file
28 └──log.txt # login/IPban log.
29 cache/ # thumbnails cache
30 # This directory is automatically created. You can erase it anytime you want.
31 tmp/ # Temporary directory for compiled RainTPL templates.
32 # This directory is automatically created. You can erase it anytime you want.
33```
diff --git a/doc/Download-CSS-styles-for-shaarlis-listed-in-an-opml-file.html b/doc/Download-CSS-styles-for-shaarlis-listed-in-an-opml-file.html
deleted file mode 100644
index 0f32fb84..00000000
--- a/doc/Download-CSS-styles-for-shaarlis-listed-in-an-opml-file.html
+++ /dev/null
@@ -1,167 +0,0 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title></title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <link rel="stylesheet" href="github-markdown.css">
13</head>
14<body>
15<h3 id="download-css-styles-for-shaarlis-listed-in-an-opml-file">Download CSS styles for shaarlis listed in an opml file</h3>
16<p>Example php script:</p>
17<pre><code>&lt;!---- ?php --&gt;
18&lt;!---- Copyright (c) 2014 Nicolas Delsaux (https://github.com/Riduidel) --&gt;
19&lt;!---- License: zlib (http://www.gzip.org/zlib/zlib_license.html) --&gt;
20
21/**
22 * Source: https://github.com/Riduidel
23 * Download css styles for shaarlis listed in an opml file
24 */
25define(&quot;SHAARLI_RSS_OPML&quot;, &quot;https://www.ecirtam.net/shaarlirss/custom/people.opml&quot;);
26
27define(&quot;THEMES_TEMP_FOLDER&quot;, &quot;new_themes&quot;);
28
29if(!file_exists(THEMES_TEMP_FOLDER)) {
30 mkdir(THEMES_TEMP_FOLDER);
31}
32
33function siteUrl($pathInSite) {
34 $indexPos = strpos($pathInSite, &quot;index.php&quot;);
35 if(!$indexPos) {
36 return $pathInSite;
37 } else {
38 return substr($pathInSite, 0, $indexPos);
39 }
40}
41
42function createShaarliHashFromOPMLL($opmlFile) {
43 $result = array();
44 $opml = file_get_contents($opmlFile);
45 $opmlXml = simplexml_load_string($opml);
46 $outlineElements = $opmlXml-&gt;xpath(&quot;body/outline&quot;);
47 foreach($outlineElements as $site) {
48 $siteUrl = siteUrl((string) $site[&#39;htmlUrl&#39;]);
49 $result[$siteUrl]=((string) $site[&#39;text&#39;]);
50 }
51 return $result;
52}
53
54function getSiteFolder($url) {
55 $domain = parse_url($url, PHP_URL_HOST);
56 return THEMES_TEMP_FOLDER.&quot;/&quot;.str_replace(&quot;.&quot;, &quot;_&quot;, $domain);
57}
58
59function get_http_response_code($theURL) {
60 $headers = get_headers($theURL);
61 return substr($headers[0], 9, 3);
62}
63
64/**
65 * This makes the code PHP-5 only (particularly the call to &quot;get_headers&quot;)
66 */
67function copyUserStyleFrom($url, $name, $knownStyles) {
68 $userStyle = $url.&quot;inc/user.css&quot;;
69 if(in_array($url, $knownStyles)) {
70 // TODO add log message
71 } else {
72 $statusCode = get_http_response_code($userStyle);
73 if(intval($statusCode)&lt;300) {
74 $styleSheet = file_get_contents($userStyle);
75 $siteFolder = getSiteFolder($url);
76 if(!file_exists($siteFolder)) {
77 mkdir($siteFolder);
78 }
79 if(!file_exists($siteFolder.&#39;/user.css&#39;)) {
80 // Copy stylesheet
81 file_put_contents($siteFolder.&#39;/user.css&#39;, $styleSheet);
82 }
83 if(!file_exists($siteFolder.&#39;/README.md&#39;)) {
84 // Then write a readme.md file
85 file_put_contents($siteFolder.&#39;/README.md&#39;,
86 &quot;User style from &quot;.$name.&quot;\n&quot;
87 .&quot;=============================&quot;
88 .&quot;\n\n&quot;
89 .&quot;This stylesheet was downloaded from &quot;.$userStyle.&quot; on &quot;.date(DATE_RFC822)
90 );
91 }
92 if(!file_exists($siteFolder.&#39;/config.ini&#39;)) {
93 // Write a config file containing useful informations
94 file_put_contents($siteFolder.&#39;/config.ini&#39;,
95 &quot;site_url=&quot;.$url.&quot;\n&quot;
96 .&quot;site_name=&quot;.$name.&quot;\n&quot;
97 );
98 }
99 if(!file_exists($siteFolder.&#39;/home.png&#39;)) {
100 // And finally copy generated thumbnail
101 $homeThumb = $siteFolder.&#39;/home.png&#39;;
102 file_put_contents($siteFolder.&#39;/home.png&#39;, file_get_contents(getThumbnailUrl($url)));
103 }
104 echo &#39;Theme have been downloaded from &lt;a href=&quot;&#39;.$url.&#39;&quot;&gt;&#39;.$url.&#39;&lt;/a&gt; into &#39;.$siteFolder
105 .&#39;. It looks like &lt;img src=&quot;&#39;.$homeThumb.&#39;&quot;&gt;&lt;br/&gt;&#39;;
106 }
107 }
108}
109
110function getThumbnailUrl($url) {
111 return &#39;http://api.webthumbnail.org/?url=&#39;.$url;
112}
113
114function copyUserStylesFrom($urlToNames, $knownStyles) {
115 foreach($urlToNames as $url =&gt; $name) {
116 copyUserStyleFrom($url, $name, $knownStyles);
117 }
118}
119
120/**
121 * Reading directory list, courtesy of http://www.laughing-buddha.net/php/dirlist/
122 * @param directory the directory we want to list files of
123 * @return a simple array containing the list of absolute file paths. Notice that current file (&quot;.&quot;) and parent one(&quot;..&quot;)
124 * are not listed here
125 */
126function getDirectoryList ($directory) {
127 $realPath = realpath($directory);
128 // create an array to hold directory list
129 $results = array();
130 // create a handler for the directory
131 $handler = opendir($directory);
132 // open directory and walk through the filenames
133 while ($file = readdir($handler)) {
134 // if file isn&#39;t this directory or its parent, add it to the results
135 if ($file != &quot;.&quot; &amp;&amp; $file != &quot;..&quot;) {
136 $results[] = realpath($realPath . &quot;/&quot; . $file);
137 }
138 }
139 // tidy up: close the handler
140 closedir($handler);
141 // done!
142 return $results;
143}
144
145/**
146 * Start in themes folder and look in all subfolders for config.ini files.
147 * These config.ini files allow us not to download styles again and again
148 */
149function findKnownStyles() {
150 $result = array();
151 $subFolders = getDirectoryList(&quot;themes&quot;);
152 foreach($subFolders as $folder) {
153 $configFile = $folder.&quot;/config.ini&quot;;
154 if(file_exists($configFile)) {
155 $iniParameters = parse_ini_file($configFile);
156 array_push($result, $iniParameters[&#39;site_url&#39;]);
157 }
158 }
159 return $result;
160}
161
162$knownStyles = findKnownStyles();
163copyUserStylesFrom(createShaarliHashFromOPMLL(SHAARLI_RSS_OPML), $knownStyles);
164
165&lt;!--- ? ----&gt;</code></pre>
166</body>
167</html>
diff --git a/doc/Download-CSS-styles-from-an-OPML-list.html b/doc/Download-CSS-styles-from-an-OPML-list.html
new file mode 100644
index 00000000..b21a54bd
--- /dev/null
+++ b/doc/Download-CSS-styles-from-an-OPML-list.html
@@ -0,0 +1,229 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Download CSS styles from an OPML list</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <style type="text/css">
13table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
14 margin: 0; padding: 0; vertical-align: baseline; border: none; }
15table.sourceCode { width: 100%; line-height: 100%; }
16td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
17td.sourceCode { padding-left: 5px; }
18code > span.kw { color: #007020; font-weight: bold; }
19code > span.dt { color: #902000; }
20code > span.dv { color: #40a070; }
21code > span.bn { color: #40a070; }
22code > span.fl { color: #40a070; }
23code > span.ch { color: #4070a0; }
24code > span.st { color: #4070a0; }
25code > span.co { color: #60a0b0; font-style: italic; }
26code > span.ot { color: #007020; }
27code > span.al { color: #ff0000; font-weight: bold; }
28code > span.fu { color: #06287e; }
29code > span.er { color: #ff0000; font-weight: bold; }
30 </style>
31 <link rel="stylesheet" href="github-markdown.css">
32</head>
33<body>
34<div id="local-sidebar">
35<ul>
36<li><a href="Home.html">Home</a></li>
37<li>Installation
38<ul>
39<li><a href="Server-requirements.html">Server requirements</a></li>
40<li><a href="Server-configuration.html">Server configuration</a></li>
41<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
42</ul></li>
43<li><a href="Usage.html">Usage</a>
44<ul>
45<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
46<li><a href="Firefox-share.html">Firefox share</a></li>
47<li><a href="RSS-feeds.html">RSS feeds</a></li>
48</ul></li>
49<li>How To
50<ul>
51<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
52<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
53<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
54</ul></li>
55<li><a href="Troubleshooting.html">Troubleshooting</a></li>
56<li><a href="Development.html">Development</a>
57<ul>
58<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
59<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
60<li><a href="Directory-structure.html">Directory structure</a></li>
61<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
62<li><a href="Plugin-System.html">Plugin System</a></li>
63<li><a href="Security.html">Security</a></li>
64<li><a href="Static-analysis.html">Static analysis</a></li>
65<li><a href="Theming.html">Theming</a></li>
66<li><a href="Unit-tests.html">Unit tests</a></li>
67</ul></li>
68<li>About
69<ul>
70<li><a href="FAQ.html">FAQ</a></li>
71<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
72<li><a href="TODO.html">TODO</a></li>
73</ul></li>
74</ul>
75</div>
76<h1 id="download-css-styles-from-an-opml-list">Download CSS styles from an OPML list</h1>
77<h3 id="download-css-styles-for-shaarlis-listed-in-an-opml-file">Download CSS styles for shaarlis listed in an opml file</h3>
78<p>Example php script:</p>
79<pre class="sourceCode php"><code class="sourceCode php">&lt;!---- <span class="ot">?</span>php --&gt;
80&lt;!---- Copyright <span class="ot">(</span>c<span class="ot">)</span> <span class="dv">2014</span> Nicolas Delsaux <span class="ot">(</span>https<span class="ot">:</span><span class="co">//github.com/Riduidel) --&gt;</span>
81&lt;!---- License: zlib <span class="ot">(</span>http:<span class="co">//www.gzip.org/zlib/zlib_license.html) --&gt;</span>
82
83<span class="co">/**</span>
84<span class="co"> * Source: https://github.com/Riduidel</span>
85<span class="co"> * Download css styles for shaarlis listed in an opml file</span>
86<span class="co"> */</span>
87<span class="fu">define</span><span class="ot">(</span><span class="st">&quot;SHAARLI_RSS_OPML&quot;</span><span class="ot">,</span> <span class="st">&quot;https://www.ecirtam.net/shaarlirss/custom/people.opml&quot;</span><span class="ot">);</span>
88
89<span class="fu">define</span><span class="ot">(</span><span class="st">&quot;THEMES_TEMP_FOLDER&quot;</span><span class="ot">,</span> <span class="st">&quot;new_themes&quot;</span><span class="ot">);</span>
90
91<span class="kw">if</span><span class="ot">(</span>!<span class="fu">file_exists</span><span class="ot">(</span><span class="kw">THEMES_TEMP_FOLDER</span><span class="ot">))</span> {
92 <span class="fu">mkdir</span><span class="ot">(</span><span class="kw">THEMES_TEMP_FOLDER</span><span class="ot">);</span>
93}
94
95<span class="kw">function</span> siteUrl<span class="ot">(</span><span class="kw">$pathInSite</span><span class="ot">)</span> {
96 <span class="kw">$indexPos</span> = <span class="fu">strpos</span><span class="ot">(</span><span class="kw">$pathInSite</span><span class="ot">,</span> <span class="st">&quot;index.php&quot;</span><span class="ot">);</span>
97 <span class="kw">if</span><span class="ot">(</span>!<span class="kw">$indexPos</span><span class="ot">)</span> {
98 <span class="kw">return</span> <span class="kw">$pathInSite</span><span class="ot">;</span>
99 } <span class="kw">else</span> {
100 <span class="kw">return</span> <span class="fu">substr</span><span class="ot">(</span><span class="kw">$pathInSite</span><span class="ot">,</span> <span class="dv">0</span><span class="ot">,</span> <span class="kw">$indexPos</span><span class="ot">);</span>
101 }
102}
103
104<span class="kw">function</span> createShaarliHashFromOPMLL<span class="ot">(</span><span class="kw">$opmlFile</span><span class="ot">)</span> {
105 <span class="kw">$result</span> = <span class="fu">array</span><span class="ot">();</span>
106 <span class="kw">$opml</span> = <span class="fu">file_get_contents</span><span class="ot">(</span><span class="kw">$opmlFile</span><span class="ot">);</span>
107 <span class="kw">$opmlXml</span> = <span class="fu">simplexml_load_string</span><span class="ot">(</span><span class="kw">$opml</span><span class="ot">);</span>
108 <span class="kw">$outlineElements</span> = <span class="kw">$opmlXml</span>-&gt;xpath<span class="ot">(</span><span class="st">&quot;body/outline&quot;</span><span class="ot">);</span>
109 <span class="kw">foreach</span><span class="ot">(</span><span class="kw">$outlineElements</span> <span class="kw">as</span> <span class="kw">$site</span><span class="ot">)</span> {
110 <span class="kw">$siteUrl</span> = siteUrl<span class="ot">(</span><span class="dt">(string)</span> <span class="kw">$site</span><span class="ot">[</span><span class="st">&#39;htmlUrl&#39;</span><span class="ot">]);[](</span>.html<span class="ot">)</span>
111 <span class="kw">$result</span><span class="ot">[</span><span class="kw">$siteUrl</span><span class="ot">]</span>=<span class="ot">(</span><span class="dt">(string)</span> <span class="kw">$site</span><span class="ot">[</span><span class="st">&#39;text&#39;</span><span class="ot">]);[](</span>.html<span class="ot">)</span>
112 }
113 <span class="kw">return</span> <span class="kw">$result</span><span class="ot">;</span>
114}
115
116<span class="kw">function</span> getSiteFolder<span class="ot">(</span><span class="kw">$url</span><span class="ot">)</span> {
117 <span class="kw">$domain</span> = <span class="fu">parse_url</span><span class="ot">(</span><span class="kw">$url</span><span class="ot">,</span> <span class="kw">PHP_URL_HOST</span><span class="ot">);</span>
118 <span class="kw">return</span> <span class="kw">THEMES_TEMP_FOLDER</span>.<span class="st">&quot;/&quot;</span>.<span class="fu">str_replace</span><span class="ot">(</span><span class="st">&quot;.&quot;</span><span class="ot">,</span> <span class="st">&quot;_&quot;</span><span class="ot">,</span> <span class="kw">$domain</span><span class="ot">);</span>
119}
120
121<span class="kw">function</span> get_http_response_code<span class="ot">(</span><span class="kw">$theURL</span><span class="ot">)</span> {
122 <span class="kw">$headers</span> = <span class="fu">get_headers</span><span class="ot">(</span><span class="kw">$theURL</span><span class="ot">);</span>
123 <span class="kw">return</span> <span class="fu">substr</span><span class="ot">(</span><span class="kw">$headers</span><span class="ot">[</span><span class="dv">0</span><span class="ot">],</span> <span class="dv">9</span><span class="ot">,</span> <span class="dv">3</span><span class="ot">);[](</span>.html<span class="ot">)</span>
124}
125
126<span class="co">/**</span>
127<span class="co"> * This makes the code PHP-5 only (particularly the call to &quot;get_headers&quot;)</span>
128<span class="co"> */</span>
129<span class="kw">function</span> copyUserStyleFrom<span class="ot">(</span><span class="kw">$url</span><span class="ot">,</span> <span class="kw">$name</span><span class="ot">,</span> <span class="kw">$knownStyles</span><span class="ot">)</span> {
130 <span class="kw">$userStyle</span> = <span class="kw">$url</span>.<span class="st">&quot;inc/user.css&quot;</span><span class="ot">;</span>
131 <span class="kw">if</span><span class="ot">(</span><span class="fu">in_array</span><span class="ot">(</span><span class="kw">$url</span><span class="ot">,</span> <span class="kw">$knownStyles</span><span class="ot">))</span> {
132 <span class="co">// TODO add log message</span>
133 } <span class="kw">else</span> {
134 <span class="kw">$statusCode</span> = get_http_response_code<span class="ot">(</span><span class="kw">$userStyle</span><span class="ot">);</span>
135 <span class="kw">if</span><span class="ot">(</span><span class="fu">intval</span><span class="ot">(</span><span class="kw">$statusCode</span><span class="ot">)</span>&lt;<span class="dv">300</span><span class="ot">)</span> {
136 <span class="kw">$styleSheet</span> = <span class="fu">file_get_contents</span><span class="ot">(</span><span class="kw">$userStyle</span><span class="ot">);</span>
137 <span class="kw">$siteFolder</span> = getSiteFolder<span class="ot">(</span><span class="kw">$url</span><span class="ot">);</span>
138 <span class="kw">if</span><span class="ot">(</span>!<span class="fu">file_exists</span><span class="ot">(</span><span class="kw">$siteFolder</span><span class="ot">))</span> {
139 <span class="fu">mkdir</span><span class="ot">(</span><span class="kw">$siteFolder</span><span class="ot">);</span>
140 }
141 <span class="kw">if</span><span class="ot">(</span>!<span class="fu">file_exists</span><span class="ot">(</span><span class="kw">$siteFolder</span>.<span class="st">&#39;/user.css&#39;</span><span class="ot">))</span> {
142 <span class="co">// Copy stylesheet</span>
143 <span class="fu">file_put_contents</span><span class="ot">(</span><span class="kw">$siteFolder</span>.<span class="st">&#39;/user.css&#39;</span><span class="ot">,</span> <span class="kw">$styleSheet</span><span class="ot">);</span>
144 }
145 <span class="kw">if</span><span class="ot">(</span>!<span class="fu">file_exists</span><span class="ot">(</span><span class="kw">$siteFolder</span>.<span class="st">&#39;/README.md&#39;</span><span class="ot">))</span> {
146 <span class="co">// Then write a readme.md file</span>
147 <span class="fu">file_put_contents</span><span class="ot">(</span><span class="kw">$siteFolder</span>.<span class="st">&#39;/README.md&#39;</span><span class="ot">,</span>
148 <span class="st">&quot;User style from &quot;</span>.<span class="kw">$name</span>.<span class="st">&quot;</span><span class="kw">\n</span><span class="st">&quot;</span>
149 .<span class="st">&quot;=============================&quot;</span>
150 .<span class="st">&quot;</span><span class="kw">\n\n</span><span class="st">&quot;</span>
151 .<span class="st">&quot;This stylesheet was downloaded from &quot;</span>.<span class="kw">$userStyle</span>.<span class="st">&quot; on &quot;</span>.<span class="fu">date</span><span class="ot">(</span><span class="kw">DATE_RFC822</span><span class="ot">)</span>
152 <span class="ot">);</span>
153 }
154 <span class="kw">if</span><span class="ot">(</span>!<span class="fu">file_exists</span><span class="ot">(</span><span class="kw">$siteFolder</span>.<span class="st">&#39;/config.ini&#39;</span><span class="ot">))</span> {
155 <span class="co">// Write a config file containing useful informations</span>
156 <span class="fu">file_put_contents</span><span class="ot">(</span><span class="kw">$siteFolder</span>.<span class="st">&#39;/config.ini&#39;</span><span class="ot">,</span>
157 <span class="st">&quot;site_url=&quot;</span>.<span class="kw">$url</span>.<span class="st">&quot;</span><span class="kw">\n</span><span class="st">&quot;</span>
158 .<span class="st">&quot;site_name=&quot;</span>.<span class="kw">$name</span>.<span class="st">&quot;</span><span class="kw">\n</span><span class="st">&quot;</span>
159 <span class="ot">);</span>
160 }
161 <span class="kw">if</span><span class="ot">(</span>!<span class="fu">file_exists</span><span class="ot">(</span><span class="kw">$siteFolder</span>.<span class="st">&#39;/home.png&#39;</span><span class="ot">))</span> {
162 <span class="co">// And finally copy generated thumbnail</span>
163 <span class="kw">$homeThumb</span> = <span class="kw">$siteFolder</span>.<span class="st">&#39;/home.png&#39;</span><span class="ot">;</span>
164 <span class="fu">file_put_contents</span><span class="ot">(</span><span class="kw">$siteFolder</span>.<span class="st">&#39;/home.png&#39;</span><span class="ot">,</span> <span class="fu">file_get_contents</span><span class="ot">(</span>getThumbnailUrl<span class="ot">(</span><span class="kw">$url</span><span class="ot">)));</span>
165 }
166 <span class="fu">echo</span> <span class="st">&#39;Theme have been downloaded from &lt;a href=&quot;&#39;</span>.<span class="kw">$url</span>.<span class="st">&#39;&quot;&gt;&#39;</span>.<span class="kw">$url</span>.<span class="st">&#39;&lt;/a&gt; into &#39;</span>.<span class="kw">$siteFolder</span>
167 .<span class="st">&#39;. It looks like &lt;img src=&quot;&#39;</span>.<span class="kw">$homeThumb</span>.<span class="st">&#39;&quot;&gt;&lt;br/&gt;&#39;</span><span class="ot">;</span>
168 }
169 }
170}
171
172<span class="kw">function</span> getThumbnailUrl<span class="ot">(</span><span class="kw">$url</span><span class="ot">)</span> {
173 <span class="kw">return</span> <span class="st">&#39;http://api.webthumbnail.org/?url=&#39;</span>.<span class="kw">$url</span><span class="ot">;</span>
174}
175
176<span class="kw">function</span> copyUserStylesFrom<span class="ot">(</span><span class="kw">$urlToNames</span><span class="ot">,</span> <span class="kw">$knownStyles</span><span class="ot">)</span> {
177 <span class="kw">foreach</span><span class="ot">(</span><span class="kw">$urlToNames</span> <span class="kw">as</span> <span class="kw">$url</span> =&gt; <span class="kw">$name</span><span class="ot">)</span> {
178 copyUserStyleFrom<span class="ot">(</span><span class="kw">$url</span><span class="ot">,</span> <span class="kw">$name</span><span class="ot">,</span> <span class="kw">$knownStyles</span><span class="ot">);</span>
179 }
180}
181
182<span class="co">/**</span>
183<span class="co"> * Reading directory list, courtesy of http://www.laughing-buddha.net/php/dirlist/</span>
184<span class="co"> * </span><span class="kw">@param</span><span class="co"> </span><span class="kw">directory</span><span class="co"> the directory we want to list files of</span>
185<span class="co"> * </span><span class="kw">@return</span><span class="co"> a simple array containing the list of absolute file paths. Notice that current file (&quot;.&quot;) and parent one(&quot;..&quot;)</span>
186<span class="co"> * are not listed here</span>
187<span class="co"> */</span>
188<span class="kw">function</span> getDirectoryList <span class="ot">(</span><span class="kw">$directory</span><span class="ot">)</span> {
189 <span class="kw">$realPath</span> = <span class="fu">realpath</span><span class="ot">(</span><span class="kw">$directory</span><span class="ot">);</span>
190 <span class="co">// create an array to hold directory list</span>
191 <span class="kw">$results</span> = <span class="fu">array</span><span class="ot">();</span>
192 <span class="co">// create a handler for the directory</span>
193 <span class="kw">$handler</span> = <span class="fu">opendir</span><span class="ot">(</span><span class="kw">$directory</span><span class="ot">);</span>
194 <span class="co">// open directory and walk through the filenames</span>
195 <span class="kw">while</span> <span class="ot">(</span><span class="kw">$file</span> = <span class="fu">readdir</span><span class="ot">(</span><span class="kw">$handler</span><span class="ot">))</span> {
196 <span class="co">// if file isn&#39;t this directory or its parent, add it to the results</span>
197 <span class="kw">if</span> <span class="ot">(</span><span class="kw">$file</span> != <span class="st">&quot;.&quot;</span> &amp;&amp; <span class="kw">$file</span> != <span class="st">&quot;..&quot;</span><span class="ot">)</span> {
198 <span class="kw">$results</span><span class="ot">[</span> = <span class="fu">realpath</span><span class="ot">(</span><span class="kw">$realPath</span> . <span class="st">&quot;/&quot;</span> . <span class="kw">$file</span><span class="ot">);](</span>-=-<span class="fu">realpath</span><span class="ot">(</span><span class="kw">$realPath</span>-.-<span class="st">&quot;/&quot;</span>-.-<span class="kw">$file</span><span class="ot">);</span>.html<span class="ot">)</span>
199 }
200 }
201 <span class="co">// tidy up: close the handler</span>
202 <span class="fu">closedir</span><span class="ot">(</span><span class="kw">$handler</span><span class="ot">);</span>
203 <span class="co">// done!</span>
204 <span class="kw">return</span> <span class="kw">$results</span><span class="ot">;</span>
205}
206
207<span class="co">/**</span>
208<span class="co"> * Start in themes folder and look in all subfolders for config.ini files. </span>
209<span class="co"> * These config.ini files allow us not to download styles again and again</span>
210<span class="co"> */</span>
211<span class="kw">function</span> findKnownStyles<span class="ot">()</span> {
212 <span class="kw">$result</span> = <span class="fu">array</span><span class="ot">();</span>
213 <span class="kw">$subFolders</span> = getDirectoryList<span class="ot">(</span><span class="st">&quot;themes&quot;</span><span class="ot">);</span>
214 <span class="kw">foreach</span><span class="ot">(</span><span class="kw">$subFolders</span> <span class="kw">as</span> <span class="kw">$folder</span><span class="ot">)</span> {
215 <span class="kw">$configFile</span> = <span class="kw">$folder</span>.<span class="st">&quot;/config.ini&quot;</span><span class="ot">;</span>
216 <span class="kw">if</span><span class="ot">(</span><span class="fu">file_exists</span><span class="ot">(</span><span class="kw">$configFile</span><span class="ot">))</span> {
217 <span class="kw">$iniParameters</span> = <span class="fu">parse_ini_file</span><span class="ot">(</span><span class="kw">$configFile</span><span class="ot">);</span>
218 <span class="fu">array_push</span><span class="ot">(</span><span class="kw">$result</span><span class="ot">,</span> <span class="kw">$iniParameters</span><span class="ot">[</span><span class="st">&#39;site_url&#39;</span><span class="ot">]);[](</span>.html<span class="ot">)</span>
219 }
220 }
221 <span class="kw">return</span> <span class="kw">$result</span><span class="ot">;</span>
222}
223
224<span class="kw">$knownStyles</span> = findKnownStyles<span class="ot">();</span>
225copyUserStylesFrom<span class="ot">(</span>createShaarliHashFromOPMLL<span class="ot">(</span><span class="kw">SHAARLI_RSS_OPML</span><span class="ot">),</span> <span class="kw">$knownStyles</span><span class="ot">);</span>
226
227&lt;!--- <span class="ot">?</span> ----&gt;</code></pre>
228</body>
229</html>
diff --git a/doc/Download-CSS-styles-for-shaarlis-listed-in-an-opml-file.md b/doc/Download-CSS-styles-from-an-OPML-list.md
index 8645b10d..eb66f955 100644
--- a/doc/Download-CSS-styles-for-shaarlis-listed-in-an-opml-file.md
+++ b/doc/Download-CSS-styles-from-an-OPML-list.md
@@ -1,7 +1,8 @@
1#Download CSS styles from an OPML list
1###Download CSS styles for shaarlis listed in an opml file 2###Download CSS styles for shaarlis listed in an opml file
2Example php script: 3Example php script:
3 4
4``` 5```php
5<!---- ?php --> 6<!---- ?php -->
6<!---- Copyright (c) 2014 Nicolas Delsaux (https://github.com/Riduidel) --> 7<!---- Copyright (c) 2014 Nicolas Delsaux (https://github.com/Riduidel) -->
7<!---- License: zlib (http://www.gzip.org/zlib/zlib_license.html) --> 8<!---- License: zlib (http://www.gzip.org/zlib/zlib_license.html) -->
@@ -33,8 +34,8 @@ function createShaarliHashFromOPMLL($opmlFile) {
33 $opmlXml = simplexml_load_string($opml); 34 $opmlXml = simplexml_load_string($opml);
34 $outlineElements = $opmlXml->xpath("body/outline"); 35 $outlineElements = $opmlXml->xpath("body/outline");
35 foreach($outlineElements as $site) { 36 foreach($outlineElements as $site) {
36 $siteUrl = siteUrl((string) $site['htmlUrl']); 37 $siteUrl = siteUrl((string) $site['htmlUrl']);[](.html)
37 $result[$siteUrl]=((string) $site['text']); 38 $result[$siteUrl]=((string) $site['text']);[](.html)
38 } 39 }
39 return $result; 40 return $result;
40} 41}
@@ -46,7 +47,7 @@ function getSiteFolder($url) {
46 47
47function get_http_response_code($theURL) { 48function get_http_response_code($theURL) {
48 $headers = get_headers($theURL); 49 $headers = get_headers($theURL);
49 return substr($headers[0], 9, 3); 50 return substr($headers[0], 9, 3);[](.html)
50} 51}
51 52
52/** 53/**
@@ -121,7 +122,7 @@ function getDirectoryList ($directory) {
121 while ($file = readdir($handler)) { 122 while ($file = readdir($handler)) {
122 // if file isn't this directory or its parent, add it to the results 123 // if file isn't this directory or its parent, add it to the results
123 if ($file != "." && $file != "..") { 124 if ($file != "." && $file != "..") {
124 $results[] = realpath($realPath . "/" . $file); 125 $results[ = realpath($realPath . "/" . $file);](-=-realpath($realPath-.-"/"-.-$file);.html)
125 } 126 }
126 } 127 }
127 // tidy up: close the handler 128 // tidy up: close the handler
@@ -141,7 +142,7 @@ function findKnownStyles() {
141 $configFile = $folder."/config.ini"; 142 $configFile = $folder."/config.ini";
142 if(file_exists($configFile)) { 143 if(file_exists($configFile)) {
143 $iniParameters = parse_ini_file($configFile); 144 $iniParameters = parse_ini_file($configFile);
144 array_push($result, $iniParameters['site_url']); 145 array_push($result, $iniParameters['site_url']);[](.html)
145 } 146 }
146 } 147 }
147 return $result; 148 return $result;
diff --git a/doc/Example-patch---add-new-via-field-for-links.html b/doc/Example-patch---add-new-via-field-for-links.html
index 7df9d253..44352d3e 100644
--- a/doc/Example-patch---add-new-via-field-for-links.html
+++ b/doc/Example-patch---add-new-via-field-for-links.html
@@ -4,7 +4,7 @@
4 <meta charset="utf-8"> 4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc"> 5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title></title> 7 <title>Shaarli - Example patch add new via field for links</title>
8 <style type="text/css">code{white-space: pre;}</style> 8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]> 9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> 10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
@@ -12,12 +12,55 @@
12 <link rel="stylesheet" href="github-markdown.css"> 12 <link rel="stylesheet" href="github-markdown.css">
13</head> 13</head>
14<body> 14<body>
15<div id="local-sidebar">
16<ul>
17<li><a href="Home.html">Home</a></li>
18<li>Installation
19<ul>
20<li><a href="Server-requirements.html">Server requirements</a></li>
21<li><a href="Server-configuration.html">Server configuration</a></li>
22<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
23</ul></li>
24<li><a href="Usage.html">Usage</a>
25<ul>
26<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
27<li><a href="Firefox-share.html">Firefox share</a></li>
28<li><a href="RSS-feeds.html">RSS feeds</a></li>
29</ul></li>
30<li>How To
31<ul>
32<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
33<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
34<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
35</ul></li>
36<li><a href="Troubleshooting.html">Troubleshooting</a></li>
37<li><a href="Development.html">Development</a>
38<ul>
39<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
40<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
41<li><a href="Directory-structure.html">Directory structure</a></li>
42<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
43<li><a href="Plugin-System.html">Plugin System</a></li>
44<li><a href="Security.html">Security</a></li>
45<li><a href="Static-analysis.html">Static analysis</a></li>
46<li><a href="Theming.html">Theming</a></li>
47<li><a href="Unit-tests.html">Unit tests</a></li>
48</ul></li>
49<li>About
50<ul>
51<li><a href="FAQ.html">FAQ</a></li>
52<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
53<li><a href="TODO.html">TODO</a></li>
54</ul></li>
55</ul>
56</div>
57<h1 id="example-patch-add-new-via-field-for-links">Example patch add new via field for links</h1>
15<p>Example patch to add a new field (&quot;via&quot;) for links, an input field to set the &quot;via&quot; property from the &quot;edit link&quot; dialog, and display the &quot;via&quot; field in the link list display. <strong>Untested, use at your own risk</strong></p> 58<p>Example patch to add a new field (&quot;via&quot;) for links, an input field to set the &quot;via&quot; property from the &quot;edit link&quot; dialog, and display the &quot;via&quot; field in the link list display. <strong>Untested, use at your own risk</strong></p>
16<p>Thanks to @Knah-Tsaeb in <a href="https://github.com/sebsauvage/Shaarli/pull/158">https://github.com/sebsauvage/Shaarli/pull/158</a></p> 59<p>Thanks to @Knah-Tsaeb in <a href="https://github.com/sebsauvage/Shaarli/pull/158" class="uri">https://github.com/sebsauvage/Shaarli/pull/158</a></p>
17<pre><code>From e0f363c18e8fe67990ed2bb1a08652e24e70bbcb Mon Sep 17 00:00:00 2001 60<pre><code>From e0f363c18e8fe67990ed2bb1a08652e24e70bbcb Mon Sep 17 00:00:00 2001
18From: Knah Tsaeb &lt;knah-tsaeb@knah-tsaeb.org&gt; 61From: Knah Tsaeb &lt;knah-tsaeb@knah-tsaeb.org&gt;
19Date: Fri, 11 Oct 2013 15:18:37 +0200 62Date: Fri, 11 Oct 2013 15:18:37 +0200
20Subject: [PATCH] Add a &quot;via&quot;/origin property for links, add new input in &quot;edit link&quot; dialog 63Subject: [PATCH] Add a &quot;via&quot;/origin property for links, add new input in &quot;edit link&quot; dialog[](.html)
21Thanks to: 64Thanks to:
22* https://github.com/Knah-Tsaeb/Shaarli/commit/040eb18ec8cdabd5ea855e108f81f97fbf0478c4 65* https://github.com/Knah-Tsaeb/Shaarli/commit/040eb18ec8cdabd5ea855e108f81f97fbf0478c4
23* https://github.com/Knah-Tsaeb/Shaarli/commit/4123658eae44d7564d1128ce52ddd5689efee813 66* https://github.com/Knah-Tsaeb/Shaarli/commit/4123658eae44d7564d1128ce52ddd5689efee813
@@ -33,27 +76,27 @@ diff --git a/index.php b/index.php
33index 6fae2f8..53f798e 100644 76index 6fae2f8..53f798e 100644
34--- a/index.php 77--- a/index.php
35+++ b/index.php 78+++ b/index.php
36@@ -436,6 +436,12 @@ if (isset($_POST[&#39;login&#39;])) 79@@ -436,6 +436,12 @@ if (isset($_POST[&#39;login&#39;]))[](.html)
37 // ------------------------------------------------------------------------------------------ 80 // ------------------------------------------------------------------------------------------
38 // Misc utility functions: 81 // Misc utility functions:
39 82
40+// Try to get just domain for @via 83+// Try to get just domain for @via
41+function getJustDomain($url){ 84+function getJustDomain($url){
42+ $parts = parse_url($url); 85+ $parts = parse_url($url);
43+ return trim($parts[&#39;host&#39;]); 86+ return trim($parts[&#39;host&#39;]);[](.html)
44+ } 87+ }
45+ 88+
46 // Returns the server URL (including port and http/https), without path. 89 // Returns the server URL (including port and http/https), without path.
47 // e.g. &quot;http://myserver.com:8080&quot; 90 // e.g. &quot;http://myserver.com:8080&quot;
48 // You can append $_SERVER[&#39;SCRIPT_NAME&#39;] to get the current script URL. 91 // You can append $_SERVER[&#39;SCRIPT_NAME&#39;] to get the current script URL.[](.html)
49@@ -799,7 +805,8 @@ class linkdb implements Iterator, Countable, ArrayAccess 92@@ -799,7 +805,8 @@ class linkdb implements Iterator, Countable, ArrayAccess
50 $found= (strpos(strtolower($l[&#39;title&#39;]),$s)!==false) 93 $found= (strpos(strtolower($l[&#39;title&#39;]),$s)!==false)[](.html)
51 || (strpos(strtolower($l[&#39;description&#39;]),$s)!==false) 94 || (strpos(strtolower($l[&#39;description&#39;]),$s)!==false)[](.html)
52 || (strpos(strtolower($l[&#39;url&#39;]),$s)!==false) 95 || (strpos(strtolower($l[&#39;url&#39;]),$s)!==false)[](.html)
53- || (strpos(strtolower($l[&#39;tags&#39;]),$s)!==false); 96- || (strpos(strtolower($l[&#39;tags&#39;]),$s)!==false);[](.html)
54+ || (strpos(strtolower($l[&#39;tags&#39;]),$s)!==false) 97+ || (strpos(strtolower($l[&#39;tags&#39;]),$s)!==false)[](.html)
55+ || (!empty($l[&#39;via&#39;]) &amp;&amp; (strpos(strtolower($l[&#39;via&#39;]),$s)!==false)); 98+ || (!empty($l[&#39;via&#39;]) &amp;&amp; (strpos(strtolower($l[&#39;via&#39;]),$s)!==false));[](.html)
56 if ($found) $filtered[$l[&#39;linkdate&#39;]] = $l; 99 if ($found) $filtered[$l[&#39;linkdate&#39;[ = $l;](-=-$l;.html)
57 } 100 }
58 krsort($filtered); 101 krsort($filtered);
59@@ -814,7 +821,7 @@ class linkdb implements Iterator, Countable, ArrayAccess 102@@ -814,7 +821,7 @@ class linkdb implements Iterator, Countable, ArrayAccess
@@ -63,74 +106,74 @@ index 6fae2f8..53f798e 100644
63- foreach($this-&gt;links as $l) 106- foreach($this-&gt;links as $l)
64+ foreach($this-&gt; links as $l) 107+ foreach($this-&gt; links as $l)
65 { 108 {
66 $linktags = explode(&#39; &#39;,($casesensitive?$l[&#39;tags&#39;]:strtolower($l[&#39;tags&#39;]))); 109 $linktags = explode(&#39; &#39;,($casesensitive?$l[&#39;tags&#39;]:strtolower($l[&#39;tags&#39;])));[](.html)
67 if (count(array_intersect($linktags,$searchtags)) == count($searchtags)) 110 if (count(array_intersect($linktags,$searchtags)) == count($searchtags))
68@@ -905,7 +912,7 @@ function showRSS() 111@@ -905,7 +912,7 @@ function showRSS()
69 else $linksToDisplay = $LINKSDB; 112 else $linksToDisplay = $LINKSDB;
70 $nblinksToDisplay = 50; // Number of links to display. 113 $nblinksToDisplay = 50; // Number of links to display.
71 if (!empty($_GET[&#39;nb&#39;])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links. 114 if (!empty($_GET[&#39;nb&#39;])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links.[](.html)
72- { 115- {
73+ { 116+ {
74 $nblinksToDisplay = $_GET[&#39;nb&#39;]==&#39;all&#39; ? count($linksToDisplay) : max($_GET[&#39;nb&#39;]+0,1) ; 117 $nblinksToDisplay = $_GET[&#39;nb&#39;]==&#39;all&#39; ? count($linksToDisplay) : max($_GET[&#39;nb&#39;]+0,1) ;[](.html)
75 } 118 }
76 119
77@@ -944,7 +951,12 @@ function showRSS() 120@@ -944,7 +951,12 @@ function showRSS()
78 // If user wants permalinks first, put the final link in description 121 // If user wants permalinks first, put the final link in description
79 if ($usepermalinks===true) $descriptionlink = &#39;(&lt;a href=&quot;&#39;.$absurl.&#39;&quot;&gt;Link&lt;/a&gt;)&#39;; 122 if ($usepermalinks===true) $descriptionlink = &#39;(&lt;a href=&quot;&#39;.$absurl.&#39;&quot;&gt;Link&lt;/a&gt;)&#39;;
80 if (strlen($link[&#39;description&#39;])&gt;0) $descriptionlink = &#39;&lt;br&gt;&#39;.$descriptionlink; 123 if (strlen($link[&#39;description&#39;])&gt;0) $descriptionlink = &#39;&lt;br&gt;&#39;.$descriptionlink;[](.html)
81- echo &#39;&lt;description&gt;&lt;![CDATA[&#39;.nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link[&#39;description&#39;])))).$descriptionlink.&#39;]]&gt;&lt;/description&gt;&#39;.&quot;\n&lt;/item&gt;\n&quot;; 124- echo &#39;&lt;description&gt;&lt;![CDATA[&#39;.nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link[&#39;description&#39;])))).$descriptionlink.&#39;[&gt;&lt;/description&gt;&#39;.&quot;\n&lt;/item&gt;\n&quot;;](&gt;&lt;/description&gt;&#39;.&quot;\n&lt;/item&gt;\n&quot;;.html)
82+ if(!empty($link[&#39;via&#39;])){ 125+ if(!empty($link[&#39;via&#39;])){[](.html)
83+ $via = &#39;&lt;br&gt;Origine =&gt; &lt;a href=&quot;&#39;.htmlspecialchars($link[&#39;via&#39;]).&#39;&quot;&gt;&#39;.htmlspecialchars(getJustDomain($link[&#39;via&#39;])).&#39;&lt;/a&gt;&#39;; 126+ $via = &#39;&lt;br&gt;Origine =&gt; &lt;a href=&quot;&#39;.htmlspecialchars($link[&#39;via&#39;]).&#39;&quot;&gt;&#39;.htmlspecialchars(getJustDomain($link[&#39;via&#39;])).&#39;&lt;/a&gt;&#39;;[](.html)
84+ } else { 127+ } else {
85+ $via = &#39;&#39;; 128+ $via = &#39;&#39;;
86+ } 129+ }
87+ echo &#39;&lt;description&gt;&lt;![CDATA[&#39;.nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link[&#39;description&#39;])))).$via.$descriptionlink.&#39;]]&gt;&lt;/description&gt;&#39;.&quot;\n&lt;/item&gt;\n&quot;; 130+ echo &#39;&lt;description&gt;&lt;![CDATA[&#39;.nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link[&#39;description&#39;])))).$via.$descriptionlink.&#39;[&gt;&lt;/description&gt;&#39;.&quot;\n&lt;/item&gt;\n&quot;;](&gt;&lt;/description&gt;&#39;.&quot;\n&lt;/item&gt;\n&quot;;.html)
88 $i++; 131 $i++;
89 } 132 }
90 echo &#39;&lt;/channel&gt;&lt;/rss&gt;&lt;!-- Cached version of &#39;.htmlspecialchars(pageUrl()).&#39; --&gt;&#39;; 133 echo &#39;&lt;/channel&gt;&lt;/rss&gt;&lt;!-- Cached version of &#39;.htmlspecialchars(pageUrl()).&#39; --&gt;&#39;;
91@@ -980,7 +992,7 @@ function showATOM() 134@@ -980,7 +992,7 @@ function showATOM()
92 else $linksToDisplay = $LINKSDB; 135 else $linksToDisplay = $LINKSDB;
93 $nblinksToDisplay = 50; // Number of links to display. 136 $nblinksToDisplay = 50; // Number of links to display.
94 if (!empty($_GET[&#39;nb&#39;])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links. 137 if (!empty($_GET[&#39;nb&#39;])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links.[](.html)
95- { 138- {
96+ { 139+ {
97 $nblinksToDisplay = $_GET[&#39;nb&#39;]==&#39;all&#39; ? count($linksToDisplay) : max($_GET[&#39;nb&#39;]+0,1) ; 140 $nblinksToDisplay = $_GET[&#39;nb&#39;]==&#39;all&#39; ? count($linksToDisplay) : max($_GET[&#39;nb&#39;]+0,1) ;[](.html)
98 } 141 }
99 142
100@@ -1006,11 +1018,16 @@ function showATOM() 143@@ -1006,11 +1018,16 @@ function showATOM()
101 144
102 // Add permalink in description 145 // Add permalink in description
103 $descriptionlink = htmlspecialchars(&#39;(&lt;a href=&quot;&#39;.$guid.&#39;&quot;&gt;Permalink&lt;/a&gt;)&#39;); 146 $descriptionlink = htmlspecialchars(&#39;(&lt;a href=&quot;&#39;.$guid.&#39;&quot;&gt;Permalink&lt;/a&gt;)&#39;);
104+ if(isset($link[&#39;via&#39;]) &amp;&amp; !empty($link[&#39;via&#39;])){ 147+ if(isset($link[&#39;via&#39;]) &amp;&amp; !empty($link[&#39;via&#39;])){[](.html)
105+ $via = htmlspecialchars(&#39;&lt;/br&gt; Origine =&gt; &lt;a href=&quot;&#39;.$link[&#39;via&#39;].&#39;&quot;&gt;&#39;.getJustDomain($link[&#39;via&#39;]).&#39;&lt;/a&gt;&#39;); 148+ $via = htmlspecialchars(&#39;&lt;/br&gt; Origine =&gt; &lt;a href=&quot;&#39;.$link[&#39;via&#39;].&#39;&quot;&gt;&#39;.getJustDomain($link[&#39;via&#39;]).&#39;&lt;/a&gt;&#39;);[](.html)
106+ } else { 149+ } else {
107+ $via = &#39;&#39;; 150+ $via = &#39;&#39;;
108+ } 151+ }
109 // If user wants permalinks first, put the final link in description 152 // If user wants permalinks first, put the final link in description
110 if ($usepermalinks===true) $descriptionlink = htmlspecialchars(&#39;(&lt;a href=&quot;&#39;.$absurl.&#39;&quot;&gt;Link&lt;/a&gt;)&#39;); 153 if ($usepermalinks===true) $descriptionlink = htmlspecialchars(&#39;(&lt;a href=&quot;&#39;.$absurl.&#39;&quot;&gt;Link&lt;/a&gt;)&#39;);
111 if (strlen($link[&#39;description&#39;])&gt;0) $descriptionlink = &#39;&amp;lt;br&amp;gt;&#39;.$descriptionlink; 154 if (strlen($link[&#39;description&#39;])&gt;0) $descriptionlink = &#39;&amp;lt;br&amp;gt;&#39;.$descriptionlink;[](.html)
112 155
113- $entries.=&#39;&lt;content type=&quot;html&quot;&gt;&#39;.htmlspecialchars(nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link[&#39;description&#39;]))))).$descriptionlink.&quot;&lt;/content&gt;\n&quot;; 156- $entries.=&#39;&lt;content type=&quot;html&quot;&gt;&#39;.htmlspecialchars(nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link[&#39;description&#39;]))))).$descriptionlink.&quot;&lt;/content&gt;\n&quot;;[](.html)
114+ $entries.=&#39;&lt;content type=&quot;html&quot;&gt;&#39;.htmlspecialchars(nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link[&#39;description&#39;]))))).$descriptionlink.$via.&quot;&lt;/content&gt;\n&quot;; 157+ $entries.=&#39;&lt;content type=&quot;html&quot;&gt;&#39;.htmlspecialchars(nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link[&#39;description&#39;]))))).$descriptionlink.$via.&quot;&lt;/content&gt;\n&quot;;[](.html)
115 if ($link[&#39;tags&#39;]!=&#39;&#39;) // Adding tags to each ATOM entry (as mentioned in ATOM specification) 158 if ($link[&#39;tags&#39;]!=&#39;&#39;) // Adding tags to each ATOM entry (as mentioned in ATOM specification)[](.html)
116 { 159 {
117 foreach(explode(&#39; &#39;,$link[&#39;tags&#39;]) as $tag) 160 foreach(explode(&#39; &#39;,$link[&#39;tags&#39;]) as $tag)[](.html)
118@@ -1478,7 +1495,7 @@ function renderPage() 161@@ -1478,7 +1495,7 @@ function renderPage()
119 if (!startsWith($url,&#39;http:&#39;) &amp;&amp; !startsWith($url,&#39;https:&#39;) &amp;&amp; !startsWith($url,&#39;ftp:&#39;) &amp;&amp; !startsWith($url,&#39;magnet:&#39;) &amp;&amp; !startsWith($url,&#39;?&#39;)) 162 if (!startsWith($url,&#39;http:&#39;) &amp;&amp; !startsWith($url,&#39;https:&#39;) &amp;&amp; !startsWith($url,&#39;ftp:&#39;) &amp;&amp; !startsWith($url,&#39;magnet:&#39;) &amp;&amp; !startsWith($url,&#39;?&#39;))
120 $url = &#39;http://&#39;.$url; 163 $url = &#39;http://&#39;.$url;
121 $link = array(&#39;title&#39;=&gt;trim($_POST[&#39;lf_title&#39;]),&#39;url&#39;=&gt;$url,&#39;description&#39;=&gt;trim($_POST[&#39;lf_description&#39;]),&#39;private&#39;=&gt;(isset($_POST[&#39;lf_private&#39;]) ? 1 : 0), 164 $link = array(&#39;title&#39;=&gt;trim($_POST[&#39;lf_title&#39;]),&#39;url&#39;=&gt;$url,&#39;description&#39;=&gt;trim($_POST[&#39;lf_description&#39;]),&#39;private&#39;=&gt;(isset($_POST[&#39;lf_private&#39;]) ? 1 : 0),[](.html)
122- &#39;linkdate&#39;=&gt;$linkdate,&#39;tags&#39;=&gt;str_replace(&#39;,&#39;,&#39; &#39;,$tags)); 165- &#39;linkdate&#39;=&gt;$linkdate,&#39;tags&#39;=&gt;str_replace(&#39;,&#39;,&#39; &#39;,$tags));
123+ &#39;linkdate&#39;=&gt;$linkdate,&#39;tags&#39;=&gt;str_replace(&#39;,&#39;,&#39; &#39;,$tags), &#39;via&#39;=&gt;trim($_POST[&#39;lf_via&#39;])); 166+ &#39;linkdate&#39;=&gt;$linkdate,&#39;tags&#39;=&gt;str_replace(&#39;,&#39;,&#39; &#39;,$tags), &#39;via&#39;=&gt;trim($_POST[&#39;lf_via&#39;]));[](.html)
124 if ($link[&#39;title&#39;]==&#39;&#39;) $link[&#39;title&#39;]=$link[&#39;url&#39;]; // If title is empty, use the URL as title. 167 if ($link[&#39;title&#39;]==&#39;&#39;) $link[&#39;title&#39;]=$link[&#39;url&#39;]; // If title is empty, use the URL as title.[](.html)
125 $LINKSDB[$linkdate] = $link; 168 $LINKSDB[$linkdate] = $link;[](.html)
126 $LINKSDB-&gt;savedb(); // Save to disk. 169 $LINKSDB-&gt;savedb(); // Save to disk.
127@@ -1556,7 +1573,8 @@ function renderPage() 170@@ -1556,7 +1573,8 @@ function renderPage()
128 $title = (empty($_GET[&#39;title&#39;]) ? &#39;&#39; : $_GET[&#39;title&#39;] ); // Get title if it was provided in URL (by the bookmarklet). 171 $title = (empty($_GET[&#39;title&#39;]) ? &#39;&#39; : $_GET[&#39;title&#39;] ); // Get title if it was provided in URL (by the bookmarklet).[](.html)
129 $description = (empty($_GET[&#39;description&#39;]) ? &#39;&#39; : $_GET[&#39;description&#39;]); // Get description if it was provided in URL (by the bookmarklet). [Bronco added that] 172 $description = (empty($_GET[&#39;description&#39;]) ? &#39;&#39; : $_GET[&#39;description&#39;]); // Get description if it was provided in URL (by the bookmarklet). [Bronco added that][](.html)
130 $tags = (empty($_GET[&#39;tags&#39;]) ? &#39;&#39; : $_GET[&#39;tags&#39;] ); // Get tags if it was provided in URL 173 $tags = (empty($_GET[&#39;tags&#39;]) ? &#39;&#39; : $_GET[&#39;tags&#39;] ); // Get tags if it was provided in URL[](.html)
131- $private = (!empty($_GET[&#39;private&#39;]) &amp;&amp; $_GET[&#39;private&#39;] === &quot;1&quot; ? 1 : 0); // Get private if it was provided in URL 174- $private = (!empty($_GET[&#39;private&#39;]) &amp;&amp; $_GET[&#39;private&#39;] === &quot;1&quot; ? 1 : 0); // Get private if it was provided in URL [](.html)
132+ $via = (empty($_GET[&#39;via&#39;]) ? &#39;&#39; : $_GET[&#39;via&#39;] ); 175+ $via = (empty($_GET[&#39;via&#39;]) ? &#39;&#39; : $_GET[&#39;via&#39;] );[](.html)
133+ $private = (!empty($_GET[&#39;private&#39;]) &amp;&amp; $_GET[&#39;private&#39;] === &quot;1&quot; ? 1 : 0); // Get private if it was provided in URL 176+ $private = (!empty($_GET[&#39;private&#39;]) &amp;&amp; $_GET[&#39;private&#39;] === &quot;1&quot; ? 1 : 0); // Get private if it was provided in URL[](.html)
134 if (($url!=&#39;&#39;) &amp;&amp; parse_url($url,PHP_URL_SCHEME)==&#39;&#39;) $url = &#39;http://&#39;.$url; 177 if (($url!=&#39;&#39;) &amp;&amp; parse_url($url,PHP_URL_SCHEME)==&#39;&#39;) $url = &#39;http://&#39;.$url;
135 // If this is an HTTP link, we try go get the page to extract the title (otherwise we will to straight to the edit form.) 178 // If this is an HTTP link, we try go get the page to extract the title (otherwise we will to straight to the edit form.)
136 if (empty($title) &amp;&amp; parse_url($url,PHP_URL_SCHEME)==&#39;http&#39;) 179 if (empty($title) &amp;&amp; parse_url($url,PHP_URL_SCHEME)==&#39;http&#39;)
@@ -141,10 +184,10 @@ index 6fae2f8..53f798e 100644
141- 184-
142+ 185+
143 // If found, extract encoding. 186 // If found, extract encoding.
144 if (!empty($meta[0])) 187 if (!empty($meta[0]))[](.html)
145 { 188 {
146@@ -1577,7 +1595,7 @@ function renderPage() 189@@ -1577,7 +1595,7 @@ function renderPage()
147 $html_charset = (!empty($enc[1])) ? strtolower($enc[1]) : &#39;utf-8&#39;; 190 $html_charset = (!empty($enc[1])) ? strtolower($enc[1]) : &#39;utf-8&#39;;[](.html)
148 } 191 }
149 else { $html_charset = &#39;utf-8&#39;; } 192 else { $html_charset = &#39;utf-8&#39;; }
150- 193-
@@ -162,13 +205,13 @@ index 6fae2f8..53f798e 100644
162 205
163 $PAGE = new pageBuilder; 206 $PAGE = new pageBuilder;
164@@ -1842,6 +1860,9 @@ function buildLinkList($PAGE,$LINKSDB) 207@@ -1842,6 +1860,9 @@ function buildLinkList($PAGE,$LINKSDB)
165 $taglist = explode(&#39; &#39;,$link[&#39;tags&#39;]); 208 $taglist = explode(&#39; &#39;,$link[&#39;tags&#39;]);[](.html)
166 uasort($taglist, &#39;strcasecmp&#39;); 209 uasort($taglist, &#39;strcasecmp&#39;);
167 $link[&#39;taglist&#39;]=$taglist; 210 $link[&#39;taglist&#39;]=$taglist;[](.html)
168+ if(!empty($link[&#39;via&#39;])){ 211+ if(!empty($link[&#39;via&#39;])){[](.html)
169+ $link[&#39;via&#39;]=htmlspecialchars($link[&#39;via&#39;]); 212+ $link[&#39;via&#39;]=htmlspecialchars($link[&#39;via&#39;]);[](.html)
170+ } 213+ }
171 $linkDisp[$keys[$i]] = $link; 214 $linkDisp[$keys[$i[ = $link;](-=-$link;.html)
172 $i++; 215 $i++;
173 } 216 }
174diff --git a/tpl/editlink.html b/tpl/editlink.html 217diff --git a/tpl/editlink.html b/tpl/editlink.html
@@ -180,7 +223,7 @@ index 4a2c30c..14d4f9c 100644
180 &lt;i&gt;Description&lt;/i&gt;&lt;br&gt;&lt;textarea name=&quot;lf_description&quot; rows=&quot;4&quot; cols=&quot;25&quot; style=&quot;width:100%&quot;&gt;{$link.description|htmlspecialchars}&lt;/textarea&gt;&lt;br&gt; 223 &lt;i&gt;Description&lt;/i&gt;&lt;br&gt;&lt;textarea name=&quot;lf_description&quot; rows=&quot;4&quot; cols=&quot;25&quot; style=&quot;width:100%&quot;&gt;{$link.description|htmlspecialchars}&lt;/textarea&gt;&lt;br&gt;
181 &lt;i&gt;Tags&lt;/i&gt;&lt;br&gt;&lt;input type=&quot;text&quot; id=&quot;lf_tags&quot; name=&quot;lf_tags&quot; value=&quot;{$link.tags|htmlspecialchars}&quot; style=&quot;width:100%&quot;&gt;&lt;br&gt; 224 &lt;i&gt;Tags&lt;/i&gt;&lt;br&gt;&lt;input type=&quot;text&quot; id=&quot;lf_tags&quot; name=&quot;lf_tags&quot; value=&quot;{$link.tags|htmlspecialchars}&quot; style=&quot;width:100%&quot;&gt;&lt;br&gt;
182+ &lt;i&gt;Origine&lt;/i&gt;&lt;br&gt;&lt;input type=&quot;text&quot; name=&quot;lf_via&quot; value=&quot;{$link.via|htmlspecialchars}&quot; style=&quot;width:100%&quot;&gt;&lt;br&gt; 225+ &lt;i&gt;Origine&lt;/i&gt;&lt;br&gt;&lt;input type=&quot;text&quot; name=&quot;lf_via&quot; value=&quot;{$link.via|htmlspecialchars}&quot; style=&quot;width:100%&quot;&gt;&lt;br&gt;
183 {if condition=&quot;($link_is_new &amp;&amp; $GLOBALS[&#39;privateLinkByDefault&#39;]==true) || $link.private == true&quot;} 226 {if condition=&quot;($link_is_new &amp;&amp; $GLOBALS[&#39;privateLinkByDefault&#39;]==true) || $link.private == true&quot;}[](.html)
184 &lt;input type=&quot;checkbox&quot; checked=&quot;checked&quot; name=&quot;lf_private&quot; id=&quot;lf_private&quot;&gt; 227 &lt;input type=&quot;checkbox&quot; checked=&quot;checked&quot; name=&quot;lf_private&quot; id=&quot;lf_private&quot;&gt;
185 &amp;nbsp;&lt;label for=&quot;lf_private&quot;&gt;&lt;i&gt;Private&lt;/i&gt;&lt;/label&gt;&lt;br&gt; 228 &amp;nbsp;&lt;label for=&quot;lf_private&quot;&gt;&lt;i&gt;Private&lt;/i&gt;&lt;/label&gt;&lt;br&gt;
186diff --git a/tpl/linklist.html b/tpl/linklist.html 229diff --git a/tpl/linklist.html b/tpl/linklist.html
@@ -192,7 +235,7 @@ index ddc38cb..0a8475f 100644
192 &lt;br&gt; 235 &lt;br&gt;
193 {if=&quot;$value.description&quot;}&lt;div class=&quot;linkdescription&quot;{if condition=&quot;$search_type==&#39;permalink&#39;&quot;} style=&quot;max-height:none !important;&quot;{/if}&gt;{$value.description}&lt;/div&gt;{/if} 236 {if=&quot;$value.description&quot;}&lt;div class=&quot;linkdescription&quot;{if condition=&quot;$search_type==&#39;permalink&#39;&quot;} style=&quot;max-height:none !important;&quot;{/if}&gt;{$value.description}&lt;/div&gt;{/if}
194+ {if condition=&quot;isset($value.via) &amp;&amp; !empty($value.via)&quot;}&lt;div&gt;&lt;a href=&quot;{$value.via}&quot;&gt;Origine =&gt; {$value.via|getJustDomain}&lt;/a&gt;&lt;/div&gt;{/if} 237+ {if condition=&quot;isset($value.via) &amp;&amp; !empty($value.via)&quot;}&lt;div&gt;&lt;a href=&quot;{$value.via}&quot;&gt;Origine =&gt; {$value.via|getJustDomain}&lt;/a&gt;&lt;/div&gt;{/if}
195 {if=&quot;!$GLOBALS[&#39;config&#39;][&#39;HIDE_TIMESTAMPS&#39;] || isLoggedIn()&quot;} 238 {if=&quot;!$GLOBALS[&#39;config&#39;[&#39;HIDE_TIMESTAMPS&#39;] || isLoggedIn()&quot;}](&#39;HIDE_TIMESTAMPS&#39;]-||-isLoggedIn()&quot;}.html)
196 &lt;span class=&quot;linkdate&quot; title=&quot;Permalink&quot;&gt;&lt;a href=&quot;?{$value.linkdate|smallHash}&quot;&gt;{$value.localdate|htmlspecialchars} - permalink&lt;/a&gt; - &lt;/span&gt; 239 &lt;span class=&quot;linkdate&quot; title=&quot;Permalink&quot;&gt;&lt;a href=&quot;?{$value.linkdate|smallHash}&quot;&gt;{$value.localdate|htmlspecialchars} - permalink&lt;/a&gt; - &lt;/span&gt;
197 {else} 240 {else}
198-- 241--
diff --git a/doc/Example-patch---add-new-via-field-for-links.md b/doc/Example-patch---add-new-via-field-for-links.md
index d84ef25a..883adf40 100644
--- a/doc/Example-patch---add-new-via-field-for-links.md
+++ b/doc/Example-patch---add-new-via-field-for-links.md
@@ -1,3 +1,4 @@
1#Example patch add new via field for links
1Example patch to add a new field ("via") for links, an input field to set the "via" property from the "edit link" dialog, and display the "via" field in the link list display. **Untested, use at your own risk** 2Example patch to add a new field ("via") for links, an input field to set the "via" property from the "edit link" dialog, and display the "via" field in the link list display. **Untested, use at your own risk**
2 3
3Thanks to @Knah-Tsaeb in https://github.com/sebsauvage/Shaarli/pull/158 4Thanks to @Knah-Tsaeb in https://github.com/sebsauvage/Shaarli/pull/158
@@ -6,7 +7,7 @@ Thanks to @Knah-Tsaeb in https://github.com/sebsauvage/Shaarli/pull/158
6From e0f363c18e8fe67990ed2bb1a08652e24e70bbcb Mon Sep 17 00:00:00 2001 7From e0f363c18e8fe67990ed2bb1a08652e24e70bbcb Mon Sep 17 00:00:00 2001
7From: Knah Tsaeb <knah-tsaeb@knah-tsaeb.org> 8From: Knah Tsaeb <knah-tsaeb@knah-tsaeb.org>
8Date: Fri, 11 Oct 2013 15:18:37 +0200 9Date: Fri, 11 Oct 2013 15:18:37 +0200
9Subject: [PATCH] Add a "via"/origin property for links, add new input in "edit link" dialog 10Subject: [PATCH] Add a "via"/origin property for links, add new input in "edit link" dialog[](.html)
10Thanks to: 11Thanks to:
11* https://github.com/Knah-Tsaeb/Shaarli/commit/040eb18ec8cdabd5ea855e108f81f97fbf0478c4 12* https://github.com/Knah-Tsaeb/Shaarli/commit/040eb18ec8cdabd5ea855e108f81f97fbf0478c4
12* https://github.com/Knah-Tsaeb/Shaarli/commit/4123658eae44d7564d1128ce52ddd5689efee813 13* https://github.com/Knah-Tsaeb/Shaarli/commit/4123658eae44d7564d1128ce52ddd5689efee813
@@ -22,27 +23,27 @@ diff --git a/index.php b/index.php
22index 6fae2f8..53f798e 100644 23index 6fae2f8..53f798e 100644
23--- a/index.php 24--- a/index.php
24+++ b/index.php 25+++ b/index.php
25@@ -436,6 +436,12 @@ if (isset($_POST['login'])) 26@@ -436,6 +436,12 @@ if (isset($_POST['login']))[](.html)
26 // ------------------------------------------------------------------------------------------ 27 // ------------------------------------------------------------------------------------------
27 // Misc utility functions: 28 // Misc utility functions:
28 29
29+// Try to get just domain for @via 30+// Try to get just domain for @via
30+function getJustDomain($url){ 31+function getJustDomain($url){
31+ $parts = parse_url($url); 32+ $parts = parse_url($url);
32+ return trim($parts['host']); 33+ return trim($parts['host']);[](.html)
33+ } 34+ }
34+ 35+
35 // Returns the server URL (including port and http/https), without path. 36 // Returns the server URL (including port and http/https), without path.
36 // e.g. "http://myserver.com:8080" 37 // e.g. "http://myserver.com:8080"
37 // You can append $_SERVER['SCRIPT_NAME'] to get the current script URL. 38 // You can append $_SERVER['SCRIPT_NAME'] to get the current script URL.[](.html)
38@@ -799,7 +805,8 @@ class linkdb implements Iterator, Countable, ArrayAccess 39@@ -799,7 +805,8 @@ class linkdb implements Iterator, Countable, ArrayAccess
39 $found= (strpos(strtolower($l['title']),$s)!==false) 40 $found= (strpos(strtolower($l['title']),$s)!==false)[](.html)
40 || (strpos(strtolower($l['description']),$s)!==false) 41 || (strpos(strtolower($l['description']),$s)!==false)[](.html)
41 || (strpos(strtolower($l['url']),$s)!==false) 42 || (strpos(strtolower($l['url']),$s)!==false)[](.html)
42- || (strpos(strtolower($l['tags']),$s)!==false); 43- || (strpos(strtolower($l['tags']),$s)!==false);[](.html)
43+ || (strpos(strtolower($l['tags']),$s)!==false) 44+ || (strpos(strtolower($l['tags']),$s)!==false)[](.html)
44+ || (!empty($l['via']) && (strpos(strtolower($l['via']),$s)!==false)); 45+ || (!empty($l['via']) && (strpos(strtolower($l['via']),$s)!==false));[](.html)
45 if ($found) $filtered[$l['linkdate']] = $l; 46 if ($found) $filtered[$l['linkdate'[ = $l;](-=-$l;.html)
46 } 47 }
47 krsort($filtered); 48 krsort($filtered);
48@@ -814,7 +821,7 @@ class linkdb implements Iterator, Countable, ArrayAccess 49@@ -814,7 +821,7 @@ class linkdb implements Iterator, Countable, ArrayAccess
@@ -52,74 +53,74 @@ index 6fae2f8..53f798e 100644
52- foreach($this->links as $l) 53- foreach($this->links as $l)
53+ foreach($this-> links as $l) 54+ foreach($this-> links as $l)
54 { 55 {
55 $linktags = explode(' ',($casesensitive?$l['tags']:strtolower($l['tags']))); 56 $linktags = explode(' ',($casesensitive?$l['tags']:strtolower($l['tags'])));[](.html)
56 if (count(array_intersect($linktags,$searchtags)) == count($searchtags)) 57 if (count(array_intersect($linktags,$searchtags)) == count($searchtags))
57@@ -905,7 +912,7 @@ function showRSS() 58@@ -905,7 +912,7 @@ function showRSS()
58 else $linksToDisplay = $LINKSDB; 59 else $linksToDisplay = $LINKSDB;
59 $nblinksToDisplay = 50; // Number of links to display. 60 $nblinksToDisplay = 50; // Number of links to display.
60 if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links. 61 if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links.[](.html)
61- { 62- {
62+ { 63+ {
63 $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ; 64 $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ;[](.html)
64 } 65 }
65 66
66@@ -944,7 +951,12 @@ function showRSS() 67@@ -944,7 +951,12 @@ function showRSS()
67 // If user wants permalinks first, put the final link in description 68 // If user wants permalinks first, put the final link in description
68 if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)'; 69 if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)';
69 if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink; 70 if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink;[](.html)
70- echo '<description><![CDATA['.nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description'])))).$descriptionlink.']]></description>'."\n</item>\n"; 71- echo '<description><![CDATA['.nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description'])))).$descriptionlink.'[></description>'."\n</item>\n";](></description>'."\n</item>\n";.html)
71+ if(!empty($link['via'])){ 72+ if(!empty($link['via'])){[](.html)
72+ $via = '<br>Origine => <a href="'.htmlspecialchars($link['via']).'">'.htmlspecialchars(getJustDomain($link['via'])).'</a>'; 73+ $via = '<br>Origine => <a href="'.htmlspecialchars($link['via']).'">'.htmlspecialchars(getJustDomain($link['via'])).'</a>';[](.html)
73+ } else { 74+ } else {
74+ $via = ''; 75+ $via = '';
75+ } 76+ }
76+ echo '<description><![CDATA['.nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description'])))).$via.$descriptionlink.']]></description>'."\n</item>\n"; 77+ echo '<description><![CDATA['.nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description'])))).$via.$descriptionlink.'[></description>'."\n</item>\n";](></description>'."\n</item>\n";.html)
77 $i++; 78 $i++;
78 } 79 }
79 echo '</channel></rss><!-- Cached version of '.htmlspecialchars(pageUrl()).' -->'; 80 echo '</channel></rss><!-- Cached version of '.htmlspecialchars(pageUrl()).' -->';
80@@ -980,7 +992,7 @@ function showATOM() 81@@ -980,7 +992,7 @@ function showATOM()
81 else $linksToDisplay = $LINKSDB; 82 else $linksToDisplay = $LINKSDB;
82 $nblinksToDisplay = 50; // Number of links to display. 83 $nblinksToDisplay = 50; // Number of links to display.
83 if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links. 84 if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links.[](.html)
84- { 85- {
85+ { 86+ {
86 $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ; 87 $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ;[](.html)
87 } 88 }
88 89
89@@ -1006,11 +1018,16 @@ function showATOM() 90@@ -1006,11 +1018,16 @@ function showATOM()
90 91
91 // Add permalink in description 92 // Add permalink in description
92 $descriptionlink = htmlspecialchars('(<a href="'.$guid.'">Permalink</a>)'); 93 $descriptionlink = htmlspecialchars('(<a href="'.$guid.'">Permalink</a>)');
93+ if(isset($link['via']) && !empty($link['via'])){ 94+ if(isset($link['via']) && !empty($link['via'])){[](.html)
94+ $via = htmlspecialchars('</br> Origine => <a href="'.$link['via'].'">'.getJustDomain($link['via']).'</a>'); 95+ $via = htmlspecialchars('</br> Origine => <a href="'.$link['via'].'">'.getJustDomain($link['via']).'</a>');[](.html)
95+ } else { 96+ } else {
96+ $via = ''; 97+ $via = '';
97+ } 98+ }
98 // If user wants permalinks first, put the final link in description 99 // If user wants permalinks first, put the final link in description
99 if ($usepermalinks===true) $descriptionlink = htmlspecialchars('(<a href="'.$absurl.'">Link</a>)'); 100 if ($usepermalinks===true) $descriptionlink = htmlspecialchars('(<a href="'.$absurl.'">Link</a>)');
100 if (strlen($link['description'])>0) $descriptionlink = '&lt;br&gt;'.$descriptionlink; 101 if (strlen($link['description'])>0) $descriptionlink = '&lt;br&gt;'.$descriptionlink;[](.html)
101 102
102- $entries.='<content type="html">'.htmlspecialchars(nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))))).$descriptionlink."</content>\n"; 103- $entries.='<content type="html">'.htmlspecialchars(nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))))).$descriptionlink."</content>\n";[](.html)
103+ $entries.='<content type="html">'.htmlspecialchars(nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))))).$descriptionlink.$via."</content>\n"; 104+ $entries.='<content type="html">'.htmlspecialchars(nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))))).$descriptionlink.$via."</content>\n";[](.html)
104 if ($link['tags']!='') // Adding tags to each ATOM entry (as mentioned in ATOM specification) 105 if ($link['tags']!='') // Adding tags to each ATOM entry (as mentioned in ATOM specification)[](.html)
105 { 106 {
106 foreach(explode(' ',$link['tags']) as $tag) 107 foreach(explode(' ',$link['tags']) as $tag)[](.html)
107@@ -1478,7 +1495,7 @@ function renderPage() 108@@ -1478,7 +1495,7 @@ function renderPage()
108 if (!startsWith($url,'http:') && !startsWith($url,'https:') && !startsWith($url,'ftp:') && !startsWith($url,'magnet:') && !startsWith($url,'?')) 109 if (!startsWith($url,'http:') && !startsWith($url,'https:') && !startsWith($url,'ftp:') && !startsWith($url,'magnet:') && !startsWith($url,'?'))
109 $url = 'http://'.$url; 110 $url = 'http://'.$url;
110 $link = array('title'=>trim($_POST['lf_title']),'url'=>$url,'description'=>trim($_POST['lf_description']),'private'=>(isset($_POST['lf_private']) ? 1 : 0), 111 $link = array('title'=>trim($_POST['lf_title']),'url'=>$url,'description'=>trim($_POST['lf_description']),'private'=>(isset($_POST['lf_private']) ? 1 : 0),[](.html)
111- 'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags)); 112- 'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags));
112+ 'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags), 'via'=>trim($_POST['lf_via'])); 113+ 'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags), 'via'=>trim($_POST['lf_via']));[](.html)
113 if ($link['title']=='') $link['title']=$link['url']; // If title is empty, use the URL as title. 114 if ($link['title']=='') $link['title']=$link['url']; // If title is empty, use the URL as title.[](.html)
114 $LINKSDB[$linkdate] = $link; 115 $LINKSDB[$linkdate] = $link;[](.html)
115 $LINKSDB->savedb(); // Save to disk. 116 $LINKSDB->savedb(); // Save to disk.
116@@ -1556,7 +1573,8 @@ function renderPage() 117@@ -1556,7 +1573,8 @@ function renderPage()
117 $title = (empty($_GET['title']) ? '' : $_GET['title'] ); // Get title if it was provided in URL (by the bookmarklet). 118 $title = (empty($_GET['title']) ? '' : $_GET['title'] ); // Get title if it was provided in URL (by the bookmarklet).[](.html)
118 $description = (empty($_GET['description']) ? '' : $_GET['description']); // Get description if it was provided in URL (by the bookmarklet). [Bronco added that] 119 $description = (empty($_GET['description']) ? '' : $_GET['description']); // Get description if it was provided in URL (by the bookmarklet). [Bronco added that][](.html)
119 $tags = (empty($_GET['tags']) ? '' : $_GET['tags'] ); // Get tags if it was provided in URL 120 $tags = (empty($_GET['tags']) ? '' : $_GET['tags'] ); // Get tags if it was provided in URL[](.html)
120- $private = (!empty($_GET['private']) && $_GET['private'] === "1" ? 1 : 0); // Get private if it was provided in URL 121- $private = (!empty($_GET['private']) && $_GET['private'] === "1" ? 1 : 0); // Get private if it was provided in URL [](.html)
121+ $via = (empty($_GET['via']) ? '' : $_GET['via'] ); 122+ $via = (empty($_GET['via']) ? '' : $_GET['via'] );[](.html)
122+ $private = (!empty($_GET['private']) && $_GET['private'] === "1" ? 1 : 0); // Get private if it was provided in URL 123+ $private = (!empty($_GET['private']) && $_GET['private'] === "1" ? 1 : 0); // Get private if it was provided in URL[](.html)
123 if (($url!='') && parse_url($url,PHP_URL_SCHEME)=='') $url = 'http://'.$url; 124 if (($url!='') && parse_url($url,PHP_URL_SCHEME)=='') $url = 'http://'.$url;
124 // If this is an HTTP link, we try go get the page to extract the title (otherwise we will to straight to the edit form.) 125 // If this is an HTTP link, we try go get the page to extract the title (otherwise we will to straight to the edit form.)
125 if (empty($title) && parse_url($url,PHP_URL_SCHEME)=='http') 126 if (empty($title) && parse_url($url,PHP_URL_SCHEME)=='http')
@@ -130,10 +131,10 @@ index 6fae2f8..53f798e 100644
130- 131-
131+ 132+
132 // If found, extract encoding. 133 // If found, extract encoding.
133 if (!empty($meta[0])) 134 if (!empty($meta[0]))[](.html)
134 { 135 {
135@@ -1577,7 +1595,7 @@ function renderPage() 136@@ -1577,7 +1595,7 @@ function renderPage()
136 $html_charset = (!empty($enc[1])) ? strtolower($enc[1]) : 'utf-8'; 137 $html_charset = (!empty($enc[1])) ? strtolower($enc[1]) : 'utf-8';[](.html)
137 } 138 }
138 else { $html_charset = 'utf-8'; } 139 else { $html_charset = 'utf-8'; }
139- 140-
@@ -151,13 +152,13 @@ index 6fae2f8..53f798e 100644
151 152
152 $PAGE = new pageBuilder; 153 $PAGE = new pageBuilder;
153@@ -1842,6 +1860,9 @@ function buildLinkList($PAGE,$LINKSDB) 154@@ -1842,6 +1860,9 @@ function buildLinkList($PAGE,$LINKSDB)
154 $taglist = explode(' ',$link['tags']); 155 $taglist = explode(' ',$link['tags']);[](.html)
155 uasort($taglist, 'strcasecmp'); 156 uasort($taglist, 'strcasecmp');
156 $link['taglist']=$taglist; 157 $link['taglist']=$taglist;[](.html)
157+ if(!empty($link['via'])){ 158+ if(!empty($link['via'])){[](.html)
158+ $link['via']=htmlspecialchars($link['via']); 159+ $link['via']=htmlspecialchars($link['via']);[](.html)
159+ } 160+ }
160 $linkDisp[$keys[$i]] = $link; 161 $linkDisp[$keys[$i[ = $link;](-=-$link;.html)
161 $i++; 162 $i++;
162 } 163 }
163diff --git a/tpl/editlink.html b/tpl/editlink.html 164diff --git a/tpl/editlink.html b/tpl/editlink.html
@@ -169,7 +170,7 @@ index 4a2c30c..14d4f9c 100644
169 <i>Description</i><br><textarea name="lf_description" rows="4" cols="25" style="width:100%">{$link.description|htmlspecialchars}</textarea><br> 170 <i>Description</i><br><textarea name="lf_description" rows="4" cols="25" style="width:100%">{$link.description|htmlspecialchars}</textarea><br>
170 <i>Tags</i><br><input type="text" id="lf_tags" name="lf_tags" value="{$link.tags|htmlspecialchars}" style="width:100%"><br> 171 <i>Tags</i><br><input type="text" id="lf_tags" name="lf_tags" value="{$link.tags|htmlspecialchars}" style="width:100%"><br>
171+ <i>Origine</i><br><input type="text" name="lf_via" value="{$link.via|htmlspecialchars}" style="width:100%"><br> 172+ <i>Origine</i><br><input type="text" name="lf_via" value="{$link.via|htmlspecialchars}" style="width:100%"><br>
172 {if condition="($link_is_new && $GLOBALS['privateLinkByDefault']==true) || $link.private == true"} 173 {if condition="($link_is_new && $GLOBALS['privateLinkByDefault']==true) || $link.private == true"}[](.html)
173 <input type="checkbox" checked="checked" name="lf_private" id="lf_private"> 174 <input type="checkbox" checked="checked" name="lf_private" id="lf_private">
174 &nbsp;<label for="lf_private"><i>Private</i></label><br> 175 &nbsp;<label for="lf_private"><i>Private</i></label><br>
175diff --git a/tpl/linklist.html b/tpl/linklist.html 176diff --git a/tpl/linklist.html b/tpl/linklist.html
@@ -181,9 +182,9 @@ index ddc38cb..0a8475f 100644
181 <br> 182 <br>
182 {if="$value.description"}<div class="linkdescription"{if condition="$search_type=='permalink'"} style="max-height:none !important;"{/if}>{$value.description}</div>{/if} 183 {if="$value.description"}<div class="linkdescription"{if condition="$search_type=='permalink'"} style="max-height:none !important;"{/if}>{$value.description}</div>{/if}
183+ {if condition="isset($value.via) && !empty($value.via)"}<div><a href="{$value.via}">Origine => {$value.via|getJustDomain}</a></div>{/if} 184+ {if condition="isset($value.via) && !empty($value.via)"}<div><a href="{$value.via}">Origine => {$value.via|getJustDomain}</a></div>{/if}
184 {if="!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()"} 185 {if="!$GLOBALS['config'['HIDE_TIMESTAMPS'] || isLoggedIn()"}]('HIDE_TIMESTAMPS']-||-isLoggedIn()"}.html)
185 <span class="linkdate" title="Permalink"><a href="?{$value.linkdate|smallHash}">{$value.localdate|htmlspecialchars} - permalink</a> - </span> 186 <span class="linkdate" title="Permalink"><a href="?{$value.linkdate|smallHash}">{$value.localdate|htmlspecialchars} - permalink</a> - </span>
186 {else} 187 {else}
187-- 188--
1882.1.1 1892.1.1
189``` \ No newline at end of file 190```
diff --git a/doc/FAQ.html b/doc/FAQ.html
new file mode 100644
index 00000000..0ebd1bcf
--- /dev/null
+++ b/doc/FAQ.html
@@ -0,0 +1,97 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - FAQ</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <link rel="stylesheet" href="github-markdown.css">
13</head>
14<body>
15<div id="local-sidebar">
16<ul>
17<li><a href="Home.html">Home</a></li>
18<li>Installation
19<ul>
20<li><a href="Server-requirements.html">Server requirements</a></li>
21<li><a href="Server-configuration.html">Server configuration</a></li>
22<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
23</ul></li>
24<li><a href="Usage.html">Usage</a>
25<ul>
26<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
27<li><a href="Firefox-share.html">Firefox share</a></li>
28<li><a href="RSS-feeds.html">RSS feeds</a></li>
29</ul></li>
30<li>How To
31<ul>
32<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
33<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
34<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
35</ul></li>
36<li><a href="Troubleshooting.html">Troubleshooting</a></li>
37<li><a href="Development.html">Development</a>
38<ul>
39<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
40<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
41<li><a href="Directory-structure.html">Directory structure</a></li>
42<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
43<li><a href="Plugin-System.html">Plugin System</a></li>
44<li><a href="Security.html">Security</a></li>
45<li><a href="Static-analysis.html">Static analysis</a></li>
46<li><a href="Theming.html">Theming</a></li>
47<li><a href="Unit-tests.html">Unit tests</a></li>
48</ul></li>
49<li>About
50<ul>
51<li><a href="FAQ.html">FAQ</a></li>
52<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
53<li><a href="TODO.html">TODO</a></li>
54</ul></li>
55</ul>
56</div>
57<h1 id="faq">FAQ</h1>
58<h3 id="why-did-you-create-shaarli">Why did you create Shaarli ?</h3>
59<p>I was a StumbleUpon user. Then I got fed up with they big toolbar. I switched to delicious, which was lighter, faster and more beautiful. Until Yahoo bought it. Then the export API broke all the time, delicious became slow and was ditched by Yahoo. I switched to Diigo, which is not bad, but does too much. And Diigo is sslllooooowww and their Firefox extension a bit buggy. And… oh… <strong>their Firefox addon sends to Diigo every single URL you visit</strong> (Don't believe me ? Use <a href="https://addons.mozilla.org/en-US/firefox/addon/tamper-data/">Tamper Data</a> and open any page).<a href=".html"></a></p>
60<p>Enough is enough. Saving simple links should not be a complicated heavy thing. I ditched them all and wrote my own: Shaarli. It's simple, but it does the job and does it well. And my data is not hosted on a foreign server, but on my server.</p>
61<h3 id="why-use-shaarli-and-not-deliciousdiigo">Why use Shaarli and not Delicious/Diigo ?</h3>
62<p>With Shaarli:</p>
63<ul>
64<li>The data is yours: It's hosted on your server.</li>
65<li>Never fear of having your data locked-in.</li>
66<li>Never fear to have your data sold to third party.</li>
67<li>Your private links are not hosted on a third party server.</li>
68<li>You are not tracked by browser addons (like Diigo does)</li>
69<li>You can change the look and feel of the pages if you want.</li>
70<li>You can change the behaviour of the program.</li>
71<li>It's magnitude faster than most bookmarking services.</li>
72</ul>
73<h3 id="what-does-shaarli-mean">What does Shaarli mean?</h3>
74<p>Shaarli is for shaaring your links.</p>
75<h3 id="my-shaarli-is-broken">My Shaarli is broken!</h3>
76<p>First of all, ensure that both the <a href="Server-configuration">web server</a> and <a href="Shaarli-configuration">Shaarli</a> are correctly configured, and that your installation is <a href="Server-requirements">supported</a>.<a href=".html"></a></p>
77<p>If everything looks right but the issue(s) remain(s), please:</p>
78<ul>
79<li>take a look at the <a href="Troubleshooting">troubleshooting</a> section<a href=".html"></a></li>
80<li>come <a href="https://gitter.im/shaarli/Shaarli">chat with us</a> on Gitter, we'll be happy to help ;-)<a href=".html"></a></li>
81<li>browse active <a href="https://github.com/shaarli/Shaarli/issues">issues</a> and <a href="https://github.com/shaarli/Shaarli/pulls">Pull Requests</a><a href=".html"></a>
82<ul>
83<li>if you find one that is related to the issue, feel free to comment and provide additional details (host/Shaarli setup)</li>
84<li>else, <a href="https://github.com/shaarli/Shaarli/issues/new">open a new issue</a>, and provide information about the problem:<a href=".html"></a>
85<ul>
86<li><em>what happens?</em> - display glitches, invalid data, security flaws...</li>
87<li><em>what is your configuration?</em> - OS, server version, activated extensions, web browser...</li>
88<li><em>is it reproducible?</em></li>
89</ul></li>
90</ul></li>
91</ul>
92<h3 id="why-not-use-a-real-database-files-are-slow">Why not use a real database? Files are slow!</h3>
93<p>Does browsing <a href="http://sebsauvage.net/links/">this page</a> feel slow? Try browsing older pages, too.<a href=".html"></a></p>
94<p>It's not slow at all, is it? And don't forget the database contains more than 16000 links, and it's on a shared host, with 32000 visitors/day for my website alone. And it's still damn fast. Why?</p>
95<p>The data file is only 3.7 Mb. It's read 99% of the time, and is probably already in the operation system disk cache. So generating a page involves no I/O at all most of the time.</p>
96</body>
97</html>
diff --git a/doc/FAQ.md b/doc/FAQ.md
new file mode 100644
index 00000000..4c69763f
--- /dev/null
+++ b/doc/FAQ.md
@@ -0,0 +1,44 @@
1#FAQ
2### Why did you create Shaarli ?
3
4I was a StumbleUpon user. Then I got fed up with they big toolbar. I switched to delicious, which was lighter, faster and more beautiful. Until Yahoo bought it. Then the export API broke all the time, delicious became slow and was ditched by Yahoo. I switched to Diigo, which is not bad, but does too much. And Diigo is sslllooooowww and their Firefox extension a bit buggy. And… oh… **their Firefox addon sends to Diigo every single URL you visit** (Don't believe me ? Use [Tamper Data](https://addons.mozilla.org/en-US/firefox/addon/tamper-data/) and open any page).[](.html)
5
6Enough is enough. Saving simple links should not be a complicated heavy thing. I ditched them all and wrote my own: Shaarli. It's simple, but it does the job and does it well. And my data is not hosted on a foreign server, but on my server.
7
8### Why use Shaarli and not Delicious/Diigo ?
9
10With Shaarli:
11
12* The data is yours: It's hosted on your server.
13* Never fear of having your data locked-in.
14* Never fear to have your data sold to third party.
15* Your private links are not hosted on a third party server.
16* You are not tracked by browser addons (like Diigo does)
17* You can change the look and feel of the pages if you want.
18* You can change the behaviour of the program.
19* It's magnitude faster than most bookmarking services.
20
21### What does Shaarli mean?
22
23Shaarli is for shaaring your links.
24
25### My Shaarli is broken!
26First of all, ensure that both the [web server](Server-configuration) and [Shaarli](Shaarli-configuration) are correctly configured, and that your installation is [supported](Server-requirements).[](.html)
27
28If everything looks right but the issue(s) remain(s), please:
29- take a look at the [troubleshooting](Troubleshooting) section[](.html)
30- come [chat with us](https://gitter.im/shaarli/Shaarli) on Gitter, we'll be happy to help ;-)[](.html)
31- browse active [issues](https://github.com/shaarli/Shaarli/issues) and [Pull Requests](https://github.com/shaarli/Shaarli/pulls)[](.html)
32 - if you find one that is related to the issue, feel free to comment and provide additional details (host/Shaarli setup)
33 - else, [open a new issue](https://github.com/shaarli/Shaarli/issues/new), and provide information about the problem:[](.html)
34 - _what happens?_ - display glitches, invalid data, security flaws...
35 - _what is your configuration?_ - OS, server version, activated extensions, web browser...
36 - _is it reproducible?_
37
38### Why not use a real database? Files are slow!
39
40Does browsing [this page](http://sebsauvage.net/links/) feel slow? Try browsing older pages, too.[](.html)
41
42It's not slow at all, is it? And don't forget the database contains more than 16000 links, and it's on a shared host, with 32000 visitors/day for my website alone. And it's still damn fast. Why?
43
44The data file is only 3.7 Mb. It's read 99% of the time, and is probably already in the operation system disk cache. So generating a page involves no I/O at all most of the time.
diff --git a/doc/Firefox-share.html b/doc/Firefox-share.html
new file mode 100644
index 00000000..198afe23
--- /dev/null
+++ b/doc/Firefox-share.html
@@ -0,0 +1,72 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Firefox share</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <link rel="stylesheet" href="github-markdown.css">
13</head>
14<body>
15<div id="local-sidebar">
16<ul>
17<li><a href="Home.html">Home</a></li>
18<li>Installation
19<ul>
20<li><a href="Server-requirements.html">Server requirements</a></li>
21<li><a href="Server-configuration.html">Server configuration</a></li>
22<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
23</ul></li>
24<li><a href="Usage.html">Usage</a>
25<ul>
26<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
27<li><a href="Firefox-share.html">Firefox share</a></li>
28<li><a href="RSS-feeds.html">RSS feeds</a></li>
29</ul></li>
30<li>How To
31<ul>
32<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
33<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
34<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
35</ul></li>
36<li><a href="Troubleshooting.html">Troubleshooting</a></li>
37<li><a href="Development.html">Development</a>
38<ul>
39<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
40<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
41<li><a href="Directory-structure.html">Directory structure</a></li>
42<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
43<li><a href="Plugin-System.html">Plugin System</a></li>
44<li><a href="Security.html">Security</a></li>
45<li><a href="Static-analysis.html">Static analysis</a></li>
46<li><a href="Theming.html">Theming</a></li>
47<li><a href="Unit-tests.html">Unit tests</a></li>
48</ul></li>
49<li>About
50<ul>
51<li><a href="FAQ.html">FAQ</a></li>
52<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
53<li><a href="TODO.html">TODO</a></li>
54</ul></li>
55</ul>
56</div>
57<h1 id="firefox-share">Firefox share</h1>
58<h3 id="add-shaarli-as-a-sharing-service-to-firefox">Add Shaarli as a sharing service to Firefox</h3>
59<ul>
60<li>Open your Shaarli and <code>Login</code></li>
61<li>Click the <code>Tools</code> button in the top bar</li>
62<li>Click the <code>✚Add to Firefox social</code> button and accept the activation.</li>
63</ul>
64<h3 id="sharing-links-using-firefox-share">Sharing links using Firefox share</h3>
65<ul>
66<li>Add the sharing service as described above</li>
67<li>When you are visiting a webpage you would like to share with Shaarli, click the Firefox <em>Share</em> button <a href="images/firefoxshare.png.html">images/firefoxshare.png</a></li>
68<li>You can edit your link before and after saving, just like the bookmarklet above.</li>
69</ul>
70<p>|  | Your Shaarli instance must be hosted on an HTTPS (SSL/TLS secure connection) enabled server for Firefox Share to work. Firefox Share will not work over plain HTTP connections. |<br />|------|-------------------------------------------------------------------------------|</p>
71</body>
72</html>
diff --git a/doc/Firefox-share.md b/doc/Firefox-share.md
new file mode 100644
index 00000000..58adc58f
--- /dev/null
+++ b/doc/Firefox-share.md
@@ -0,0 +1,16 @@
1#Firefox share
2### Add Shaarli as a sharing service to Firefox
3
4 * Open your Shaarli and `Login`
5 * Click the `Tools` button in the top bar
6 * Click the `✚Add to Firefox social` button and accept the activation.
7
8
9### Sharing links using Firefox share
10
11 * Add the sharing service as described above
12 * When you are visiting a webpage you would like to share with Shaarli, click the Firefox _Share_ button [images/firefoxshare.png](images/firefoxshare.png.html)
13 * You can edit your link before and after saving, just like the bookmarklet above.
14
15|  | Your Shaarli instance must be hosted on an HTTPS (SSL/TLS secure connection) enabled server for Firefox Share to work. Firefox Share will not work over plain HTTP connections. |
16|------|-------------------------------------------------------------------------------|
diff --git a/doc/GnuPG-signature.html b/doc/GnuPG-signature.html
new file mode 100644
index 00000000..c9e0455a
--- /dev/null
+++ b/doc/GnuPG-signature.html
@@ -0,0 +1,199 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - GnuPG signature</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <style type="text/css">
13table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
14 margin: 0; padding: 0; vertical-align: baseline; border: none; }
15table.sourceCode { width: 100%; line-height: 100%; }
16td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
17td.sourceCode { padding-left: 5px; }
18code > span.kw { color: #007020; font-weight: bold; }
19code > span.dt { color: #902000; }
20code > span.dv { color: #40a070; }
21code > span.bn { color: #40a070; }
22code > span.fl { color: #40a070; }
23code > span.ch { color: #4070a0; }
24code > span.st { color: #4070a0; }
25code > span.co { color: #60a0b0; font-style: italic; }
26code > span.ot { color: #007020; }
27code > span.al { color: #ff0000; font-weight: bold; }
28code > span.fu { color: #06287e; }
29code > span.er { color: #ff0000; font-weight: bold; }
30 </style>
31 <link rel="stylesheet" href="github-markdown.css">
32</head>
33<body>
34<div id="local-sidebar">
35<ul>
36<li><a href="Home.html">Home</a></li>
37<li>Installation
38<ul>
39<li><a href="Server-requirements.html">Server requirements</a></li>
40<li><a href="Server-configuration.html">Server configuration</a></li>
41<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
42</ul></li>
43<li><a href="Usage.html">Usage</a>
44<ul>
45<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
46<li><a href="Firefox-share.html">Firefox share</a></li>
47<li><a href="RSS-feeds.html">RSS feeds</a></li>
48</ul></li>
49<li>How To
50<ul>
51<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
52<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
53<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
54</ul></li>
55<li><a href="Troubleshooting.html">Troubleshooting</a></li>
56<li><a href="Development.html">Development</a>
57<ul>
58<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
59<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
60<li><a href="Directory-structure.html">Directory structure</a></li>
61<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
62<li><a href="Plugin-System.html">Plugin System</a></li>
63<li><a href="Security.html">Security</a></li>
64<li><a href="Static-analysis.html">Static analysis</a></li>
65<li><a href="Theming.html">Theming</a></li>
66<li><a href="Unit-tests.html">Unit tests</a></li>
67</ul></li>
68<li>About
69<ul>
70<li><a href="FAQ.html">FAQ</a></li>
71<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
72<li><a href="TODO.html">TODO</a></li>
73</ul></li>
74</ul>
75</div>
76<h1 id="gnupg-signature">GnuPG signature</h1>
77<h2 id="introduction">Introduction</h2>
78<h3 id="pgp-and-gpg">PGP and GPG</h3>
79<p><a href="https://gnupg.org/">Gnu Privacy Guard</a> (GnuPG) is an Open Source implementation of the <a href="https://en.wikipedia.org/wiki/Pretty_Good_Privacy#OpenPGP">Pretty Good [](.html)<br />Privacy</a> (OpenPGP) specification. Its main purposes are digital authentication,<br />signature and encryption.</p>
80<p>It is often used by the <a href="https://en.wikipedia.org/wiki/Free_and_open-source_software">FLOSS</a> community to verify:<a href=".html"></a></p>
81<ul>
82<li>Linux package signatures: Debian <a href="https://wiki.debian.org/SecureApt">SecureApt</a>, ArchLinux <a href="https://www.archlinux.org/master-keys/">Master [](.html)<br />Keys</a></li>
83<li><a href="https://en.wikipedia.org/wiki/Revision_control">SCM</a> releases &amp; maintainer identity<a href=".html"></a></li>
84</ul>
85<h3 id="trust">Trust</h3>
86<p>To quote Phil Pennock (the author of the <a href="https://bitbucket.org/skskeyserver/sks-keyserver/wiki/Home">SKS</a> key server - <a href="http://sks.spodhuis.org/" class="uri">http://sks.spodhuis.org/</a>):<a href=".html"></a></p>
87<blockquote>
88<p>You MUST understand that presence of data in the keyserver (pools) in no way connotes trust. Anyone can generate a key, with any name or email address, and upload it. All security and trust comes from evaluating security at the “object level”, via PGP Web-Of-Trust signatures. This keyserver makes it possible to retrieve keys, looking them up via various indices, but the collection of keys in this public pool is KNOWN to contain malicious and fraudulent keys. It is the common expectation of server operators that users understand this and use software which, like all known common OpenPGP implementations, evaluates trust accordingly. This expectation is so common that it is not normally explicitly stated.</p>
89</blockquote>
90<p>Trust can be gained by having your key signed by other people (and signing their key back, too :) ), for instance during <a href="https://en.wikipedia.org/wiki/Key_signing_party">key signing parties</a>, see:<a href=".html"></a></p>
91<ul>
92<li><a href="http://www.cryptnet.net/fdp/crypto/keysigning_party/en/keysigning_party.html">The Keysigning party HOWTO</a><a href=".html"></a></li>
93<li><a href="https://en.wikipedia.org/wiki/Web_of_trust">Web of trust</a><a href=".html"></a></li>
94</ul>
95<h2 id="generate-a-gpg-key">Generate a GPG key</h2>
96<p>See <a href="http://stackoverflow.com/a/16725717">Generating a GPG key for Git tagging</a>.<a href=".html"></a></p>
97<h3 id="gpg---provide-identity-information">gpg - provide identity information</h3>
98<pre class="sourceCode bash"><code class="sourceCode bash">$ <span class="kw">gpg</span> --gen-key
99
100<span class="kw">gpg</span> (GnuPG) <span class="kw">2.1.6;</span> <span class="kw">Copyright</span> (C) <span class="kw">2015</span> Free Software Foundation, Inc.
101<span class="kw">This</span> is free software: you are free to change and redistribute it.
102<span class="kw">There</span> is NO WARRANTY, to the extent permitted by law.
103
104<span class="kw">Note</span>: Use <span class="st">&quot;gpg2 --full-gen-key&quot;</span> for a full featured key generation dialog.
105
106<span class="kw">GnuPG</span> needs to construct a user ID to identify your key.
107
108<span class="kw">Real</span> name: Marvin the Paranoid Android
109<span class="kw">Email</span> address: marvin@h2g2.net
110<span class="kw">You</span> selected this USER-ID:
111 <span class="st">&quot;Marvin the Paranoid Android &lt;marvin@h2g2.net&gt;&quot;</span>
112
113<span class="kw">Change</span> (N)<span class="kw">ame</span>, (E)<span class="kw">mail</span>, or (O)<span class="kw">kay</span>/<span class="kw">(Q)uit?</span> o
114<span class="kw">We</span> need to generate a lot of random bytes. It is a good idea to perform
115<span class="kw">some</span> other action (type on the keyboard, move the mouse, utilize the
116<span class="kw">disks</span>) <span class="kw">during</span> the prime generation<span class="kw">;</span> <span class="kw">this</span> gives the random number
117<span class="kw">generator</span> a better chance to gain enough entropy.</code></pre>
118<h3 id="gpg---entropy-interlude">gpg - entropy interlude</h3>
119<p>At this point, you will:</p>
120<ul>
121<li>be prompted for a secure password to protect your key (the input method will depend on your Desktop Environment and configuration)</li>
122<li>be asked to use your machine's input devices (mouse, keyboard, etc.) to generate random entropy; this step <em>may take some time</em></li>
123</ul>
124<h3 id="gpg---key-creation-confirmation">gpg - key creation confirmation</h3>
125<pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">gpg</span>: key A9D53A3E marked as ultimately trusted
126<span class="kw">public</span> and secret key created and signed.
127
128<span class="kw">gpg</span>: checking the trustdb
129<span class="kw">gpg</span>: 3 marginal(s) <span class="kw">needed</span>, 1 complete(s) <span class="kw">needed</span>, PGP trust model
130<span class="kw">gpg</span>: depth: 0 valid: 2 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 2u
131<span class="kw">pub</span> rsa2048/A9D53A3E 2015-07-31
132 <span class="kw">Key</span> fingerprint = AF2A 5381 E54B 2FD2 14C4 A9A3 0E35 ACA4 A9D5 3A3E
133<span class="kw">uid</span> [ultimate] Marvin the Paranoid Android <span class="kw">&lt;</span>marvin@h2g2.net<span class="kw">&gt;</span>[](.html)
134<span class="kw">sub</span> rsa2048/8C0EACF1 2015-07-31</code></pre>
135<h3 id="gpg---submit-your-public-key-to-a-pgp-server-optional">gpg - submit your public key to a PGP server (Optional)</h3>
136<pre class="sourceCode bash"><code class="sourceCode bash">$ <span class="kw">gpg</span> --keyserver pgp.mit.edu --send-keys A9D53A3E
137<span class="kw">gpg</span>: sending key A9D53A3E to hkp server pgp.mit.edu</code></pre>
138<h2 id="create-and-push-a-gpg-signed-tag">Create and push a GPG-signed tag</h2>
139<p>See <a href="http://git-scm.com/book/en/v2/Distributed-Git-Maintaining-a-Project#Tagging-Your-Releases">Git - Maintaining a project - Tagging your [](.html)<br />releases</a>.</p>
140<h3 id="prerequisites">Prerequisites</h3>
141<p>This guide assumes that you have:</p>
142<ul>
143<li>a GPG key matching your GitHub authentication credentials
144<ul>
145<li>i.e., the email address identified by the GPG key is the same as the one in your <code>~/.gitconfig</code></li>
146</ul></li>
147<li>a GitHub fork of Shaarli</li>
148<li>a local clone of your Shaarli fork, with the following remotes:
149<ul>
150<li><code>origin</code> pointing to your GitHub fork</li>
151<li><code>upstream</code> pointing to the main Shaarli repository</li>
152</ul></li>
153<li>maintainer permissions on the main Shaarli repository (to push the signed tag)</li>
154</ul>
155<h3 id="bump-shaarlis-version">Bump Shaarli's version</h3>
156<pre class="sourceCode bash"><code class="sourceCode bash">$ <span class="kw">cd</span> /path/to/shaarli
157
158<span class="co"># create a new branch</span>
159$ <span class="kw">git</span> fetch upstream
160$ <span class="kw">git</span> checkout upstream/master -b v0.5.0
161
162<span class="co"># bump the version number</span>
163$ <span class="kw">vim</span> index.php shaarli_version.php
164
165<span class="co"># commit the changes</span>
166$ <span class="kw">git</span> add index.php shaarli_version.php
167$ <span class="kw">git</span> commit -s -m <span class="st">&quot;Bump version to v0.5.0&quot;</span>
168
169<span class="co"># push the commit on your GitHub fork</span>
170$ <span class="kw">git</span> push origin v0.5.0</code></pre>
171<h3 id="create-and-merge-a-pull-request">Create and merge a Pull Request</h3>
172<p>This one is pretty straightforward ;-)</p>
173<h3 id="create-and-push-a-signed-tag">Create and push a signed tag</h3>
174<pre class="sourceCode bash"><code class="sourceCode bash"><span class="co"># update your local copy</span>
175$ <span class="kw">git</span> checkout master
176$ <span class="kw">git</span> fetch upstream
177$ <span class="kw">git</span> pull upstream master
178
179<span class="co"># create a signed tag</span>
180$ <span class="kw">git</span> tag -s -m <span class="st">&quot;Release v0.5.0&quot;</span> v0.5.0
181
182<span class="co"># push it to &quot;upstream&quot;</span>
183$ <span class="kw">git</span> push --tags upstream</code></pre>
184<h3 id="verify-a-signed-tag">Verify a signed tag</h3>
185<p><a href="https://github.com/shaarli/Shaarli/releases/tag/v0.5.0"><code>v0.5.0</code></a> is the first GPG-signed tag pushed on the Community Shaarli.<a href=".html"></a></p>
186<p>Let's have a look at its signature!</p>
187<pre class="sourceCode bash"><code class="sourceCode bash">$ <span class="kw">cd</span> /path/to/shaarli
188$ <span class="kw">git</span> fetch upstream
189
190<span class="co"># get the SHA1 reference of the tag</span>
191$ <span class="kw">git</span> show-ref tags/v0.5.0
192<span class="kw">f7762cf803f03f5caf4b8078359a63783d0090c1</span> refs/tags/v0.5.0
193
194<span class="co"># verify the tag signature information</span>
195$ <span class="kw">git</span> verify-tag f7762cf803f03f5caf4b8078359a63783d0090c1
196<span class="kw">gpg</span>: Signature made Thu 30 Jul 2015 11:46:34 CEST using RSA key ID 4100DF6F
197<span class="kw">gpg</span>: Good signature from <span class="st">&quot;VirtualTam &lt;virtualtam@flibidi.net&gt;&quot;</span> [ultimate][](.html)</code></pre>
198</body>
199</html>
diff --git a/doc/GnuPG-signature.md b/doc/GnuPG-signature.md
new file mode 100644
index 00000000..e8dbdb11
--- /dev/null
+++ b/doc/GnuPG-signature.md
@@ -0,0 +1,141 @@
1#GnuPG signature
2## Introduction
3### PGP and GPG
4[Gnu Privacy Guard](https://gnupg.org/) (GnuPG) is an Open Source implementation of the [Pretty Good [](.html)
5Privacy](https://en.wikipedia.org/wiki/Pretty_Good_Privacy#OpenPGP) (OpenPGP) specification. Its main purposes are digital authentication,
6signature and encryption.
7
8It is often used by the [FLOSS](https://en.wikipedia.org/wiki/Free_and_open-source_software) community to verify:[](.html)
9- Linux package signatures: Debian [SecureApt](https://wiki.debian.org/SecureApt), ArchLinux [Master [](.html)
10Keys](https://www.archlinux.org/master-keys/)
11- [SCM](https://en.wikipedia.org/wiki/Revision_control) releases & maintainer identity[](.html)
12
13### Trust
14To quote Phil Pennock (the author of the [SKS](https://bitbucket.org/skskeyserver/sks-keyserver/wiki/Home) key server - http://sks.spodhuis.org/):[](.html)
15
16> You MUST understand that presence of data in the keyserver (pools) in no way connotes trust. Anyone can generate a key, with any name or email address, and upload it. All security and trust comes from evaluating security at the “object level”, via PGP Web-Of-Trust signatures. This keyserver makes it possible to retrieve keys, looking them up via various indices, but the collection of keys in this public pool is KNOWN to contain malicious and fraudulent keys. It is the common expectation of server operators that users understand this and use software which, like all known common OpenPGP implementations, evaluates trust accordingly. This expectation is so common that it is not normally explicitly stated.
17
18Trust can be gained by having your key signed by other people (and signing their key back, too :) ), for instance during [key signing parties](https://en.wikipedia.org/wiki/Key_signing_party), see:[](.html)
19- [The Keysigning party HOWTO](http://www.cryptnet.net/fdp/crypto/keysigning_party/en/keysigning_party.html)[](.html)
20- [Web of trust](https://en.wikipedia.org/wiki/Web_of_trust)[](.html)
21
22## Generate a GPG key
23See [Generating a GPG key for Git tagging](http://stackoverflow.com/a/16725717).[](.html)
24
25### gpg - provide identity information
26```bash
27$ gpg --gen-key
28
29gpg (GnuPG) 2.1.6; Copyright (C) 2015 Free Software Foundation, Inc.
30This is free software: you are free to change and redistribute it.
31There is NO WARRANTY, to the extent permitted by law.
32
33Note: Use "gpg2 --full-gen-key" for a full featured key generation dialog.
34
35GnuPG needs to construct a user ID to identify your key.
36
37Real name: Marvin the Paranoid Android
38Email address: marvin@h2g2.net
39You selected this USER-ID:
40 "Marvin the Paranoid Android <marvin@h2g2.net>"
41
42Change (N)ame, (E)mail, or (O)kay/(Q)uit? o
43We need to generate a lot of random bytes. It is a good idea to perform
44some other action (type on the keyboard, move the mouse, utilize the
45disks) during the prime generation; this gives the random number
46generator a better chance to gain enough entropy.
47```
48
49### gpg - entropy interlude
50At this point, you will:
51- be prompted for a secure password to protect your key (the input method will depend on your Desktop Environment and configuration)
52- be asked to use your machine's input devices (mouse, keyboard, etc.) to generate random entropy; this step _may take some time_
53
54### gpg - key creation confirmation
55```bash
56gpg: key A9D53A3E marked as ultimately trusted
57public and secret key created and signed.
58
59gpg: checking the trustdb
60gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
61gpg: depth: 0 valid: 2 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 2u
62pub rsa2048/A9D53A3E 2015-07-31
63 Key fingerprint = AF2A 5381 E54B 2FD2 14C4 A9A3 0E35 ACA4 A9D5 3A3E
64uid [ultimate] Marvin the Paranoid Android <marvin@h2g2.net>[](.html)
65sub rsa2048/8C0EACF1 2015-07-31
66```
67
68### gpg - submit your public key to a PGP server (Optional)
69``` bash
70$ gpg --keyserver pgp.mit.edu --send-keys A9D53A3E
71gpg: sending key A9D53A3E to hkp server pgp.mit.edu
72```
73
74## Create and push a GPG-signed tag
75See [Git - Maintaining a project - Tagging your [](.html)
76releases](http://git-scm.com/book/en/v2/Distributed-Git-Maintaining-a-Project#Tagging-Your-Releases).
77
78### Prerequisites
79This guide assumes that you have:
80- a GPG key matching your GitHub authentication credentials
81 - i.e., the email address identified by the GPG key is the same as the one in your `~/.gitconfig`
82- a GitHub fork of Shaarli
83- a local clone of your Shaarli fork, with the following remotes:
84 - `origin` pointing to your GitHub fork
85 - `upstream` pointing to the main Shaarli repository
86- maintainer permissions on the main Shaarli repository (to push the signed tag)
87
88### Bump Shaarli's version
89```bash
90$ cd /path/to/shaarli
91
92# create a new branch
93$ git fetch upstream
94$ git checkout upstream/master -b v0.5.0
95
96# bump the version number
97$ vim index.php shaarli_version.php
98
99# commit the changes
100$ git add index.php shaarli_version.php
101$ git commit -s -m "Bump version to v0.5.0"
102
103# push the commit on your GitHub fork
104$ git push origin v0.5.0
105```
106
107### Create and merge a Pull Request
108This one is pretty straightforward ;-)
109
110### Create and push a signed tag
111```bash
112# update your local copy
113$ git checkout master
114$ git fetch upstream
115$ git pull upstream master
116
117# create a signed tag
118$ git tag -s -m "Release v0.5.0" v0.5.0
119
120# push it to "upstream"
121$ git push --tags upstream
122```
123
124### Verify a signed tag
125[`v0.5.0`](https://github.com/shaarli/Shaarli/releases/tag/v0.5.0) is the first GPG-signed tag pushed on the Community Shaarli.[](.html)
126
127Let's have a look at its signature!
128
129```bash
130$ cd /path/to/shaarli
131$ git fetch upstream
132
133# get the SHA1 reference of the tag
134$ git show-ref tags/v0.5.0
135f7762cf803f03f5caf4b8078359a63783d0090c1 refs/tags/v0.5.0
136
137# verify the tag signature information
138$ git verify-tag f7762cf803f03f5caf4b8078359a63783d0090c1
139gpg: Signature made Thu 30 Jul 2015 11:46:34 CEST using RSA key ID 4100DF6F
140gpg: Good signature from "VirtualTam <virtualtam@flibidi.net>" [ultimate][](.html)
141```
diff --git a/doc/Home.html b/doc/Home.html
index 2cb54c86..37d62e8b 100644
--- a/doc/Home.html
+++ b/doc/Home.html
@@ -4,7 +4,7 @@
4 <meta charset="utf-8"> 4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc"> 5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title></title> 7 <title>Shaarli - Home</title>
8 <style type="text/css">code{white-space: pre;}</style> 8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]> 9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> 10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
@@ -12,404 +12,55 @@
12 <link rel="stylesheet" href="github-markdown.css"> 12 <link rel="stylesheet" href="github-markdown.css">
13</head> 13</head>
14<body> 14<body>
15<h1 id="shaarli-wiki">Shaarli wiki</h1> 15<div id="local-sidebar">
16<p>Welcome to the <a href="https://github.com/shaarli/Shaarli/">Shaarli</a> wiki! Here you can find some info on how to use, configure, tweak and solve problems with your Shaarli. For general info, read the <a href="https://github.com/shaarli/Shaarli/blob/master/README.md">README</a>.</p>
17<p>If you have any questions or ideas, please join the <a href="https://gitter.im/shaarli/Shaarli">chat</a> (also reachable via <a href="https://irc.gitter.im/">IRC</a>), post them in our <a href="https://github.com/shaarli/Shaarli/issues/44">general discussion</a> or read the current <a href="https://github.com/shaarli/Shaarli/issues">issues</a>. If you've found a bug, please create a <a href="https://github.com/shaarli/Shaarli/issues/new">new issue</a>. If you would like a feature added to Shaarli, check the issues labeled <a href="https://github.com/shaarli/Shaarli/labels/feature"><code>feature</code></a>, <a href="https://github.com/shaarli/Shaarli/labels/enhancement"><code>enhancement</code></a>, and <a href="https://github.com/shaarli/Shaarli/labels/plugin"><code>plugin</code></a>.</p>
18<p><em>Note: This documentation is available online at <a href="https://github.com/shaarli/Shaarli/wiki">https://github.com/shaarli/Shaarli/wiki</a>, and locally in the <code>doc/</code> directory of your Shaarli installation.</em></p>
19<hr />
20<!-- MarkdownTOC depth=3 -->
21
22
23<ul> 16<ul>
24<li><p><a href="#basic-usage">Basic Usage</a></p> 17<li><a href="Home.html">Home</a></li>
18<li>Installation
25<ul> 19<ul>
26<li><a href="#add-the-sharing-button-_bookmarklet_-to-your-browser">Add the sharing button (<em>bookmarklet</em>) to your browser</a><br /></li> 20<li><a href="Server-requirements.html">Server requirements</a></li>
27<li><a href="#add-shaarli-as-a-sharing-service-to-firefox">Add Shaarli as a sharing service to Firefox</a><br /></li> 21<li><a href="Server-configuration.html">Server configuration</a></li>
28<li><a href="#share-links-using-the-_bookmarklet_">Share links using the <em>bookmarklet</em></a><br /></li> 22<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
29<li><a href="#sharing-links-using-firefox-share">Sharing links using Firefox share</a><br /></li>
30</ul></li> 23</ul></li>
31<li><p><a href="#other-usage-examples">Other usage examples</a></p> 24<li><a href="Usage.html">Usage</a>
32<ul> 25<ul>
33<li><a href="#using-shaarli-as-a-blog-notepad-pastebin">Using Shaarli as a blog, notepad, pastebin...</a><br /></li> 26<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
34<li><a href="#rss-feeds-or-picture-wall-for-a-specific-searchtag">RSS Feeds or Picture Wall for a specific search/tag</a><br /></li> 27<li><a href="Firefox-share.html">Firefox share</a></li>
28<li><a href="RSS-feeds.html">RSS feeds</a></li>
35</ul></li> 29</ul></li>
36<li><p><a href="#configuration">Configuration</a></p> 30<li>How To
37<ul> 31<ul>
38<li><a href="#main-dataoptionsphp-file">Main data/options.php file</a><br /></li> 32<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
39<li><a href="#changing-theme">Changing theme</a><br /></li> 33<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
40<li><a href="#changing-template">Changing template</a><br /></li> 34<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
41</ul></li> 35</ul></li>
42<li><a href="#backup">Backup</a><br /></li> 36<li><a href="Troubleshooting.html">Troubleshooting</a></li>
43<li><p><a href="#troubleshooting">Troubleshooting</a></p> 37<li><a href="Development.html">Development</a>
44<ul> 38<ul>
45<li><a href="#i-forgot-my-password-">I forgot my password !</a><br /></li> 39<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
46<li><a href="#im-locked-out---login-bruteforce-protection">I'm locked out - Login bruteforce protection</a><br /></li> 40<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
47<li><a href="#list-of-all-login-attempts">List of all login attempts</a><br /></li> 41<li><a href="Directory-structure.html">Directory structure</a></li>
48<li><a href="#exporting-from-diigo">Exporting from Diigo</a><br /></li> 42<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
49<li><a href="#importing-from-semanticscuttle">Importing from SemanticScuttle</a><br /></li> 43<li><a href="Plugin-System.html">Plugin System</a></li>
50<li><a href="#importing-from-mister-wong">Importing from Mister Wong</a><br /></li> 44<li><a href="Security.html">Security</a></li>
51<li><a href="#hosting-problems">Hosting problems</a><br /></li> 45<li><a href="Static-analysis.html">Static analysis</a></li>
52<li><a href="#dates-are-not-properly-formatted">Dates are not properly formatted</a><br /></li> 46<li><a href="Theming.html">Theming</a></li>
53<li><a href="#problems-on-centos-servers">Problems on CentOS servers</a><br /></li> 47<li><a href="Unit-tests.html">Unit tests</a></li>
54<li><a href="#my-session-expires--i-cant-stay-logged-in">My session expires ! I can't stay logged in</a><br /></li>
55<li><a href="#sessions-do-not-seem-to-work-correctly-on-your-server"><code>Sessions do not seem to work correctly on your server</code></a><br /></li>
56<li><a href="#pubsubhubbub-support">pubsubhubbub support</a><br /></li>
57</ul></li> 48</ul></li>
58<li><p><a href="#notes">Notes</a></p> 49<li>About
59<ul> 50<ul>
60<li><a href="#various-hacks">Various hacks</a><br /></li> 51<li><a href="FAQ.html">FAQ</a></li>
61<li><a href="#changing-timestamp-for-a-link">Changing timestamp for a link</a><br /></li> 52<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
53<li><a href="TODO.html">TODO</a></li>
62</ul></li> 54</ul></li>
63<li><p><a href="#related-software">Related software</a></p>
64<ul>
65<li><a href="#server-apps">Server apps</a><br /></li>
66<li><a href="#android-apps">Android apps</a><br /></li>
67<li><a href="#themes--templates">Themes &amp; templates</a><br /></li>
68<li><a href="#integrate-shaarli-with-other-platforms">Integrate Shaarli with other platforms</a><br /></li>
69<li><a href="#alternative-to-shaarli">Alternative to Shaarli</a><br /></li>
70</ul></li>
71<li><a href="#other-links">Other links</a><br /></li>
72<li><p><a href="#faq">FAQ</a></p>
73<ul>
74<li><a href="#why-did-you-create-shaarli-">Why did you create Shaarli ?</a><br /></li>
75<li><a href="#why-use-shaarli-and-not-deliciousdiigo-">Why use Shaarli and not Delicious/Diigo ?</a><br /></li>
76<li><a href="#what-does-shaarli-mean-">What does Shaarli mean ?</a><br /></li>
77</ul></li>
78<li><p><a href="#technical-details">Technical details</a></p>
79<ul>
80<li><a href="#directory-structure">Directory structure</a><br /></li>
81<li><a href="#development">Development</a><br /></li>
82<li><a href="#why-not-use-a-real-database--files-are-slow-">Why not use a real database ? Files are slow !</a><br /></li>
83</ul></li>
84<li><p><a href="#wiki---todo">Wiki - TODO</a></p></li>
85</ul>
86<!-- /MarkdownTOC -->
87
88
89
90
91<hr />
92<h1 id="basic-usage">Basic Usage</h1>
93<h3 id="add-the-sharing-button-bookmarklet-to-your-browser">Add the sharing button (<em>bookmarklet</em>) to your browser</h3>
94<ul>
95<li>Open your Shaarli and <code>Login</code><br /></li>
96<li>Click the <code>Tools</code> button in the top bar<br /></li>
97<li>Drag the <strong><code>✚Shaare link</code> button</strong>, and drop it to your browser's bookmarks bar.</li>
98</ul>
99<p><em>This bookmarklet button in compatible with Firefox, Opera, Chrome and Safari. Under Opera, you can't drag'n drop the button: You have to right-click on it and add a bookmark to your personal toolbar.</em></p>
100<p><img src="images/bookmarklet.png" /></p>
101<h3 id="add-shaarli-as-a-sharing-service-to-firefox">Add Shaarli as a sharing service to Firefox</h3>
102<ul>
103<li>Open your Shaarli and <code>Login</code><br /></li>
104<li>Click the <code>Tools</code> button in the top bar<br /></li>
105<li>Click the <code>✚Add to Firefox social</code> button and accept the activation.</li>
106</ul>
107<h3 id="share-links-using-the-bookmarklet">Share links using the <em>bookmarklet</em></h3>
108<ul>
109<li>When you are visiting a webpage you would like to share with Shaarli, click the <em>bookmarklet</em> you just added.<br /></li>
110<li>A window opens.<br /></li>
111<li>You can freely edit title, description, tags... to find it later using the text search or tag filtering.<br /></li>
112<li>You will be able to edit this link later using the <img src="https://raw.githubusercontent.com/shaarli/Shaarli/master/images/edit_icon.png" /> edit button.<br /></li>
113<li>You can also check the “Private” box so that the link is saved but only visible to you.<br /></li>
114<li>Click <code>Save</code>.<strong>Voila! Your link is now shared.</strong></li>
115</ul>
116<h3 id="sharing-links-using-firefox-share">Sharing links using Firefox share</h3>
117<ul>
118<li>Add the sharing service as described above<br /></li>
119<li>When you are visiting a webpage you would like to share with Shaarli, click the Firefox <em>Share</em> button [[images/firefoxshare.png]]<br /></li>
120<li>You can edit your link before and after saving, just like the bookmarklet above.</li>
121</ul>
122<h1 id="other-usage-examples">Other usage examples</h1>
123<p>Shaarli can be used:</p>
124<ul>
125<li>to share, comment and save interesting links and news<br /></li>
126<li>to bookmark useful/frequent personal links (as private links) and share them between computers<br /></li>
127<li>as a minimal blog/microblog/writing platform (no character limit)<br /></li>
128<li>as a read-it-later list (for example items tagged <code>readlater</code>)<br /></li>
129<li>to draft and save articles/ideas<br /></li>
130<li>to keep code snippets<br /></li>
131<li>to keep notes and documentation<br /></li>
132<li>as a shared clipboard between machines<br /></li>
133<li>as a todo list<br /></li>
134<li>to store playlists (e.g. with the <code>music</code> or <code>video</code> tags)<br /></li>
135<li>to keep extracts/comments from webpages that may disappear<br /></li>
136<li>to keep track of ongoing discussions (for example items tagged <code>discussion</code>)<br /></li>
137<li><a href="http://shaarli.chassegnouf.net/?9Efeiw">to feed RSS aggregators</a> (planets) with specific tags<br /></li>
138<li>to feed other social networks, blogs... using RSS feeds and external services (dlvr.it, ifttt.com ...)</li>
139</ul>
140<h3 id="using-shaarli-as-a-blog-notepad-pastebin...">Using Shaarli as a blog, notepad, pastebin...</h3>
141<ul>
142<li>Go to your Shaarli setup and log in<br /></li>
143<li>Click the <code>Add Link</code> button<br /></li>
144<li>To share text only, do not enter any URL in the corresponding input field and click <code>Add Link</code><br /></li>
145<li>Pick a title and enter your article, or note, in the description field; add a few tags; optionally check <code>Private</code> then click <code>Save</code><br /></li>
146<li>Voilà! Your article is now published (privately if you selected that option) and accessible using its permalink.</li>
147</ul>
148<h3 id="rss-feeds-or-picture-wall-for-a-specific-searchtag">RSS Feeds or Picture Wall for a specific search/tag</h3>
149<p>It is possible to filter RSS/ATOM feeds and Picture Wall on a Shaarli to <strong>only display results of a specific search, or for a specific tag</strong>. For example, if you want to subscribe only to links tagged <code>photography</code>:</p>
150<ul>
151<li>Go to the desired Shaarli instance.<br /></li>
152<li>Search for the <code>photography</code> tag in the <em>Filter by tag</em> box. Links tagged <code>photography</code> are displayed.<br /></li>
153<li>Click on the <code>RSS Feed</code> button.<br /></li>
154<li>You are presented with an RSS feed showing only these links. Subscribe to it to receive only updates with this tag.<br /></li>
155<li>The same method <strong>also works for a full-text search</strong> (<em>Search</em> box) <strong>and for the Picture Wall</strong> (want to only see pictures about <code>nature</code>?)<br /></li>
156<li>You can also build the URL manually: <code>https://my.shaarli.domain/?do=rss&amp;searchtags=nature</code>, <code>https://my.shaarli.domain/links/?do=picwall&amp;searchterm=poney</code></li>
157</ul>
158<p><img src="images/rss-filter-1.png" /> <img src="images/rss-filter-2.png" /></p>
159<h1 id="configuration">Configuration</h1>
160<h3 id="main-dataoptions.php-file">Main data/options.php file</h3>
161<p>To change the configuration, create the file <code>data/options.php</code>, example:</p>
162<pre><code> &lt;?php
163 $GLOBALS[&#39;config&#39;][&#39;LINKS_PER_PAGE&#39;] = 30;
164 $GLOBALS[&#39;config&#39;][&#39;HIDE_TIMESTAMPS&#39;] = true;
165 $GLOBALS[&#39;config&#39;][&#39;ENABLE_THUMBNAILS&#39;] = false;
166 ?&gt;</code></pre>
167<p><strong>Do not edit config options in index.php! Your changes would be lost when you upgrade.</strong> The following parameters are available (parameters (default value)):</p>
168<ul>
169<li><code>DATADIR ('data')</code> : This is the name of the subdirectory where Shaarli stores is data file. You can change it for better security.<br /></li>
170<li><code>CONFIG_FILE ($GLOBALS['config']['DATADIR'].'/config.php')</code> : Name of file which is used to store login/password.<br /></li>
171<li><code>DATASTORE ($GLOBALS['config']['DATADIR'].'/datastore.php')</code> : Name of file which contains the link database.<br /></li>
172<li><code>LINKS_PER_PAGE (20)</code> : Default number of links per page displayed.<br /></li>
173<li><code>IPBANS_FILENAME ($GLOBALS['config']['DATADIR'].'/ipbans.php')</code> : Name of file which records login attempts and IP bans.<br /></li>
174<li><code>BAN_AFTER (4)</code> : An IP address will be banned after this many failed login attempts.<br /></li>
175<li><code>BAN_DURATION (1800)</code> : Duration of ban (in seconds). (1800 seconds = 30 minutes)<br /></li>
176<li><code>OPEN_SHAARLI (false)</code> : If you set this option to true, anyone will be able to add/modify/delete/import/exports links without having to login.<br /></li>
177<li><code>HIDE_TIMESTAMPS (false)</code> : If you set this option to true, the date/time of each link will not be displayed (including in RSS Feed).#related-software<br /></li>
178<li><code>ENABLE_THUMBNAILS (true)</code> : Enable/disable thumbnails.<br /></li>
179<li><code>RAINTPL_TMP (tmp/)</code> : Raintpl cache directory (keep the trailing slash!)<br /></li>
180<li><code>RAINTPL_TPL (tpl/)</code> : Raintpl template directory (keep the trailing slash!). Edit this option if you want to change the rendering template (page structure) used by Shaarli. See <a href="#changing-template">Changing template</a><br /></li>
181<li><code>CACHEDIR ('cache')</code> : Directory where the thumbnails are stored.<br /></li>
182<li><code>ENABLE_LOCALCACHE (true)</code> : If you have a limited quota on your webspace, you can set this option to false: Shaarli will not generate thumbnails which need to be cached locally (vimeo, flickr, etc.). Thumbnails will still be visible for the services which do not use the local cache (youtube.com, imgur.com, dailymotion.com, imageshack.us)<br /></li>
183<li><code>UPDATECHECK_FILENAME ($GLOBALS['config']['DATADIR'].'/lastupdatecheck.txt')</code> : name of the file used to store available shaarli version.<br /></li>
184<li><code>UPDATECHECK_INTERVAL (86400)</code> : Delay between new Shaarli version check. 86400 seconds = 24 hours. Note that if you do not login for a week, Shaarli will not check for new version for a week.<br /></li>
185<li><code>ENABLE_UPDATECHECK</code>: Determines whether Shaarli check for new releases at <a href="https://github.com/shaarli/Shaarli">https://github.com/shaarli/Shaarli</a><br /></li>
186<li><code>SHOW_ATOM (false)</code> : Show an <code>ATOM Feed</code> button next to the <code>Subscribe</code> (RSS) button. ATOM feeds are available at the address <code>?do=atom</code> regardless of this option.<br /></li>
187<li><code>ARCHIVE_ORG (false)</code> : For each link, display a link to an archived version on archive.org<br /></li>
188<li><code>ENABLE_RSS_PERMALINKS (true)</code>: choose whether the RSS item title link points directly to the link, or to the entry on Shaarli (permalink). <code>true</code> is the original Shaarli bahevior (point directly to the link)<br /></li>
189<li><code>HIDE_PUBLIC_LINKS (false)</code>: setting this to true hides all links, even public ones, for non-logged in users.</li>
190</ul>
191<h3 id="changing-theme">Changing theme</h3>
192<ul>
193<li>Shaarli's apparence can be modified by editing CSS rules in <code>inc/user.css</code>. This file allows to override rules defined in the main <code>inc/shaarli.css</code> (only add changed rules), or define a whole new theme.<br /></li>
194<li>Do not edit <code>inc/shaarli.css</code>! Your changes would be overriden when updating Shaarli.<br /></li>
195<li>Some themes are available at <a href="https://github.com/shaarli/shaarli-themes">https://github.com/shaarli/shaarli-themes</a>.</li>
196</ul>
197<p>See also:</p>
198<ul>
199<li><a href="https://github.com/shaarli/Shaarli/wiki/Download-CSS-styles-for-shaarlis-listed-in-an-opml-file">Download CSS styles for shaarlis listed in an opml file</a></li>
200</ul>
201<h3 id="changing-template">Changing template</h3>
202<p>| WARNING | This feature is currently being worked on and will be improved in the next releases. Experimental. |<br />|---------|---------|</p>
203<ul>
204<li>Find the template you'd like to install. See the list of available templates (TODO). Find it's git clone URL or download the zip archive for the template.<br /></li>
205<li>In your Shaarli <code>tpl/</code> directory, run <code>git clone https://url/of/my-template/</code> or unpack the zip archive. There should now be a <code>my-template/</code> directory under the <code>tpl/</code> dir, containing directly all the template files.<br /></li>
206<li>Edit <code>data/options.php</code> to have Shaarli use this template. Eg.</li>
207</ul>
208<p><code>$GLOBALS['config']['RAINTPL_TPL'] = 'tpl/my-template/' ;</code></p>
209<p>You can find a list of compatible templates in <a href="#related-software">Related Software</a></p>
210<h1 id="backup">Backup</h1>
211<p>You have two ways of backing up your database:</p>
212<ul>
213<li><strong>Backup the file <code>data/datastore.php</code></strong> (by FTP or SSH). Restore by putting the file back in place.<br /></li>
214<li>Example command: <code>rsync -avzP my.server.com:/var/www/shaarli/data/datastore.php datastore-$(date +%Y-%m-%d_%H%M).php</code><br /></li>
215<li><strong>Export your links as HTML</strong> (Menu <code>Tools</code> &gt; <code>Export</code>). Restore by using the <code>Import</code> feature.<br /></li>
216<li>This can be done using the <a href="https://github.com/nodiscc/shaarchiver">shaarchiver</a> tool. Example command: <code>./export-bookmarks.py --url=https://my.server.com/shaarli --username=myusername --password=mysupersecretpassword --download-dir=./ --type=all</code></li>
217</ul>
218<h1 id="troubleshooting">Troubleshooting</h1>
219<h3 id="i-forgot-my-password">I forgot my password !</h3>
220<p>Delete the file data/config.php and display the page again. You will be asked for a new login/password.</p>
221<h3 id="im-locked-out---login-bruteforce-protection">I'm locked out - Login bruteforce protection</h3>
222<p>Login form is protected against brute force attacks: 4 failed logins will ban the IP address from login for 30 minutes. Banned IPs can still browse links.</p>
223<p>To remove the current IP bans, delete the file <code>data/ipbans.php</code></p>
224<h3 id="list-of-all-login-attempts">List of all login attempts</h3>
225<p>The file <code>data/log.txt</code> shows all logins (successful or failed) and bans/lifted bans.<br />Search for <code>failed</code> in this file to look for unauthorized login attempts.</p>
226<h3 id="exporting-from-diigo">Exporting from Diigo</h3>
227<p>If you export your bookmark from Diigo, make sure you use the Delicious export, not the Netscape export. (Their Netscape export is broken, and they don't seem to be interested in fixing it.)</p>
228<h3 id="importing-from-semanticscuttle">Importing from SemanticScuttle</h3>
229<p>To correctly import the tags from a <a href="http://semanticscuttle.sourceforge.net/">SemanticScuttle</a> HTML export, edit the HTML file before importing and replace all occurences of <code>tags=</code> (lowercase) to <code>TAGS=</code> (uppercase).</p>
230<h3 id="importing-from-mister-wong">Importing from Mister Wong</h3>
231<p>See <a href="https://github.com/sebsauvage/Shaarli/issues/146">this issue</a> for import tweaks.</p>
232<h3 id="hosting-problems">Hosting problems</h3>
233<ul>
234<li>On <strong>free.fr</strong> : Please note that free uses php 5.1 and thus you will not have autocomplete in tag editing. Don't forget to create a <code>sessions</code> directory at the root of your webspace. Change the file extension to <code>.php5</code> or create a <code>.htaccess</code> file in the directory where Shaarli is located containing:</li>
235</ul>
236<pre><code>php 1
237SetEnv PHP_VER 5</code></pre>
238<ul>
239<li>If you have an error such as: <code>Parse error: syntax error, unexpected '=', expecting '(' in /links/index.php on line xxx</code>, it means that your host is using php4, not php5. Shaarli requires php 5.1. Try changing the file extension to <code>.php5</code><br /></li>
240<li>On <strong>1and1</strong> : If you add the link from the page (and not from the bookmarklet), Shaarli will no be able to get the title of the page. You will have to enter it manually. (Because they have disabled the ability to download a file through HTTP).<br /></li>
241<li>If you have the error <code>Warning: file_get_contents() [function.file-get-contents]: URL file-access is disabled in the server configuration in /…/index.php on line xxx</code>, it means that your host has disabled the ability to fetch a file by HTTP in the php config (Typically in 1and1 hosting). Bad host. Change host. Or comment the following lines:</li>
242</ul>
243<pre><code>//list($status,$headers,$data) = getHTTP($url,4); // Short timeout to keep the application responsive.
244// FIXME: Decode charset according to charset specified in either 1) HTTP response headers or 2) &lt;head&gt; in html
245//if (strpos($status,&#39;200 OK&#39;)) $title=html_extract_title($data);</code></pre>
246<ul>
247<li>On hosts which forbid outgoing HTTP requests (such as free.fr), some thumbnails will not work.<br /></li>
248<li>On <strong>lost-oasis</strong>, RSS doesn't work correctly, because of this message at the begining of the RSS/ATOM feed : <code>&lt;? // tout ce qui est charge ici (generalement des includes et require) est charge en permanence. ?&gt;</code>. To fix this, remove this message from <code>php-include/prepend.php</code></li>
249</ul>
250<h3 id="dates-are-not-properly-formatted">Dates are not properly formatted</h3>
251<p>Shaarli tries to sniff the language of the browser (using HTTP_ACCEPT_LANGUAGE headers) and choose a date format accordingly. But Shaarli can only use the date formats (and more generaly speaking, the locales) provided by the webserver. So even if you have a browser in French, you may end up with dates in US format (it's the case on sebsauvage.net :-( )</p>
252<h3 id="problems-on-centos-servers">Problems on CentOS servers</h3>
253<p>On <strong>CentOS</strong>/RedHat derivatives, you may need to install the <code>php-mbstring</code> package.</p>
254<h3 id="my-session-expires-i-cant-stay-logged-in">My session expires ! I can't stay logged in</h3>
255<p>This can be caused by several things:</p>
256<ul>
257<li>Your php installation may not have a proper directory setup for session files. (eg. on Free.fr you need to create a <code>session</code> directory on the root of your website.) You may need to create the session directory of set it up.<br /></li>
258<li>Most hosts regularly clean the temporary and session directories. Your host may be cleaning those directories too aggressively (eg.OVH hosts), forcing an expire of the session. You may want to set the session directory in your web root. (eg. Create the <code>sessions</code> subdirectory and add <code>ini_set('session.save_path', $_SERVER['DOCUMENT_ROOT'].'/../sessions');</code>. Make sure this directory is not browsable !)<br /></li>
259<li>If your IP address changes during surfing, Shaarli will force expire your session for security reasons (to prevent session cookie hijacking). This can happen when surfing from WiFi or 3G (you may have switched WiFi/3G access point), or in some corporate/university proxies which use load balancing (and may have proxies with several external IP addresses).<br /></li>
260<li>Some browser addons may interfer with HTTP headers (ipfuck/ipflood/GreaseMonkey…). Try disabling those.<br /></li>
261<li>You may be using OperaTurbo or OperaMini, which use their own proxies which may change from time to time.<br /></li>
262<li>If you have another application on the same webserver where Shaarli is installed, these application may forcefully expire php sessions.</li>
263</ul>
264<h3 id="sessions-do-not-seem-to-work-correctly-on-your-server"><code>Sessions do not seem to work correctly on your server</code></h3>
265<p>Follow the instructions in the error message. Make sure you are accessing shaarli via a direct IP address or a proper hostname. If you have <strong>no dots</strong> in the hostname (e.g. <code>localhost</code> or <code>http://my-webserver/shaarli/</code>), some browsers will not store cookies at all (this respects the <a href="http://curl.haxx.se/rfc/cookie_spec.html">HTTP cookie specification</a>).</p>
266<h3 id="pubsubhubbub-support">pubsubhubbub support</h3>
267<p>Download <a href="https://pubsubhubbub.googlecode.com/git/publisher_clients/php/library/publisher.php">publisher.php</a> at the root of your Shaarli installation and set <code>$GLOBALS['config']['PUBSUBHUB_URL']</code> in your <code>config.php</code></p>
268<h1 id="notes">Notes</h1>
269<h3 id="various-hacks">Various hacks</h3>
270<ul>
271<li><a href="Example-patch---add-new-via-field-for-links">Example patch: add a new &quot;via&quot; field for links</a><br /></li>
272<li><a href="Copy-a-Shaarli-installation-over-SSH-SCP,-serve-it-locally-with-php-cli">Copy a Shaarli installation over SSH SCP, serve it locally with php cli</a><br /></li>
273<li><p>To display the array representing the data saved in datastore.php, use the following snippet</p>
274<pre><code>$data = &quot;tZNdb9MwFIb... &lt;Commented content inside datastore.php&gt;&quot;;
275$out = unserialize(gzinflate(base64_decode($data)));
276echo &quot;&lt;pre&gt;&quot;; // Pretty printing is love, pretty printing is life
277print_r($out);
278echo &quot;&lt;/pre&gt;&quot;;
279exit;</code></pre>
280<p>This will output the internal representation of the datastore, &quot;unobfuscated&quot; (if this can really be considered obfuscation)</p></li>
281</ul>
282<h3 id="changing-timestamp-for-a-link">Changing timestamp for a link</h3>
283<ul>
284<li>Look for <code>&lt;input type=&quot;hidden&quot; name=&quot;lf_linkdate&quot; value=&quot;{$link.linkdate}&quot;&gt;</code> in <code>tpl/editlink.tpl</code> (line 14)<br /></li>
285<li>Remove <code>type=&quot;hidden&quot;</code> from this line<br /></li>
286<li>A new date/time field becomes available in the edit/new link dialog. You can set the timestamp manually by entering it in the format <code>YYYMMDD_HHMMS</code>.</li>
287</ul>
288<h1 id="related-software">Related software</h1>
289<p>Unofficial but relatedd work on Shaarli. If you maintain one of these, please get in touch with us to help us find a way to adapt your work to our fork. <strong>TODO</strong> contact repos owners to see if they'd like to standardize their work for the community fork.</p>
290<h3 id="server-apps">Server apps</h3>
291<ul>
292<li><a href="https://github.com/nodiscc/shaarchiver">shaarchiver</a> - Archive your Shaarli bookmarks and their content<br /></li>
293<li><a href="https://github.com/mknexen/shaarli-river">shaarli-river</a> - An aggregator for shaarlis with many features<br /></li>
294<li><a href="https://github.com/DMeloni/shaarlo">Shaarlo</a> - An aggregator for shaarlis with many features (a very popular running instance among french shaarliers: <a href="http://shaarli.fr/">shaarli.fr</a>)<br /></li>
295<li><a href="https://github.com/BoboTiG/shaarlimages">Shaarlimages</a> - An image-oriented aggregator for Shaarlis<br /></li>
296<li><a href="https://github.com/mknexen/shaarli-api">mknexen/shaarli-api</a> - A REST API for Shaarli</li>
297</ul>
298<h3 id="android-apps">Android apps</h3>
299<ul>
300<li><a href="http://sebsauvage.net/links/?ZAyDzg">Shaarli for Android</a> - Android application that adds Shaarli as a sharing provider<br /></li>
301<li><a href="https://github.com/dimtion/Shaarlier">Shaarlier for Android</a> - Android application to simply add links directly into your Shaarli</li>
302</ul>
303<h3 id="themes-templates">Themes &amp; templates</h3>
304<ul>
305<li><a href="https://github.com/AkibaTech/Shaarli---SuperHero-Theme">AkibaTech/Shaarli Superhero Theme</a> - A template/theme for Shaarli<br /></li>
306<li><a href="https://github.com/alexisju/albinomouse-template">alexisju/albinomouse-template</a> - A full template for Shaarli<br /></li>
307<li><a href="https://github.com/dhoko/ShaarliTemplate">dhoko/ShaarliTemplate</a> - A template/theme for Shaarli<br /></li>
308<li><a href="https://github.com/kalvn/shaarli-blocks">kalvn/shaarli-blocks</a> - A template/theme for Shaarli<br /></li>
309<li><a href="https://github.com/kalvn/Shaarli-Material">kalvn/Shaarli-Material</a> - A theme (template) based on Google's Material Design for Shaarli, the superfast delicious clone.<br /></li>
310<li><a href="https://github.com/misterair/limonade">misterair/Limonade</a> - A fork of (legacy) Shaarli with a new template<br /></li>
311<li><a href="https://github.com/Vinm/Blue-theme-for-Shaarli">Vinm/Blue-theme-for Shaarli</a> - A template/theme for Shaarli (<a href="https://github.com/Vinm/Blue-theme-for-Shaarli/issues/2">unmaintained</a>, compatibility unknown)<br /></li>
312<li><a href="https://github.com/vivienhaese/shaarlitheme">vivienhaese/shaarlitheme</a> - A Shaarli fork meant to be run in an openshift instance</li>
313</ul>
314<h3 id="integrate-shaarli-with-other-platforms">Integrate Shaarli with other platforms</h3>
315<ul>
316<li><a href="https://github.com/jcsaaddupuy/tt-rss-shaarli">tt-rss-shaarli</a> - <a href="http://tt-rss.org/">TinyTiny RSS</a> plugin that adds support for sharing articles with Shaarli<br /></li>
317<li><a href="https://github.com/ahmet2mir/octopress-shaarli">octopress-shaarli</a> - octoprress plugin to retrieve SHaarli links on the sidebara</li>
318</ul>
319<h3 id="alternative-to-shaarli">Alternative to Shaarli</h3>
320<ul>
321<li><a href="https://github.com/bookieio/bookie">Bookie</a> - Another self-hostable, Free bookmark sharing software, written in Python<br /></li>
322<li><a href="https://github.com/plainmade/unmark">Unmark</a> - An open source to do app for bookmarks (<a href="https://unmark.it/">Homepage</a>)</li>
323</ul>
324<h1 id="other-links">Other links</h1>
325<ul>
326<li><a href="http://sebsauvage.net/links/">Liens en vrac de sebsauvage</a> - the original Shaarli<br /></li>
327<li><a href="http://porneia.free.fr/pub/links/ou-est-shaarli.html">A large list of Shaarlis</a><br /></li>
328<li><a href="https://raw.githubusercontent.com/Oros42/find_shaarlis/master/annuaires.json">A list of working Shaarli aggregators</a><br /></li>
329<li><a href="https://github.com/Oros42/shaarlis_list">A list of some known Shaarlis</a><br /></li>
330<li><a href="http://sebsauvage.net/rhaa/index.php?2011/09/16/09/29/58-adieu-delicious-diigo-et-stumbleupon-salut-shaarli-">Adieu Delicious, Diigo et StumbleUpon. Salut Shaarli ! - sebsauvage.net</a> (fr) <em>16/09/2011 - the original post about Shaarli</em><br /></li>
331<li><a href="http://sebsauvage.net/wiki/doku.php?id=php:shaarli:ideas">Original ideas/fixme/TODO page</a><br /></li>
332<li><a href="http://sebsauvage.net/wiki/doku.php?id=php:shaarli:discussion">Original discussion page</a> (fr)<br /></li>
333<li><a href="http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history">Original revisions history</a><br /></li>
334<li><a href="https://www.shaarli.fr/my.php">Shaarli.fr/my</a> - Unofficial, unsupported (old fork) hosted Shaarlis provider, courtesy of <a href="https://github.com/DMeloni">DMeloni</a><br /></li>
335<li><a href="http://shaarferme.etudiant-libre.fr.nf/index.php">Shaarli Communauty</a> - Another unofficial Shaarli hoster (unsupported, old fork), hoster unknown</li>
336</ul>
337<h1 id="faq">FAQ</h1>
338<h3 id="why-did-you-create-shaarli">Why did you create Shaarli ?</h3>
339<p>I was a StumbleUpon user. Then I got fed up with they big toolbar. I switched to delicious, which was lighter, faster and more beautiful. Until Yahoo bought it. Then the export API broke all the time, delicious became slow and was ditched by Yahoo. I switched to Diigo, which is not bad, but does too much. And Diigo is sslllooooowww and their Firefox extension a bit buggy. And… oh… <strong>their Firefox addon sends to Diigo every single URL you visit</strong> (Don't believe me ? Use <a href="https://addons.mozilla.org/en-US/firefox/addon/tamper-data/">Tamper Data</a> and open any page).</p>
340<p>Enough is enough. Saving simple links should not be a complicated heavy thing. I ditched them all and wrote my own: Shaarli. It's simple, but it does the job and does it well. And my data is not hosted on a foreign server, but on my server.</p>
341<h3 id="why-use-shaarli-and-not-deliciousdiigo">Why use Shaarli and not Delicious/Diigo ?</h3>
342<p>With Shaarli:</p>
343<ul>
344<li>The data is yours: It's hosted on your server.<br /></li>
345<li>Never fear of having your data locked-in.<br /></li>
346<li>Never fear to have your data sold to third party.<br /></li>
347<li>Your private links are not hosted on a third party server.<br /></li>
348<li>You are not tracked by browser addons (like Diigo does)<br /></li>
349<li>You can change the look and feel of the pages if you want.<br /></li>
350<li>You can change the behaviour of the program.<br /></li>
351<li>It's magnitude faster than most bookmarking services.</li>
352</ul>
353<h3 id="what-does-shaarli-mean">What does Shaarli mean ?</h3>
354<p>Shaarli is for shaaring your links.</p>
355<h1 id="technical-details">Technical details</h1>
356<ul>
357<li>Application is protected against XSRF (Cross-site requests forgery): Forms which act on data (save,delete…) contain a token generated by the server. Any posted form which does not contain a valid token is rejected. Any token can only be used once. Token are attached to the session and cannot be reused in another session.<br /></li>
358<li>Sessions automatically expires after 60 minutes. Sessions are protected against highjacking: The sessionID cannot be used from a different IP address.<br /></li>
359<li>An .htaccess file protects the data file.<br /></li>
360<li><p>Link database is an associative array which is serialized, compressed (with deflate), base64-encoded and saved as a comment in a .php file. Thus even if the server does not support htaccess files, the data file will still not be readable by URL. The database looks like this:</p>
361<pre><code>&lt;?php /* zP1ZjxxJtiYIvvevEPJ2lDOaLrZv7o...
362...ka7gaco/Z+TFXM2i7BlfMf8qxpaSSYfKlvqv/x8= */ ?&gt;</code></pre></li>
363<li>The password is salted, hashed and stored in the data subdirectory, in a php file, and protected by htaccess. Even if the webserver does not support htaccess, the hash is not readable by URL. Even if the .php file is stolen, the password cannot deduced from the hash. The salt prevents rainbow-tables attacks.<br /></li>
364<li>Shaarli relies on <code>HTTP_REFERER</code> for some functions (like redirects and clicking on tags). If you have disabled or masqueraded <code>HTTP_REFERER</code> in your browser, some features of Shaarli may not work<br /></li>
365<li><code>magic_quotes</code> is a horrible option of php which is often activated on servers. No serious developer should rely on this horror to secure their code against SQL injections. You should disable it (and Shaarli expects this option to be disabled). Nevertheless, I have added code to cope with magic_quotes on, so you should not be bothered even on crappy hosts.<br /></li>
366<li><p>Small hashes are used to make a link to an entry in Shaarli. They are unique. In fact, the date of the items (eg.20110923_150523) is hashed with CRC32, then converted to base64 and some characters are replaced. They are always 6 characters longs and use only A-Z a-z 0-9 - _ and @.</p></li>
367</ul>
368<h3 id="directory-structure">Directory structure</h3>
369<p>Here is the directory structure of Shaarli and the purpose of the different files:</p>
370<pre><code> index.php : Main program.
371 application/ : Shaarli classes
372 ├── LinkDB.php
373 └── Utils.php
374 tests/ : Shaarli unitary &amp; functional tests
375 ├── LinkDBTest.php
376 ├── utils # utilities to ease testing
377 │ └── ReferenceLinkDB.php
378 └── UtilsTest.php
379 COPYING : Shaarli license.
380 inc/ : Includes (libraries, CSS…)
381 ├── awesomplete.*: tags autocompletion library
382 ├── blazy.*: picture wall lazy image loading library
383 ├── shaarli.css, reset.css : Shaarli stylesheet.
384 ├── qr.* : qr code generation library
385 └──rain.tpl.class.php : RainTPL templating library.
386 tpl/ : RainTPL templates for Shaarli. They are used to build the pages.
387 images/ : Images and icons used in Shaarli.
388 data/ : Directory where data is stored (bookmark database, configuration, logs, banlist…)
389 ├── config.php : Shaarli configuration (login, password, timezone, title…)
390 ├── datastore.php : Your link database (compressed).
391 ├── ipban.php : IP address ban system data.
392 ├── lastupdatecheck.txt : Update check timestamp file (used to check every 24 hours if a new version of Shaarli is available).
393 └──log.txt : login/IPban log.
394 cache/ : Directory containing the thumbnails cache. This directory is automatically created. You can erase it anytime you want.
395 tmp/ : Temporary directory for compiled RainTPL templates. This directory is automatically created. You can erase it anytime you want.</code></pre>
396<h3 id="development">Development</h3>
397<ul>
398<li><a href="https://github.com/shaarli/Shaarli/tree/master/CONTRIBUTING.md">Contributing to Shaarli</a><br /></li>
399<li><a href="Running-unit-tests">Running unit tests</a><br /></li>
400<li>Patches should try to stick to the <a href="http://www.php-fig.org/psr/">PHP Standard Recommendations</a> (PSR), especially:<br /></li>
401<li><a href="http://www.php-fig.org/psr/psr-1/">PSR-1</a> - Basic Coding Standard<br /></li>
402<li><a href="http://www.php-fig.org/psr/psr-2/">PSR-2</a> - Coding Style Guide</li>
403</ul>
404<h3 id="why-not-use-a-real-database-files-are-slow">Why not use a real database ? Files are slow !</h3>
405<p>Does browsing <a href="http://sebsauvage.net/links/">this page</a> feel slow ? Try browsing older pages, too.</p>
406<p>It's not slow at all, is it ? And don't forget the database contains more than 16000 links, and it's on a shared host, with 32000 visitors/day for my website alone. And it's still damn fast. Why ?</p>
407<p>The data file is only 3.7 Mb. It's read 99% of the time, and is probably already in the operation system disk cache. So generating a page involves no I/O at all most of the time.</p>
408<h1 id="wiki---todo">Wiki - TODO</h1>
409<ul>
410<li>translate (new page can be called Home.fr, Home.es ... and linked from Home)<br /></li>
411<li>add more screenshots<br /></li>
412<li>add developer documentation (storage architecture, classes and functions, security handling, ...)</li>
413</ul> 55</ul>
56</div>
57<h1 id="home">Home</h1>
58<h1 id="shaarli-wiki">Shaarli wiki</h1>
59<p>Welcome to the <a href="https://github.com/shaarli/Shaarli/">Shaarli</a> wiki<embed src=".html" /></p>
60<p>Here you can find some info on how to use, configure, tweak and solve problems with your Shaarli.</p>
61<p>For general info, read the <a href="https://github.com/shaarli/Shaarli/blob/master/README.md">README</a>.<a href=".html"></a></p>
62<p>If you have any questions or ideas, please join the <a href="https://gitter.im/shaarli/Shaarli">chat</a> (also reachable via <a href="https://irc.gitter.im/">IRC</a>), post them in our <a href="https://github.com/shaarli/Shaarli/issues/44">general discussion</a> or read the current <a href="https://github.com/shaarli/Shaarli/issues">issues</a>. If you've found a bug, please create a <a href="https://github.com/shaarli/Shaarli/issues/new">new issue</a>.<a href=".html"></a></p>
63<p>If you would like a feature added to Shaarli, check the issues labeled <a href="https://github.com/shaarli/Shaarli/labels/feature"><code>feature</code></a>, <a href="https://github.com/shaarli/Shaarli/labels/enhancement"><code>enhancement</code></a>, and <a href="https://github.com/shaarli/Shaarli/labels/plugin"><code>plugin</code></a>.<a href=".html"></a></p>
64<p><em>Note: This documentation is available online at <a href="https://github.com/shaarli/Shaarli/wiki" class="uri">https://github.com/shaarli/Shaarli/wiki</a>, and locally in the <code>doc/</code> directory of your Shaarli installation.</em></p>
414</body> 65</body>
415</html> 66</html>
diff --git a/doc/Home.md b/doc/Home.md
index b5d9c396..a824d983 100644
--- a/doc/Home.md
+++ b/doc/Home.md
@@ -1,449 +1,14 @@
1#Home
1# Shaarli wiki 2# Shaarli wiki
2 3
3Welcome to the [Shaarli](https://github.com/shaarli/Shaarli/) wiki! Here you can find some info on how to use, configure, tweak and solve problems with your Shaarli. For general info, read the [README](https://github.com/shaarli/Shaarli/blob/master/README.md). 4Welcome to the [Shaarli](https://github.com/shaarli/Shaarli/) wiki![](.html)
4 5
5If you have any questions or ideas, please join the [chat](https://gitter.im/shaarli/Shaarli) (also reachable via [IRC](https://irc.gitter.im/)), post them in our [general discussion](https://github.com/shaarli/Shaarli/issues/44) or read the current [issues](https://github.com/shaarli/Shaarli/issues). If you've found a bug, please create a [new issue](https://github.com/shaarli/Shaarli/issues/new). If you would like a feature added to Shaarli, check the issues labeled [`feature`](https://github.com/shaarli/Shaarli/labels/feature), [`enhancement`](https://github.com/shaarli/Shaarli/labels/enhancement), and [`plugin`](https://github.com/shaarli/Shaarli/labels/plugin). 6Here you can find some info on how to use, configure, tweak and solve problems with your Shaarli.
6
7_Note: This documentation is available online at https://github.com/shaarli/Shaarli/wiki, and locally in the `doc/` directory of your Shaarli installation._
8
9----------------------------------------------------------------------------------
10
11<!-- MarkdownTOC depth=3 -->
12
13- [Basic Usage](#basic-usage)
14 - [Add the sharing button (_bookmarklet_) to your browser](#add-the-sharing-button-_bookmarklet_-to-your-browser)
15 - [Add Shaarli as a sharing service to Firefox](#add-shaarli-as-a-sharing-service-to-firefox)
16 - [Share links using the _bookmarklet_](#share-links-using-the-_bookmarklet_)
17 - [Sharing links using Firefox share](#sharing-links-using-firefox-share)
18- [Other usage examples](#other-usage-examples)
19 - [Using Shaarli as a blog, notepad, pastebin...](#using-shaarli-as-a-blog-notepad-pastebin)
20 - [RSS Feeds or Picture Wall for a specific search/tag](#rss-feeds-or-picture-wall-for-a-specific-searchtag)
21- [Configuration](#configuration)
22 - [Main data/options.php file](#main-dataoptionsphp-file)
23 - [Changing theme](#changing-theme)
24 - [Changing template](#changing-template)
25- [Backup](#backup)
26- [Troubleshooting](#troubleshooting)
27 - [I forgot my password !](#i-forgot-my-password-)
28 - [I'm locked out - Login bruteforce protection](#im-locked-out---login-bruteforce-protection)
29 - [List of all login attempts](#list-of-all-login-attempts)
30 - [Exporting from Diigo](#exporting-from-diigo)
31 - [Importing from SemanticScuttle](#importing-from-semanticscuttle)
32 - [Importing from Mister Wong](#importing-from-mister-wong)
33 - [Hosting problems](#hosting-problems)
34 - [Dates are not properly formatted](#dates-are-not-properly-formatted)
35 - [Problems on CentOS servers](#problems-on-centos-servers)
36 - [My session expires ! I can't stay logged in](#my-session-expires--i-cant-stay-logged-in)
37 - [`Sessions do not seem to work correctly on your server`](#sessions-do-not-seem-to-work-correctly-on-your-server)
38 - [pubsubhubbub support](#pubsubhubbub-support)
39- [Notes](#notes)
40 - [Various hacks](#various-hacks)
41 - [Changing timestamp for a link](#changing-timestamp-for-a-link)
42- [Related software](#related-software)
43 - [Server apps](#server-apps)
44 - [Android apps](#android-apps)
45 - [Themes & templates](#themes--templates)
46 - [Integrate Shaarli with other platforms](#integrate-shaarli-with-other-platforms)
47 - [Alternative to Shaarli](#alternative-to-shaarli)
48- [Other links](#other-links)
49- [FAQ](#faq)
50 - [Why did you create Shaarli ?](#why-did-you-create-shaarli-)
51 - [Why use Shaarli and not Delicious/Diigo ?](#why-use-shaarli-and-not-deliciousdiigo-)
52 - [What does Shaarli mean ?](#what-does-shaarli-mean-)
53- [Technical details](#technical-details)
54 - [Directory structure](#directory-structure)
55 - [Development](#development)
56 - [Why not use a real database ? Files are slow !](#why-not-use-a-real-database--files-are-slow-)
57- [Wiki - TODO](#wiki---todo)
58
59<!-- /MarkdownTOC -->
60
61
62
63------------------------------------------------------------------
64
65# Basic Usage
66
67### Add the sharing button (_bookmarklet_) to your browser
68
69 * Open your Shaarli and `Login`
70 * Click the `Tools` button in the top bar
71 * Drag the **`✚Shaare link` button**, and drop it to your browser's bookmarks bar.
72
73_This bookmarklet button in compatible with Firefox, Opera, Chrome and Safari. Under Opera, you can't drag'n drop the button: You have to right-click on it and add a bookmark to your personal toolbar._
74
75![](images/bookmarklet.png)
76
77
78### Add Shaarli as a sharing service to Firefox
79
80 * Open your Shaarli and `Login`
81 * Click the `Tools` button in the top bar
82 * Click the `✚Add to Firefox social` button and accept the activation.
83
84
85### Share links using the _bookmarklet_
86
87 * When you are visiting a webpage you would like to share with Shaarli, click the _bookmarklet_ you just added.
88 * A window opens.
89 * You can freely edit title, description, tags... to find it later using the text search or tag filtering.
90 * You will be able to edit this link later using the ![](https://raw.githubusercontent.com/shaarli/Shaarli/master/images/edit_icon.png) edit button.
91 * You can also check the “Private” box so that the link is saved but only visible to you.
92 * Click `Save`.**Voila! Your link is now shared.**
93
94
95### Sharing links using Firefox share
96
97 * Add the sharing service as described above
98 * When you are visiting a webpage you would like to share with Shaarli, click the Firefox _Share_ button [[images/firefoxshare.png]]
99 * You can edit your link before and after saving, just like the bookmarklet above.
100
101
102# Other usage examples
103Shaarli can be used:
104
105 * to share, comment and save interesting links and news
106 * to bookmark useful/frequent personal links (as private links) and share them between computers
107 * as a minimal blog/microblog/writing platform (no character limit)
108 * as a read-it-later list (for example items tagged `readlater`)
109 * to draft and save articles/ideas
110 * to keep code snippets
111 * to keep notes and documentation
112 * as a shared clipboard between machines
113 * as a todo list
114 * to store playlists (e.g. with the `music` or `video` tags)
115 * to keep extracts/comments from webpages that may disappear
116 * to keep track of ongoing discussions (for example items tagged `discussion`)
117 * [to feed RSS aggregators](http://shaarli.chassegnouf.net/?9Efeiw) (planets) with specific tags
118 * to feed other social networks, blogs... using RSS feeds and external services (dlvr.it, ifttt.com ...)
119
120### Using Shaarli as a blog, notepad, pastebin...
121
122 * Go to your Shaarli setup and log in
123 * Click the `Add Link` button
124 * To share text only, do not enter any URL in the corresponding input field and click `Add Link`
125 * Pick a title and enter your article, or note, in the description field; add a few tags; optionally check `Private` then click `Save`
126 * Voilà! Your article is now published (privately if you selected that option) and accessible using its permalink.
127
128
129### RSS Feeds or Picture Wall for a specific search/tag
130It is possible to filter RSS/ATOM feeds and Picture Wall on a Shaarli to **only display results of a specific search, or for a specific tag**. For example, if you want to subscribe only to links tagged `photography`:
131 * Go to the desired Shaarli instance.
132 * Search for the `photography` tag in the _Filter by tag_ box. Links tagged `photography` are displayed.
133 * Click on the `RSS Feed` button.
134 * You are presented with an RSS feed showing only these links. Subscribe to it to receive only updates with this tag.
135 * The same method **also works for a full-text search** (_Search_ box) **and for the Picture Wall** (want to only see pictures about `nature`?)
136 * You can also build the URL manually: `https://my.shaarli.domain/?do=rss&searchtags=nature`, `https://my.shaarli.domain/links/?do=picwall&searchterm=poney`
137
138![](images/rss-filter-1.png) ![](images/rss-filter-2.png)
139
140# Configuration
141
142### Main data/options.php file
143
144To change the configuration, create the file `data/options.php`, example:
145```
146 <?php
147 $GLOBALS['config']['LINKS_PER_PAGE'] = 30;
148 $GLOBALS['config']['HIDE_TIMESTAMPS'] = true;
149 $GLOBALS['config']['ENABLE_THUMBNAILS'] = false;
150 ?>
151```
152
153**Do not edit config options in index.php! Your changes would be lost when you upgrade.** The following parameters are available (parameters (default value)):
154
155 * `DATADIR ('data')` : This is the name of the subdirectory where Shaarli stores is data file. You can change it for better security.
156 * `CONFIG_FILE ($GLOBALS['config']['DATADIR'].'/config.php')` : Name of file which is used to store login/password.
157 * `DATASTORE ($GLOBALS['config']['DATADIR'].'/datastore.php')` : Name of file which contains the link database.
158 * `LINKS_PER_PAGE (20)` : Default number of links per page displayed.
159 * `IPBANS_FILENAME ($GLOBALS['config']['DATADIR'].'/ipbans.php')` : Name of file which records login attempts and IP bans.
160 * `BAN_AFTER (4)` : An IP address will be banned after this many failed login attempts.
161 * `BAN_DURATION (1800)` : Duration of ban (in seconds). (1800 seconds = 30 minutes)
162 * `OPEN_SHAARLI (false)` : If you set this option to true, anyone will be able to add/modify/delete/import/exports links without having to login.
163 * `HIDE_TIMESTAMPS (false)` : If you set this option to true, the date/time of each link will not be displayed (including in RSS Feed).#related-software
164 * `ENABLE_THUMBNAILS (true)` : Enable/disable thumbnails.
165 * `RAINTPL_TMP (tmp/)` : Raintpl cache directory (keep the trailing slash!)
166 * `RAINTPL_TPL (tpl/)` : Raintpl template directory (keep the trailing slash!). Edit this option if you want to change the rendering template (page structure) used by Shaarli. See [Changing template](#changing-template)
167 * `CACHEDIR ('cache')` : Directory where the thumbnails are stored.
168 * `ENABLE_LOCALCACHE (true)` : If you have a limited quota on your webspace, you can set this option to false: Shaarli will not generate thumbnails which need to be cached locally (vimeo, flickr, etc.). Thumbnails will still be visible for the services which do not use the local cache (youtube.com, imgur.com, dailymotion.com, imageshack.us)
169 * `UPDATECHECK_FILENAME ($GLOBALS['config']['DATADIR'].'/lastupdatecheck.txt')` : name of the file used to store available shaarli version.
170 * `UPDATECHECK_INTERVAL (86400)` : Delay between new Shaarli version check. 86400 seconds = 24 hours. Note that if you do not login for a week, Shaarli will not check for new version for a week.
171 * `ENABLE_UPDATECHECK`: Determines whether Shaarli check for new releases at https://github.com/shaarli/Shaarli
172 * `SHOW_ATOM (false)` : Show an `ATOM Feed` button next to the `Subscribe` (RSS) button. ATOM feeds are available at the address `?do=atom` regardless of this option.
173 * `ARCHIVE_ORG (false)` : For each link, display a link to an archived version on archive.org
174 * `ENABLE_RSS_PERMALINKS (true)`: choose whether the RSS item title link points directly to the link, or to the entry on Shaarli (permalink). `true` is the original Shaarli bahevior (point directly to the link)
175 * `HIDE_PUBLIC_LINKS (false)`: setting this to true hides all links, even public ones, for non-logged in users.
176
177
178### Changing theme
179 * Shaarli's apparence can be modified by editing CSS rules in `inc/user.css`. This file allows to override rules defined in the main `inc/shaarli.css` (only add changed rules), or define a whole new theme.
180 * Do not edit `inc/shaarli.css`! Your changes would be overriden when updating Shaarli.
181 * Some themes are available at https://github.com/shaarli/shaarli-themes.
182
183See also:
184 * [Download CSS styles for shaarlis listed in an opml file](https://github.com/shaarli/Shaarli/wiki/Download-CSS-styles-for-shaarlis-listed-in-an-opml-file)
185
186### Changing template
187
188| WARNING | This feature is currently being worked on and will be improved in the next releases. Experimental. |
189|---------|---------|
190
191 * Find the template you'd like to install. See the list of available templates (TODO). Find it's git clone URL or download the zip archive for the template.
192 * In your Shaarli `tpl/` directory, run `git clone https://url/of/my-template/` or unpack the zip archive. There should now be a `my-template/` directory under the `tpl/` dir, containing directly all the template files.
193 * Edit `data/options.php` to have Shaarli use this template. Eg.
194
195`$GLOBALS['config']['RAINTPL_TPL'] = 'tpl/my-template/' ;`
196
197You can find a list of compatible templates in [Related Software](#related-software)
198
199# Backup
200
201You have two ways of backing up your database:
202* **Backup the file `data/datastore.php`** (by FTP or SSH). Restore by putting the file back in place.
203 * Example command: `rsync -avzP my.server.com:/var/www/shaarli/data/datastore.php datastore-$(date +%Y-%m-%d_%H%M).php`
204* **Export your links as HTML** (Menu `Tools` > `Export`). Restore by using the `Import` feature.
205 * This can be done using the [shaarchiver](https://github.com/nodiscc/shaarchiver) tool. Example command: `./export-bookmarks.py --url=https://my.server.com/shaarli --username=myusername --password=mysupersecretpassword --download-dir=./ --type=all`
206
207
208# Troubleshooting
209
210### I forgot my password !
211
212Delete the file data/config.php and display the page again. You will be asked for a new login/password.
213
214
215
216### I'm locked out - Login bruteforce protection
217Login form is protected against brute force attacks: 4 failed logins will ban the IP address from login for 30 minutes. Banned IPs can still browse links.
218
219To remove the current IP bans, delete the file `data/ipbans.php`
220
221### List of all login attempts
222
223The file `data/log.txt` shows all logins (successful or failed) and bans/lifted bans.
224Search for `failed` in this file to look for unauthorized login attempts.
225 7
8For general info, read the [README](https://github.com/shaarli/Shaarli/blob/master/README.md).[](.html)
226 9
227### Exporting from Diigo 10If you have any questions or ideas, please join the [chat](https://gitter.im/shaarli/Shaarli) (also reachable via [IRC](https://irc.gitter.im/)), post them in our [general discussion](https://github.com/shaarli/Shaarli/issues/44) or read the current [issues](https://github.com/shaarli/Shaarli/issues). If you've found a bug, please create a [new issue](https://github.com/shaarli/Shaarli/issues/new).[](.html)
228 11
229If you export your bookmark from Diigo, make sure you use the Delicious export, not the Netscape export. (Their Netscape export is broken, and they don't seem to be interested in fixing it.) 12If you would like a feature added to Shaarli, check the issues labeled [`feature`](https://github.com/shaarli/Shaarli/labels/feature), [`enhancement`](https://github.com/shaarli/Shaarli/labels/enhancement), and [`plugin`](https://github.com/shaarli/Shaarli/labels/plugin).[](.html)
230 13
231### Importing from SemanticScuttle 14_Note: This documentation is available online at https://github.com/shaarli/Shaarli/wiki, and locally in the `doc/` directory of your Shaarli installation._
232
233To correctly import the tags from a [SemanticScuttle](http://semanticscuttle.sourceforge.net/) HTML export, edit the HTML file before importing and replace all occurences of `tags=` (lowercase) to `TAGS=` (uppercase).
234
235### Importing from Mister Wong
236See [this issue](https://github.com/sebsauvage/Shaarli/issues/146) for import tweaks.
237
238
239### Hosting problems
240 * On **free.fr** : Please note that free uses php 5.1 and thus you will not have autocomplete in tag editing. Don't forget to create a `sessions` directory at the root of your webspace. Change the file extension to `.php5` or create a `.htaccess` file in the directory where Shaarli is located containing:
241
242```
243php 1
244SetEnv PHP_VER 5
245```
246
247 * If you have an error such as: `Parse error: syntax error, unexpected '=', expecting '(' in /links/index.php on line xxx`, it means that your host is using php4, not php5. Shaarli requires php 5.1. Try changing the file extension to `.php5`
248 * On **1and1** : If you add the link from the page (and not from the bookmarklet), Shaarli will no be able to get the title of the page. You will have to enter it manually. (Because they have disabled the ability to download a file through HTTP).
249 * If you have the error `Warning: file_get_contents() [function.file-get-contents]: URL file-access is disabled in the server configuration in /…/index.php on line xxx`, it means that your host has disabled the ability to fetch a file by HTTP in the php config (Typically in 1and1 hosting). Bad host. Change host. Or comment the following lines:
250
251```
252//list($status,$headers,$data) = getHTTP($url,4); // Short timeout to keep the application responsive.
253// FIXME: Decode charset according to charset specified in either 1) HTTP response headers or 2) <head> in html
254//if (strpos($status,'200 OK')) $title=html_extract_title($data);
255```
256
257 * On hosts which forbid outgoing HTTP requests (such as free.fr), some thumbnails will not work.
258 * On **lost-oasis**, RSS doesn't work correctly, because of this message at the begining of the RSS/ATOM feed : `<? // tout ce qui est charge ici (generalement des includes et require) est charge en permanence. ?>`. To fix this, remove this message from `php-include/prepend.php`
259
260### Dates are not properly formatted
261Shaarli tries to sniff the language of the browser (using HTTP_ACCEPT_LANGUAGE headers) and choose a date format accordingly. But Shaarli can only use the date formats (and more generaly speaking, the locales) provided by the webserver. So even if you have a browser in French, you may end up with dates in US format (it's the case on sebsauvage.net :-( )
262
263### Problems on CentOS servers
264On **CentOS**/RedHat derivatives, you may need to install the `php-mbstring` package.
265
266
267### My session expires ! I can't stay logged in
268This can be caused by several things:
269
270* Your php installation may not have a proper directory setup for session files. (eg. on Free.fr you need to create a `session` directory on the root of your website.) You may need to create the session directory of set it up.
271* Most hosts regularly clean the temporary and session directories. Your host may be cleaning those directories too aggressively (eg.OVH hosts), forcing an expire of the session. You may want to set the session directory in your web root. (eg. Create the `sessions` subdirectory and add `ini_set('session.save_path', $_SERVER['DOCUMENT_ROOT'].'/../sessions');`. Make sure this directory is not browsable !)
272* If your IP address changes during surfing, Shaarli will force expire your session for security reasons (to prevent session cookie hijacking). This can happen when surfing from WiFi or 3G (you may have switched WiFi/3G access point), or in some corporate/university proxies which use load balancing (and may have proxies with several external IP addresses).
273* Some browser addons may interfer with HTTP headers (ipfuck/ipflood/GreaseMonkey…). Try disabling those.
274* You may be using OperaTurbo or OperaMini, which use their own proxies which may change from time to time.
275* If you have another application on the same webserver where Shaarli is installed, these application may forcefully expire php sessions.
276
277### `Sessions do not seem to work correctly on your server`
278Follow the instructions in the error message. Make sure you are accessing shaarli via a direct IP address or a proper hostname. If you have **no dots** in the hostname (e.g. `localhost` or `http://my-webserver/shaarli/`), some browsers will not store cookies at all (this respects the [HTTP cookie specification](http://curl.haxx.se/rfc/cookie_spec.html)).
279
280
281### pubsubhubbub support
282
283Download [publisher.php](https://pubsubhubbub.googlecode.com/git/publisher_clients/php/library/publisher.php) at the root of your Shaarli installation and set `$GLOBALS['config']['PUBSUBHUB_URL']` in your `config.php`
284
285# Notes
286### Various hacks
287
288 * [Example patch: add a new "via" field for links](Example-patch---add-new-via-field-for-links)
289 * [Copy a Shaarli installation over SSH SCP, serve it locally with php cli](Copy-a-Shaarli-installation-over-SSH-SCP,-serve-it-locally-with-php-cli)
290 * To display the array representing the data saved in datastore.php, use the following snippet
291```
292$data = "tZNdb9MwFIb... <Commented content inside datastore.php>";
293$out = unserialize(gzinflate(base64_decode($data)));
294echo "<pre>"; // Pretty printing is love, pretty printing is life
295print_r($out);
296echo "</pre>";
297exit;
298```
299This will output the internal representation of the datastore, "unobfuscated" (if this can really be considered obfuscation)
300
301### Changing timestamp for a link
302 * Look for `<input type="hidden" name="lf_linkdate" value="{$link.linkdate}">` in `tpl/editlink.tpl` (line 14)
303 * Remove `type="hidden"` from this line
304 * A new date/time field becomes available in the edit/new link dialog. You can set the timestamp manually by entering it in the format `YYYMMDD_HHMMS`.
305
306
307# Related software
308Unofficial but relatedd work on Shaarli. If you maintain one of these, please get in touch with us to help us find a way to adapt your work to our fork. **TODO** contact repos owners to see if they'd like to standardize their work for the community fork.
309### Server apps
310 * [shaarchiver](https://github.com/nodiscc/shaarchiver) - Archive your Shaarli bookmarks and their content
311 * [shaarli-river](https://github.com/mknexen/shaarli-river) - An aggregator for shaarlis with many features
312 * [Shaarlo](https://github.com/DMeloni/shaarlo) - An aggregator for shaarlis with many features (a very popular running instance among french shaarliers: [shaarli.fr](http://shaarli.fr/))
313 * [Shaarlimages](https://github.com/BoboTiG/shaarlimages) - An image-oriented aggregator for Shaarlis
314 * [mknexen/shaarli-api](https://github.com/mknexen/shaarli-api) - A REST API for Shaarli
315
316### Android apps
317 * [Shaarli for Android](http://sebsauvage.net/links/?ZAyDzg) - Android application that adds Shaarli as a sharing provider
318 * [Shaarlier for Android](https://github.com/dimtion/Shaarlier) - Android application to simply add links directly into your Shaarli
319
320### Themes & templates
321 * [AkibaTech/Shaarli Superhero Theme](https://github.com/AkibaTech/Shaarli---SuperHero-Theme) - A template/theme for Shaarli
322 * [alexisju/albinomouse-template](https://github.com/alexisju/albinomouse-template) - A full template for Shaarli
323 * [dhoko/ShaarliTemplate](https://github.com/dhoko/ShaarliTemplate) - A template/theme for Shaarli
324 * [kalvn/shaarli-blocks](https://github.com/kalvn/shaarli-blocks) - A template/theme for Shaarli
325 * [kalvn/Shaarli-Material](https://github.com/kalvn/Shaarli-Material) - A theme (template) based on Google's Material Design for Shaarli, the superfast delicious clone.
326 * [misterair/Limonade](https://github.com/misterair/limonade) - A fork of (legacy) Shaarli with a new template
327 * [Vinm/Blue-theme-for Shaarli](https://github.com/Vinm/Blue-theme-for-Shaarli) - A template/theme for Shaarli ([unmaintained](https://github.com/Vinm/Blue-theme-for-Shaarli/issues/2), compatibility unknown)
328 * [vivienhaese/shaarlitheme](https://github.com/vivienhaese/shaarlitheme) - A Shaarli fork meant to be run in an openshift instance
329
330### Integrate Shaarli with other platforms
331 * [tt-rss-shaarli](https://github.com/jcsaaddupuy/tt-rss-shaarli) - [TinyTiny RSS](http://tt-rss.org/) plugin that adds support for sharing articles with Shaarli
332 * [octopress-shaarli](https://github.com/ahmet2mir/octopress-shaarli) - octoprress plugin to retrieve SHaarli links on the sidebara
333
334### Alternative to Shaarli
335 * [Bookie](https://github.com/bookieio/bookie) - Another self-hostable, Free bookmark sharing software, written in Python
336 * [Unmark](https://github.com/plainmade/unmark) - An open source to do app for bookmarks ([Homepage](https://unmark.it/))
337
338
339
340# Other links
341 * [Liens en vrac de sebsauvage](http://sebsauvage.net/links/) - the original Shaarli
342 * [A large list of Shaarlis](http://porneia.free.fr/pub/links/ou-est-shaarli.html)
343 * [A list of working Shaarli aggregators](https://raw.githubusercontent.com/Oros42/find_shaarlis/master/annuaires.json)
344 * [A list of some known Shaarlis](https://github.com/Oros42/shaarlis_list)
345 * [Adieu Delicious, Diigo et StumbleUpon. Salut Shaarli ! - sebsauvage.net](http://sebsauvage.net/rhaa/index.php?2011/09/16/09/29/58-adieu-delicious-diigo-et-stumbleupon-salut-shaarli-) (fr) _16/09/2011 - the original post about Shaarli_
346 * [Original ideas/fixme/TODO page](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:ideas)
347 * [Original discussion page](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:discussion) (fr)
348 * [Original revisions history](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history)
349 * [Shaarli.fr/my](https://www.shaarli.fr/my.php) - Unofficial, unsupported (old fork) hosted Shaarlis provider, courtesy of [DMeloni](https://github.com/DMeloni)
350 * [Shaarli Communauty](http://shaarferme.etudiant-libre.fr.nf/index.php) - Another unofficial Shaarli hoster (unsupported, old fork), hoster unknown
351
352
353
354
355# FAQ
356
357### Why did you create Shaarli ?
358
359I was a StumbleUpon user. Then I got fed up with they big toolbar. I switched to delicious, which was lighter, faster and more beautiful. Until Yahoo bought it. Then the export API broke all the time, delicious became slow and was ditched by Yahoo. I switched to Diigo, which is not bad, but does too much. And Diigo is sslllooooowww and their Firefox extension a bit buggy. And… oh… **their Firefox addon sends to Diigo every single URL you visit** (Don't believe me ? Use [Tamper Data](https://addons.mozilla.org/en-US/firefox/addon/tamper-data/) and open any page).
360
361Enough is enough. Saving simple links should not be a complicated heavy thing. I ditched them all and wrote my own: Shaarli. It's simple, but it does the job and does it well. And my data is not hosted on a foreign server, but on my server.
362
363### Why use Shaarli and not Delicious/Diigo ?
364
365With Shaarli:
366
367* The data is yours: It's hosted on your server.
368* Never fear of having your data locked-in.
369* Never fear to have your data sold to third party.
370* Your private links are not hosted on a third party server.
371* You are not tracked by browser addons (like Diigo does)
372* You can change the look and feel of the pages if you want.
373* You can change the behaviour of the program.
374* It's magnitude faster than most bookmarking services.
375
376### What does Shaarli mean ?
377
378Shaarli is for shaaring your links.
379
380
381
382# Technical details
383 * Application is protected against XSRF (Cross-site requests forgery): Forms which act on data (save,delete…) contain a token generated by the server. Any posted form which does not contain a valid token is rejected. Any token can only be used once. Token are attached to the session and cannot be reused in another session.
384 * Sessions automatically expires after 60 minutes. Sessions are protected against highjacking: The sessionID cannot be used from a different IP address.
385 * An .htaccess file protects the data file.
386 * Link database is an associative array which is serialized, compressed (with deflate), base64-encoded and saved as a comment in a .php file. Thus even if the server does not support htaccess files, the data file will still not be readable by URL. The database looks like this:
387```
388<?php /* zP1ZjxxJtiYIvvevEPJ2lDOaLrZv7o...
389...ka7gaco/Z+TFXM2i7BlfMf8qxpaSSYfKlvqv/x8= */ ?>
390```
391
392* The password is salted, hashed and stored in the data subdirectory, in a php file, and protected by htaccess. Even if the webserver does not support htaccess, the hash is not readable by URL. Even if the .php file is stolen, the password cannot deduced from the hash. The salt prevents rainbow-tables attacks.
393* Shaarli relies on `HTTP_REFERER` for some functions (like redirects and clicking on tags). If you have disabled or masqueraded `HTTP_REFERER` in your browser, some features of Shaarli may not work
394* `magic_quotes` is a horrible option of php which is often activated on servers. No serious developer should rely on this horror to secure their code against SQL injections. You should disable it (and Shaarli expects this option to be disabled). Nevertheless, I have added code to cope with magic_quotes on, so you should not be bothered even on crappy hosts.
395* Small hashes are used to make a link to an entry in Shaarli. They are unique. In fact, the date of the items (eg.20110923_150523) is hashed with CRC32, then converted to base64 and some characters are replaced. They are always 6 characters longs and use only A-Z a-z 0-9 - _ and @.
396
397### Directory structure
398
399Here is the directory structure of Shaarli and the purpose of the different files:
400
401```
402 index.php : Main program.
403 application/ : Shaarli classes
404 ├── LinkDB.php
405 └── Utils.php
406 tests/ : Shaarli unitary & functional tests
407 ├── LinkDBTest.php
408 ├── utils # utilities to ease testing
409 │ └── ReferenceLinkDB.php
410 └── UtilsTest.php
411 COPYING : Shaarli license.
412 inc/ : Includes (libraries, CSS…)
413 ├── awesomplete.*: tags autocompletion library
414 ├── blazy.*: picture wall lazy image loading library
415 ├── shaarli.css, reset.css : Shaarli stylesheet.
416 ├── qr.* : qr code generation library
417 └──rain.tpl.class.php : RainTPL templating library.
418 tpl/ : RainTPL templates for Shaarli. They are used to build the pages.
419 images/ : Images and icons used in Shaarli.
420 data/ : Directory where data is stored (bookmark database, configuration, logs, banlist…)
421 ├── config.php : Shaarli configuration (login, password, timezone, title…)
422 ├── datastore.php : Your link database (compressed).
423 ├── ipban.php : IP address ban system data.
424 ├── lastupdatecheck.txt : Update check timestamp file (used to check every 24 hours if a new version of Shaarli is available).
425 └──log.txt : login/IPban log.
426 cache/ : Directory containing the thumbnails cache. This directory is automatically created. You can erase it anytime you want.
427 tmp/ : Temporary directory for compiled RainTPL templates. This directory is automatically created. You can erase it anytime you want.
428```
429
430### Development
431
432 * [Contributing to Shaarli](https://github.com/shaarli/Shaarli/tree/master/CONTRIBUTING.md)
433 * [Running unit tests](Running-unit-tests)
434 * Patches should try to stick to the [PHP Standard Recommendations](http://www.php-fig.org/psr/) (PSR), especially:
435 * [PSR-1](http://www.php-fig.org/psr/psr-1/) - Basic Coding Standard
436 * [PSR-2](http://www.php-fig.org/psr/psr-2/) - Coding Style Guide
437
438### Why not use a real database ? Files are slow !
439
440Does browsing [this page](http://sebsauvage.net/links/) feel slow ? Try browsing older pages, too.
441
442It's not slow at all, is it ? And don't forget the database contains more than 16000 links, and it's on a shared host, with 32000 visitors/day for my website alone. And it's still damn fast. Why ?
443
444The data file is only 3.7 Mb. It's read 99% of the time, and is probably already in the operation system disk cache. So generating a page involves no I/O at all most of the time.
445
446# Wiki - TODO
447 * translate (new page can be called Home.fr, Home.es ... and linked from Home)
448 * add more screenshots
449 * add developer documentation (storage architecture, classes and functions, security handling, ...) \ No newline at end of file
diff --git a/doc/Plugin-System.html b/doc/Plugin-System.html
new file mode 100644
index 00000000..6d08d859
--- /dev/null
+++ b/doc/Plugin-System.html
@@ -0,0 +1,499 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Plugin System</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <style type="text/css">
13table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
14 margin: 0; padding: 0; vertical-align: baseline; border: none; }
15table.sourceCode { width: 100%; line-height: 100%; }
16td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
17td.sourceCode { padding-left: 5px; }
18code > span.kw { color: #007020; font-weight: bold; }
19code > span.dt { color: #902000; }
20code > span.dv { color: #40a070; }
21code > span.bn { color: #40a070; }
22code > span.fl { color: #40a070; }
23code > span.ch { color: #4070a0; }
24code > span.st { color: #4070a0; }
25code > span.co { color: #60a0b0; font-style: italic; }
26code > span.ot { color: #007020; }
27code > span.al { color: #ff0000; font-weight: bold; }
28code > span.fu { color: #06287e; }
29code > span.er { color: #ff0000; font-weight: bold; }
30 </style>
31 <link rel="stylesheet" href="github-markdown.css">
32</head>
33<body>
34<div id="local-sidebar">
35<ul>
36<li><a href="Home.html">Home</a></li>
37<li>Installation
38<ul>
39<li><a href="Server-requirements.html">Server requirements</a></li>
40<li><a href="Server-configuration.html">Server configuration</a></li>
41<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
42</ul></li>
43<li><a href="Usage.html">Usage</a>
44<ul>
45<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
46<li><a href="Firefox-share.html">Firefox share</a></li>
47<li><a href="RSS-feeds.html">RSS feeds</a></li>
48</ul></li>
49<li>How To
50<ul>
51<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
52<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
53<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
54</ul></li>
55<li><a href="Troubleshooting.html">Troubleshooting</a></li>
56<li><a href="Development.html">Development</a>
57<ul>
58<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
59<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
60<li><a href="Directory-structure.html">Directory structure</a></li>
61<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
62<li><a href="Plugin-System.html">Plugin System</a></li>
63<li><a href="Security.html">Security</a></li>
64<li><a href="Static-analysis.html">Static analysis</a></li>
65<li><a href="Theming.html">Theming</a></li>
66<li><a href="Unit-tests.html">Unit tests</a></li>
67</ul></li>
68<li>About
69<ul>
70<li><a href="FAQ.html">FAQ</a></li>
71<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
72<li><a href="TODO.html">TODO</a></li>
73</ul></li>
74</ul>
75</div>
76<h1 id="plugin-system">Plugin System</h1>
77<blockquote>
78<p>Note: Plugin current status - in developpement (not merged into master).</p>
79</blockquote>
80<p><a href="#plugin-user-guide"><strong>I am a user.</strong> Plugin User Guide.</a><a href=".html"></a></p>
81<p><a href="#developper-api"><strong>I am a developper.</strong> Developper API.</a><a href=".html"></a></p>
82<p><a href="#guide-for-template-designer"><strong>I am a template designer.</strong> Guide for template designer.</a><a href=".html"></a></p>
83<h2 id="plugin-user-guide">Plugin User Guide</h2>
84<h3 id="manage-plugins">Manage plugins</h3>
85<p>In <code>config.php</code>, change $GLOBALS<a href="&#39;ENABLED_PLUGINS&#39;]-array:.html">'config'['ENABLED_PLUGINS'] array:</a></p>
86<pre class="sourceCode php"><code class="sourceCode php"><span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;ENABLED_PLUGINS&#39;</span><span class="ot">]](</span><span class="st">&#39;ENABLED_PLUGINS&#39;</span><span class="ot">]</span>.html<span class="ot">)</span></code></pre>
87<p>Full list:</p>
88<pre class="sourceCode php"><code class="sourceCode php"><span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;ENABLED_PLUGINS&#39;</span><span class="ot">]</span> = <span class="fu">array</span><span class="ot">(](</span><span class="st">&#39;ENABLED_PLUGINS&#39;</span><span class="ot">]</span>-=-<span class="fu">array</span><span class="ot">(</span>.html<span class="ot">)</span>
89 <span class="st">&#39;qrcode&#39;</span><span class="ot">,</span> <span class="st">&#39;archiveorg&#39;</span><span class="ot">,</span> <span class="st">&#39;readityourself&#39;</span><span class="ot">,</span> <span class="st">&#39;playvideos&#39;</span><span class="ot">,</span>
90 <span class="st">&#39;wallabag&#39;</span><span class="ot">,</span> <span class="st">&#39;markdown&#39;</span><span class="ot">,</span> <span class="st">&#39;addlink_toolbar&#39;</span><span class="ot">,</span>
91<span class="ot">);</span></code></pre>
92<h3 id="list-of-plugins">List of plugins</h3>
93<p>Plugin maintained by the community:</p>
94<ul>
95<li>Archive.org - add a clickable icon to every link to archive.org.</li>
96<li>Addlink in toolbar - add a field to paste new links URL in toolbar.</li>
97<li>Markdown - write and display Shaare in Markdown.</li>
98<li>Play videos - popup to play all videos displayed in linklist.</li>
99<li>QRCode - add a clickable icon generating a QRCode for every link.</li>
100<li>ReadItYourself - add a clickable icon for ReadItYourself.</li>
101<li>Wallabag - add a clickable icon for Wallabag.</li>
102</ul>
103<h2 id="developper-api">Developper API</h2>
104<h3 id="what-can-i-do-with-plugins">What can I do with plugins?</h3>
105<p>The plugin system let you:</p>
106<ul>
107<li>insert content into specific places across templates.</li>
108<li>alter data before templates rendering.</li>
109<li>alter data before saving new links.</li>
110</ul>
111<h3 id="how-can-i-create-a-plugin-for-shaarli">How can I create a plugin for Shaarli?</h3>
112<p>First, chose a plugin name, such as <code>demo_plugin</code>.</p>
113<p>Under <code>plugin</code> folder, create a folder named with your plugin name. Then create a <plugin_name>.php file in that folder.</p>
114<p>You should have the following tree view:</p>
115<pre><code>| index.php
116| plugins/
117|---| demo_plugin/
118| |---| demo_plugin.php</code></pre>
119<h3 id="understanding-hooks">Understanding hooks</h3>
120<p>A plugin is a set of functions. Each function will be triggered by the plugin system at certain point in Shaarli execution.</p>
121<p>These functions need to be named with this pattern:</p>
122<pre><code>hook_&lt;plugin_name&gt;_&lt;hook_name&gt;</code></pre>
123<p>For exemple, if my plugin want to add data to the header, this function is needed:</p>
124<pre><code>hook_demo_plugin_render_header()</code></pre>
125<p>If this function is declared, and the plugin enabled, it will be called every time Shaarli is rendering the header.</p>
126<h3 id="plugins-data">Plugin's data</h3>
127<h4 id="parameters">Parameters</h4>
128<p>Every hook function has a <code>$data</code> parameter. Its content differs for each hooks.</p>
129<p><strong>This parameter needs to be returned every time</strong>, otherwise data is lost.</p>
130<pre><code>return $data;</code></pre>
131<h4 id="filling-templates-placeholder">Filling templates placeholder</h4>
132<p>Template placeholders are displayed in template in specific places.</p>
133<p>RainTPL displays every element contained in the placeholder's array. These element can be added by plugins.</p>
134<p>For example, let's add a value in the placeholder <code>top_placeholder</code> which is displayed at the top of my page:</p>
135<pre class="sourceCode php"><code class="sourceCode php"><span class="kw">$data</span><span class="ot">[</span><span class="st">&#39;top_placeholder&#39;</span><span class="ot">[]</span> = <span class="st">&#39;My content&#39;</span><span class="ot">;](]</span>-=-<span class="st">&#39;My-content&#39;</span><span class="ot">;</span>.html<span class="ot">)</span>
136<span class="co"># OR</span>
137<span class="fu">array_push</span><span class="ot">(</span><span class="kw">$data</span><span class="ot">[</span><span class="st">&#39;top_placeholder&#39;</span><span class="ot">],</span> <span class="st">&#39;My&#39;</span><span class="ot">,</span> <span class="st">&#39;content&#39;</span><span class="ot">);[](</span>.html<span class="ot">)</span>
138
139<span class="kw">return</span> <span class="kw">$data</span><span class="ot">;</span></code></pre>
140<h4 id="data-manipulation">Data manipulation</h4>
141<p>When a page is displayed, every variable send to the template engine is passed to plugins before that in <code>$data</code>.</p>
142<p>The data contained by this array can be altered before template rendering.</p>
143<p>For exemple, in linklist, it is possible to alter every title:</p>
144<pre class="sourceCode php"><code class="sourceCode php"><span class="co">// mind the reference if you want $data to be altered</span>
145<span class="kw">foreach</span> <span class="ot">(</span><span class="kw">$data</span><span class="ot">[</span><span class="st">&#39;links&#39;</span><span class="ot">]</span> <span class="kw">as</span> &amp;<span class="kw">$value</span><span class="ot">)</span> {<span class="ot">[](</span>.html<span class="ot">)</span>
146 <span class="co">// String reverse every title.</span>
147 <span class="kw">$value</span><span class="ot">[</span><span class="st">&#39;title&#39;</span><span class="ot">]</span> = <span class="fu">strrev</span><span class="ot">(</span><span class="kw">$value</span><span class="ot">[</span><span class="st">&#39;title&#39;</span><span class="ot">]);[](</span>.html<span class="ot">)</span>
148}
149
150<span class="kw">return</span> <span class="kw">$data</span><span class="ot">;</span></code></pre>
151<h3 id="its-not-working">It's not working!</h3>
152<p>Use <code>demo_plugin</code> as a functional example. It covers most of the plugin system features.</p>
153<p>If it's still not working, please <a href="https://github.com/shaarli/Shaarli/issues/new">open an issue</a>.<a href=".html"></a></p>
154<h3 id="hooks">Hooks</h3>
155<table>
156<thead>
157<tr class="header">
158<th style="text-align: left;">Hooks</th>
159<th style="text-align: center;">Description</th>
160</tr>
161</thead>
162<tbody>
163<tr class="odd">
164<td style="text-align: left;"><a href="#render_header">render_header</a></td>
165<td style="text-align: center;">Allow plugin to add content in page headers.</td>
166</tr>
167<tr class="even">
168<td style="text-align: left;"><a href="#render_includes">render_includes</a></td>
169<td style="text-align: center;">Allow plugin to include their own CSS files.</td>
170</tr>
171<tr class="odd">
172<td style="text-align: left;"><a href="#render_footer">render_footer</a></td>
173<td style="text-align: center;">Allow plugin to add content in page footer and include their own JS files.</td>
174</tr>
175<tr class="even">
176<td style="text-align: left;"><a href="#render_linklist">render_linklist</a></td>
177<td style="text-align: center;">It allows to add content at the begining and end of the page, after every link displayed and to alter link data.</td>
178</tr>
179<tr class="odd">
180<td style="text-align: left;"><a href="#render_editlink">render_editlink</a></td>
181<td style="text-align: center;">Allow to add fields in the form, or display elements.</td>
182</tr>
183<tr class="even">
184<td style="text-align: left;"><a href="#render_tools">render_tools</a></td>
185<td style="text-align: center;">Allow to add content at the end of the page.</td>
186</tr>
187<tr class="odd">
188<td style="text-align: left;"><a href="#render_picwall">render_picwall</a></td>
189<td style="text-align: center;">Allow to add content at the top and bottom of the page.</td>
190</tr>
191<tr class="even">
192<td style="text-align: left;"><a href="#render_tagcloud">render_tagcloud</a></td>
193<td style="text-align: center;">Allow to add content at the top and bottom of the page.</td>
194</tr>
195<tr class="odd">
196<td style="text-align: left;"><a href="#render_daily">render_daily</a></td>
197<td style="text-align: center;">Allow to add content at the top and bottom of the page, the bottom of each link and to alter data.</td>
198</tr>
199<tr class="even">
200<td style="text-align: left;"><a href="#savelink">savelink</a></td>
201<td style="text-align: center;">Allow to alter the link being saved in the datastore.</td>
202</tr>
203</tbody>
204</table>
205<h4 id="render_header">render_header</h4>
206<p>Triggered on every page.</p>
207<p>Allow plugin to add content in page headers.</p>
208<h5 id="data">Data</h5>
209<p><code>$data</code> is an array containing:</p>
210<ul>
211<li><code>_PAGE_</code>: current target page (eg: <code>linklist</code>, <code>picwall</code>, etc.).</li>
212<li><code>_LOGGEDIN_</code>: true if user is logged in, false otherwise.</li>
213</ul>
214<h5 id="template-placeholders">Template placeholders</h5>
215<p>Items can be displayed in templates by adding an entry in <code>$data['&lt;placeholder&gt;']</code> array.<a href=".html"></a></p>
216<p>List of placeholders:</p>
217<ul>
218<li><code>buttons_toolbar</code>: after the list of buttons in the header.</li>
219</ul>
220<p><img src="http://i.imgur.com/ssJUOrt.png" alt="buttons_toolbar_example" /><a href=".html"></a></p>
221<ul>
222<li><code>fields_toolbar</code>: after search fields in the header.</li>
223</ul>
224<blockquote>
225<p>Note: This will only be called in linklist.</p>
226</blockquote>
227<p><img src="http://i.imgur.com/3GMifI2.png" alt="fields_toolbar_example" /><a href=".html"></a></p>
228<h4 id="render_includes">render_includes</h4>
229<p>Triggered on every page.</p>
230<p>Allow plugin to include their own CSS files.</p>
231<h5 id="data-1">Data</h5>
232<p><code>$data</code> is an array containing:</p>
233<ul>
234<li><code>_PAGE_</code>: current target page (eg: <code>linklist</code>, <code>picwall</code>, etc.).</li>
235<li><code>_LOGGEDIN_</code>: true if user is logged in, false otherwise.</li>
236</ul>
237<h5 id="template-placeholders-1">Template placeholders</h5>
238<p>Items can be displayed in templates by adding an entry in <code>$data['&lt;placeholder&gt;']</code> array.<a href=".html"></a></p>
239<p>List of placeholders:</p>
240<ul>
241<li><code>css_files</code>: called after loading default CSS.</li>
242</ul>
243<blockquote>
244<p>Note: only add the path of the CSS file. E.g: <code>plugins/demo_plugin/custom_demo.css</code>.</p>
245</blockquote>
246<h4 id="render_footer">render_footer</h4>
247<p>Triggered on every page.</p>
248<p>Allow plugin to add content in page footer and include their own JS files.</p>
249<h5 id="data-2">Data</h5>
250<p><code>$data</code> is an array containing:</p>
251<ul>
252<li><code>_PAGE_</code>: current target page (eg: <code>linklist</code>, <code>picwall</code>, etc.).</li>
253<li><code>_LOGGEDIN_</code>: true if user is logged in, false otherwise.</li>
254</ul>
255<h5 id="template-placeholders-2">Template placeholders</h5>
256<p>Items can be displayed in templates by adding an entry in <code>$data['&lt;placeholder&gt;']</code> array.<a href=".html"></a></p>
257<p>List of placeholders:</p>
258<ul>
259<li><code>text</code>: called after the end of the footer text.</li>
260</ul>
261<p><img src="http://i.imgur.com/L5S2YEH.png" alt="text_example" /><a href=".html"></a></p>
262<ul>
263<li><code>js_files</code>: called at the end of the page, to include custom JS scripts.</li>
264</ul>
265<blockquote>
266<p>Note: only add the path of the JS file. E.g: <code>plugins/demo_plugin/custom_demo.js</code>.</p>
267</blockquote>
268<h4 id="render_linklist">render_linklist</h4>
269<p>Triggered when <code>linklist</code> is displayed (list of links, permalink, search, tag filtered, etc.).</p>
270<p>It allows to add content at the begining and end of the page, after every link displayed and to alter link data.</p>
271<h5 id="data-3">Data</h5>
272<p><code>$data</code> is an array containing:</p>
273<ul>
274<li><code>_LOGGEDIN_</code>: true if user is logged in, false otherwise.</li>
275<li>All templates data, including links.</li>
276</ul>
277<h5 id="template-placeholders-3">Template placeholders</h5>
278<p>Items can be displayed in templates by adding an entry in <code>$data['&lt;placeholder&gt;']</code> array.<a href=".html"></a></p>
279<p>List of placeholders:</p>
280<ul>
281<li><code>action_plugin</code>: next to the button &quot;private only&quot; at the top and bottom of the page.</li>
282</ul>
283<p><img src="http://i.imgur.com/Q12PWg0.png" alt="action_plugin_example" /><a href=".html"></a></p>
284<ul>
285<li><code>link_plugin</code>: for every link, between permalink and link URL.</li>
286</ul>
287<p><img src="http://i.imgur.com/3oDPhWx.png" alt="link_plugin_example" /><a href=".html"></a></p>
288<ul>
289<li><code>plugin_start_zone</code>: before displaying the template content.</li>
290</ul>
291<p><img src="http://i.imgur.com/OVBkGy3.png" alt="plugin_start_zone_example" /><a href=".html"></a></p>
292<ul>
293<li><code>plugin_end_zone</code>: after displaying the template content.</li>
294</ul>
295<p><img src="http://i.imgur.com/6IoRuop.png" alt="plugin_end_zone_example" /><a href=".html"></a></p>
296<h4 id="render_editlink">render_editlink</h4>
297<p>Triggered when the link edition form is displayed.</p>
298<p>Allow to add fields in the form, or display elements.</p>
299<h5 id="data-4">Data</h5>
300<p><code>$data</code> is an array containing:</p>
301<ul>
302<li>All templates data.</li>
303</ul>
304<h5 id="template-placeholders-4">Template placeholders</h5>
305<p>Items can be displayed in templates by adding an entry in <code>$data['&lt;placeholder&gt;']</code> array.<a href=".html"></a></p>
306<p>List of placeholders:</p>
307<ul>
308<li><code>edit_link_plugin</code>: after tags field.</li>
309</ul>
310<p><img src="http://i.imgur.com/5u17Ens.png" alt="edit_link_plugin_example" /><a href=".html"></a></p>
311<h4 id="render_tools">render_tools</h4>
312<p>Triggered when the &quot;tools&quot; page is displayed.</p>
313<p>Allow to add content at the end of the page.</p>
314<h5 id="data-5">Data</h5>
315<p><code>$data</code> is an array containing:</p>
316<ul>
317<li>All templates data.</li>
318</ul>
319<h5 id="template-placeholders-5">Template placeholders</h5>
320<p>Items can be displayed in templates by adding an entry in <code>$data['&lt;placeholder&gt;']</code> array.<a href=".html"></a></p>
321<p>List of placeholders:</p>
322<ul>
323<li><code>tools_plugin</code>: at the end of the page.</li>
324</ul>
325<p><img src="http://i.imgur.com/Bqhu9oQ.png" alt="tools_plugin_example" /><a href=".html"></a></p>
326<h4 id="render_picwall">render_picwall</h4>
327<p>Triggered when picwall is displayed.</p>
328<p>Allow to add content at the top and bottom of the page.</p>
329<h5 id="data-6">Data</h5>
330<p><code>$data</code> is an array containing:</p>
331<ul>
332<li><code>_LOGGEDIN_</code>: true if user is logged in, false otherwise.</li>
333<li>All templates data.</li>
334</ul>
335<h5 id="template-placeholders-6">Template placeholders</h5>
336<p>Items can be displayed in templates by adding an entry in <code>$data['&lt;placeholder&gt;']</code> array.<a href=".html"></a></p>
337<p>List of placeholders:</p>
338<ul>
339<li><p><code>plugin_start_zone</code>: before displaying the template content.</p></li>
340<li><p><code>plugin_end_zone</code>: after displaying the template content.</p></li>
341</ul>
342<p><img src="http://i.imgur.com/tVTQFER.png" alt="plugin_start_end_zone_example" /><a href=".html"></a></p>
343<h4 id="render_tagcloud">render_tagcloud</h4>
344<p>Triggered when tagcloud is displayed.</p>
345<p>Allow to add content at the top and bottom of the page.</p>
346<h5 id="data-7">Data</h5>
347<p><code>$data</code> is an array containing:</p>
348<ul>
349<li><code>_LOGGEDIN_</code>: true if user is logged in, false otherwise.</li>
350<li>All templates data.</li>
351</ul>
352<h5 id="template-placeholders-7">Template placeholders</h5>
353<p>Items can be displayed in templates by adding an entry in <code>$data['&lt;placeholder&gt;']</code> array.<a href=".html"></a></p>
354<p>List of placeholders:</p>
355<ul>
356<li><p><code>plugin_start_zone</code>: before displaying the template content.</p></li>
357<li><p><code>plugin_end_zone</code>: after displaying the template content.</p></li>
358</ul>
359<p><img src="http://i.imgur.com/vHmyT3a.png" alt="plugin_start_end_zone_example" /><a href=".html"></a></p>
360<h4 id="render_daily">render_daily</h4>
361<p>Triggered when tagcloud is displayed.</p>
362<p>Allow to add content at the top and bottom of the page, the bottom of each link and to alter data.</p>
363<h5 id="data-8">Data</h5>
364<p><code>$data</code> is an array containing:</p>
365<ul>
366<li><code>_LOGGEDIN_</code>: true if user is logged in, false otherwise.</li>
367<li>All templates data, including links.</li>
368</ul>
369<h5 id="template-placeholders-8">Template placeholders</h5>
370<p>Items can be displayed in templates by adding an entry in <code>$data['&lt;placeholder&gt;']</code> array.<a href=".html"></a></p>
371<p>List of placeholders:</p>
372<ul>
373<li><code>link_plugin</code>: used at bottom of each link.</li>
374</ul>
375<p><img src="http://i.imgur.com/hzhMfSZ.png" alt="link_plugin_example" /><a href=".html"></a></p>
376<ul>
377<li><p><code>plugin_start_zone</code>: before displaying the template content.</p></li>
378<li><p><code>plugin_end_zone</code>: after displaying the template content.</p></li>
379</ul>
380<h4 id="savelink">savelink</h4>
381<p>Triggered when a link is save (new link or edit).</p>
382<p>Allow to alter the link being saved in the datastore.</p>
383<h5 id="data-9">Data</h5>
384<p><code>$data</code> is an array containing the link being saved:</p>
385<ul>
386<li>title</li>
387<li>url</li>
388<li>description</li>
389<li>linkdate</li>
390<li>private</li>
391<li>tags</li>
392</ul>
393<h2 id="guide-for-template-designer">Guide for template designer</h2>
394<h3 id="placeholder-system">Placeholder system</h3>
395<p>In order to make plugins work with every custom themes, you need to add variable placeholder in your templates.</p>
396<p>It's a RainTPL loop like this:</p>
397<pre><code>{loop=&quot;$plugin_variable&quot;}
398 {$value}
399{/loop}</code></pre>
400<p>You should enable <code>demo_plugin</code> for testing purpose, since it uses every placeholder available.</p>
401<h3 id="list-of-placeholders">List of placeholders</h3>
402<p><strong>page.header.html</strong></p>
403<p>At the end of the menu:</p>
404<pre><code>{loop=&quot;$plugins_header.buttons_toolbar&quot;}
405 {$value}
406{/loop}</code></pre>
407<p><strong>includes.html</strong></p>
408<p>At the end of the file:</p>
409<pre class="sourceCode html"><code class="sourceCode html">{loop=&quot;$plugins_includes.css_files&quot;}
410<span class="kw">&lt;link</span><span class="ot"> type=</span><span class="st">&quot;text/css&quot;</span><span class="ot"> rel=</span><span class="st">&quot;stylesheet&quot;</span><span class="ot"> href=</span><span class="st">&quot;{$value}#&quot;</span><span class="kw">/&gt;</span>
411{/loop}</code></pre>
412<p><strong>page.footer.html</strong></p>
413<p>At the end of your footer notes:</p>
414<pre class="sourceCode html"><code class="sourceCode html">{loop=&quot;$plugins_footer.text&quot;}
415 {$value}
416{/loop}</code></pre>
417<p>At the end of file:</p>
418<pre class="sourceCode html"><code class="sourceCode html">{loop=&quot;$plugins_footer.js_files&quot;}
419 <span class="kw">&lt;script</span><span class="ot"> src=</span><span class="st">&quot;{$value}#&quot;</span><span class="kw">&gt;&lt;/script&gt;</span>
420{/loop}</code></pre>
421<p><strong>linklist.html</strong></p>
422<p>After search fields:</p>
423<pre class="sourceCode html"><code class="sourceCode html">{loop=&quot;$plugins_header.fields_toolbar&quot;}
424 {$value}
425{/loop}</code></pre>
426<p>Before displaying the link list (after paging):</p>
427<pre class="sourceCode html"><code class="sourceCode html">{loop=&quot;$plugin_start_zone&quot;}
428 {$value}
429{/loop}</code></pre>
430<p>For every links (icons):</p>
431<pre class="sourceCode html"><code class="sourceCode html">{loop=&quot;$value.link_plugin&quot;}
432 <span class="kw">&lt;span&gt;</span>{$value}<span class="kw">&lt;/span&gt;</span>
433{/loop}</code></pre>
434<p>Before end paging:</p>
435<pre class="sourceCode html"><code class="sourceCode html">{loop=&quot;$plugin_end_zone&quot;}
436 {$value}
437{/loop}</code></pre>
438<p><strong>linklist.paging.html</strong></p>
439<p>After the &quot;private only&quot; icon:</p>
440<pre class="sourceCode html"><code class="sourceCode html">{loop=&quot;$action_plugin&quot;}
441 {$value}
442{/loop}</code></pre>
443<p><strong>editlink.html</strong></p>
444<p>After tags field:</p>
445<pre class="sourceCode html"><code class="sourceCode html">{loop=&quot;$edit_link_plugin&quot;}
446 {$value}
447{/loop}</code></pre>
448<p><strong>tools.html</strong></p>
449<p>After the last tool:</p>
450<pre class="sourceCode html"><code class="sourceCode html">{loop=&quot;$tools_plugin&quot;}
451 {$value}
452{/loop}</code></pre>
453<p><strong>picwall.html</strong></p>
454<p>Top:</p>
455<pre class="sourceCode html"><code class="sourceCode html"><span class="kw">&lt;div</span><span class="ot"> id=</span><span class="st">&quot;plugin_zone_start_picwall&quot;</span><span class="ot"> class=</span><span class="st">&quot;plugin_zone&quot;</span><span class="kw">&gt;</span>
456 {loop=&quot;$plugin_start_zone&quot;}
457 {$value}
458 {/loop}
459<span class="kw">&lt;/div&gt;</span></code></pre>
460<p>Bottom:</p>
461<pre class="sourceCode html"><code class="sourceCode html"><span class="kw">&lt;div</span><span class="ot"> id=</span><span class="st">&quot;plugin_zone_end_picwall&quot;</span><span class="ot"> class=</span><span class="st">&quot;plugin_zone&quot;</span><span class="kw">&gt;</span>
462 {loop=&quot;$plugin_end_zone&quot;}
463 {$value}
464 {/loop}
465<span class="kw">&lt;/div&gt;</span></code></pre>
466<p><strong>tagcloud.html</strong></p>
467<p>Top:</p>
468<pre class="sourceCode html"><code class="sourceCode html"> <span class="kw">&lt;div</span><span class="ot"> id=</span><span class="st">&quot;plugin_zone_start_tagcloud&quot;</span><span class="ot"> class=</span><span class="st">&quot;plugin_zone&quot;</span><span class="kw">&gt;</span>
469 {loop=&quot;$plugin_start_zone&quot;}
470 {$value}
471 {/loop}
472 <span class="kw">&lt;/div&gt;</span></code></pre>
473<p>Bottom:</p>
474<pre class="sourceCode html"><code class="sourceCode html"> <span class="kw">&lt;div</span><span class="ot"> id=</span><span class="st">&quot;plugin_zone_end_tagcloud&quot;</span><span class="ot"> class=</span><span class="st">&quot;plugin_zone&quot;</span><span class="kw">&gt;</span>
475 {loop=&quot;$plugin_end_zone&quot;}
476 {$value}
477 {/loop}
478 <span class="kw">&lt;/div&gt;</span></code></pre>
479<p><strong>daily.html</strong></p>
480<p>Top:</p>
481<pre class="sourceCode html"><code class="sourceCode html"><span class="kw">&lt;div</span><span class="ot"> id=</span><span class="st">&quot;plugin_zone_start_picwall&quot;</span><span class="ot"> class=</span><span class="st">&quot;plugin_zone&quot;</span><span class="kw">&gt;</span>
482 {loop=&quot;$plugin_start_zone&quot;}
483 {$value}
484 {/loop}
485<span class="kw">&lt;/div&gt;</span></code></pre>
486<p>After every link:</p>
487<pre class="sourceCode html"><code class="sourceCode html"><span class="kw">&lt;div</span><span class="ot"> class=</span><span class="st">&quot;dailyEntryFooter&quot;</span><span class="kw">&gt;</span>
488 {loop=&quot;$link.link_plugin&quot;}
489 {$value}
490 {/loop}
491<span class="kw">&lt;/div&gt;</span></code></pre>
492<p>Bottom:</p>
493<pre class="sourceCode html"><code class="sourceCode html"><span class="kw">&lt;div</span><span class="ot"> id=</span><span class="st">&quot;plugin_zone_end_picwall&quot;</span><span class="ot"> class=</span><span class="st">&quot;plugin_zone&quot;</span><span class="kw">&gt;</span>
494 {loop=&quot;$plugin_end_zone&quot;}
495 {$value}
496 {/loop}
497<span class="kw">&lt;/div&gt;</span></code></pre>
498</body>
499</html>
diff --git a/doc/Plugin-System.md b/doc/Plugin-System.md
new file mode 100644
index 00000000..8cba6664
--- /dev/null
+++ b/doc/Plugin-System.md
@@ -0,0 +1,590 @@
1#Plugin System
2> Note: Plugin current status - in developpement (not merged into master).
3
4[**I am a user.** Plugin User Guide.](#plugin-user-guide)[](.html)
5
6[**I am a developper.** Developper API.](#developper-api)[](.html)
7
8[**I am a template designer.** Guide for template designer.](#guide-for-template-designer)[](.html)
9
10## Plugin User Guide
11
12### Manage plugins
13
14In `config.php`, change $GLOBALS['config'['ENABLED_PLUGINS'] array:]('ENABLED_PLUGINS']-array:.html)
15
16```php
17$GLOBALS['config'['ENABLED_PLUGINS']]('ENABLED_PLUGINS'].html)
18```
19
20Full list:
21
22```php
23$GLOBALS['config'['ENABLED_PLUGINS'] = array(]('ENABLED_PLUGINS']-=-array(.html)
24 'qrcode', 'archiveorg', 'readityourself', 'playvideos',
25 'wallabag', 'markdown', 'addlink_toolbar',
26);
27```
28
29### List of plugins
30
31Plugin maintained by the community:
32
33 * Archive.org - add a clickable icon to every link to archive.org.
34 * Addlink in toolbar - add a field to paste new links URL in toolbar.
35 * Markdown - write and display Shaare in Markdown.
36 * Play videos - popup to play all videos displayed in linklist.
37 * QRCode - add a clickable icon generating a QRCode for every link.
38 * ReadItYourself - add a clickable icon for ReadItYourself.
39 * Wallabag - add a clickable icon for Wallabag.
40
41## Developper API
42
43### What can I do with plugins?
44
45The plugin system let you:
46
47 * insert content into specific places across templates.
48 * alter data before templates rendering.
49 * alter data before saving new links.
50
51### How can I create a plugin for Shaarli?
52
53First, chose a plugin name, such as `demo_plugin`.
54
55Under `plugin` folder, create a folder named with your plugin name. Then create a <plugin_name>.php file in that folder.
56
57You should have the following tree view:
58
59```
60| index.php
61| plugins/
62|---| demo_plugin/
63| |---| demo_plugin.php
64```
65
66### Understanding hooks
67
68A plugin is a set of functions. Each function will be triggered by the plugin system at certain point in Shaarli execution.
69
70These functions need to be named with this pattern:
71
72```
73hook_<plugin_name>_<hook_name>
74```
75
76For exemple, if my plugin want to add data to the header, this function is needed:
77
78 hook_demo_plugin_render_header()
79
80If this function is declared, and the plugin enabled, it will be called every time Shaarli is rendering the header.
81
82### Plugin's data
83
84#### Parameters
85
86Every hook function has a `$data` parameter. Its content differs for each hooks.
87
88**This parameter needs to be returned every time**, otherwise data is lost.
89
90 return $data;
91
92#### Filling templates placeholder
93
94Template placeholders are displayed in template in specific places.
95
96RainTPL displays every element contained in the placeholder's array. These element can be added by plugins.
97
98For example, let's add a value in the placeholder `top_placeholder` which is displayed at the top of my page:
99
100```php
101$data['top_placeholder'[] = 'My content';](]-=-'My-content';.html)
102# OR
103array_push($data['top_placeholder'], 'My', 'content');[](.html)
104
105return $data;
106```
107
108#### Data manipulation
109
110When a page is displayed, every variable send to the template engine is passed to plugins before that in `$data`.
111
112The data contained by this array can be altered before template rendering.
113
114For exemple, in linklist, it is possible to alter every title:
115
116```php
117// mind the reference if you want $data to be altered
118foreach ($data['links'] as &$value) {[](.html)
119 // String reverse every title.
120 $value['title'] = strrev($value['title']);[](.html)
121}
122
123return $data;
124```
125
126### It's not working!
127
128Use `demo_plugin` as a functional example. It covers most of the plugin system features.
129
130If it's still not working, please [open an issue](https://github.com/shaarli/Shaarli/issues/new).[](.html)
131
132### Hooks
133
134| Hooks | Description |
135| ------------- |:-------------:|
136| [render_header](#render_header) | Allow plugin to add content in page headers. |[](.html)
137| [render_includes](#render_includes) | Allow plugin to include their own CSS files. |[](.html)
138| [render_footer](#render_footer) | Allow plugin to add content in page footer and include their own JS files. | [](.html)
139| [render_linklist](#render_linklist) | It allows to add content at the begining and end of the page, after every link displayed and to alter link data. |[](.html)
140| [render_editlink](#render_editlink) | Allow to add fields in the form, or display elements. |[](.html)
141| [render_tools](#render_tools) | Allow to add content at the end of the page. |[](.html)
142| [render_picwall](#render_picwall) | Allow to add content at the top and bottom of the page. |[](.html)
143| [render_tagcloud](#render_tagcloud) | Allow to add content at the top and bottom of the page. |[](.html)
144| [render_daily](#render_daily) | Allow to add content at the top and bottom of the page, the bottom of each link and to alter data. |[](.html)
145| [savelink](#savelink) | Allow to alter the link being saved in the datastore. |[](.html)
146
147
148#### render_header
149
150Triggered on every page.
151
152Allow plugin to add content in page headers.
153
154##### Data
155
156`$data` is an array containing:
157
158 * `_PAGE_`: current target page (eg: `linklist`, `picwall`, etc.).
159 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
160
161##### Template placeholders
162
163Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
164
165List of placeholders:
166
167 * `buttons_toolbar`: after the list of buttons in the header.
168
169![buttons_toolbar_example](http://i.imgur.com/ssJUOrt.png)[](.html)
170
171 * `fields_toolbar`: after search fields in the header.
172
173> Note: This will only be called in linklist.
174
175![fields_toolbar_example](http://i.imgur.com/3GMifI2.png)[](.html)
176
177#### render_includes
178
179Triggered on every page.
180
181Allow plugin to include their own CSS files.
182
183##### Data
184
185`$data` is an array containing:
186
187 * `_PAGE_`: current target page (eg: `linklist`, `picwall`, etc.).
188 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
189
190##### Template placeholders
191
192Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
193
194List of placeholders:
195
196 * `css_files`: called after loading default CSS.
197
198> Note: only add the path of the CSS file. E.g: `plugins/demo_plugin/custom_demo.css`.
199
200#### render_footer
201
202Triggered on every page.
203
204Allow plugin to add content in page footer and include their own JS files.
205
206##### Data
207
208`$data` is an array containing:
209
210 * `_PAGE_`: current target page (eg: `linklist`, `picwall`, etc.).
211 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
212
213##### Template placeholders
214
215Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
216
217List of placeholders:
218
219 * `text`: called after the end of the footer text.
220
221![text_example](http://i.imgur.com/L5S2YEH.png)[](.html)
222
223 * `js_files`: called at the end of the page, to include custom JS scripts.
224
225> Note: only add the path of the JS file. E.g: `plugins/demo_plugin/custom_demo.js`.
226
227#### render_linklist
228
229Triggered when `linklist` is displayed (list of links, permalink, search, tag filtered, etc.).
230
231It allows to add content at the begining and end of the page, after every link displayed and to alter link data.
232
233##### Data
234
235`$data` is an array containing:
236
237 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
238 * All templates data, including links.
239
240##### Template placeholders
241
242Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
243
244List of placeholders:
245
246 * `action_plugin`: next to the button "private only" at the top and bottom of the page.
247
248![action_plugin_example](http://i.imgur.com/Q12PWg0.png)[](.html)
249
250 * `link_plugin`: for every link, between permalink and link URL.
251
252![link_plugin_example](http://i.imgur.com/3oDPhWx.png)[](.html)
253
254 * `plugin_start_zone`: before displaying the template content.
255
256![plugin_start_zone_example](http://i.imgur.com/OVBkGy3.png)[](.html)
257
258 * `plugin_end_zone`: after displaying the template content.
259
260![plugin_end_zone_example](http://i.imgur.com/6IoRuop.png)[](.html)
261
262#### render_editlink
263
264Triggered when the link edition form is displayed.
265
266Allow to add fields in the form, or display elements.
267
268##### Data
269
270`$data` is an array containing:
271
272 * All templates data.
273
274##### Template placeholders
275
276Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
277
278List of placeholders:
279
280 * `edit_link_plugin`: after tags field.
281
282![edit_link_plugin_example](http://i.imgur.com/5u17Ens.png)[](.html)
283
284#### render_tools
285
286Triggered when the "tools" page is displayed.
287
288Allow to add content at the end of the page.
289
290##### Data
291
292`$data` is an array containing:
293
294 * All templates data.
295
296##### Template placeholders
297
298Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
299
300List of placeholders:
301
302 * `tools_plugin`: at the end of the page.
303
304![tools_plugin_example](http://i.imgur.com/Bqhu9oQ.png)[](.html)
305
306#### render_picwall
307
308Triggered when picwall is displayed.
309
310Allow to add content at the top and bottom of the page.
311
312##### Data
313
314`$data` is an array containing:
315
316 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
317 * All templates data.
318
319##### Template placeholders
320
321Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
322
323List of placeholders:
324
325 * `plugin_start_zone`: before displaying the template content.
326
327 * `plugin_end_zone`: after displaying the template content.
328
329![plugin_start_end_zone_example](http://i.imgur.com/tVTQFER.png)[](.html)
330
331#### render_tagcloud
332
333Triggered when tagcloud is displayed.
334
335Allow to add content at the top and bottom of the page.
336
337##### Data
338
339`$data` is an array containing:
340
341 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
342 * All templates data.
343
344##### Template placeholders
345
346Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
347
348List of placeholders:
349
350 * `plugin_start_zone`: before displaying the template content.
351
352 * `plugin_end_zone`: after displaying the template content.
353
354![plugin_start_end_zone_example](http://i.imgur.com/vHmyT3a.png)[](.html)
355
356#### render_daily
357
358Triggered when tagcloud is displayed.
359
360Allow to add content at the top and bottom of the page, the bottom of each link and to alter data.
361
362##### Data
363
364`$data` is an array containing:
365
366 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
367 * All templates data, including links.
368
369##### Template placeholders
370
371Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
372
373List of placeholders:
374
375 * `link_plugin`: used at bottom of each link.
376
377![link_plugin_example](http://i.imgur.com/hzhMfSZ.png)[](.html)
378
379 * `plugin_start_zone`: before displaying the template content.
380
381 * `plugin_end_zone`: after displaying the template content.
382
383#### savelink
384
385Triggered when a link is save (new link or edit).
386
387Allow to alter the link being saved in the datastore.
388
389##### Data
390
391`$data` is an array containing the link being saved:
392
393 * title
394 * url
395 * description
396 * linkdate
397 * private
398 * tags
399
400## Guide for template designer
401
402### Placeholder system
403
404In order to make plugins work with every custom themes, you need to add variable placeholder in your templates.
405
406It's a RainTPL loop like this:
407
408 {loop="$plugin_variable"}
409 {$value}
410 {/loop}
411
412You should enable `demo_plugin` for testing purpose, since it uses every placeholder available.
413
414### List of placeholders
415
416**page.header.html**
417
418At the end of the menu:
419
420 {loop="$plugins_header.buttons_toolbar"}
421 {$value}
422 {/loop}
423
424**includes.html**
425
426At the end of the file:
427
428```html
429{loop="$plugins_includes.css_files"}
430<link type="text/css" rel="stylesheet" href="{$value}#"/>
431{/loop}
432```
433
434**page.footer.html**
435
436At the end of your footer notes:
437
438```html
439{loop="$plugins_footer.text"}
440 {$value}
441{/loop}
442```
443
444At the end of file:
445
446```html
447{loop="$plugins_footer.js_files"}
448 <script src="{$value}#"></script>
449{/loop}
450```
451
452**linklist.html**
453
454After search fields:
455
456```html
457{loop="$plugins_header.fields_toolbar"}
458 {$value}
459{/loop}
460```
461
462Before displaying the link list (after paging):
463
464```html
465{loop="$plugin_start_zone"}
466 {$value}
467{/loop}
468```
469
470For every links (icons):
471
472```html
473{loop="$value.link_plugin"}
474 <span>{$value}</span>
475{/loop}
476```
477
478Before end paging:
479
480```html
481{loop="$plugin_end_zone"}
482 {$value}
483{/loop}
484```
485
486**linklist.paging.html**
487
488After the "private only" icon:
489
490```html
491{loop="$action_plugin"}
492 {$value}
493{/loop}
494```
495
496**editlink.html**
497
498After tags field:
499
500```html
501{loop="$edit_link_plugin"}
502 {$value}
503{/loop}
504```
505
506**tools.html**
507
508After the last tool:
509
510```html
511{loop="$tools_plugin"}
512 {$value}
513{/loop}
514```
515
516**picwall.html**
517
518Top:
519
520```html
521<div id="plugin_zone_start_picwall" class="plugin_zone">
522 {loop="$plugin_start_zone"}
523 {$value}
524 {/loop}
525</div>
526```
527
528Bottom:
529
530```html
531<div id="plugin_zone_end_picwall" class="plugin_zone">
532 {loop="$plugin_end_zone"}
533 {$value}
534 {/loop}
535</div>
536```
537
538**tagcloud.html**
539
540Top:
541
542```html
543 <div id="plugin_zone_start_tagcloud" class="plugin_zone">
544 {loop="$plugin_start_zone"}
545 {$value}
546 {/loop}
547 </div>
548```
549
550Bottom:
551
552```html
553 <div id="plugin_zone_end_tagcloud" class="plugin_zone">
554 {loop="$plugin_end_zone"}
555 {$value}
556 {/loop}
557 </div>
558```
559
560**daily.html**
561
562Top:
563
564```html
565<div id="plugin_zone_start_picwall" class="plugin_zone">
566 {loop="$plugin_start_zone"}
567 {$value}
568 {/loop}
569</div>
570```
571
572After every link:
573
574```html
575<div class="dailyEntryFooter">
576 {loop="$link.link_plugin"}
577 {$value}
578 {/loop}
579</div>
580```
581
582Bottom:
583
584```html
585<div id="plugin_zone_end_picwall" class="plugin_zone">
586 {loop="$plugin_end_zone"}
587 {$value}
588 {/loop}
589</div>
590```
diff --git a/doc/RSS-feeds.html b/doc/RSS-feeds.html
new file mode 100644
index 00000000..4a9b7a0e
--- /dev/null
+++ b/doc/RSS-feeds.html
@@ -0,0 +1,75 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - RSS feeds</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <link rel="stylesheet" href="github-markdown.css">
13</head>
14<body>
15<div id="local-sidebar">
16<ul>
17<li><a href="Home.html">Home</a></li>
18<li>Installation
19<ul>
20<li><a href="Server-requirements.html">Server requirements</a></li>
21<li><a href="Server-configuration.html">Server configuration</a></li>
22<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
23</ul></li>
24<li><a href="Usage.html">Usage</a>
25<ul>
26<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
27<li><a href="Firefox-share.html">Firefox share</a></li>
28<li><a href="RSS-feeds.html">RSS feeds</a></li>
29</ul></li>
30<li>How To
31<ul>
32<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
33<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
34<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
35</ul></li>
36<li><a href="Troubleshooting.html">Troubleshooting</a></li>
37<li><a href="Development.html">Development</a>
38<ul>
39<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
40<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
41<li><a href="Directory-structure.html">Directory structure</a></li>
42<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
43<li><a href="Plugin-System.html">Plugin System</a></li>
44<li><a href="Security.html">Security</a></li>
45<li><a href="Static-analysis.html">Static analysis</a></li>
46<li><a href="Theming.html">Theming</a></li>
47<li><a href="Unit-tests.html">Unit tests</a></li>
48</ul></li>
49<li>About
50<ul>
51<li><a href="FAQ.html">FAQ</a></li>
52<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
53<li><a href="TODO.html">TODO</a></li>
54</ul></li>
55</ul>
56</div>
57<h1 id="rss-feeds">RSS feeds</h1>
58<h3 id="rss-feeds-or-picture-wall-for-a-specific-searchtag">RSS Feeds or Picture Wall for a specific search/tag</h3>
59<p>It is possible to filter RSS/ATOM feeds and Picture Wall on a Shaarli to <strong>only display results of a specific search, or for a specific tag</strong>.</p>
60<p>For example, if you want to subscribe only to links tagged <code>photography</code>:</p>
61<ul>
62<li>Go to the desired Shaarli instance.</li>
63<li>Search for the <code>photography</code> tag in the <em>Filter by tag</em> box. Links tagged <code>photography</code> are displayed.</li>
64<li>Click on the <code>RSS Feed</code> button.</li>
65<li>You are presented with an RSS feed showing only these links. Subscribe to it to receive only updates with this tag.</li>
66<li>The same method <strong>also works for a full-text search</strong> (<em>Search</em> box) <strong>and for the Picture Wall</strong> (want to only see pictures about <code>nature</code>?)</li>
67<li>You can also build the URLs manually:
68<ul>
69<li><code>https://my.shaarli.domain/?do=rss&amp;searchtags=nature</code></li>
70<li><code>https://my.shaarli.domain/links/?do=picwall&amp;searchterm=poney</code></li>
71</ul></li>
72</ul>
73<p><embed src="(images/rss-filter-1.png)-!.html" />(images/rss-filter-2.png)</p>
74</body>
75</html>
diff --git a/doc/RSS-feeds.md b/doc/RSS-feeds.md
new file mode 100644
index 00000000..764b3a49
--- /dev/null
+++ b/doc/RSS-feeds.md
@@ -0,0 +1,15 @@
1#RSS feeds
2### RSS Feeds or Picture Wall for a specific search/tag
3It is possible to filter RSS/ATOM feeds and Picture Wall on a Shaarli to **only display results of a specific search, or for a specific tag**.
4
5For example, if you want to subscribe only to links tagged `photography`:
6- Go to the desired Shaarli instance.
7- Search for the `photography` tag in the _Filter by tag_ box. Links tagged `photography` are displayed.
8- Click on the `RSS Feed` button.
9- You are presented with an RSS feed showing only these links. Subscribe to it to receive only updates with this tag.
10- The same method **also works for a full-text search** (_Search_ box) **and for the Picture Wall** (want to only see pictures about `nature`?)
11- You can also build the URLs manually:
12 - `https://my.shaarli.domain/?do=rss&searchtags=nature`
13 - `https://my.shaarli.domain/links/?do=picwall&searchterm=poney`
14
15![(images/rss-filter-1.png) !]((images/rss-filter-1.png)-!.html)(images/rss-filter-2.png)
diff --git a/doc/Security.html b/doc/Security.html
new file mode 100644
index 00000000..1fbbabde
--- /dev/null
+++ b/doc/Security.html
@@ -0,0 +1,107 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Security</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <style type="text/css">
13table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
14 margin: 0; padding: 0; vertical-align: baseline; border: none; }
15table.sourceCode { width: 100%; line-height: 100%; }
16td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
17td.sourceCode { padding-left: 5px; }
18code > span.kw { color: #007020; font-weight: bold; }
19code > span.dt { color: #902000; }
20code > span.dv { color: #40a070; }
21code > span.bn { color: #40a070; }
22code > span.fl { color: #40a070; }
23code > span.ch { color: #4070a0; }
24code > span.st { color: #4070a0; }
25code > span.co { color: #60a0b0; font-style: italic; }
26code > span.ot { color: #007020; }
27code > span.al { color: #ff0000; font-weight: bold; }
28code > span.fu { color: #06287e; }
29code > span.er { color: #ff0000; font-weight: bold; }
30 </style>
31 <link rel="stylesheet" href="github-markdown.css">
32</head>
33<body>
34<div id="local-sidebar">
35<ul>
36<li><a href="Home.html">Home</a></li>
37<li>Installation
38<ul>
39<li><a href="Server-requirements.html">Server requirements</a></li>
40<li><a href="Server-configuration.html">Server configuration</a></li>
41<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
42</ul></li>
43<li><a href="Usage.html">Usage</a>
44<ul>
45<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
46<li><a href="Firefox-share.html">Firefox share</a></li>
47<li><a href="RSS-feeds.html">RSS feeds</a></li>
48</ul></li>
49<li>How To
50<ul>
51<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
52<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
53<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
54</ul></li>
55<li><a href="Troubleshooting.html">Troubleshooting</a></li>
56<li><a href="Development.html">Development</a>
57<ul>
58<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
59<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
60<li><a href="Directory-structure.html">Directory structure</a></li>
61<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
62<li><a href="Plugin-System.html">Plugin System</a></li>
63<li><a href="Security.html">Security</a></li>
64<li><a href="Static-analysis.html">Static analysis</a></li>
65<li><a href="Theming.html">Theming</a></li>
66<li><a href="Unit-tests.html">Unit tests</a></li>
67</ul></li>
68<li>About
69<ul>
70<li><a href="FAQ.html">FAQ</a></li>
71<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
72<li><a href="TODO.html">TODO</a></li>
73</ul></li>
74</ul>
75</div>
76<h1 id="security">Security</h1>
77<h2 id="client-browser">Client browser</h2>
78<ul>
79<li>Shaarli relies on <code>HTTP_REFERER</code> for some functions (like redirects and clicking on tags). If you have disabled or masqueraded <code>HTTP_REFERER</code> in your browser, some features of Shaarli may not work</li>
80</ul>
81<h2 id="php">PHP</h2>
82<ul>
83<li><code>magic_quotes</code> is an horrible option of PHP which is often activated on servers. No serious developer should rely on this horror to secure their code against SQL injections. You should disable it (and Shaarli expects this option to be disabled). Nevertheless, I have added code to cope with <code>magic_quotes</code> on, so you should not be bothered even on crappy hosts.</li>
84</ul>
85<h2 id="server-and-sessions">Server and sessions</h2>
86<ul>
87<li>Directories are protected using <code>.htaccess</code> files</li>
88<li>Forms are protected against XSRF (Cross-site requests forgery):</li>
89<li>Forms which act on data (save,delete…) contain a token generated by the server.</li>
90<li>Any posted form which does not contain a valid token is rejected.</li>
91<li>Any token can only be used once.</li>
92<li>Tokens are attached to the session and cannot be reused in another session.</li>
93<li>Sessions automatically expire after 60 minutes.</li>
94<li>Sessions are protected against hijacking: the session ID cannot be used from a different IP address.</li>
95</ul>
96<h2 id="shaarli-datastore-and-configuration">Shaarli datastore and configuration</h2>
97<ul>
98<li>The password is salted, hashed and stored in the data subdirectory, in a PHP file, and protected by htaccess. Even if the webserver does not support htaccess, the hash is not readable by URL. Even if the .php file is stolen, the password cannot deduced from the hash. The salt prevents rainbow-tables attacks.</li>
99<li>Links are stored as an associative array which is serialized, compressed (with deflate), base64-encoded and saved as a comment in a <code>.php</code> file.</li>
100<li>Even if the server does not support <code>.htaccess</code> files, the data file will still not be readable by URL.</li>
101<li><p>The database looks like this:</p>
102<pre class="sourceCode php"><code class="sourceCode php"><span class="kw">&lt;?php</span> <span class="co">/* zP1ZjxxJtiYIvvevEPJ2lDOaLrZv7o...</span>
103<span class="co">...ka7gaco/Z+TFXM2i7BlfMf8qxpaSSYfKlvqv/x8= */</span> <span class="kw">?&gt;</span></code></pre></li>
104<li><p>Small hashes are used to make a link to an entry in Shaarli. They are unique. In fact, the date of the items (eg. <code>20110923_150523</code>) is hashed with CRC32, then converted to base64 and some characters are replaced. They are always 6 characters longs and use only <code>A-Z a-z 0-9 - _</code> and <code>@</code>.</p></li>
105</ul>
106</body>
107</html>
diff --git a/doc/Security.md b/doc/Security.md
new file mode 100644
index 00000000..7947460c
--- /dev/null
+++ b/doc/Security.md
@@ -0,0 +1,28 @@
1#Security
2## Client browser
3* Shaarli relies on `HTTP_REFERER` for some functions (like redirects and clicking on tags). If you have disabled or masqueraded `HTTP_REFERER` in your browser, some features of Shaarli may not work
4
5## PHP
6* `magic_quotes` is an horrible option of PHP which is often activated on servers. No serious developer should rely on this horror to secure their code against SQL injections. You should disable it (and Shaarli expects this option to be disabled). Nevertheless, I have added code to cope with `magic_quotes` on, so you should not be bothered even on crappy hosts.
7
8## Server and sessions
9* Directories are protected using `.htaccess` files
10* Forms are protected against XSRF (Cross-site requests forgery):
11 * Forms which act on data (save,delete…) contain a token generated by the server.
12 * Any posted form which does not contain a valid token is rejected.
13 * Any token can only be used once.
14 * Tokens are attached to the session and cannot be reused in another session.
15* Sessions automatically expire after 60 minutes.
16* Sessions are protected against hijacking: the session ID cannot be used from a different IP address.
17
18## Shaarli datastore and configuration
19* The password is salted, hashed and stored in the data subdirectory, in a PHP file, and protected by htaccess. Even if the webserver does not support htaccess, the hash is not readable by URL. Even if the .php file is stolen, the password cannot deduced from the hash. The salt prevents rainbow-tables attacks.
20* Links are stored as an associative array which is serialized, compressed (with deflate), base64-encoded and saved as a comment in a `.php` file.
21* Even if the server does not support `.htaccess` files, the data file will still not be readable by URL.
22* The database looks like this:
23```php
24<?php /* zP1ZjxxJtiYIvvevEPJ2lDOaLrZv7o...
25...ka7gaco/Z+TFXM2i7BlfMf8qxpaSSYfKlvqv/x8= */ ?>
26```
27
28* Small hashes are used to make a link to an entry in Shaarli. They are unique. In fact, the date of the items (eg. `20110923_150523`) is hashed with CRC32, then converted to base64 and some characters are replaced. They are always 6 characters longs and use only `A-Z a-z 0-9 - _` and `@`.
diff --git a/doc/Server-configuration.html b/doc/Server-configuration.html
new file mode 100644
index 00000000..de6bf488
--- /dev/null
+++ b/doc/Server-configuration.html
@@ -0,0 +1,371 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Server configuration</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <style type="text/css">
13table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
14 margin: 0; padding: 0; vertical-align: baseline; border: none; }
15table.sourceCode { width: 100%; line-height: 100%; }
16td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
17td.sourceCode { padding-left: 5px; }
18code > span.kw { color: #007020; font-weight: bold; }
19code > span.dt { color: #902000; }
20code > span.dv { color: #40a070; }
21code > span.bn { color: #40a070; }
22code > span.fl { color: #40a070; }
23code > span.ch { color: #4070a0; }
24code > span.st { color: #4070a0; }
25code > span.co { color: #60a0b0; font-style: italic; }
26code > span.ot { color: #007020; }
27code > span.al { color: #ff0000; font-weight: bold; }
28code > span.fu { color: #06287e; }
29code > span.er { color: #ff0000; font-weight: bold; }
30 </style>
31 <link rel="stylesheet" href="github-markdown.css">
32</head>
33<body>
34<div id="local-sidebar">
35<ul>
36<li><a href="Home.html">Home</a></li>
37<li>Installation
38<ul>
39<li><a href="Server-requirements.html">Server requirements</a></li>
40<li><a href="Server-configuration.html">Server configuration</a></li>
41<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
42</ul></li>
43<li><a href="Usage.html">Usage</a>
44<ul>
45<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
46<li><a href="Firefox-share.html">Firefox share</a></li>
47<li><a href="RSS-feeds.html">RSS feeds</a></li>
48</ul></li>
49<li>How To
50<ul>
51<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
52<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
53<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
54</ul></li>
55<li><a href="Troubleshooting.html">Troubleshooting</a></li>
56<li><a href="Development.html">Development</a>
57<ul>
58<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
59<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
60<li><a href="Directory-structure.html">Directory structure</a></li>
61<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
62<li><a href="Plugin-System.html">Plugin System</a></li>
63<li><a href="Security.html">Security</a></li>
64<li><a href="Static-analysis.html">Static analysis</a></li>
65<li><a href="Theming.html">Theming</a></li>
66<li><a href="Unit-tests.html">Unit tests</a></li>
67</ul></li>
68<li>About
69<ul>
70<li><a href="FAQ.html">FAQ</a></li>
71<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
72<li><a href="TODO.html">TODO</a></li>
73</ul></li>
74</ul>
75</div>
76<h1 id="server-configuration">Server configuration</h1>
77<p><em>Example virtual host configurations for popular web servers</em></p>
78<ul>
79<li><a href="#apache">Apache</a><a href=".html"></a></li>
80<li><a href="#lighthttpd">LightHttpd</a> (empty)<a href=".html"></a></li>
81<li><a href="#nginx">Nginx</a><a href=".html"></a></li>
82</ul>
83<h2 id="prerequisites">Prerequisites</h2>
84<ul>
85<li>Shaarli is installed in a directory readable/writeable by the user</li>
86<li>the correct read/write permissions have been granted to the web server <em>user and/or group</em></li>
87<li>for HTTPS / SSL:</li>
88<li>a key pair (public, private) and a certificate have been generated</li>
89<li>the appropriate server SSL extension is installed and active</li>
90</ul>
91<p>Related guides:</p>
92<ul>
93<li><a href="http://www.xenocafe.com/tutorials/linux/centos/openssl/self_signed_certificates/index.php">How to Create Self-Signed SSL Certificates with OpenSSL</a><a href=".html"></a></li>
94<li><a href="https://workaround.org/certificate-authority">How do I create my own Certificate Authority?</a><a href=".html"></a></li>
95</ul>
96<h2 id="apache">Apache</h2>
97<h3 id="minimal">Minimal</h3>
98<pre class="sourceCode apache"><code class="sourceCode apache"><span class="fu">&lt;VirtualHost</span><span class="ot"> *:80</span><span class="fu">&gt;</span>
99 ServerName<span class="st"> shaarli.my-domain.org</span>
100 DocumentRoot<span class="st"> /absolute/path/to/shaarli/</span>
101<span class="fu">&lt;/VirtualHost&gt;</span></code></pre>
102<h3 id="debug---log-all-the-things">Debug - Log all the things!</h3>
103<p>This configuration will log both Apache and PHP errors, which may prove useful to identify server configuration errors.</p>
104<p>See:</p>
105<ul>
106<li><a href="http://stackoverflow.com/q/176">Apache/PHP - error log per VirtualHost</a> (StackOverflow)<a href=".html"></a></li>
107<li><a href="PHP:%20php_value%20vs%20php_admin_value%20and%20the%20use%20of%20php_flag%20explained">PHP: php_value vs php_admin_value and the use of php_flag explained</a><a href=".html"></a></li>
108</ul>
109<pre class="sourceCode apache"><code class="sourceCode apache"><span class="fu">&lt;VirtualHost</span><span class="ot"> *:80</span><span class="fu">&gt;</span>
110 ServerName<span class="st"> shaarli.my-domain.org</span>
111 DocumentRoot<span class="st"> /absolute/path/to/shaarli/</span>
112
113 <span class="ot">LogLevel</span><span class="ch"> </span><span class="kw">warn</span>
114 ErrorLog<span class="st"> /var/log/apache2/shaarli-error.log</span>
115 CustomLog<span class="st"> /var/log/apache2/shaarli-access.log combined</span>
116
117 php_flag log_errors on
118 php_flag display_errors on
119 php_value error_reporting 2147483647
120 php_value error_log /var/log/apache2/shaarli-php-error.log
121<span class="fu">&lt;/VirtualHost&gt;</span></code></pre>
122<h3 id="standard---keep-access-and-error-logs">Standard - Keep access and error logs</h3>
123<pre class="sourceCode apache"><code class="sourceCode apache"><span class="fu">&lt;VirtualHost</span><span class="ot"> *:80</span><span class="fu">&gt;</span>
124 ServerName<span class="st"> shaarli.my-domain.org</span>
125 DocumentRoot<span class="st"> /absolute/path/to/shaarli/</span>
126
127 <span class="ot">LogLevel</span><span class="ch"> </span><span class="kw">warn</span>
128 ErrorLog<span class="st"> /var/log/apache2/shaarli-error.log</span>
129 CustomLog<span class="st"> /var/log/apache2/shaarli-access.log combined</span>
130<span class="fu">&lt;/VirtualHost&gt;</span></code></pre>
131<h3 id="paranoid---redirect-http-80-to-https-443">Paranoid - Redirect HTTP (:80) to HTTPS (:443)</h3>
132<p>See <a href="https://wiki.mozilla.org/Security/Server_Side_TLS#Apache">Server-side TLS</a> (Mozilla).<a href=".html"></a></p>
133<pre class="sourceCode apache"><code class="sourceCode apache"><span class="fu">&lt;VirtualHost</span><span class="ot"> *:443</span><span class="fu">&gt;</span>
134 ServerName<span class="st"> shaarli.my-domain.org</span>
135 DocumentRoot<span class="st"> /absolute/path/to/shaarli/</span>
136
137 <span class="ot">SSLEngine</span><span class="ch"> </span><span class="kw">on</span>
138 SSLCertificateFile<span class="st"> /absolute/path/to/the/website/certificate.crt</span>
139 SSLCertificateKeyFile<span class="st"> /absolute/path/to/the/website/key.key</span>
140
141 <span class="fu">&lt;Directory</span><span class="ot"> /absolute/path/to/shaarli/</span><span class="fu">&gt;</span>
142 <span class="ot">AllowOverride</span><span class="ch"> </span><span class="kw">All</span>
143 <span class="ot">Options</span><span class="ch"> </span><span class="kw">Indexes</span><span class="ch"> </span><span class="kw">FollowSymLinks</span><span class="ch"> </span><span class="kw">MultiViews</span>
144 <span class="ot">Order</span><span class="ch"> </span><span class="kw">allow,deny</span>
145 allow<span class="st"> from all</span>
146 <span class="fu">&lt;/Directory&gt;</span>
147
148 <span class="ot">LogLevel</span><span class="ch"> </span><span class="kw">warn</span>
149 ErrorLog<span class="st"> /var/log/apache2/shaarli-error.log</span>
150 CustomLog<span class="st"> /var/log/apache2/shaarli-access.log combined</span>
151<span class="fu">&lt;/VirtualHost&gt;</span>
152<span class="fu">&lt;VirtualHost</span><span class="ot"> *:80</span><span class="fu">&gt;</span>
153 ServerName<span class="st"> shaarli.my-domain.org</span>
154 Redirect<span class="st"> 301 / https://shaarli.my-domain.org</span>
155
156 <span class="ot">LogLevel</span><span class="ch"> </span><span class="kw">warn</span>
157 ErrorLog<span class="st"> /var/log/apache2/shaarli-error.log</span>
158 CustomLog<span class="st"> /var/log/apache2/shaarli-access.log combined</span>
159<span class="fu">&lt;/VirtualHost&gt;</span></code></pre>
160<h2 id="lighthttpd">LightHttpd</h2>
161<h2 id="nginx">Nginx</h2>
162<h3 id="foreword">Foreword</h3>
163<p>Nginx does not natively interpret PHP scripts; to this effect, we will run a <a href="https://en.wikipedia.org/wiki/FastCGI">FastCGI</a> service, to which Nginx's FastCGI module will proxy all requests to PHP resources.<a href=".html"></a></p>
164<p>Required packages:</p>
165<ul>
166<li><a href="http://nginx.org">nginx</a><a href=".html"></a></li>
167<li><a href="http://php-fpm.org">php-fpm</a> - PHP FastCGI Process Manager<a href=".html"></a></li>
168</ul>
169<p>Official documentation:</p>
170<ul>
171<li><a href="http://nginx.org/en/docs/beginners_guide.html">Beginner's guide</a><a href=".html"></a></li>
172<li><a href="http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html">ngx_http_fastcgi_module</a><a href=".html"></a></li>
173<li><a href="http://wiki.nginx.org/Pitfalls">Pitfalls</a><a href=".html"></a></li>
174</ul>
175<p>Community resources:</p>
176<ul>
177<li><a href="https://wiki.mozilla.org/Security/Server_Side_TLS#Nginx">Server-side TLS (Nginx)</a> (Mozilla)<a href=".html"></a></li>
178<li><a href="http://kbeezie.com/nginx-configuration-examples/">PHP configuration examples</a> (Karl Blessing)<a href=".html"></a></li>
179</ul>
180<h3 id="common-setup">Common setup</h3>
181<p>Once Nginx and PHP-FPM are installed, we need to ensure:</p>
182<ul>
183<li>Nginx and PHP-FPM are running using the <em>same user and group</em></li>
184<li>both these user and group have
185<ul>
186<li><code>read</code> permissions for Shaarli resources</li>
187<li><code>execute</code> permissions for Shaarli directories <em>AND</em> their parent directories</li>
188</ul></li>
189</ul>
190<p>On a production server:</p>
191<ul>
192<li><code>user:group</code> will likely be <code>http:http</code>, <code>www:www</code> or <code>www-data:www-data</code></li>
193<li>files will be located under <code>/var/www</code>, <code>/var/http</code> or <code>/usr/share/nginx</code></li>
194</ul>
195<p>On a development server:</p>
196<ul>
197<li>files may be located in a user's home directory</li>
198<li>in this case, make sure both Nginx and PHP-FPM are running as the local user/group!</li>
199</ul>
200<p>For all following examples, a development configuration will be used:</p>
201<ul>
202<li><code>user:group = john:users</code>,</li>
203</ul>
204<p>which corresponds to the following service configuration:</p>
205<pre class="sourceCode ini"><code class="sourceCode ini"><span class="co">; /etc/php/php-fpm.conf</span>
206<span class="dt">user </span><span class="ot">=</span><span class="st"> john</span>
207<span class="dt">group </span><span class="ot">=</span><span class="st"> users</span>
208
209<span class="kw">[...][]</span><span class="dt">(.html)</span>
210<span class="dt">listen.owner </span><span class="ot">=</span><span class="st"> john</span>
211<span class="dt">listen.group </span><span class="ot">=</span><span class="st"> users</span></code></pre>
212<pre class="nginx"><code># /etc/nginx/nginx.conf
213user john users;
214
215http {
216 [...][](.html)
217}</code></pre>
218<h3 id="minimal-1">Minimal</h3>
219<p><em>WARNING: Use for development only!</em></p>
220<pre class="nginx"><code>user john users;
221worker_processes 1;
222events {
223 worker_connections 1024;
224}
225
226http {
227 include mime.types;
228 default_type application/octet-stream;
229 keepalive_timeout 20;
230
231 index index.html index.php;
232
233 server {
234 listen 80;
235 server_name localhost;
236 root /home/john/web;
237
238 access_log /var/log/nginx/access.log;
239 error_log /var/log/nginx/error.log;
240
241 location /shaarli/ {
242 access_log /var/log/nginx/shaarli.access.log;
243 error_log /var/log/nginx/shaarli.error.log;
244 }
245
246 location ~ (index)\.php$ {
247 fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
248 fastcgi_index index.php;
249 include fastcgi.conf;
250 }
251 }
252}</code></pre>
253<h3 id="modular">Modular</h3>
254<p>The previous setup is sufficient for development purposes, but has several major caveats:</p>
255<ul>
256<li>every content that does not match the PHP rule will be sent to client browsers:
257<ul>
258<li>dotfiles - in our case, <code>.htaccess</code></li>
259<li>temporary files, e.g. Vim or Emacs files: <code>index.php~</code></li>
260</ul></li>
261<li>asset / static resource caching is not optimized</li>
262<li>if serving several PHP sites, there will be a lot of duplication: <code>location /shaarli/</code>, <code>location /mysite/</code>, etc.</li>
263</ul>
264<p>To solve this, we will split Nginx configuration in several parts, that will be included when needed:</p>
265<pre class="nginx"><code># /etc/nginx/deny.conf
266location ~ /\. {
267 # deny access to dotfiles
268 access_log off;
269 log_not_found off;
270 deny all;
271}
272
273location ~ ~$ {
274 # deny access to temp editor files, e.g. &quot;script.php~&quot;
275 access_log off;
276 log_not_found off;
277 deny all;
278}</code></pre>
279<pre class="nginx"><code># /etc/nginx/php.conf
280location ~ (index)\.php$ {
281 # proxy PHP requests to PHP-FPM
282 fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
283 fastcgi_index index.php;
284 include fastcgi.conf;
285}</code></pre>
286<pre class="nginx"><code># /etc/nginx/static_assets.conf
287location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
288 expires max;
289 add_header Pragma public;
290 add_header Cache-Control &quot;public, must-revalidate, proxy-revalidate&quot;;
291}</code></pre>
292<pre class="nginx"><code># /etc/nginx/nginx.conf
293[...][](.html)
294
295http {
296 [...][](.html)
297
298 root /home/john/web;
299 access_log /var/log/nginx/access.log;
300 error_log /var/log/nginx/error.log;
301
302 server {
303 # virtual host for a first domain
304 listen 80;
305 server_name my.first.domain.org;
306
307 location /shaarli/ {
308 access_log /var/log/nginx/shaarli.access.log;
309 error_log /var/log/nginx/shaarli.error.log;
310 }
311
312 include deny.conf;
313 include static_assets.conf;
314 include php.conf;
315 }
316
317 server {
318 # virtual host for a second domain
319 listen 80;
320 server_name second.domain.com;
321
322 location /minigal/ {
323 access_log /var/log/nginx/minigal.access.log;
324 error_log /var/log/nginx/minigal.error.log;
325 }
326
327 include deny.conf;
328 include static_assets.conf;
329 include php.conf;
330 }
331}</code></pre>
332<h3 id="redirect-http-to-https">Redirect HTTP to HTTPS</h3>
333<p>Assuming you have generated a (self-signed) key and certificate, and they are located under <code>/home/john/ssl/localhost.{key,crt}</code>, it is pretty straightforward to set an HTTP (:80) to HTTPS (:443) redirection to force SSL/TLS usage.</p>
334<pre class="nginx"><code># /etc/nginx/nginx.conf
335[...][](.html)
336
337http {
338 [...][](.html)
339
340 index index.html index.php;
341
342 root /home/john/web;
343 access_log /var/log/nginx/access.log;
344 error_log /var/log/nginx/error.log;
345
346 server {
347 listen 80;
348 server_name localhost;
349
350 return 301 https://localhost$request_uri;
351 }
352
353 server {
354 listen 443 ssl;
355 server_name localhost;
356
357 ssl_certificate /home/john/ssl/localhost.crt;
358 ssl_certificate_key /home/john/ssl/localhost.key;
359
360 location /shaarli/ {
361 access_log /var/log/nginx/shaarli.access.log;
362 error_log /var/log/nginx/shaarli.error.log;
363 }
364
365 include deny.conf;
366 include static_assets.conf;
367 include php.conf;
368 }
369}</code></pre>
370</body>
371</html>
diff --git a/doc/Server-configuration.md b/doc/Server-configuration.md
new file mode 100644
index 00000000..c9ec4e13
--- /dev/null
+++ b/doc/Server-configuration.md
@@ -0,0 +1,321 @@
1#Server configuration
2*Example virtual host configurations for popular web servers*
3
4- [Apache](#apache)[](.html)
5- [LightHttpd](#lighthttpd) (empty)[](.html)
6- [Nginx](#nginx)[](.html)
7
8## Prerequisites
9* Shaarli is installed in a directory readable/writeable by the user
10* the correct read/write permissions have been granted to the web server _user and/or group_
11* for HTTPS / SSL:
12 * a key pair (public, private) and a certificate have been generated
13 * the appropriate server SSL extension is installed and active
14
15Related guides:
16* [How to Create Self-Signed SSL Certificates with OpenSSL](http://www.xenocafe.com/tutorials/linux/centos/openssl/self_signed_certificates/index.php)[](.html)
17* [How do I create my own Certificate Authority?](https://workaround.org/certificate-authority)[](.html)
18
19## Apache
20### Minimal
21```apache
22<VirtualHost *:80>
23 ServerName shaarli.my-domain.org
24 DocumentRoot /absolute/path/to/shaarli/
25</VirtualHost>
26```
27### Debug - Log all the things!
28This configuration will log both Apache and PHP errors, which may prove useful to identify server configuration errors.
29
30See:
31* [Apache/PHP - error log per VirtualHost](http://stackoverflow.com/q/176) (StackOverflow)[](.html)
32* [PHP: php_value vs php_admin_value and the use of php_flag explained](PHP: php_value vs php_admin_value and the use of php_flag explained)[](.html)
33
34```apache
35<VirtualHost *:80>
36 ServerName shaarli.my-domain.org
37 DocumentRoot /absolute/path/to/shaarli/
38
39 LogLevel warn
40 ErrorLog /var/log/apache2/shaarli-error.log
41 CustomLog /var/log/apache2/shaarli-access.log combined
42
43 php_flag log_errors on
44 php_flag display_errors on
45 php_value error_reporting 2147483647
46 php_value error_log /var/log/apache2/shaarli-php-error.log
47</VirtualHost>
48```
49
50### Standard - Keep access and error logs
51```apache
52<VirtualHost *:80>
53 ServerName shaarli.my-domain.org
54 DocumentRoot /absolute/path/to/shaarli/
55
56 LogLevel warn
57 ErrorLog /var/log/apache2/shaarli-error.log
58 CustomLog /var/log/apache2/shaarli-access.log combined
59</VirtualHost>
60```
61
62### Paranoid - Redirect HTTP (:80) to HTTPS (:443)
63See [Server-side TLS](https://wiki.mozilla.org/Security/Server_Side_TLS#Apache) (Mozilla).[](.html)
64
65```apache
66<VirtualHost *:443>
67 ServerName shaarli.my-domain.org
68 DocumentRoot /absolute/path/to/shaarli/
69
70 SSLEngine on
71 SSLCertificateFile /absolute/path/to/the/website/certificate.crt
72 SSLCertificateKeyFile /absolute/path/to/the/website/key.key
73
74 <Directory /absolute/path/to/shaarli/>
75 AllowOverride All
76 Options Indexes FollowSymLinks MultiViews
77 Order allow,deny
78 allow from all
79 </Directory>
80
81 LogLevel warn
82 ErrorLog /var/log/apache2/shaarli-error.log
83 CustomLog /var/log/apache2/shaarli-access.log combined
84</VirtualHost>
85<VirtualHost *:80>
86 ServerName shaarli.my-domain.org
87 Redirect 301 / https://shaarli.my-domain.org
88
89 LogLevel warn
90 ErrorLog /var/log/apache2/shaarli-error.log
91 CustomLog /var/log/apache2/shaarli-access.log combined
92</VirtualHost>
93```
94
95## LightHttpd
96
97## Nginx
98### Foreword
99Nginx does not natively interpret PHP scripts; to this effect, we will run a [FastCGI](https://en.wikipedia.org/wiki/FastCGI) service, to which Nginx's FastCGI module will proxy all requests to PHP resources.[](.html)
100
101Required packages:
102- [nginx](http://nginx.org)[](.html)
103- [php-fpm](http://php-fpm.org) - PHP FastCGI Process Manager[](.html)
104
105Official documentation:
106- [Beginner's guide](http://nginx.org/en/docs/beginners_guide.html)[](.html)
107- [ngx_http_fastcgi_module](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html)[](.html)
108- [Pitfalls](http://wiki.nginx.org/Pitfalls)[](.html)
109
110Community resources:
111- [Server-side TLS (Nginx)](https://wiki.mozilla.org/Security/Server_Side_TLS#Nginx) (Mozilla)[](.html)
112- [PHP configuration examples](http://kbeezie.com/nginx-configuration-examples/) (Karl Blessing)[](.html)
113
114### Common setup
115Once Nginx and PHP-FPM are installed, we need to ensure:
116- Nginx and PHP-FPM are running using the _same user and group_
117- both these user and group have
118 - `read` permissions for Shaarli resources
119 - `execute` permissions for Shaarli directories _AND_ their parent directories
120
121On a production server:
122- `user:group` will likely be `http:http`, `www:www` or `www-data:www-data`
123- files will be located under `/var/www`, `/var/http` or `/usr/share/nginx`
124
125On a development server:
126- files may be located in a user's home directory
127- in this case, make sure both Nginx and PHP-FPM are running as the local user/group!
128
129For all following examples, a development configuration will be used:
130- `user:group = john:users`,
131
132which corresponds to the following service configuration:
133
134```ini
135; /etc/php/php-fpm.conf
136user = john
137group = users
138
139[...][](.html)
140listen.owner = john
141listen.group = users
142```
143
144```nginx
145# /etc/nginx/nginx.conf
146user john users;
147
148http {
149 [...][](.html)
150}
151```
152
153### Minimal
154_WARNING: Use for development only!_
155
156```nginx
157user john users;
158worker_processes 1;
159events {
160 worker_connections 1024;
161}
162
163http {
164 include mime.types;
165 default_type application/octet-stream;
166 keepalive_timeout 20;
167
168 index index.html index.php;
169
170 server {
171 listen 80;
172 server_name localhost;
173 root /home/john/web;
174
175 access_log /var/log/nginx/access.log;
176 error_log /var/log/nginx/error.log;
177
178 location /shaarli/ {
179 access_log /var/log/nginx/shaarli.access.log;
180 error_log /var/log/nginx/shaarli.error.log;
181 }
182
183 location ~ (index)\.php$ {
184 fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
185 fastcgi_index index.php;
186 include fastcgi.conf;
187 }
188 }
189}
190```
191
192### Modular
193The previous setup is sufficient for development purposes, but has several major caveats:
194- every content that does not match the PHP rule will be sent to client browsers:
195 - dotfiles - in our case, `.htaccess`
196 - temporary files, e.g. Vim or Emacs files: `index.php~`
197- asset / static resource caching is not optimized
198- if serving several PHP sites, there will be a lot of duplication: `location /shaarli/`, `location /mysite/`, etc.
199
200To solve this, we will split Nginx configuration in several parts, that will be included when needed:
201
202```nginx
203# /etc/nginx/deny.conf
204location ~ /\. {
205 # deny access to dotfiles
206 access_log off;
207 log_not_found off;
208 deny all;
209}
210
211location ~ ~$ {
212 # deny access to temp editor files, e.g. "script.php~"
213 access_log off;
214 log_not_found off;
215 deny all;
216}
217```
218
219```nginx
220# /etc/nginx/php.conf
221location ~ (index)\.php$ {
222 # proxy PHP requests to PHP-FPM
223 fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
224 fastcgi_index index.php;
225 include fastcgi.conf;
226}
227```
228
229```nginx
230# /etc/nginx/static_assets.conf
231location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
232 expires max;
233 add_header Pragma public;
234 add_header Cache-Control "public, must-revalidate, proxy-revalidate";
235}
236```
237
238```nginx
239# /etc/nginx/nginx.conf
240[...][](.html)
241
242http {
243 [...][](.html)
244
245 root /home/john/web;
246 access_log /var/log/nginx/access.log;
247 error_log /var/log/nginx/error.log;
248
249 server {
250 # virtual host for a first domain
251 listen 80;
252 server_name my.first.domain.org;
253
254 location /shaarli/ {
255 access_log /var/log/nginx/shaarli.access.log;
256 error_log /var/log/nginx/shaarli.error.log;
257 }
258
259 include deny.conf;
260 include static_assets.conf;
261 include php.conf;
262 }
263
264 server {
265 # virtual host for a second domain
266 listen 80;
267 server_name second.domain.com;
268
269 location /minigal/ {
270 access_log /var/log/nginx/minigal.access.log;
271 error_log /var/log/nginx/minigal.error.log;
272 }
273
274 include deny.conf;
275 include static_assets.conf;
276 include php.conf;
277 }
278}
279```
280
281### Redirect HTTP to HTTPS
282Assuming you have generated a (self-signed) key and certificate, and they are located under `/home/john/ssl/localhost.{key,crt}`, it is pretty straightforward to set an HTTP (:80) to HTTPS (:443) redirection to force SSL/TLS usage.
283
284```nginx
285# /etc/nginx/nginx.conf
286[...][](.html)
287
288http {
289 [...][](.html)
290
291 index index.html index.php;
292
293 root /home/john/web;
294 access_log /var/log/nginx/access.log;
295 error_log /var/log/nginx/error.log;
296
297 server {
298 listen 80;
299 server_name localhost;
300
301 return 301 https://localhost$request_uri;
302 }
303
304 server {
305 listen 443 ssl;
306 server_name localhost;
307
308 ssl_certificate /home/john/ssl/localhost.crt;
309 ssl_certificate_key /home/john/ssl/localhost.key;
310
311 location /shaarli/ {
312 access_log /var/log/nginx/shaarli.access.log;
313 error_log /var/log/nginx/shaarli.error.log;
314 }
315
316 include deny.conf;
317 include static_assets.conf;
318 include php.conf;
319 }
320}
321```
diff --git a/doc/Server-requirements.html b/doc/Server-requirements.html
new file mode 100644
index 00000000..bf5a2e8b
--- /dev/null
+++ b/doc/Server-requirements.html
@@ -0,0 +1,132 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Server requirements</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <link rel="stylesheet" href="github-markdown.css">
13</head>
14<body>
15<div id="local-sidebar">
16<ul>
17<li><a href="Home.html">Home</a></li>
18<li>Installation
19<ul>
20<li><a href="Server-requirements.html">Server requirements</a></li>
21<li><a href="Server-configuration.html">Server configuration</a></li>
22<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
23</ul></li>
24<li><a href="Usage.html">Usage</a>
25<ul>
26<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
27<li><a href="Firefox-share.html">Firefox share</a></li>
28<li><a href="RSS-feeds.html">RSS feeds</a></li>
29</ul></li>
30<li>How To
31<ul>
32<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
33<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
34<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
35</ul></li>
36<li><a href="Troubleshooting.html">Troubleshooting</a></li>
37<li><a href="Development.html">Development</a>
38<ul>
39<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
40<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
41<li><a href="Directory-structure.html">Directory structure</a></li>
42<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
43<li><a href="Plugin-System.html">Plugin System</a></li>
44<li><a href="Security.html">Security</a></li>
45<li><a href="Static-analysis.html">Static analysis</a></li>
46<li><a href="Theming.html">Theming</a></li>
47<li><a href="Unit-tests.html">Unit tests</a></li>
48</ul></li>
49<li>About
50<ul>
51<li><a href="FAQ.html">FAQ</a></li>
52<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
53<li><a href="TODO.html">TODO</a></li>
54</ul></li>
55</ul>
56</div>
57<h1 id="server-requirements">Server requirements</h1>
58<h2 id="php">PHP</h2>
59<h3 id="release-information">Release information</h3>
60<ul>
61<li><a href="http://php.net/supported-versions.php">PHP: Supported versions</a><a href=".html"></a></li>
62<li><a href="http://php.net/eol.php">PHP: Unsupported versions</a> <em>(EOL - End Of Life)</em><a href=".html"></a></li>
63<li><a href="http://php.net/ChangeLog-5.php">PHP 5 Changelog</a><a href=".html"></a></li>
64<li><a href="https://bugs.php.net/">PHP: Bugs</a><a href=".html"></a></li>
65</ul>
66<h3 id="supported-versions">Supported versions</h3>
67<table>
68<thead>
69<tr class="header">
70<th style="text-align: center;">Version</th>
71<th style="text-align: center;">Status</th>
72<th style="text-align: center;">Shaarli compatibility</th>
73</tr>
74</thead>
75<tbody>
76<tr class="odd">
77<td style="text-align: center;">5.6</td>
78<td style="text-align: center;">Supported</td>
79<td style="text-align: center;">:white_check_mark:</td>
80</tr>
81<tr class="even">
82<td style="text-align: center;">5.5</td>
83<td style="text-align: center;">Supported</td>
84<td style="text-align: center;">:white_check_mark:</td>
85</tr>
86<tr class="odd">
87<td style="text-align: center;">5.4</td>
88<td style="text-align: center;">Supported</td>
89<td style="text-align: center;">:white_check_mark:</td>
90</tr>
91<tr class="even">
92<td style="text-align: center;">5.3</td>
93<td style="text-align: center;">EOL: 2014-08-14</td>
94<td style="text-align: center;">:white_check_mark:</td>
95</tr>
96</tbody>
97</table>
98<p>See also:</p>
99<ul>
100<li><a href="https://github.com/shaarli/Shaarli/blob/master/.travis.yml">Travis configuration</a><a href=".html"></a></li>
101</ul>
102<p>PHP 7.0 information:</p>
103<ul>
104<li><a href="http://php.net/archive/2015.php#id2015-07-10-4">Beta1 announcement</a><a href=".html"></a></li>
105<li><a href="https://wiki.php.net/todo/php70">TODOLIST</a><a href=".html"></a></li>
106<li><a href="https://bugs.php.net/search.php?limit=30&amp;order_by=id&amp;direction=DESC&amp;cmd=display&amp;status=Open&amp;bug_type=All&amp;phpver=7.0">Recent bugs</a><a href=".html"></a></li>
107<li><a href="http://git.php.net/?p=php-src.git;a=shortlog;h=refs/heads/PHP-7.0.0">Git repository</a><a href=".html"></a></li>
108</ul>
109<h3 id="extensions">Extensions</h3>
110<table>
111<thead>
112<tr class="header">
113<th style="text-align: left;">Extension</th>
114<th style="text-align: center;">Required?</th>
115<th style="text-align: left;">Usage</th>
116</tr>
117</thead>
118<tbody>
119<tr class="odd">
120<td style="text-align: left;"><a href="http://php.net/manual/en/book.mbstring.php"><code>php-mbstring</code></a></td>
121<td style="text-align: center;">CentOS, Fedora, RHEL, Windows</td>
122<td style="text-align: left;">multibyte (Unicode) string support<a href=".html"></a></td>
123</tr>
124<tr class="even">
125<td style="text-align: left;"><a href="http://php.net/manual/en/book.image.php"><code>php-gd</code></a></td>
126<td style="text-align: center;">-</td>
127<td style="text-align: left;">thumbnail resizing<a href=".html"></a></td>
128</tr>
129</tbody>
130</table>
131</body>
132</html>
diff --git a/doc/Server-requirements.md b/doc/Server-requirements.md
new file mode 100644
index 00000000..6ccccaca
--- /dev/null
+++ b/doc/Server-requirements.md
@@ -0,0 +1,30 @@
1#Server requirements
2## PHP
3### Release information
4- [PHP: Supported versions](http://php.net/supported-versions.php)[](.html)
5- [PHP: Unsupported versions](http://php.net/eol.php) _(EOL - End Of Life)_[](.html)
6- [PHP 5 Changelog](http://php.net/ChangeLog-5.php)[](.html)
7- [PHP: Bugs](https://bugs.php.net/)[](.html)
8
9### Supported versions
10Version | Status | Shaarli compatibility
11:---:|:---:|:---:
125.6 | Supported | :white_check_mark:
135.5 | Supported | :white_check_mark:
145.4 | Supported | :white_check_mark:
155.3 | EOL: 2014-08-14 | :white_check_mark:
16
17See also:
18- [Travis configuration](https://github.com/shaarli/Shaarli/blob/master/.travis.yml)[](.html)
19
20PHP 7.0 information:
21- [Beta1 announcement](http://php.net/archive/2015.php#id2015-07-10-4)[](.html)
22- [TODOLIST](https://wiki.php.net/todo/php70)[](.html)
23- [Recent bugs](https://bugs.php.net/search.php?limit=30&order_by=id&direction=DESC&cmd=display&status=Open&bug_type=All&phpver=7.0)[](.html)
24- [Git repository](http://git.php.net/?p=php-src.git;a=shortlog;h=refs/heads/PHP-7.0.0)[](.html)
25
26### Extensions
27Extension | Required? | Usage
28---|:---:|---
29[`php-mbstring`](http://php.net/manual/en/book.mbstring.php) | CentOS, Fedora, RHEL, Windows | multibyte (Unicode) string support[](.html)
30[`php-gd`](http://php.net/manual/en/book.image.php) | - | thumbnail resizing[](.html)
diff --git a/doc/Shaarli-configuration.html b/doc/Shaarli-configuration.html
new file mode 100644
index 00000000..90c09542
--- /dev/null
+++ b/doc/Shaarli-configuration.html
@@ -0,0 +1,221 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Shaarli configuration</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <style type="text/css">
13table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
14 margin: 0; padding: 0; vertical-align: baseline; border: none; }
15table.sourceCode { width: 100%; line-height: 100%; }
16td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
17td.sourceCode { padding-left: 5px; }
18code > span.kw { color: #007020; font-weight: bold; }
19code > span.dt { color: #902000; }
20code > span.dv { color: #40a070; }
21code > span.bn { color: #40a070; }
22code > span.fl { color: #40a070; }
23code > span.ch { color: #4070a0; }
24code > span.st { color: #4070a0; }
25code > span.co { color: #60a0b0; font-style: italic; }
26code > span.ot { color: #007020; }
27code > span.al { color: #ff0000; font-weight: bold; }
28code > span.fu { color: #06287e; }
29code > span.er { color: #ff0000; font-weight: bold; }
30 </style>
31 <link rel="stylesheet" href="github-markdown.css">
32</head>
33<body>
34<div id="local-sidebar">
35<ul>
36<li><a href="Home.html">Home</a></li>
37<li>Installation
38<ul>
39<li><a href="Server-requirements.html">Server requirements</a></li>
40<li><a href="Server-configuration.html">Server configuration</a></li>
41<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
42</ul></li>
43<li><a href="Usage.html">Usage</a>
44<ul>
45<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
46<li><a href="Firefox-share.html">Firefox share</a></li>
47<li><a href="RSS-feeds.html">RSS feeds</a></li>
48</ul></li>
49<li>How To
50<ul>
51<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
52<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
53<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
54</ul></li>
55<li><a href="Troubleshooting.html">Troubleshooting</a></li>
56<li><a href="Development.html">Development</a>
57<ul>
58<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
59<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
60<li><a href="Directory-structure.html">Directory structure</a></li>
61<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
62<li><a href="Plugin-System.html">Plugin System</a></li>
63<li><a href="Security.html">Security</a></li>
64<li><a href="Static-analysis.html">Static analysis</a></li>
65<li><a href="Theming.html">Theming</a></li>
66<li><a href="Unit-tests.html">Unit tests</a></li>
67</ul></li>
68<li>About
69<ul>
70<li><a href="FAQ.html">FAQ</a></li>
71<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
72<li><a href="TODO.html">TODO</a></li>
73</ul></li>
74</ul>
75</div>
76<h1 id="shaarli-configuration">Shaarli configuration</h1>
77<h2 id="foreword">Foreword</h2>
78<p><strong>Do not edit configuration options in index.php! Your changes would be lost.</strong></p>
79<p>Once your Shaarli instance is installed, the file <code>data/config.php</code> is generated:</p>
80<ul>
81<li>it contains all settings, and can be edited to customize values</li>
82<li>its values override those defined in <code>index.php</code></li>
83</ul>
84<h2 id="file-and-directory-permissions">File and directory permissions</h2>
85<p>The server process running Shaarli must have:</p>
86<ul>
87<li><code>read</code> access to the following resources:
88<ul>
89<li>PHP scripts: <code>index.php</code>, <code>application/*.php</code></li>
90<li>3rd party PHP and Javascript libraries: <code>inc/*.php</code>, <code>inc\*.js</code></li>
91<li>static assets:
92<ul>
93<li>CSS stylesheets: <code>inc\*.css</code></li>
94<li><code>images\*</code></li>
95</ul></li>
96<li>RainTPL templates: <code>tpl\*.html</code></li>
97</ul></li>
98<li><code>read</code>, <code>write</code> and <code>execution</code> access to the following directories:
99<ul>
100<li><code>cache</code> - thumbnail cache</li>
101<li><code>data</code> - link data store, configuration options</li>
102<li><code>pagecache</code> - Atom/RSS feed cache</li>
103<li><code>tmp</code> - RainTPL page cache</li>
104</ul></li>
105</ul>
106<p>On a Linux distribution:</p>
107<ul>
108<li>the web server user will likely be <code>www</code> or <code>http</code> (for Apache2)</li>
109<li>it will be a member of a group of the same name: <code>www:www</code>, <code>http:http</code></li>
110<li>to give it access to Shaarli, either:
111<ul>
112<li>unzip Shaarli in the default web server location (usually <code>/var/www/</code>) and set the web server user as the owner</li>
113<li>put users in the same group as the web server, and set the appropriate access rights</li>
114</ul></li>
115<li>if you have a domain / subdomain to serve Shaarli, <a href="Server-configuration">configure the server</a> accordingly<a href=".html"></a></li>
116</ul>
117<h2 id="example-dataconfig.php">Example <code>data/config.php</code></h2>
118<pre class="sourceCode php"><code class="sourceCode php"><span class="kw">&lt;?php</span>
119<span class="co">// User login</span>
120<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;login&#39;</span><span class="ot">]</span> = <span class="st">&#39;&lt;login&gt;&#39;</span><span class="ot">;[](</span>.html<span class="ot">)</span>
121
122<span class="co">// User password hash</span>
123<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;hash&#39;</span><span class="ot">]</span> = <span class="st">&#39;200c452da46c2f889e5e48c49ef044bcacdcb095&#39;</span><span class="ot">;[](</span>.html<span class="ot">)</span>
124
125<span class="co">// Password salt</span>
126<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;salt&#39;</span><span class="ot">]</span> = <span class="st">&#39;13b654102321576033d8473b63a275a1bf94c0f0&#39;</span><span class="ot">;</span> <span class="ot">[](</span>.html<span class="ot">)</span>
127
128<span class="co">// Local timezone</span>
129<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;timezone&#39;</span><span class="ot">]</span> = <span class="st">&#39;Africa/Abidjan&#39;</span><span class="ot">;[](</span>.html<span class="ot">)</span>
130<span class="fu">date_default_timezone_set</span><span class="ot">(</span><span class="st">&#39;Africa/Abidjan&#39;</span><span class="ot">);</span>
131
132<span class="co">// Shaarli title</span>
133<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;title&#39;</span><span class="ot">]</span> = <span class="st">&#39;My Little Shaarly&#39;</span><span class="ot">;[](</span>.html<span class="ot">)</span>
134
135<span class="co">// Link the Shaarli title points to</span>
136<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;titleLink&#39;</span><span class="ot">]</span> = <span class="st">&#39;?&#39;</span><span class="ot">;[](</span>.html<span class="ot">)</span>
137
138<span class="co">// HTTP referer redirector</span>
139<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;redirector&#39;</span><span class="ot">]</span> = <span class="st">&#39;&#39;</span><span class="ot">;[](</span>.html<span class="ot">)</span>
140
141<span class="co">// Disable session hijacking</span>
142<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;disablesessionprotection&#39;</span><span class="ot">]</span> = <span class="kw">false</span><span class="ot">;</span> <span class="ot">[](</span>.html<span class="ot">)</span>
143
144<span class="co">// Whether new links are private by default</span>
145<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;privateLinkByDefault&#39;</span><span class="ot">]</span> = <span class="kw">false</span><span class="ot">;[](</span>.html<span class="ot">)</span>
146
147<span class="co">// Subdirectory where Shaarli stores its data files.</span>
148<span class="co">// You can change it for better security.</span>
149<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;DATADIR&#39;</span><span class="ot">]</span> = <span class="st">&#39;data&#39;</span><span class="ot">;](</span><span class="st">&#39;DATADIR&#39;</span><span class="ot">]</span>-=-<span class="st">&#39;data&#39;</span><span class="ot">;</span>.html<span class="ot">)</span>
150
151<span class="co">// File used to store settings</span>
152<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;CONFIG_FILE&#39;</span><span class="ot">]</span> = <span class="st">&#39;data/config.php&#39;</span><span class="ot">;](</span><span class="st">&#39;CONFIG_FILE&#39;</span><span class="ot">]</span>-=-<span class="st">&#39;data/config.php&#39;</span><span class="ot">;</span>.html<span class="ot">)</span>
153
154<span class="co">// File containing the link database</span>
155<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;DATASTORE&#39;</span><span class="ot">]</span> = <span class="st">&#39;data/datastore.php&#39;</span><span class="ot">;](</span><span class="st">&#39;DATASTORE&#39;</span><span class="ot">]</span>-=-<span class="st">&#39;data/datastore.php&#39;</span><span class="ot">;</span>.html<span class="ot">)</span>
156
157<span class="co">// Number of links displayed per page</span>
158<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;LINKS_PER_PAGE&#39;</span><span class="ot">]</span> = <span class="dv">20</span><span class="ot">;](</span><span class="st">&#39;LINKS_PER_PAGE&#39;</span><span class="ot">]</span>-=-<span class="dv">20</span><span class="ot">;</span>.html<span class="ot">)</span>
159
160<span class="co">// File recording failed login attempts and IP bans</span>
161<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;IPBANS_FILENAME&#39;</span><span class="ot">]</span> = <span class="st">&#39;data/ipbans.php&#39;</span><span class="ot">;](</span><span class="st">&#39;IPBANS_FILENAME&#39;</span><span class="ot">]</span>-=-<span class="st">&#39;data/ipbans.php&#39;</span><span class="ot">;</span>.html<span class="ot">)</span>
162
163<span class="co">// Failed login attempts before being banned</span>
164<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;BAN_AFTER&#39;</span><span class="ot">]</span> = <span class="dv">4</span><span class="ot">;](</span><span class="st">&#39;BAN_AFTER&#39;</span><span class="ot">]</span>-=-<span class="dv">4</span><span class="ot">;</span>.html<span class="ot">)</span>
165
166<span class="co">// Duration of an IP ban, in seconds (30 minutes)</span>
167<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;BAN_DURATION&#39;</span><span class="ot">]</span> = <span class="dv">1800</span><span class="ot">;](</span><span class="st">&#39;BAN_DURATION&#39;</span><span class="ot">]</span>-=-<span class="dv">1800</span><span class="ot">;</span>.html<span class="ot">)</span>
168
169<span class="co">// If set to true, everyone will be able to add, edit and remove links,</span>
170<span class="co">// as well as change configuration</span>
171<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;OPEN_SHAARLI&#39;</span><span class="ot">]</span> = <span class="kw">false</span><span class="ot">;](</span><span class="st">&#39;OPEN_SHAARLI&#39;</span><span class="ot">]</span>-=-<span class="kw">false</span><span class="ot">;</span>.html<span class="ot">)</span>
172
173<span class="co">// Do not show link timestamps</span>
174<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;HIDE_TIMESTAMPS&#39;</span><span class="ot">]</span> = <span class="kw">false</span><span class="ot">;](</span><span class="st">&#39;HIDE_TIMESTAMPS&#39;</span><span class="ot">]</span>-=-<span class="kw">false</span><span class="ot">;</span>.html<span class="ot">)</span>
175
176<span class="co">// Set to false to disable local thumbnail cache, e.g. due to limited disk quotas</span>
177<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;ENABLE_THUMBNAILS&#39;</span><span class="ot">]</span> = <span class="kw">true</span><span class="ot">;](</span><span class="st">&#39;ENABLE_THUMBNAILS&#39;</span><span class="ot">]</span>-=-<span class="kw">true</span><span class="ot">;</span>.html<span class="ot">)</span>
178
179<span class="co">// Thumbnail cache directory</span>
180<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;CACHEDIR&#39;</span><span class="ot">]</span> = <span class="st">&#39;cache&#39;</span><span class="ot">;](</span><span class="st">&#39;CACHEDIR&#39;</span><span class="ot">]</span>-=-<span class="st">&#39;cache&#39;</span><span class="ot">;</span>.html<span class="ot">)</span>
181
182<span class="co">// Enable feed (rss, atom, dailyrss) cache</span>
183<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;ENABLE_LOCALCACHE&#39;</span><span class="ot">]</span> = <span class="kw">true</span><span class="ot">;](</span><span class="st">&#39;ENABLE_LOCALCACHE&#39;</span><span class="ot">]</span>-=-<span class="kw">true</span><span class="ot">;</span>.html<span class="ot">)</span>
184
185<span class="co">// Feed cache directory</span>
186<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;PAGECACHE&#39;</span><span class="ot">]</span> = <span class="st">&#39;pagecache&#39;</span><span class="ot">;](</span><span class="st">&#39;PAGECACHE&#39;</span><span class="ot">]</span>-=-<span class="st">&#39;pagecache&#39;</span><span class="ot">;</span>.html<span class="ot">)</span>
187
188<span class="co">// RainTPL cache directory (keep the trailing slash!)</span>
189<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;RAINTPL_TMP&#39;</span><span class="ot">]</span> = <span class="st">&#39;tmp/&#39;</span><span class="ot">;](</span><span class="st">&#39;RAINTPL_TMP&#39;</span><span class="ot">]</span>-=-<span class="st">&#39;tmp/&#39;</span><span class="ot">;</span>.html<span class="ot">)</span>
190
191<span class="co">// RainTPL template directory (keep the trailing slash!)</span>
192<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;RAINTPL_TPL&#39;</span><span class="ot">]</span> = <span class="st">&#39;tpl/&#39;</span><span class="ot">;](</span><span class="st">&#39;RAINTPL_TPL&#39;</span><span class="ot">]</span>-=-<span class="st">&#39;tpl/&#39;</span><span class="ot">;</span>.html<span class="ot">)</span>
193
194<span class="co">// Whether Shaarli checks for new releases at https://github.com/shaarli/Shaarli</span>
195<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;ENABLE_UPDATECHECK&#39;</span><span class="ot">]</span> = <span class="kw">true</span><span class="ot">;](</span><span class="st">&#39;ENABLE_UPDATECHECK&#39;</span><span class="ot">]</span>-=-<span class="kw">true</span><span class="ot">;</span>.html<span class="ot">)</span>
196
197<span class="co">// File to store the latest Shaarli version</span>
198<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;UPDATECHECK_FILENAME&#39;</span><span class="ot">]</span> = <span class="st">&#39;data/lastupdatecheck.txt&#39;</span><span class="ot">;](</span><span class="st">&#39;UPDATECHECK_FILENAME&#39;</span><span class="ot">]</span>-=-<span class="st">&#39;data/lastupdatecheck.txt&#39;</span><span class="ot">;</span>.html<span class="ot">)</span>
199
200<span class="co">// Delay between version checks (requires to be logged in) (24 hours)</span>
201<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;UPDATECHECK_INTERVAL&#39;</span><span class="ot">]</span> = <span class="dv">86400</span><span class="ot">;](</span><span class="st">&#39;UPDATECHECK_INTERVAL&#39;</span><span class="ot">]</span>-=-<span class="dv">86400</span><span class="ot">;</span>.html<span class="ot">)</span>
202
203<span class="co">// For each link, display a link to an archived version on archive.org</span>
204<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;ARCHIVE_ORG&#39;</span><span class="ot">]</span> = <span class="kw">false</span><span class="ot">;](</span><span class="st">&#39;ARCHIVE_ORG&#39;</span><span class="ot">]</span>-=-<span class="kw">false</span><span class="ot">;</span>.html<span class="ot">)</span>
205
206<span class="co">// The RSS item links point:</span>
207<span class="co">// true =&gt; directly to the link</span>
208<span class="co">// false =&gt; to the entry on Shaarli (permalink)</span>
209<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;ENABLE_RSS_PERMALINKS&#39;</span><span class="ot">]</span> = <span class="kw">true</span><span class="ot">;](</span><span class="st">&#39;ENABLE_RSS_PERMALINKS&#39;</span><span class="ot">]</span>-=-<span class="kw">true</span><span class="ot">;</span>.html<span class="ot">)</span>
210
211<span class="co">// Hide all links to non-logged users</span>
212<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;HIDE_PUBLIC_LINKS&#39;</span><span class="ot">]</span> = <span class="kw">false</span><span class="ot">;](</span><span class="st">&#39;HIDE_PUBLIC_LINKS&#39;</span><span class="ot">]</span>-=-<span class="kw">false</span><span class="ot">;</span>.html<span class="ot">)</span>
213
214<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;PUBSUBHUB_URL&#39;</span><span class="ot">]</span> = <span class="st">&#39;&#39;</span><span class="ot">;](</span><span class="st">&#39;PUBSUBHUB_URL&#39;</span><span class="ot">]</span>-=-<span class="st">&#39;&#39;</span><span class="ot">;</span>.html<span class="ot">)</span>
215
216<span class="co">// Show an ATOM Feed button next to the Subscribe (RSS) button.</span>
217<span class="co">// ATOM feeds are available at the address ?do=atom regardless of this option.</span>
218<span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;SHOW_ATOM&#39;</span><span class="ot">]</span> = <span class="kw">false</span><span class="ot">;](</span><span class="st">&#39;SHOW_ATOM&#39;</span><span class="ot">]</span>-=-<span class="kw">false</span><span class="ot">;</span>.html<span class="ot">)</span>
219<span class="kw">?&gt;</span></code></pre>
220</body>
221</html>
diff --git a/doc/Shaarli-configuration.md b/doc/Shaarli-configuration.md
new file mode 100644
index 00000000..5bf70a62
--- /dev/null
+++ b/doc/Shaarli-configuration.md
@@ -0,0 +1,137 @@
1#Shaarli configuration
2## Foreword
3
4**Do not edit configuration options in index.php! Your changes would be lost.**
5
6Once your Shaarli instance is installed, the file `data/config.php` is generated:
7* it contains all settings, and can be edited to customize values
8* its values override those defined in `index.php`
9
10## File and directory permissions
11The server process running Shaarli must have:
12- `read` access to the following resources:
13 - PHP scripts: `index.php`, `application/*.php`
14 - 3rd party PHP and Javascript libraries: `inc/*.php`, `inc\*.js`
15 - static assets:
16 - CSS stylesheets: `inc\*.css`
17 - `images\*`
18 - RainTPL templates: `tpl\*.html`
19- `read`, `write` and `execution` access to the following directories:
20 - `cache` - thumbnail cache
21 - `data` - link data store, configuration options
22 - `pagecache` - Atom/RSS feed cache
23 - `tmp` - RainTPL page cache
24
25On a Linux distribution:
26- the web server user will likely be `www` or `http` (for Apache2)
27- it will be a member of a group of the same name: `www:www`, `http:http`
28- to give it access to Shaarli, either:
29 - unzip Shaarli in the default web server location (usually `/var/www/`) and set the web server user as the owner
30 - put users in the same group as the web server, and set the appropriate access rights
31- if you have a domain / subdomain to serve Shaarli, [configure the server](Server-configuration) accordingly[](.html)
32
33## Example `data/config.php`
34```php
35<?php
36// User login
37$GLOBALS['login'] = '<login>';[](.html)
38
39// User password hash
40$GLOBALS['hash'] = '200c452da46c2f889e5e48c49ef044bcacdcb095';[](.html)
41
42// Password salt
43$GLOBALS['salt'] = '13b654102321576033d8473b63a275a1bf94c0f0'; [](.html)
44
45// Local timezone
46$GLOBALS['timezone'] = 'Africa/Abidjan';[](.html)
47date_default_timezone_set('Africa/Abidjan');
48
49// Shaarli title
50$GLOBALS['title'] = 'My Little Shaarly';[](.html)
51
52// Link the Shaarli title points to
53$GLOBALS['titleLink'] = '?';[](.html)
54
55// HTTP referer redirector
56$GLOBALS['redirector'] = '';[](.html)
57
58// Disable session hijacking
59$GLOBALS['disablesessionprotection'] = false; [](.html)
60
61// Whether new links are private by default
62$GLOBALS['privateLinkByDefault'] = false;[](.html)
63
64// Subdirectory where Shaarli stores its data files.
65// You can change it for better security.
66$GLOBALS['config'['DATADIR'] = 'data';]('DATADIR']-=-'data';.html)
67
68// File used to store settings
69$GLOBALS['config'['CONFIG_FILE'] = 'data/config.php';]('CONFIG_FILE']-=-'data/config.php';.html)
70
71// File containing the link database
72$GLOBALS['config'['DATASTORE'] = 'data/datastore.php';]('DATASTORE']-=-'data/datastore.php';.html)
73
74// Number of links displayed per page
75$GLOBALS['config'['LINKS_PER_PAGE'] = 20;]('LINKS_PER_PAGE']-=-20;.html)
76
77// File recording failed login attempts and IP bans
78$GLOBALS['config'['IPBANS_FILENAME'] = 'data/ipbans.php';]('IPBANS_FILENAME']-=-'data/ipbans.php';.html)
79
80// Failed login attempts before being banned
81$GLOBALS['config'['BAN_AFTER'] = 4;]('BAN_AFTER']-=-4;.html)
82
83// Duration of an IP ban, in seconds (30 minutes)
84$GLOBALS['config'['BAN_DURATION'] = 1800;]('BAN_DURATION']-=-1800;.html)
85
86// If set to true, everyone will be able to add, edit and remove links,
87// as well as change configuration
88$GLOBALS['config'['OPEN_SHAARLI'] = false;]('OPEN_SHAARLI']-=-false;.html)
89
90// Do not show link timestamps
91$GLOBALS['config'['HIDE_TIMESTAMPS'] = false;]('HIDE_TIMESTAMPS']-=-false;.html)
92
93// Set to false to disable local thumbnail cache, e.g. due to limited disk quotas
94$GLOBALS['config'['ENABLE_THUMBNAILS'] = true;]('ENABLE_THUMBNAILS']-=-true;.html)
95
96// Thumbnail cache directory
97$GLOBALS['config'['CACHEDIR'] = 'cache';]('CACHEDIR']-=-'cache';.html)
98
99// Enable feed (rss, atom, dailyrss) cache
100$GLOBALS['config'['ENABLE_LOCALCACHE'] = true;]('ENABLE_LOCALCACHE']-=-true;.html)
101
102// Feed cache directory
103$GLOBALS['config'['PAGECACHE'] = 'pagecache';]('PAGECACHE']-=-'pagecache';.html)
104
105// RainTPL cache directory (keep the trailing slash!)
106$GLOBALS['config'['RAINTPL_TMP'] = 'tmp/';]('RAINTPL_TMP']-=-'tmp/';.html)
107
108// RainTPL template directory (keep the trailing slash!)
109$GLOBALS['config'['RAINTPL_TPL'] = 'tpl/';]('RAINTPL_TPL']-=-'tpl/';.html)
110
111// Whether Shaarli checks for new releases at https://github.com/shaarli/Shaarli
112$GLOBALS['config'['ENABLE_UPDATECHECK'] = true;]('ENABLE_UPDATECHECK']-=-true;.html)
113
114// File to store the latest Shaarli version
115$GLOBALS['config'['UPDATECHECK_FILENAME'] = 'data/lastupdatecheck.txt';]('UPDATECHECK_FILENAME']-=-'data/lastupdatecheck.txt';.html)
116
117// Delay between version checks (requires to be logged in) (24 hours)
118$GLOBALS['config'['UPDATECHECK_INTERVAL'] = 86400;]('UPDATECHECK_INTERVAL']-=-86400;.html)
119
120// For each link, display a link to an archived version on archive.org
121$GLOBALS['config'['ARCHIVE_ORG'] = false;]('ARCHIVE_ORG']-=-false;.html)
122
123// The RSS item links point:
124// true => directly to the link
125// false => to the entry on Shaarli (permalink)
126$GLOBALS['config'['ENABLE_RSS_PERMALINKS'] = true;]('ENABLE_RSS_PERMALINKS']-=-true;.html)
127
128// Hide all links to non-logged users
129$GLOBALS['config'['HIDE_PUBLIC_LINKS'] = false;]('HIDE_PUBLIC_LINKS']-=-false;.html)
130
131$GLOBALS['config'['PUBSUBHUB_URL'] = '';]('PUBSUBHUB_URL']-=-'';.html)
132
133// Show an ATOM Feed button next to the Subscribe (RSS) button.
134// ATOM feeds are available at the address ?do=atom regardless of this option.
135$GLOBALS['config'['SHOW_ATOM'] = false;]('SHOW_ATOM']-=-false;.html)
136?>
137```
diff --git a/doc/Sharing-button.html b/doc/Sharing-button.html
new file mode 100644
index 00000000..034f2f9c
--- /dev/null
+++ b/doc/Sharing-button.html
@@ -0,0 +1,76 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Sharing button</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <link rel="stylesheet" href="github-markdown.css">
13</head>
14<body>
15<div id="local-sidebar">
16<ul>
17<li><a href="Home.html">Home</a></li>
18<li>Installation
19<ul>
20<li><a href="Server-requirements.html">Server requirements</a></li>
21<li><a href="Server-configuration.html">Server configuration</a></li>
22<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
23</ul></li>
24<li><a href="Usage.html">Usage</a>
25<ul>
26<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
27<li><a href="Firefox-share.html">Firefox share</a></li>
28<li><a href="RSS-feeds.html">RSS feeds</a></li>
29</ul></li>
30<li>How To
31<ul>
32<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
33<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
34<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
35</ul></li>
36<li><a href="Troubleshooting.html">Troubleshooting</a></li>
37<li><a href="Development.html">Development</a>
38<ul>
39<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
40<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
41<li><a href="Directory-structure.html">Directory structure</a></li>
42<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
43<li><a href="Plugin-System.html">Plugin System</a></li>
44<li><a href="Security.html">Security</a></li>
45<li><a href="Static-analysis.html">Static analysis</a></li>
46<li><a href="Theming.html">Theming</a></li>
47<li><a href="Unit-tests.html">Unit tests</a></li>
48</ul></li>
49<li>About
50<ul>
51<li><a href="FAQ.html">FAQ</a></li>
52<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
53<li><a href="TODO.html">TODO</a></li>
54</ul></li>
55</ul>
56</div>
57<h1 id="sharing-button">Sharing button</h1>
58<h3 id="add-the-sharing-button-bookmarklet-to-your-browser">Add the sharing button (<em>bookmarklet</em>) to your browser</h3>
59<ul>
60<li>Open your Shaarli and <code>Login</code></li>
61<li>Click the <code>Tools</code> button in the top bar</li>
62<li>Drag the <strong><code>✚Shaare link</code> button</strong>, and drop it to your browser's bookmarks bar.</li>
63</ul>
64<p><em>This bookmarklet button is compatible with Firefox, Opera, Chrome and Safari. Under Opera, you can't drag'n drop the button: You have to right-click on it and add a bookmark to your personal toolbar.</em></p>
65<p><embed src="(images/bookmarklet.png).html" /></p>
66<h3 id="share-links-using-the-bookmarklet">Share links using the <em>bookmarklet</em></h3>
67<ul>
68<li>When you are visiting a webpage you would like to share with Shaarli, click the <em>bookmarklet</em> you just added.</li>
69<li>A window opens.</li>
70<li>You can freely edit title, description, tags... to find it later using the text search or tag filtering.</li>
71<li>You will be able to edit this link later using the <embed src="(https://raw.githubusercontent.com/shaarli/Shaarli/master/images/edit_icon.png)-edit-button..html" /></li>
72<li>You can also check the “Private” box so that the link is saved but only visible to you.</li>
73<li>Click <code>Save</code>.<strong>Voilà! Your link is now shared.</strong></li>
74</ul>
75</body>
76</html>
diff --git a/doc/Sharing-button.md b/doc/Sharing-button.md
new file mode 100644
index 00000000..fe576a77
--- /dev/null
+++ b/doc/Sharing-button.md
@@ -0,0 +1,19 @@
1#Sharing button
2### Add the sharing button (_bookmarklet_) to your browser
3
4 * Open your Shaarli and `Login`
5 * Click the `Tools` button in the top bar
6 * Drag the **`✚Shaare link` button**, and drop it to your browser's bookmarks bar.
7
8_This bookmarklet button is compatible with Firefox, Opera, Chrome and Safari. Under Opera, you can't drag'n drop the button: You have to right-click on it and add a bookmark to your personal toolbar._
9
10![(images/bookmarklet.png)]((images/bookmarklet.png).html)
11
12### Share links using the _bookmarklet_
13
14 * When you are visiting a webpage you would like to share with Shaarli, click the _bookmarklet_ you just added.
15 * A window opens.
16 * You can freely edit title, description, tags... to find it later using the text search or tag filtering.
17 * You will be able to edit this link later using the ![(https://raw.githubusercontent.com/shaarli/Shaarli/master/images/edit_icon.png) edit button.]((https://raw.githubusercontent.com/shaarli/Shaarli/master/images/edit_icon.png)-edit-button..html)
18 * You can also check the “Private” box so that the link is saved but only visible to you.
19 * Click `Save`.**Voilà! Your link is now shared.**
diff --git a/doc/Static-analysis.html b/doc/Static-analysis.html
new file mode 100644
index 00000000..d4588e4d
--- /dev/null
+++ b/doc/Static-analysis.html
@@ -0,0 +1,72 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Static analysis</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <link rel="stylesheet" href="github-markdown.css">
13</head>
14<body>
15<div id="local-sidebar">
16<ul>
17<li><a href="Home.html">Home</a></li>
18<li>Installation
19<ul>
20<li><a href="Server-requirements.html">Server requirements</a></li>
21<li><a href="Server-configuration.html">Server configuration</a></li>
22<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
23</ul></li>
24<li><a href="Usage.html">Usage</a>
25<ul>
26<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
27<li><a href="Firefox-share.html">Firefox share</a></li>
28<li><a href="RSS-feeds.html">RSS feeds</a></li>
29</ul></li>
30<li>How To
31<ul>
32<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
33<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
34<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
35</ul></li>
36<li><a href="Troubleshooting.html">Troubleshooting</a></li>
37<li><a href="Development.html">Development</a>
38<ul>
39<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
40<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
41<li><a href="Directory-structure.html">Directory structure</a></li>
42<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
43<li><a href="Plugin-System.html">Plugin System</a></li>
44<li><a href="Security.html">Security</a></li>
45<li><a href="Static-analysis.html">Static analysis</a></li>
46<li><a href="Theming.html">Theming</a></li>
47<li><a href="Unit-tests.html">Unit tests</a></li>
48</ul></li>
49<li>About
50<ul>
51<li><a href="FAQ.html">FAQ</a></li>
52<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
53<li><a href="TODO.html">TODO</a></li>
54</ul></li>
55</ul>
56</div>
57<h1 id="static-analysis">Static analysis</h1>
58<h2 id="wip">WIP</h2>
59<p>This topic is currently being discussed here:</p>
60<ul>
61<li><a href="https://github.com/shaarli/Shaarli/issues/95">Fix coding style (static analysis)</a> (#95)<a href=".html"></a></li>
62<li><a href="https://github.com/shaarli/Shaarli/issues/130">Continuous Integration tools &amp; features</a> (#130)<a href=".html"></a></li>
63</ul>
64<h3 id="usage">Usage</h3>
65<p>Static analysis tools can be installed with Composer, and used through Shaarli's <a href="https://github.com/shaarli/Shaarli/blob/master/Makefile">Makefile</a>.<a href=".html"></a></p>
66<p>For an overview of the available features, see:</p>
67<ul>
68<li><a href="https://github.com/shaarli/Shaarli/pull/124">Code quality: Makefile to run static code checkers</a> (#124)<a href=".html"></a></li>
69<li><a href="https://github.com/shaarli/Shaarli/pull/276">Run PHPCS against different coding standards</a> (#276)<a href=".html"></a></li>
70</ul>
71</body>
72</html>
diff --git a/doc/Static-analysis.md b/doc/Static-analysis.md
new file mode 100644
index 00000000..5781e055
--- /dev/null
+++ b/doc/Static-analysis.md
@@ -0,0 +1,12 @@
1#Static analysis
2## WIP
3This topic is currently being discussed here:
4- [Fix coding style (static analysis)](https://github.com/shaarli/Shaarli/issues/95) (#95)[](.html)
5- [Continuous Integration tools & features](https://github.com/shaarli/Shaarli/issues/130) (#130)[](.html)
6
7### Usage
8Static analysis tools can be installed with Composer, and used through Shaarli's [Makefile](https://github.com/shaarli/Shaarli/blob/master/Makefile).[](.html)
9
10For an overview of the available features, see:
11- [Code quality: Makefile to run static code checkers](https://github.com/shaarli/Shaarli/pull/124) (#124)[](.html)
12- [Run PHPCS against different coding standards](https://github.com/shaarli/Shaarli/pull/276) (#276)[](.html)
diff --git a/doc/TODO.html b/doc/TODO.html
new file mode 100644
index 00000000..f66d64f2
--- /dev/null
+++ b/doc/TODO.html
@@ -0,0 +1,64 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - TODO</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <link rel="stylesheet" href="github-markdown.css">
13</head>
14<body>
15<div id="local-sidebar">
16<ul>
17<li><a href="Home.html">Home</a></li>
18<li>Installation
19<ul>
20<li><a href="Server-requirements.html">Server requirements</a></li>
21<li><a href="Server-configuration.html">Server configuration</a></li>
22<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
23</ul></li>
24<li><a href="Usage.html">Usage</a>
25<ul>
26<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
27<li><a href="Firefox-share.html">Firefox share</a></li>
28<li><a href="RSS-feeds.html">RSS feeds</a></li>
29</ul></li>
30<li>How To
31<ul>
32<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
33<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
34<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
35</ul></li>
36<li><a href="Troubleshooting.html">Troubleshooting</a></li>
37<li><a href="Development.html">Development</a>
38<ul>
39<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
40<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
41<li><a href="Directory-structure.html">Directory structure</a></li>
42<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
43<li><a href="Plugin-System.html">Plugin System</a></li>
44<li><a href="Security.html">Security</a></li>
45<li><a href="Static-analysis.html">Static analysis</a></li>
46<li><a href="Theming.html">Theming</a></li>
47<li><a href="Unit-tests.html">Unit tests</a></li>
48</ul></li>
49<li>About
50<ul>
51<li><a href="FAQ.html">FAQ</a></li>
52<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
53<li><a href="TODO.html">TODO</a></li>
54</ul></li>
55</ul>
56</div>
57<h1 id="todo">TODO</h1>
58<ul>
59<li>add more screenshots</li>
60<li>improve developer documentation: storage architecture, classes and functions, security handling...</li>
61<li>add server configuration examples: lighthttpd</li>
62</ul>
63</body>
64</html>
diff --git a/doc/TODO.md b/doc/TODO.md
new file mode 100644
index 00000000..fb72fd57
--- /dev/null
+++ b/doc/TODO.md
@@ -0,0 +1,4 @@
1#TODO
2* add more screenshots
3* improve developer documentation: storage architecture, classes and functions, security handling...
4* add server configuration examples: lighthttpd
diff --git a/doc/Theming.html b/doc/Theming.html
new file mode 100644
index 00000000..e814dadf
--- /dev/null
+++ b/doc/Theming.html
@@ -0,0 +1,138 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Theming</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <style type="text/css">
13table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
14 margin: 0; padding: 0; vertical-align: baseline; border: none; }
15table.sourceCode { width: 100%; line-height: 100%; }
16td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
17td.sourceCode { padding-left: 5px; }
18code > span.kw { color: #007020; font-weight: bold; }
19code > span.dt { color: #902000; }
20code > span.dv { color: #40a070; }
21code > span.bn { color: #40a070; }
22code > span.fl { color: #40a070; }
23code > span.ch { color: #4070a0; }
24code > span.st { color: #4070a0; }
25code > span.co { color: #60a0b0; font-style: italic; }
26code > span.ot { color: #007020; }
27code > span.al { color: #ff0000; font-weight: bold; }
28code > span.fu { color: #06287e; }
29code > span.er { color: #ff0000; font-weight: bold; }
30 </style>
31 <link rel="stylesheet" href="github-markdown.css">
32</head>
33<body>
34<div id="local-sidebar">
35<ul>
36<li><a href="Home.html">Home</a></li>
37<li>Installation
38<ul>
39<li><a href="Server-requirements.html">Server requirements</a></li>
40<li><a href="Server-configuration.html">Server configuration</a></li>
41<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
42</ul></li>
43<li><a href="Usage.html">Usage</a>
44<ul>
45<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
46<li><a href="Firefox-share.html">Firefox share</a></li>
47<li><a href="RSS-feeds.html">RSS feeds</a></li>
48</ul></li>
49<li>How To
50<ul>
51<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
52<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
53<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
54</ul></li>
55<li><a href="Troubleshooting.html">Troubleshooting</a></li>
56<li><a href="Development.html">Development</a>
57<ul>
58<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
59<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
60<li><a href="Directory-structure.html">Directory structure</a></li>
61<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
62<li><a href="Plugin-System.html">Plugin System</a></li>
63<li><a href="Security.html">Security</a></li>
64<li><a href="Static-analysis.html">Static analysis</a></li>
65<li><a href="Theming.html">Theming</a></li>
66<li><a href="Unit-tests.html">Unit tests</a></li>
67</ul></li>
68<li>About
69<ul>
70<li><a href="FAQ.html">FAQ</a></li>
71<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
72<li><a href="TODO.html">TODO</a></li>
73</ul></li>
74</ul>
75</div>
76<h1 id="theming">Theming</h1>
77<h2 id="user-css">User CSS</h2>
78<ul>
79<li>Shaarli's apparence can be modified by editing CSS rules in <code>inc/user.css</code>. This file allows to override rules defined in the main <code>inc/shaarli.css</code> (only add changed rules), or define a whole new theme.</li>
80<li>Do not edit <code>inc/shaarli.css</code>! Your changes would be overriden when updating Shaarli.</li>
81<li>Some themes are available at <a href="https://github.com/shaarli/shaarli-themes" class="uri">https://github.com/shaarli/shaarli-themes</a>.</li>
82</ul>
83<p>See also:</p>
84<ul>
85<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
86</ul>
87<h2 id="raintpl-template">RainTPL template</h2>
88<p><em>WARNING - This feature is currently being worked on and will be improved in the next releases. Experimental.</em></p>
89<ul>
90<li>Find the template you'd like to install (see the list of <a href="available-templates|Theming#community-themes--templates.html">available templates|Theming#community-themes--templates</a>)</li>
91<li>Find it's git clone URL or download the zip archive for the template.</li>
92<li>In your Shaarli <code>tpl/</code> directory, run <code>git clone https://url/of/my-template/</code> or unpack the zip archive.
93<ul>
94<li>There should now be a <code>my-template/</code> directory under the <code>tpl/</code> dir, containing directly all the template files.</li>
95</ul></li>
96<li><p>Edit <code>data/config.php</code> to have Shaarli use this template, e.g.</p>
97<pre class="sourceCode php"><code class="sourceCode php"><span class="kw">$GLOBALS</span><span class="ot">[</span><span class="st">&#39;config&#39;</span><span class="ot">[</span><span class="st">&#39;RAINTPL_TPL&#39;</span><span class="ot">]</span> = <span class="st">&#39;tpl/my-template/&#39;</span><span class="ot">;](</span><span class="st">&#39;RAINTPL_TPL&#39;</span><span class="ot">]</span>-=-<span class="st">&#39;tpl/my-template/&#39;</span><span class="ot">;</span>.html<span class="ot">)</span></code></pre></li>
98</ul>
99<h2 id="community-themes-templates">Community themes &amp; templates</h2>
100<ul>
101<li><a href="https://github.com/AkibaTech/Shaarli---SuperHero-Theme">AkibaTech/Shaarli Superhero Theme</a> - A template/theme for Shaarli<a href=".html"></a></li>
102<li><a href="https://github.com/alexisju/albinomouse-template">alexisju/albinomouse-template</a> - A full template for Shaarli<a href=".html"></a></li>
103<li><a href="https://github.com/dhoko/ShaarliTemplate">dhoko/ShaarliTemplate</a> - A template/theme for Shaarli<a href=".html"></a></li>
104<li><a href="https://github.com/kalvn/shaarli-blocks">kalvn/shaarli-blocks</a> - A template/theme for Shaarli<a href=".html"></a></li>
105<li><a href="https://github.com/kalvn/Shaarli-Material">kalvn/Shaarli-Material</a> - A theme (template) based on Google's Material Design for Shaarli, the superfast delicious clone.<a href=".html"></a></li>
106<li><a href="https://github.com/misterair/limonade">misterair/Limonade</a> - A fork of (legacy) Shaarli with a new template<a href=".html"></a></li>
107<li><a href="https://github.com/Vinm/Blue-theme-for-Shaarli">Vinm/Blue-theme-for Shaarli</a> - A template/theme for Shaarli (<a href="https://github.com/Vinm/Blue-theme-for-Shaarli/issues/2">unmaintained</a>, compatibility unknown)<a href=".html"></a></li>
108<li><a href="https://github.com/vivienhaese/shaarlitheme">vivienhaese/shaarlitheme</a> - A Shaarli fork meant to be run in an openshift instance<a href=".html"></a></li>
109</ul>
110<h3 id="example-installation-albinomouse-template">Example installation: AlbinoMouse template</h3>
111<p>With the following configuration:</p>
112<ul>
113<li>Apache 2 / PHP 5.6</li>
114<li>user sites are enabled, e.g. <code>/home/user/public_html/somedir</code> is served as <code>http://localhost/~user/somedir</code></li>
115<li><code>http</code> is the name of the Apache user</li>
116</ul>
117<pre class="sourceCode bash"><code class="sourceCode bash">$ <span class="kw">cd</span> ~/public_html
118
119<span class="co"># clone repositories</span>
120$ <span class="kw">git</span> clone https://github.com/shaarli/Shaarli.git shaarli
121$ <span class="kw">pushd</span> shaarli/tpl
122$ <span class="kw">git</span> clone https://github.com/alexisju/albinomouse-template.git
123$ <span class="kw">popd</span>
124
125<span class="co"># set access rights for Apache</span>
126$ <span class="kw">chgrp</span> -R http shaarli
127$ <span class="kw">chmod</span> g+rwx shaarli shaarli/cache shaarli/data shaarli/pagecache shaarli/tmp</code></pre>
128<p>Get config written:</p>
129<ul>
130<li>go to the freshly installed site</li>
131<li>fill the install form</li>
132<li>log in to Shaarli</li>
133</ul>
134<p>Edit Shaarli's <a href="configuration|Shaarli-configuration.html">configuration|Shaarli configuration</a>:</p>
135<pre class="sourceCode bash"><code class="sourceCode bash"><span class="co"># the file should be owned by Apache, thus not writeable =&gt; sudo</span>
136$ <span class="kw">sudo</span> sed -i s=tpl=tpl/albinomouse-template=g shaarli/data/config.php</code></pre>
137</body>
138</html>
diff --git a/doc/Theming.md b/doc/Theming.md
new file mode 100644
index 00000000..9dfdcf9f
--- /dev/null
+++ b/doc/Theming.md
@@ -0,0 +1,63 @@
1#Theming
2## User CSS
3
4- Shaarli's apparence can be modified by editing CSS rules in `inc/user.css`. This file allows to override rules defined in the main `inc/shaarli.css` (only add changed rules), or define a whole new theme.
5- Do not edit `inc/shaarli.css`! Your changes would be overriden when updating Shaarli.
6- Some themes are available at https://github.com/shaarli/shaarli-themes.
7
8See also:
9- [Download CSS styles from an OPML list](Download-CSS-styles-from-an-OPML-list.html)
10
11## RainTPL template
12
13_WARNING - This feature is currently being worked on and will be improved in the next releases. Experimental._
14
15- Find the template you'd like to install (see the list of [available templates|Theming#community-themes--templates](available-templates|Theming#community-themes--templates.html))
16- Find it's git clone URL or download the zip archive for the template.
17- In your Shaarli `tpl/` directory, run `git clone https://url/of/my-template/` or unpack the zip archive.
18 - There should now be a `my-template/` directory under the `tpl/` dir, containing directly all the template files.
19- Edit `data/config.php` to have Shaarli use this template, e.g.
20```php
21$GLOBALS['config'['RAINTPL_TPL'] = 'tpl/my-template/';]('RAINTPL_TPL']-=-'tpl/my-template/';.html)
22```
23
24## Community themes & templates
25- [AkibaTech/Shaarli Superhero Theme](https://github.com/AkibaTech/Shaarli---SuperHero-Theme) - A template/theme for Shaarli[](.html)
26- [alexisju/albinomouse-template](https://github.com/alexisju/albinomouse-template) - A full template for Shaarli[](.html)
27- [dhoko/ShaarliTemplate](https://github.com/dhoko/ShaarliTemplate) - A template/theme for Shaarli[](.html)
28- [kalvn/shaarli-blocks](https://github.com/kalvn/shaarli-blocks) - A template/theme for Shaarli[](.html)
29- [kalvn/Shaarli-Material](https://github.com/kalvn/Shaarli-Material) - A theme (template) based on Google's Material Design for Shaarli, the superfast delicious clone.[](.html)
30- [misterair/Limonade](https://github.com/misterair/limonade) - A fork of (legacy) Shaarli with a new template[](.html)
31- [Vinm/Blue-theme-for Shaarli](https://github.com/Vinm/Blue-theme-for-Shaarli) - A template/theme for Shaarli ([unmaintained](https://github.com/Vinm/Blue-theme-for-Shaarli/issues/2), compatibility unknown)[](.html)
32- [vivienhaese/shaarlitheme](https://github.com/vivienhaese/shaarlitheme) - A Shaarli fork meant to be run in an openshift instance[](.html)
33
34### Example installation: AlbinoMouse template
35With the following configuration:
36- Apache 2 / PHP 5.6
37- user sites are enabled, e.g. `/home/user/public_html/somedir` is served as `http://localhost/~user/somedir`
38- `http` is the name of the Apache user
39
40```bash
41$ cd ~/public_html
42
43# clone repositories
44$ git clone https://github.com/shaarli/Shaarli.git shaarli
45$ pushd shaarli/tpl
46$ git clone https://github.com/alexisju/albinomouse-template.git
47$ popd
48
49# set access rights for Apache
50$ chgrp -R http shaarli
51$ chmod g+rwx shaarli shaarli/cache shaarli/data shaarli/pagecache shaarli/tmp
52```
53
54Get config written:
55- go to the freshly installed site
56- fill the install form
57- log in to Shaarli
58
59Edit Shaarli's [configuration|Shaarli configuration](configuration|Shaarli-configuration.html):
60```bash
61# the file should be owned by Apache, thus not writeable => sudo
62$ sudo sed -i s=tpl=tpl/albinomouse-template=g shaarli/data/config.php
63```
diff --git a/doc/Troubleshooting.html b/doc/Troubleshooting.html
new file mode 100644
index 00000000..6965a578
--- /dev/null
+++ b/doc/Troubleshooting.html
@@ -0,0 +1,122 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Troubleshooting</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <style type="text/css">
13table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
14 margin: 0; padding: 0; vertical-align: baseline; border: none; }
15table.sourceCode { width: 100%; line-height: 100%; }
16td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
17td.sourceCode { padding-left: 5px; }
18code > span.kw { color: #007020; font-weight: bold; }
19code > span.dt { color: #902000; }
20code > span.dv { color: #40a070; }
21code > span.bn { color: #40a070; }
22code > span.fl { color: #40a070; }
23code > span.ch { color: #4070a0; }
24code > span.st { color: #4070a0; }
25code > span.co { color: #60a0b0; font-style: italic; }
26code > span.ot { color: #007020; }
27code > span.al { color: #ff0000; font-weight: bold; }
28code > span.fu { color: #06287e; }
29code > span.er { color: #ff0000; font-weight: bold; }
30 </style>
31 <link rel="stylesheet" href="github-markdown.css">
32</head>
33<body>
34<div id="local-sidebar">
35<ul>
36<li><a href="Home.html">Home</a></li>
37<li>Installation
38<ul>
39<li><a href="Server-requirements.html">Server requirements</a></li>
40<li><a href="Server-configuration.html">Server configuration</a></li>
41<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
42</ul></li>
43<li><a href="Usage.html">Usage</a>
44<ul>
45<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
46<li><a href="Firefox-share.html">Firefox share</a></li>
47<li><a href="RSS-feeds.html">RSS feeds</a></li>
48</ul></li>
49<li>How To
50<ul>
51<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
52<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
53<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
54</ul></li>
55<li><a href="Troubleshooting.html">Troubleshooting</a></li>
56<li><a href="Development.html">Development</a>
57<ul>
58<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
59<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
60<li><a href="Directory-structure.html">Directory structure</a></li>
61<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
62<li><a href="Plugin-System.html">Plugin System</a></li>
63<li><a href="Security.html">Security</a></li>
64<li><a href="Static-analysis.html">Static analysis</a></li>
65<li><a href="Theming.html">Theming</a></li>
66<li><a href="Unit-tests.html">Unit tests</a></li>
67</ul></li>
68<li>About
69<ul>
70<li><a href="FAQ.html">FAQ</a></li>
71<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
72<li><a href="TODO.html">TODO</a></li>
73</ul></li>
74</ul>
75</div>
76<h1 id="troubleshooting">Troubleshooting</h1>
77<h2 id="login">Login</h2>
78<h3 id="i-forgot-my-password">I forgot my password!</h3>
79<p>Delete the file <code>data/config.php</code> and display the page again. You will be asked for a new login/password.</p>
80<h3 id="im-locked-out---login-bruteforce-protection">I'm locked out - Login bruteforce protection</h3>
81<p>Login form is protected against brute force attacks: 4 failed logins will ban the IP address from login for 30 minutes. Banned IPs can still browse links.</p>
82<p>To remove the current IP bans, delete the file <code>data/ipbans.php</code></p>
83<h3 id="list-of-all-login-attempts">List of all login attempts</h3>
84<p>The file <code>data/log.txt</code> shows all logins (successful or failed) and bans/lifted bans.<br />Search for <code>failed</code> in this file to look for unauthorized login attempts.</p>
85<h2 id="hosting-problems">Hosting problems</h2>
86<ul>
87<li>On <strong>free.fr</strong> : Please note that free uses php 5.1 and thus you will not have autocomplete in tag editing. Don't forget to create a <code>sessions</code> directory at the root of your webspace. Change the file extension to <code>.php5</code> or create a <code>.htaccess</code> file in the directory where Shaarli is located containing:</li>
88</ul>
89<pre class="sourceCode ini"><code class="sourceCode ini"><span class="dt">php 1</span>
90<span class="dt">SetEnv PHP_VER 5</span></code></pre>
91<ul>
92<li>If you have an error such as: <code>Parse error: syntax error, unexpected '=', expecting '(' in /links/index.php on line xxx</code>, it means that your host is using php4, not php5. Shaarli requires php 5.1. Try changing the file extension to <code>.php5</code></li>
93<li>On <strong>1and1</strong> : If you add the link from the page (and not from the bookmarklet), Shaarli will no be able to get the title of the page. You will have to enter it manually. (Because they have disabled the ability to download a file through HTTP).</li>
94<li>If you have the error <code>Warning: file_get_contents() [function.file-get-contents]: URL file-access is disabled in the server configuration in /…/index.php on line xxx</code>, it means that your host has disabled the ability to fetch a file by HTTP in the php config (Typically in 1and1 hosting). Bad host. Change host. Or comment the following lines:<a href=".html"></a></li>
95</ul>
96<pre class="sourceCode php"><code class="sourceCode php"><span class="co">//list($status,$headers,$data) = getHTTP($url,4); // Short timeout to keep the application responsive.</span>
97<span class="co">// FIXME: Decode charset according to charset specified in either 1) HTTP response headers or 2) &lt;head&gt; in html </span>
98<span class="co">//if (strpos($status,&#39;200 OK&#39;)) $title=html_extract_title($data);</span></code></pre>
99<ul>
100<li>On hosts which forbid outgoing HTTP requests (such as free.fr), some thumbnails will not work.</li>
101<li>On <strong>lost-oasis</strong>, RSS doesn't work correctly, because of this message at the begining of the RSS/ATOM feed : <code>&lt;? // tout ce qui est charge ici (generalement des includes et require) est charge en permanence. ?&gt;</code>. To fix this, remove this message from <code>php-include/prepend.php</code></li>
102</ul>
103<h3 id="dates-are-not-properly-formatted">Dates are not properly formatted</h3>
104<p>Shaarli tries to sniff the language of the browser (using HTTP_ACCEPT_LANGUAGE headers) and choose a date format accordingly. But Shaarli can only use the date formats (and more generaly speaking, the locales) provided by the webserver. So even if you have a browser in French, you may end up with dates in US format (it's the case on sebsauvage.net :-( )</p>
105<h3 id="problems-on-centos-servers">Problems on CentOS servers</h3>
106<p>On <strong>CentOS</strong>/RedHat derivatives, you may need to install the <code>php-mbstring</code> package.</p>
107<h3 id="my-session-expires-i-cant-stay-logged-in">My session expires! I can't stay logged in</h3>
108<p>This can be caused by several things:</p>
109<ul>
110<li>Your php installation may not have a proper directory setup for session files. (eg. on Free.fr you need to create a <code>session</code> directory on the root of your website.) You may need to create the session directory of set it up.</li>
111<li>Most hosts regularly clean the temporary and session directories. Your host may be cleaning those directories too aggressively (eg.OVH hosts), forcing an expire of the session. You may want to set the session directory in your web root. (eg. Create the <code>sessions</code> subdirectory and add <code>ini_set('session.save_path', $_SERVER['DOCUMENT_ROOT'].'/../sessions');</code>. Make sure this directory is not browsable !)<a href=".html"></a></li>
112<li>If your IP address changes during surfing, Shaarli will force expire your session for security reasons (to prevent session cookie hijacking). This can happen when surfing from WiFi or 3G (you may have switched WiFi/3G access point), or in some corporate/university proxies which use load balancing (and may have proxies with several external IP addresses).</li>
113<li>Some browser addons may interfer with HTTP headers (ipfuck/ipflood/GreaseMonkey…). Try disabling those.</li>
114<li>You may be using OperaTurbo or OperaMini, which use their own proxies which may change from time to time.</li>
115<li>If you have another application on the same webserver where Shaarli is installed, these application may forcefully expire php sessions.</li>
116</ul>
117<h2 id="sessions-do-not-seem-to-work-correctly-on-your-server">Sessions do not seem to work correctly on your server</h2>
118<p>Follow the instructions in the error message. Make sure you are accessing shaarli via a direct IP address or a proper hostname. If you have <strong>no dots</strong> in the hostname (e.g. <code>localhost</code> or <code>http://my-webserver/shaarli/</code>), some browsers will not store cookies at all (this respects the <a href="http://curl.haxx.se/rfc/cookie_spec.html">HTTP cookie specification</a>).<a href=".html"></a></p>
119<h3 id="pubsubhubbub-support">pubsubhubbub support</h3>
120<p>Download <a href="https://pubsubhubbub.googlecode.com/git/publisher_clients/php/library/publisher.php">publisher.php</a> at the root of your Shaarli installation and set <code>$GLOBALS['config'['PUBSUBHUB_URL']</code> in your <code>config.php</code>]('PUBSUBHUB_URL']<code>-in-your-</code>config.php`.html)</p>
121</body>
122</html>
diff --git a/doc/Troubleshooting.md b/doc/Troubleshooting.md
new file mode 100644
index 00000000..4adf7c92
--- /dev/null
+++ b/doc/Troubleshooting.md
@@ -0,0 +1,60 @@
1#Troubleshooting
2## Login
3### I forgot my password!
4
5Delete the file `data/config.php` and display the page again. You will be asked for a new login/password.
6
7### I'm locked out - Login bruteforce protection
8Login form is protected against brute force attacks: 4 failed logins will ban the IP address from login for 30 minutes. Banned IPs can still browse links.
9
10To remove the current IP bans, delete the file `data/ipbans.php`
11
12### List of all login attempts
13
14The file `data/log.txt` shows all logins (successful or failed) and bans/lifted bans.
15Search for `failed` in this file to look for unauthorized login attempts.
16
17## Hosting problems
18 * On **free.fr** : Please note that free uses php 5.1 and thus you will not have autocomplete in tag editing. Don't forget to create a `sessions` directory at the root of your webspace. Change the file extension to `.php5` or create a `.htaccess` file in the directory where Shaarli is located containing:
19
20```ini
21php 1
22SetEnv PHP_VER 5
23```
24
25 * If you have an error such as: `Parse error: syntax error, unexpected '=', expecting '(' in /links/index.php on line xxx`, it means that your host is using php4, not php5. Shaarli requires php 5.1. Try changing the file extension to `.php5`
26 * On **1and1** : If you add the link from the page (and not from the bookmarklet), Shaarli will no be able to get the title of the page. You will have to enter it manually. (Because they have disabled the ability to download a file through HTTP).
27 * If you have the error `Warning: file_get_contents() [function.file-get-contents]: URL file-access is disabled in the server configuration in /…/index.php on line xxx`, it means that your host has disabled the ability to fetch a file by HTTP in the php config (Typically in 1and1 hosting). Bad host. Change host. Or comment the following lines:[](.html)
28
29```php
30//list($status,$headers,$data) = getHTTP($url,4); // Short timeout to keep the application responsive.
31// FIXME: Decode charset according to charset specified in either 1) HTTP response headers or 2) <head> in html
32//if (strpos($status,'200 OK')) $title=html_extract_title($data);
33```
34
35 * On hosts which forbid outgoing HTTP requests (such as free.fr), some thumbnails will not work.
36 * On **lost-oasis**, RSS doesn't work correctly, because of this message at the begining of the RSS/ATOM feed : `<? // tout ce qui est charge ici (generalement des includes et require) est charge en permanence. ?>`. To fix this, remove this message from `php-include/prepend.php`
37
38### Dates are not properly formatted
39Shaarli tries to sniff the language of the browser (using HTTP_ACCEPT_LANGUAGE headers) and choose a date format accordingly. But Shaarli can only use the date formats (and more generaly speaking, the locales) provided by the webserver. So even if you have a browser in French, you may end up with dates in US format (it's the case on sebsauvage.net :-( )
40
41### Problems on CentOS servers
42On **CentOS**/RedHat derivatives, you may need to install the `php-mbstring` package.
43
44
45### My session expires! I can't stay logged in
46This can be caused by several things:
47
48* Your php installation may not have a proper directory setup for session files. (eg. on Free.fr you need to create a `session` directory on the root of your website.) You may need to create the session directory of set it up.
49* Most hosts regularly clean the temporary and session directories. Your host may be cleaning those directories too aggressively (eg.OVH hosts), forcing an expire of the session. You may want to set the session directory in your web root. (eg. Create the `sessions` subdirectory and add `ini_set('session.save_path', $_SERVER['DOCUMENT_ROOT'].'/../sessions');`. Make sure this directory is not browsable !)[](.html)
50* If your IP address changes during surfing, Shaarli will force expire your session for security reasons (to prevent session cookie hijacking). This can happen when surfing from WiFi or 3G (you may have switched WiFi/3G access point), or in some corporate/university proxies which use load balancing (and may have proxies with several external IP addresses).
51* Some browser addons may interfer with HTTP headers (ipfuck/ipflood/GreaseMonkey…). Try disabling those.
52* You may be using OperaTurbo or OperaMini, which use their own proxies which may change from time to time.
53* If you have another application on the same webserver where Shaarli is installed, these application may forcefully expire php sessions.
54
55## Sessions do not seem to work correctly on your server
56Follow the instructions in the error message. Make sure you are accessing shaarli via a direct IP address or a proper hostname. If you have **no dots** in the hostname (e.g. `localhost` or `http://my-webserver/shaarli/`), some browsers will not store cookies at all (this respects the [HTTP cookie specification](http://curl.haxx.se/rfc/cookie_spec.html)).[](.html)
57
58### pubsubhubbub support
59
60Download [publisher.php](https://pubsubhubbub.googlecode.com/git/publisher_clients/php/library/publisher.php) at the root of your Shaarli installation and set `$GLOBALS['config'['PUBSUBHUB_URL']` in your `config.php`]('PUBSUBHUB_URL']`-in-your-`config.php`.html)
diff --git a/doc/Running-unit-tests.html b/doc/Unit-tests.html
index 43423bc7..25873cb0 100644
--- a/doc/Running-unit-tests.html
+++ b/doc/Unit-tests.html
@@ -4,7 +4,7 @@
4 <meta charset="utf-8"> 4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc"> 5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title></title> 7 <title>Shaarli - Unit tests</title>
8 <style type="text/css">code{white-space: pre;}</style> 8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]> 9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> 10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
@@ -31,12 +31,55 @@ code > span.er { color: #ff0000; font-weight: bold; }
31 <link rel="stylesheet" href="github-markdown.css"> 31 <link rel="stylesheet" href="github-markdown.css">
32</head> 32</head>
33<body> 33<body>
34<div id="local-sidebar">
35<ul>
36<li><a href="Home.html">Home</a></li>
37<li>Installation
38<ul>
39<li><a href="Server-requirements.html">Server requirements</a></li>
40<li><a href="Server-configuration.html">Server configuration</a></li>
41<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
42</ul></li>
43<li><a href="Usage.html">Usage</a>
44<ul>
45<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
46<li><a href="Firefox-share.html">Firefox share</a></li>
47<li><a href="RSS-feeds.html">RSS feeds</a></li>
48</ul></li>
49<li>How To
50<ul>
51<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
52<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
53<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
54</ul></li>
55<li><a href="Troubleshooting.html">Troubleshooting</a></li>
56<li><a href="Development.html">Development</a>
57<ul>
58<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
59<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
60<li><a href="Directory-structure.html">Directory structure</a></li>
61<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
62<li><a href="Plugin-System.html">Plugin System</a></li>
63<li><a href="Security.html">Security</a></li>
64<li><a href="Static-analysis.html">Static analysis</a></li>
65<li><a href="Theming.html">Theming</a></li>
66<li><a href="Unit-tests.html">Unit tests</a></li>
67</ul></li>
68<li>About
69<ul>
70<li><a href="FAQ.html">FAQ</a></li>
71<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
72<li><a href="TODO.html">TODO</a></li>
73</ul></li>
74</ul>
75</div>
76<h1 id="unit-tests">Unit tests</h1>
34<h3 id="setup-your-environment-for-tests">Setup your environment for tests</h3> 77<h3 id="setup-your-environment-for-tests">Setup your environment for tests</h3>
35<p>The framework used is <a href="https://phpunit.de/">PHPUnit</a>; it can be installed with <a href="https://getcomposer.org/">Composer</a>, which is a dependency management tool.</p> 78<p>The framework used is <a href="https://phpunit.de/">PHPUnit</a>; it can be installed with <a href="https://getcomposer.org/">Composer</a>, which is a dependency management tool.<a href=".html"></a></p>
36<p>Regarding Composer, you can either use:</p> 79<p>Regarding Composer, you can either use:</p>
37<ul> 80<ul>
38<li>a system-wide version, e.g. installed through your distro's package manager<br /></li> 81<li>a system-wide version, e.g. installed through your distro's package manager</li>
39<li>a local version, downloadable <a href="https://getcomposer.org/download/">here</a></li> 82<li>a local version, downloadable <a href="https://getcomposer.org/download/">here</a><a href=".html"></a></li>
40</ul> 83</ul>
41<h4 id="sample-usage">Sample usage</h4> 84<h4 id="sample-usage">Sample usage</h4>
42<pre class="sourceCode bash"><code class="sourceCode bash"><span class="co"># system-wide version</span> 85<pre class="sourceCode bash"><code class="sourceCode bash"><span class="co"># system-wide version</span>
@@ -90,7 +133,7 @@ $ <span class="kw">composer</span> update</code></pre>
90 133
91<span class="kw">1</span>) <span class="kw">LinkDBTest</span>::testConstructLoggedIn 134<span class="kw">1</span>) <span class="kw">LinkDBTest</span>::testConstructLoggedIn
92<span class="kw">Missing</span> argument 2 for LinkDB::__construct(), <span class="kw">called</span> in /home/virtualtam/public_html/shaarli/tests/Link\ 135<span class="kw">Missing</span> argument 2 for LinkDB::__construct(), <span class="kw">called</span> in /home/virtualtam/public_html/shaarli/tests/Link\
93<span class="kw">DBTest.php</span> on line 79 and defined 136DBTest.php on line 79 and defined
94 137
95<span class="kw">/home/virtualtam/public_html/shaarli/application</span>/LinkDB.php:<span class="kw">58</span> 138<span class="kw">/home/virtualtam/public_html/shaarli/application</span>/LinkDB.php:<span class="kw">58</span>
96<span class="kw">/home/virtualtam/public_html/shaarli/tests</span>/LinkDBTest.php:<span class="kw">79</span> 139<span class="kw">/home/virtualtam/public_html/shaarli/tests</span>/LinkDBTest.php:<span class="kw">79</span>
@@ -125,18 +168,18 @@ $ <span class="kw">composer</span> update</code></pre>
125<p>By default, PHPUnit will run all suitable tests found under the <code>tests</code> directory.</p> 168<p>By default, PHPUnit will run all suitable tests found under the <code>tests</code> directory.</p>
126<p>Each test has 3 possible outcomes:</p> 169<p>Each test has 3 possible outcomes:</p>
127<ul> 170<ul>
128<li><code>.</code> - success<br /></li> 171<li><code>.</code> - success</li>
129<li><code>F</code> - failure: the test was run but its results are invalid<br /></li> 172<li><code>F</code> - failure: the test was run but its results are invalid</li>
130<li>the code does not behave as expected<br /></li> 173<li>the code does not behave as expected</li>
131<li>dependencies to external elements: globals, session, cache...<br /></li> 174<li>dependencies to external elements: globals, session, cache...</li>
132<li><code>E</code> - error: something went wrong and the tested code has crashed<br /></li> 175<li><code>E</code> - error: something went wrong and the tested code has crashed</li>
133<li>typos in the code, or in the test code<br /></li> 176<li>typos in the code, or in the test code</li>
134<li>dependencies to missing external elements</li> 177<li>dependencies to missing external elements</li>
135</ul> 178</ul>
136<p>If Xdebug has been installed and activated, two coverage reports will be generated:</p> 179<p>If Xdebug has been installed and activated, two coverage reports will be generated:</p>
137<ul> 180<ul>
138<li>a summary in the console<br /></li> 181<li>a summary in the console</li>
139<li>a detailed HTML report with metrics for tested code<br /></li> 182<li>a detailed HTML report with metrics for tested code</li>
140<li>to open it in a web browser: <code>firefox coverage/index.html &amp;</code></li> 183<li>to open it in a web browser: <code>firefox coverage/index.html &amp;</code></li>
141</ul> 184</ul>
142</body> 185</body>
diff --git a/doc/Running-unit-tests.md b/doc/Unit-tests.md
index 94e99591..f2888780 100644
--- a/doc/Running-unit-tests.md
+++ b/doc/Unit-tests.md
@@ -1,10 +1,11 @@
1#Unit tests
1 2
2### Setup your environment for tests 3### Setup your environment for tests
3The framework used is [PHPUnit](https://phpunit.de/); it can be installed with [Composer](https://getcomposer.org/), which is a dependency management tool. 4The framework used is [PHPUnit](https://phpunit.de/); it can be installed with [Composer](https://getcomposer.org/), which is a dependency management tool.[](.html)
4 5
5Regarding Composer, you can either use: 6Regarding Composer, you can either use:
6* a system-wide version, e.g. installed through your distro's package manager 7* a system-wide version, e.g. installed through your distro's package manager
7* a local version, downloadable [here](https://getcomposer.org/download/) 8* a local version, downloadable [here](https://getcomposer.org/download/)[](.html)
8 9
9#### Sample usage 10#### Sample usage
10```bash 11```bash
@@ -124,4 +125,4 @@ Each test has 3 possible outcomes:
124If Xdebug has been installed and activated, two coverage reports will be generated: 125If Xdebug has been installed and activated, two coverage reports will be generated:
125* a summary in the console 126* a summary in the console
126* a detailed HTML report with metrics for tested code 127* a detailed HTML report with metrics for tested code
127 * to open it in a web browser: `firefox coverage/index.html &` \ No newline at end of file 128 * to open it in a web browser: `firefox coverage/index.html &`
diff --git a/doc/Usage.html b/doc/Usage.html
new file mode 100644
index 00000000..cffdc4d6
--- /dev/null
+++ b/doc/Usage.html
@@ -0,0 +1,85 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - Usage</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <link rel="stylesheet" href="github-markdown.css">
13</head>
14<body>
15<div id="local-sidebar">
16<ul>
17<li><a href="Home.html">Home</a></li>
18<li>Installation
19<ul>
20<li><a href="Server-requirements.html">Server requirements</a></li>
21<li><a href="Server-configuration.html">Server configuration</a></li>
22<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
23</ul></li>
24<li><a href="Usage.html">Usage</a>
25<ul>
26<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
27<li><a href="Firefox-share.html">Firefox share</a></li>
28<li><a href="RSS-feeds.html">RSS feeds</a></li>
29</ul></li>
30<li>How To
31<ul>
32<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
33<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
34<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
35</ul></li>
36<li><a href="Troubleshooting.html">Troubleshooting</a></li>
37<li><a href="Development.html">Development</a>
38<ul>
39<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
40<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
41<li><a href="Directory-structure.html">Directory structure</a></li>
42<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
43<li><a href="Plugin-System.html">Plugin System</a></li>
44<li><a href="Security.html">Security</a></li>
45<li><a href="Static-analysis.html">Static analysis</a></li>
46<li><a href="Theming.html">Theming</a></li>
47<li><a href="Unit-tests.html">Unit tests</a></li>
48</ul></li>
49<li>About
50<ul>
51<li><a href="FAQ.html">FAQ</a></li>
52<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
53<li><a href="TODO.html">TODO</a></li>
54</ul></li>
55</ul>
56</div>
57<h1 id="usage">Usage</h1>
58<h3 id="main-features">Main features</h3>
59<p>Shaarli is intended:</p>
60<ul>
61<li>to share, comment and save interesting links and news</li>
62<li>to bookmark useful/frequent personal links (as private links) and share them between computers</li>
63<li>as a minimal blog/microblog/writing platform (no character limit)</li>
64<li>as a read-it-later list (for example items tagged <code>readlater</code>)</li>
65<li>to draft and save articles/ideas</li>
66<li>to keep code snippets</li>
67<li>to keep notes and documentation</li>
68<li>as a shared clipboard between machines</li>
69<li>as a todo list</li>
70<li>to store playlists (e.g. with the <code>music</code> or <code>video</code> tags)</li>
71<li>to keep extracts/comments from webpages that may disappear</li>
72<li>to keep track of ongoing discussions (for example items tagged <code>discussion</code>)</li>
73<li><a href="http://shaarli.chassegnouf.net/?9Efeiw">to feed RSS aggregators</a> (planets) with specific tags<a href=".html"></a></li>
74<li>to feed other social networks, blogs... using RSS feeds and external services (dlvr.it, ifttt.com ...)</li>
75</ul>
76<h3 id="using-shaarli-as-a-blog-notepad-pastebin...">Using Shaarli as a blog, notepad, pastebin...</h3>
77<ul>
78<li>Go to your Shaarli setup and log in</li>
79<li>Click the <code>Add Link</code> button</li>
80<li>To share text only, do not enter any URL in the corresponding input field and click <code>Add Link</code></li>
81<li>Pick a title and enter your article, or note, in the description field; add a few tags; optionally check <code>Private</code> then click <code>Save</code></li>
82<li>Voilà! Your article is now published (privately if you selected that option) and accessible using its permalink.</li>
83</ul>
84</body>
85</html>
diff --git a/doc/Usage.md b/doc/Usage.md
new file mode 100644
index 00000000..30ad1466
--- /dev/null
+++ b/doc/Usage.md
@@ -0,0 +1,25 @@
1#Usage
2### Main features
3Shaarli is intended:
4 * to share, comment and save interesting links and news
5 * to bookmark useful/frequent personal links (as private links) and share them between computers
6 * as a minimal blog/microblog/writing platform (no character limit)
7 * as a read-it-later list (for example items tagged `readlater`)
8 * to draft and save articles/ideas
9 * to keep code snippets
10 * to keep notes and documentation
11 * as a shared clipboard between machines
12 * as a todo list
13 * to store playlists (e.g. with the `music` or `video` tags)
14 * to keep extracts/comments from webpages that may disappear
15 * to keep track of ongoing discussions (for example items tagged `discussion`)
16 * [to feed RSS aggregators](http://shaarli.chassegnouf.net/?9Efeiw) (planets) with specific tags[](.html)
17 * to feed other social networks, blogs... using RSS feeds and external services (dlvr.it, ifttt.com ...)
18
19### Using Shaarli as a blog, notepad, pastebin...
20
21 * Go to your Shaarli setup and log in
22 * Click the `Add Link` button
23 * To share text only, do not enter any URL in the corresponding input field and click `Add Link`
24 * Pick a title and enter your article, or note, in the description field; add a few tags; optionally check `Private` then click `Save`
25 * Voilà! Your article is now published (privately if you selected that option) and accessible using its permalink.
diff --git a/doc/_Sidebar.html b/doc/_Sidebar.html
new file mode 100644
index 00000000..c2725196
--- /dev/null
+++ b/doc/_Sidebar.html
@@ -0,0 +1,99 @@
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="generator" content="pandoc">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
7 <title>Shaarli - _Sidebar</title>
8 <style type="text/css">code{white-space: pre;}</style>
9 <!--[if lt IE 9]>
10 <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
11 <![endif]-->
12 <link rel="stylesheet" href="github-markdown.css">
13</head>
14<body>
15<div id="local-sidebar">
16<ul>
17<li><a href="Home.html">Home</a></li>
18<li>Installation
19<ul>
20<li><a href="Server-requirements.html">Server requirements</a></li>
21<li><a href="Server-configuration.html">Server configuration</a></li>
22<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
23</ul></li>
24<li><a href="Usage.html">Usage</a>
25<ul>
26<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
27<li><a href="Firefox-share.html">Firefox share</a></li>
28<li><a href="RSS-feeds.html">RSS feeds</a></li>
29</ul></li>
30<li>How To
31<ul>
32<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
33<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
34<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
35</ul></li>
36<li><a href="Troubleshooting.html">Troubleshooting</a></li>
37<li><a href="Development.html">Development</a>
38<ul>
39<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
40<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
41<li><a href="Directory-structure.html">Directory structure</a></li>
42<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
43<li><a href="Plugin-System.html">Plugin System</a></li>
44<li><a href="Security.html">Security</a></li>
45<li><a href="Static-analysis.html">Static analysis</a></li>
46<li><a href="Theming.html">Theming</a></li>
47<li><a href="Unit-tests.html">Unit tests</a></li>
48</ul></li>
49<li>About
50<ul>
51<li><a href="FAQ.html">FAQ</a></li>
52<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
53<li><a href="TODO.html">TODO</a></li>
54</ul></li>
55</ul>
56</div>
57<h1 id="sidebar">_Sidebar</h1>
58<ul>
59<li><a href="Home.html">Home</a></li>
60<li>Installation
61<ul>
62<li><a href="Server-requirements.html">Server requirements</a></li>
63<li><a href="Server-configuration.html">Server configuration</a></li>
64<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
65</ul></li>
66<li><a href="Usage.html">Usage</a>
67<ul>
68<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
69<li><a href="Firefox-share.html">Firefox share</a></li>
70<li><a href="RSS-feeds.html">RSS feeds</a></li>
71</ul></li>
72<li>How To
73<ul>
74<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
75<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
76<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
77</ul></li>
78<li><a href="Troubleshooting.html">Troubleshooting</a></li>
79<li><a href="Development.html">Development</a>
80<ul>
81<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
82<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
83<li><a href="Directory-structure.html">Directory structure</a></li>
84<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
85<li><a href="Plugin-System.html">Plugin System</a></li>
86<li><a href="Security.html">Security</a></li>
87<li><a href="Static-analysis.html">Static analysis</a></li>
88<li><a href="Theming.html">Theming</a></li>
89<li><a href="Unit-tests.html">Unit tests</a></li>
90</ul></li>
91<li>About
92<ul>
93<li><a href="FAQ.html">FAQ</a></li>
94<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
95<li><a href="TODO.html">TODO</a></li>
96</ul></li>
97</ul>
98</body>
99</html>
diff --git a/doc/_Sidebar.md b/doc/_Sidebar.md
new file mode 100644
index 00000000..64b16491
--- /dev/null
+++ b/doc/_Sidebar.md
@@ -0,0 +1,29 @@
1#_Sidebar
2- [Home](Home.html)
3- Installation
4 - [Server requirements](Server-requirements.html)
5 - [Server configuration](Server-configuration.html)
6 - [Shaarli configuration](Shaarli-configuration.html)
7- [Usage](Usage.html)
8 - [Sharing button](Sharing-button.html) (bookmarklet)
9 - [Firefox share](Firefox-share.html)
10 - [RSS feeds](RSS-feeds.html)
11- How To
12 - [Backup, restore, import and export](Backup,-restore,-import-and-export.html)
13 - [Copy an existing installation over SSH and serve it locally](Copy-an-existing-installation-over-SSH-and-serve-it-locally.html)
14 - [Download CSS styles from an OPML list](Download-CSS-styles-from-an-OPML-list.html)
15- [Troubleshooting](Troubleshooting.html)
16- [Development](Development.html)
17 - [GnuPG signature](GnuPG-signature.html)
18 - [Coding guidelines](Coding-guidelines.html)
19 - [Directory structure](Directory-structure.html)
20 - [3rd party libraries](3rd-party-libraries.html)
21 - [Plugin System](Plugin-System.html)
22 - [Security](Security.html)
23 - [Static analysis](Static-analysis.html)
24 - [Theming](Theming.html)
25 - [Unit tests](Unit-tests.html)
26- About
27 - [FAQ](FAQ.html)
28 - [Community & Related software](Community-&-Related-software.html)
29 - [TODO](TODO.html)
diff --git a/doc/github-markdown.css b/doc/github-markdown.css
index 2b853b3f..581350ae 100644
--- a/doc/github-markdown.css
+++ b/doc/github-markdown.css
@@ -1,3 +1,13 @@
1#local-sidebar {
2 width: 230px;
3 float: right;
4 position: relative;
5 z-index: 4;
6 background-color: #fff;
7 border: 1px solid #e2e2e2;
8 border-radius: 3px;
9}
10
1body { 11body {
2 font-family: Helvetica, arial, sans-serif; 12 font-family: Helvetica, arial, sans-serif;
3 font-size: 14px; 13 font-size: 14px;
diff --git a/doc/sidebar.html b/doc/sidebar.html
new file mode 100644
index 00000000..1b585400
--- /dev/null
+++ b/doc/sidebar.html
@@ -0,0 +1,42 @@
1<div id="local-sidebar">
2<ul>
3<li><a href="Home.html">Home</a></li>
4<li>Installation
5<ul>
6<li><a href="Server-requirements.html">Server requirements</a></li>
7<li><a href="Server-configuration.html">Server configuration</a></li>
8<li><a href="Shaarli-configuration.html">Shaarli configuration</a></li>
9</ul></li>
10<li><a href="Usage.html">Usage</a>
11<ul>
12<li><a href="Sharing-button.html">Sharing button</a> (bookmarklet)</li>
13<li><a href="Firefox-share.html">Firefox share</a></li>
14<li><a href="RSS-feeds.html">RSS feeds</a></li>
15</ul></li>
16<li>How To
17<ul>
18<li><a href="Backup,-restore,-import-and-export.html">Backup, restore, import and export</a></li>
19<li><a href="Copy-an-existing-installation-over-SSH-and-serve-it-locally.html">Copy an existing installation over SSH and serve it locally</a></li>
20<li><a href="Download-CSS-styles-from-an-OPML-list.html">Download CSS styles from an OPML list</a></li>
21</ul></li>
22<li><a href="Troubleshooting.html">Troubleshooting</a></li>
23<li><a href="Development.html">Development</a>
24<ul>
25<li><a href="GnuPG-signature.html">GnuPG signature</a></li>
26<li><a href="Coding-guidelines.html">Coding guidelines</a></li>
27<li><a href="Directory-structure.html">Directory structure</a></li>
28<li><a href="3rd-party-libraries.html">3rd party libraries</a></li>
29<li><a href="Plugin-System.html">Plugin System</a></li>
30<li><a href="Security.html">Security</a></li>
31<li><a href="Static-analysis.html">Static analysis</a></li>
32<li><a href="Theming.html">Theming</a></li>
33<li><a href="Unit-tests.html">Unit tests</a></li>
34</ul></li>
35<li>About
36<ul>
37<li><a href="FAQ.html">FAQ</a></li>
38<li><a href="Community-&amp;-Related-software.html">Community &amp; Related software</a></li>
39<li><a href="TODO.html">TODO</a></li>
40</ul></li>
41</ul>
42</div>