5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
vendor
|
||||
composer.phar
|
||||
db/poche.sqlite
|
||||
output
|
||||
phpdoc*
|
15
.travis.yml
Normal file
@ -0,0 +1,15 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 5.4
|
||||
|
||||
branches:
|
||||
only:
|
||||
- dev
|
||||
|
||||
before_script:
|
||||
- composer install
|
||||
|
||||
notifications:
|
||||
email:
|
||||
- nicolas.loeuillet@gmail.com
|
12
CREDITS
@ -1,16 +1,14 @@
|
||||
poche is based on :
|
||||
* ReadItYourself http://www.memiks.fr/readityourself/
|
||||
* PHP Readability http://www.keyvan.net/2010/08/php-readability/
|
||||
* PHP Readability https://bitbucket.org/fivefilters/php-readability
|
||||
* Encoding https://github.com/neitanod/forceutf8
|
||||
* logo by Brightmix http://www.iconfinder.com/icondetails/43256/128/jeans_monotone_pocket_icon
|
||||
* icons http://icomoon.io
|
||||
* PHP Simple HTML DOM Parser (for Pocket import) http://simplehtmldom.sourceforge.net/
|
||||
* Session https://github.com/tontof/kriss_feed/blob/master/src/class/Session.php
|
||||
* Twig http://twig.sensiolabs.org
|
||||
* Flash messages https://github.com/plasticbrain/PHP-Flash-Messages
|
||||
* Pagination https://github.com/daveismyname/pagination
|
||||
|
||||
poche is developed by Nicolas Lœuillet under the Do What the Fuck You Want to Public License
|
||||
|
||||
Contributors :
|
||||
Nicolas Lœuillet aka nico_somb
|
||||
Tom.C. aka tmos
|
||||
PeaceCopathe
|
||||
Gregoire_M
|
||||
Contributors : https://github.com/inthepoche/poche/graphs/contributors
|
53
INSTALL.md
Normal file
@ -0,0 +1,53 @@
|
||||
# Installing poche
|
||||
|
||||
Get the [latest dev version](https://github.com/inthepoche/poche/archive/dev.zip) of poche on github. Unzip it and upload it on your server.
|
||||
|
||||
your datas can be stored on sqlite, postgres or mysql databases.
|
||||
|
||||
Edit /inc/poche/config.inc.php :
|
||||
|
||||
```php
|
||||
define ('STORAGE','sqlite'); # postgres, mysql, sqlite
|
||||
define ('STORAGE_SERVER', 'localhost'); # leave blank for sqlite
|
||||
define ('STORAGE_DB', 'poche'); # only for postgres & mysql
|
||||
define ('STORAGE_SQLITE', './db/poche.sqlite');
|
||||
define ('STORAGE_USER', 'user'); # leave blank for sqlite
|
||||
define ('STORAGE_PASSWORD', 'pass'); # leave blank for sqlite
|
||||
```
|
||||
|
||||
poche must have write access on assets, cache and db directories.
|
||||
|
||||
[PHP cURL](http://www.php.net/manual/en/book.curl.php) & [tidy_parse_string](http://www.php.net/manual/en/tidy.parsestring.php) are recommended.
|
||||
|
||||
## twig
|
||||
poche now uses twig for templating. You have to install twig.
|
||||
|
||||
Install composer in your project :
|
||||
```bash
|
||||
curl -s http://getcomposer.org/installer | php
|
||||
```
|
||||
Install via composer :
|
||||
```bash
|
||||
php composer.phar install
|
||||
```
|
||||
|
||||
If you don't want to install twig by yourself, you can download [this file](http://static.inthepoche.com/files/poche-1.0-latest-with-twig.zip).
|
||||
|
||||
## storage in sqlite
|
||||
You have to install [sqlite for php](http://www.php.net/manual/en/book.sqlite.php) on your server.
|
||||
|
||||
Copy /install/poche.sqlite in /db
|
||||
|
||||
## storage in mysql
|
||||
Execute /install/mysql.sql file in your database.
|
||||
|
||||
## storage in postgres
|
||||
Execute /install/postgres.sql file in your database.
|
||||
|
||||
## upgrading from poche <= 0.3
|
||||
With poche <= 0.3, all your datas were stored in a sqlite file. The structure of this file changed.
|
||||
|
||||
You have to execute http://yourpoche/install/update_sqlite_from_0_to_1.php before using this new version.
|
||||
|
||||
## installing poche
|
||||
you can go on your poche http://yourpoche. You have to fill the fields and that's all !
|
30
README.md
@ -1,5 +1,5 @@
|
||||
# poche
|
||||
Abandon Pocket, Instapaper and other Readability service : adopt poche. It is the same, but it is open source.
|
||||
Abandon Pocket, Instapaper and other Readability service : adopt poche. It is the same, but it is open source. Moreover, you can migrate from Pocket & Readability.
|
||||
|
||||
![poche](http://inthepoche.com/img/logo.png)
|
||||
|
||||
@ -11,24 +11,6 @@ To get news from poche, [follow us on twitter](http://twitter.com/getpoche) or [
|
||||
|
||||
[![flattr](http://api.flattr.com/button/flattr-badge-large.png)](http://flattr.com/thing/1265480/poche-a-read-it-later-open-source-system)
|
||||
|
||||
## Usage
|
||||
You can easily add a "poched" page with the bookmarklet.
|
||||
|
||||
poche save the entire content of a poched links : text and pictures are stored on your server.
|
||||
|
||||
You can :
|
||||
* read a page in a comfortable reading view
|
||||
* archive a link
|
||||
* put a link in favorite
|
||||
* delete a link
|
||||
|
||||
## Requirements & installation
|
||||
You have to install [sqlite for php](http://www.php.net/manual/en/book.sqlite.php) on your server.
|
||||
|
||||
Get the [latest version](https://github.com/inthepoche/poche) of poche on github. Unzip it and upload it on your server. poche must have write access on assets, cache and db directories.
|
||||
|
||||
That's all, **poche works** !
|
||||
|
||||
## Security
|
||||
You **have** to protect your db/poche.sqlite file. Modify the virtual host of your website to add this condition :
|
||||
```apache
|
||||
@ -46,12 +28,14 @@ location ~ /(db) {
|
||||
}
|
||||
```
|
||||
|
||||
## Import from Pocket
|
||||
## Usage
|
||||
See the documentation on our website : [inthepoche.com](http://inthepoche.com).
|
||||
|
||||
If you want to import your Pocket datas, [export them here](https://getpocket.com/export). Put the HTML file in your poche directory, execute import.php file locally by following instructions. Be careful, the script can take a very long time.
|
||||
## Travis
|
||||
[![Build Status](https://api.travis-ci.org/inthepoche/poche.png?branch=dev)](http://travis-ci.org/#!/inthepoche/poche)
|
||||
|
||||
## License
|
||||
Copyright © 2010-2013 Nicolas Lœuillet <nicolas@loeuillet.org>
|
||||
Copyright © 2010-2013 Nicolas Lœuillet <nicolas.loeuillet@gmail.com>
|
||||
This work is free. You can redistribute it and/or modify it under the
|
||||
terms of the Do What The Fuck You Want To Public License, Version 2,
|
||||
as published by Sam Hocevar. See the COPYING file for more details.
|
||||
as published by Sam Hocevar. See the COPYING file for more details.
|
11
TODO.md
Normal file
@ -0,0 +1,11 @@
|
||||
# TODO
|
||||
|
||||
pouvoir annuler la suppression
|
||||
conventions codage ? phing ? vérifier error_log qui trainent
|
||||
phpDocumentor
|
||||
minifier css
|
||||
revoir tous les css
|
||||
barre fixe d'admin sur la page d'un billet ?
|
||||
revoir export (export vers pocket &cie ? )
|
||||
raccourcis clavier
|
||||
date d'ajout d'un lien
|
7
composer.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"require": {
|
||||
"twig/twig": "1.*",
|
||||
"twig/extensions": "1.0.*",
|
||||
"umpirsky/twig-gettext-extractor": "1.1.*"
|
||||
}
|
||||
}
|
744
composer.lock
generated
Normal file
@ -0,0 +1,744 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
|
||||
],
|
||||
"hash": "1c8badb14d91f4f3ef1cfae23252a2c4",
|
||||
"packages": [
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v2.3.2",
|
||||
"target-dir": "Symfony/Component/EventDispatcher",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/EventDispatcher.git",
|
||||
"reference": "v2.3.2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.3.2",
|
||||
"reference": "v2.3.2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/dependency-injection": "~2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/dependency-injection": "",
|
||||
"symfony/http-kernel": ""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Component\\EventDispatcher\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony EventDispatcher Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2013-05-13 14:36:40"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v2.3.2",
|
||||
"target-dir": "Symfony/Component/Filesystem",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Filesystem.git",
|
||||
"reference": "v2.3.2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Filesystem/zipball/v2.3.2",
|
||||
"reference": "v2.3.2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Component\\Filesystem\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Filesystem Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2013-06-04 15:02:05"
|
||||
},
|
||||
{
|
||||
"name": "symfony/form",
|
||||
"version": "v2.3.2",
|
||||
"target-dir": "Symfony/Component/Form",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Form.git",
|
||||
"reference": "v2.3.2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Form/zipball/v2.3.2",
|
||||
"reference": "v2.3.2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"symfony/event-dispatcher": "~2.1",
|
||||
"symfony/intl": "~2.3",
|
||||
"symfony/options-resolver": "~2.1",
|
||||
"symfony/property-access": "~2.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/http-foundation": "~2.2",
|
||||
"symfony/validator": "~2.2"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/http-foundation": "",
|
||||
"symfony/validator": ""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Component\\Form\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Form Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2013-07-01 12:24:43"
|
||||
},
|
||||
{
|
||||
"name": "symfony/icu",
|
||||
"version": "v1.0.0",
|
||||
"target-dir": "Symfony/Component/Icu",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Icu.git",
|
||||
"reference": "v1.0.0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Icu/zipball/v1.0.0",
|
||||
"reference": "v1.0.0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"symfony/intl": ">=2.3,<3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Component\\Icu\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
},
|
||||
{
|
||||
"name": "Bernhard Schussek",
|
||||
"email": "bschussek@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Contains an excerpt of the ICU data and classes to load it.",
|
||||
"homepage": "http://symfony.com",
|
||||
"keywords": [
|
||||
"icu",
|
||||
"intl"
|
||||
],
|
||||
"time": "2013-06-03 18:32:07"
|
||||
},
|
||||
{
|
||||
"name": "symfony/intl",
|
||||
"version": "v2.3.2",
|
||||
"target-dir": "Symfony/Component/Intl",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Intl.git",
|
||||
"reference": "v2.3.2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Intl/zipball/v2.3.2",
|
||||
"reference": "v2.3.2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"symfony/icu": "~1.0-RC"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/filesystem": ">=2.1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "to use the component with locales other than \"en\""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Component\\Intl\\": ""
|
||||
},
|
||||
"classmap": [
|
||||
"Symfony/Component/Intl/Resources/stubs"
|
||||
],
|
||||
"files": [
|
||||
"Symfony/Component/Intl/Resources/stubs/functions.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
},
|
||||
{
|
||||
"name": "Igor Wiedler",
|
||||
"email": "igor@wiedler.ch",
|
||||
"homepage": "http://wiedler.ch/igor/"
|
||||
},
|
||||
{
|
||||
"name": "Bernhard Schussek",
|
||||
"email": "bschussek@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Eriksen Costa",
|
||||
"email": "eriksen.costa@infranology.com.br"
|
||||
}
|
||||
],
|
||||
"description": "A PHP replacement layer for the C intl extension that includes additional data from the ICU library.",
|
||||
"homepage": "http://symfony.com",
|
||||
"keywords": [
|
||||
"i18n",
|
||||
"icu",
|
||||
"internationalization",
|
||||
"intl",
|
||||
"l10n",
|
||||
"localization"
|
||||
],
|
||||
"time": "2013-07-08 13:00:35"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
"version": "v2.3.2",
|
||||
"target-dir": "Symfony/Component/OptionsResolver",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/OptionsResolver.git",
|
||||
"reference": "v2.3.2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/OptionsResolver/zipball/v2.3.2",
|
||||
"reference": "v2.3.2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Component\\OptionsResolver\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony OptionsResolver Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"keywords": [
|
||||
"config",
|
||||
"configuration",
|
||||
"options"
|
||||
],
|
||||
"time": "2013-04-11 06:50:46"
|
||||
},
|
||||
{
|
||||
"name": "symfony/property-access",
|
||||
"version": "v2.3.2",
|
||||
"target-dir": "Symfony/Component/PropertyAccess",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/PropertyAccess.git",
|
||||
"reference": "v2.3.2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/PropertyAccess/zipball/v2.3.2",
|
||||
"reference": "v2.3.2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Component\\PropertyAccess\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony PropertyAccess Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"keywords": [
|
||||
"access",
|
||||
"array",
|
||||
"extraction",
|
||||
"index",
|
||||
"injection",
|
||||
"object",
|
||||
"property",
|
||||
"property path",
|
||||
"reflection"
|
||||
],
|
||||
"time": "2013-07-01 12:24:43"
|
||||
},
|
||||
{
|
||||
"name": "symfony/routing",
|
||||
"version": "v2.3.2",
|
||||
"target-dir": "Symfony/Component/Routing",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Routing.git",
|
||||
"reference": "v2.3.2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Routing/zipball/v2.3.2",
|
||||
"reference": "v2.3.2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/common": "~2.2",
|
||||
"psr/log": "~1.0",
|
||||
"symfony/config": "~2.2",
|
||||
"symfony/yaml": "~2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"doctrine/common": "",
|
||||
"symfony/config": "",
|
||||
"symfony/yaml": ""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Component\\Routing\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Routing Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2013-06-23 08:16:02"
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation",
|
||||
"version": "v2.3.2",
|
||||
"target-dir": "Symfony/Component/Translation",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Translation.git",
|
||||
"reference": "v2.3.2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Translation/zipball/v2.3.2",
|
||||
"reference": "v2.3.2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/config": "~2.0",
|
||||
"symfony/yaml": "~2.2"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/config": "",
|
||||
"symfony/yaml": ""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Component\\Translation\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Translation Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2013-05-13 14:36:40"
|
||||
},
|
||||
{
|
||||
"name": "symfony/twig-bridge",
|
||||
"version": "v2.3.2",
|
||||
"target-dir": "Symfony/Bridge/Twig",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/TwigBridge.git",
|
||||
"reference": "v2.3.2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/TwigBridge/zipball/v2.3.2",
|
||||
"reference": "v2.3.2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"twig/twig": "~1.11"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/form": "2.2.*",
|
||||
"symfony/http-kernel": "~2.2",
|
||||
"symfony/routing": "~2.2",
|
||||
"symfony/security": "~2.0",
|
||||
"symfony/templating": "~2.1",
|
||||
"symfony/translation": "~2.2",
|
||||
"symfony/yaml": "~2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/form": "",
|
||||
"symfony/http-kernel": "",
|
||||
"symfony/routing": "",
|
||||
"symfony/security": "",
|
||||
"symfony/templating": "",
|
||||
"symfony/translation": "",
|
||||
"symfony/yaml": ""
|
||||
},
|
||||
"type": "symfony-bridge",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Bridge\\Twig\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Twig Bridge",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2013-05-16 10:19:58"
|
||||
},
|
||||
{
|
||||
"name": "twig/extensions",
|
||||
"version": "v1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fabpot/Twig-extensions.git",
|
||||
"reference": "v1.0.0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/fabpot/Twig-extensions/zipball/v1.0.0",
|
||||
"reference": "v1.0.0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"twig/twig": "1.*"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Twig_Extensions_": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
}
|
||||
],
|
||||
"description": "Common additional features for Twig that do not directly belong in core",
|
||||
"homepage": "https://github.com/fabpot/Twig-extensions",
|
||||
"keywords": [
|
||||
"debug",
|
||||
"i18n",
|
||||
"text"
|
||||
],
|
||||
"time": "2013-02-28 14:21:30"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v1.13.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fabpot/Twig.git",
|
||||
"reference": "v1.13.2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/fabpot/Twig/zipball/v1.13.2",
|
||||
"reference": "v1.13.2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.13-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Twig_": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Armin Ronacher",
|
||||
"email": "armin.ronacher@active-4.com"
|
||||
}
|
||||
],
|
||||
"description": "Twig, the flexible, fast, and secure template language for PHP",
|
||||
"homepage": "http://twig.sensiolabs.org",
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"time": "2013-08-03 15:35:31"
|
||||
},
|
||||
{
|
||||
"name": "umpirsky/twig-gettext-extractor",
|
||||
"version": "1.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/umpirsky/Twig-Gettext-Extractor.git",
|
||||
"reference": "1.1.3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/umpirsky/Twig-Gettext-Extractor/zipball/1.1.3",
|
||||
"reference": "1.1.3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"symfony/filesystem": ">=2.0,<3.0",
|
||||
"symfony/form": ">=2.0,<3.0",
|
||||
"symfony/routing": ">=2.0,<3.0",
|
||||
"symfony/translation": ">=2.0,<3.0",
|
||||
"symfony/twig-bridge": ">=2.0,<3.0",
|
||||
"twig/extensions": "1.0.*",
|
||||
"twig/twig": ">=1.2.0,<2.0-dev"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/config": "2.1.*"
|
||||
},
|
||||
"bin": [
|
||||
"twig-gettext-extractor"
|
||||
],
|
||||
"type": "application",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Twig\\Gettext": "."
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Саша Стаменковић",
|
||||
"email": "umpirsky@gmail.com",
|
||||
"homepage": "http://umpirsky.com"
|
||||
}
|
||||
],
|
||||
"description": "The Twig Gettext Extractor is Poedit friendly tool which extracts translations from twig templates.",
|
||||
"time": "2013-02-14 16:41:48"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
|
||||
],
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [
|
||||
|
||||
],
|
||||
"platform": [
|
||||
|
||||
],
|
||||
"platform-dev": [
|
||||
|
||||
]
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
/*** GENERAL ***/
|
||||
body {
|
||||
color: #fff;
|
||||
background-color: #0d0d0d;
|
||||
}
|
||||
|
||||
a, a:hover, a:visited {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#main ul#links li a.current {
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#links a:hover, .backhome a:hover{
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
input[type=submit].delete {
|
||||
background : url('../img/dark/remove.png') no-repeat center center;
|
||||
color : transparent;
|
||||
}
|
||||
|
||||
#main .entrie {
|
||||
color: #fff;
|
||||
background-color: #000;
|
||||
border: 1px solid #fff;
|
||||
}
|
||||
|
||||
#main .entrie h2 a:hover {
|
||||
color: #29B1E3;
|
||||
}
|
||||
|
||||
a.fav span {
|
||||
background: url('../img/dark/star-on.png') no-repeat;
|
||||
}
|
||||
|
||||
a.fav span:hover {
|
||||
background: url('../img/dark/star-off.png') no-repeat;
|
||||
}
|
||||
|
||||
a.fav-off span {
|
||||
background: url('../img/dark/star-off.png') no-repeat;
|
||||
}
|
||||
|
||||
a.fav-off span:hover {
|
||||
background: url('../img/dark/star-on.png') no-repeat;
|
||||
}
|
||||
|
||||
a.archive span {
|
||||
background: url('../img/dark/checkmark-on.png') no-repeat;
|
||||
}
|
||||
|
||||
a.archive span:hover {
|
||||
background: url('../img/dark/checkmark-off.png') no-repeat;
|
||||
}
|
||||
|
||||
a.archive-off span {
|
||||
background: url('../img/dark/checkmark-off.png') no-repeat;
|
||||
}
|
||||
|
||||
a.archive-off span:hover {
|
||||
background: url('../img/dark/checkmark-on.png') no-repeat;
|
||||
}
|
||||
|
||||
/*** ***/
|
||||
/*** ARTICLE PAGE ***/
|
||||
|
||||
body.article {
|
||||
color: #fff;
|
||||
background-color: #0d0d0d;
|
||||
}
|
||||
|
||||
#article header {
|
||||
border-bottom: 1px solid #222222;
|
||||
}
|
||||
|
||||
#article article {
|
||||
border-bottom: 1px solid #222222;
|
||||
}
|
||||
|
||||
.vieworiginal a {
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.entrie {
|
||||
background-color: #fff;
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
/*** GENERAL ***/
|
||||
body {
|
||||
color: #222222;
|
||||
background-color: #F1F1F1;
|
||||
}
|
||||
|
||||
a, a:hover, a:visited {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.bouton {
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
border: none;
|
||||
}
|
||||
.bouton:hover {
|
||||
background-color: #222222;
|
||||
color: #F1F1F1;
|
||||
}
|
||||
|
||||
#main ul#links li a.current {
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#links a:hover, .backhome a:hover{
|
||||
background-color: #040707;
|
||||
color: #F1F1F1;
|
||||
}
|
||||
|
||||
input[type=submit].delete {
|
||||
background : url('../img/light/remove.png') no-repeat center center;
|
||||
color : transparent;
|
||||
}
|
||||
|
||||
#main .entrie {
|
||||
color: #2e2e2e;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #000;
|
||||
}
|
||||
|
||||
#main .entrie h2 a:hover {
|
||||
color: #F5BE00;
|
||||
}
|
||||
|
||||
a.fav span {
|
||||
background: url('../img/light/star-on.png') no-repeat;
|
||||
}
|
||||
|
||||
a.fav span:hover {
|
||||
background: url('../img/light/star-off.png') no-repeat;
|
||||
}
|
||||
|
||||
a.fav-off span {
|
||||
background: url('../img/light/star-off.png') no-repeat;
|
||||
}
|
||||
|
||||
a.fav-off span:hover {
|
||||
background: url('../img/light/star-on.png') no-repeat;
|
||||
}
|
||||
|
||||
a.archive span {
|
||||
background: url('../img/light/checkmark-on.png') no-repeat;
|
||||
}
|
||||
|
||||
a.archive span:hover {
|
||||
background: url('../img/light/checkmark-off.png') no-repeat;
|
||||
}
|
||||
|
||||
a.archive-off span {
|
||||
background: url('../img/light/checkmark-off.png') no-repeat;
|
||||
}
|
||||
|
||||
a.archive-off span:hover {
|
||||
background: url('../img/light/checkmark-on.png') no-repeat;
|
||||
}
|
||||
|
||||
/*** ***/
|
||||
/*** ARTICLE PAGE ***/
|
||||
|
||||
body.article {
|
||||
color: #222222;
|
||||
background-color: #F1F1F1;
|
||||
}
|
||||
|
||||
#article header {
|
||||
border-bottom: 1px solid #222222;
|
||||
}
|
||||
|
||||
#article article {
|
||||
border-bottom: 1px solid #222222;
|
||||
}
|
||||
|
||||
.vieworiginal a {
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.entrie {
|
||||
background-color: #fff;
|
||||
}
|
215
css/style.css
@ -1,215 +0,0 @@
|
||||
/*** GENERAL ***/
|
||||
body {
|
||||
font: 20px/1.3em Palatino,Georgia,serif;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
header {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.bouton {
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#main ul#links {
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#main ul#links li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#main ul#links li a.current {
|
||||
-webkit-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#main ul#sort {
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#main ul#sort li {
|
||||
display: inline;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
#main ul#sort img:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#main, #article {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#links a, .backhome a{
|
||||
text-decoration: none;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
#links a:hover, .backhome a:hover{
|
||||
-webkit-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
footer {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/*** ***/
|
||||
/*** LINKS DISPLAY ***/
|
||||
|
||||
#main a.tool {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type=submit].delete {
|
||||
width : 16px;
|
||||
height :16px;
|
||||
border : none;
|
||||
cursor: pointer;
|
||||
font-size : 0;
|
||||
}
|
||||
|
||||
#main #content {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#main .entrie {
|
||||
padding: 15px;
|
||||
min-height: 8em;
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
#main .entrie h2 a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.tools {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.tools ul {
|
||||
padding: 0; margin: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.tools ul li {
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.tools a.tool {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#article .tools {
|
||||
position: relative;
|
||||
display: inline;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#article .tools ul li{
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#main .entrie .tools a.tool span, #article .tools a.tool span {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
|
||||
/*** ***/
|
||||
/*** ARTICLE PAGE ***/
|
||||
|
||||
body.article {
|
||||
font: 20px/1.3em Palatino,Georgia,serif;
|
||||
}
|
||||
|
||||
#article header {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#article header a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.vieworiginal a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.backhome {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/*** ***/
|
||||
|
||||
#main
|
||||
{
|
||||
max-width: 60em; /* 960 px */
|
||||
margin: 0 auto;
|
||||
}
|
||||
#content
|
||||
{
|
||||
width: 103.125%; /* 990px */
|
||||
overflow: hidden;
|
||||
margin-left: -1.562%; /* 15px */
|
||||
margin-bottom: -1.875em; /* 30px */
|
||||
}
|
||||
|
||||
.entrie
|
||||
{
|
||||
width: 30.303%; /* 300px */
|
||||
background-color: #fff;
|
||||
float: left;
|
||||
margin: 0 1.515% 1.875em; /* 15px 30px */
|
||||
}
|
||||
|
||||
@media only screen and ( max-width: 40em ) /* 640px */
|
||||
{
|
||||
.entrie
|
||||
{
|
||||
width: 46.876%; /* 305px */
|
||||
margin-bottom: 0.938em; /* 15px */
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and ( max-width: 20em ) /* 320px */
|
||||
{
|
||||
#content
|
||||
{
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.entrie
|
||||
{
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*** ***/
|
||||
/*** MESSAGES ***/
|
||||
|
||||
.messages { width: 100%; -moz-border-radius: 4px; border-radius: 4px; display: block; padding: 10px 0; margin: 10px auto 10px; clear: both; }
|
||||
.messages a.closeMessage { margin: -14px -8px 0 0; display:none; width: 16px; height: 16px; float: right; background: url(../img/messages/close.png) no-repeat; }
|
||||
/*.messages:hover a.closeMessage { visibility:visible; }*/
|
||||
.messages p { margin: 3px 0 3px 10px !important; padding: 0 10px 0 23px !important; font-size: 14px; line-height: 16px; }
|
||||
.messages.error { border: 1px solid #C42608; color: #c00 !important; background: #FFF0EF; }
|
||||
.messages.error p { background: url(../img/messages/cross.png ) no-repeat 0px 50%; color:#c00 !important; }
|
||||
.messages.success {background: #E0FBCC; border: 1px solid #6DC70C; }
|
||||
.messages.success p { background: url(../img/messages/tick.png) no-repeat 0px 50%; color: #2B6301 !important; }
|
||||
.messages.warning { background: #FFFCD3; border: 1px solid #EBCD41; color: #000; }
|
||||
.messages.warning p { background: url(../img/messages/warning.png ) no-repeat 0px 50%; color: #5F4E01; }
|
||||
.messages.information, .messages.info { background: #DFEBFB; border: 1px solid #82AEE7; }
|
||||
.messages.information p, .messages.info p { background: url(../img/messages/help.png ) no-repeat 0px 50%; color: #064393; }
|
||||
.messages.information a { text-decoration: underline; }
|
Before Width: | Height: | Size: 267 B |
Before Width: | Height: | Size: 221 B |
Before Width: | Height: | Size: 223 B |
Before Width: | Height: | Size: 786 B |
Before Width: | Height: | Size: 265 B |
Before Width: | Height: | Size: 330 B |
Before Width: | Height: | Size: 277 B |
BIN
img/dark/up.png
Before Width: | Height: | Size: 225 B |
BIN
img/logo.png
Before Width: | Height: | Size: 911 B |
50
import.php
@ -1,50 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* poche, a read it later open source system
|
||||
*
|
||||
* @category poche
|
||||
* @author Nicolas Lœuillet <support@inthepoche.com>
|
||||
* @copyright 2013
|
||||
* @license http://www.wtfpl.net/ see COPYING file
|
||||
*/
|
||||
|
||||
set_time_limit(0);
|
||||
|
||||
include dirname(__FILE__).'/inc/config.php';
|
||||
include dirname(__FILE__).'/inc/simple_html_dom.php';
|
||||
|
||||
if (!isset($_GET['start'])) {
|
||||
echo 'Please execute the import script locally, it can take a very long time. <br /><a href="import.php?start">Bye bye Pocket, let\'s go !</a>';
|
||||
}
|
||||
else {
|
||||
$html = new simple_html_dom();
|
||||
$html->load_file('ril_export.html');
|
||||
|
||||
$read = 0;
|
||||
$errors = array();
|
||||
foreach($html->find('ul') as $ul)
|
||||
{
|
||||
foreach($ul->find('li') as $li)
|
||||
{
|
||||
$a = $li->find('a');
|
||||
$url = $a[0]->href;
|
||||
|
||||
|
||||
action_to_do('add', $url);
|
||||
if ($read == '1') {
|
||||
$last_id = $db->getHandle()->lastInsertId();
|
||||
$sql_update = "UPDATE entries SET is_read=~is_read WHERE id=?";
|
||||
$params_update = array($last_id);
|
||||
$query_update = $db->getHandle()->prepare($sql_update);
|
||||
$query_update->execute($params_update);
|
||||
}
|
||||
}
|
||||
# Pocket génère un fichier HTML avec deux <ul>
|
||||
# Le premier concerne les éléments non lus
|
||||
# Le second concerne les éléments archivés
|
||||
$read = 1;
|
||||
}
|
||||
|
||||
echo 'Import from Pocket completed. <a href="index.php">Welcome to #poche !</a>';
|
||||
logm('import from pocket completed');
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
*
|
||||
* This class extends PHP's DOMElement to allow
|
||||
* users to get and set the innerHTML property of
|
||||
* HTML elements in the same way it's done in
|
||||
* HTML elements in the same way it's done in
|
||||
* JavaScript.
|
||||
*
|
||||
* Example usage:
|
||||
@ -15,16 +15,16 @@
|
||||
* $doc->registerNodeClass('DOMElement', 'JSLikeHTMLElement');
|
||||
* $doc->loadHTML('<div><p>Para 1</p><p>Para 2</p></div>');
|
||||
* $elem = $doc->getElementsByTagName('div')->item(0);
|
||||
*
|
||||
*
|
||||
* // print innerHTML
|
||||
* echo $elem->innerHTML; // prints '<p>Para 1</p><p>Para 2</p>'
|
||||
* echo "\n\n";
|
||||
*
|
||||
*
|
||||
* // set innerHTML
|
||||
* $elem->innerHTML = '<a href="http://fivefilters.org">FiveFilters.org</a>';
|
||||
* echo $elem->innerHTML; // prints '<a href="http://fivefilters.org">FiveFilters.org</a>'
|
||||
* echo "\n\n";
|
||||
*
|
||||
*
|
||||
* // print document (with our changes)
|
||||
* echo $doc->saveXML();
|
||||
* @endcode
|
||||
@ -59,7 +59,7 @@ class JSLikeHTMLElement extends DOMElement
|
||||
$value = mb_convert_encoding($value, 'HTML-ENTITIES', 'UTF-8');
|
||||
// Using <htmlfragment> will generate a warning, but so will bad HTML
|
||||
// (and by this point, bad HTML is what we've got).
|
||||
// We use it (and suppress the warning) because an HTML fragment will
|
||||
// We use it (and suppress the warning) because an HTML fragment will
|
||||
// be wrapped around <html><body> tags which we don't really want to keep.
|
||||
// Note: despite the warning, if loadHTML succeeds it will return true.
|
||||
$result = @$f->loadHTML('<htmlfragment>'.$value.'</htmlfragment>');
|
||||
@ -86,7 +86,7 @@ class JSLikeHTMLElement extends DOMElement
|
||||
* @code
|
||||
* $string = $div->innerHTML;
|
||||
* @endcode
|
||||
*/
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
if ($name == 'innerHTML') {
|
198
inc/Readability.php → inc/3rdparty/Readability.php
vendored
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
/**
|
||||
/**
|
||||
* Arc90's Readability ported to PHP for FiveFilters.org
|
||||
* Based on readability.js version 1.7.1 (without multi-page support)
|
||||
* Updated to allow HTML5 parsing with html5lib
|
||||
@ -13,34 +13,34 @@
|
||||
* License: Apache License, Version 2.0
|
||||
* Requires: PHP5
|
||||
* Date: 2012-09-19
|
||||
*
|
||||
*
|
||||
* Differences between the PHP port and the original
|
||||
* ------------------------------------------------------
|
||||
* Arc90's Readability is designed to run in the browser. It works on the DOM
|
||||
* tree (the parsed HTML) after the page's CSS styles have been applied and
|
||||
* Javascript code executed. This PHP port does not run inside a browser.
|
||||
* We use PHP's ability to parse HTML to build our DOM tree, but we cannot
|
||||
* rely on CSS or Javascript support. As such, the results will not always
|
||||
* match Arc90's Readability. (For example, if a web page contains CSS style
|
||||
* rules or Javascript code which hide certain HTML elements from display,
|
||||
* Arc90's Readability will dismiss those from consideration but our PHP port,
|
||||
* Arc90's Readability is designed to run in the browser. It works on the DOM
|
||||
* tree (the parsed HTML) after the page's CSS styles have been applied and
|
||||
* Javascript code executed. This PHP port does not run inside a browser.
|
||||
* We use PHP's ability to parse HTML to build our DOM tree, but we cannot
|
||||
* rely on CSS or Javascript support. As such, the results will not always
|
||||
* match Arc90's Readability. (For example, if a web page contains CSS style
|
||||
* rules or Javascript code which hide certain HTML elements from display,
|
||||
* Arc90's Readability will dismiss those from consideration but our PHP port,
|
||||
* unable to understand CSS or Javascript, will not know any better.)
|
||||
*
|
||||
* Another significant difference is that the aim of Arc90's Readability is
|
||||
* to re-present the main content block of a given web page so users can
|
||||
* read it more easily in their browsers. Correct identification, clean up,
|
||||
* and separation of the content block is only a part of this process.
|
||||
* This PHP port is only concerned with this part, it does not include code
|
||||
* that relates to presentation in the browser - Arc90 already do
|
||||
* that extremely well, and for PDF output there's FiveFilters.org's
|
||||
*
|
||||
* Another significant difference is that the aim of Arc90's Readability is
|
||||
* to re-present the main content block of a given web page so users can
|
||||
* read it more easily in their browsers. Correct identification, clean up,
|
||||
* and separation of the content block is only a part of this process.
|
||||
* This PHP port is only concerned with this part, it does not include code
|
||||
* that relates to presentation in the browser - Arc90 already do
|
||||
* that extremely well, and for PDF output there's FiveFilters.org's
|
||||
* PDF Newspaper: http://fivefilters.org/pdf-newspaper/.
|
||||
*
|
||||
* Finally, this class contains methods that might be useful for developers
|
||||
* working on HTML document fragments. So without deviating too much from
|
||||
* the original code (which I don't want to do because it makes debugging
|
||||
* and updating more difficult), I've tried to make it a little more
|
||||
* developer friendly. You should be able to use the methods here on
|
||||
* existing DOMElement objects without passing an entire HTML document to
|
||||
*
|
||||
* Finally, this class contains methods that might be useful for developers
|
||||
* working on HTML document fragments. So without deviating too much from
|
||||
* the original code (which I don't want to do because it makes debugging
|
||||
* and updating more difficult), I've tried to make it a little more
|
||||
* developer friendly. You should be able to use the methods here on
|
||||
* existing DOMElement objects without passing an entire HTML document to
|
||||
* be parsed.
|
||||
*/
|
||||
|
||||
@ -48,7 +48,7 @@
|
||||
require_once(dirname(__FILE__).'/JSLikeHTMLElement.php');
|
||||
|
||||
// Alternative usage (for testing only!)
|
||||
// uncomment the lines below and call Readability.php in your browser
|
||||
// uncomment the lines below and call Readability.php in your browser
|
||||
// passing it the URL of the page you'd like content from, e.g.:
|
||||
// Readability.php?url=http://medialens.org/alerts/09/090615_the_guardian_climate.php
|
||||
|
||||
@ -75,11 +75,11 @@ class Readability
|
||||
public $url = null; // optional - URL where HTML was retrieved
|
||||
public $debug = false;
|
||||
public $lightClean = true; // preserves more content (experimental) added 2012-09-19
|
||||
protected $body = null; //
|
||||
protected $body = null; //
|
||||
protected $bodyCache = null; // Cache the body HTML in case we need to re-use it later
|
||||
protected $flags = 7; // 1 | 2 | 4; // Start with all flags set.
|
||||
protected $success = false; // indicates whether we were able to extract or not
|
||||
|
||||
|
||||
/**
|
||||
* All of the regular expressions in use within readability.
|
||||
* Defined up here so we don't instantiate them repeatedly in loops.
|
||||
@ -97,19 +97,19 @@ class Readability
|
||||
'killBreaks' => '/(<br\s*\/?>(\s| ?)*){1,}/',
|
||||
'video' => '!//(player\.|www\.)?(youtube|vimeo|viddler)\.com!i',
|
||||
'skipFootnoteLink' => '/^\s*(\[?[a-z0-9]{1,2}\]?|^|edit|citation needed)\s*$/i'
|
||||
);
|
||||
|
||||
);
|
||||
|
||||
/* constants */
|
||||
const FLAG_STRIP_UNLIKELYS = 1;
|
||||
const FLAG_WEIGHT_CLASSES = 2;
|
||||
const FLAG_CLEAN_CONDITIONALLY = 4;
|
||||
|
||||
|
||||
/**
|
||||
* Create instance of Readability
|
||||
* @param string UTF-8 encoded string
|
||||
* @param string (optional) URL associated with HTML (used for footnotes)
|
||||
* @param string which parser to use for turning raw HTML into a DOMDocument (either 'libxml' or 'html5lib')
|
||||
*/
|
||||
*/
|
||||
function __construct($html, $url=null, $parser='libxml')
|
||||
{
|
||||
$this->url = $url;
|
||||
@ -135,18 +135,18 @@ class Readability
|
||||
public function getTitle() {
|
||||
return $this->articleTitle;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get article content element
|
||||
* @return DOMElement
|
||||
*/
|
||||
public function getContent() {
|
||||
return $this->articleContent;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs readability.
|
||||
*
|
||||
*
|
||||
* Workflow:
|
||||
* 1. Prep the document by removing script tags, css, etc.
|
||||
* 2. Build readability's DOM tree.
|
||||
@ -161,7 +161,7 @@ class Readability
|
||||
if (!isset($this->dom->documentElement)) return false;
|
||||
$this->removeScripts($this->dom);
|
||||
//die($this->getInnerHTML($this->dom->documentElement));
|
||||
|
||||
|
||||
// Assume successful outcome
|
||||
$this->success = true;
|
||||
|
||||
@ -176,7 +176,7 @@ class Readability
|
||||
}
|
||||
|
||||
$this->prepDocument();
|
||||
|
||||
|
||||
//die($this->dom->documentElement->parentNode->nodeType);
|
||||
//$this->setInnerHTML($this->dom->documentElement, $this->getInnerHTML($this->dom->documentElement));
|
||||
//die($this->getInnerHTML($this->dom->documentElement));
|
||||
@ -191,9 +191,9 @@ class Readability
|
||||
$this->success = false;
|
||||
$articleContent = $this->dom->createElement('div');
|
||||
$articleContent->setAttribute('id', 'readability-content');
|
||||
$articleContent->innerHTML = '<p>Sorry, Readability was unable to parse this page for content.</p>';
|
||||
$articleContent->innerHTML = '<p>Sorry, Readability was unable to parse this page for content.</p>';
|
||||
}
|
||||
|
||||
|
||||
$overlay->setAttribute('id', 'readOverlay');
|
||||
$innerDiv->setAttribute('id', 'readInner');
|
||||
|
||||
@ -201,7 +201,7 @@ class Readability
|
||||
$innerDiv->appendChild($articleTitle);
|
||||
$innerDiv->appendChild($articleContent);
|
||||
$overlay->appendChild($innerDiv);
|
||||
|
||||
|
||||
/* Clear the old HTML, insert the new content. */
|
||||
$this->body->innerHTML = '';
|
||||
$this->body->appendChild($overlay);
|
||||
@ -209,21 +209,21 @@ class Readability
|
||||
$this->body->removeAttribute('style');
|
||||
|
||||
$this->postProcessContent($articleContent);
|
||||
|
||||
|
||||
// Set title and content instance variables
|
||||
$this->articleTitle = $articleTitle;
|
||||
$this->articleContent = $articleContent;
|
||||
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Debug
|
||||
*/
|
||||
protected function dbg($msg) {
|
||||
if ($this->debug) echo '* ',$msg, "\n";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run any post-process modifications to article content as necessary.
|
||||
*
|
||||
@ -231,11 +231,11 @@ class Readability
|
||||
* @return void
|
||||
*/
|
||||
public function postProcessContent($articleContent) {
|
||||
if ($this->convertLinksToFootnotes && !preg_match('/wikipedia\.org/', @$this->url)) {
|
||||
if ($this->convertLinksToFootnotes && !preg_match('/wikipedia\.org/', @$this->url)) {
|
||||
$this->addFootnotes($articleContent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the article title as an H1.
|
||||
*
|
||||
@ -248,11 +248,11 @@ class Readability
|
||||
try {
|
||||
$curTitle = $origTitle = $this->getInnerText($this->dom->getElementsByTagName('title')->item(0));
|
||||
} catch(Exception $e) {}
|
||||
|
||||
|
||||
if (preg_match('/ [\|\-] /', $curTitle))
|
||||
{
|
||||
$curTitle = preg_replace('/(.*)[\|\-] .*/i', '$1', $origTitle);
|
||||
|
||||
|
||||
if (count(explode(' ', $curTitle)) < 3) {
|
||||
$curTitle = preg_replace('/[^\|\-]*[\|\-](.*)/i', '$1', $origTitle);
|
||||
}
|
||||
@ -279,17 +279,17 @@ class Readability
|
||||
if (count(explode(' ', $curTitle)) <= 4) {
|
||||
$curTitle = $origTitle;
|
||||
}
|
||||
|
||||
|
||||
$articleTitle = $this->dom->createElement('h1');
|
||||
$articleTitle->innerHTML = $curTitle;
|
||||
|
||||
|
||||
return $articleTitle;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare the HTML document for readability to scrape it.
|
||||
* This includes things like stripping javascript, CSS, and handling terrible markup.
|
||||
*
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
protected function prepDocument() {
|
||||
@ -328,13 +328,13 @@ class Readability
|
||||
$footnotesWrapper = $this->dom->createElement('div');
|
||||
$footnotesWrapper->setAttribute('id', 'readability-footnotes');
|
||||
$footnotesWrapper->innerHTML = '<h3>References</h3>';
|
||||
|
||||
|
||||
$articleFootnotes = $this->dom->createElement('ol');
|
||||
$articleFootnotes->setAttribute('id', 'readability-footnotes-list');
|
||||
$footnotesWrapper->appendChild($articleFootnotes);
|
||||
|
||||
|
||||
$articleLinks = $articleContent->getElementsByTagName('a');
|
||||
|
||||
|
||||
$linkCount = 0;
|
||||
for ($i = 0; $i < $articleLinks->length; $i++)
|
||||
{
|
||||
@ -346,11 +346,11 @@ class Readability
|
||||
if (!$linkDomain && isset($this->url)) $linkDomain = @parse_url($this->url, PHP_URL_HOST);
|
||||
//linkDomain = footnoteLink.host ? footnoteLink.host : document.location.host,
|
||||
$linkText = $this->getInnerText($articleLink);
|
||||
|
||||
|
||||
if ((strpos($articleLink->getAttribute('class'), 'readability-DoNotFootnote') !== false) || preg_match($this->regexps['skipFootnoteLink'], $linkText)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$linkCount++;
|
||||
|
||||
/** Add a superscript reference after the article link */
|
||||
@ -358,7 +358,7 @@ class Readability
|
||||
$refLink->innerHTML = '<small><sup>[' . $linkCount . ']</sup></small>';
|
||||
$refLink->setAttribute('class', 'readability-DoNotFootnote');
|
||||
$refLink->setAttribute('style', 'color: inherit;');
|
||||
|
||||
|
||||
//TODO: does this work or should we use DOMNode.isSameNode()?
|
||||
if ($articleLink->parentNode->lastChild == $articleLink) {
|
||||
$articleLink->parentNode->appendChild($refLink);
|
||||
@ -373,15 +373,15 @@ class Readability
|
||||
|
||||
$footnoteLink->innerHTML = ($footnoteLink->getAttribute('title') != '' ? $footnoteLink->getAttribute('title') : $linkText);
|
||||
$footnoteLink->setAttribute('name', 'readabilityFootnoteLink-' . $linkCount);
|
||||
|
||||
|
||||
$footnote->appendChild($footnoteLink);
|
||||
if ($linkDomain) $footnote->innerHTML = $footnote->innerHTML . '<small> (' . $linkDomain . ')</small>';
|
||||
|
||||
|
||||
$articleFootnotes->appendChild($footnote);
|
||||
}
|
||||
|
||||
if ($linkCount > 0) {
|
||||
$articleContent->appendChild($footnotesWrapper);
|
||||
$articleContent->appendChild($footnotesWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
@ -404,7 +404,7 @@ class Readability
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare the article node for display. Clean out any inline styles,
|
||||
* iframes, forms, strip extraneous <p> tags, etc.
|
||||
@ -429,7 +429,7 @@ class Readability
|
||||
* as a header and not a subheader, so remove it since we already have a header.
|
||||
***/
|
||||
if (!$this->lightClean && ($articleContent->getElementsByTagName('h2')->length == 1)) {
|
||||
$this->clean($articleContent, 'h2');
|
||||
$this->clean($articleContent, 'h2');
|
||||
}
|
||||
$this->clean($articleContent, 'iframe');
|
||||
|
||||
@ -448,7 +448,7 @@ class Readability
|
||||
$embedCount = $articleParagraphs->item($i)->getElementsByTagName('embed')->length;
|
||||
$objectCount = $articleParagraphs->item($i)->getElementsByTagName('object')->length;
|
||||
$iframeCount = $articleParagraphs->item($i)->getElementsByTagName('iframe')->length;
|
||||
|
||||
|
||||
if ($imgCount === 0 && $embedCount === 0 && $objectCount === 0 && $iframeCount === 0 && $this->getInnerText($articleParagraphs->item($i), false) == '')
|
||||
{
|
||||
$articleParagraphs->item($i)->parentNode->removeChild($articleParagraphs->item($i));
|
||||
@ -457,13 +457,13 @@ class Readability
|
||||
|
||||
try {
|
||||
$articleContent->innerHTML = preg_replace('/<br[^>]*>\s*<p/i', '<p', $articleContent->innerHTML);
|
||||
//articleContent.innerHTML = articleContent.innerHTML.replace(/<br[^>]*>\s*<p/gi, '<p');
|
||||
//articleContent.innerHTML = articleContent.innerHTML.replace(/<br[^>]*>\s*<p/gi, '<p');
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$this->dbg("Cleaning innerHTML of breaks failed. This is an IE strict-block-elements bug. Ignoring.: " . $e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a node with the readability object. Also checks the
|
||||
* className/id for special names to add to its score.
|
||||
@ -474,7 +474,7 @@ class Readability
|
||||
protected function initializeNode($node) {
|
||||
$readability = $this->dom->createAttribute('readability');
|
||||
$readability->value = 0; // this is our contentScore
|
||||
$node->setAttributeNode($readability);
|
||||
$node->setAttributeNode($readability);
|
||||
|
||||
switch (strtoupper($node->tagName)) { // unsure if strtoupper is needed, but using it just in case
|
||||
case 'DIV':
|
||||
@ -486,7 +486,7 @@ class Readability
|
||||
case 'BLOCKQUOTE':
|
||||
$readability->value += 3;
|
||||
break;
|
||||
|
||||
|
||||
case 'ADDRESS':
|
||||
case 'OL':
|
||||
case 'UL':
|
||||
@ -510,7 +510,7 @@ class Readability
|
||||
}
|
||||
$readability->value += $this->getClassWeight($node);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* grabArticle - Using a variety of metrics (content score, classname, element types), find the content that is
|
||||
* most likely to be the stuff a user wants to read. Then return it wrapped up in a div.
|
||||
@ -548,7 +548,7 @@ class Readability
|
||||
$node->parentNode->removeChild($node);
|
||||
$nodeIndex--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($tagName == 'P' || $tagName == 'TD' || $tagName == 'PRE') {
|
||||
@ -589,7 +589,7 @@ class Readability
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loop through all paragraphs, and assign a score to them based on how content-y they look.
|
||||
* Then add their score to their parent node.
|
||||
@ -613,7 +613,7 @@ class Readability
|
||||
}
|
||||
|
||||
/* Initialize readability data for the parent. */
|
||||
if (!$parentNode->hasAttribute('readability'))
|
||||
if (!$parentNode->hasAttribute('readability'))
|
||||
{
|
||||
$this->initializeNode($parentNode);
|
||||
$candidates[] = $parentNode;
|
||||
@ -633,15 +633,15 @@ class Readability
|
||||
|
||||
/* Add points for any commas within this paragraph */
|
||||
$contentScore += count(explode(',', $innerText));
|
||||
|
||||
|
||||
/* For every 100 characters in this paragraph, add another point. Up to 3 points. */
|
||||
$contentScore += min(floor(strlen($innerText) / 100), 3);
|
||||
|
||||
|
||||
/* Add the score to the parent. The grandparent gets half. */
|
||||
$parentNode->getAttributeNode('readability')->value += $contentScore;
|
||||
|
||||
if ($grandParentNode) {
|
||||
$grandParentNode->getAttributeNode('readability')->value += $contentScore/2;
|
||||
$grandParentNode->getAttributeNode('readability')->value += $contentScore/2;
|
||||
}
|
||||
}
|
||||
|
||||
@ -727,12 +727,12 @@ class Readability
|
||||
{
|
||||
$append = true;
|
||||
}
|
||||
|
||||
|
||||
if (strtoupper($siblingNode->nodeName) == 'P') {
|
||||
$linkDensity = $this->getLinkDensity($siblingNode);
|
||||
$nodeContent = $this->getInnerText($siblingNode);
|
||||
$nodeLength = strlen($nodeContent);
|
||||
|
||||
|
||||
if ($nodeLength > 80 && $linkDensity < 0.25)
|
||||
{
|
||||
$append = true;
|
||||
@ -751,7 +751,7 @@ class Readability
|
||||
$sibNodeName = strtoupper($siblingNode->nodeName);
|
||||
if ($sibNodeName != 'DIV' && $sibNodeName != 'P') {
|
||||
/* We have a node that isn't a common block level element, like a form or td tag. Turn it into a div so it doesn't get filtered out later by accident. */
|
||||
|
||||
|
||||
$this->dbg('Altering siblingNode of ' . $sibNodeName . ' to div.');
|
||||
$nodeToAppend = $this->dom->createElement('div');
|
||||
try {
|
||||
@ -770,7 +770,7 @@ class Readability
|
||||
$s--;
|
||||
$sl--;
|
||||
}
|
||||
|
||||
|
||||
/* To ensure a node does not interfere with readability styles, remove its classnames */
|
||||
$nodeToAppend->removeAttribute('class');
|
||||
|
||||
@ -796,14 +796,14 @@ class Readability
|
||||
// in the meantime, we check and create an empty element if it's not there.
|
||||
if (!isset($this->body->childNodes)) $this->body = $this->dom->createElement('body');
|
||||
$this->body->innerHTML = $this->bodyCache;
|
||||
|
||||
|
||||
if ($this->flagIsActive(self::FLAG_STRIP_UNLIKELYS)) {
|
||||
$this->removeFlag(self::FLAG_STRIP_UNLIKELYS);
|
||||
return $this->grabArticle($this->body);
|
||||
}
|
||||
else if ($this->flagIsActive(self::FLAG_WEIGHT_CLASSES)) {
|
||||
$this->removeFlag(self::FLAG_WEIGHT_CLASSES);
|
||||
return $this->grabArticle($this->body);
|
||||
return $this->grabArticle($this->body);
|
||||
}
|
||||
else if ($this->flagIsActive(self::FLAG_CLEAN_CONDITIONALLY)) {
|
||||
$this->removeFlag(self::FLAG_CLEAN_CONDITIONALLY);
|
||||
@ -815,7 +815,7 @@ class Readability
|
||||
}
|
||||
return $articleContent;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove script tags from document
|
||||
*
|
||||
@ -829,7 +829,7 @@ class Readability
|
||||
$scripts->item($i)->parentNode->removeChild($scripts->item($i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the inner text of a node.
|
||||
* This also strips out any excess whitespace to be found.
|
||||
@ -878,11 +878,11 @@ class Readability
|
||||
$elem->removeAttribute('style');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the density of links as a percentage of the content
|
||||
* This is the amount of text that is inside a link divided by the total text in the node.
|
||||
*
|
||||
*
|
||||
* @param DOMElement $e
|
||||
* @return number (float)
|
||||
*/
|
||||
@ -900,9 +900,9 @@ class Readability
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get an elements class/id weight. Uses regular expressions to tell if this
|
||||
* Get an elements class/id weight. Uses regular expressions to tell if this
|
||||
* element looks good or bad.
|
||||
*
|
||||
* @param DOMElement $e
|
||||
@ -964,7 +964,7 @@ class Readability
|
||||
public function clean($e, $tag) {
|
||||
$targetList = $e->getElementsByTagName($tag);
|
||||
$isEmbed = ($tag == 'iframe' || $tag == 'object' || $tag == 'embed');
|
||||
|
||||
|
||||
for ($y=$targetList->length-1; $y >= 0; $y--) {
|
||||
/* Allow youtube and vimeo videos through as people usually want to see those. */
|
||||
if ($isEmbed) {
|
||||
@ -972,7 +972,7 @@ class Readability
|
||||
for ($i=0, $il=$targetList->item($y)->attributes->length; $i < $il; $i++) {
|
||||
$attributeValues .= $targetList->item($y)->attributes->item($i)->value . '|'; // DOMAttr? (TODO: test)
|
||||
}
|
||||
|
||||
|
||||
/* First, check the elements attributes to see if any of them contain youtube or vimeo */
|
||||
if (preg_match($this->regexps['video'], $attributeValues)) {
|
||||
continue;
|
||||
@ -986,10 +986,10 @@ class Readability
|
||||
$targetList->item($y)->parentNode->removeChild($targetList->item($y));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clean an element of all tags of type "tag" if they look fishy.
|
||||
* "Fishy" is an algorithm based on content length, classnames,
|
||||
* "Fishy" is an algorithm based on content length, classnames,
|
||||
* link density, number of images & embeds, etc.
|
||||
*
|
||||
* @param DOMElement $e
|
||||
@ -1013,7 +1013,7 @@ class Readability
|
||||
for ($i=$curTagsLength-1; $i >= 0; $i--) {
|
||||
$weight = $this->getClassWeight($tagsList->item($i));
|
||||
$contentScore = ($tagsList->item($i)->hasAttribute('readability')) ? (int)$tagsList->item($i)->getAttribute('readability') : 0;
|
||||
|
||||
|
||||
$this->dbg('Cleaning Conditionally ' . $tagsList->item($i)->tagName . ' (' . $tagsList->item($i)->getAttribute('class') . ':' . $tagsList->item($i)->getAttribute('id') . ')' . (($tagsList->item($i)->hasAttribute('readability')) ? (' with score ' . $tagsList->item($i)->getAttribute('readability')) : ''));
|
||||
|
||||
if ($weight + $contentScore < 0) {
|
||||
@ -1034,13 +1034,13 @@ class Readability
|
||||
$embeds = $tagsList->item($i)->getElementsByTagName('embed');
|
||||
for ($ei=0, $il=$embeds->length; $ei < $il; $ei++) {
|
||||
if (preg_match($this->regexps['video'], $embeds->item($ei)->getAttribute('src'))) {
|
||||
$embedCount++;
|
||||
$embedCount++;
|
||||
}
|
||||
}
|
||||
$embeds = $tagsList->item($i)->getElementsByTagName('iframe');
|
||||
for ($ei=0, $il=$embeds->length; $ei < $il; $ei++) {
|
||||
if (preg_match($this->regexps['video'], $embeds->item($ei)->getAttribute('src'))) {
|
||||
$embedCount++;
|
||||
$embedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1058,7 +1058,7 @@ class Readability
|
||||
$toRemove = true;
|
||||
} else if ( $input > floor($p/3) ) {
|
||||
$this->dbg(' too many <input> elements');
|
||||
$toRemove = true;
|
||||
$toRemove = true;
|
||||
} else if ($contentLength < 25 && ($embedCount === 0 && ($img === 0 || $img > 2))) {
|
||||
$this->dbg(' content length less than 25 chars, 0 embeds and either 0 images or more than 2 images');
|
||||
$toRemove = true;
|
||||
@ -1082,7 +1082,7 @@ class Readability
|
||||
$toRemove = true;
|
||||
} else if ( $input > floor($p/3) ) {
|
||||
$this->dbg(' too many <input> elements');
|
||||
$toRemove = true;
|
||||
$toRemove = true;
|
||||
} else if ($contentLength < 25 && ($img === 0 || $img > 2) ) {
|
||||
$this->dbg(' content length less than 25 chars and 0 images, or more than 2 images');
|
||||
$toRemove = true;
|
||||
@ -1126,11 +1126,11 @@ class Readability
|
||||
public function flagIsActive($flag) {
|
||||
return ($this->flags & $flag) > 0;
|
||||
}
|
||||
|
||||
|
||||
public function addFlag($flag) {
|
||||
$this->flags = $this->flags | $flag;
|
||||
}
|
||||
|
||||
|
||||
public function removeFlag($flag) {
|
||||
$this->flags = $this->flags & ~$flag;
|
||||
}
|
@ -93,7 +93,7 @@ class Session
|
||||
// Force logout
|
||||
public static function logout()
|
||||
{
|
||||
unset($_SESSION['uid'],$_SESSION['info'],$_SESSION['expires_on'],$_SESSION['tokens'], $_SESSION['login'], $_SESSION['pass']);
|
||||
unset($_SESSION['uid'],$_SESSION['info'],$_SESSION['expires_on'],$_SESSION['tokens'], $_SESSION['login'], $_SESSION['pass'], $_SESSION['poche_user']);
|
||||
}
|
||||
|
||||
// Make sure user is logged in.
|
460
inc/class.messages.php → inc/3rdparty/class.messages.php
vendored
Normal file → Executable file
@ -1,231 +1,231 @@
|
||||
<?php
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Session-Based Flash Messages v1.0
|
||||
// Copyright 2012 Mike Everhart (http://mikeeverhart.net)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
// Description:
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Stores messages in Session data to be easily retrieved later on.
|
||||
// This class includes four different types of messages:
|
||||
// - Success
|
||||
// - Error
|
||||
// - Warning
|
||||
// - Information
|
||||
//
|
||||
// See README for basic usage instructions, or see samples/index.php for more advanced samples
|
||||
//
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Changelog
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// 2011-05-15 - v1.0 - Initial Version
|
||||
//
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
class Messages {
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
// Class Variables
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
var $msgId;
|
||||
var $msgTypes = array( 'help', 'info', 'warning', 'success', 'error' );
|
||||
var $msgClass = 'messages';
|
||||
var $msgWrapper = "<div class='%s %s'><a href='#' class='closeMessage'></a>\n%s</div>\n";
|
||||
var $msgBefore = '<p>';
|
||||
var $msgAfter = "</p>\n";
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @author Mike Everhart
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
// Generate a unique ID for this user and session
|
||||
$this->msgId = md5(uniqid());
|
||||
|
||||
// Create the session array if it doesnt already exist
|
||||
if( !array_key_exists('flash_messages', $_SESSION) ) $_SESSION['flash_messages'] = array();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a message to the queue
|
||||
*
|
||||
* @author Mike Everhart
|
||||
*
|
||||
* @param string $type The type of message to add
|
||||
* @param string $message The message
|
||||
* @param string $redirect_to (optional) If set, the user will be redirected to this URL
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public function add($type, $message, $redirect_to=null) {
|
||||
|
||||
if( !isset($_SESSION['flash_messages']) ) return false;
|
||||
|
||||
if( !isset($type) || !isset($message[0]) ) return false;
|
||||
|
||||
// Replace any shorthand codes with their full version
|
||||
if( strlen(trim($type)) == 1 ) {
|
||||
$type = str_replace( array('h', 'i', 'w', 'e', 's'), array('help', 'info', 'warning', 'error', 'success'), $type );
|
||||
|
||||
// Backwards compatibility...
|
||||
} elseif( $type == 'information' ) {
|
||||
$type = 'info';
|
||||
}
|
||||
|
||||
// Make sure it's a valid message type
|
||||
if( !in_array($type, $this->msgTypes) ) die('"' . strip_tags($type) . '" is not a valid message type!' );
|
||||
|
||||
// If the session array doesn't exist, create it
|
||||
if( !array_key_exists( $type, $_SESSION['flash_messages'] ) ) $_SESSION['flash_messages'][$type] = array();
|
||||
|
||||
$_SESSION['flash_messages'][$type][] = $message;
|
||||
|
||||
if( !is_null($redirect_to) ) {
|
||||
header("Location: $redirect_to");
|
||||
exit();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
// display()
|
||||
// print queued messages to the screen
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Display the queued messages
|
||||
*
|
||||
* @author Mike Everhart
|
||||
*
|
||||
* @param string $type Which messages to display
|
||||
* @param bool $print True = print the messages on the screen
|
||||
* @return mixed
|
||||
*
|
||||
*/
|
||||
public function display($type='all', $print=true) {
|
||||
$messages = '';
|
||||
$data = '';
|
||||
|
||||
if( !isset($_SESSION['flash_messages']) ) return false;
|
||||
|
||||
if( $type == 'g' || $type == 'growl' ) {
|
||||
$this->displayGrowlMessages();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Print a certain type of message?
|
||||
if( in_array($type, $this->msgTypes) ) {
|
||||
foreach( $_SESSION['flash_messages'][$type] as $msg ) {
|
||||
$messages .= $this->msgBefore . $msg . $this->msgAfter;
|
||||
}
|
||||
|
||||
$data .= sprintf($this->msgWrapper, $this->msgClass, $type, $messages);
|
||||
|
||||
// Clear the viewed messages
|
||||
$this->clear($type);
|
||||
|
||||
// Print ALL queued messages
|
||||
} elseif( $type == 'all' ) {
|
||||
foreach( $_SESSION['flash_messages'] as $type => $msgArray ) {
|
||||
$messages = '';
|
||||
foreach( $msgArray as $msg ) {
|
||||
$messages .= $this->msgBefore . $msg . $this->msgAfter;
|
||||
}
|
||||
$data .= sprintf($this->msgWrapper, $this->msgClass, $type, $messages);
|
||||
}
|
||||
|
||||
// Clear ALL of the messages
|
||||
$this->clear();
|
||||
|
||||
// Invalid Message Type?
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Print everything to the screen or return the data
|
||||
if( $print ) {
|
||||
echo $data;
|
||||
} else {
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check to see if there are any queued error messages
|
||||
*
|
||||
* @author Mike Everhart
|
||||
*
|
||||
* @return bool true = There ARE error messages
|
||||
* false = There are NOT any error messages
|
||||
*
|
||||
*/
|
||||
public function hasErrors() {
|
||||
return empty($_SESSION['flash_messages']['error']) ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if there are any ($type) messages queued
|
||||
*
|
||||
* @author Mike Everhart
|
||||
*
|
||||
* @param string $type The type of messages to check for
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public function hasMessages($type=null) {
|
||||
if( !is_null($type) ) {
|
||||
if( !empty($_SESSION['flash_messages'][$type]) ) return $_SESSION['flash_messages'][$type];
|
||||
} else {
|
||||
foreach( $this->msgTypes as $type ) {
|
||||
if( !empty($_SESSION['flash_messages']) ) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear messages from the session data
|
||||
*
|
||||
* @author Mike Everhart
|
||||
*
|
||||
* @param string $type The type of messages to clear
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public function clear($type='all') {
|
||||
if( $type == 'all' ) {
|
||||
unset($_SESSION['flash_messages']);
|
||||
} else {
|
||||
unset($_SESSION['flash_messages'][$type]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function __toString() { return $this->hasMessages(); }
|
||||
|
||||
public function __destruct() {
|
||||
//$this->clear();
|
||||
}
|
||||
|
||||
|
||||
} // end class
|
||||
<?php
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Session-Based Flash Messages v1.0
|
||||
// Copyright 2012 Mike Everhart (http://mikeeverhart.net)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
// Description:
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Stores messages in Session data to be easily retrieved later on.
|
||||
// This class includes four different types of messages:
|
||||
// - Success
|
||||
// - Error
|
||||
// - Warning
|
||||
// - Information
|
||||
//
|
||||
// See README for basic usage instructions, or see samples/index.php for more advanced samples
|
||||
//
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Changelog
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// 2011-05-15 - v1.0 - Initial Version
|
||||
//
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
class Messages {
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
// Class Variables
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
var $msgId;
|
||||
var $msgTypes = array( 'help', 'info', 'warning', 'success', 'error' );
|
||||
var $msgClass = 'messages';
|
||||
var $msgWrapper = "<div class='%s %s'><a href='#' class='closeMessage'>X</a>\n%s</div>\n";
|
||||
var $msgBefore = '<p>';
|
||||
var $msgAfter = "</p>\n";
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @author Mike Everhart
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
// Generate a unique ID for this user and session
|
||||
$this->msgId = md5(uniqid());
|
||||
|
||||
// Create the session array if it doesnt already exist
|
||||
if( !array_key_exists('flash_messages', $_SESSION) ) $_SESSION['flash_messages'] = array();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a message to the queue
|
||||
*
|
||||
* @author Mike Everhart
|
||||
*
|
||||
* @param string $type The type of message to add
|
||||
* @param string $message The message
|
||||
* @param string $redirect_to (optional) If set, the user will be redirected to this URL
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public function add($type, $message, $redirect_to=null) {
|
||||
|
||||
if( !isset($_SESSION['flash_messages']) ) return false;
|
||||
|
||||
if( !isset($type) || !isset($message[0]) ) return false;
|
||||
|
||||
// Replace any shorthand codes with their full version
|
||||
if( strlen(trim($type)) == 1 ) {
|
||||
$type = str_replace( array('h', 'i', 'w', 'e', 's'), array('help', 'info', 'warning', 'error', 'success'), $type );
|
||||
|
||||
// Backwards compatibility...
|
||||
} elseif( $type == 'information' ) {
|
||||
$type = 'info';
|
||||
}
|
||||
|
||||
// Make sure it's a valid message type
|
||||
if( !in_array($type, $this->msgTypes) ) die('"' . strip_tags($type) . '" is not a valid message type!' );
|
||||
|
||||
// If the session array doesn't exist, create it
|
||||
if( !array_key_exists( $type, $_SESSION['flash_messages'] ) ) $_SESSION['flash_messages'][$type] = array();
|
||||
|
||||
$_SESSION['flash_messages'][$type][] = $message;
|
||||
|
||||
if( !is_null($redirect_to) ) {
|
||||
header("Location: $redirect_to");
|
||||
exit();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
// display()
|
||||
// print queued messages to the screen
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Display the queued messages
|
||||
*
|
||||
* @author Mike Everhart
|
||||
*
|
||||
* @param string $type Which messages to display
|
||||
* @param bool $print True = print the messages on the screen
|
||||
* @return mixed
|
||||
*
|
||||
*/
|
||||
public function display($type='all', $print=true) {
|
||||
$messages = '';
|
||||
$data = '';
|
||||
|
||||
if( !isset($_SESSION['flash_messages']) ) return false;
|
||||
|
||||
if( $type == 'g' || $type == 'growl' ) {
|
||||
$this->displayGrowlMessages();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Print a certain type of message?
|
||||
if( in_array($type, $this->msgTypes) ) {
|
||||
foreach( $_SESSION['flash_messages'][$type] as $msg ) {
|
||||
$messages .= $this->msgBefore . $msg . $this->msgAfter;
|
||||
}
|
||||
|
||||
$data .= sprintf($this->msgWrapper, $this->msgClass, $type, $messages);
|
||||
|
||||
// Clear the viewed messages
|
||||
$this->clear($type);
|
||||
|
||||
// Print ALL queued messages
|
||||
} elseif( $type == 'all' ) {
|
||||
foreach( $_SESSION['flash_messages'] as $type => $msgArray ) {
|
||||
$messages = '';
|
||||
foreach( $msgArray as $msg ) {
|
||||
$messages .= $this->msgBefore . $msg . $this->msgAfter;
|
||||
}
|
||||
$data .= sprintf($this->msgWrapper, $this->msgClass, $type, $messages);
|
||||
}
|
||||
|
||||
// Clear ALL of the messages
|
||||
$this->clear();
|
||||
|
||||
// Invalid Message Type?
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Print everything to the screen or return the data
|
||||
if( $print ) {
|
||||
echo $data;
|
||||
} else {
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check to see if there are any queued error messages
|
||||
*
|
||||
* @author Mike Everhart
|
||||
*
|
||||
* @return bool true = There ARE error messages
|
||||
* false = There are NOT any error messages
|
||||
*
|
||||
*/
|
||||
public function hasErrors() {
|
||||
return empty($_SESSION['flash_messages']['error']) ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if there are any ($type) messages queued
|
||||
*
|
||||
* @author Mike Everhart
|
||||
*
|
||||
* @param string $type The type of messages to check for
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public function hasMessages($type=null) {
|
||||
if( !is_null($type) ) {
|
||||
if( !empty($_SESSION['flash_messages'][$type]) ) return $_SESSION['flash_messages'][$type];
|
||||
} else {
|
||||
foreach( $this->msgTypes as $type ) {
|
||||
if( !empty($_SESSION['flash_messages']) ) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear messages from the session data
|
||||
*
|
||||
* @author Mike Everhart
|
||||
*
|
||||
* @param string $type The type of messages to clear
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public function clear($type='all') {
|
||||
if( $type == 'all' ) {
|
||||
unset($_SESSION['flash_messages']);
|
||||
} else {
|
||||
unset($_SESSION['flash_messages'][$type]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function __toString() { return $this->hasMessages(); }
|
||||
|
||||
public function __destruct() {
|
||||
//$this->clear();
|
||||
}
|
||||
|
||||
|
||||
} // end class
|
||||
?>
|
202
inc/3rdparty/paginator.php
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
<?php
|
||||
/*
|
||||
* PHP Pagination Class
|
||||
*
|
||||
* @author David Carr - dave@daveismyname.com - http://www.daveismyname.com
|
||||
* @version 1.0
|
||||
* @date October 20, 2013
|
||||
*/
|
||||
class Paginator{
|
||||
|
||||
/**
|
||||
* set the number of items per page.
|
||||
*
|
||||
* @var numeric
|
||||
*/
|
||||
private $_perPage;
|
||||
|
||||
/**
|
||||
* set get parameter for fetching the page number
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_instance;
|
||||
|
||||
/**
|
||||
* sets the page number.
|
||||
*
|
||||
* @var numeric
|
||||
*/
|
||||
private $_page;
|
||||
|
||||
/**
|
||||
* set the limit for the data source
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_limit;
|
||||
|
||||
/**
|
||||
* set the total number of records/items.
|
||||
*
|
||||
* @var numeric
|
||||
*/
|
||||
private $_totalRows = 0;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* __construct
|
||||
*
|
||||
* pass values when class is istantiated
|
||||
*
|
||||
* @param numeric $_perPage sets the number of iteems per page
|
||||
* @param numeric $_instance sets the instance for the GET parameter
|
||||
*/
|
||||
public function __construct($perPage,$instance){
|
||||
$this->_instance = $instance;
|
||||
$this->_perPage = $perPage;
|
||||
$this->set_instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* get_start
|
||||
*
|
||||
* creates the starting point for limiting the dataset
|
||||
* @return numeric
|
||||
*/
|
||||
private function get_start(){
|
||||
return ($this->_page * $this->_perPage) - $this->_perPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* set_instance
|
||||
*
|
||||
* sets the instance parameter, if numeric value is 0 then set to 1
|
||||
*
|
||||
* @var numeric
|
||||
*/
|
||||
private function set_instance(){
|
||||
$this->_page = (int) (!isset($_GET[$this->_instance]) ? 1 : $_GET[$this->_instance]);
|
||||
$this->_page = ($this->_page == 0 ? 1 : $this->_page);
|
||||
}
|
||||
|
||||
/**
|
||||
* set_total
|
||||
*
|
||||
* collect a numberic value and assigns it to the totalRows
|
||||
*
|
||||
* @var numeric
|
||||
*/
|
||||
public function set_total($_totalRows){
|
||||
$this->_totalRows = $_totalRows;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_limit
|
||||
*
|
||||
* returns the limit for the data source, calling the get_start method and passing in the number of items perp page
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_limit(){
|
||||
if (STORAGE == 'postgres') {
|
||||
return "LIMIT ".$this->_perPage." OFFSET ".$this->get_start();
|
||||
} else {
|
||||
return "LIMIT ".$this->get_start().",".$this->_perPage;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* page_links
|
||||
*
|
||||
* create the html links for navigating through the dataset
|
||||
*
|
||||
* @var sting $path optionally set the path for the link
|
||||
* @var sting $ext optionally pass in extra parameters to the GET
|
||||
* @return string returns the html menu
|
||||
*/
|
||||
public function page_links($path='?',$ext=null)
|
||||
{
|
||||
$adjacents = "2";
|
||||
$prev = $this->_page - 1;
|
||||
$next = $this->_page + 1;
|
||||
$lastpage = ceil($this->_totalRows/$this->_perPage);
|
||||
$lpm1 = $lastpage - 1;
|
||||
|
||||
$pagination = "";
|
||||
if($lastpage > 1)
|
||||
{
|
||||
$pagination .= "<div class='pagination'>";
|
||||
if ($this->_page > 1)
|
||||
$pagination.= "<a href='".$path."$this->_instance=$prev"."$ext'>« previous</a>";
|
||||
else
|
||||
$pagination.= "<span class='disabled'>« previous</span>";
|
||||
|
||||
if ($lastpage < 7 + ($adjacents * 2))
|
||||
{
|
||||
for ($counter = 1; $counter <= $lastpage; $counter++)
|
||||
{
|
||||
if ($counter == $this->_page)
|
||||
$pagination.= "<span class='current'>$counter</span>";
|
||||
else
|
||||
$pagination.= "<a href='".$path."$this->_instance=$counter"."$ext'>$counter</a>";
|
||||
}
|
||||
}
|
||||
elseif($lastpage > 5 + ($adjacents * 2))
|
||||
{
|
||||
if($this->_page < 1 + ($adjacents * 2))
|
||||
{
|
||||
for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++)
|
||||
{
|
||||
if ($counter == $this->_page)
|
||||
$pagination.= "<span class='current'>$counter</span>";
|
||||
else
|
||||
$pagination.= "<a href='".$path."$this->_instance=$counter"."$ext'>$counter</a>";
|
||||
}
|
||||
$pagination.= "...";
|
||||
$pagination.= "<a href='".$path."$this->_instance=$lpm1"."$ext'>$lpm1</a>";
|
||||
$pagination.= "<a href='".$path."$this->_instance=$lastpage"."$ext'>$lastpage</a>";
|
||||
}
|
||||
elseif($lastpage - ($adjacents * 2) > $this->_page && $this->_page > ($adjacents * 2))
|
||||
{
|
||||
$pagination.= "<a href='".$path."$this->_instance=1"."$ext'>1</a>";
|
||||
$pagination.= "<a href='".$path."$this->_instance=2"."$ext'>2</a>";
|
||||
$pagination.= "...";
|
||||
for ($counter = $this->_page - $adjacents; $counter <= $this->_page + $adjacents; $counter++)
|
||||
{
|
||||
if ($counter == $this->_page)
|
||||
$pagination.= "<span class='current'>$counter</span>";
|
||||
else
|
||||
$pagination.= "<a href='".$path."$this->_instance=$counter"."$ext'>$counter</a>";
|
||||
}
|
||||
$pagination.= "..";
|
||||
$pagination.= "<a href='".$path."$this->_instance=$lpm1"."$ext'>$lpm1</a>";
|
||||
$pagination.= "<a href='".$path."$this->_instance=$lastpage"."$ext'>$lastpage</a>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$pagination.= "<a href='".$path."$this->_instance=1"."$ext'>1</a>";
|
||||
$pagination.= "<a href='".$path."$this->_instance=2"."$ext'>2</a>";
|
||||
$pagination.= "..";
|
||||
for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++)
|
||||
{
|
||||
if ($counter == $this->_page)
|
||||
$pagination.= "<span class='current'>$counter</span>";
|
||||
else
|
||||
$pagination.= "<a href='".$path."$this->_instance=$counter"."$ext'>$counter</a>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->_page < $counter - 1)
|
||||
$pagination.= "<a href='".$path."$this->_instance=$next"."$ext'>next »</a>";
|
||||
else
|
||||
$pagination.= "<span class='disabled'>next »</span>";
|
||||
$pagination.= "</div>\n";
|
||||
}
|
||||
|
||||
|
||||
return $pagination;
|
||||
}
|
||||
}
|
@ -1,265 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* poche, a read it later open source system
|
||||
*
|
||||
* @category poche
|
||||
* @author Nicolas Lœuillet <support@inthepoche.com>
|
||||
* @copyright 2013
|
||||
* @license http://www.wtfpl.net/ see COPYING file
|
||||
*/
|
||||
|
||||
class MyTool
|
||||
{
|
||||
public static function initPhp()
|
||||
{
|
||||
define('START_TIME', microtime(true));
|
||||
|
||||
if (phpversion() < 5) {
|
||||
die("Argh you don't have PHP 5 !");
|
||||
}
|
||||
|
||||
error_reporting(E_ALL);
|
||||
|
||||
function stripslashesDeep($value) {
|
||||
return is_array($value)
|
||||
? array_map('stripslashesDeep', $value)
|
||||
: stripslashes($value);
|
||||
}
|
||||
|
||||
if (get_magic_quotes_gpc()) {
|
||||
$_POST = array_map('stripslashesDeep', $_POST);
|
||||
$_GET = array_map('stripslashesDeep', $_GET);
|
||||
$_COOKIE = array_map('stripslashesDeep', $_COOKIE);
|
||||
}
|
||||
|
||||
ob_start();
|
||||
register_shutdown_function('ob_end_flush');
|
||||
}
|
||||
|
||||
public static function isUrl($url)
|
||||
{
|
||||
// http://neo22s.com/check-if-url-exists-and-is-online-php/
|
||||
$pattern='|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i';
|
||||
|
||||
return preg_match($pattern, $url);
|
||||
}
|
||||
|
||||
public static function isEmail($email)
|
||||
{
|
||||
$pattern = "/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2, 4}$/i";
|
||||
|
||||
return (preg_match($pattern, $email));
|
||||
}
|
||||
|
||||
public static function formatBBCode($text)
|
||||
{
|
||||
$replace = array(
|
||||
'/\[m\](.+?)\[\/m\]/is'
|
||||
=> '/* moderate */',
|
||||
'/\[b\](.+?)\[\/b\]/is'
|
||||
=> '<strong>$1</strong>',
|
||||
'/\[i\](.+?)\[\/i\]/is'
|
||||
=> '<em>$1</em>',
|
||||
'/\[s\](.+?)\[\/s\]/is'
|
||||
=> '<del>$1</del>',
|
||||
'/\[u\](.+?)\[\/u\]/is'
|
||||
=> '<span style="text-decoration: underline;">$1</span>',
|
||||
'/\[url\](.+?)\[\/url]/is'
|
||||
=> '<a href="$1">$1</a>',
|
||||
'/\[url=(\w+:\/\/[^\]]+)\](.+?)\[\/url]/is'
|
||||
=> '<a href="$1">$2</a>',
|
||||
'/\[quote\](.+?)\[\/quote\]/is'
|
||||
=> '<blockquote>$1</blockquote>',
|
||||
'/\[code\](.+?)\[\/code\]/is'
|
||||
=> '<code>$1</code>',
|
||||
'/\[([^[]+)\|([^[]+)\]/is'
|
||||
=> '<a href="$2">$1</a>'
|
||||
);
|
||||
$text = preg_replace(
|
||||
array_keys($replace),
|
||||
array_values($replace),
|
||||
$text
|
||||
);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
public static function formatText($text)
|
||||
{
|
||||
$text = preg_replace_callback(
|
||||
'/<code_html>(.*?)<\/code_html>/is',
|
||||
create_function(
|
||||
'$matches',
|
||||
'return htmlspecialchars($matches[1]);'
|
||||
),
|
||||
$text
|
||||
);
|
||||
$text = preg_replace_callback(
|
||||
'/<code_php>(.*?)<\/code_php>/is',
|
||||
create_function(
|
||||
'$matches',
|
||||
'return highlight_string("<?php $matches[1] ?>", true);'
|
||||
),
|
||||
$text
|
||||
);
|
||||
$text = preg_replace('/<br \/>/is', '', $text);
|
||||
|
||||
$text = preg_replace(
|
||||
'#(^|\s)([a-z]+://([^\s\w/]?[\w/])*)(\s|$)#im',
|
||||
'\\1<a href="\\2">\\2</a>\\4',
|
||||
$text
|
||||
);
|
||||
$text = preg_replace(
|
||||
'#(^|\s)wp:?([a-z]{2}|):([\w]+)#im',
|
||||
'\\1<a href="http://\\2.wikipedia.org/wiki/\\3">\\3</a>',
|
||||
$text
|
||||
);
|
||||
$text = str_replace(
|
||||
'http://.wikipedia.org/wiki/',
|
||||
'http://www.wikipedia.org/wiki/',
|
||||
$text
|
||||
);
|
||||
$text = str_replace('\wp:', 'wp:', $text);
|
||||
$text = str_replace('\http:', 'http:', $text);
|
||||
$text = MyTool::formatBBCode($text);
|
||||
$text = nl2br($text);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
public static function getUrl()
|
||||
{
|
||||
$https = (!empty($_SERVER['HTTPS'])
|
||||
&& (strtolower($_SERVER['HTTPS']) == 'on'))
|
||||
|| (isset($_SERVER["SERVER_PORT"])
|
||||
&& $_SERVER["SERVER_PORT"] == '443'); // HTTPS detection.
|
||||
$serverport = (!isset($_SERVER["SERVER_PORT"])
|
||||
|| $_SERVER["SERVER_PORT"] == '80'
|
||||
|| ($https && $_SERVER["SERVER_PORT"] == '443')
|
||||
? ''
|
||||
: ':' . $_SERVER["SERVER_PORT"]);
|
||||
|
||||
$scriptname = str_replace('/index.php', '/', $_SERVER["SCRIPT_NAME"]);
|
||||
|
||||
if (!isset($_SERVER["SERVER_NAME"])) {
|
||||
return $scriptname;
|
||||
}
|
||||
|
||||
return 'http' . ($https ? 's' : '') . '://'
|
||||
. $_SERVER["SERVER_NAME"] . $serverport . $scriptname;
|
||||
}
|
||||
|
||||
public static function rrmdir($dir)
|
||||
{
|
||||
if (is_dir($dir) && ($d = @opendir($dir))) {
|
||||
while (($file = @readdir($d)) !== false) {
|
||||
if ( $file == '.' || $file == '..' ) {
|
||||
continue;
|
||||
} else {
|
||||
unlink($dir . '/' . $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function humanBytes($bytes)
|
||||
{
|
||||
$siPrefix = array( 'bytes', 'KB', 'MB', 'GB', 'TB', 'EB', 'ZB', 'YB' );
|
||||
$base = 1024;
|
||||
$class = min((int) log($bytes, $base), count($siPrefix) - 1);
|
||||
$val = sprintf('%1.2f', $bytes / pow($base, $class));
|
||||
|
||||
return $val . ' ' . $siPrefix[$class];
|
||||
}
|
||||
|
||||
public static function returnBytes($val)
|
||||
{
|
||||
$val = trim($val);
|
||||
$last = strtolower($val[strlen($val)-1]);
|
||||
switch($last)
|
||||
{
|
||||
case 'g': $val *= 1024;
|
||||
case 'm': $val *= 1024;
|
||||
case 'k': $val *= 1024;
|
||||
}
|
||||
|
||||
return $val;
|
||||
}
|
||||
|
||||
public static function getMaxFileSize()
|
||||
{
|
||||
$sizePostMax = MyTool::returnBytes(ini_get('post_max_size'));
|
||||
$sizeUploadMax = MyTool::returnBytes(ini_get('upload_max_filesize'));
|
||||
|
||||
// Return the smaller of two:
|
||||
return min($sizePostMax, $sizeUploadMax);
|
||||
}
|
||||
|
||||
public static function smallHash($text)
|
||||
{
|
||||
$t = rtrim(base64_encode(hash('crc32', $text, true)), '=');
|
||||
// Get rid of characters which need encoding in URLs.
|
||||
$t = str_replace('+', '-', $t);
|
||||
$t = str_replace('/', '_', $t);
|
||||
$t = str_replace('=', '@', $t);
|
||||
|
||||
return $t;
|
||||
}
|
||||
|
||||
public static function renderJson($data)
|
||||
{
|
||||
header('Cache-Control: no-cache, must-revalidate');
|
||||
header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
|
||||
header('Content-type: application/json; charset=UTF-8');
|
||||
|
||||
echo json_encode($data);
|
||||
exit();
|
||||
}
|
||||
|
||||
public static function grabToLocal($url, $file, $force = false)
|
||||
{
|
||||
if ((!file_exists($file) || $force) && in_array('curl', get_loaded_extensions())){
|
||||
$ch = curl_init ($url);
|
||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
|
||||
$raw = curl_exec($ch);
|
||||
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == 200) {
|
||||
$fp = fopen($file, 'x');
|
||||
fwrite($fp, $raw);
|
||||
fclose($fp);
|
||||
}
|
||||
curl_close ($ch);
|
||||
}
|
||||
}
|
||||
|
||||
public static function redirect($rurl = '')
|
||||
{
|
||||
if ($rurl === '') {
|
||||
// if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['SERVER_NAME'])==0)
|
||||
$rurl = (empty($_SERVER['HTTP_REFERER'])?'?':$_SERVER['HTTP_REFERER']);
|
||||
if (isset($_POST['returnurl'])) {
|
||||
$rurl = $_POST['returnurl'];
|
||||
}
|
||||
}
|
||||
|
||||
// prevent loop
|
||||
if (empty($rurl) || parse_url($rurl, PHP_URL_QUERY) === $_SERVER['QUERY_STRING']) {
|
||||
$rurl = MyTool::getUrl();
|
||||
}
|
||||
|
||||
if (substr($rurl, 0, 1) !== '?') {
|
||||
$ref = MyTool::getUrl();
|
||||
if (substr($rurl, 0, strlen($ref)) !== $ref) {
|
||||
$rurl = $ref;
|
||||
}
|
||||
}
|
||||
header('Location: '.$rurl);
|
||||
exit();
|
||||
}
|
||||
|
||||
public static function silence_errors($num, $str)
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* poche, a read it later open source system
|
||||
*
|
||||
* @category poche
|
||||
* @author Nicolas Lœuillet <nicolas@loeuillet.org>
|
||||
* @copyright 2013
|
||||
* @license http://www.wtfpl.net/ see COPYING file
|
||||
*/
|
||||
|
||||
define ('POCHE_VERSION', '0.2.1');
|
||||
|
||||
if (!is_dir('db/')) {
|
||||
@mkdir('db/',0705);
|
||||
}
|
||||
|
||||
define ('MODE_DEMO', FALSE);
|
||||
define ('ABS_PATH', 'assets/');
|
||||
define ('CONVERT_LINKS_FOOTNOTES', TRUE);
|
||||
define ('REVERT_FORCED_PARAGRAPH_ELEMENTS',FALSE);
|
||||
define ('DOWNLOAD_PICTURES', TRUE);
|
||||
define ('SALT', '464v54gLLw928uz4zUBqkRJeiPY68zCX');
|
||||
$storage_type = 'sqlite'; # sqlite or file
|
||||
|
||||
include 'functions.php';
|
||||
require_once 'Readability.php';
|
||||
require_once 'Encoding.php';
|
||||
require_once 'rain.tpl.class.php';
|
||||
require_once 'MyTool.class.php';
|
||||
require_once 'Session.class.php';
|
||||
require_once 'store/store.class.php';
|
||||
require_once 'store/sqlite.class.php';
|
||||
require_once 'store/file.class.php';
|
||||
require_once 'class.messages.php';
|
||||
|
||||
Session::init();
|
||||
|
||||
$store = new $storage_type();
|
||||
# initialisation de RainTPL
|
||||
raintpl::$tpl_dir = './tpl/';
|
||||
raintpl::$cache_dir = './cache/';
|
||||
raintpl::$base_url = get_poche_url();
|
||||
raintpl::configure('path_replace', false);
|
||||
raintpl::configure('debug', false);
|
||||
$tpl = new raintpl();
|
||||
|
||||
if(!$store->isInstalled())
|
||||
{
|
||||
logm('poche still not installed');
|
||||
$tpl->draw('install');
|
||||
if (isset($_GET['install'])) {
|
||||
if (($_POST['password'] == $_POST['password_repeat'])
|
||||
&& $_POST['password'] != "" && $_POST['login'] != "") {
|
||||
$store->install($_POST['login'], encode_string($_POST['password'] . $_POST['login']));
|
||||
Session::logout();
|
||||
MyTool::redirect();
|
||||
}
|
||||
}
|
||||
exit();
|
||||
}
|
||||
|
||||
$_SESSION['login'] = (isset ($_SESSION['login'])) ? $_SESSION['login'] : $store->getLogin();
|
||||
$_SESSION['pass'] = (isset ($_SESSION['pass'])) ? $_SESSION['pass'] : $store->getPassword();
|
||||
|
||||
$msg = new Messages();
|
||||
$tpl->assign('msg', $msg);
|
@ -1,398 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* poche, a read it later open source system
|
||||
*
|
||||
* @category poche
|
||||
* @author Nicolas Lœuillet <support@inthepoche.com>
|
||||
* @copyright 2013
|
||||
* @license http://www.wtfpl.net/ see COPYING file
|
||||
*/
|
||||
|
||||
/**
|
||||
* Permet de générer l'URL de poche pour le bookmarklet
|
||||
*/
|
||||
function get_poche_url()
|
||||
{
|
||||
$protocol = "http";
|
||||
if(isset($_SERVER['HTTPS'])) {
|
||||
if($_SERVER['HTTPS'] != "off" && $_SERVER['HTTPS'] != "") {
|
||||
$protocol = "https";
|
||||
}
|
||||
}
|
||||
|
||||
return $protocol . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
||||
}
|
||||
|
||||
function encode_string($string)
|
||||
{
|
||||
return sha1($string . SALT);
|
||||
}
|
||||
|
||||
// function define to retrieve url content
|
||||
function get_external_file($url)
|
||||
{
|
||||
$timeout = 15;
|
||||
// spoofing FireFox 18.0
|
||||
$useragent="Mozilla/5.0 (Windows NT 5.1; rv:18.0) Gecko/20100101 Firefox/18.0";
|
||||
|
||||
if (in_array ('curl', get_loaded_extensions())) {
|
||||
// Fetch feed from URL
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
|
||||
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_HEADER, false);
|
||||
|
||||
// FOR SSL do not verified certificate
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
|
||||
curl_setopt($curl, CURLOPT_AUTOREFERER, TRUE );
|
||||
|
||||
// FeedBurner requires a proper USER-AGENT...
|
||||
curl_setopt($curl, CURL_HTTP_VERSION_1_1, true);
|
||||
curl_setopt($curl, CURLOPT_ENCODING, "gzip, deflate");
|
||||
curl_setopt($curl, CURLOPT_USERAGENT, $useragent);
|
||||
|
||||
$data = curl_exec($curl);
|
||||
|
||||
$httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
|
||||
$httpcodeOK = isset($httpcode) and ($httpcode == 200 or $httpcode == 301);
|
||||
|
||||
curl_close($curl);
|
||||
} else {
|
||||
|
||||
// create http context and add timeout and user-agent
|
||||
$context = stream_context_create(array(
|
||||
'http'=>array('timeout' => $timeout,
|
||||
'header'=> "User-Agent: ".$useragent, /*spoot Mozilla Firefox*/
|
||||
'follow_location' => true),
|
||||
// FOR SSL do not verified certificate
|
||||
'ssl' => array('verify_peer' => false,
|
||||
'allow_self_signed' => true)
|
||||
)
|
||||
);
|
||||
|
||||
// only download page lesser than 4MB
|
||||
$data = @file_get_contents($url, false, $context, -1, 4000000); // We download at most 4 MB from source.
|
||||
|
||||
if(isset($http_response_header) and isset($http_response_header[0])) {
|
||||
$httpcodeOK = isset($http_response_header) and isset($http_response_header[0]) and ((strpos($http_response_header[0], '200 OK') !== FALSE) or (strpos($http_response_header[0], '301 Moved Permanently') !== FALSE));
|
||||
}
|
||||
}
|
||||
|
||||
// if response is not empty and response is OK
|
||||
if (isset($data) and isset($httpcodeOK) and $httpcodeOK ) {
|
||||
|
||||
// take charset of page and get it
|
||||
preg_match('#<meta .*charset=.*>#Usi', $data, $meta);
|
||||
|
||||
// if meta tag is found
|
||||
if (!empty($meta[0])) {
|
||||
// retrieve encoding in $enc
|
||||
preg_match('#charset="?(.*)"#si', $meta[0], $enc);
|
||||
|
||||
// if charset is found set it otherwise, set it to utf-8
|
||||
$html_charset = (!empty($enc[1])) ? strtolower($enc[1]) : 'utf-8';
|
||||
|
||||
} else {
|
||||
$html_charset = 'utf-8';
|
||||
$enc[1] = '';
|
||||
}
|
||||
|
||||
// replace charset of url to charset of page
|
||||
$data = str_replace('charset='.$enc[1], 'charset='.$html_charset, $data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Préparation de l'URL avec récupération du contenu avant insertion en base
|
||||
*/
|
||||
function prepare_url($url)
|
||||
{
|
||||
$parametres = array();
|
||||
$url = html_entity_decode(trim($url));
|
||||
|
||||
// We remove the annoying parameters added by FeedBurner and GoogleFeedProxy (?utm_source=...)
|
||||
// from shaarli, by sebsauvage
|
||||
$i=strpos($url,'&utm_source='); if ($i!==false) $url=substr($url,0,$i);
|
||||
$i=strpos($url,'?utm_source='); if ($i!==false) $url=substr($url,0,$i);
|
||||
$i=strpos($url,'#xtor=RSS-'); if ($i!==false) $url=substr($url,0,$i);
|
||||
|
||||
$title = $url;
|
||||
$html = Encoding::toUTF8(get_external_file($url,15));
|
||||
// If get_external_file if not able to retrieve HTTPS content try the same URL with HTTP protocol
|
||||
if (!preg_match('!^https?://!i', $url) && (!isset($html) || strlen($html) <= 0)) {
|
||||
$url = 'http://' . $url;
|
||||
$html = Encoding::toUTF8(get_external_file($url,15));
|
||||
}
|
||||
|
||||
if (function_exists('tidy_parse_string')) {
|
||||
$tidy = tidy_parse_string($html, array(), 'UTF8');
|
||||
$tidy->cleanRepair();
|
||||
$html = $tidy->value;
|
||||
}
|
||||
|
||||
if (isset($html) and strlen($html) > 0)
|
||||
{
|
||||
$r = new Readability($html, $url);
|
||||
|
||||
$r->convertLinksToFootnotes = CONVERT_LINKS_FOOTNOTES;
|
||||
$r->revertForcedParagraphElements = REVERT_FORCED_PARAGRAPH_ELEMENTS;
|
||||
|
||||
if($r->init())
|
||||
{
|
||||
$content = $r->articleContent->innerHTML;
|
||||
$parametres['title'] = $r->articleTitle->innerHTML;
|
||||
$parametres['content'] = $content;
|
||||
return $parametres;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* On modifie les URLS des images dans le corps de l'article
|
||||
*/
|
||||
function filtre_picture($content, $url, $id)
|
||||
{
|
||||
$matches = array();
|
||||
preg_match_all('#<\s*(img)[^>]+src="([^"]*)"[^>]*>#Si', $content, $matches, PREG_SET_ORDER);
|
||||
foreach($matches as $i => $link)
|
||||
{
|
||||
$link[1] = trim($link[1]);
|
||||
if (!preg_match('#^(([a-z]+://)|(\#))#', $link[1]) )
|
||||
{
|
||||
$absolute_path = get_absolute_link($link[2],$url);
|
||||
$filename = basename(parse_url($absolute_path, PHP_URL_PATH));
|
||||
$directory = create_assets_directory($id);
|
||||
$fullpath = $directory . '/' . $filename;
|
||||
download_pictures($absolute_path, $fullpath);
|
||||
$content = str_replace($matches[$i][2], $fullpath, $content);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le lien absolu
|
||||
*/
|
||||
function get_absolute_link($relative_link, $url)
|
||||
{
|
||||
/* return if already absolute URL */
|
||||
if (parse_url($relative_link, PHP_URL_SCHEME) != '') return $relative_link;
|
||||
|
||||
/* queries and anchors */
|
||||
if ($relative_link[0]=='#' || $relative_link[0]=='?') return $url . $relative_link;
|
||||
|
||||
/* parse base URL and convert to local variables:
|
||||
$scheme, $host, $path */
|
||||
extract(parse_url($url));
|
||||
|
||||
/* remove non-directory element from path */
|
||||
$path = preg_replace('#/[^/]*$#', '', $path);
|
||||
|
||||
/* destroy path if relative url points to root */
|
||||
if ($relative_link[0] == '/') $path = '';
|
||||
|
||||
/* dirty absolute URL */
|
||||
$abs = $host . $path . '/' . $relative_link;
|
||||
|
||||
/* replace '//' or '/./' or '/foo/../' with '/' */
|
||||
$re = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#');
|
||||
for($n=1; $n>0; $abs=preg_replace($re, '/', $abs, -1, $n)) {}
|
||||
|
||||
/* absolute URL is ready! */
|
||||
return $scheme.'://'.$abs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Téléchargement des images
|
||||
*/
|
||||
|
||||
function download_pictures($absolute_path, $fullpath)
|
||||
{
|
||||
$rawdata = get_external_file($absolute_path);
|
||||
|
||||
if(file_exists($fullpath)) {
|
||||
unlink($fullpath);
|
||||
}
|
||||
$fp = fopen($fullpath, 'x');
|
||||
fwrite($fp, $rawdata);
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un répertoire de médias pour l'article
|
||||
*/
|
||||
function create_assets_directory($id)
|
||||
{
|
||||
$assets_path = ABS_PATH;
|
||||
if(!is_dir($assets_path)) {
|
||||
mkdir($assets_path, 0705);
|
||||
}
|
||||
|
||||
$article_directory = $assets_path . $id;
|
||||
if(!is_dir($article_directory)) {
|
||||
mkdir($article_directory, 0705);
|
||||
}
|
||||
|
||||
return $article_directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppression du répertoire d'images
|
||||
*/
|
||||
function remove_directory($directory)
|
||||
{
|
||||
if(is_dir($directory)) {
|
||||
$files = array_diff(scandir($directory), array('.','..'));
|
||||
foreach ($files as $file) {
|
||||
(is_dir("$directory/$file")) ? remove_directory("$directory/$file") : unlink("$directory/$file");
|
||||
}
|
||||
return rmdir($directory);
|
||||
}
|
||||
}
|
||||
|
||||
function display_view($view, $id = 0, $full_head = 'yes')
|
||||
{
|
||||
global $tpl, $store, $msg;
|
||||
|
||||
switch ($view)
|
||||
{
|
||||
case 'export':
|
||||
$entries = $store->retrieveAll();
|
||||
$tpl->assign('export', myTool::renderJson($entries));
|
||||
$tpl->draw('export');
|
||||
logm('export view');
|
||||
break;
|
||||
case 'config':
|
||||
$tpl->assign('load_all_js', 0);
|
||||
$tpl->draw('head');
|
||||
$tpl->draw('home');
|
||||
$tpl->draw('config');
|
||||
$tpl->draw('js');
|
||||
$tpl->draw('footer');
|
||||
logm('config view');
|
||||
break;
|
||||
case 'view':
|
||||
$entry = $store->retrieveOneById($id);
|
||||
|
||||
if ($entry != NULL) {
|
||||
$tpl->assign('id', $entry['id']);
|
||||
$tpl->assign('url', $entry['url']);
|
||||
$tpl->assign('title', $entry['title']);
|
||||
$content = $entry['content'];
|
||||
if (function_exists('tidy_parse_string')) {
|
||||
$tidy = tidy_parse_string($content, array('indent'=>true, 'show-body-only' => true), 'UTF8');
|
||||
$tidy->cleanRepair();
|
||||
$content = $tidy->value;
|
||||
}
|
||||
$tpl->assign('content', $content);
|
||||
$tpl->assign('is_fav', $entry['is_fav']);
|
||||
$tpl->assign('is_read', $entry['is_read']);
|
||||
$tpl->assign('load_all_js', 0);
|
||||
$tpl->draw('view');
|
||||
}
|
||||
else {
|
||||
logm('error in view call : entry is NULL');
|
||||
}
|
||||
|
||||
logm('view link #' . $id);
|
||||
break;
|
||||
default: # home view
|
||||
$entries = $store->getEntriesByView($view);
|
||||
|
||||
$tpl->assign('entries', $entries);
|
||||
|
||||
if ($full_head == 'yes') {
|
||||
$tpl->assign('load_all_js', 1);
|
||||
$tpl->draw('head');
|
||||
$tpl->draw('home');
|
||||
}
|
||||
|
||||
$tpl->draw('entries');
|
||||
|
||||
if ($full_head == 'yes') {
|
||||
$tpl->draw('js');
|
||||
$tpl->draw('footer');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appel d'une action (mark as fav, archive, delete)
|
||||
*/
|
||||
function action_to_do($action, $url, $id = 0)
|
||||
{
|
||||
global $store, $msg;
|
||||
|
||||
switch ($action)
|
||||
{
|
||||
case 'add':
|
||||
if ($url == '')
|
||||
continue;
|
||||
|
||||
if (MyTool::isUrl($url)) {
|
||||
if($parametres_url = prepare_url($url)) {
|
||||
if ($store->add($url, $parametres_url['title'], $parametres_url['content'])) {
|
||||
$last_id = $store->getLastId();
|
||||
if (DOWNLOAD_PICTURES) {
|
||||
$content = filtre_picture($parametres_url['content'], $url, $last_id);
|
||||
}
|
||||
$msg->add('s', 'the link has been added successfully');
|
||||
}
|
||||
else {
|
||||
$msg->add('e', 'error during insertion : the link wasn\'t added');
|
||||
}
|
||||
}
|
||||
else {
|
||||
$msg->add('e', 'error during url preparation : the link wasn\'t added');
|
||||
logm('error during url preparation');
|
||||
}
|
||||
}
|
||||
else {
|
||||
$msg->add('e', 'error during url preparation : the link is not valid');
|
||||
logm($url . ' is not a valid url');
|
||||
}
|
||||
|
||||
logm('add link ' . $url);
|
||||
break;
|
||||
case 'delete':
|
||||
if ($store->deleteById($id)) {
|
||||
remove_directory(ABS_PATH . $id);
|
||||
$msg->add('s', 'the link has been deleted successfully');
|
||||
logm('delete link #' . $id);
|
||||
}
|
||||
else {
|
||||
$msg->add('e', 'the link wasn\'t deleted');
|
||||
logm('error : can\'t delete link #' . $id);
|
||||
}
|
||||
break;
|
||||
case 'toggle_fav' :
|
||||
$store->favoriteById($id);
|
||||
logm('mark as favorite link #' . $id);
|
||||
break;
|
||||
case 'toggle_archive' :
|
||||
$store->archiveById($id);
|
||||
logm('archive link #' . $id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function logm($message)
|
||||
{
|
||||
$t = strval(date('Y/m/d_H:i:s')).' - '.$_SERVER["REMOTE_ADDR"].' - '.strval($message)."\n";
|
||||
file_put_contents('./log.txt',$t,FILE_APPEND);
|
||||
}
|
216
inc/poche/Database.class.php
Normal file
@ -0,0 +1,216 @@
|
||||
<?php
|
||||
/**
|
||||
* poche, a read it later open source system
|
||||
*
|
||||
* @category poche
|
||||
* @author Nicolas Lœuillet <support@inthepoche.com>
|
||||
* @copyright 2013
|
||||
* @license http://www.wtfpl.net/ see COPYING file
|
||||
*/
|
||||
|
||||
class Database {
|
||||
var $handle;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
switch (STORAGE) {
|
||||
case 'sqlite':
|
||||
$db_path = 'sqlite:' . STORAGE_SQLITE;
|
||||
$this->handle = new PDO($db_path);
|
||||
break;
|
||||
case 'mysql':
|
||||
$db_path = 'mysql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB;
|
||||
$this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD);
|
||||
break;
|
||||
case 'postgres':
|
||||
$db_path = 'pgsql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB;
|
||||
$this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD);
|
||||
break;
|
||||
}
|
||||
|
||||
$this->handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
Tools::logm('storage type ' . STORAGE);
|
||||
}
|
||||
|
||||
private function getHandle() {
|
||||
return $this->handle;
|
||||
}
|
||||
|
||||
public function isInstalled() {
|
||||
$sql = "SELECT username FROM users";
|
||||
$query = $this->executeQuery($sql, array());
|
||||
$hasAdmin = count($query->fetchAll());
|
||||
|
||||
if ($hasAdmin == 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
public function install($login, $password) {
|
||||
$sql = 'INSERT INTO users ( username, password, name, email) VALUES (?, ?, ?, ?)';
|
||||
$params = array($login, $password, $login, ' ');
|
||||
$query = $this->executeQuery($sql, $params);
|
||||
|
||||
$sequence = '';
|
||||
if (STORAGE == 'postgres') {
|
||||
$sequence = 'users_id_seq';
|
||||
}
|
||||
|
||||
$id_user = intval($this->getLastId($sequence));
|
||||
|
||||
$sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)';
|
||||
$params = array($id_user, 'pager', '10');
|
||||
$query = $this->executeQuery($sql, $params);
|
||||
|
||||
$sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)';
|
||||
$params = array($id_user, 'language', 'en_EN.UTF8');
|
||||
$query = $this->executeQuery($sql, $params);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
private function getConfigUser($id) {
|
||||
$sql = "SELECT * FROM users_config WHERE user_id = ?";
|
||||
$query = $this->executeQuery($sql, array($id));
|
||||
$result = $query->fetchAll();
|
||||
$user_config = array();
|
||||
|
||||
foreach ($result as $key => $value) {
|
||||
$user_config[$value['name']] = $value['value'];
|
||||
}
|
||||
|
||||
return $user_config;
|
||||
}
|
||||
|
||||
public function login($username, $password) {
|
||||
$sql = "SELECT * FROM users WHERE username=? AND password=?";
|
||||
$query = $this->executeQuery($sql, array($username, $password));
|
||||
$login = $query->fetchAll();
|
||||
|
||||
$user = array();
|
||||
if (isset($login[0])) {
|
||||
$user['id'] = $login[0]['id'];
|
||||
$user['username'] = $login[0]['username'];
|
||||
$user['password'] = $login[0]['password'];
|
||||
$user['name'] = $login[0]['name'];
|
||||
$user['email'] = $login[0]['email'];
|
||||
$user['config'] = $this->getConfigUser($login[0]['id']);
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function updatePassword($id, $password)
|
||||
{
|
||||
$sql_update = "UPDATE users SET password=? WHERE id=?";
|
||||
$params_update = array($password, $id);
|
||||
$query = $this->executeQuery($sql_update, $params_update);
|
||||
}
|
||||
|
||||
private function executeQuery($sql, $params) {
|
||||
try
|
||||
{
|
||||
$query = $this->getHandle()->prepare($sql);
|
||||
$query->execute($params);
|
||||
return $query;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
Tools::logm('execute query error : '.$e->getMessage());
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
public function retrieveAll($user_id) {
|
||||
$sql = "SELECT * FROM entries WHERE user_id=? ORDER BY id";
|
||||
$query = $this->executeQuery($sql, array($user_id));
|
||||
$entries = $query->fetchAll();
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
public function retrieveOneById($id, $user_id) {
|
||||
$entry = NULL;
|
||||
$sql = "SELECT * FROM entries WHERE id=? AND user_id=?";
|
||||
$params = array(intval($id), $user_id);
|
||||
$query = $this->executeQuery($sql, $params);
|
||||
$entry = $query->fetchAll();
|
||||
|
||||
return $entry[0];
|
||||
}
|
||||
|
||||
public function getEntriesByView($view, $user_id, $limit = '') {
|
||||
switch ($_SESSION['sort'])
|
||||
{
|
||||
case 'ia':
|
||||
$order = 'ORDER BY id';
|
||||
break;
|
||||
case 'id':
|
||||
$order = 'ORDER BY id DESC';
|
||||
break;
|
||||
case 'ta':
|
||||
$order = 'ORDER BY lower(title)';
|
||||
break;
|
||||
case 'td':
|
||||
$order = 'ORDER BY lower(title) DESC';
|
||||
break;
|
||||
default:
|
||||
$order = 'ORDER BY id';
|
||||
break;
|
||||
}
|
||||
|
||||
switch ($view)
|
||||
{
|
||||
case 'archive':
|
||||
$sql = "SELECT * FROM entries WHERE user_id=? AND is_read=? " . $order;
|
||||
$params = array($user_id, 1);
|
||||
break;
|
||||
case 'fav' :
|
||||
$sql = "SELECT * FROM entries WHERE user_id=? AND is_fav=? " . $order;
|
||||
$params = array($user_id, 1);
|
||||
break;
|
||||
default:
|
||||
$sql = "SELECT * FROM entries WHERE user_id=? AND is_read=? " . $order;
|
||||
$params = array($user_id, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
$sql .= ' ' . $limit;
|
||||
|
||||
$query = $this->executeQuery($sql, $params);
|
||||
$entries = $query->fetchAll();
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
public function add($url, $title, $content, $user_id) {
|
||||
$sql_action = 'INSERT INTO entries ( url, title, content, user_id ) VALUES (?, ?, ?, ?)';
|
||||
$params_action = array($url, $title, $content, $user_id);
|
||||
$query = $this->executeQuery($sql_action, $params_action);
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function deleteById($id, $user_id) {
|
||||
$sql_action = "DELETE FROM entries WHERE id=? AND user_id=?";
|
||||
$params_action = array($id, $user_id);
|
||||
$query = $this->executeQuery($sql_action, $params_action);
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function favoriteById($id, $user_id) {
|
||||
$sql_action = "UPDATE entries SET is_fav=NOT is_fav WHERE id=? AND user_id=?";
|
||||
$params_action = array($id, $user_id);
|
||||
$query = $this->executeQuery($sql_action, $params_action);
|
||||
}
|
||||
|
||||
public function archiveById($id, $user_id) {
|
||||
$sql_action = "UPDATE entries SET is_read=NOT is_read WHERE id=? AND user_id=?";
|
||||
$params_action = array($id, $user_id);
|
||||
$query = $this->executeQuery($sql_action, $params_action);
|
||||
}
|
||||
|
||||
public function getLastId($column = '') {
|
||||
return $this->getHandle()->lastInsertId($column);
|
||||
}
|
||||
}
|
485
inc/poche/Poche.class.php
Normal file
@ -0,0 +1,485 @@
|
||||
<?php
|
||||
/**
|
||||
* poche, a read it later open source system
|
||||
*
|
||||
* @category poche
|
||||
* @author Nicolas Lœuillet <support@inthepoche.com>
|
||||
* @copyright 2013
|
||||
* @license http://www.wtfpl.net/ see COPYING file
|
||||
*/
|
||||
|
||||
class Poche
|
||||
{
|
||||
public $user;
|
||||
public $store;
|
||||
public $tpl;
|
||||
public $messages;
|
||||
public $pagination;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->store = new Database();
|
||||
$this->init();
|
||||
$this->messages = new Messages();
|
||||
|
||||
# installation
|
||||
if(!$this->store->isInstalled())
|
||||
{
|
||||
$this->install();
|
||||
}
|
||||
}
|
||||
|
||||
private function init()
|
||||
{
|
||||
if (file_exists('./install') && !DEBUG_POCHE) {
|
||||
Tools::logm('folder /install exists');
|
||||
die('the folder /install exists, you have to delete it before using poche.');
|
||||
}
|
||||
|
||||
Tools::initPhp();
|
||||
Session::init();
|
||||
|
||||
if (isset($_SESSION['poche_user']) && $_SESSION['poche_user'] != array()) {
|
||||
$this->user = $_SESSION['poche_user'];
|
||||
}
|
||||
else {
|
||||
# fake user, just for install & login screens
|
||||
$this->user = new User();
|
||||
$this->user->setConfig($this->getDefaultConfig());
|
||||
}
|
||||
|
||||
# l10n
|
||||
$language = $this->user->getConfigValue('language');
|
||||
putenv('LC_ALL=' . $language);
|
||||
setlocale(LC_ALL, $language);
|
||||
bindtextdomain($language, LOCALE);
|
||||
textdomain($language);
|
||||
|
||||
# template engine
|
||||
$loader = new Twig_Loader_Filesystem(TPL);
|
||||
if (DEBUG_POCHE) {
|
||||
$twig_params = array();
|
||||
}
|
||||
else {
|
||||
$twig_params = array('cache' => CACHE);
|
||||
}
|
||||
$this->tpl = new Twig_Environment($loader, $twig_params);
|
||||
$this->tpl->addExtension(new Twig_Extensions_Extension_I18n());
|
||||
# filter to display domain name of an url
|
||||
$filter = new Twig_SimpleFilter('getDomain', 'Tools::getDomain');
|
||||
$this->tpl->addFilter($filter);
|
||||
|
||||
# Pagination
|
||||
$this->pagination = new Paginator($this->user->getConfigValue('pager'), 'p');
|
||||
}
|
||||
|
||||
private function install()
|
||||
{
|
||||
Tools::logm('poche still not installed');
|
||||
echo $this->tpl->render('install.twig', array(
|
||||
'token' => Session::getToken()
|
||||
));
|
||||
if (isset($_GET['install'])) {
|
||||
if (($_POST['password'] == $_POST['password_repeat'])
|
||||
&& $_POST['password'] != "" && $_POST['login'] != "") {
|
||||
# let's rock, install poche baby !
|
||||
$this->store->install($_POST['login'], Tools::encodeString($_POST['password'] . $_POST['login']));
|
||||
Session::logout();
|
||||
Tools::logm('poche is now installed');
|
||||
Tools::redirect();
|
||||
}
|
||||
else {
|
||||
Tools::logm('error during installation');
|
||||
Tools::redirect();
|
||||
}
|
||||
}
|
||||
exit();
|
||||
}
|
||||
|
||||
public function getDefaultConfig()
|
||||
{
|
||||
return array(
|
||||
'pager' => PAGINATION,
|
||||
'language' => LANG,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call action (mark as fav, archive, delete, etc.)
|
||||
*/
|
||||
public function action($action, Url $url, $id = 0, $import = FALSE)
|
||||
{
|
||||
switch ($action)
|
||||
{
|
||||
case 'add':
|
||||
if($parametres_url = $url->fetchContent()) {
|
||||
if ($this->store->add($url->getUrl(), $parametres_url['title'], $parametres_url['content'], $this->user->getId())) {
|
||||
Tools::logm('add link ' . $url->getUrl());
|
||||
$sequence = '';
|
||||
if (STORAGE == 'postgres') {
|
||||
$sequence = 'entries_id_seq';
|
||||
}
|
||||
$last_id = $this->store->getLastId($sequence);
|
||||
if (DOWNLOAD_PICTURES) {
|
||||
$content = filtre_picture($parametres_url['content'], $url->getUrl(), $last_id);
|
||||
}
|
||||
if (!$import) {
|
||||
$this->messages->add('s', _('the link has been added successfully'));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!$import) {
|
||||
$this->messages->add('e', _('error during insertion : the link wasn\'t added'));
|
||||
Tools::logm('error during insertion : the link wasn\'t added ' . $url->getUrl());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!$import) {
|
||||
$this->messages->add('e', _('error during fetching content : the link wasn\'t added'));
|
||||
Tools::logm('error during content fetch ' . $url->getUrl());
|
||||
}
|
||||
}
|
||||
if (!$import) {
|
||||
Tools::redirect();
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
$msg = 'delete link #' . $id;
|
||||
if ($this->store->deleteById($id, $this->user->getId())) {
|
||||
if (DOWNLOAD_PICTURES) {
|
||||
remove_directory(ABS_PATH . $id);
|
||||
}
|
||||
$this->messages->add('s', _('the link has been deleted successfully'));
|
||||
}
|
||||
else {
|
||||
$this->messages->add('e', _('the link wasn\'t deleted'));
|
||||
$msg = 'error : can\'t delete link #' . $id;
|
||||
}
|
||||
Tools::logm($msg);
|
||||
Tools::redirect('?');
|
||||
break;
|
||||
case 'toggle_fav' :
|
||||
$this->store->favoriteById($id, $this->user->getId());
|
||||
Tools::logm('mark as favorite link #' . $id);
|
||||
if (!$import) {
|
||||
Tools::redirect();
|
||||
}
|
||||
break;
|
||||
case 'toggle_archive' :
|
||||
$this->store->archiveById($id, $this->user->getId());
|
||||
Tools::logm('archive link #' . $id);
|
||||
if (!$import) {
|
||||
Tools::redirect();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function displayView($view, $id = 0)
|
||||
{
|
||||
$tpl_vars = array();
|
||||
|
||||
switch ($view)
|
||||
{
|
||||
case 'config':
|
||||
$dev = $this->getPocheVersion('dev');
|
||||
$prod = $this->getPocheVersion('prod');
|
||||
$compare_dev = version_compare(POCHE_VERSION, $dev);
|
||||
$compare_prod = version_compare(POCHE_VERSION, $prod);
|
||||
$tpl_vars = array(
|
||||
'dev' => $dev,
|
||||
'prod' => $prod,
|
||||
'compare_dev' => $compare_dev,
|
||||
'compare_prod' => $compare_prod,
|
||||
);
|
||||
Tools::logm('config view');
|
||||
break;
|
||||
case 'view':
|
||||
$entry = $this->store->retrieveOneById($id, $this->user->getId());
|
||||
if ($entry != NULL) {
|
||||
Tools::logm('view link #' . $id);
|
||||
$content = $entry['content'];
|
||||
if (function_exists('tidy_parse_string')) {
|
||||
$tidy = tidy_parse_string($content, array('indent'=>true, 'show-body-only' => true), 'UTF8');
|
||||
$tidy->cleanRepair();
|
||||
$content = $tidy->value;
|
||||
}
|
||||
$tpl_vars = array(
|
||||
'entry' => $entry,
|
||||
'content' => $content,
|
||||
);
|
||||
}
|
||||
else {
|
||||
Tools::logm('error in view call : entry is NULL');
|
||||
}
|
||||
break;
|
||||
default: # home view
|
||||
$entries = $this->store->getEntriesByView($view, $this->user->getId());
|
||||
$this->pagination->set_total(count($entries));
|
||||
$page_links = $this->pagination->page_links('?view=' . $view . '&sort=' . $_SESSION['sort'] . '&');
|
||||
$datas = $this->store->getEntriesByView($view, $this->user->getId(), $this->pagination->get_limit());
|
||||
$tpl_vars = array(
|
||||
'entries' => $datas,
|
||||
'page_links' => $page_links,
|
||||
);
|
||||
Tools::logm('display ' . $view . ' view');
|
||||
break;
|
||||
}
|
||||
|
||||
return $tpl_vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* update the password of the current user.
|
||||
* if MODE_DEMO is TRUE, the password can't be updated.
|
||||
* @todo add the return value
|
||||
* @todo set the new password in function header like this updatePassword($newPassword)
|
||||
* @return boolean
|
||||
*/
|
||||
public function updatePassword()
|
||||
{
|
||||
if (MODE_DEMO) {
|
||||
$this->messages->add('i', _('in demo mode, you can\'t update your password'));
|
||||
Tools::logm('in demo mode, you can\'t do this');
|
||||
Tools::redirect('?view=config');
|
||||
}
|
||||
else {
|
||||
if (isset($_POST['password']) && isset($_POST['password_repeat'])) {
|
||||
if ($_POST['password'] == $_POST['password_repeat'] && $_POST['password'] != "") {
|
||||
$this->messages->add('s', _('your password has been updated'));
|
||||
$this->store->updatePassword($this->user->getId(), Tools::encodeString($_POST['password'] . $this->user->getUsername()));
|
||||
Session::logout();
|
||||
Tools::logm('password updated');
|
||||
Tools::redirect();
|
||||
}
|
||||
else {
|
||||
$this->messages->add('e', _('the two fields have to be filled & the password must be the same in the two fields'));
|
||||
Tools::redirect('?view=config');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if login & password are correct and save the user in session.
|
||||
* it redirects the user to the $referer link
|
||||
* @param string $referer the url to redirect after login
|
||||
* @todo add the return value
|
||||
* @return boolean
|
||||
*/
|
||||
public function login($referer)
|
||||
{
|
||||
if (!empty($_POST['login']) && !empty($_POST['password'])) {
|
||||
$user = $this->store->login($_POST['login'], Tools::encodeString($_POST['password'] . $_POST['login']));
|
||||
if ($user != array()) {
|
||||
# Save login into Session
|
||||
Session::login($user['username'], $user['password'], $_POST['login'], Tools::encodeString($_POST['password'] . $_POST['login']), array('poche_user' => new User($user)));
|
||||
|
||||
$this->messages->add('s', _('welcome to your poche'));
|
||||
if (!empty($_POST['longlastingsession'])) {
|
||||
$_SESSION['longlastingsession'] = 31536000;
|
||||
$_SESSION['expires_on'] = time() + $_SESSION['longlastingsession'];
|
||||
session_set_cookie_params($_SESSION['longlastingsession']);
|
||||
} else {
|
||||
session_set_cookie_params(0);
|
||||
}
|
||||
session_regenerate_id(true);
|
||||
Tools::logm('login successful');
|
||||
Tools::redirect($referer);
|
||||
}
|
||||
$this->messages->add('e', _('login failed: bad login or password'));
|
||||
Tools::logm('login failed');
|
||||
Tools::redirect();
|
||||
} else {
|
||||
$this->messages->add('e', _('login failed: you have to fill all fields'));
|
||||
Tools::logm('login failed');
|
||||
Tools::redirect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* log out the poche user. It cleans the session.
|
||||
* @todo add the return value
|
||||
* @return boolean
|
||||
*/
|
||||
public function logout()
|
||||
{
|
||||
$this->user = array();
|
||||
Session::logout();
|
||||
$this->messages->add('s', _('see you soon!'));
|
||||
Tools::logm('logout');
|
||||
Tools::redirect();
|
||||
}
|
||||
|
||||
/**
|
||||
* import from Instapaper. poche needs a ./instapaper-export.html file
|
||||
* @todo add the return value
|
||||
* @return boolean
|
||||
*/
|
||||
private function importFromInstapaper()
|
||||
{
|
||||
# TODO gestion des articles favs
|
||||
$html = new simple_html_dom();
|
||||
$html->load_file('./instapaper-export.html');
|
||||
Tools::logm('starting import from instapaper');
|
||||
|
||||
$read = 0;
|
||||
$errors = array();
|
||||
foreach($html->find('ol') as $ul)
|
||||
{
|
||||
foreach($ul->find('li') as $li)
|
||||
{
|
||||
$a = $li->find('a');
|
||||
$url = new Url(base64_encode($a[0]->href));
|
||||
$this->action('add', $url, 0, TRUE);
|
||||
if ($read == '1') {
|
||||
$sequence = '';
|
||||
if (STORAGE == 'postgres') {
|
||||
$sequence = 'entries_id_seq';
|
||||
}
|
||||
$last_id = $this->store->getLastId($sequence);
|
||||
$this->action('toggle_archive', $url, $last_id, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
# the second <ol> is for read links
|
||||
$read = 1;
|
||||
}
|
||||
$this->messages->add('s', _('import from instapaper completed'));
|
||||
Tools::logm('import from instapaper completed');
|
||||
Tools::redirect();
|
||||
}
|
||||
|
||||
/**
|
||||
* import from Pocket. poche needs a ./ril_export.html file
|
||||
* @todo add the return value
|
||||
* @return boolean
|
||||
*/
|
||||
private function importFromPocket()
|
||||
{
|
||||
# TODO gestion des articles favs
|
||||
$html = new simple_html_dom();
|
||||
$html->load_file('./ril_export.html');
|
||||
Tools::logm('starting import from pocket');
|
||||
|
||||
$read = 0;
|
||||
$errors = array();
|
||||
foreach($html->find('ul') as $ul)
|
||||
{
|
||||
foreach($ul->find('li') as $li)
|
||||
{
|
||||
$a = $li->find('a');
|
||||
$url = new Url(base64_encode($a[0]->href));
|
||||
$this->action('add', $url, 0, TRUE);
|
||||
if ($read == '1') {
|
||||
$sequence = '';
|
||||
if (STORAGE == 'postgres') {
|
||||
$sequence = 'entries_id_seq';
|
||||
}
|
||||
$last_id = $this->store->getLastId($sequence);
|
||||
$this->action('toggle_archive', $url, $last_id, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
# the second <ul> is for read links
|
||||
$read = 1;
|
||||
}
|
||||
$this->messages->add('s', _('import from pocket completed'));
|
||||
Tools::logm('import from pocket completed');
|
||||
Tools::redirect();
|
||||
}
|
||||
|
||||
/**
|
||||
* import from Readability. poche needs a ./readability file
|
||||
* @todo add the return value
|
||||
* @return boolean
|
||||
*/
|
||||
private function importFromReadability()
|
||||
{
|
||||
# TODO gestion des articles lus / favs
|
||||
$str_data = file_get_contents("./readability");
|
||||
$data = json_decode($str_data,true);
|
||||
Tools::logm('starting import from Readability');
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
$url = '';
|
||||
foreach ($value as $attr => $attr_value) {
|
||||
if ($attr == 'article__url') {
|
||||
$url = new Url(base64_encode($attr_value));
|
||||
}
|
||||
$sequence = '';
|
||||
if (STORAGE == 'postgres') {
|
||||
$sequence = 'entries_id_seq';
|
||||
}
|
||||
// if ($attr_value == 'favorite' && $attr_value == 'true') {
|
||||
// $last_id = $this->store->getLastId($sequence);
|
||||
// $this->store->favoriteById($last_id);
|
||||
// $this->action('toogle_fav', $url, $last_id, TRUE);
|
||||
// }
|
||||
if ($attr_value == 'archive' && $attr_value == 'true') {
|
||||
$last_id = $this->store->getLastId($sequence);
|
||||
$this->action('toggle_archive', $url, $last_id, TRUE);
|
||||
}
|
||||
}
|
||||
if ($url->isCorrect())
|
||||
$this->action('add', $url, 0, TRUE);
|
||||
}
|
||||
$this->messages->add('s', _('import from Readability completed'));
|
||||
Tools::logm('import from Readability completed');
|
||||
Tools::redirect();
|
||||
}
|
||||
|
||||
/**
|
||||
* import datas into your poche
|
||||
* @param string $from name of the service to import : pocket, instapaper or readability
|
||||
* @todo add the return value
|
||||
* @return boolean
|
||||
*/
|
||||
public function import($from)
|
||||
{
|
||||
if ($from == 'pocket') {
|
||||
return $this->importFromPocket();
|
||||
}
|
||||
else if ($from == 'readability') {
|
||||
return $this->importFromReadability();
|
||||
}
|
||||
else if ($from == 'instapaper') {
|
||||
return $this->importFromInstapaper();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* export poche entries in json
|
||||
* @return json all poche entries
|
||||
*/
|
||||
public function export()
|
||||
{
|
||||
$entries = $this->store->retrieveAll($this->user->getId());
|
||||
echo $this->tpl->render('export.twig', array(
|
||||
'export' => Tools::renderJson($entries),
|
||||
));
|
||||
Tools::logm('export view');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks online the latest version of poche and cache it
|
||||
* @param string $which 'prod' or 'dev'
|
||||
* @return string latest $which version
|
||||
*/
|
||||
private function getPocheVersion($which = 'prod')
|
||||
{
|
||||
$cache_file = CACHE . '/' . $which;
|
||||
|
||||
# checks if the cached version file exists
|
||||
if (file_exists($cache_file) && (filemtime($cache_file) > (time() - 86400 ))) {
|
||||
$version = file_get_contents($cache_file);
|
||||
} else {
|
||||
$version = file_get_contents('http://static.inthepoche.com/versions/' . $which);
|
||||
file_put_contents($cache_file, $version, LOCK_EX);
|
||||
}
|
||||
return $version;
|
||||
}
|
||||
}
|
226
inc/poche/Tools.class.php
Normal file
@ -0,0 +1,226 @@
|
||||
<?php
|
||||
/**
|
||||
* poche, a read it later open source system
|
||||
*
|
||||
* @category poche
|
||||
* @author Nicolas Lœuillet <support@inthepoche.com>
|
||||
* @copyright 2013
|
||||
* @license http://www.wtfpl.net/ see COPYING file
|
||||
*/
|
||||
|
||||
class Tools
|
||||
{
|
||||
public static function initPhp()
|
||||
{
|
||||
define('START_TIME', microtime(true));
|
||||
|
||||
if (phpversion() < 5) {
|
||||
die(_('Oops, it seems you don\'t have PHP 5.'));
|
||||
}
|
||||
|
||||
error_reporting(E_ALL);
|
||||
|
||||
function stripslashesDeep($value) {
|
||||
return is_array($value)
|
||||
? array_map('stripslashesDeep', $value)
|
||||
: stripslashes($value);
|
||||
}
|
||||
|
||||
if (get_magic_quotes_gpc()) {
|
||||
$_POST = array_map('stripslashesDeep', $_POST);
|
||||
$_GET = array_map('stripslashesDeep', $_GET);
|
||||
$_COOKIE = array_map('stripslashesDeep', $_COOKIE);
|
||||
}
|
||||
|
||||
ob_start();
|
||||
register_shutdown_function('ob_end_flush');
|
||||
}
|
||||
|
||||
public static function getPocheUrl()
|
||||
{
|
||||
$https = (!empty($_SERVER['HTTPS'])
|
||||
&& (strtolower($_SERVER['HTTPS']) == 'on'))
|
||||
|| (isset($_SERVER["SERVER_PORT"])
|
||||
&& $_SERVER["SERVER_PORT"] == '443'); // HTTPS detection.
|
||||
$serverport = (!isset($_SERVER["SERVER_PORT"])
|
||||
|| $_SERVER["SERVER_PORT"] == '80'
|
||||
|| ($https && $_SERVER["SERVER_PORT"] == '443')
|
||||
? '' : ':' . $_SERVER["SERVER_PORT"]);
|
||||
|
||||
$scriptname = str_replace('/index.php', '/', $_SERVER["SCRIPT_NAME"]);
|
||||
|
||||
if (!isset($_SERVER["SERVER_NAME"])) {
|
||||
return $scriptname;
|
||||
}
|
||||
|
||||
return 'http' . ($https ? 's' : '') . '://'
|
||||
. $_SERVER["SERVER_NAME"] . $serverport . $scriptname;
|
||||
}
|
||||
|
||||
public static function redirect($url = '')
|
||||
{
|
||||
if ($url === '') {
|
||||
$url = (empty($_SERVER['HTTP_REFERER'])?'?':$_SERVER['HTTP_REFERER']);
|
||||
if (isset($_POST['returnurl'])) {
|
||||
$url = $_POST['returnurl'];
|
||||
}
|
||||
}
|
||||
|
||||
# prevent loop
|
||||
if (empty($url) || parse_url($url, PHP_URL_QUERY) === $_SERVER['QUERY_STRING']) {
|
||||
$url = Tools::getPocheUrl();
|
||||
}
|
||||
|
||||
if (substr($url, 0, 1) !== '?') {
|
||||
$ref = Tools::getPocheUrl();
|
||||
if (substr($url, 0, strlen($ref)) !== $ref) {
|
||||
$url = $ref;
|
||||
}
|
||||
}
|
||||
self::logm('redirect to ' . $url);
|
||||
header('Location: '.$url);
|
||||
exit();
|
||||
}
|
||||
|
||||
public static function getTplFile($view)
|
||||
{
|
||||
$tpl_file = 'home.twig';
|
||||
switch ($view)
|
||||
{
|
||||
case 'install':
|
||||
$tpl_file = 'install.twig';
|
||||
break;
|
||||
case 'import';
|
||||
$tpl_file = 'import.twig';
|
||||
break;
|
||||
case 'export':
|
||||
$tpl_file = 'export.twig';
|
||||
break;
|
||||
case 'config':
|
||||
$tpl_file = 'config.twig';
|
||||
break;
|
||||
case 'view':
|
||||
$tpl_file = 'view.twig';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return $tpl_file;
|
||||
}
|
||||
|
||||
public static function getFile($url)
|
||||
{
|
||||
$timeout = 15;
|
||||
$useragent = "Mozilla/5.0 (Windows NT 5.1; rv:18.0) Gecko/20100101 Firefox/18.0";
|
||||
|
||||
if (in_array ('curl', get_loaded_extensions())) {
|
||||
# Fetch feed from URL
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
|
||||
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_HEADER, false);
|
||||
|
||||
# for ssl, do not verified certificate
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
|
||||
curl_setopt($curl, CURLOPT_AUTOREFERER, TRUE );
|
||||
|
||||
# FeedBurner requires a proper USER-AGENT...
|
||||
curl_setopt($curl, CURL_HTTP_VERSION_1_1, true);
|
||||
curl_setopt($curl, CURLOPT_ENCODING, "gzip, deflate");
|
||||
curl_setopt($curl, CURLOPT_USERAGENT, $useragent);
|
||||
|
||||
$data = curl_exec($curl);
|
||||
$httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
$httpcodeOK = isset($httpcode) and ($httpcode == 200 or $httpcode == 301);
|
||||
curl_close($curl);
|
||||
} else {
|
||||
# create http context and add timeout and user-agent
|
||||
$context = stream_context_create(
|
||||
array(
|
||||
'http' => array(
|
||||
'timeout' => $timeout,
|
||||
'header' => "User-Agent: " . $useragent,
|
||||
'follow_location' => true
|
||||
),
|
||||
'ssl' => array(
|
||||
'verify_peer' => false,
|
||||
'allow_self_signed' => true
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
# only download page lesser than 4MB
|
||||
$data = @file_get_contents($url, false, $context, -1, 4000000);
|
||||
|
||||
if (isset($http_response_header) and isset($http_response_header[0])) {
|
||||
$httpcodeOK = isset($http_response_header) and isset($http_response_header[0]) and ((strpos($http_response_header[0], '200 OK') !== FALSE) or (strpos($http_response_header[0], '301 Moved Permanently') !== FALSE));
|
||||
}
|
||||
}
|
||||
|
||||
# if response is not empty and response is OK
|
||||
if (isset($data) and isset($httpcodeOK) and $httpcodeOK) {
|
||||
|
||||
# take charset of page and get it
|
||||
preg_match('#<meta .*charset=.*>#Usi', $data, $meta);
|
||||
|
||||
# if meta tag is found
|
||||
if (!empty($meta[0])) {
|
||||
preg_match('#charset="?(.*)"#si', $meta[0], $encoding);
|
||||
# if charset is found set it otherwise, set it to utf-8
|
||||
$html_charset = (!empty($encoding[1])) ? strtolower($encoding[1]) : 'utf-8';
|
||||
} else {
|
||||
$html_charset = 'utf-8';
|
||||
$encoding[1] = '';
|
||||
}
|
||||
|
||||
# replace charset of url to charset of page
|
||||
$data = str_replace('charset=' . $encoding[1], 'charset=' . $html_charset, $data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
public static function renderJson($data)
|
||||
{
|
||||
header('Cache-Control: no-cache, must-revalidate');
|
||||
header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
|
||||
header('Content-type: application/json; charset=UTF-8');
|
||||
echo json_encode($data);
|
||||
exit();
|
||||
}
|
||||
|
||||
public static function logm($message)
|
||||
{
|
||||
if (DEBUG_POCHE) {
|
||||
$t = strval(date('Y/m/d_H:i:s')) . ' - ' . $_SERVER["REMOTE_ADDR"] . ' - ' . strval($message) . "\n";
|
||||
file_put_contents(CACHE . '/log.txt', $t, FILE_APPEND);
|
||||
error_log('DEBUG POCHE : ' . $message);
|
||||
}
|
||||
}
|
||||
|
||||
public static function encodeString($string)
|
||||
{
|
||||
return sha1($string . SALT);
|
||||
}
|
||||
|
||||
public static function checkVar($var, $default = '')
|
||||
{
|
||||
return ((isset ($_REQUEST["$var"])) ? htmlentities($_REQUEST["$var"]) : $default);
|
||||
}
|
||||
|
||||
public static function getDomain($url)
|
||||
{
|
||||
$pieces = parse_url($url);
|
||||
$domain = isset($pieces['host']) ? $pieces['host'] : '';
|
||||
if (preg_match('/(?P<domain>[a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6})$/i', $domain, $regs)) {
|
||||
return $regs['domain'];
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
94
inc/poche/Url.class.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* poche, a read it later open source system
|
||||
*
|
||||
* @category poche
|
||||
* @author Nicolas Lœuillet <support@inthepoche.com>
|
||||
* @copyright 2013
|
||||
* @license http://www.wtfpl.net/ see COPYING file
|
||||
*/
|
||||
|
||||
class Url
|
||||
{
|
||||
public $url;
|
||||
|
||||
function __construct($url)
|
||||
{
|
||||
$this->url = base64_decode($url);
|
||||
}
|
||||
|
||||
public function getUrl() {
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
public function setUrl($url) {
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
public function isCorrect()
|
||||
{
|
||||
$pattern = '|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i';
|
||||
|
||||
return preg_match($pattern, $this->url);
|
||||
}
|
||||
|
||||
public function clean()
|
||||
{
|
||||
$url = html_entity_decode(trim($this->url));
|
||||
|
||||
$stuff = strpos($url,'&utm_source=');
|
||||
if ($stuff !== FALSE)
|
||||
$url = substr($url, 0, $stuff);
|
||||
$stuff = strpos($url,'?utm_source=');
|
||||
if ($stuff !== FALSE)
|
||||
$url = substr($url, 0, $stuff);
|
||||
$stuff = strpos($url,'#xtor=RSS-');
|
||||
if ($stuff !== FALSE)
|
||||
$url = substr($url, 0, $stuff);
|
||||
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
public function fetchContent()
|
||||
{
|
||||
if ($this->isCorrect()) {
|
||||
$this->clean();
|
||||
$html = Encoding::toUTF8(Tools::getFile($this->getUrl()));
|
||||
|
||||
# if Tools::getFile() if not able to retrieve HTTPS content, try the same URL with HTTP protocol
|
||||
if (!preg_match('!^https?://!i', $this->getUrl()) && (!isset($html) || strlen($html) <= 0)) {
|
||||
$this->setUrl('http://' . $this->getUrl());
|
||||
$html = Encoding::toUTF8(Tools::getFile($this->getUrl()));
|
||||
}
|
||||
|
||||
if (function_exists('tidy_parse_string')) {
|
||||
$tidy = tidy_parse_string($html, array(), 'UTF8');
|
||||
$tidy->cleanRepair();
|
||||
$html = $tidy->value;
|
||||
}
|
||||
|
||||
$parameters = array();
|
||||
if (isset($html) and strlen($html) > 0)
|
||||
{
|
||||
$readability = new Readability($html, $this->getUrl());
|
||||
$readability->convertLinksToFootnotes = CONVERT_LINKS_FOOTNOTES;
|
||||
$readability->revertForcedParagraphElements = REVERT_FORCED_PARAGRAPH_ELEMENTS;
|
||||
|
||||
if($readability->init())
|
||||
{
|
||||
$content = $readability->articleContent->innerHTML;
|
||||
$parameters['title'] = $readability->articleTitle->innerHTML;
|
||||
$parameters['content'] = $content;
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
#$msg->add('e', _('error during url preparation : the link is not valid'));
|
||||
Tools::logm($this->getUrl() . ' is not a valid url');
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
50
inc/poche/User.class.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/**
|
||||
* poche, a read it later open source system
|
||||
*
|
||||
* @category poche
|
||||
* @author Nicolas Lœuillet <support@inthepoche.com>
|
||||
* @copyright 2013
|
||||
* @license http://www.wtfpl.net/ see COPYING file
|
||||
*/
|
||||
|
||||
class User
|
||||
{
|
||||
public $id;
|
||||
public $username;
|
||||
public $name;
|
||||
public $password;
|
||||
public $email;
|
||||
public $config;
|
||||
|
||||
function __construct($user = array())
|
||||
{
|
||||
if ($user != array()) {
|
||||
$this->id = $user['id'];
|
||||
$this->username = $user['username'];
|
||||
$this->name = $user['name'];
|
||||
$this->password = $user['password'];
|
||||
$this->email = $user['email'];
|
||||
$this->config = $user['config'];
|
||||
}
|
||||
}
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getUsername()
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
public function setConfig($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function getConfigValue($name) {
|
||||
return (isset($this->config[$name])) ? $this->config[$name] : FALSE;
|
||||
}
|
||||
}
|
61
inc/poche/config.inc.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* poche, a read it later open source system
|
||||
*
|
||||
* @category poche
|
||||
* @author Nicolas Lœuillet <nicolas@loeuillet.org>
|
||||
* @copyright 2013
|
||||
* @license http://www.wtfpl.net/ see COPYING file
|
||||
*/
|
||||
|
||||
# storage
|
||||
define ('STORAGE','sqlite'); # postgres, mysql, sqlite
|
||||
define ('STORAGE_SERVER', 'localhost'); # leave blank for sqlite
|
||||
define ('STORAGE_DB', 'poche'); # only for postgres & mysql
|
||||
define ('STORAGE_SQLITE', './db/poche.sqlite');
|
||||
define ('STORAGE_USER', 'postgres'); # leave blank for sqlite
|
||||
define ('STORAGE_PASSWORD', 'postgres'); # leave blank for sqlite
|
||||
|
||||
define ('POCHE_VERSION', '1.0-beta1');
|
||||
define ('MODE_DEMO', FALSE);
|
||||
define ('DEBUG_POCHE', TRUE);
|
||||
define ('CONVERT_LINKS_FOOTNOTES', FALSE);
|
||||
define ('REVERT_FORCED_PARAGRAPH_ELEMENTS', FALSE);
|
||||
define ('DOWNLOAD_PICTURES', FALSE);
|
||||
define ('SHARE_TWITTER', TRUE);
|
||||
define ('SHARE_MAIL', TRUE);
|
||||
define ('SALT', '464v54gLLw928uz4zUBqkRJeiPY68zCX');
|
||||
define ('ABS_PATH', 'assets/');
|
||||
define ('TPL', './tpl');
|
||||
define ('LOCALE', './locale');
|
||||
define ('CACHE', './cache');
|
||||
define ('LANG', 'en_EN.UTF8');
|
||||
define ('PAGINATION', '10');
|
||||
define ('THEME', 'light');
|
||||
|
||||
# /!\ Be careful if you change the lines below /!\
|
||||
require_once './inc/poche/User.class.php';
|
||||
require_once './inc/poche/Tools.class.php';
|
||||
require_once './inc/poche/Url.class.php';
|
||||
require_once './inc/3rdparty/class.messages.php';
|
||||
require_once './inc/poche/Poche.class.php';
|
||||
require_once './inc/3rdparty/Readability.php';
|
||||
require_once './inc/3rdparty/Encoding.php';
|
||||
require_once './inc/poche/Database.class.php';
|
||||
require_once './vendor/autoload.php';
|
||||
require_once './inc/3rdparty/simple_html_dom.php';
|
||||
require_once './inc/3rdparty/paginator.php';
|
||||
require_once './inc/3rdparty/Session.class.php';
|
||||
|
||||
if (DOWNLOAD_PICTURES) {
|
||||
require_once './inc/poche/pochePictures.php';
|
||||
}
|
||||
|
||||
$poche = new Poche();
|
||||
#XSRF protection with token
|
||||
// if (!empty($_POST)) {
|
||||
// if (!Session::isToken($_POST['token'])) {
|
||||
// die(_('Wrong token'));
|
||||
// }
|
||||
// unset($_SESSION['tokens']);
|
||||
// }
|
110
inc/poche/pochePictures.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
/**
|
||||
* poche, a read it later open source system
|
||||
*
|
||||
* @category poche
|
||||
* @author Nicolas Lœuillet <support@inthepoche.com>
|
||||
* @copyright 2013
|
||||
* @license http://www.wtfpl.net/ see COPYING file
|
||||
*/
|
||||
|
||||
/**
|
||||
* On modifie les URLS des images dans le corps de l'article
|
||||
*/
|
||||
function filtre_picture($content, $url, $id)
|
||||
{
|
||||
$matches = array();
|
||||
preg_match_all('#<\s*(img)[^>]+src="([^"]*)"[^>]*>#Si', $content, $matches, PREG_SET_ORDER);
|
||||
foreach($matches as $i => $link) {
|
||||
$link[1] = trim($link[1]);
|
||||
if (!preg_match('#^(([a-z]+://)|(\#))#', $link[1])) {
|
||||
$absolute_path = get_absolute_link($link[2],$url);
|
||||
$filename = basename(parse_url($absolute_path, PHP_URL_PATH));
|
||||
$directory = create_assets_directory($id);
|
||||
$fullpath = $directory . '/' . $filename;
|
||||
download_pictures($absolute_path, $fullpath);
|
||||
$content = str_replace($matches[$i][2], $fullpath, $content);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le lien absolu
|
||||
*/
|
||||
function get_absolute_link($relative_link, $url) {
|
||||
/* return if already absolute URL */
|
||||
if (parse_url($relative_link, PHP_URL_SCHEME) != '') return $relative_link;
|
||||
|
||||
/* queries and anchors */
|
||||
if ($relative_link[0]=='#' || $relative_link[0]=='?') return $url . $relative_link;
|
||||
|
||||
/* parse base URL and convert to local variables:
|
||||
$scheme, $host, $path */
|
||||
extract(parse_url($url));
|
||||
|
||||
/* remove non-directory element from path */
|
||||
$path = preg_replace('#/[^/]*$#', '', $path);
|
||||
|
||||
/* destroy path if relative url points to root */
|
||||
if ($relative_link[0] == '/') $path = '';
|
||||
|
||||
/* dirty absolute URL */
|
||||
$abs = $host . $path . '/' . $relative_link;
|
||||
|
||||
/* replace '//' or '/./' or '/foo/../' with '/' */
|
||||
$re = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#');
|
||||
for($n=1; $n>0; $abs=preg_replace($re, '/', $abs, -1, $n)) {}
|
||||
|
||||
/* absolute URL is ready! */
|
||||
return $scheme.'://'.$abs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Téléchargement des images
|
||||
*/
|
||||
function download_pictures($absolute_path, $fullpath)
|
||||
{
|
||||
$rawdata = Tools::getFile($absolute_path);
|
||||
|
||||
if(file_exists($fullpath)) {
|
||||
unlink($fullpath);
|
||||
}
|
||||
$fp = fopen($fullpath, 'x');
|
||||
fwrite($fp, $rawdata);
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un répertoire de médias pour l'article
|
||||
*/
|
||||
function create_assets_directory($id)
|
||||
{
|
||||
$assets_path = ABS_PATH;
|
||||
if(!is_dir($assets_path)) {
|
||||
mkdir($assets_path, 0705);
|
||||
}
|
||||
|
||||
$article_directory = $assets_path . $id;
|
||||
if(!is_dir($article_directory)) {
|
||||
mkdir($article_directory, 0705);
|
||||
}
|
||||
|
||||
return $article_directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppression du répertoire d'images
|
||||
*/
|
||||
function remove_directory($directory)
|
||||
{
|
||||
if(is_dir($directory)) {
|
||||
$files = array_diff(scandir($directory), array('.','..'));
|
||||
foreach ($files as $file) {
|
||||
(is_dir("$directory/$file")) ? remove_directory("$directory/$file") : unlink("$directory/$file");
|
||||
}
|
||||
return rmdir($directory);
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* poche, a read it later open source system
|
||||
*
|
||||
* @category poche
|
||||
* @author Nicolas Lœuillet <support@inthepoche.com>
|
||||
* @copyright 2013
|
||||
* @license http://www.wtfpl.net/ see COPYING file
|
||||
*/
|
||||
|
||||
class File extends Store {
|
||||
function __construct() {
|
||||
|
||||
}
|
||||
|
||||
public function add() {
|
||||
|
||||
}
|
||||
|
||||
public function retrieveOneById($id) {
|
||||
|
||||
}
|
||||
|
||||
public function retrieveOneByURL($url) {
|
||||
|
||||
}
|
||||
|
||||
public function deleteById($id) {
|
||||
|
||||
}
|
||||
|
||||
public function favoriteById($id) {
|
||||
|
||||
}
|
||||
|
||||
public function archiveById($id) {
|
||||
|
||||
}
|
||||
|
||||
public function getEntriesByView($view) {
|
||||
|
||||
}
|
||||
|
||||
public function getLastId() {
|
||||
|
||||
}
|
||||
|
||||
public function updateContentById($id) {
|
||||
|
||||
}
|
||||
}
|
@ -1,202 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* poche, a read it later open source system
|
||||
*
|
||||
* @category poche
|
||||
* @author Nicolas Lœuillet <support@inthepoche.com>
|
||||
* @copyright 2013
|
||||
* @license http://www.wtfpl.net/ see COPYING file
|
||||
*/
|
||||
|
||||
class Sqlite extends Store {
|
||||
|
||||
public static $db_path = 'sqlite:./db/poche.sqlite';
|
||||
var $handle;
|
||||
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->handle = new PDO(self::$db_path);
|
||||
$this->handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
}
|
||||
|
||||
private function getHandle() {
|
||||
return $this->handle;
|
||||
}
|
||||
|
||||
public function isInstalled() {
|
||||
$sql = "SELECT name FROM sqlite_sequence WHERE name=?";
|
||||
$query = $this->executeQuery($sql, array('config'));
|
||||
$hasConfig = $query->fetchAll();
|
||||
|
||||
if (count($hasConfig) == 0)
|
||||
return FALSE;
|
||||
|
||||
if (!$this->getLogin() || !$this->getPassword())
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
public function install($login, $password) {
|
||||
$this->getHandle()->exec('CREATE TABLE IF NOT EXISTS "config" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE , "name" VARCHAR UNIQUE, "value" BLOB)');
|
||||
|
||||
$this->handle->exec('CREATE TABLE IF NOT EXISTS "entries" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE , "title" VARCHAR, "url" VARCHAR UNIQUE , "is_read" INTEGER DEFAULT 0, "is_fav" INTEGER DEFAULT 0, "content" BLOB)');
|
||||
|
||||
if (!$this->getLogin()) {
|
||||
$sql_login = 'INSERT INTO config ( name, value ) VALUES (?, ?)';
|
||||
$params_login = array('login', $login);
|
||||
$query = $this->executeQuery($sql_login, $params_login);
|
||||
}
|
||||
|
||||
if (!$this->getPassword()) {
|
||||
$sql_pass = 'INSERT INTO config ( name, value ) VALUES (?, ?)';
|
||||
$params_pass = array('password', $password);
|
||||
$query = $this->executeQuery($sql_pass, $params_pass);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
public function getLogin() {
|
||||
$sql = "SELECT value FROM config WHERE name=?";
|
||||
$query = $this->executeQuery($sql, array('login'));
|
||||
$login = $query->fetchAll();
|
||||
|
||||
return isset($login[0]['value']) ? $login[0]['value'] : FALSE;
|
||||
}
|
||||
|
||||
public function getPassword() {
|
||||
$sql = "SELECT value FROM config WHERE name=?";
|
||||
$query = $this->executeQuery($sql, array('password'));
|
||||
$pass = $query->fetchAll();
|
||||
|
||||
return isset($pass[0]['value']) ? $pass[0]['value'] : FALSE;
|
||||
}
|
||||
|
||||
public function updatePassword($password)
|
||||
{
|
||||
$sql_update = "UPDATE config SET value=? WHERE name='password'";
|
||||
$params_update = array($password);
|
||||
$query = $this->executeQuery($sql_update, $params_update);
|
||||
}
|
||||
|
||||
private function executeQuery($sql, $params) {
|
||||
try
|
||||
{
|
||||
$query = $this->getHandle()->prepare($sql);
|
||||
$query->execute($params);
|
||||
return $query;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
logm('execute query error : '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function retrieveAll() {
|
||||
$sql = "SELECT * FROM entries ORDER BY id";
|
||||
$query = $this->executeQuery($sql, array());
|
||||
$entries = $query->fetchAll();
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
public function retrieveOneById($id) {
|
||||
parent::__construct();
|
||||
|
||||
$entry = NULL;
|
||||
$sql = "SELECT * FROM entries WHERE id=?";
|
||||
$params = array(intval($id));
|
||||
$query = $this->executeQuery($sql, $params);
|
||||
$entry = $query->fetchAll();
|
||||
|
||||
return $entry[0];
|
||||
}
|
||||
|
||||
public function getEntriesByView($view) {
|
||||
parent::__construct();
|
||||
|
||||
switch ($_SESSION['sort'])
|
||||
{
|
||||
case 'ia':
|
||||
$order = 'ORDER BY id';
|
||||
break;
|
||||
case 'id':
|
||||
$order = 'ORDER BY id DESC';
|
||||
break;
|
||||
case 'ta':
|
||||
$order = 'ORDER BY lower(title)';
|
||||
break;
|
||||
case 'td':
|
||||
$order = 'ORDER BY lower(title) DESC';
|
||||
break;
|
||||
default:
|
||||
$order = 'ORDER BY id';
|
||||
break;
|
||||
}
|
||||
|
||||
switch ($view)
|
||||
{
|
||||
case 'archive':
|
||||
$sql = "SELECT * FROM entries WHERE is_read=? " . $order;
|
||||
$params = array(-1);
|
||||
break;
|
||||
case 'fav' :
|
||||
$sql = "SELECT * FROM entries WHERE is_fav=? " . $order;
|
||||
$params = array(-1);
|
||||
break;
|
||||
default:
|
||||
$sql = "SELECT * FROM entries WHERE is_read=? " . $order;
|
||||
$params = array(0);
|
||||
break;
|
||||
}
|
||||
|
||||
$query = $this->executeQuery($sql, $params);
|
||||
$entries = $query->fetchAll();
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
public function add($url, $title, $content) {
|
||||
parent::__construct();
|
||||
$sql_action = 'INSERT INTO entries ( url, title, content ) VALUES (?, ?, ?)';
|
||||
$params_action = array($url, $title, $content);
|
||||
$query = $this->executeQuery($sql_action, $params_action);
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function deleteById($id) {
|
||||
parent::__construct();
|
||||
$sql_action = "DELETE FROM entries WHERE id=?";
|
||||
$params_action = array($id);
|
||||
$query = $this->executeQuery($sql_action, $params_action);
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function favoriteById($id) {
|
||||
parent::__construct();
|
||||
$sql_action = "UPDATE entries SET is_fav=~is_fav WHERE id=?";
|
||||
$params_action = array($id);
|
||||
$query = $this->executeQuery($sql_action, $params_action);
|
||||
}
|
||||
|
||||
public function archiveById($id) {
|
||||
parent::__construct();
|
||||
$sql_action = "UPDATE entries SET is_read=~is_read WHERE id=?";
|
||||
$params_action = array($id);
|
||||
$query = $this->executeQuery($sql_action, $params_action);
|
||||
}
|
||||
|
||||
public function getLastId() {
|
||||
parent::__construct();
|
||||
return $this->getHandle()->lastInsertId();
|
||||
}
|
||||
|
||||
public function updateContentById($id) {
|
||||
parent::__construct();
|
||||
$sql_update = "UPDATE entries SET content=? WHERE id=?";
|
||||
$params_update = array($content, $id);
|
||||
$query = $this->executeQuery($sql_update, $params_update);
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* poche, a read it later open source system
|
||||
*
|
||||
* @category poche
|
||||
* @author Nicolas Lœuillet <support@inthepoche.com>
|
||||
* @copyright 2013
|
||||
* @license http://www.wtfpl.net/ see COPYING file
|
||||
*/
|
||||
|
||||
class Store {
|
||||
function __construct() {
|
||||
|
||||
}
|
||||
|
||||
public function getLogin() {
|
||||
|
||||
}
|
||||
|
||||
public function getPassword() {
|
||||
|
||||
}
|
||||
|
||||
public function add() {
|
||||
|
||||
}
|
||||
|
||||
public function retrieveAll() {
|
||||
|
||||
}
|
||||
|
||||
public function retrieveOneById($id) {
|
||||
|
||||
}
|
||||
|
||||
public function retrieveOneByURL($url) {
|
||||
|
||||
}
|
||||
|
||||
public function deleteById($id) {
|
||||
|
||||
}
|
||||
|
||||
public function favoriteById($id) {
|
||||
|
||||
}
|
||||
|
||||
public function archiveById($id) {
|
||||
|
||||
}
|
||||
|
||||
public function getEntriesByView($view) {
|
||||
|
||||
}
|
||||
|
||||
public function getLastId() {
|
||||
|
||||
}
|
||||
|
||||
public function updateContentById($id) {
|
||||
|
||||
}
|
||||
}
|
108
index.php
@ -8,83 +8,57 @@
|
||||
* @license http://www.wtfpl.net/ see COPYING file
|
||||
*/
|
||||
|
||||
include dirname(__FILE__).'/inc/config.php';
|
||||
include dirname(__FILE__).'/inc/poche/config.inc.php';
|
||||
|
||||
myTool::initPhp();
|
||||
|
||||
# XSRF protection with token
|
||||
if (!empty($_POST)) {
|
||||
if (!Session::isToken($_POST['token'])) {
|
||||
die('Wrong token.');
|
||||
}
|
||||
unset($_SESSION['tokens']);
|
||||
}
|
||||
|
||||
$ref = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER'];
|
||||
# Parse GET & REFERER vars
|
||||
$referer = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER'];
|
||||
$view = Tools::checkVar('view', 'home');
|
||||
$action = Tools::checkVar('action');
|
||||
$id = Tools::checkVar('id');
|
||||
$_SESSION['sort'] = Tools::checkVar('sort', 'id');
|
||||
$url = new Url((isset ($_GET['url'])) ? $_GET['url'] : '');
|
||||
|
||||
# poche actions
|
||||
if (isset($_GET['login'])) {
|
||||
// Login
|
||||
if (!empty($_POST['login']) && !empty($_POST['password'])) {
|
||||
if (Session::login($_SESSION['login'], $_SESSION['pass'], $_POST['login'], encode_string($_POST['password'] . $_POST['login']))) {
|
||||
logm('login successful');
|
||||
$msg->add('s', 'welcome in your poche!');
|
||||
if (!empty($_POST['longlastingsession'])) {
|
||||
$_SESSION['longlastingsession'] = 31536000;
|
||||
$_SESSION['expires_on'] = time() + $_SESSION['longlastingsession'];
|
||||
session_set_cookie_params($_SESSION['longlastingsession']);
|
||||
} else {
|
||||
session_set_cookie_params(0); // when browser closes
|
||||
}
|
||||
session_regenerate_id(true);
|
||||
|
||||
MyTool::redirect($ref);
|
||||
}
|
||||
logm('login failed');
|
||||
die("Login failed !");
|
||||
} else {
|
||||
logm('login failed');
|
||||
}
|
||||
# hello you
|
||||
$poche->login($referer);
|
||||
}
|
||||
elseif (isset($_GET['logout'])) {
|
||||
logm('logout');
|
||||
Session::logout();
|
||||
MyTool::redirect();
|
||||
# see you soon !
|
||||
$poche->logout();
|
||||
}
|
||||
elseif (isset($_GET['config'])) {
|
||||
if (isset($_POST['password']) && isset($_POST['password_repeat'])) {
|
||||
if ($_POST['password'] == $_POST['password_repeat'] && $_POST['password'] != "") {
|
||||
logm('password updated');
|
||||
if (!DEMO) {
|
||||
$store->updatePassword(encode_string($_POST['password'] . $_SESSION['login']));
|
||||
$msg->add('s', 'your password has been updated');
|
||||
}
|
||||
else {
|
||||
$msg->add('i', 'in demo mode, you can\'t update password');
|
||||
}
|
||||
}
|
||||
else
|
||||
$msg->add('e', 'your password can\'t be empty and you have to repeat it in the second field');
|
||||
}
|
||||
elseif (isset($_GET['config'])) {
|
||||
# Update password
|
||||
$poche->updatePassword();
|
||||
}
|
||||
elseif (isset($_GET['import'])) {
|
||||
$import = $poche->import($_GET['from']);
|
||||
}
|
||||
elseif (isset($_GET['export'])) {
|
||||
$poche->export();
|
||||
}
|
||||
|
||||
# Traitement des paramètres et déclenchement des actions
|
||||
$view = (isset ($_REQUEST['view'])) ? htmlentities($_REQUEST['view']) : 'index';
|
||||
$full_head = (isset ($_REQUEST['full_head'])) ? htmlentities($_REQUEST['full_head']) : 'yes';
|
||||
$action = (isset ($_REQUEST['action'])) ? htmlentities($_REQUEST['action']) : '';
|
||||
$_SESSION['sort'] = (isset ($_REQUEST['sort'])) ? htmlentities($_REQUEST['sort']) : 'id';
|
||||
$id = (isset ($_REQUEST['id'])) ? htmlspecialchars($_REQUEST['id']) : '';
|
||||
$url = (isset ($_GET['url'])) ? $_GET['url'] : '';
|
||||
|
||||
$tpl->assign('isLogged', Session::isLogged());
|
||||
$tpl->assign('referer', $ref);
|
||||
$tpl->assign('view', $view);
|
||||
$tpl->assign('poche_url', myTool::getUrl());
|
||||
$tpl->assign('title', 'poche, a read it later open source system');
|
||||
# vars to send to templates
|
||||
$tpl_vars = array(
|
||||
'referer' => $referer,
|
||||
'view' => $view,
|
||||
'poche_url' => Tools::getPocheUrl(),
|
||||
'title' => _('poche, a read it later open source system'),
|
||||
'token' => Session::getToken(),
|
||||
);
|
||||
|
||||
if (Session::isLogged()) {
|
||||
action_to_do($action, $url, $id);
|
||||
display_view($view, $id, $full_head);
|
||||
$poche->action($action, $url, $id);
|
||||
$tpl_file = Tools::getTplFile($view);
|
||||
$tpl_vars = array_merge($tpl_vars, $poche->displayView($view, $id));
|
||||
}
|
||||
else {
|
||||
$tpl->draw('login');
|
||||
$tpl_file = 'login.twig';
|
||||
}
|
||||
|
||||
# because messages can be added in $poche->action(), we have to add this entry now (we can add it before)
|
||||
$messages = $poche->messages->display('all', FALSE);
|
||||
$tpl_vars = array_merge($tpl_vars, array('messages' => $messages));
|
||||
|
||||
# display poche
|
||||
echo $poche->tpl->render($tpl_file, $tpl_vars);
|
34
install/mysql.sql
Normal file
@ -0,0 +1,34 @@
|
||||
CREATE TABLE IF NOT EXISTS `config` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`value` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `entries` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`title` varchar(255) NOT NULL,
|
||||
`url` varchar(255) NOT NULL,
|
||||
`is_read` tinyint(1) NOT NULL,
|
||||
`is_fav` tinyint(1) NOT NULL,
|
||||
`content` blob NOT NULL,
|
||||
`user_id` int(11) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `users` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`username` varchar(255) NOT NULL,
|
||||
`password` varchar(255) NOT NULL,
|
||||
`name` int(255) NOT NULL,
|
||||
`email` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `users_config` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`value` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
30
install/postgres.sql
Normal file
@ -0,0 +1,30 @@
|
||||
CREATE TABLE config (
|
||||
id bigserial primary key,
|
||||
name varchar(255) NOT NULL,
|
||||
value varchar(255) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE entries (
|
||||
id bigserial primary key,
|
||||
title varchar(255) NOT NULL,
|
||||
url varchar(255) NOT NULL,
|
||||
is_read boolean DEFAULT false,
|
||||
is_fav boolean DEFAULT false,
|
||||
content TEXT,
|
||||
user_id integer NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE users (
|
||||
id bigserial primary key,
|
||||
username varchar(255) NOT NULL,
|
||||
password varchar(255) NOT NULL,
|
||||
name varchar(255) NOT NULL,
|
||||
email varchar(255) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE users_config (
|
||||
id bigserial primary key,
|
||||
user_id integer NOT NULL,
|
||||
name varchar(255) NOT NULL,
|
||||
value varchar(255) NOT NULL
|
||||
);
|
72
install/update_sqlite_from_0_to_1.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
# import script to upgrade from poche 0.3
|
||||
$db_path = 'sqlite:../db/poche.sqlite';
|
||||
$handle = new PDO($db_path);
|
||||
$handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
# Requêtes à exécuter pour mettre à jour poche.sqlite en 1.x
|
||||
|
||||
# ajout d'un champ user_id sur la table entries
|
||||
$sql = 'ALTER TABLE entries RENAME TO tempEntries;';
|
||||
$query = $handle->prepare($sql);
|
||||
$query->execute();
|
||||
|
||||
$sql = 'CREATE TABLE entries (id INTEGER PRIMARY KEY, title TEXT, url TEXT, is_read NUMERIC DEFAULT 0, is_fav NUMERIC DEFAULT 0, content BLOB, user_id NUMERIC);';
|
||||
$query = $handle->prepare($sql);
|
||||
$query->execute();
|
||||
|
||||
$sql = 'INSERT INTO entries (id, title, url, is_read, is_fav, content) SELECT id, title, url, is_read, is_fav, content FROM tempEntries;';
|
||||
$query = $handle->prepare($sql);
|
||||
$query->execute();
|
||||
|
||||
# Update tout pour mettre user_id = 1
|
||||
$sql = 'UPDATE entries SET user_id = 1;';
|
||||
$query = $handle->prepare($sql);
|
||||
$query->execute();
|
||||
|
||||
# Changement des flags pour les lus / favoris
|
||||
$sql = 'UPDATE entries SET is_read = 1 WHERE is_read = -1;';
|
||||
$query = $handle->prepare($sql);
|
||||
$query->execute();
|
||||
|
||||
$sql = 'UPDATE entries SET is_fav = 1 WHERE is_fav = -1;';
|
||||
$query = $handle->prepare($sql);
|
||||
$query->execute();
|
||||
|
||||
# Création de la table users
|
||||
$sql = 'CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT, password TEXT, name TEXT, email TEXT);';
|
||||
$query = $handle->prepare($sql);
|
||||
$query->execute();
|
||||
|
||||
$sql = 'INSERT INTO users (username) SELECT value FROM config WHERE name = "login";';
|
||||
$query = $handle->prepare($sql);
|
||||
$query->execute();
|
||||
|
||||
$sql = "UPDATE users SET password = (SELECT value FROM config WHERE name = 'password')";
|
||||
$query = $handle->prepare($sql);
|
||||
$query->execute();
|
||||
|
||||
# Création de la table users_config
|
||||
$sql = 'CREATE TABLE users_config (id INTEGER PRIMARY KEY, user_id NUMERIC, name TEXT, value TEXT);';
|
||||
$query = $handle->prepare($sql);
|
||||
$query->execute();
|
||||
|
||||
$sql = 'INSERT INTO users_config (user_id, name, value) VALUES (1, "pager", "10");';
|
||||
$query = $handle->prepare($sql);
|
||||
$query->execute();
|
||||
|
||||
$sql = 'INSERT INTO users_config (user_id, name, value) VALUES (1, "language", "en_EN.UTF8");';
|
||||
$query = $handle->prepare($sql);
|
||||
$query->execute();
|
||||
|
||||
# Suppression de la table temporaire
|
||||
$sql = 'DROP TABLE tempEntries;';
|
||||
$query = $handle->prepare($sql);
|
||||
$query->execute();
|
||||
|
||||
# Vidage de la table de config
|
||||
$sql = 'DELETE FROM config;';
|
||||
$query = $handle->prepare($sql);
|
||||
$query->execute();
|
||||
|
||||
echo 'welcome to poche 1.0 !';
|
5
js/jquery-1.9.1.min.js
vendored
10
js/jquery.masonry.min.js
vendored
57
js/poche.js
@ -1,57 +0,0 @@
|
||||
function toggle_favorite(element, id) {
|
||||
$(element).toggleClass('fav-off');
|
||||
$.ajax ({
|
||||
url: "index.php?action=toggle_fav",
|
||||
data:{id:id}
|
||||
});
|
||||
}
|
||||
|
||||
function toggle_archive(element, id, view_article) {
|
||||
$(element).toggleClass('archive-off');
|
||||
$.ajax ({
|
||||
url: "index.php?action=toggle_archive",
|
||||
data:{id:id}
|
||||
});
|
||||
var obj = $('#entry-'+id);
|
||||
|
||||
// on vient de la vue de l'article, donc pas de gestion de grille
|
||||
if (view_article != 1) {
|
||||
$('#content').masonry('remove',obj);
|
||||
$('#content').masonry('reloadItems');
|
||||
$('#content').masonry('reload');
|
||||
}
|
||||
}
|
||||
|
||||
function sort_links(view, sort) {
|
||||
$.get('index.php', { view: view, sort: sort, full_head: 'no' }, function(data) {
|
||||
$('#content').html(data);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ---------- Swith light or dark view
|
||||
function setActiveStyleSheet(title) {
|
||||
var i, a, main;
|
||||
for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
|
||||
if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title")) {
|
||||
a.disabled = true;
|
||||
if(a.getAttribute("title") == title) a.disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
$('#themeswitch').click(function() {
|
||||
// we want the dark
|
||||
if ($('body').hasClass('light-style')) {
|
||||
setActiveStyleSheet('dark-style');
|
||||
$('body').addClass('dark-style');
|
||||
$('body').removeClass('light-style');
|
||||
$('#themeswitch').text('light');
|
||||
// we want the light
|
||||
} else if ($('body').hasClass('dark-style')) {
|
||||
setActiveStyleSheet('light-style');
|
||||
$('body').addClass('light-style');
|
||||
$('body').removeClass('dark-style');
|
||||
$('#themeswitch').text('dark');
|
||||
}
|
||||
return false;
|
||||
});
|
BIN
locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.mo
Normal file
376
locale/fr_FR.UTF8/LC_MESSAGES/fr_FR.UTF8.po
Normal file
@ -0,0 +1,376 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: poche\n"
|
||||
"POT-Creation-Date: 2013-08-06 08:35+0100\n"
|
||||
"PO-Revision-Date: 2013-08-06 08:35+0100\n"
|
||||
"Last-Translator: Nicolas Lœuillet <nicolas.loeuillet@gmail.com>\n"
|
||||
"Language-Team: poche <support@inthepoche.com>\n"
|
||||
"Language: Français\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 1.5.4\n"
|
||||
"X-Poedit-KeywordsList: _;gettext;gettext_noop\n"
|
||||
"X-Poedit-Basepath: /\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"X-Poedit-SearchPath-0: /var/www/poche-i18n\n"
|
||||
|
||||
#: /var/www/poche-i18n/index.php:43
|
||||
msgid "poche, a read it later open source system"
|
||||
msgstr "poche, a read it later open source system"
|
||||
|
||||
#: /var/www/poche-i18n/inc/poche/Poche.class.php:101
|
||||
msgid "the link has been added successfully"
|
||||
msgstr "le lien a été ajouté avec succès"
|
||||
|
||||
#: /var/www/poche-i18n/inc/poche/Poche.class.php:104
|
||||
msgid "error during insertion : the link wasn't added"
|
||||
msgstr "erreur durant l'insertion : le lien n'a pas été ajouté"
|
||||
|
||||
#: /var/www/poche-i18n/inc/poche/Poche.class.php:109
|
||||
msgid "error during fetching content : the link wasn't added"
|
||||
msgstr "erreur durant la récupération du contenu : le lien n'a pas été ajouté"
|
||||
|
||||
#: /var/www/poche-i18n/inc/poche/Poche.class.php:119
|
||||
msgid "the link has been deleted successfully"
|
||||
msgstr "le lien a été supprimé avec succès"
|
||||
|
||||
#: /var/www/poche-i18n/inc/poche/Poche.class.php:123
|
||||
msgid "the link wasn't deleted"
|
||||
msgstr "le lien n'a pas été supprimé"
|
||||
|
||||
#: /var/www/poche-i18n/inc/poche/Tools.class.php:18
|
||||
msgid "Oops, it seems you don't have PHP 5."
|
||||
msgstr "Oups, il semblerait que PHP 5 ne soit pas installé. "
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:32
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:70
|
||||
#: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:50
|
||||
msgid "config"
|
||||
msgstr "config"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:46
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:31
|
||||
#: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:26
|
||||
#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:34
|
||||
msgid "home"
|
||||
msgstr "accueil"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:54
|
||||
#: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:34
|
||||
msgid "favorites"
|
||||
msgstr "favoris"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:62
|
||||
#: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:42
|
||||
msgid "archive"
|
||||
msgstr "archives"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:74
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:76
|
||||
#: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:54
|
||||
#: /var/www/poche-i18n/cache/76/a4/e7c21f2e0ba29104fc654cd8ba41.php:56
|
||||
msgid "logout"
|
||||
msgstr "déconnexion"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:87
|
||||
msgid "Bookmarklet"
|
||||
msgstr "Bookmarklet"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:91
|
||||
msgid ""
|
||||
"Thanks to the bookmarklet, you will be able to easily add a link to your "
|
||||
"poche."
|
||||
msgstr ""
|
||||
"Grâce au bookmarklet, vous pouvez ajouter facilement un lien dans votre "
|
||||
"poche."
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:93
|
||||
msgid "Have a look to this documentation:"
|
||||
msgstr "Jetez un œil à la documentation :"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:97
|
||||
msgid "Drag & drop this link to your bookmarks bar and have fun with poche."
|
||||
msgstr ""
|
||||
"Glissez / déposez ce lien dans votre barre de favoris de votre navigateur et "
|
||||
"prenez du bon temps avec poche."
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:103
|
||||
msgid "poche it!"
|
||||
msgstr "poche-le !"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:108
|
||||
msgid "Updating poche"
|
||||
msgstr "Mettre à jour poche"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:113
|
||||
msgid "your version"
|
||||
msgstr "votre version"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:119
|
||||
msgid "latest stable version"
|
||||
msgstr "dernière version stable"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:125
|
||||
msgid "a more recent stable version is available."
|
||||
msgstr "une version stable plus récente est disponible."
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:128
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:142
|
||||
msgid "you are up to date."
|
||||
msgstr "vous êtes à jour."
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:133
|
||||
msgid "latest dev version"
|
||||
msgstr "dernière version de développement"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:139
|
||||
msgid "a more recent development version is available."
|
||||
msgstr "une version de développement plus récente est disponible."
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:150
|
||||
msgid "Change your password"
|
||||
msgstr "Modifier votre mot de passe"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:157
|
||||
msgid "New password:"
|
||||
msgstr "Nouveau mot de passe :"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:161
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:171
|
||||
#: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:60
|
||||
#: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:68
|
||||
msgid "Password"
|
||||
msgstr "Mot de passe"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:167
|
||||
msgid "Repeat your new password:"
|
||||
msgstr "Répétez le nouveau mot de passe :"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:177
|
||||
msgid "Update"
|
||||
msgstr "Mettre à jour"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:193
|
||||
msgid "Import"
|
||||
msgstr "Import"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:197
|
||||
msgid "Please execute the import script locally, it can take a very long time."
|
||||
msgstr "Merci d'exécuter l'import en local, cela peut prendre du temps. "
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:201
|
||||
msgid "More infos in the official doc:"
|
||||
msgstr "Plus d'infos sur la documentation officielle :"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:206
|
||||
msgid "import from Pocket"
|
||||
msgstr "l'import depuis Pocket est terminé."
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:210
|
||||
msgid "import from Readability"
|
||||
msgstr "l'import depuis Readability est terminé."
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:214
|
||||
msgid "import from Instapaper"
|
||||
msgstr "Import depuis Instapaper"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:220
|
||||
msgid "Export your poche datas"
|
||||
msgstr "Exporter vos données de poche"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:224
|
||||
msgid "Click here"
|
||||
msgstr "Cliquez-ici"
|
||||
|
||||
#: /var/www/poche-i18n/cache/c9/b0/845a8dc93165e6c00b6b43068799.php:226
|
||||
msgid "to export your poche datas."
|
||||
msgstr "pour exporter vos données de poche."
|
||||
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:46
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:139
|
||||
#: /var/www/poche-i18n/cache/30/97/b548692380c89d047a16cec7af79.php:22
|
||||
msgid "back to home"
|
||||
msgstr "retour à l'accueil"
|
||||
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:50
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:147
|
||||
#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:119
|
||||
msgid "toggle mark as read"
|
||||
msgstr "marquer comme lu"
|
||||
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:60
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:157
|
||||
#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:129
|
||||
msgid "toggle favorite"
|
||||
msgstr "favori"
|
||||
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:70
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:167
|
||||
#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:139
|
||||
msgid "delete"
|
||||
msgstr "supprimer"
|
||||
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:82
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:179
|
||||
msgid "tweet"
|
||||
msgstr "tweeter"
|
||||
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:93
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:190
|
||||
msgid "email"
|
||||
msgstr "envoyer par email"
|
||||
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:109
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:125
|
||||
#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:153
|
||||
msgid "original"
|
||||
msgstr "original"
|
||||
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:143
|
||||
msgid "back to top"
|
||||
msgstr "retour en haut de page"
|
||||
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:198
|
||||
msgid "this article appears wrong?"
|
||||
msgstr "cet article s'affiche mal ?"
|
||||
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:200
|
||||
msgid "create an issue"
|
||||
msgstr "créer un ticket"
|
||||
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:202
|
||||
msgid "or"
|
||||
msgstr "ou"
|
||||
|
||||
#: /var/www/poche-i18n/cache/7a/1e/68e6b4aec1301ae024cc85232e7c.php:206
|
||||
msgid "contact us by mail"
|
||||
msgstr "contactez-nous par email"
|
||||
|
||||
#: /var/www/poche-i18n/cache/88/8a/ee3b7080c13204391c14947a0c2c.php:22
|
||||
msgid "powered by"
|
||||
msgstr "propulsé par"
|
||||
|
||||
#: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:31
|
||||
msgid "installation"
|
||||
msgstr "installation"
|
||||
|
||||
#: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:42
|
||||
msgid "install your poche"
|
||||
msgstr "installez votre poche"
|
||||
|
||||
#: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:47
|
||||
msgid ""
|
||||
"poche is still not installed. Please fill the below form to install it. "
|
||||
"Don't hesitate to <a href='http://inthepoche.com/?pages/Documentation'>read "
|
||||
"the documentation on poche website</a>."
|
||||
msgstr ""
|
||||
"poche n'est pas encore installé. Merci de remplir les champs ci-dessous pour "
|
||||
"l'installer. N'hésitez pas à <a href='http://inthepoche.com/?pages/"
|
||||
"Documentation'>lire la documentation sur le site de poche</a>."
|
||||
|
||||
#: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:53
|
||||
#: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:55
|
||||
msgid "Login"
|
||||
msgstr "Nom d'utilisateur"
|
||||
|
||||
#: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:67
|
||||
msgid "Repeat your password"
|
||||
msgstr "Répétez votre mot de passe"
|
||||
|
||||
#: /var/www/poche-i18n/cache/d4/28/e0d08991ec2d8a7b133505e7c651.php:74
|
||||
msgid "Install"
|
||||
msgstr "Installer"
|
||||
|
||||
#: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:31
|
||||
#: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:42
|
||||
msgid "login to your poche"
|
||||
msgstr "Se connecter à votre poche"
|
||||
|
||||
#: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:48
|
||||
msgid "you are in demo mode, some features may be disabled."
|
||||
msgstr ""
|
||||
"vous êtes en mode démo, certaines fonctionnalités sont peut-être désactivées."
|
||||
|
||||
#: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:80
|
||||
msgid "Stay signed in"
|
||||
msgstr "rester connecté"
|
||||
|
||||
#: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:86
|
||||
msgid "(Do not check on public computers)"
|
||||
msgstr "(à ne pas cocher sur un ordinateur public)"
|
||||
|
||||
#: /var/www/poche-i18n/cache/ae/26/05eb67771213c16bd8c9aaf2d2c4.php:93
|
||||
msgid "Sign in"
|
||||
msgstr ""
|
||||
|
||||
#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:55
|
||||
#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:57
|
||||
msgid "by date asc"
|
||||
msgstr "par date asc"
|
||||
|
||||
#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:59
|
||||
msgid "by date"
|
||||
msgstr "par date"
|
||||
|
||||
#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:65
|
||||
#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:67
|
||||
msgid "by date desc"
|
||||
msgstr "par date desc"
|
||||
|
||||
#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:75
|
||||
#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:77
|
||||
msgid "by title asc"
|
||||
msgstr "par titre asc"
|
||||
|
||||
#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:79
|
||||
msgid "by title"
|
||||
msgstr "par titre"
|
||||
|
||||
#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:85
|
||||
#: /var/www/poche-i18n/cache/dd/a8/530129765655dcde0a70a31a78b6.php:87
|
||||
msgid "by title desc"
|
||||
msgstr "par titre desc"
|
||||
|
||||
#~ msgid "Please choose between Pocket & Readabilty :"
|
||||
#~ msgstr "Merci de choisir entre Pocket & Readability :"
|
||||
|
||||
#~ msgid "Bye bye Pocket, let's go !"
|
||||
#~ msgstr "Bye bye Pocket, en route !"
|
||||
|
||||
#~ msgid "Bye bye Readability, let's go !"
|
||||
#~ msgstr "Bye bye Readability, en route !"
|
||||
|
||||
#~ msgid "Welcome to poche !"
|
||||
#~ msgstr "Bienvenue dans poche !"
|
||||
|
||||
#~ msgid "Error with the import."
|
||||
#~ msgstr "Erreur durant l'import."
|
||||
|
||||
#~ msgid "Wrong token."
|
||||
#~ msgstr "Mauvais jeton."
|
||||
|
||||
#~ msgid "Login failed !"
|
||||
#~ msgstr "Connexion échouée."
|
||||
|
||||
#~ msgid "your password has been updated"
|
||||
#~ msgstr "Votre mot de passe a été mis à jour. "
|
||||
|
||||
#~ msgid "in demo mode, you can't update password"
|
||||
#~ msgstr "En mode démo, le mot de passe ne peut être modifié."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "your password can't be empty and you have to repeat it in the second field"
|
||||
#~ msgstr ""
|
||||
#~ "Votre mot de passe ne peut être vide et vous devez le répéter dans le "
|
||||
#~ "second champ."
|
||||
|
||||
#~ msgid "error during url preparation : the link wasn't added"
|
||||
#~ msgstr "erreur durant l'insertion : le lien n'a pas été ajouté"
|
||||
|
||||
#~ msgid "error during url preparation : the link is not valid"
|
||||
#~ msgstr "erreur durant la préparation de l'URL : le lien n'est pas valide"
|
||||
|
||||
#~ msgid "TEST"
|
||||
#~ msgstr "NICOLAS"
|
0
phpunit.xml.dist
Normal file
3
tpl/_bookmarklet.twig
Normal file
@ -0,0 +1,3 @@
|
||||
<script type="text/javascript">
|
||||
top["bookmarklet-url@inthepoche.com"]=""+"<!DOCTYPE html>"+"<html>"+"<head>"+"<title>poche it !</title>"+'<link rel="icon" href="{{poche_url}}tpl/img/favicon.ico" />'+"</head>"+"<body>"+"<script>"+"window.onload=function(){"+"window.setTimeout(function(){"+"history.back();"+"},250);"+"};"+"</scr"+"ipt>"+"</body>"+"</html>"
|
||||
</script>
|
4
tpl/_footer.twig
Normal file
@ -0,0 +1,4 @@
|
||||
<footer class="w600p center mt3 smaller txtright">
|
||||
<p>{% trans "powered by" %} <a href="http://inthepoche.com">poche</a></p>
|
||||
{% if constant('DEBUG_POCHE') == 1 %}<p><strong>{% trans "debug mode is on so cache is off." %} {% trans "your poche version:" %}{{constant('POCHE_VERSION')}}. {% trans "storage:" %} {{constant('STORAGE')}}</strong></p>{% endif %}
|
||||
</footer>
|
9
tpl/_head.twig
Normal file
@ -0,0 +1,9 @@
|
||||
<link rel="shortcut icon" type="image/x-icon" href="./tpl/img/favicon.ico" />
|
||||
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="./tpl/img/apple-touch-icon-144x144-precomposed.png">
|
||||
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="./tpl/img/apple-touch-icon-72x72-precomposed.png">
|
||||
<link rel="apple-touch-icon-precomposed" href="./tpl/img/apple-touch-icon-precomposed.png">
|
||||
<link rel="stylesheet" href="./tpl/css/knacss.css" media="all">
|
||||
<link rel="stylesheet" href="./tpl/css/style.css" media="all">
|
||||
<link rel="stylesheet" href="./tpl/css/style-{{ constant('THEME') }}.css" media="all" title="{{ constant('THEME') }} theme">
|
||||
<link rel="stylesheet" href="./tpl/css/messages.css" media="all">
|
||||
<link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>
|
7
tpl/_menu.twig
Normal file
@ -0,0 +1,7 @@
|
||||
<ul id="links">
|
||||
<li><a href="./" {% if view == 'home' %}class="current"{% endif %}>{% trans "home" %}</a></li>
|
||||
<li><a href="./?view=fav" {% if view == 'fav' %}class="current"{% endif %}>{% trans "favorites" %}</a></li>
|
||||
<li><a href="./?view=archive" {% if view == 'archive' %}class="current"{% endif %}>{% trans "archive" %}</a></li>
|
||||
<li><a href="./?view=config" {% if view == 'config' %}class="current"{% endif %}>{% trans "config" %}</a></li>
|
||||
<li><a href="./?logout" title="{% trans "logout" %}">{% trans "logout" %}</a></li>
|
||||
</ul>
|
1
tpl/_messages.twig
Normal file
@ -0,0 +1 @@
|
||||
{{ messages | raw }}
|
3
tpl/_top.twig
Normal file
@ -0,0 +1,3 @@
|
||||
<header class="w600p center mbm">
|
||||
<h1><a href="./" title="{% trans "back to home" %}" ><img src="./tpl/img/logo.png" alt="logo poche" /></a></h1>
|
||||
</header>
|
@ -1,27 +0,0 @@
|
||||
<div id="content">
|
||||
<h2>Bookmarklet</h2>
|
||||
<p>Thanks to the bookmarklet, you will be able to easily add a link to your poche. If you don't know how use a bookmarklet, <a href="http://support.mozilla.org/en-US/kb/bookmarklets-perform-common-web-page-tasks">have a look here</a>.</p>
|
||||
<p>Drag & drop this link to your bookmarks bar and have fun with poche.</p>
|
||||
<p><a style="cursor: move; border: 1px dashed grey; background: white;" title="i am a bookmarklet, use me !" href="javascript:(function(){var%20url%20=%20location.href%20||%20url;window.open('{$poche_url}?action=add&url='%20+%20encodeURIComponent(url),'_self');})();">poche it !</a></p>
|
||||
|
||||
<h2>Password</h2>
|
||||
<form method="post" action="?config" name="loginform">
|
||||
<fieldset class="w500p">
|
||||
<div class="row">
|
||||
<label class="col w150p" for="password">New password</label>
|
||||
<input class="col" type="password" id="password" name="password" placeholder="Password" tabindex="2">
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="col w150p" for="password_repeat">Repeat your new password</label>
|
||||
<input class="col" type="password" id="password_repeat" name="password_repeat" placeholder="Password" tabindex="3">
|
||||
</div>
|
||||
<div class="row mts txtcenter">
|
||||
<button class="bouton" type="submit" tabindex="4">Update</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
<input type="hidden" name="returnurl" value="<?php echo htmlspecialchars($referer);?>">
|
||||
<input type="hidden" name="token" value="<?php echo Session::getToken(); ?>">
|
||||
</form>
|
||||
<h2>Export</h2>
|
||||
<p><a href="?view=export" target="_blank">Click here</a> to export your poche datas.</p>
|
||||
</div>
|
57
tpl/config.twig
Normal file
@ -0,0 +1,57 @@
|
||||
{% extends "layout.twig" %}
|
||||
|
||||
{% block title %}{% trans "config" %}{% endblock %}
|
||||
{% block menu %}
|
||||
<ul id="links">
|
||||
<li><a href="./" {% if view == 'home' %}class="current"{% endif %}>{% trans "home" %}</a></li>
|
||||
<li><a href="./?view=fav" {% if view == 'fav' %}class="current"{% endif %}>{% trans "favorites" %}</a></li>
|
||||
<li><a href="./?view=archive" {% if view == 'archive' %}class="current"{% endif %}>{% trans "archive" %}</a></li>
|
||||
<li><a href="./?view=config" {% if view == 'config' %}class="current"{% endif %}>{% trans "config" %}</a></li>
|
||||
<li><a href="./?logout" title="{% trans "logout" %}">{% trans "logout" %}</a></li>
|
||||
</ul>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h2>{% trans "Bookmarklet" %}</h2>
|
||||
<p>{% trans "Thanks to the bookmarklet, you will be able to easily add a link to your poche." %} {% trans "Have a look to this documentation:" %} <a href="http://inthepoche.com/?pages/Documentation">inthepoche.com</a>.</p>
|
||||
<p>{% trans "Drag & drop this link to your bookmarks bar and have fun with poche." %}</p>
|
||||
<p class="txtcenter"><a ondragend="this.click();" style="cursor: move; border: 1px dashed grey; background: white; padding: 5px;" title="i am a bookmarklet, use me !" href="javascript:if(top['bookmarklet-url@inthepoche.com']){top['bookmarklet-url@inthepoche.com'];}else{(function(){var%20url%20=%20location.href%20||%20url;window.open('{{ poche_url }}?action=add&url='%20+%20btoa(url),'_self');})();void(0);}">{% trans "poche it!" %}</a></p>
|
||||
|
||||
<h2>{% trans "Updating poche" %}</h2>
|
||||
<p><ul>
|
||||
<li>{% trans "your version" %} : <strong>{{ constant('POCHE_VERSION') }}</strong></li>
|
||||
<li>{% trans "latest stable version" %} : {{ prod }}. {% if compare_prod == -1 %}<strong><a href="http://inthepoche.com/?pages/T%C3%A9l%C3%A9charger-poche">{% trans "a more recent stable version is available." %}</a></strong>{% else %}{% trans "you are up to date." %}{% endif %}</li>
|
||||
<li>{% trans "latest dev version" %} : {{ dev }}. {% if compare_dev == -1 %}<strong><a href="http://inthepoche.com/?pages/T%C3%A9l%C3%A9charger-poche">{% trans "a more recent development version is available." %}</a></strong>{% else %}{% trans "you are up to date." %}{% endif %}</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<h2>{% trans "Change your password" %}</h2>
|
||||
<form method="post" action="?config" name="loginform">
|
||||
<fieldset class="w500p">
|
||||
<div class="row">
|
||||
<label class="col w150p" for="password">{% trans "New password:" %}</label>
|
||||
<input class="col" type="password" id="password" name="password" placeholder="{% trans "Password" %}" tabindex="2">
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="col w150p" for="password_repeat">{% trans "Repeat your new password:" %}</label>
|
||||
<input class="col" type="password" id="password_repeat" name="password_repeat" placeholder="{% trans "Password" %}" tabindex="3">
|
||||
</div>
|
||||
<div class="row mts txtcenter">
|
||||
<button class="bouton" type="submit" tabindex="4">{% trans "Update" %}</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
<input type="hidden" name="returnurl" value="{{ referer }}">
|
||||
<input type="hidden" name="token" value="{{ token }}">
|
||||
</form>
|
||||
|
||||
<h2>{% trans "Import" %}</h2>
|
||||
<p>{% trans "Please execute the import script locally, it can take a very long time." %}</p>
|
||||
<p>{% trans "More infos in the official doc:" %} <a href="http://inthepoche.com/?pages/Documentation">inthepoche.com</a></p>
|
||||
<p><ul>
|
||||
<li><a href="./?import&from=pocket">{% trans "import from Pocket" %}</a> (you must have a "ril_export.html" file on your server)</li>
|
||||
<li><a href="./?import&from=readability">{% trans "import from Readability" %}</a> (you must have a "readability" file on your server)</li>
|
||||
<li><a href="./?import&from=instapaper">{% trans "import from Instapaper" %}</a> (you must have a "instapaper-export.html" file on your server)</li>
|
||||
</ul></p>
|
||||
|
||||
<h2>{% trans "Export your poche datas" %}</h2>
|
||||
<p><a href="./?export" target="_blank">{% trans "Click here" %}</a> {% trans "to export your poche datas." %}</p>
|
||||
{% endblock %}
|
13
tpl/css/messages.css
Executable file
@ -0,0 +1,13 @@
|
||||
.messages { width: 400px; -moz-border-radius: 4px; border-radius: 4px; display: block; padding: 10px 0; margin: 10px auto 10px; clear: both; }
|
||||
.messages a.closeMessage { margin: -14px -8px 0 0; display:none; width: 16px; height: 16px; float: right; background: url(../img/messages/close.png) no-repeat; }
|
||||
/*.messages:hover a.closeMessage { visibility:visible; }*/
|
||||
.messages p { margin: 3px 0 3px 10px !important; padding: 0 10px 0 23px !important; font-size: 14px; line-height: 16px; }
|
||||
.messages.error { border: 1px solid #C42608; color: #c00 !important; background: #FFF0EF; }
|
||||
.messages.error p { background: url(../img/messages/cross.png ) no-repeat 0px 50%; color:#c00 !important; }
|
||||
.messages.success {background: #E0FBCC; border: 1px solid #6DC70C; }
|
||||
.messages.success p { background: url(../img/messages/tick.png) no-repeat 0px 50%; color: #2B6301 !important; }
|
||||
.messages.warning { background: #FFFCD3; border: 1px solid #EBCD41; color: #000; }
|
||||
.messages.warning p { background: url(../img/messages/warning.png ) no-repeat 0px 50%; color: #5F4E01; }
|
||||
.messages.information, .messages.info { background: #DFEBFB; border: 1px solid #82AEE7; }
|
||||
.messages.information p, .messages.info p { background: url(../img/messages/help.png ) no-repeat 0px 50%; color: #064393; }
|
||||
.messages.information a { text-decoration: underline; }
|
53
tpl/css/style-light.css
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
a.back span {
|
||||
background: url('../img/light/left.png') no-repeat;
|
||||
}
|
||||
|
||||
a.top span {
|
||||
background: url('../img/light/top.png') no-repeat;
|
||||
}
|
||||
|
||||
|
||||
a.fav span {
|
||||
background: url('../img/light/star-on.png') no-repeat;
|
||||
}
|
||||
|
||||
a.fav span:hover {
|
||||
background: url('../img/light/star-off.png') no-repeat;
|
||||
}
|
||||
|
||||
a.fav-off span {
|
||||
background: url('../img/light/star-off.png') no-repeat;
|
||||
}
|
||||
|
||||
a.fav-off span:hover {
|
||||
background: url('../img/light/star-on.png') no-repeat;
|
||||
}
|
||||
|
||||
a.archive span {
|
||||
background: url('../img/light/checkmark-on.png') no-repeat;
|
||||
}
|
||||
|
||||
a.archive span:hover {
|
||||
background: url('../img/light/checkmark-off.png') no-repeat;
|
||||
}
|
||||
|
||||
a.archive-off span {
|
||||
background: url('../img/light/checkmark-off.png') no-repeat;
|
||||
}
|
||||
|
||||
a.archive-off span:hover {
|
||||
background: url('../img/light/checkmark-on.png') no-repeat;
|
||||
}
|
||||
|
||||
a.twitter span {
|
||||
background: url('../img/light/twitter.png') no-repeat;
|
||||
}
|
||||
|
||||
a.email span {
|
||||
background: url('../img/light/envelop.png') no-repeat;
|
||||
}
|
||||
|
||||
a.delete span {
|
||||
background: url('../img/light/remove.png') no-repeat;
|
||||
}
|
244
tpl/css/style.css
Normal file
@ -0,0 +1,244 @@
|
||||
body {
|
||||
font-size: 16px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
header {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
header h1 {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.bouton {
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#main {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#main ul#links {
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
text-align: center;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
#main ul#links li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#main ul#links li a.current {
|
||||
-webkit-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#main ul#sort {
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
text-align: center;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
#main ul#sort li {
|
||||
display: inline;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
#main ul#sort img:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
#links a{
|
||||
text-decoration: none;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
#links a:hover{
|
||||
-webkit-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/*** ***/
|
||||
/*** LINKS DISPLAY ***/
|
||||
|
||||
#main a.tool {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#main #content {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#main #content h2 {
|
||||
font-size: 1.3em;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#main #content .entrie {
|
||||
border-bottom: 1px dashed #222222;
|
||||
}
|
||||
|
||||
#main .entrie ul.tools {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#main .entrie ul.tools li {
|
||||
/*display: inline;*/
|
||||
}
|
||||
|
||||
.tools {
|
||||
float: right;
|
||||
text-align: right;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.tools p {
|
||||
font-size: 0.8em;}
|
||||
|
||||
/*
|
||||
.tools ul {
|
||||
padding: 0; margin: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.tools ul li {
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.tools a.tool {
|
||||
cursor: pointer;
|
||||
}*/
|
||||
|
||||
#main .entrie .tools a.tool span, #article .tools a.tool span {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#main .entrie .url {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
|
||||
/*** ***/
|
||||
/*** ARTICLE PAGE ***/
|
||||
|
||||
#article {
|
||||
margin: 0 auto;
|
||||
}
|
||||
#article header {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#article header a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.vieworiginal a, .vieworiginal a:hover, .vieworiginal a:visited {
|
||||
text-decoration: none;
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.backhome {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#article .tools {
|
||||
position: relative;
|
||||
display: inline;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#article .tools ul li{
|
||||
display: inline;
|
||||
}
|
||||
|
||||
|
||||
/*** GENERAL ***/
|
||||
body {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
a, a:hover, a:visited {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.bouton {
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
border: none;
|
||||
}
|
||||
.bouton:hover {
|
||||
background-color: #222222;
|
||||
color: #F1F1F1;
|
||||
}
|
||||
|
||||
#main ul#links li a.current {
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#links a:hover{
|
||||
background-color: #040707;
|
||||
color: #F1F1F1;
|
||||
}
|
||||
|
||||
|
||||
/*** ***/
|
||||
/*** ARTICLE PAGE ***/
|
||||
|
||||
#article header, #article article {
|
||||
border-bottom: 1px solid #222222;
|
||||
}
|
||||
|
||||
|
||||
/* Pagination */
|
||||
.pagination {
|
||||
clear: both;
|
||||
padding-bottom: 20px;
|
||||
padding-top: 10px;
|
||||
text-align: right;
|
||||
}
|
||||
.pagination a {
|
||||
border: 1px solid #D5D5D5;
|
||||
color: #333;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
height: 25px;
|
||||
padding: 4px 8px;
|
||||
text-decoration: none;
|
||||
margin:2px;
|
||||
}
|
||||
.pagination a:hover, .pagination a:active {
|
||||
background:#efefef;
|
||||
}
|
||||
.pagination span.current {
|
||||
background-color: #ccc;
|
||||
border: 1px solid #D5D5D5;
|
||||
color: #000;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
height: 25px;
|
||||
padding: 4px 8px;
|
||||
text-decoration: none;
|
||||
margin:2px;
|
||||
}
|
||||
.pagination span.disabled {
|
||||
border: 1px solid #EEEEEE;
|
||||
color: #DDDDDD;
|
||||
margin:2px;
|
||||
padding: 4px 8px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
footer {
|
||||
clear: both;
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
<div id="content">
|
||||
{loop="entries"}
|
||||
<div id="entry-{$value.id}" class="entrie mb2">
|
||||
<span class="content">
|
||||
<h2 class="h6-like">
|
||||
<a href="index.php?&view=view&id={$value.id}">{$value.title}</a>
|
||||
</h2>
|
||||
<div class="tools">
|
||||
<ul>
|
||||
<li><a title="toggle mark as read" class="tool archive {if="$value.is_read == '0'"}archive-off{/if}" onclick="toggle_archive(this, {$value.id})"><span></span></a></li>
|
||||
<li><a title="toggle favorite" class="tool fav {if="$value.is_fav == '0'"}fav-off{/if}" onclick="toggle_favorite(this, {$value.id})"><span></span></a></li>
|
||||
<li><form method="post" onsubmit="return confirm('Are you sure?')" style="display: inline;"><input type="hidden" name="token" id="token" value="<?php echo Session::getToken(); ?>" /><input type="hidden" id="action" name="action" value="delete" /><input type="hidden" id="view" name="view" value="{$view}" /><input type="hidden" id="id" name="id" value="{$value.id}" /><input type="submit" class="delete" title="toggle delete" /></form></li>
|
||||
</ul>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
{/loop}
|
||||
</div>
|
@ -1 +0,0 @@
|
||||
export {$export}
|
1
tpl/export.twig
Normal file
@ -0,0 +1 @@
|
||||
{{ export }}
|
@ -1,7 +0,0 @@
|
||||
</div>
|
||||
<footer class="mr2 mt3 smaller">
|
||||
<p>powered by <a href="http://inthepoche.com">poche</a><br />follow us on <a href="https://twitter.com/getpoche" title="follow us on twitter">twitter</a></p>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,22 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!--[if lte IE 6]> <html class="no-js ie6 ie67 ie678" lang="en"> <![endif]-->
|
||||
<!--[if lte IE 7]> <html class="no-js ie7 ie67 ie678" lang="en"> <![endif]-->
|
||||
<!--[if IE 8]> <html class="no-js ie8 ie678" lang="en"> <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=10">
|
||||
<title>{$title}</title>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="./img/favicon.ico" />
|
||||
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="./img/apple-touch-icon-144x144-precomposed.png">
|
||||
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="./img/apple-touch-icon-72x72-precomposed.png">
|
||||
<link rel="apple-touch-icon-precomposed" href="./img/apple-touch-icon-precomposed.png">
|
||||
<link rel="stylesheet" href="./css/knacss.css" media="all">
|
||||
<link rel="stylesheet" href="./css/style.css" media="all">
|
||||
<!-- Light Theme -->
|
||||
<link rel="stylesheet" href="./css/style-light.css" media="all" title="light-style">
|
||||
<!-- Dark Theme -->
|
||||
<link rel="alternate stylesheet" href="./css/style-dark.css" media="all" title="dark-style">
|
||||
</head>
|
@ -1,19 +0,0 @@
|
||||
<body class="light-style">
|
||||
<header>
|
||||
<h1><a href="index.php"><img src="./img/logo.png" alt="logo poche" /></a>poche</h1>
|
||||
</header>
|
||||
<div id="main">
|
||||
<ul id="links">
|
||||
<li><a href="index.php" {if="$view == 'index'"}class="current"{/if}>home</a></li>
|
||||
<li><a href="?view=fav" {if="$view == 'fav'"}class="current"{/if}>favorites</a></li>
|
||||
<li><a href="?view=archive" {if="$view == 'archive'"}class="current"{/if}>archive</a></li>
|
||||
<li><a href="?view=config" {if="$view == 'config'"}class="current"{/if}>config</a></li>
|
||||
<li><a href="?logout" title="Logout">logout</a></li>
|
||||
</ul>
|
||||
{if condition="isset($entries)"}
|
||||
<ul id="sort">
|
||||
<li><img src="img/up.png" onclick="sort_links('{$view}', 'ia');" title="by date asc" /> by date <img src="img/down.png" onclick="sort_links('{$view}', 'id');" title="by date desc" /></li>
|
||||
<li><img src="img/up.png" onclick="sort_links('{$view}', 'ta');" title="by title asc" /> by title <img src="img/down.png" onclick="sort_links('{$view}', 'td');" title="by title desc" /></li>
|
||||
</ul>
|
||||
{/if}
|
||||
{include="messages"}
|
29
tpl/home.twig
Normal file
@ -0,0 +1,29 @@
|
||||
{% extends "layout.twig" %}
|
||||
{% block title %}{% trans "home" %}{% endblock %}
|
||||
{% block menu %}
|
||||
{% include '_menu.twig' %}
|
||||
{% endblock %}
|
||||
{% block precontent %}
|
||||
<ul id="sort">
|
||||
<li><a href="./?sort=ia&view={{ view }}"><img src="./tpl/img/{{ constant('THEME') }}/top.png" alt="{% trans "by date asc" %}" title="{% trans "by date asc" %}" /></a> {% trans "by date" %} <a href="./?sort=id&view={{ view }}"><img src="./tpl/img/{{ constant('THEME') }}/down.png" alt="{% trans "by date desc" %}" title="{% trans "by date desc" %}" /></a></li>
|
||||
<li><a href="./?sort=ta&view={{ view }}"><img src="./tpl/img/{{ constant('THEME') }}/top.png" alt="{% trans "by title asc" %}" title="{% trans "by title asc" %}" /></a> {% trans "by title" %} <a href="./?sort=td&view={{ view }}"><img src="./tpl/img/{{ constant('THEME') }}/down.png" alt="{% trans "by title desc" %}" title="{% trans "by title desc" %}" /></a></li>
|
||||
</ul>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
{{ page_links | raw }}
|
||||
{% for entry in entries %}
|
||||
<div id="entry-{{ entry.id|e }}" class="entrie">
|
||||
<h2><a href="index.php?view=view&id={{ entry.id|e }}">{{ entry.title|e }}</a></h2>
|
||||
<ul class="tools">
|
||||
<li>
|
||||
<a title="{% trans "toggle mark as read" %}" class="tool archive {% if entry.is_read == 0 %}archive-off{% endif %}" href="./?action=toggle_archive&id={{ entry.id|e }}"><span></span></a></li>
|
||||
<li><a title="{% trans "toggle favorite" %}" class="tool fav {% if entry.is_fav == 0 %}fav-off{% endif %}" href="./?action=toggle_fav&id={{ entry.id|e }}"><span></span></a></li>
|
||||
<li><a title="{% trans "delete" %}" class="tool delete" href="./?action=delete&id={{ entry.id|e }}"><span></span></a></li>
|
||||
</li>
|
||||
</ul>
|
||||
<p>{{ entry.content|striptags|slice(0, 300) }}...</p>
|
||||
<p class="vieworiginal txtright small"><a href="{{ entry.url|e }}" target="_blank" title="{% trans "original" %} : {{ entry.title|e }}">{{ entry.url | e | getDomain }}</a></p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{{ page_links | raw }}
|
||||
{% endblock %}
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 346 B After Width: | Height: | Size: 346 B |
Before Width: | Height: | Size: 277 B After Width: | Height: | Size: 277 B |
Before Width: | Height: | Size: 235 B After Width: | Height: | Size: 235 B |
Before Width: | Height: | Size: 216 B After Width: | Height: | Size: 216 B |
BIN
tpl/img/light/envelop.png
Executable file
After Width: | Height: | Size: 285 B |
BIN
tpl/img/light/left.png
Executable file
After Width: | Height: | Size: 196 B |
Before Width: | Height: | Size: 252 B After Width: | Height: | Size: 252 B |
Before Width: | Height: | Size: 314 B After Width: | Height: | Size: 314 B |
Before Width: | Height: | Size: 281 B After Width: | Height: | Size: 281 B |
0
img/up.png → tpl/img/light/top.png
Normal file → Executable file
Before Width: | Height: | Size: 212 B After Width: | Height: | Size: 212 B |
BIN
tpl/img/light/twitter.png
Executable file
After Width: | Height: | Size: 297 B |
BIN
tpl/img/logo.png
Normal file
After Width: | Height: | Size: 454 B |
0
img/messages/close.png → tpl/img/messages/close.png
Normal file → Executable file
Before Width: | Height: | Size: 662 B After Width: | Height: | Size: 662 B |
0
img/messages/cross.png → tpl/img/messages/cross.png
Normal file → Executable file
Before Width: | Height: | Size: 655 B After Width: | Height: | Size: 655 B |
0
img/messages/help.png → tpl/img/messages/help.png
Normal file → Executable file
Before Width: | Height: | Size: 786 B After Width: | Height: | Size: 786 B |
0
img/messages/tick.png → tpl/img/messages/tick.png
Normal file → Executable file
Before Width: | Height: | Size: 537 B After Width: | Height: | Size: 537 B |
0
img/messages/warning.png → tpl/img/messages/warning.png
Normal file → Executable file
Before Width: | Height: | Size: 666 B After Width: | Height: | Size: 666 B |
@ -1,30 +0,0 @@
|
||||
{include="head"}
|
||||
<body class="light-style">
|
||||
<header>
|
||||
<h1><a href="index.php"><img src="./img/logo.png" alt="logo poche" /></a>poche</h1>
|
||||
</header>
|
||||
<div id="main">
|
||||
<form method="post" action="?install" name="loginform">
|
||||
<fieldset class="w500p center">
|
||||
<h2 class="mbs txtcenter">install your poche</h2>
|
||||
<div class="row">
|
||||
<label class="col w150p" for="login">Login</label>
|
||||
<input class="col" type="text" id="login" name="login" placeholder="Login" tabindex="1" autofocus />
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="col w150p" for="password">Password</label>
|
||||
<input class="col" type="password" id="password" name="password" placeholder="Password" tabindex="2">
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="col w150p" for="password_repeat">Repeat your password</label>
|
||||
<input class="col" type="password" id="password_repeat" name="password_repeat" placeholder="Password" tabindex="3">
|
||||
</div>
|
||||
<div class="row mts txtcenter">
|
||||
<button class="bouton" type="submit" tabindex="4">Install</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
<input type="hidden" name="returnurl" value="<?php echo htmlspecialchars($referer);?>">
|
||||
<input type="hidden" name="token" value="<?php echo Session::getToken(); ?>">
|
||||
</form>
|
||||
|
||||
{include="footer"}
|
28
tpl/install.twig
Normal file
@ -0,0 +1,28 @@
|
||||
{% extends "layout.twig" %}
|
||||
{% block title %}{% trans "installation" %}{% endblock %}
|
||||
{% block content %}
|
||||
<form method="post" action="?install" name="loginform">
|
||||
<fieldset class="w500p center">
|
||||
<h2 class="mbs txtcenter">{% trans "install your poche" %}</h2>
|
||||
<p>
|
||||
{% trans "poche is still not installed. Please fill the below form to install it. Don't hesitate to <a href='http://inthepoche.com/?pages/Documentation'>read the documentation on poche website</a>." %}
|
||||
</p>
|
||||
<div class="row">
|
||||
<label class="col w150p" for="login">{% trans "Login" %}</label>
|
||||
<input class="col" type="text" id="login" name="login" placeholder="Login" tabindex="1" autofocus />
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="col w150p" for="password">{% trans "Password" %}</label>
|
||||
<input class="col" type="password" id="password" name="password" placeholder="Password" tabindex="2">
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="col w150p" for="password_repeat">{% trans "Repeat your password" %}</label>
|
||||
<input class="col" type="password" id="password_repeat" name="password_repeat" placeholder="Password" tabindex="3">
|
||||
</div>
|
||||
<div class="row mts txtcenter">
|
||||
<button class="bouton" type="submit" tabindex="4">{% trans "Install" %}</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
<input type="hidden" name="token" value="{{ token }}">
|
||||
</form>
|
||||
{% endblock %}
|
22
tpl/js.html
@ -1,22 +0,0 @@
|
||||
<script type="text/javascript" src="js/jquery-1.9.1.min.js"></script>
|
||||
<script type="text/javascript" src="js/poche.js"></script>
|
||||
|
||||
{if="$load_all_js == '1'"}
|
||||
<script type="text/javascript" src="js/jquery.masonry.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$( window ).load( function()
|
||||
{
|
||||
var columns = 3,
|
||||
setColumns = function() { columns = $( window ).width() > 640 ? 3 : $( window ).width() > 320 ? 2 : 1; };
|
||||
|
||||
setColumns();
|
||||
$( window ).resize( setColumns );
|
||||
|
||||
$( '#content' ).masonry(
|
||||
{
|
||||
itemSelector: '.entrie',
|
||||
columnWidth: function( containerWidth ) { return containerWidth / columns; }
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{/if}
|
29
tpl/layout.twig
Normal file
@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<!--[if lte IE 6]> <html class="no-js ie6 ie67 ie678" lang="en"> <![endif]-->
|
||||
<!--[if lte IE 7]> <html class="no-js ie7 ie67 ie678" lang="en"> <![endif]-->
|
||||
<!--[if IE 8]> <html class="no-js ie8 ie678" lang="en"> <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=10">
|
||||
<title>{% block title %}{% endblock %} - poche</title>
|
||||
{% include '_head.twig' %}
|
||||
{% include '_bookmarklet.twig' %}
|
||||
</head>
|
||||
<body>
|
||||
{% include '_top.twig' %}
|
||||
<div id="main">
|
||||
{% block menu %}{% endblock %}
|
||||
{% block precontent %}{% endblock %}
|
||||
{% block messages %}
|
||||
{% include '_messages.twig' %}
|
||||
{% endblock %}
|
||||
<div id="content" class="w600p center">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
{% include '_footer.twig' %}
|
||||
</body>
|
||||
</html>
|
@ -1,33 +0,0 @@
|
||||
{include="head"}
|
||||
<body class="light-style">
|
||||
<header>
|
||||
<h1><a href="index.php"><img src="./img/logo.png" alt="logo poche" /></a>poche</h1>
|
||||
</header>
|
||||
<div id="main">
|
||||
<form method="post" action="?login" name="loginform">
|
||||
<fieldset class="w500p center">
|
||||
<h2 class="mbs txtcenter">login to your poche</h2>
|
||||
<div class="row">
|
||||
<label class="col w150p" for="login">Login</label>
|
||||
<input class="col" type="text" id="login" name="login" placeholder="Login" tabindex="1" autofocus />
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="col w150p" for="password">Password</label>
|
||||
<input class="col" type="password" id="password" name="password" placeholder="Password" tabindex="2">
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="col w150p">Stay signed in</label>
|
||||
<div class="col">
|
||||
<input type="checkbox" name="longlastingsession" tabindex="3">
|
||||
<small class="inbl">(Do not check on public computers)</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mts txtcenter">
|
||||
<button class="bouton" type="submit" tabindex="4">Sign in</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
<input type="hidden" name="returnurl" value="<?php echo htmlspecialchars($referer);?>">
|
||||
<input type="hidden" name="token" value="<?php echo Session::getToken(); ?>">
|
||||
</form>
|
||||
|
||||
{include="footer"}
|
32
tpl/login.twig
Normal file
@ -0,0 +1,32 @@
|
||||
{% extends "layout.twig" %}
|
||||
|
||||
{% block title %}{% trans "login to your poche" %}{% endblock %}
|
||||
{% block content %}
|
||||
<form method="post" action="?login" name="loginform">
|
||||
<fieldset class="w500p center">
|
||||
<h2 class="mbs txtcenter">{% trans "login to your poche" %}</h2>
|
||||
{% if constant('MODE_DEMO') == 1 %}<p>{% trans "you are in demo mode, some features may be disabled." %}</p>{% endif %}
|
||||
<div class="row">
|
||||
<label class="col w150p" for="login">{% trans "Login" %}</label>
|
||||
<input class="col" type="text" id="login" name="login" placeholder="Login" tabindex="1" autofocus {% if constant('MODE_DEMO') == 1 %}value="poche"{% endif %} />
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<label class="col w150p" for="password">{% trans "Password" %}</label>
|
||||
<input class="col" type="password" id="password" name="password" placeholder="Password" tabindex="2" {% if constant('MODE_DEMO') == 1 %}value="poche"{% endif %} />
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="col w150p" for="longlastingsession">{% trans "Stay signed in" %}</label>
|
||||
<div class="col">
|
||||
<input type="checkbox" id="longlastingsession" name="longlastingsession" tabindex="3">
|
||||
<small class="inbl">{% trans "(Do not check on public computers)" %}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mts txtcenter">
|
||||
<button class="bouton" type="submit" tabindex="4">{% trans "Login" %}</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
<input type="hidden" name="returnurl" value="{{ referer }}">
|
||||
<input type="hidden" name="token" value="{{ token }}">
|
||||
</form>
|
||||
{% endblock %}
|
@ -1 +0,0 @@
|
||||
<div id="messages"><?php echo $msg->display(); ?></div>
|
@ -1,53 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!--[if lte IE 6]> <html class="no-js ie6 ie67 ie678" lang="en"> <![endif]-->
|
||||
<!--[if lte IE 7]> <html class="no-js ie7 ie67 ie678" lang="en"> <![endif]-->
|
||||
<!--[if IE 8]> <html class="no-js ie8 ie678" lang="en"> <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=10">
|
||||
<title>{$title}</title>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="./img/favicon.ico" />
|
||||
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="./img/apple-touch-icon-144x144-precomposed.png">
|
||||
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="./img/apple-touch-icon-72x72-precomposed.png">
|
||||
<link rel="apple-touch-icon-precomposed" href="./img/apple-touch-icon-precomposed.png">
|
||||
<link rel="stylesheet" href="./css/knacss.css" media="all">
|
||||
<link rel="stylesheet" href="./css/style.css" media="all">
|
||||
<!-- Light Theme -->
|
||||
<link rel="stylesheet" href="./css/style-light.css" media="all" title="light-style">
|
||||
<!-- Dark Theme -->
|
||||
<link rel="alternate stylesheet" href="./css/style-dark.css" media="all" title="dark-style">
|
||||
</head>
|
||||
<body class="article light-style">
|
||||
<div id="article" class="w600p">
|
||||
<div class="backhome">
|
||||
<a href="index.php" title="back to home">←</a>
|
||||
</div>
|
||||
<div class="tools">
|
||||
<ul>
|
||||
<li><a title="toggle mark as read" class="tool archive {if="$is_read == '0'"}archive-off{/if}" onclick="toggle_archive(this, {$id})"><span></span></a></li>
|
||||
<li><a href="#" id="themeswitch">dark</a></li>
|
||||
<li><a title="toggle favorite" class="tool fav {if="$is_fav == '0'"}fav-off{/if}" onclick="toggle_favorite(this, {$id})"><span></span></a></li>
|
||||
<li><form method="post" onsubmit="return confirm('Are you sure?')" style="display: inline;" action="index.php"><input type="hidden" name="token" id="token" value="<?php echo Session::getToken(); ?>" /><input type="hidden" id="view" name="view" value="index" /><input type="hidden" id="action" name="action" value="delete" /><input type="hidden" id="id" name="id" value="{$id}" /><input type="submit" class="delete" title="toggle delete" /></form></li>
|
||||
<li><a href="?logout" title="Logout">logout</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<header class="mbm">
|
||||
<h1><a href="{$url}">{$title}</a></h1>
|
||||
<div class="vieworiginal txtright small"><a href="{$url}" target="_blank" title="original : {$title}">view original</a></div>
|
||||
</header>
|
||||
{include="messages"}
|
||||
<article>
|
||||
<div id="readityourselfcontent">
|
||||
{$content}
|
||||
</div>
|
||||
</article>
|
||||
<div class="vieworiginal txtright small"><a href="{$url}" target="_blank" title="original : {$title}">view original</a></div>
|
||||
<div class="backhome">
|
||||
<a href="index.php" title="back to home">←</a>
|
||||
</div>
|
||||
|
||||
{include="js"}
|
||||
{include="footer"}
|