diff --git a/app/controllers/services.php b/app/controllers/services.php
index 9accb67..9f85b8d 100644
--- a/app/controllers/services.php
+++ b/app/controllers/services.php
@@ -25,7 +25,11 @@ Router\get_action('services', function () {
// Update bookmark services
Router\post_action('services', function () {
$user_id = SessionStorage::getInstance()->getUserId();
- $values = Request\values() + array('pinboard_enabled' => 0, 'instapaper_enabled' => 0, 'wallabag_enabled' => 0);
+ $values = Request\values() + array('pinboard_enabled' => 0,
+ 'instapaper_enabled' => 0,
+ 'wallabag_enabled' => 0,
+ 'shaarli_enabled' => 0,
+ 'shaarli_private' => 0,);
Helper\check_csrf_values($values);
if (Model\Config\save($user_id, $values)) {
diff --git a/app/handlers/service.php b/app/handlers/service.php
index 88fb541..674ecdd 100644
--- a/app/handlers/service.php
+++ b/app/handlers/service.php
@@ -22,6 +22,10 @@ function sync($user_id, $item_id)
if (Helper\bool_config('wallabag_enabled')) {
wallabag_sync($item);
}
+
+ if (Helper\bool_config('shaarli_enabled')) {
+ shaarli_sync($item);
+ }
}
function instapaper_sync(array $item)
@@ -131,6 +135,43 @@ function wallabag_get_access_token()
return false;
}
+function shaarli_sync(array $item)
+{
+ $headers = array(
+ 'Authorization: Bearer ' . shaarli_get_access_token()
+ );
+ $apiUrl = rtrim(Helper\config('shaarli_url'), '\/') . '/api/v1/links';
+ $tags = explode(',', Helper\config('shaarli_tags'));
+ $data = array(
+ 'url' => $item['url'],
+ 'title' => $item['title'],
+ 'description' => '',
+ 'tags' => $tags,
+ 'private' => Helper\bool_config('shaarli_private'),
+ );
+ $response = api_post_json_call($apiUrl, $data, $headers);
+ if ($response !== false) {
+ $response = json_decode($response, true);
+ }
+ return empty($response['id']);
+}
+
+function shaarli_get_access_token()
+{
+ $secret = Helper\config('shaarli_secret');
+ $header = base64_encode('{
+ "typ": "JWT",
+ "alg": "HS512"
+ }');
+ $payload = base64_encode('{
+ "iat": '. time() .'
+ }');
+ $signature = hash_hmac('sha512', $header . '.' . $payload, $secret, true);
+ // Base64Url Encoding:
+ $signature = rtrim(strtr(base64_encode($signature), '+/' , '-_' ), '=' );
+ return $header . '.' . $payload . '.' . $signature;
+}
+
function api_get_call($url, array $headers = array())
{
try {
@@ -147,13 +188,52 @@ function api_get_call($url, array $headers = array())
}
function api_post_call($url, array $data, array $headers = array())
+{
+ $data = http_build_query($data);
+ $additionalHeaders = array(
+ 'Content-Type: application/x-www-form-urlencoded'
+ );
+ $headers = $headers
+ ? array_merge($headers, $additionalHeaders)
+ : $additionalHeaders;
+ return api_post($url, $data, $headers);
+}
+
+function api_post_json_call($url, array $data, array $headers = array())
+{
+ $data = json_encode($data);
+ $additionalHeaders = array(
+ 'Content-Type: application/json',
+ 'Content-Length:' . strlen($data)
+ );
+ $headers = $headers
+ ? array_merge($headers, $additionalHeaders)
+ : $additionalHeaders;
+ return api_post($url, $data, $headers);
+}
+
+function api_post($url, $data, array $headers)
{
return function_exists('curl_init')
? post_curl($url, $data, $headers)
: post_stream($url, $data, $headers);
}
-function post_curl($url, array $data, array $headers = array())
+function post_stream($url, $data, array $headers = array())
+{
+ $options = array(
+ 'http' => array(
+ 'method' => 'POST',
+ 'header' => implode("\r\n", $headers),
+ 'content' => $data
+ )
+ );
+ $context = stream_context_create($options);
+ $result = file_get_contents($url, false, $context);
+ return $result;
+}
+
+function post_curl($url, $data, array $headers = array())
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
@@ -162,26 +242,8 @@ function post_curl($url, array $data, array $headers = array())
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
-
-function post_stream($url, array $data, array $headers = array())
-{
- $contentType = array('Content-Type: application/x-www-form-urlencoded');
- $headers = $headers
- ? array_merge($headers, $contentType)
- : $contentType;
- $options = array(
- 'http' => array(
- 'method' => 'POST',
- 'header' => implode("\r\n", $headers),
- 'content' => http_build_query($data)
- )
- );
- $context = stream_context_create($options);
- $result = file_get_contents($url, false, $context);
- return $result;
-}
diff --git a/app/locales/de_DE/translations.php b/app/locales/de_DE/translations.php
index acc3ecd..dd01021 100644
--- a/app/locales/de_DE/translations.php
+++ b/app/locales/de_DE/translations.php
@@ -219,6 +219,11 @@ return array(
'Last Login' => 'Letzte Anmeldung',
'Search' => 'Suchen',
'There are no results for your search' => 'Deine Suche lieferte keine Ergebnisse',
+ 'Send bookmarks to Shaarli' => 'Lesezeichen an Shaarli senden',
+ 'Shaarli secret' => 'Shaarli Secret',
+ 'Shaarli URL' => 'Shaarli URL',
+ 'Shaarli tags' => 'Shaarli Tags',
+ 'Private bookmarks' => 'Lesezeichen nicht öffentlich',
'Send bookmarks to Wallabag' => 'Lesezeichen an Wallabag senden',
'Wallabag username' => 'Wallabag-Benutzername',
'Wallabag password' => 'Wallabag-Passwort',
diff --git a/app/templates/config/services.php b/app/templates/config/services.php
index d36bacc..10b2a7b 100644
--- a/app/templates/config/services.php
+++ b/app/templates/config/services.php
@@ -63,6 +63,22 @@
+