Sfoglia il codice sorgente

Merge branch 'master' into prng, resolve merge conflicts

rugk 10 anni fa
parent
commit
75cb771e4b
47 ha cambiato i file con 1970 aggiunte e 346 eliminazioni
  1. 1 0
      .gitattributes
  2. 4 7
      .gitignore
  3. 23 0
      .php_cs
  4. 4 2
      CHANGELOG.md
  5. 25 2
      LICENSE.md
  6. 10 14
      cfg/conf.ini.sample
  7. 2 1
      composer.json
  8. 858 0
      composer.lock
  9. 8 4
      css/bootstrap/privatebin.css
  10. 52 9
      js/privatebin.js
  11. 3 3
      lib/Configuration.php
  12. 31 31
      lib/Data/Database.php
  13. 15 12
      lib/Data/Filesystem.php
  14. 1 1
      lib/Filter.php
  15. 6 6
      lib/I18n.php
  16. 48 0
      lib/Json.php
  17. 3 3
      lib/Model/AbstractModel.php
  18. 21 11
      lib/Model/Comment.php
  19. 8 8
      lib/Model/Paste.php
  20. 1 1
      lib/Persistence/AbstractPersistence.php
  21. 2 2
      lib/Persistence/PurgeLimiter.php
  22. 11 10
      lib/Persistence/TrafficLimiter.php
  23. 10 10
      lib/PrivateBin.php
  24. 2 2
      lib/Request.php
  25. 1 0
      lib/View.php
  26. 39 56
      lib/Vizhash16x16.php
  27. 0 1
      privatebin
  28. 16 16
      tpl/bootstrap-compact.php
  29. 16 16
      tpl/bootstrap-dark-page.php
  30. 18 18
      tpl/bootstrap-dark.php
  31. 16 16
      tpl/bootstrap-page.php
  32. 16 16
      tpl/bootstrap.php
  33. 3 3
      tpl/page.php
  34. 30 1
      tst/Data/FilesystemTest.php
  35. 82 4
      tst/ModelTest.php
  36. 3 3
      tst/Vizhash16x16Test.php
  37. 7 1
      vendor/composer/autoload_classmap.php
  38. 0 10
      vendor/composer/autoload_files.php
  39. 1 0
      vendor/composer/autoload_namespaces.php
  40. 0 18
      vendor/composer/autoload_real.php
  41. 18 5
      vendor/composer/autoload_static.php
  42. 25 23
      vendor/composer/installed.json
  43. 241 0
      vendor/yzalis/identicon/src/Identicon/Generator/BaseGenerator.php
  44. 76 0
      vendor/yzalis/identicon/src/Identicon/Generator/GdGenerator.php
  45. 33 0
      vendor/yzalis/identicon/src/Identicon/Generator/GeneratorInterface.php
  46. 80 0
      vendor/yzalis/identicon/src/Identicon/Generator/ImageMagickGenerator.php
  47. 100 0
      vendor/yzalis/identicon/src/Identicon/Identicon.php

+ 1 - 0
.gitattributes

@@ -8,4 +8,5 @@ tst/ export-ignore
 .gitattributes export-ignore
 .gitattributes export-ignore
 .github export-ignore
 .github export-ignore
 .gitignore export-ignore
 .gitignore export-ignore
+.php_cs export-ignore
 .travis.yml export-ignore
 .travis.yml export-ignore

+ 4 - 7
.gitignore

@@ -1,15 +1,12 @@
-# Ignore data/, tmp/ and vendor/
-data/
-!lib/data/
-tmp/
-vendor/
 # Ignore for safety
 # Ignore for safety
 .htaccess
 .htaccess
 .htpasswd
 .htpasswd
+# Ignore data/ and vendor/
+data/
+vendor/
 # Ignore unit testing logs, api docs and eclipse project files
 # Ignore unit testing logs, api docs and eclipse project files
-tst/log/
 doc/
 doc/
-composer.lock
+tst/log/
 .settings
 .settings
 .buildpath
 .buildpath
 .project
 .project

+ 23 - 0
.php_cs

@@ -0,0 +1,23 @@
+<?php
+/**
+ * Configuration file for PHP Coding Standards Fixer (php-cs-fixer).
+ *
+ * On GitHub: https://github.com/FriendsOfPhp/php-cs-fixer
+ * More information: http://cs.sensiolabs.org/
+ */
+
+$finder = Symfony\CS\Finder\DefaultFinder::create()
+    ->in('lib')
+;
+
+return Symfony\CS\Config\Config::create()
+    ->level(Symfony\CS\FixerInterface::PSR2_LEVEL)
+    ->fixers(['concat_with_spaces', 'long_array_syntax', 'standardize_not_equal',
+              'operators_spaces', 'duplicate_semicolon',
+              'remove_leading_slash_use', 'align_equals',
+              'single_array_no_trailing_comma', 'phpdoc_indent', 'phpdoc_scalar',
+              'phpdoc_to_comment', 'phpdoc_trim',
+              'phpdoc_types', 'print_to_echo', 'self_accessor', 'single_quote',
+              'spaces_cast', 'ternary_spaces', 'phpdoc_order'])
+    ->finder($finder)
+;

+ 4 - 2
CHANGELOG.md

@@ -5,7 +5,7 @@
     * ADDED: re-introduced URL shortener support (optional), which was removed back in version 0.16 for privacy concerns
     * ADDED: re-introduced URL shortener support (optional), which was removed back in version 0.16 for privacy concerns
     * ADDED: Preview tab, helpful for writing markdown code or check source code rendering
     * ADDED: Preview tab, helpful for writing markdown code or check source code rendering
     * ADDED: Automatic purging of expired pastes, done on paste creation
     * ADDED: Automatic purging of expired pastes, done on paste creation
-    * ADDED: Option to disable vizhashs in discussions (will only affect newly created pastes)
+    * ADDED: Option to disable icons in discussions (will only affect newly created pastes)
     * ADDED: Composer support
     * ADDED: Composer support
     * CHANGED: Renamed the ZeroBin fork to PrivateBin
     * CHANGED: Renamed the ZeroBin fork to PrivateBin
     * CHANGED: Removed unmaintained RainTPL template engine, replacing the templates with straight forward PHP files
     * CHANGED: Removed unmaintained RainTPL template engine, replacing the templates with straight forward PHP files
@@ -14,7 +14,9 @@
     * CHANGED: Switched to GCM instead CCM mode for AES encryption for newly created pastes
     * CHANGED: Switched to GCM instead CCM mode for AES encryption for newly created pastes
     * CHANGED: Switched to a SHA256 HMAC of the IP in traffic limiter instead of storing it in plain text on the server
     * CHANGED: Switched to a SHA256 HMAC of the IP in traffic limiter instead of storing it in plain text on the server
     * CHANGED: Introduced content security policy header to reduce cross site scripting (XSS) risks
     * CHANGED: Introduced content security policy header to reduce cross site scripting (XSS) risks
-    * CHANGED: Refactored PHP code to conform to PSR-4 and PSR-2 standards.
+    * CHANGED: Refactored PHP code to conform to PSR-4 and PSR-2 standards
+    * CHANGED: Switched to Identicons as the default for comments with nicknames
+    * CHANGED: Vizhash is now optional and based on (128 byte) SHA512 HMAC instead of (144 bytes) combination of MD5, SHA1 and a reversal of that string
     * FIXED: Content-type negociation for HTML in certain uncommon browser configurations
     * FIXED: Content-type negociation for HTML in certain uncommon browser configurations
     * FIXED: JavaScript error displayed before page is loaded or during attachment load
     * FIXED: JavaScript error displayed before page is loaded or during attachment load
     * FIXED: Don't strip space characters at beginning or end of optional password
     * FIXED: Don't strip space characters at beginning or end of optional password

+ 25 - 2
LICENSE.md

@@ -4,8 +4,9 @@ PrivateBin consists of PHP and JS code which was originally written by Sébastie
 Sauvage in 2012 and falls unter the Zlib/libpng license. Also included are
 Sauvage in 2012 and falls unter the Zlib/libpng license. Also included are
 libraries that fall under the GPLv2 (SJCL, rawinflate, rawdeflate), BSD
 libraries that fall under the GPLv2 (SJCL, rawinflate, rawdeflate), BSD
 2-clause (SJCL), BSD 3-clause (base64.js version 2.1.9, Showdown), MIT
 2-clause (SJCL), BSD 3-clause (base64.js version 2.1.9, Showdown), MIT
-(base64.js version 1.7, Bootstrap), Apache (prettify.js) and CC-BY (favicon,
-icon, logo) licenses. All of these license terms can be found here below:
+(base64.js version 1.7, Bootstrap, Identicon), Apache (prettify.js) and CC-BY
+(favicon, icon, logo) licenses. All of these license terms can be found here
+below:
 
 
 ## Zlib/libpng license for PrivateBin
 ## Zlib/libpng license for PrivateBin
 
 
@@ -440,6 +441,28 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 THE SOFTWARE.
 
 
+## MIT License for Identicon
+
+Copyright © 2013 Benjamin Laugueux <benjamin@yzalis.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
 ## Apache License for prettify.js
 ## Apache License for prettify.js
 
 
 _Version 2.0, January 2004_
 _Version 2.0, January 2004_

+ 10 - 14
cfg/conf.ini.sample

@@ -1,11 +1,6 @@
-; PrivateBin
-;
-; a zero-knowledge paste bin
-;
-; @link      https://github.com/PrivateBin/PrivateBin
-; @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
-; @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
-; @version   0.22
+; config file for PrivateBin
+; 
+; An explanation of each setting can be find online at https://github.com/PrivateBin/PrivateBin/wiki/Configuration.
 
 
 [main]
 [main]
 ; enable or disable the discussion feature, defaults to true
 ; enable or disable the discussion feature, defaults to true
@@ -53,18 +48,19 @@ languageselection = false
 ; the pastes encryption key
 ; the pastes encryption key
 ; urlshortener = "https://shortener.example.com/api?link="
 ; urlshortener = "https://shortener.example.com/api?link="
 
 
-; (optional) vizhash is a weak mechanism to detect if a comment was from a
-; different user when the same username was used in a comment. It is based on
-; the IP and might be used to get the posters IP if the server salt is leaked
-; and a rainbow table is generated for all IPs. Enabled by default.
-; vizhash = false
+; (optional) IP based icons are a weak mechanism to detect if a comment was from
+; a different user when the same username was used in a comment. It might be
+; used to get the IP of a non anonymous comment poster if the server salt is
+; leaked and a SHA256 HMAC rainbow table is generated for all (relevant) IPs.
+; Can be set to one these values: none / vizhash / identicon (default).
+; icon = none
 
 
 ; Content Security Policy headers allow a website to restrict what sources are
 ; Content Security Policy headers allow a website to restrict what sources are
 ; allowed to be accessed in its context. You need to change this if you added
 ; allowed to be accessed in its context. You need to change this if you added
 ; custom scripts from third-party domains to your templates, e.g. tracking
 ; custom scripts from third-party domains to your templates, e.g. tracking
 ; scripts or run your site behind certain DDoS-protection services.
 ; scripts or run your site behind certain DDoS-protection services.
 ; Check the documentation at https://content-security-policy.com/
 ; Check the documentation at https://content-security-policy.com/
-cspheader = "default-src 'none'; connect-src *; script-src 'self'; style-src 'self'; font-src 'self'; img-src 'self';"
+cspheader = "default-src 'none'; connect-src *; script-src 'self'; style-src 'self'; font-src 'self'; img-src 'self' data:;"
 
 
 ; stay compatible with PrivateBin Alpha 0.19, less secure
 ; stay compatible with PrivateBin Alpha 0.19, less secure
 ; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of
 ; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of

+ 2 - 1
composer.json

@@ -19,7 +19,8 @@
     ],
     ],
     "require": {
     "require": {
         "php": "^5.2.6 || ^7.0",
         "php": "^5.2.6 || ^7.0",
-        "paragonie/random_compat": "^2.0"
+        "paragonie/random_compat": "^2.0",
+        "yzalis/identicon": "^1.1"
     },
     },
     "require-dev": {
     "require-dev": {
         "codacy/coverage": "dev-master",
         "codacy/coverage": "dev-master",

+ 858 - 0
composer.lock

@@ -0,0 +1,858 @@
+{
+    "_readme": [
+        "This file locks the dependencies of your project to a known state",
+        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+        "This file is @generated automatically"
+    ],
+    "hash": "e3520dc72004bd92b2bd0b0febf71c7f",
+    "content-hash": "ac3ea1f44998ea42345107fd21d6a2e0",
+    "packages": [
+        {
+            "name": "yzalis/identicon",
+            "version": "1.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/yzalis/Identicon.git",
+                "reference": "a99fc2a3d018512f7914bc6f972952536c0f309b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/yzalis/Identicon/zipball/a99fc2a3d018512f7914bc6f972952536c0f309b",
+                "reference": "a99fc2a3d018512f7914bc6f972952536c0f309b",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "require-dev": {
+                "fzaninotto/faker": "1.2.*@dev"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Identicon": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Benjamin Laugueux",
+                    "email": "benjamin@yzalis.com"
+                }
+            ],
+            "description": "Create awesome unique avatar.",
+            "homepage": "http://identicon-php.org",
+            "keywords": [
+                "avatar",
+                "identicon",
+                "image"
+            ],
+            "time": "2014-07-13 09:19:12"
+        }
+    ],
+    "packages-dev": [
+        {
+            "name": "codacy/coverage",
+            "version": "dev-master",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/codacy/php-codacy-coverage.git",
+                "reference": "92194b1ece3379e56bb1f95d6f540fc6244d9946"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/codacy/php-codacy-coverage/zipball/92194b1ece3379e56bb1f95d6f540fc6244d9946",
+                "reference": "92194b1ece3379e56bb1f95d6f540fc6244d9946",
+                "shasum": ""
+            },
+            "require": {
+                "gitonomy/gitlib": "~0.1",
+                "php": ">=5.3.3",
+                "symfony/console": "~2.5|~3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.5"
+            },
+            "bin": [
+                "bin/codacycoverage"
+            ],
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jakob Pupke",
+                    "email": "jakob.pupke@gmail.com"
+                }
+            ],
+            "description": "Sends PHP test coverage information to Codacy.",
+            "homepage": "https://github.com/codacy/php-codacy-coverage",
+            "time": "2016-07-07 15:33:12"
+        },
+        {
+            "name": "codeclimate/php-test-reporter",
+            "version": "dev-master",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/codeclimate/php-test-reporter.git",
+                "reference": "68786c391d2b859054046a7b7ed07c64e7b741a1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/codeclimate/php-test-reporter/zipball/68786c391d2b859054046a7b7ed07c64e7b741a1",
+                "reference": "68786c391d2b859054046a7b7ed07c64e7b741a1",
+                "shasum": ""
+            },
+            "require": {
+                "ext-curl": "*",
+                "php": ">=5.3",
+                "satooshi/php-coveralls": "^1.0",
+                "symfony/console": "^2.0|^3.0"
+            },
+            "require-dev": {
+                "ext-xdebug": "*",
+                "phpunit/phpunit": "3.7.*@stable",
+                "tm/tooly-composer-script": "^1.0"
+            },
+            "bin": [
+                "composer/bin/test-reporter"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "0.3.x-dev"
+                },
+                "tools": {
+                    "box": {
+                        "url": "https://github.com/box-project/box2/releases/download/2.7.2/box-2.7.2.phar",
+                        "only-dev": true
+                    }
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "CodeClimate\\PhpTestReporter\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Code Climate",
+                    "email": "hello@codeclimate.com",
+                    "homepage": "https://codeclimate.com"
+                }
+            ],
+            "description": "PHP client for reporting test coverage to Code Climate",
+            "homepage": "https://github.com/codeclimate/php-test-reporter",
+            "keywords": [
+                "codeclimate",
+                "coverage"
+            ],
+            "time": "2016-08-09 19:41:51"
+        },
+        {
+            "name": "gitonomy/gitlib",
+            "version": "v0.1.8",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/gitonomy/gitlib.git",
+                "reference": "f575b8f7da917ade7890c6aa705fa22545690389"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/f575b8f7da917ade7890c6aa705fa22545690389",
+                "reference": "f575b8f7da917ade7890c6aa705fa22545690389",
+                "shasum": ""
+            },
+            "require": {
+                "symfony/process": "^2.3|^3.0"
+            },
+            "require-dev": {
+                "psr/log": "^1.0"
+            },
+            "suggest": {
+                "psr/log": "Add some log"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Gitonomy\\Git\\": "src/Gitonomy/Git/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Alexandre Salomé",
+                    "email": "alexandre.salome@gmail.com",
+                    "homepage": "http://alexandre-salome.fr"
+                },
+                {
+                    "name": "Julien DIDIER",
+                    "email": "genzo.wm@gmail.com",
+                    "homepage": "http://www.jdidier.net"
+                }
+            ],
+            "description": "Library for accessing git",
+            "homepage": "http://gitonomy.com",
+            "time": "2015-12-01 22:25:57"
+        },
+        {
+            "name": "guzzle/guzzle",
+            "version": "v3.9.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/guzzle/guzzle3.git",
+                "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9",
+                "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9",
+                "shasum": ""
+            },
+            "require": {
+                "ext-curl": "*",
+                "php": ">=5.3.3",
+                "symfony/event-dispatcher": "~2.1"
+            },
+            "replace": {
+                "guzzle/batch": "self.version",
+                "guzzle/cache": "self.version",
+                "guzzle/common": "self.version",
+                "guzzle/http": "self.version",
+                "guzzle/inflection": "self.version",
+                "guzzle/iterator": "self.version",
+                "guzzle/log": "self.version",
+                "guzzle/parser": "self.version",
+                "guzzle/plugin": "self.version",
+                "guzzle/plugin-async": "self.version",
+                "guzzle/plugin-backoff": "self.version",
+                "guzzle/plugin-cache": "self.version",
+                "guzzle/plugin-cookie": "self.version",
+                "guzzle/plugin-curlauth": "self.version",
+                "guzzle/plugin-error-response": "self.version",
+                "guzzle/plugin-history": "self.version",
+                "guzzle/plugin-log": "self.version",
+                "guzzle/plugin-md5": "self.version",
+                "guzzle/plugin-mock": "self.version",
+                "guzzle/plugin-oauth": "self.version",
+                "guzzle/service": "self.version",
+                "guzzle/stream": "self.version"
+            },
+            "require-dev": {
+                "doctrine/cache": "~1.3",
+                "monolog/monolog": "~1.0",
+                "phpunit/phpunit": "3.7.*",
+                "psr/log": "~1.0",
+                "symfony/class-loader": "~2.1",
+                "zendframework/zend-cache": "2.*,<2.3",
+                "zendframework/zend-log": "2.*,<2.3"
+            },
+            "suggest": {
+                "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated."
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.9-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Guzzle": "src/",
+                    "Guzzle\\Tests": "tests/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                },
+                {
+                    "name": "Guzzle Community",
+                    "homepage": "https://github.com/guzzle/guzzle/contributors"
+                }
+            ],
+            "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle",
+            "homepage": "http://guzzlephp.org/",
+            "keywords": [
+                "client",
+                "curl",
+                "framework",
+                "http",
+                "http client",
+                "rest",
+                "web service"
+            ],
+            "abandoned": "guzzlehttp/guzzle",
+            "time": "2015-03-18 18:23:50"
+        },
+        {
+            "name": "psr/log",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/log.git",
+                "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
+                "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
+                "shasum": ""
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Psr\\Log\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for logging libraries",
+            "keywords": [
+                "log",
+                "psr",
+                "psr-3"
+            ],
+            "time": "2012-12-21 11:40:51"
+        },
+        {
+            "name": "satooshi/php-coveralls",
+            "version": "v1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/satooshi/php-coveralls.git",
+                "reference": "da51d304fe8622bf9a6da39a8446e7afd432115c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/satooshi/php-coveralls/zipball/da51d304fe8622bf9a6da39a8446e7afd432115c",
+                "reference": "da51d304fe8622bf9a6da39a8446e7afd432115c",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "ext-simplexml": "*",
+                "guzzle/guzzle": "^2.8|^3.0",
+                "php": ">=5.3.3",
+                "psr/log": "^1.0",
+                "symfony/config": "^2.1|^3.0",
+                "symfony/console": "^2.1|^3.0",
+                "symfony/stopwatch": "^2.0|^3.0",
+                "symfony/yaml": "^2.0|^3.0"
+            },
+            "suggest": {
+                "symfony/http-kernel": "Allows Symfony integration"
+            },
+            "bin": [
+                "bin/coveralls"
+            ],
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Satooshi\\": "src/Satooshi/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Kitamura Satoshi",
+                    "email": "with.no.parachute@gmail.com",
+                    "homepage": "https://www.facebook.com/satooshi.jp"
+                }
+            ],
+            "description": "PHP client library for Coveralls API",
+            "homepage": "https://github.com/satooshi/php-coveralls",
+            "keywords": [
+                "ci",
+                "coverage",
+                "github",
+                "test"
+            ],
+            "time": "2016-01-20 17:35:46"
+        },
+        {
+            "name": "symfony/config",
+            "version": "v3.1.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/config.git",
+                "reference": "a7630397b91be09cdd2fe57fd13612e258700598"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/config/zipball/a7630397b91be09cdd2fe57fd13612e258700598",
+                "reference": "a7630397b91be09cdd2fe57fd13612e258700598",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9",
+                "symfony/filesystem": "~2.8|~3.0"
+            },
+            "suggest": {
+                "symfony/yaml": "To use the yaml reference dumper"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Config\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Config Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-07-26 08:04:17"
+        },
+        {
+            "name": "symfony/console",
+            "version": "v3.1.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/console.git",
+                "reference": "f9e638e8149e9e41b570ff092f8007c477ef0ce5"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/console/zipball/f9e638e8149e9e41b570ff092f8007c477ef0ce5",
+                "reference": "f9e638e8149e9e41b570ff092f8007c477ef0ce5",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9",
+                "symfony/polyfill-mbstring": "~1.0"
+            },
+            "require-dev": {
+                "psr/log": "~1.0",
+                "symfony/event-dispatcher": "~2.8|~3.0",
+                "symfony/process": "~2.8|~3.0"
+            },
+            "suggest": {
+                "psr/log": "For using the console logger",
+                "symfony/event-dispatcher": "",
+                "symfony/process": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Console\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Console Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-07-26 08:04:17"
+        },
+        {
+            "name": "symfony/event-dispatcher",
+            "version": "v2.8.9",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/event-dispatcher.git",
+                "reference": "889983a79a043dfda68f38c38b6dba092dd49cd8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/889983a79a043dfda68f38c38b6dba092dd49cd8",
+                "reference": "889983a79a043dfda68f38c38b6dba092dd49cd8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.9"
+            },
+            "require-dev": {
+                "psr/log": "~1.0",
+                "symfony/config": "~2.0,>=2.0.5|~3.0.0",
+                "symfony/dependency-injection": "~2.6|~3.0.0",
+                "symfony/expression-language": "~2.6|~3.0.0",
+                "symfony/stopwatch": "~2.3|~3.0.0"
+            },
+            "suggest": {
+                "symfony/dependency-injection": "",
+                "symfony/http-kernel": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.8-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\EventDispatcher\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony EventDispatcher Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-07-28 16:56:28"
+        },
+        {
+            "name": "symfony/filesystem",
+            "version": "v3.1.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/filesystem.git",
+                "reference": "bb29adceb552d202b6416ede373529338136e84f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/filesystem/zipball/bb29adceb552d202b6416ede373529338136e84f",
+                "reference": "bb29adceb552d202b6416ede373529338136e84f",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Filesystem\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Filesystem Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-07-20 05:44:26"
+        },
+        {
+            "name": "symfony/polyfill-mbstring",
+            "version": "v1.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-mbstring.git",
+                "reference": "dff51f72b0706335131b00a7f49606168c582594"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594",
+                "reference": "dff51f72b0706335131b00a7f49606168c582594",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "suggest": {
+                "ext-mbstring": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.2-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Mbstring\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for the Mbstring extension",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "mbstring",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "time": "2016-05-18 14:26:46"
+        },
+        {
+            "name": "symfony/process",
+            "version": "v3.1.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/process.git",
+                "reference": "04c2dfaae4ec56a5c677b0c69fac34637d815758"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/process/zipball/04c2dfaae4ec56a5c677b0c69fac34637d815758",
+                "reference": "04c2dfaae4ec56a5c677b0c69fac34637d815758",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Process\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Process Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-07-28 11:13:48"
+        },
+        {
+            "name": "symfony/stopwatch",
+            "version": "v3.1.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/stopwatch.git",
+                "reference": "bb42806b12c5f89db4ebf64af6741afe6d8457e1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/stopwatch/zipball/bb42806b12c5f89db4ebf64af6741afe6d8457e1",
+                "reference": "bb42806b12c5f89db4ebf64af6741afe6d8457e1",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Stopwatch\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Stopwatch Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-06-29 05:41:56"
+        },
+        {
+            "name": "symfony/yaml",
+            "version": "v3.1.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/yaml.git",
+                "reference": "1819adf2066880c7967df7180f4f662b6f0567ac"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/yaml/zipball/1819adf2066880c7967df7180f4f662b6f0567ac",
+                "reference": "1819adf2066880c7967df7180f4f662b6f0567ac",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Yaml\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Yaml Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-07-17 14:02:08"
+        }
+    ],
+    "aliases": [],
+    "minimum-stability": "stable",
+    "stability-flags": {
+        "codacy/coverage": 20,
+        "codeclimate/php-test-reporter": 20
+    },
+    "prefer-stable": false,
+    "prefer-lowest": false,
+    "platform": {
+        "php": "^5.3 || ^7.0"
+    },
+    "platform-dev": []
+}

+ 8 - 4
css/bootstrap/privatebin.css

@@ -17,11 +17,19 @@ body.navbar-spacing {
 	margin: 0 8px;
 	margin: 0 8px;
 }
 }
 
 
+.nav.navbar-nav > li {
+	margin-left: 8px;
+}
+
 .navbar-brand {
 .navbar-brand {
 	padding: 3px;
 	padding: 3px;
 	padding-left: 8px;
 	padding-left: 8px;
 }
 }
 
 
+.navbar-form {
+	padding: 0;
+}
+
 .dropdown-menu > li > label, .dropdown-menu > li > div {
 .dropdown-menu > li > label, .dropdown-menu > li > div {
 	clear: both;
 	clear: both;
 	display: block;
 	display: block;
@@ -49,10 +57,6 @@ body.navbar-spacing {
 	margin-right: 8px;
 	margin-right: 8px;
 }
 }
 
 
-.dropdown > #expiration {
-	margin-left: 8px;
-}
-
 #image img {
 #image img {
 	max-width: 100%;
 	max-width: 100%;
 	height: auto;
 	height: auto;

+ 52 - 9
js/privatebin.js

@@ -741,6 +741,7 @@ $(function() {
                     this.passwordInput.val(password);
                     this.passwordInput.val(password);
                     if (cleartext.length > 0)
                     if (cleartext.length > 0)
                     {
                     {
+                        $('#pasteFormatter').val(paste.meta.formatter);
                         this.formatPaste(paste.meta.formatter, cleartext);
                         this.formatPaste(paste.meta.formatter, cleartext);
                     }
                     }
                 }
                 }
@@ -870,12 +871,12 @@ $(function() {
                 '<div class="reply">' +
                 '<div class="reply">' +
                 '<input type="text" id="nickname" class="form-control" title="' + hint + '" placeholder="' + hint + '" />' +
                 '<input type="text" id="nickname" class="form-control" title="' + hint + '" placeholder="' + hint + '" />' +
                 '<textarea id="replymessage" class="replymessage form-control" cols="80" rows="7"></textarea>' +
                 '<textarea id="replymessage" class="replymessage form-control" cols="80" rows="7"></textarea>' +
-                '<br /><button id="replybutton" class="btn btn-default btn-sm">' + i18n._('Post comment') + '</button>' +
-                '<div id="replystatus"> </div>' +
-                '</div>'
+                '<br /><div id="replystatus"></div><button id="replybutton" class="btn btn-default btn-sm">' +
+                i18n._('Post comment') + '</button></div>'
             );
             );
             reply.find('button').click({parentid: commentid}, $.proxy(this.sendComment, this));
             reply.find('button').click({parentid: commentid}, $.proxy(this.sendComment, this));
             source.after(reply);
             source.after(reply);
+            this.replyStatus = $('#replystatus');
             $('#replymessage').focus();
             $('#replymessage').focus();
         },
         },
 
 
@@ -1201,6 +1202,23 @@ $(function() {
             }
             }
         },
         },
 
 
+        /**
+         * If discussion is checked, disable "burn after reading".
+         */
+        changeOpenDisc: function()
+        {
+            if (this.openDiscussion.is(':checked') )
+            {
+                this.burnAfterReadingOption.addClass('buttondisabled');
+                this.burnAfterReading.attr({checked: false, disabled: true});
+            }
+            else
+            {
+                this.burnAfterReadingOption.removeClass('buttondisabled');
+                this.burnAfterReading.removeAttr('disabled');
+            }
+        },
+
         /**
         /**
          * Reload the page.
          * Reload the page.
          *
          *
@@ -1220,7 +1238,8 @@ $(function() {
         rawText: function(event)
         rawText: function(event)
         {
         {
             event.preventDefault();
             event.preventDefault();
-            var paste = this.clearText.html();
+            var paste = $('#pasteFormatter').val() === 'markdown' ?
+                this.prettyPrint.text() : this.clearText.text();
             var newDoc = document.open('text/html', 'replace');
             var newDoc = document.open('text/html', 'replace');
             newDoc.write('<pre>' + paste + '</pre>');
             newDoc.write('<pre>' + paste + '</pre>');
             newDoc.close();
             newDoc.close();
@@ -1245,7 +1264,10 @@ $(function() {
                 this.clonedFile.removeClass('hidden');
                 this.clonedFile.removeClass('hidden');
                 this.fileWrap.addClass('hidden');
                 this.fileWrap.addClass('hidden');
             }
             }
-            this.message.text(this.clearText.text());
+            this.message.text(
+                $('#pasteFormatter').val() === 'markdown' ?
+                    this.prettyPrint.text() : this.clearText.text()
+            );
             $('.navbar-toggle').click();
             $('.navbar-toggle').click();
         },
         },
 
 
@@ -1273,6 +1295,10 @@ $(function() {
             var target = $(event.target);
             var target = $(event.target);
             $('#pasteFormatter').val(target.data('format'));
             $('#pasteFormatter').val(target.data('format'));
             $('#pasteFormatterDisplay').text(target.text());
             $('#pasteFormatterDisplay').text(target.text());
+
+            if (this.messagePreview.parent().hasClass('active')) {
+                this.viewPreview(event);
+            }
         },
         },
 
 
         /**
         /**
@@ -1349,6 +1375,8 @@ $(function() {
             this.stateNewPaste();
             this.stateNewPaste();
             this.showStatus('', false);
             this.showStatus('', false);
             this.message.text('');
             this.message.text('');
+            this.changeBurnAfterReading();
+            this.changeOpenDisc();
         },
         },
 
 
         /**
         /**
@@ -1381,7 +1409,18 @@ $(function() {
                 this.errorMessage.removeClass('hidden');
                 this.errorMessage.removeClass('hidden');
                 helper.setMessage(this.errorMessage, message);
                 helper.setMessage(this.errorMessage, message);
             }
             }
-            this.replyStatus.addClass('errorMessage').text(message);
+            if (typeof this.replyStatus !== 'undefined') {
+                this.replyStatus.addClass('errorMessage');
+                this.replyStatus.addClass(this.errorMessage.attr('class'));
+                if (this.status.length)
+                {
+                    this.replyStatus.html(this.status.html());
+                }
+                else
+                {
+                    this.replyStatus.html(this.errorMessage.html());
+                }
+            }
         },
         },
 
 
         /**
         /**
@@ -1393,7 +1432,9 @@ $(function() {
          */
          */
         showStatus: function(message, spin)
         showStatus: function(message, spin)
         {
         {
-            this.replyStatus.removeClass('errorMessage').text(message);
+            if (typeof this.replyStatus !== 'undefined') {
+                this.replyStatus.removeClass('errorMessage').text(message);
+            }
             if (!message)
             if (!message)
             {
             {
                 this.status.html(' ');
                 this.status.html(' ');
@@ -1409,7 +1450,9 @@ $(function() {
             {
             {
                 var img = '<img src="img/busy.gif" style="width:16px;height:9px;margin:0 4px 0 0;" />';
                 var img = '<img src="img/busy.gif" style="width:16px;height:9px;margin:0 4px 0 0;" />';
                 this.status.prepend(img);
                 this.status.prepend(img);
-                this.replyStatus.prepend(img);
+                if (typeof this.replyStatus !== 'undefined') {
+                    this.replyStatus.prepend(img);
+                }
             }
             }
         },
         },
 
 
@@ -1419,6 +1462,7 @@ $(function() {
         bindEvents: function()
         bindEvents: function()
         {
         {
             this.burnAfterReading.change($.proxy(this.changeBurnAfterReading, this));
             this.burnAfterReading.change($.proxy(this.changeBurnAfterReading, this));
+            this.openDisc.change($.proxy(this.changeOpenDisc, this));
             this.sendButton.click($.proxy(this.sendData, this));
             this.sendButton.click($.proxy(this.sendData, this));
             this.cloneButton.click($.proxy(this.clonePaste, this));
             this.cloneButton.click($.proxy(this.clonePaste, this));
             this.rawTextButton.click($.proxy(this.rawText, this));
             this.rawTextButton.click($.proxy(this.rawText, this));
@@ -1477,7 +1521,6 @@ $(function() {
             this.preview = $('#preview');
             this.preview = $('#preview');
             this.rawTextButton = $('#rawtextbutton');
             this.rawTextButton = $('#rawtextbutton');
             this.remainingTime = $('#remainingtime');
             this.remainingTime = $('#remainingtime');
-            this.replyStatus = $('#replystatus');
             this.sendButton = $('#sendbutton');
             this.sendButton = $('#sendbutton');
             this.status = $('#status');
             this.status = $('#status');
             this.bindEvents();
             this.bindEvents();

+ 3 - 3
lib/Configuration.php

@@ -50,8 +50,8 @@ class Configuration
             'languageselection' => false,
             'languageselection' => false,
             'languagedefault' => '',
             'languagedefault' => '',
             'urlshortener' => '',
             'urlshortener' => '',
-            'vizhash' => true,
-            'cspheader' => 'default-src \'none\'; connect-src *; script-src \'self\'; style-src \'self\'; font-src \'self\'; img-src \'self\';',
+            'icon' => 'identicon',
+            'cspheader' => 'default-src \'none\'; connect-src *; script-src \'self\'; style-src \'self\'; font-src \'self\'; img-src \'self\' data:;',
             'zerobincompatibility' => false,
             'zerobincompatibility' => false,
         ),
         ),
         'expire' => array(
         'expire' => array(
@@ -98,7 +98,7 @@ class Configuration
      */
      */
     public function __construct()
     public function __construct()
     {
     {
-        $config = array();
+        $config     = array();
         $configFile = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini';
         $configFile = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini';
         if (is_readable($configFile)) {
         if (is_readable($configFile)) {
             $config = parse_ini_file($configFile, true);
             $config = parse_ini_file($configFile, true);

+ 31 - 31
lib/Data/Database.php

@@ -71,7 +71,7 @@ class Database extends AbstractData
     public static function getInstance($options = null)
     public static function getInstance($options = null)
     {
     {
         // if needed initialize the singleton
         // if needed initialize the singleton
-        if (!(self::$_instance instanceof Database)) {
+        if (!(self::$_instance instanceof self)) {
             self::$_instance = new self;
             self::$_instance = new self;
         }
         }
 
 
@@ -89,17 +89,17 @@ class Database extends AbstractData
                 array_key_exists('opt', $options)
                 array_key_exists('opt', $options)
             ) {
             ) {
                 // set default options
                 // set default options
-                $options['opt'][PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
+                $options['opt'][PDO::ATTR_ERRMODE]          = PDO::ERRMODE_EXCEPTION;
                 $options['opt'][PDO::ATTR_EMULATE_PREPARES] = false;
                 $options['opt'][PDO::ATTR_EMULATE_PREPARES] = false;
-                $options['opt'][PDO::ATTR_PERSISTENT] = true;
-                $db_tables_exist = true;
+                $options['opt'][PDO::ATTR_PERSISTENT]       = true;
+                $db_tables_exist                            = true;
 
 
                 // setup type and dabase connection
                 // setup type and dabase connection
                 self::$_type = strtolower(
                 self::$_type = strtolower(
                     substr($options['dsn'], 0, strpos($options['dsn'], ':'))
                     substr($options['dsn'], 0, strpos($options['dsn'], ':'))
                 );
                 );
                 $tableQuery = self::_getTableQuery(self::$_type);
                 $tableQuery = self::_getTableQuery(self::$_type);
-                self::$_db = new PDO(
+                self::$_db  = new PDO(
                     $options['dsn'],
                     $options['dsn'],
                     $options['usr'],
                     $options['usr'],
                     $options['pwd'],
                     $options['pwd'],
@@ -168,8 +168,8 @@ class Database extends AbstractData
         }
         }
 
 
         $opendiscussion = $burnafterreading = false;
         $opendiscussion = $burnafterreading = false;
-        $attachment = $attachmentname = '';
-        $meta = $paste['meta'];
+        $attachment     = $attachmentname     = '';
+        $meta           = $paste['meta'];
         unset($meta['postdate']);
         unset($meta['postdate']);
         $expire_date = 0;
         $expire_date = 0;
         if (array_key_exists('expire_date', $paste['meta'])) {
         if (array_key_exists('expire_date', $paste['meta'])) {
@@ -222,14 +222,14 @@ class Database extends AbstractData
             !array_key_exists($pasteid, self::$_cache)
             !array_key_exists($pasteid, self::$_cache)
         ) {
         ) {
             self::$_cache[$pasteid] = false;
             self::$_cache[$pasteid] = false;
-            $paste = self::_select(
+            $paste                  = self::_select(
                 'SELECT * FROM ' . self::_sanitizeIdentifier('paste') .
                 'SELECT * FROM ' . self::_sanitizeIdentifier('paste') .
                 ' WHERE dataid = ?', array($pasteid), true
                 ' WHERE dataid = ?', array($pasteid), true
             );
             );
 
 
             if (false !== $paste) {
             if (false !== $paste) {
                 // create object
                 // create object
-                self::$_cache[$pasteid] = new stdClass;
+                self::$_cache[$pasteid]       = new stdClass;
                 self::$_cache[$pasteid]->data = $paste['data'];
                 self::$_cache[$pasteid]->data = $paste['data'];
 
 
                 $meta = json_decode($paste['meta']);
                 $meta = json_decode($paste['meta']);
@@ -253,9 +253,9 @@ class Database extends AbstractData
                         self::$_cache[$pasteid]->attachmentname = $paste['attachmentname'];
                         self::$_cache[$pasteid]->attachmentname = $paste['attachmentname'];
                     }
                     }
                 }
                 }
-                self::$_cache[$pasteid]->meta = $meta;
+                self::$_cache[$pasteid]->meta           = $meta;
                 self::$_cache[$pasteid]->meta->postdate = (int) $paste['postdate'];
                 self::$_cache[$pasteid]->meta->postdate = (int) $paste['postdate'];
-                $expire_date = (int) $paste['expiredate'];
+                $expire_date                            = (int) $paste['expiredate'];
                 if (
                 if (
                     $expire_date > 0
                     $expire_date > 0
                 ) {
                 ) {
@@ -368,12 +368,12 @@ class Database extends AbstractData
         $comments = array();
         $comments = array();
         if (count($rows)) {
         if (count($rows)) {
             foreach ($rows as $row) {
             foreach ($rows as $row) {
-                $i = $this->getOpenSlot($comments, (int) $row['postdate']);
-                $comments[$i] = new stdClass;
-                $comments[$i]->id = $row['dataid'];
-                $comments[$i]->parentid = $row['parentid'];
-                $comments[$i]->data = $row['data'];
-                $comments[$i]->meta = new stdClass;
+                $i                            = $this->getOpenSlot($comments, (int) $row['postdate']);
+                $comments[$i]                 = new stdClass;
+                $comments[$i]->id             = $row['dataid'];
+                $comments[$i]->parentid       = $row['parentid'];
+                $comments[$i]->data           = $row['data'];
+                $comments[$i]->meta           = new stdClass;
                 $comments[$i]->meta->postdate = (int) $row['postdate'];
                 $comments[$i]->meta->postdate = (int) $row['postdate'];
                 if (array_key_exists('nickname', $row) && !empty($row['nickname'])) {
                 if (array_key_exists('nickname', $row) && !empty($row['nickname'])) {
                     $comments[$i]->meta->nickname = $row['nickname'];
                     $comments[$i]->meta->nickname = $row['nickname'];
@@ -415,7 +415,7 @@ class Database extends AbstractData
     protected function _getExpiredPastes($batchsize)
     protected function _getExpiredPastes($batchsize)
     {
     {
         $pastes = array();
         $pastes = array();
-        $rows = self::_select(
+        $rows   = self::_select(
             'SELECT dataid FROM ' . self::_sanitizeIdentifier('paste') .
             'SELECT dataid FROM ' . self::_sanitizeIdentifier('paste') .
             ' WHERE expiredate < ? LIMIT ?', array(time(), $batchsize)
             ' WHERE expiredate < ? LIMIT ?', array(time(), $batchsize)
         );
         );
@@ -440,7 +440,7 @@ class Database extends AbstractData
     private static function _exec($sql, array $params)
     private static function _exec($sql, array $params)
     {
     {
         $statement = self::$_db->prepare($sql);
         $statement = self::$_db->prepare($sql);
-        $result = $statement->execute($params);
+        $result    = $statement->execute($params);
         $statement->closeCursor();
         $statement->closeCursor();
         return $result;
         return $result;
     }
     }
@@ -486,7 +486,7 @@ class Database extends AbstractData
                 $sql = 'SELECT tabname FROM systables ';
                 $sql = 'SELECT tabname FROM systables ';
                 break;
                 break;
             case 'mssql':
             case 'mssql':
-                $sql = "SELECT name FROM sysobjects "
+                $sql = 'SELECT name FROM sysobjects '
                      . "WHERE type = 'U' ORDER BY name";
                      . "WHERE type = 'U' ORDER BY name";
                 break;
                 break;
             case 'mysql':
             case 'mysql':
@@ -496,22 +496,22 @@ class Database extends AbstractData
                 $sql = 'SELECT table_name FROM all_tables';
                 $sql = 'SELECT table_name FROM all_tables';
                 break;
                 break;
             case 'pgsql':
             case 'pgsql':
-                $sql = "SELECT c.relname AS table_name "
-                     . "FROM pg_class c, pg_user u "
+                $sql = 'SELECT c.relname AS table_name '
+                     . 'FROM pg_class c, pg_user u '
                      . "WHERE c.relowner = u.usesysid AND c.relkind = 'r' "
                      . "WHERE c.relowner = u.usesysid AND c.relkind = 'r' "
-                     . "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) "
+                     . 'AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) '
                      . "AND c.relname !~ '^(pg_|sql_)' "
                      . "AND c.relname !~ '^(pg_|sql_)' "
-                     . "UNION "
-                     . "SELECT c.relname AS table_name "
-                     . "FROM pg_class c "
+                     . 'UNION '
+                     . 'SELECT c.relname AS table_name '
+                     . 'FROM pg_class c '
                      . "WHERE c.relkind = 'r' "
                      . "WHERE c.relkind = 'r' "
-                     . "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) "
-                     . "AND NOT EXISTS (SELECT 1 FROM pg_user WHERE usesysid = c.relowner) "
+                     . 'AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) '
+                     . 'AND NOT EXISTS (SELECT 1 FROM pg_user WHERE usesysid = c.relowner) '
                      . "AND c.relname !~ '^pg_'";
                      . "AND c.relname !~ '^pg_'";
                 break;
                 break;
             case 'sqlite':
             case 'sqlite':
                 $sql = "SELECT name FROM sqlite_master WHERE type='table' "
                 $sql = "SELECT name FROM sqlite_master WHERE type='table' "
-                     . "UNION ALL SELECT name FROM sqlite_temp_master "
+                     . 'UNION ALL SELECT name FROM sqlite_temp_master '
                      . "WHERE type='table' ORDER BY name";
                      . "WHERE type='table' ORDER BY name";
                 break;
                 break;
             default:
             default:
@@ -569,7 +569,7 @@ class Database extends AbstractData
     private static function _createPasteTable()
     private static function _createPasteTable()
     {
     {
         list($main_key, $after_key) = self::_getPrimaryKeyClauses();
         list($main_key, $after_key) = self::_getPrimaryKeyClauses();
-        $dataType = self::$_type === 'pgsql' ? 'TEXT' : 'BLOB';
+        $dataType                   = self::$_type === 'pgsql' ? 'TEXT' : 'BLOB';
         self::$_db->exec(
         self::$_db->exec(
             'CREATE TABLE ' . self::_sanitizeIdentifier('paste') . ' ( ' .
             'CREATE TABLE ' . self::_sanitizeIdentifier('paste') . ' ( ' .
             "dataid CHAR(16) NOT NULL$main_key, " .
             "dataid CHAR(16) NOT NULL$main_key, " .
@@ -594,7 +594,7 @@ class Database extends AbstractData
     private static function _createCommentTable()
     private static function _createCommentTable()
     {
     {
         list($main_key, $after_key) = self::_getPrimaryKeyClauses();
         list($main_key, $after_key) = self::_getPrimaryKeyClauses();
-        $dataType = self::$_type === 'pgsql' ? 'text' : 'BLOB';
+        $dataType                   = self::$_type === 'pgsql' ? 'text' : 'BLOB';
         self::$_db->exec(
         self::$_db->exec(
             'CREATE TABLE ' . self::_sanitizeIdentifier('comment') . ' ( ' .
             'CREATE TABLE ' . self::_sanitizeIdentifier('comment') . ' ( ' .
             "dataid CHAR(16) NOT NULL$main_key, " .
             "dataid CHAR(16) NOT NULL$main_key, " .

+ 15 - 12
lib/Data/Filesystem.php

@@ -13,6 +13,7 @@
 namespace PrivateBin\Data;
 namespace PrivateBin\Data;
 
 
 use PrivateBin\Model\Paste;
 use PrivateBin\Model\Paste;
+use PrivateBin\Json;
 
 
 /**
 /**
  * Filesystem
  * Filesystem
@@ -48,7 +49,7 @@ class Filesystem extends AbstractData
             self::$_dir = $options['dir'] . DIRECTORY_SEPARATOR;
             self::$_dir = $options['dir'] . DIRECTORY_SEPARATOR;
         }
         }
         // if needed initialize the singleton
         // if needed initialize the singleton
-        if (!(self::$_instance instanceof Filesystem)) {
+        if (!(self::$_instance instanceof self)) {
             self::$_instance = new self;
             self::$_instance = new self;
             self::_init();
             self::_init();
         }
         }
@@ -61,6 +62,7 @@ class Filesystem extends AbstractData
      * @access public
      * @access public
      * @param  string $pasteid
      * @param  string $pasteid
      * @param  array  $paste
      * @param  array  $paste
+     * @throws Exception
      * @return bool
      * @return bool
      */
      */
     public function create($pasteid, $paste)
     public function create($pasteid, $paste)
@@ -72,7 +74,7 @@ class Filesystem extends AbstractData
         if (!is_dir($storagedir)) {
         if (!is_dir($storagedir)) {
             mkdir($storagedir, 0700, true);
             mkdir($storagedir, 0700, true);
         }
         }
-        return (bool) file_put_contents($storagedir . $pasteid, json_encode($paste));
+        return (bool) file_put_contents($storagedir . $pasteid, Json::encode($paste));
     }
     }
 
 
     /**
     /**
@@ -153,19 +155,20 @@ class Filesystem extends AbstractData
      * @param  string $parentid
      * @param  string $parentid
      * @param  string $commentid
      * @param  string $commentid
      * @param  array  $comment
      * @param  array  $comment
+     * @throws Exception
      * @return bool
      * @return bool
      */
      */
     public function createComment($pasteid, $parentid, $commentid, $comment)
     public function createComment($pasteid, $parentid, $commentid, $comment)
     {
     {
         $storagedir = self::_dataid2discussionpath($pasteid);
         $storagedir = self::_dataid2discussionpath($pasteid);
-        $filename = $pasteid . '.' . $commentid . '.' . $parentid;
+        $filename   = $pasteid . '.' . $commentid . '.' . $parentid;
         if (is_file($storagedir . $filename)) {
         if (is_file($storagedir . $filename)) {
             return false;
             return false;
         }
         }
         if (!is_dir($storagedir)) {
         if (!is_dir($storagedir)) {
             mkdir($storagedir, 0700, true);
             mkdir($storagedir, 0700, true);
         }
         }
-        return (bool) file_put_contents($storagedir . $filename, json_encode($comment));
+        return (bool) file_put_contents($storagedir . $filename, Json::encode($comment));
     }
     }
 
 
     /**
     /**
@@ -178,7 +181,7 @@ class Filesystem extends AbstractData
     public function readComments($pasteid)
     public function readComments($pasteid)
     {
     {
         $comments = array();
         $comments = array();
-        $discdir = self::_dataid2discussionpath($pasteid);
+        $discdir  = self::_dataid2discussionpath($pasteid);
         if (is_dir($discdir)) {
         if (is_dir($discdir)) {
             // Delete all files in discussion directory
             // Delete all files in discussion directory
             $dir = dir($discdir);
             $dir = dir($discdir);
@@ -189,13 +192,13 @@ class Filesystem extends AbstractData
                 // - parentid is the comment this comment replies to (It can be pasteid)
                 // - parentid is the comment this comment replies to (It can be pasteid)
                 if (is_file($discdir . $filename)) {
                 if (is_file($discdir . $filename)) {
                     $comment = json_decode(file_get_contents($discdir . $filename));
                     $comment = json_decode(file_get_contents($discdir . $filename));
-                    $items = explode('.', $filename);
+                    $items   = explode('.', $filename);
                     // Add some meta information not contained in file.
                     // Add some meta information not contained in file.
-                    $comment->id = $items[1];
+                    $comment->id       = $items[1];
                     $comment->parentid = $items[2];
                     $comment->parentid = $items[2];
 
 
                     // Store in array
                     // Store in array
-                    $key = $this->getOpenSlot($comments, (int) $comment->meta->postdate);
+                    $key            = $this->getOpenSlot($comments, (int) $comment->meta->postdate);
                     $comments[$key] = $comment;
                     $comments[$key] = $comment;
                 }
                 }
             }
             }
@@ -233,7 +236,7 @@ class Filesystem extends AbstractData
      */
      */
     protected function _getExpiredPastes($batchsize)
     protected function _getExpiredPastes($batchsize)
     {
     {
-        $pastes = array();
+        $pastes     = array();
         $firstLevel = array_filter(
         $firstLevel = array_filter(
             scandir(self::$_dir),
             scandir(self::$_dir),
             'self::_isFirstLevelDir'
             'self::_isFirstLevelDir'
@@ -241,7 +244,7 @@ class Filesystem extends AbstractData
         if (count($firstLevel) > 0) {
         if (count($firstLevel) > 0) {
             // try at most 10 times the $batchsize pastes before giving up
             // try at most 10 times the $batchsize pastes before giving up
             for ($i = 0, $max = $batchsize * 10; $i < $max; ++$i) {
             for ($i = 0, $max = $batchsize * 10; $i < $max; ++$i) {
-                $firstKey = array_rand($firstLevel);
+                $firstKey    = array_rand($firstLevel);
                 $secondLevel = array_filter(
                 $secondLevel = array_filter(
                     scandir(self::$_dir . $firstLevel[$firstKey]),
                     scandir(self::$_dir . $firstLevel[$firstKey]),
                     'self::_isSecondLevelDir'
                     'self::_isSecondLevelDir'
@@ -254,7 +257,7 @@ class Filesystem extends AbstractData
                 }
                 }
 
 
                 $secondKey = array_rand($secondLevel);
                 $secondKey = array_rand($secondLevel);
-                $path = self::$_dir . $firstLevel[$firstKey] .
+                $path      = self::$_dir . $firstLevel[$firstKey] .
                     DIRECTORY_SEPARATOR . $secondLevel[$secondKey];
                     DIRECTORY_SEPARATOR . $secondLevel[$secondKey];
                 if (!is_dir($path)) {
                 if (!is_dir($path)) {
                     continue;
                     continue;
@@ -267,7 +270,7 @@ class Filesystem extends AbstractData
                     continue;
                     continue;
                 }
                 }
                 $thirdKey = array_rand($thirdLevel);
                 $thirdKey = array_rand($thirdLevel);
-                $pasteid = $thirdLevel[$thirdKey];
+                $pasteid  = $thirdLevel[$thirdKey];
                 if (in_array($pasteid, $pastes)) {
                 if (in_array($pasteid, $pastes)) {
                     continue;
                     continue;
                 }
                 }

+ 1 - 1
lib/Filter.php

@@ -77,7 +77,7 @@ class Filter
     public static function formatHumanReadableSize($size)
     public static function formatHumanReadableSize($size)
     {
     {
         $iec = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB');
         $iec = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB');
-        $i = 0;
+        $i   = 0;
         while (($size / 1024) >= 1) {
         while (($size / 1024) >= 1) {
             $size = $size / 1024;
             $size = $size / 1024;
             $i++;
             $i++;

+ 6 - 6
lib/I18n.php

@@ -114,8 +114,8 @@ class I18n
         $args = func_get_args();
         $args = func_get_args();
         if (is_array(self::$_translations[$messageId])) {
         if (is_array(self::$_translations[$messageId])) {
             $number = (int) $args[1];
             $number = (int) $args[1];
-            $key = self::_getPluralForm($number);
-            $max = count(self::$_translations[$messageId]) - 1;
+            $key    = self::_getPluralForm($number);
+            $max    = count(self::$_translations[$messageId]) - 1;
             if ($key > $max) {
             if ($key > $max) {
                 $key = $max;
                 $key = $max;
             }
             }
@@ -143,7 +143,7 @@ class I18n
 
 
         // check if the lang cookie was set and that language exists
         // check if the lang cookie was set and that language exists
         if (array_key_exists('lang', $_COOKIE) && in_array($_COOKIE['lang'], $availableLanguages)) {
         if (array_key_exists('lang', $_COOKIE) && in_array($_COOKIE['lang'], $availableLanguages)) {
-            $match = $availableLanguages[array_search($_COOKIE['lang'], $availableLanguages)];
+            $match = $_COOKIE['lang'];
         }
         }
         // find a translation file matching the browsers language preferences
         // find a translation file matching the browsers language preferences
         else {
         else {
@@ -153,7 +153,7 @@ class I18n
         }
         }
 
 
         // load translations
         // load translations
-        self::$_language = $match;
+        self::$_language     = $match;
         self::$_translations = ($match == 'en') ? array() : json_decode(
         self::$_translations = ($match == 'en') ? array() : json_decode(
             file_get_contents(self::_getPath($match . '.json')),
             file_get_contents(self::_getPath($match . '.json')),
             true
             true
@@ -319,7 +319,7 @@ class I18n
     protected static function _getMatchingLanguage($acceptedLanguages, $availableLanguages)
     protected static function _getMatchingLanguage($acceptedLanguages, $availableLanguages)
     {
     {
         $matches = array();
         $matches = array();
-        $any = false;
+        $any     = false;
         foreach ($acceptedLanguages as $acceptedQuality => $acceptedValues) {
         foreach ($acceptedLanguages as $acceptedQuality => $acceptedValues) {
             $acceptedQuality = floatval($acceptedQuality);
             $acceptedQuality = floatval($acceptedQuality);
             if ($acceptedQuality === 0.0) {
             if ($acceptedQuality === 0.0) {
@@ -372,7 +372,7 @@ class I18n
     {
     {
         $a = explode('-', $a);
         $a = explode('-', $a);
         $b = explode('-', $b);
         $b = explode('-', $b);
-        for ($i=0, $n = min(count($a), count($b)); $i < $n; ++$i) {
+        for ($i = 0, $n = min(count($a), count($b)); $i < $n; ++$i) {
             if ($a[$i] !== $b[$i]) {
             if ($a[$i] !== $b[$i]) {
                 break;
                 break;
             }
             }

+ 48 - 0
lib/Json.php

@@ -0,0 +1,48 @@
+<?php
+/**
+ * PrivateBin
+ *
+ * a zero-knowledge paste bin
+ *
+ * @link      https://github.com/PrivateBin/PrivateBin
+ * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
+ * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
+ * @version   0.22
+ */
+
+namespace PrivateBin;
+
+use Exception;
+
+/**
+ * Json
+ *
+ * Provides JSON functions in an object oriented way.
+ */
+class Json
+{
+    /**
+     * Returns a string containing the JSON representation of the given input
+     *
+     * @access public
+     * @static
+     * @param  mixed $input
+     * @throws Exception
+     * @return string
+     */
+    public static function encode($input)
+    {
+        $jsonString = json_encode($input);
+        $errorCode  = json_last_error();
+        if ($errorCode === JSON_ERROR_NONE) {
+            return $jsonString;
+        }
+
+        $message = 'A JSON error occurred';
+        if (function_exists('json_last_error_msg')) {
+            $message .= ': ' . json_last_error_msg();
+        }
+        $message .= ' (' . $errorCode . ')';
+        throw new Exception($message, 90);
+    }
+}

+ 3 - 3
lib/Model/AbstractModel.php

@@ -67,9 +67,9 @@ abstract class AbstractModel
      */
      */
     public function __construct(Configuration $configuration, AbstractData $storage)
     public function __construct(Configuration $configuration, AbstractData $storage)
     {
     {
-        $this->_conf = $configuration;
-        $this->_store = $storage;
-        $this->_data = new stdClass;
+        $this->_conf       = $configuration;
+        $this->_store      = $storage;
+        $this->_data       = new stdClass;
         $this->_data->meta = new stdClass;
         $this->_data->meta = new stdClass;
     }
     }
 
 

+ 21 - 11
lib/Model/Comment.php

@@ -10,11 +10,12 @@
  * @version   0.22
  * @version   0.22
  */
  */
 
 
-namespace PrivateBin\model;
+namespace PrivateBin\Model;
 
 
 use PrivateBin\Sjcl;
 use PrivateBin\Sjcl;
 use PrivateBin\Persistence\TrafficLimiter;
 use PrivateBin\Persistence\TrafficLimiter;
 use PrivateBin\Vizhash16x16;
 use PrivateBin\Vizhash16x16;
+use Identicon\Identicon;
 use Exception;
 use Exception;
 
 
 /**
 /**
@@ -132,7 +133,7 @@ class Comment extends AbstractModel
      */
      */
     public function setPaste(Paste $paste)
     public function setPaste(Paste $paste)
     {
     {
-        $this->_paste = $paste;
+        $this->_paste               = $paste;
         $this->_data->meta->pasteid = $paste->getId();
         $this->_data->meta->pasteid = $paste->getId();
     }
     }
 
 
@@ -192,17 +193,26 @@ class Comment extends AbstractModel
         }
         }
         $this->_data->meta->nickname = $nickname;
         $this->_data->meta->nickname = $nickname;
 
 
-        if ($this->_conf->getKey('vizhash')) {
-            // Generation of the anonymous avatar (Vizhash):
-            // If a nickname is provided, we generate a Vizhash.
-            // (We assume that if the user did not enter a nickname, he/she wants
-            // to be anonymous and we will not generate the vizhash.)
-            $vh = new Vizhash16x16();
-            $pngdata = $vh->generate(TrafficLimiter::getIp());
+        // If a nickname is provided, we generate an icon based on a SHA512 HMAC
+        // of the users IP. (We assume that if the user did not enter a nickname,
+        // the user wants to be anonymous and we will not generate an icon.)
+        $icon = $this->_conf->getKey('icon');
+        if ($icon != 'none') {
+            $pngdata = '';
+            $hmac    = TrafficLimiter::getHash();
+            if ($icon == 'identicon') {
+                $identicon = new Identicon();
+                $pngdata   = $identicon->getImageDataUri($hmac, 16);
+            } elseif ($icon == 'vizhash') {
+                $vh      = new Vizhash16x16();
+                $pngdata = 'data:image/png;base64,' . base64_encode(
+                    $vh->generate($hmac)
+                );
+            }
             if ($pngdata != '') {
             if ($pngdata != '') {
-                $this->_data->meta->vizhash = 'data:image/png;base64,' . base64_encode($pngdata);
+                $this->_data->meta->vizhash = $pngdata;
             }
             }
-            // Once the avatar is generated, we do not keep the IP address, nor its hash.
         }
         }
+        // Once the icon is generated, we do not keep the IP address hash.
     }
     }
 }
 }

+ 8 - 8
lib/Model/Paste.php

@@ -62,11 +62,11 @@ class Paste extends AbstractModel
         if (!property_exists($data->meta, 'salt')) {
         if (!property_exists($data->meta, 'salt')) {
             $data->meta->salt = ServerSalt::get();
             $data->meta->salt = ServerSalt::get();
         }
         }
-        $data->comments = array_values($this->getComments());
-        $data->comment_count = count($data->comments);
+        $data->comments       = array_values($this->getComments());
+        $data->comment_count  = count($data->comments);
         $data->comment_offset = 0;
         $data->comment_offset = 0;
-        $data->{'@context'} = 'js/paste.jsonld';
-        $this->_data = $data;
+        $data->{'@context'}   = 'js/paste.jsonld';
+        $this->_data          = $data;
         return $this->_data;
         return $this->_data;
     }
     }
 
 
@@ -85,7 +85,7 @@ class Paste extends AbstractModel
         }
         }
 
 
         $this->_data->meta->postdate = time();
         $this->_data->meta->postdate = time();
-        $this->_data->meta->salt = serversalt::generate();
+        $this->_data->meta->salt     = serversalt::generate();
 
 
         // store paste
         // store paste
         if (
         if (
@@ -247,7 +247,7 @@ class Paste extends AbstractModel
                 throw new Exception('Invalid data.', 73);
                 throw new Exception('Invalid data.', 73);
             }
             }
             $this->_data->meta->burnafterreading = true;
             $this->_data->meta->burnafterreading = true;
-            $this->_data->meta->opendiscussion = false;
+            $this->_data->meta->opendiscussion   = false;
         }
         }
     }
     }
 
 
@@ -296,7 +296,7 @@ class Paste extends AbstractModel
      *
      *
      * @access public
      * @access public
      * @throws Exception
      * @throws Exception
-     * @return boolean
+     * @return bool
      */
      */
     public function isBurnafterreading()
     public function isBurnafterreading()
     {
     {
@@ -313,7 +313,7 @@ class Paste extends AbstractModel
      *
      *
      * @access public
      * @access public
      * @throws Exception
      * @throws Exception
-     * @return boolean
+     * @return bool
      */
      */
     public function isOpendiscussion()
     public function isOpendiscussion()
     {
     {

+ 1 - 1
lib/Persistence/AbstractPersistence.php

@@ -119,7 +119,7 @@ abstract class AbstractPersistence
     protected static function _store($filename, $data)
     protected static function _store($filename, $data)
     {
     {
         self::_initialize();
         self::_initialize();
-        $file = self::$_path . DIRECTORY_SEPARATOR . $filename;
+        $file         = self::$_path . DIRECTORY_SEPARATOR . $filename;
         $writtenBytes = @file_put_contents($file, $data, LOCK_EX);
         $writtenBytes = @file_put_contents($file, $data, LOCK_EX);
         if ($writtenBytes === false || $writtenBytes < strlen($data)) {
         if ($writtenBytes === false || $writtenBytes < strlen($data)) {
             throw new Exception('unable to write to file ' . $file, 13);
             throw new Exception('unable to write to file ' . $file, 13);

+ 2 - 2
lib/Persistence/PurgeLimiter.php

@@ -72,8 +72,8 @@ class PurgeLimiter extends AbstractPersistence
             return true;
             return true;
         }
         }
 
 
-        $file = 'purge_limiter.php';
-        $now = time();
+        $file    = 'purge_limiter.php';
+        $now     = time();
         $content = '<?php' . PHP_EOL . '$GLOBALS[\'purge_limiter\'] = ' . $now . ';' . PHP_EOL;
         $content = '<?php' . PHP_EOL . '$GLOBALS[\'purge_limiter\'] = ' . $now . ';' . PHP_EOL;
         if (!self::_exists($file)) {
         if (!self::_exists($file)) {
             self::_store($file, $content);
             self::_store($file, $content);

+ 11 - 10
lib/Persistence/TrafficLimiter.php

@@ -73,15 +73,16 @@ class TrafficLimiter extends AbstractPersistence
     }
     }
 
 
     /**
     /**
-     * get the current visitors IP address
+     * get a HMAC of the current visitors IP address
      *
      *
      * @access public
      * @access public
      * @static
      * @static
+     * @param  string $algo
      * @return string
      * @return string
      */
      */
-    public static function getIp()
+    public static function getHash($algo = 'sha512')
     {
     {
-        return $_SERVER[self::$_ipKey];
+        return hash_hmac($algo, $_SERVER[self::$_ipKey], ServerSalt::get());
     }
     }
 
 
     /**
     /**
@@ -101,8 +102,6 @@ class TrafficLimiter extends AbstractPersistence
             return true;
             return true;
         }
         }
 
 
-        $ip = hash_hmac('sha256', self::getIp(), ServerSalt::get());
-
         $file = 'traffic_limiter.php';
         $file = 'traffic_limiter.php';
         if (!self::_exists($file)) {
         if (!self::_exists($file)) {
             self::_store(
             self::_store(
@@ -115,20 +114,22 @@ class TrafficLimiter extends AbstractPersistence
         $path = self::getPath($file);
         $path = self::getPath($file);
         require $path;
         require $path;
         $now = time();
         $now = time();
-        $tl = $GLOBALS['traffic_limiter'];
+        $tl  = $GLOBALS['traffic_limiter'];
 
 
-        // purge file of expired IPs to keep it small
+        // purge file of expired hashes to keep it small
         foreach ($tl as $key => $time) {
         foreach ($tl as $key => $time) {
             if ($time + self::$_limit < $now) {
             if ($time + self::$_limit < $now) {
                 unset($tl[$key]);
                 unset($tl[$key]);
             }
             }
         }
         }
 
 
-        if (array_key_exists($ip, $tl) && ($tl[$ip] + self::$_limit >= $now)) {
+        // this hash is used as an array key, hence a shorter hash is used
+        $hash = self::getHash('sha256');
+        if (array_key_exists($hash, $tl) && ($tl[$hash] + self::$_limit >= $now)) {
             $result = false;
             $result = false;
         } else {
         } else {
-            $tl[$ip] = time();
-            $result = true;
+            $tl[$hash] = time();
+            $result    = true;
         }
         }
         self::_store(
         self::_store(
             $file,
             $file,

+ 10 - 10
lib/PrivateBin.php

@@ -168,14 +168,14 @@ class PrivateBin
                 file_put_contents(
                 file_put_contents(
                 PATH . $dir . DIRECTORY_SEPARATOR . '.htaccess',
                 PATH . $dir . DIRECTORY_SEPARATOR . '.htaccess',
                 'Allow from none' . PHP_EOL .
                 'Allow from none' . PHP_EOL .
-                'Deny from all'. PHP_EOL,
+                'Deny from all' . PHP_EOL,
                 LOCK_EX
                 LOCK_EX
             );
             );
             }
             }
         }
         }
 
 
-        $this->_conf = new Configuration;
-        $this->_model = new Model($this->_conf);
+        $this->_conf    = new Configuration;
+        $this->_model   = new Model($this->_conf);
         $this->_request = new Request;
         $this->_request = new Request;
         $this->_urlBase = array_key_exists('REQUEST_URI', $_SERVER) ?
         $this->_urlBase = array_key_exists('REQUEST_URI', $_SERVER) ?
             htmlspecialchars($_SERVER['REQUEST_URI']) : '/';
             htmlspecialchars($_SERVER['REQUEST_URI']) : '/';
@@ -223,8 +223,8 @@ class PrivateBin
         );
         );
         }
         }
 
 
-        $data = $this->_request->getParam('data');
-        $attachment = $this->_request->getParam('attachment');
+        $data           = $this->_request->getParam('data');
+        $attachment     = $this->_request->getParam('attachment');
         $attachmentname = $this->_request->getParam('attachmentname');
         $attachmentname = $this->_request->getParam('attachmentname');
 
 
         // Ensure content is not too big.
         // Ensure content is not too big.
@@ -247,7 +247,7 @@ class PrivateBin
         }
         }
 
 
         // The user posts a comment.
         // The user posts a comment.
-        $pasteid = $this->_request->getParam('pasteid');
+        $pasteid  = $this->_request->getParam('pasteid');
         $parentid = $this->_request->getParam('parentid');
         $parentid = $this->_request->getParam('parentid');
         if (!empty($pasteid) && !empty($parentid)) {
         if (!empty($pasteid) && !empty($parentid)) {
             $paste = $this->_model->getPaste($pasteid);
             $paste = $this->_model->getPaste($pasteid);
@@ -365,7 +365,7 @@ class PrivateBin
         try {
         try {
             $paste = $this->_model->getPaste($dataid);
             $paste = $this->_model->getPaste($dataid);
             if ($paste->exists()) {
             if ($paste->exists()) {
-                $data = $paste->get();
+                $data              = $paste->get();
                 $this->_doesExpire = property_exists($data, 'meta') && property_exists($data->meta, 'expire_date');
                 $this->_doesExpire = property_exists($data, 'meta') && property_exists($data->meta, 'expire_date');
                 if (property_exists($data->meta, 'salt')) {
                 if (property_exists($data->meta, 'salt')) {
                     unset($data->meta->salt);
                     unset($data->meta->salt);
@@ -407,7 +407,7 @@ class PrivateBin
         // label all the expiration options
         // label all the expiration options
         $expire = array();
         $expire = array();
         foreach ($this->_conf->getSection('expire_options') as $time => $seconds) {
         foreach ($this->_conf->getSection('expire_options') as $time => $seconds) {
-            $expire[$time] = ($seconds == 0) ? I18n::_(ucfirst($time)): Filter::formatHumanReadableTime($time);
+            $expire[$time] = ($seconds == 0) ? I18n::_(ucfirst($time)) : Filter::formatHumanReadableTime($time);
         }
         }
 
 
         // translate all the formatter options
         // translate all the formatter options
@@ -462,7 +462,7 @@ class PrivateBin
             $type = '';
             $type = '';
         }
         }
         $content = '{}';
         $content = '{}';
-        $file = PUBLIC_PATH . DIRECTORY_SEPARATOR . 'js' . DIRECTORY_SEPARATOR . $type . '.jsonld';
+        $file    = PUBLIC_PATH . DIRECTORY_SEPARATOR . 'js' . DIRECTORY_SEPARATOR . $type . '.jsonld';
         if (is_readable($file)) {
         if (is_readable($file)) {
             $content = str_replace(
             $content = str_replace(
                 '?jsonld=',
                 '?jsonld=',
@@ -492,7 +492,7 @@ class PrivateBin
         if ($status) {
         if ($status) {
             $result['message'] = I18n::_($message);
             $result['message'] = I18n::_($message);
         } else {
         } else {
-            $result['id'] = $message;
+            $result['id']  = $message;
             $result['url'] = $this->_urlBase . '?' . $message;
             $result['url'] = $this->_urlBase . '?' . $message;
         }
         }
         $result += $other;
         $result += $other;

+ 2 - 2
lib/Request.php

@@ -16,7 +16,7 @@ namespace PrivateBin;
  * Request
  * Request
  *
  *
  * parses request parameters and provides helper functions for routing
  * parses request parameters and provides helper functions for routing
-*/
+ */
 class Request
 class Request
 {
 {
     /**
     /**
@@ -184,7 +184,7 @@ class Request
     private function _detectJsonRequest()
     private function _detectJsonRequest()
     {
     {
         $hasAcceptHeader = array_key_exists('HTTP_ACCEPT', $_SERVER);
         $hasAcceptHeader = array_key_exists('HTTP_ACCEPT', $_SERVER);
-        $acceptHeader = $hasAcceptHeader ? $_SERVER['HTTP_ACCEPT'] : '';
+        $acceptHeader    = $hasAcceptHeader ? $_SERVER['HTTP_ACCEPT'] : '';
 
 
         // simple cases
         // simple cases
         if (
         if (

+ 1 - 0
lib/View.php

@@ -11,6 +11,7 @@
  */
  */
 
 
 namespace PrivateBin;
 namespace PrivateBin;
+
 use Exception;
 use Exception;
 
 
 /**
 /**

+ 39 - 56
lib/Vizhash16x16.php

@@ -13,8 +13,6 @@
 
 
 namespace PrivateBin;
 namespace PrivateBin;
 
 
-use PrivateBin\Persistence\ServerSalt;
-
 /**
 /**
  * Vizhash16x16
  * Vizhash16x16
  *
  *
@@ -60,14 +58,6 @@ class Vizhash16x16
      */
      */
     private $height;
     private $height;
 
 
-    /**
-     * salt used when generating the image
-     *
-     * @access private
-     * @var    string
-     */
-    private $salt;
-
     /**
     /**
      * constructor
      * constructor
      *
      *
@@ -78,12 +68,13 @@ class Vizhash16x16
     {
     {
         $this->width  = 16;
         $this->width  = 16;
         $this->height = 16;
         $this->height = 16;
-        $this->salt   = ServerSalt::get();
     }
     }
 
 
     /**
     /**
      * Generate a 16x16 png corresponding to $text.
      * Generate a 16x16 png corresponding to $text.
      *
      *
+     * The given text should to be 128 to 150 characters long
+     *
      * @access public
      * @access public
      * @param  string $text
      * @param  string $text
      * @return string PNG data. Or empty string if GD is not available.
      * @return string PNG data. Or empty string if GD is not available.
@@ -94,44 +85,35 @@ class Vizhash16x16
             return '';
             return '';
         }
         }
 
 
-        // We hash the input string.
-        $hash=hash('sha1', $text.$this->salt).hash('md5', $text.$this->salt);
-        $hash=$hash.strrev($hash);  # more data to make graphics
-        $hashlen=strlen($hash);
+        $textlen = strlen($text);
 
 
         // We convert the hash into an array of integers.
         // We convert the hash into an array of integers.
-        $this->VALUES=array();
-        for ($i=0; $i<$hashlen; $i=$i+2) {
-            array_push($this->VALUES, hexdec(substr($hash, $i, 2)));
+        $this->VALUES = array();
+        for ($i = 0; $i < $textlen; $i = $i + 2) {
+            array_push($this->VALUES, hexdec(substr($text, $i, 2)));
         }
         }
-        $this->VALUES_INDEX=0; // to walk the array.
+        $this->VALUES_INDEX = 0; // to walk the array.
 
 
         // Then use these integers to drive the creation of an image.
         // Then use these integers to drive the creation of an image.
         $image = imagecreatetruecolor($this->width, $this->height);
         $image = imagecreatetruecolor($this->width, $this->height);
 
 
-        $r0 = $this->getInt();
-        $r=$r0;
-        $g0 = $this->getInt();
-        $g=$g0;
-        $b0 = $this->getInt();
-        $b=$b0;
+        $r = $r0 = $this->getInt();
+        $g = $g0 = $this->getInt();
+        $b = $b0 = $this->getInt();
 
 
         // First, create an image with a specific gradient background.
         // First, create an image with a specific gradient background.
-        $op='v';
-        if (($this->getInt()%2)==0) {
-            $op='h';
+        $op = 'v';
+        if (($this->getInt() % 2) == 0) {
+            $op = 'h';
         };
         };
         $image = $this->degrade($image, $op, array($r0, $g0, $b0), array(0, 0, 0));
         $image = $this->degrade($image, $op, array($r0, $g0, $b0), array(0, 0, 0));
 
 
-        for ($i=0; $i<7; $i=$i+1) {
-            $action=$this->getInt();
-            $color = imagecolorallocate($image, $r, $g, $b);
-            $r = ($r0 + $this->getInt()/25)%256;
-            $g = ($g0 + $this->getInt()/25)%256;
-            $b = ($b0 + $this->getInt()/25)%256;
-            $r0=$r;
-            $g0=$g;
-            $b0=$b;
+        for ($i = 0; $i < 7; ++$i) {
+            $action = $this->getInt();
+            $color  = imagecolorallocate($image, $r, $g, $b);
+            $r      = $r0      = ($r0 + $this->getInt() / 25) % 256;
+            $g      = $g0      = ($g0 + $this->getInt() / 25) % 256;
+            $b      = $b0      = ($b0 + $this->getInt() / 25) % 256;
             $this->drawshape($image, $action, $color);
             $this->drawshape($image, $action, $color);
         }
         }
 
 
@@ -154,8 +136,8 @@ class Vizhash16x16
      */
      */
     private function getInt()
     private function getInt()
     {
     {
-        $v= $this->VALUES[$this->VALUES_INDEX];
-        $this->VALUES_INDEX++;
+        $v = $this->VALUES[$this->VALUES_INDEX];
+        ++$this->VALUES_INDEX;
         $this->VALUES_INDEX %= count($this->VALUES); // Warp around the array
         $this->VALUES_INDEX %= count($this->VALUES); // Warp around the array
         return $v;
         return $v;
     }
     }
@@ -168,7 +150,7 @@ class Vizhash16x16
      */
      */
     private function getX()
     private function getX()
     {
     {
-        return $this->width*$this->getInt()/256;
+        return $this->width * $this->getInt() / 256;
     }
     }
 
 
     /**
     /**
@@ -179,7 +161,7 @@ class Vizhash16x16
      */
      */
     private function getY()
     private function getY()
     {
     {
-        return $this->height*$this->getInt()/256;
+        return $this->height * $this->getInt() / 256;
     }
     }
 
 
     /**
     /**
@@ -197,23 +179,23 @@ class Vizhash16x16
      */
      */
     private function degrade($img, $direction, $color1, $color2)
     private function degrade($img, $direction, $color1, $color2)
     {
     {
-        if ($direction=='h') {
-            $size = imagesx($img);
+        if ($direction == 'h') {
+            $size    = imagesx($img);
             $sizeinv = imagesy($img);
             $sizeinv = imagesy($img);
         } else {
         } else {
-            $size = imagesy($img);
+            $size    = imagesy($img);
             $sizeinv = imagesx($img);
             $sizeinv = imagesx($img);
         }
         }
         $diffs = array(
         $diffs = array(
-                    (($color2[0]-$color1[0])/$size),
-                    (($color2[1]-$color1[1])/$size),
-                    (($color2[2]-$color1[2])/$size)
-            );
-        for ($i=0;$i<$size;$i++) {
-            $r = $color1[0]+($diffs[0]*$i);
-            $g = $color1[1]+($diffs[1]*$i);
-            $b = $color1[2]+($diffs[2]*$i);
-            if ($direction=='h') {
+            (($color2[0] - $color1[0]) / $size),
+            (($color2[1] - $color1[1]) / $size),
+            (($color2[2] - $color1[2]) / $size)
+        );
+        for ($i = 0; $i < $size; ++$i) {
+            $r = $color1[0] + ($diffs[0] * $i);
+            $g = $color1[1] + ($diffs[1] * $i);
+            $b = $color1[2] + ($diffs[2] * $i);
+            if ($direction == 'h') {
                 imageline($img, $i, 0, $i, $sizeinv, imagecolorallocate($img, $r, $g, $b));
                 imageline($img, $i, 0, $i, $sizeinv, imagecolorallocate($img, $r, $g, $b));
             } else {
             } else {
                 imageline($img, 0, $i, $sizeinv, $i, imagecolorallocate($img, $r, $g, $b));
                 imageline($img, 0, $i, $sizeinv, $i, imagecolorallocate($img, $r, $g, $b));
@@ -233,7 +215,7 @@ class Vizhash16x16
      */
      */
     private function drawshape($image, $action, $color)
     private function drawshape($image, $action, $color)
     {
     {
-        switch ($action%7) {
+        switch ($action % 7) {
             case 0:
             case 0:
                 ImageFilledRectangle($image, $this->getX(), $this->getY(), $this->getX(), $this->getY(), $color);
                 ImageFilledRectangle($image, $this->getX(), $this->getY(), $this->getX(), $this->getY(), $color);
                 break;
                 break;
@@ -242,11 +224,12 @@ class Vizhash16x16
                 ImageFilledEllipse($image, $this->getX(), $this->getY(), $this->getX(), $this->getY(), $color);
                 ImageFilledEllipse($image, $this->getX(), $this->getY(), $this->getX(), $this->getY(), $color);
                 break;
                 break;
             case 3:
             case 3:
-                $points = array($this->getX(), $this->getY(), $this->getX(), $this->getY(), $this->getX(), $this->getY(),$this->getX(), $this->getY());
+                $points = array($this->getX(), $this->getY(), $this->getX(), $this->getY(), $this->getX(), $this->getY(), $this->getX(), $this->getY());
                 ImageFilledPolygon($image, $points, 4, $color);
                 ImageFilledPolygon($image, $points, 4, $color);
                 break;
                 break;
             default:
             default:
-                $start=$this->getInt()*360/256; $end=$start+$this->getInt()*180/256;
+                $start = $this->getInt() * 360 / 256;
+                $end   = $start + $this->getInt() * 180 / 256;
                 ImageFilledArc($image, $this->getX(), $this->getY(), $this->getX(), $this->getY(), $start, $end, $color, IMG_ARC_PIE);
                 ImageFilledArc($image, $this->getX(), $this->getY(), $this->getX(), $this->getY(), $start, $end, $color, IMG_ARC_PIE);
         }
         }
     }
     }

+ 0 - 1
privatebin

@@ -1 +0,0 @@
-privatebin

+ 16 - 16
tpl/bootstrap-compact.php

@@ -72,19 +72,19 @@ endif;
 					<ul class="nav navbar-nav">
 					<ul class="nav navbar-nav">
 						<li>
 						<li>
 							<button id="sendbutton" type="button" class="hidden btn btn-default navbar-btn">
 							<button id="sendbutton" type="button" class="hidden btn btn-default navbar-btn">
-								<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Send'); ?>
+								<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Send'), PHP_EOL; ?>
 							</button>
 							</button>
 <?php
 <?php
 if ($EXPIRECLONE):
 if ($EXPIRECLONE):
 ?>
 ?>
 							<button id="clonebutton" type="button" class="hidden btn btn-default navbar-btn">
 							<button id="clonebutton" type="button" class="hidden btn btn-default navbar-btn">
-								<span class="glyphicon glyphicon-duplicate" aria-hidden="true"></span> <?php echo I18n::_('Clone'); ?>
+								<span class="glyphicon glyphicon-duplicate" aria-hidden="true"></span> <?php echo I18n::_('Clone'), PHP_EOL; ?>
 							</button>
 							</button>
 <?php
 <?php
 endif;
 endif;
 ?>
 ?>
 							<button id="rawtextbutton" type="button" class="hidden btn btn-default navbar-btn">
 							<button id="rawtextbutton" type="button" class="hidden btn btn-default navbar-btn">
-								<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> <?php echo I18n::_('Raw text'); ?>
+								<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> <?php echo I18n::_('Raw text'), PHP_EOL; ?>
 							</button>
 							</button>
 						</li>
 						</li>
 						<li class="dropdown">
 						<li class="dropdown">
@@ -108,7 +108,7 @@ foreach ($EXPIRE as $key => $value):
 ?>
 ?>
 								<li>
 								<li>
 									<a href="#" data-expiration="<?php echo $key; ?>">
 									<a href="#" data-expiration="<?php echo $key; ?>">
-										<?php echo $value; ?>
+										<?php echo $value, PHP_EOL; ?>
 									</a>
 									</a>
 								</li>
 								</li>
 <?php
 <?php
@@ -121,12 +121,12 @@ endforeach;
 							<ul class="dropdown-menu">
 							<ul class="dropdown-menu">
 								<li id="burnafterreadingoption" class="checkbox hidden">
 								<li id="burnafterreadingoption" class="checkbox hidden">
 									<label>
 									<label>
-										<input type="checkbox" id="burnafterreading" name="burnafterreading" <?php
+										<input type="checkbox" id="burnafterreading" name="burnafterreading"<?php
 if ($BURNAFTERREADINGSELECTED):
 if ($BURNAFTERREADINGSELECTED):
 ?> checked="checked"<?php
 ?> checked="checked"<?php
 endif;
 endif;
 ?> />
 ?> />
-										<?php echo I18n::_('Burn after reading'); ?>
+										<?php echo I18n::_('Burn after reading'), PHP_EOL; ?>
 									</label>
 									</label>
 								</li>
 								</li>
 <?php
 <?php
@@ -134,12 +134,12 @@ if ($DISCUSSION):
 ?>
 ?>
 								<li id="opendisc" class="checkbox hidden">
 								<li id="opendisc" class="checkbox hidden">
 									<label>
 									<label>
-										<input type="checkbox" id="opendiscussion" name="opendiscussion" <?php
+										<input type="checkbox" id="opendiscussion" name="opendiscussion"<?php
     if ($OPENDISCUSSION):
     if ($OPENDISCUSSION):
 ?> checked="checked"<?php
 ?> checked="checked"<?php
     endif;
     endif;
 ?> />
 ?> />
-										<?php echo I18n::_('Open discussion'); ?>
+										<?php echo I18n::_('Open discussion'), PHP_EOL; ?>
 									</label>
 									</label>
 								</li>
 								</li>
 <?php
 <?php
@@ -156,7 +156,7 @@ foreach ($FORMATTER as $key => $value):
 ?>
 ?>
 								<li>
 								<li>
 									<a href="#" data-format="<?php echo $key; ?>">
 									<a href="#" data-format="<?php echo $key; ?>">
-										<?php echo $value; ?>
+										<?php echo $value, PHP_EOL; ?>
 									</a>
 									</a>
 								</li>
 								</li>
 <?php
 <?php
@@ -199,7 +199,7 @@ if ($FILEUPLOAD):
 								</li>
 								</li>
 								<li>
 								<li>
 									<a id="fileremovebutton"  href="#">
 									<a id="fileremovebutton"  href="#">
-										<?php echo I18n::_('Remove attachment'); ?>
+										<?php echo I18n::_('Remove attachment'), PHP_EOL; ?>
 									</a>
 									</a>
 								</li>
 								</li>
 							</ul>
 							</ul>
@@ -233,7 +233,7 @@ endif;
 ?>
 ?>
 						<li>
 						<li>
 							<button id="newbutton" type="button" class="reloadlink hidden btn btn-default navbar-btn">
 							<button id="newbutton" type="button" class="reloadlink hidden btn btn-default navbar-btn">
-								<span class="glyphicon glyphicon-file" aria-hidden="true"></span> <?php echo I18n::_('New'); ?>
+								<span class="glyphicon glyphicon-file" aria-hidden="true"></span> <?php echo I18n::_('New'), PHP_EOL; ?>
 							</button>
 							</button>
 						</li>
 						</li>
 					</ul>
 					</ul>
@@ -245,7 +245,7 @@ endif;
 if (strlen($NOTICE)):
 if (strlen($NOTICE)):
 ?>
 ?>
 			<div role="alert" class="alert alert-info">
 			<div role="alert" class="alert alert-info">
-				<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> <?php echo htmlspecialchars($NOTICE); ?>
+				<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> <?php echo htmlspecialchars($NOTICE), PHP_EOL; ?>
 			</div>
 			</div>
 <?php
 <?php
 endif;
 endif;
@@ -264,7 +264,7 @@ endif;
 if (strlen($STATUS)):
 if (strlen($STATUS)):
 ?>
 ?>
 			<div id="status" role="alert" class="alert alert-success">
 			<div id="status" role="alert" class="alert alert-success">
-				<span class="glyphicon glyphicon-ok" aria-hidden="true"></span> <?php echo htmlspecialchars($STATUS); ?>
+				<span class="glyphicon glyphicon-ok" aria-hidden="true"></span> <?php echo htmlspecialchars($STATUS), PHP_EOL; ?>
 			</div>
 			</div>
 <?php
 <?php
 endif;
 endif;
@@ -276,7 +276,7 @@ endif;
 ?>alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo htmlspecialchars($ERROR); ?></div>
 ?>alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo htmlspecialchars($ERROR); ?></div>
 			<noscript><div id="noscript" role="alert" class="nonworking alert alert-warning"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <?php echo I18n::_('Javascript is required for PrivateBin to work.<br />Sorry for the inconvenience.'); ?></div></noscript>
 			<noscript><div id="noscript" role="alert" class="nonworking alert alert-warning"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <?php echo I18n::_('Javascript is required for PrivateBin to work.<br />Sorry for the inconvenience.'); ?></div></noscript>
 			<div id="oldienotice" role="alert" class="hidden nonworking alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo I18n::_('PrivateBin requires a modern browser to work.'); ?></div>
 			<div id="oldienotice" role="alert" class="hidden nonworking alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo I18n::_('PrivateBin requires a modern browser to work.'); ?></div>
-			<div id="ienotice" role="alert" class="hidden alert alert-warning"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span> <?php echo I18n::_('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:'); ?>
+			<div id="ienotice" role="alert" class="hidden alert alert-warning"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span> <?php echo I18n::_('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:'), PHP_EOL; ?>
 				<a href="https://www.mozilla.org/firefox/">Firefox</a>,
 				<a href="https://www.mozilla.org/firefox/">Firefox</a>,
 				<a href="https://www.opera.com/">Opera</a>,
 				<a href="https://www.opera.com/">Opera</a>,
 				<a href="https://www.google.com/chrome">Chrome</a>,
 				<a href="https://www.google.com/chrome">Chrome</a>,
@@ -290,7 +290,7 @@ endif;
 if (strlen($URLSHORTENER)):
 if (strlen($URLSHORTENER)):
 ?>
 ?>
 					<button id="shortenbutton" data-shortener="<?php echo htmlspecialchars($URLSHORTENER); ?>" type="button" class="btn btn-primary">
 					<button id="shortenbutton" data-shortener="<?php echo htmlspecialchars($URLSHORTENER); ?>" type="button" class="btn btn-primary">
-						<span class="glyphicon glyphicon-send" aria-hidden="true"></span> <?php echo I18n::_('Shorten URL'); ?>
+						<span class="glyphicon glyphicon-send" aria-hidden="true"></span> <?php echo I18n::_('Shorten URL'), PHP_EOL; ?>
 					</button>
 					</button>
 <?php
 <?php
 endif;
 endif;
@@ -323,7 +323,7 @@ endif;
 				<h4 class="col-md-5 col-xs-8"><?php echo I18n::_('PrivateBin'); ?> <small>- <?php echo I18n::_('Because ignorance is bliss'); ?></small></h4>
 				<h4 class="col-md-5 col-xs-8"><?php echo I18n::_('PrivateBin'); ?> <small>- <?php echo I18n::_('Because ignorance is bliss'); ?></small></h4>
 				<p class="col-md-1 col-xs-4 text-center"><?php echo $VERSION; ?></p>
 				<p class="col-md-1 col-xs-4 text-center"><?php echo $VERSION; ?></p>
 				<p id="aboutbox" class="col-md-6 col-xs-12">
 				<p id="aboutbox" class="col-md-6 col-xs-12">
-					<?php echo I18n::_('PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted <i>in the browser</i> using 256 bits AES. More information on the <a href="https://github.com/PrivateBin/PrivateBin/wiki">project page</a>.'); ?>
+					<?php echo I18n::_('PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted <i>in the browser</i> using 256 bits AES. More information on the <a href="https://github.com/PrivateBin/PrivateBin/wiki">project page</a>.'), PHP_EOL; ?>
 				</p>
 				</p>
 			</div>
 			</div>
 		</footer>
 		</footer>

+ 16 - 16
tpl/bootstrap-dark-page.php

@@ -71,19 +71,19 @@ endif;
 				<ul class="nav navbar-nav">
 				<ul class="nav navbar-nav">
 					<li>
 					<li>
 						<button id="sendbutton" type="button" class="hidden btn btn-warning navbar-btn">
 						<button id="sendbutton" type="button" class="hidden btn btn-warning navbar-btn">
-							<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Send'); ?>
+							<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Send'), PHP_EOL; ?>
 						</button>
 						</button>
 <?php
 <?php
 if ($EXPIRECLONE):
 if ($EXPIRECLONE):
 ?>
 ?>
 						<button id="clonebutton" type="button" class="hidden btn btn-warning navbar-btn">
 						<button id="clonebutton" type="button" class="hidden btn btn-warning navbar-btn">
-							<span class="glyphicon glyphicon-duplicate" aria-hidden="true"></span> <?php echo I18n::_('Clone'); ?>
+							<span class="glyphicon glyphicon-duplicate" aria-hidden="true"></span> <?php echo I18n::_('Clone'), PHP_EOL; ?>
 						</button>
 						</button>
 <?php
 <?php
 endif;
 endif;
 ?>
 ?>
 						<button id="rawtextbutton" type="button" class="hidden btn btn-warning navbar-btn">
 						<button id="rawtextbutton" type="button" class="hidden btn btn-warning navbar-btn">
-							<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> <?php echo I18n::_('Raw text'); ?>
+							<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> <?php echo I18n::_('Raw text'), PHP_EOL; ?>
 						</button>
 						</button>
 					</li>
 					</li>
 					<li class="dropdown">
 					<li class="dropdown">
@@ -107,7 +107,7 @@ foreach ($EXPIRE as $key => $value):
 ?>
 ?>
 							<li>
 							<li>
 								<a href="#" data-expiration="<?php echo $key; ?>">
 								<a href="#" data-expiration="<?php echo $key; ?>">
-									<?php echo $value; ?>
+									<?php echo $value, PHP_EOL; ?>
 								</a>
 								</a>
 							</li>
 							</li>
 <?php
 <?php
@@ -118,12 +118,12 @@ endforeach;
 					<li>
 					<li>
 						<div id="burnafterreadingoption" class="navbar-text checkbox hidden">
 						<div id="burnafterreadingoption" class="navbar-text checkbox hidden">
 							<label>
 							<label>
-								<input type="checkbox" id="burnafterreading" name="burnafterreading" <?php
+								<input type="checkbox" id="burnafterreading" name="burnafterreading"<?php
 if ($BURNAFTERREADINGSELECTED):
 if ($BURNAFTERREADINGSELECTED):
 ?> checked="checked"<?php
 ?> checked="checked"<?php
 endif;
 endif;
 ?> />
 ?> />
-								<?php echo I18n::_('Burn after reading'); ?>
+								<?php echo I18n::_('Burn after reading'), PHP_EOL; ?>
 							</label>
 							</label>
 						</div>
 						</div>
 					</li>
 					</li>
@@ -133,12 +133,12 @@ if ($DISCUSSION):
 					<li>
 					<li>
 						<div id="opendisc" class="navbar-text checkbox hidden">
 						<div id="opendisc" class="navbar-text checkbox hidden">
 							<label>
 							<label>
-								<input type="checkbox" id="opendiscussion" name="opendiscussion" <?php
+								<input type="checkbox" id="opendiscussion" name="opendiscussion"<?php
     if ($OPENDISCUSSION):
     if ($OPENDISCUSSION):
 ?> checked="checked"<?php
 ?> checked="checked"<?php
     endif;
     endif;
 ?> />
 ?> />
-								<?php echo I18n::_('Open discussion'); ?>
+								<?php echo I18n::_('Open discussion'), PHP_EOL; ?>
 						 	</label>
 						 	</label>
 						</div>
 						</div>
 					</li>
 					</li>
@@ -165,7 +165,7 @@ if ($FILEUPLOAD):
 							</li>
 							</li>
 							<li>
 							<li>
 								<a id="fileremovebutton"  href="#">
 								<a id="fileremovebutton"  href="#">
-									<?php echo I18n::_('Remove attachment'); ?>
+									<?php echo I18n::_('Remove attachment'), PHP_EOL; ?>
 								</a>
 								</a>
 							</li>
 							</li>
 						</ul>
 						</ul>
@@ -194,7 +194,7 @@ foreach ($FORMATTER as $key => $value):
 ?>
 ?>
 							<li>
 							<li>
 								<a href="#" data-format="<?php echo $key; ?>">
 								<a href="#" data-format="<?php echo $key; ?>">
-									<?php echo $value; ?>
+									<?php echo $value, PHP_EOL; ?>
 								</a>
 								</a>
 							</li>
 							</li>
 <?php
 <?php
@@ -228,7 +228,7 @@ endif;
 ?>
 ?>
 					<li>
 					<li>
 						<button id="newbutton" type="button" class="reloadlink hidden btn btn-warning navbar-btn">
 						<button id="newbutton" type="button" class="reloadlink hidden btn btn-warning navbar-btn">
-							<span class="glyphicon glyphicon-file" aria-hidden="true"></span> <?php echo I18n::_('New'); ?>
+							<span class="glyphicon glyphicon-file" aria-hidden="true"></span> <?php echo I18n::_('New'), PHP_EOL; ?>
 						</button>
 						</button>
 					</li>
 					</li>
 				</ul>
 				</ul>
@@ -239,7 +239,7 @@ endif;
 if (strlen($NOTICE)):
 if (strlen($NOTICE)):
 ?>
 ?>
 			<div role="alert" class="alert alert-info">
 			<div role="alert" class="alert alert-info">
-				<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> <?php echo htmlspecialchars($NOTICE); ?>
+				<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> <?php echo htmlspecialchars($NOTICE), PHP_EOL; ?>
 			</div>
 			</div>
 <?php
 <?php
 endif;
 endif;
@@ -258,7 +258,7 @@ endif;
 if (strlen($STATUS)):
 if (strlen($STATUS)):
 ?>
 ?>
 			<div id="status" role="alert" class="alert alert-success">
 			<div id="status" role="alert" class="alert alert-success">
-				<span class="glyphicon glyphicon-ok" aria-hidden="true"></span> <?php echo htmlspecialchars($STATUS); ?>
+				<span class="glyphicon glyphicon-ok" aria-hidden="true"></span> <?php echo htmlspecialchars($STATUS), PHP_EOL; ?>
 			</div>
 			</div>
 <?php
 <?php
 endif;
 endif;
@@ -270,7 +270,7 @@ endif;
 ?>alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo htmlspecialchars($ERROR); ?></div>
 ?>alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo htmlspecialchars($ERROR); ?></div>
 			<noscript><div id="noscript" role="alert" class="nonworking alert alert-error"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <?php echo I18n::_('Javascript is required for PrivateBin to work.<br />Sorry for the inconvenience.'); ?></div></noscript>
 			<noscript><div id="noscript" role="alert" class="nonworking alert alert-error"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <?php echo I18n::_('Javascript is required for PrivateBin to work.<br />Sorry for the inconvenience.'); ?></div></noscript>
 			<div id="oldienotice" role="alert" class="hidden nonworking alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo I18n::_('PrivateBin requires a modern browser to work.'); ?></div>
 			<div id="oldienotice" role="alert" class="hidden nonworking alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo I18n::_('PrivateBin requires a modern browser to work.'); ?></div>
-			<div id="ienotice" role="alert" class="hidden alert alert-error"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span> <?php echo I18n::_('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:'); ?>
+			<div id="ienotice" role="alert" class="hidden alert alert-error"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span> <?php echo I18n::_('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:'), PHP_EOL; ?>
 				<a href="https://www.mozilla.org/firefox/">Firefox</a>,
 				<a href="https://www.mozilla.org/firefox/">Firefox</a>,
 				<a href="https://www.opera.com/">Opera</a>,
 				<a href="https://www.opera.com/">Opera</a>,
 				<a href="https://www.google.com/chrome">Chrome</a>,
 				<a href="https://www.google.com/chrome">Chrome</a>,
@@ -284,7 +284,7 @@ endif;
 if (strlen($URLSHORTENER)):
 if (strlen($URLSHORTENER)):
 ?>
 ?>
 					<button id="shortenbutton" data-shortener="<?php echo htmlspecialchars($URLSHORTENER); ?>" type="button" class="btn btn-warning">
 					<button id="shortenbutton" data-shortener="<?php echo htmlspecialchars($URLSHORTENER); ?>" type="button" class="btn btn-warning">
-						<span class="glyphicon glyphicon-send" aria-hidden="true"></span> <?php echo I18n::_('Shorten URL'); ?>
+						<span class="glyphicon glyphicon-send" aria-hidden="true"></span> <?php echo I18n::_('Shorten URL'), PHP_EOL; ?>
 					</button>
 					</button>
 <?php
 <?php
 endif;
 endif;
@@ -317,7 +317,7 @@ endif;
 				<h4 class="col-md-5 col-xs-8"><?php echo I18n::_('PrivateBin'); ?> <small>- <?php echo I18n::_('Because ignorance is bliss'); ?></small></h4>
 				<h4 class="col-md-5 col-xs-8"><?php echo I18n::_('PrivateBin'); ?> <small>- <?php echo I18n::_('Because ignorance is bliss'); ?></small></h4>
 				<p class="col-md-1 col-xs-4 text-center"><?php echo $VERSION; ?></p>
 				<p class="col-md-1 col-xs-4 text-center"><?php echo $VERSION; ?></p>
 				<p id="aboutbox" class="col-md-6 col-xs-12">
 				<p id="aboutbox" class="col-md-6 col-xs-12">
-					<?php echo I18n::_('PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted <i>in the browser</i> using 256 bits AES. More information on the <a href="https://github.com/PrivateBin/PrivateBin/wiki">project page</a>.'); ?>
+					<?php echo I18n::_('PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted <i>in the browser</i> using 256 bits AES. More information on the <a href="https://github.com/PrivateBin/PrivateBin/wiki">project page</a>.'), PHP_EOL; ?>
 				</p>
 				</p>
 			</div>
 			</div>
 		</footer>
 		</footer>

+ 18 - 18
tpl/bootstrap-dark.php

@@ -71,19 +71,19 @@ endif;
 				<ul class="nav navbar-nav">
 				<ul class="nav navbar-nav">
 					<li>
 					<li>
 						<button id="newbutton" type="button" class="reloadlink hidden btn btn-warning navbar-btn">
 						<button id="newbutton" type="button" class="reloadlink hidden btn btn-warning navbar-btn">
-							<span class="glyphicon glyphicon-file" aria-hidden="true"></span> <?php echo I18n::_('New'); ?>
+							<span class="glyphicon glyphicon-file" aria-hidden="true"></span> <?php echo I18n::_('New'), PHP_EOL; ?>
 						</button>
 						</button>
 <?php
 <?php
 if ($EXPIRECLONE):
 if ($EXPIRECLONE):
 ?>
 ?>
 						<button id="clonebutton" type="button" class="hidden btn btn-warning navbar-btn">
 						<button id="clonebutton" type="button" class="hidden btn btn-warning navbar-btn">
-							<span class="glyphicon glyphicon-duplicate" aria-hidden="true"></span> <?php echo I18n::_('Clone'); ?>
+							<span class="glyphicon glyphicon-duplicate" aria-hidden="true"></span> <?php echo I18n::_('Clone'), PHP_EOL; ?>
 						</button>
 						</button>
 <?php
 <?php
 endif;
 endif;
 ?>
 ?>
 						<button id="rawtextbutton" type="button" class="hidden btn btn-warning navbar-btn">
 						<button id="rawtextbutton" type="button" class="hidden btn btn-warning navbar-btn">
-							<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> <?php echo I18n::_('Raw text'); ?>
+							<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> <?php echo I18n::_('Raw text'), PHP_EOL; ?>
 						</button>
 						</button>
 					</li>
 					</li>
 					<li class="dropdown">
 					<li class="dropdown">
@@ -107,7 +107,7 @@ foreach ($EXPIRE as $key => $value):
 ?>
 ?>
 							<li>
 							<li>
 								<a href="#" data-expiration="<?php echo $key; ?>">
 								<a href="#" data-expiration="<?php echo $key; ?>">
-									<?php echo $value; ?>
+									<?php echo $value, PHP_EOL; ?>
 								</a>
 								</a>
 							</li>
 							</li>
 <?php
 <?php
@@ -118,12 +118,12 @@ endforeach;
 					<li>
 					<li>
 						<div id="burnafterreadingoption" class="navbar-text checkbox hidden">
 						<div id="burnafterreadingoption" class="navbar-text checkbox hidden">
 							<label>
 							<label>
-								<input type="checkbox" id="burnafterreading" name="burnafterreading" <?php
+								<input type="checkbox" id="burnafterreading" name="burnafterreading"<?php
 if ($BURNAFTERREADINGSELECTED):
 if ($BURNAFTERREADINGSELECTED):
-?> checked="checked"<?php
+?> checked<?php
 endif;
 endif;
 ?> />
 ?> />
-								<?php echo I18n::_('Burn after reading'); ?>
+								<?php echo I18n::_('Burn after reading'), PHP_EOL; ?>
 							</label>
 							</label>
 						</div>
 						</div>
 					</li>
 					</li>
@@ -133,12 +133,12 @@ if ($DISCUSSION):
 					<li>
 					<li>
 						<div id="opendisc" class="navbar-text checkbox hidden">
 						<div id="opendisc" class="navbar-text checkbox hidden">
 							<label>
 							<label>
-								<input type="checkbox" id="opendiscussion" name="opendiscussion" <?php
+								<input type="checkbox" id="opendiscussion" name="opendiscussion"<?php
     if ($OPENDISCUSSION):
     if ($OPENDISCUSSION):
-?> checked="checked"<?php
+?> checked<?php
     endif;
     endif;
 ?> />
 ?> />
-								<?php echo I18n::_('Open discussion'); ?>
+								<?php echo I18n::_('Open discussion'), PHP_EOL; ?>
 						 	</label>
 						 	</label>
 						</div>
 						</div>
 					</li>
 					</li>
@@ -165,7 +165,7 @@ if ($FILEUPLOAD):
 							</li>
 							</li>
 							<li>
 							<li>
 								<a id="fileremovebutton"  href="#">
 								<a id="fileremovebutton"  href="#">
-									<?php echo I18n::_('Remove attachment'); ?>
+									<?php echo I18n::_('Remove attachment'), PHP_EOL; ?>
 								</a>
 								</a>
 							</li>
 							</li>
 						</ul>
 						</ul>
@@ -194,7 +194,7 @@ foreach ($FORMATTER as $key => $value):
 ?>
 ?>
 							<li>
 							<li>
 								<a href="#" data-format="<?php echo $key; ?>">
 								<a href="#" data-format="<?php echo $key; ?>">
-									<?php echo $value; ?>
+									<?php echo $value, PHP_EOL; ?>
 								</a>
 								</a>
 							</li>
 							</li>
 <?php
 <?php
@@ -228,7 +228,7 @@ endif;
 ?>
 ?>
 					<li>
 					<li>
 						<button id="sendbutton" type="button" class="hidden btn btn-warning navbar-btn">
 						<button id="sendbutton" type="button" class="hidden btn btn-warning navbar-btn">
-							<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Send'); ?>
+							<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Send'), PHP_EOL; ?>
 						</button>
 						</button>
 					</li>
 					</li>
 				</ul>
 				</ul>
@@ -239,7 +239,7 @@ endif;
 if (strlen($NOTICE)):
 if (strlen($NOTICE)):
 ?>
 ?>
 			<div role="alert" class="alert alert-info">
 			<div role="alert" class="alert alert-info">
-				<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> <?php echo htmlspecialchars($NOTICE); ?>
+				<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> <?php echo htmlspecialchars($NOTICE), PHP_EOL; ?>
 			</div>
 			</div>
 <?php
 <?php
 endif;
 endif;
@@ -258,7 +258,7 @@ endif;
 if (strlen($STATUS)):
 if (strlen($STATUS)):
 ?>
 ?>
 			<div id="status" role="alert" class="alert alert-success">
 			<div id="status" role="alert" class="alert alert-success">
-				<span class="glyphicon glyphicon-ok" aria-hidden="true"></span> <?php echo htmlspecialchars($STATUS); ?>
+				<span class="glyphicon glyphicon-ok" aria-hidden="true"></span> <?php echo htmlspecialchars($STATUS), PHP_EOL; ?>
 			</div>
 			</div>
 <?php
 <?php
 endif;
 endif;
@@ -270,7 +270,7 @@ endif;
 ?>alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo htmlspecialchars($ERROR); ?></div>
 ?>alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo htmlspecialchars($ERROR); ?></div>
 			<noscript><div id="noscript" role="alert" class="nonworking alert alert-error"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <?php echo I18n::_('Javascript is required for PrivateBin to work.<br />Sorry for the inconvenience.'); ?></div></noscript>
 			<noscript><div id="noscript" role="alert" class="nonworking alert alert-error"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <?php echo I18n::_('Javascript is required for PrivateBin to work.<br />Sorry for the inconvenience.'); ?></div></noscript>
 			<div id="oldienotice" role="alert" class="hidden nonworking alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo I18n::_('PrivateBin requires a modern browser to work.'); ?></div>
 			<div id="oldienotice" role="alert" class="hidden nonworking alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo I18n::_('PrivateBin requires a modern browser to work.'); ?></div>
-			<div id="ienotice" role="alert" class="hidden alert alert-error"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span> <?php echo I18n::_('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:'); ?>
+			<div id="ienotice" role="alert" class="hidden alert alert-error"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span> <?php echo I18n::_('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:'), PHP_EOL; ?>
 				<a href="https://www.mozilla.org/firefox/">Firefox</a>,
 				<a href="https://www.mozilla.org/firefox/">Firefox</a>,
 				<a href="https://www.opera.com/">Opera</a>,
 				<a href="https://www.opera.com/">Opera</a>,
 				<a href="https://www.google.com/chrome">Chrome</a>,
 				<a href="https://www.google.com/chrome">Chrome</a>,
@@ -284,7 +284,7 @@ endif;
 if (strlen($URLSHORTENER)):
 if (strlen($URLSHORTENER)):
 ?>
 ?>
 					<button id="shortenbutton" data-shortener="<?php echo htmlspecialchars($URLSHORTENER); ?>" type="button" class="btn btn-warning">
 					<button id="shortenbutton" data-shortener="<?php echo htmlspecialchars($URLSHORTENER); ?>" type="button" class="btn btn-warning">
-						<span class="glyphicon glyphicon-send" aria-hidden="true"></span> <?php echo I18n::_('Shorten URL'); ?>
+						<span class="glyphicon glyphicon-send" aria-hidden="true"></span> <?php echo I18n::_('Shorten URL'), PHP_EOL; ?>
 					</button>
 					</button>
 <?php
 <?php
 endif;
 endif;
@@ -317,7 +317,7 @@ endif;
 				<h4 class="col-md-5 col-xs-8"><?php echo I18n::_('PrivateBin'); ?> <small>- <?php echo I18n::_('Because ignorance is bliss'); ?></small></h4>
 				<h4 class="col-md-5 col-xs-8"><?php echo I18n::_('PrivateBin'); ?> <small>- <?php echo I18n::_('Because ignorance is bliss'); ?></small></h4>
 				<p class="col-md-1 col-xs-4 text-center"><?php echo $VERSION; ?></p>
 				<p class="col-md-1 col-xs-4 text-center"><?php echo $VERSION; ?></p>
 				<p id="aboutbox" class="col-md-6 col-xs-12">
 				<p id="aboutbox" class="col-md-6 col-xs-12">
-					<?php echo I18n::_('PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted <i>in the browser</i> using 256 bits AES. More information on the <a href="https://github.com/PrivateBin/PrivateBin/wiki">project page</a>.'); ?>
+					<?php echo I18n::_('PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted <i>in the browser</i> using 256 bits AES. More information on the <a href="https://github.com/PrivateBin/PrivateBin/wiki">project page</a>.'), PHP_EOL; ?>
 				</p>
 				</p>
 			</div>
 			</div>
 		</footer>
 		</footer>

+ 16 - 16
tpl/bootstrap-page.php

@@ -71,19 +71,19 @@ endif;
 				<ul class="nav navbar-nav">
 				<ul class="nav navbar-nav">
 					<li>
 					<li>
 						<button id="sendbutton" type="button" class="hidden btn btn-primary navbar-btn">
 						<button id="sendbutton" type="button" class="hidden btn btn-primary navbar-btn">
-							<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Send'); ?>
+							<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Send'), PHP_EOL; ?>
 						</button>
 						</button>
 <?php
 <?php
 if ($EXPIRECLONE):
 if ($EXPIRECLONE):
 ?>
 ?>
 						<button id="clonebutton" type="button" class="hidden btn btn-default navbar-btn">
 						<button id="clonebutton" type="button" class="hidden btn btn-default navbar-btn">
-							<span class="glyphicon glyphicon-duplicate" aria-hidden="true"></span> <?php echo I18n::_('Clone'); ?>
+							<span class="glyphicon glyphicon-duplicate" aria-hidden="true"></span> <?php echo I18n::_('Clone'), PHP_EOL; ?>
 						</button>
 						</button>
 <?php
 <?php
 endif;
 endif;
 ?>
 ?>
 						<button id="rawtextbutton" type="button" class="hidden btn btn-default navbar-btn">
 						<button id="rawtextbutton" type="button" class="hidden btn btn-default navbar-btn">
-							<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> <?php echo I18n::_('Raw text'); ?>
+							<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> <?php echo I18n::_('Raw text'), PHP_EOL; ?>
 						</button>
 						</button>
 					</li>
 					</li>
 					<li class="dropdown">
 					<li class="dropdown">
@@ -107,7 +107,7 @@ foreach ($EXPIRE as $key => $value):
 ?>
 ?>
 							<li>
 							<li>
 								<a href="#" data-expiration="<?php echo $key; ?>">
 								<a href="#" data-expiration="<?php echo $key; ?>">
-									<?php echo $value; ?>
+									<?php echo $value, PHP_EOL; ?>
 								</a>
 								</a>
 							</li>
 							</li>
 <?php
 <?php
@@ -118,12 +118,12 @@ endforeach;
 					<li>
 					<li>
 						<div id="burnafterreadingoption" class="navbar-text checkbox hidden">
 						<div id="burnafterreadingoption" class="navbar-text checkbox hidden">
 							<label>
 							<label>
-								<input type="checkbox" id="burnafterreading" name="burnafterreading" <?php
+								<input type="checkbox" id="burnafterreading" name="burnafterreading"<?php
 if ($BURNAFTERREADINGSELECTED):
 if ($BURNAFTERREADINGSELECTED):
 ?> checked="checked"<?php
 ?> checked="checked"<?php
 endif;
 endif;
 ?> />
 ?> />
-								<?php echo I18n::_('Burn after reading'); ?>
+								<?php echo I18n::_('Burn after reading'), PHP_EOL; ?>
 							</label>
 							</label>
 						</div>
 						</div>
 					</li>
 					</li>
@@ -133,12 +133,12 @@ if ($DISCUSSION):
 					<li>
 					<li>
 						<div id="opendisc" class="navbar-text checkbox hidden">
 						<div id="opendisc" class="navbar-text checkbox hidden">
 							<label>
 							<label>
-								<input type="checkbox" id="opendiscussion" name="opendiscussion" <?php
+								<input type="checkbox" id="opendiscussion" name="opendiscussion"<?php
     if ($OPENDISCUSSION):
     if ($OPENDISCUSSION):
 ?> checked="checked"<?php
 ?> checked="checked"<?php
     endif;
     endif;
 ?> />
 ?> />
-								<?php echo I18n::_('Open discussion'); ?>
+								<?php echo I18n::_('Open discussion'), PHP_EOL; ?>
 						 	</label>
 						 	</label>
 						</div>
 						</div>
 					</li>
 					</li>
@@ -165,7 +165,7 @@ if ($FILEUPLOAD):
 							</li>
 							</li>
 							<li>
 							<li>
 								<a id="fileremovebutton"  href="#">
 								<a id="fileremovebutton"  href="#">
-									<?php echo I18n::_('Remove attachment'); ?>
+									<?php echo I18n::_('Remove attachment'), PHP_EOL; ?>
 								</a>
 								</a>
 							</li>
 							</li>
 						</ul>
 						</ul>
@@ -194,7 +194,7 @@ foreach ($FORMATTER as $key => $value):
 ?>
 ?>
 							<li>
 							<li>
 								<a href="#" data-format="<?php echo $key; ?>">
 								<a href="#" data-format="<?php echo $key; ?>">
-									<?php echo $value; ?>
+									<?php echo $value, PHP_EOL; ?>
 								</a>
 								</a>
 							</li>
 							</li>
 <?php
 <?php
@@ -228,7 +228,7 @@ endif;
 ?>
 ?>
 					<li>
 					<li>
 						<button id="newbutton" type="button" class="reloadlink hidden btn btn-default navbar-btn">
 						<button id="newbutton" type="button" class="reloadlink hidden btn btn-default navbar-btn">
-							<span class="glyphicon glyphicon-file" aria-hidden="true"></span> <?php echo I18n::_('New'); ?>
+							<span class="glyphicon glyphicon-file" aria-hidden="true"></span> <?php echo I18n::_('New'), PHP_EOL; ?>
 						</button>
 						</button>
 					</li>
 					</li>
 				</ul>
 				</ul>
@@ -239,7 +239,7 @@ endif;
 if (strlen($NOTICE)):
 if (strlen($NOTICE)):
 ?>
 ?>
 			<div role="alert" class="alert alert-info">
 			<div role="alert" class="alert alert-info">
-				<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> <?php echo htmlspecialchars($NOTICE); ?>
+				<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> <?php echo htmlspecialchars($NOTICE), PHP_EOL; ?>
 			</div>
 			</div>
 <?php
 <?php
 endif;
 endif;
@@ -258,7 +258,7 @@ endif;
 if (strlen($STATUS)):
 if (strlen($STATUS)):
 ?>
 ?>
 			<div id="status" role="alert" class="alert alert-success">
 			<div id="status" role="alert" class="alert alert-success">
-				<span class="glyphicon glyphicon-ok" aria-hidden="true"></span> <?php echo htmlspecialchars($STATUS); ?>
+				<span class="glyphicon glyphicon-ok" aria-hidden="true"></span> <?php echo htmlspecialchars($STATUS), PHP_EOL; ?>
 			</div>
 			</div>
 <?php
 <?php
 endif;
 endif;
@@ -270,7 +270,7 @@ endif;
 ?>alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo htmlspecialchars($ERROR); ?></div>
 ?>alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo htmlspecialchars($ERROR); ?></div>
 			<noscript><div id="noscript" role="alert" class="nonworking alert alert-warning"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <?php echo I18n::_('Javascript is required for PrivateBin to work.<br />Sorry for the inconvenience.'); ?></div></noscript>
 			<noscript><div id="noscript" role="alert" class="nonworking alert alert-warning"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <?php echo I18n::_('Javascript is required for PrivateBin to work.<br />Sorry for the inconvenience.'); ?></div></noscript>
 			<div id="oldienotice" role="alert" class="hidden nonworking alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo I18n::_('PrivateBin requires a modern browser to work.'); ?></div>
 			<div id="oldienotice" role="alert" class="hidden nonworking alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo I18n::_('PrivateBin requires a modern browser to work.'); ?></div>
-			<div id="ienotice" role="alert" class="hidden alert alert-warning"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span> <?php echo I18n::_('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:'); ?>
+			<div id="ienotice" role="alert" class="hidden alert alert-warning"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span> <?php echo I18n::_('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:'), PHP_EOL; ?>
 				<a href="https://www.mozilla.org/firefox/">Firefox</a>,
 				<a href="https://www.mozilla.org/firefox/">Firefox</a>,
 				<a href="https://www.opera.com/">Opera</a>,
 				<a href="https://www.opera.com/">Opera</a>,
 				<a href="https://www.google.com/chrome">Chrome</a>,
 				<a href="https://www.google.com/chrome">Chrome</a>,
@@ -284,7 +284,7 @@ endif;
 if (strlen($URLSHORTENER)):
 if (strlen($URLSHORTENER)):
 ?>
 ?>
 					<button id="shortenbutton" data-shortener="<?php echo htmlspecialchars($URLSHORTENER); ?>" type="button" class="btn btn-primary">
 					<button id="shortenbutton" data-shortener="<?php echo htmlspecialchars($URLSHORTENER); ?>" type="button" class="btn btn-primary">
-						<span class="glyphicon glyphicon-send" aria-hidden="true"></span> <?php echo I18n::_('Shorten URL'); ?>
+						<span class="glyphicon glyphicon-send" aria-hidden="true"></span> <?php echo I18n::_('Shorten URL'), PHP_EOL; ?>
 					</button>
 					</button>
 <?php
 <?php
 endif;
 endif;
@@ -317,7 +317,7 @@ endif;
 				<h4 class="col-md-5 col-xs-8"><?php echo I18n::_('PrivateBin'); ?> <small>- <?php echo I18n::_('Because ignorance is bliss'); ?></small></h4>
 				<h4 class="col-md-5 col-xs-8"><?php echo I18n::_('PrivateBin'); ?> <small>- <?php echo I18n::_('Because ignorance is bliss'); ?></small></h4>
 				<p class="col-md-1 col-xs-4 text-center"><?php echo $VERSION; ?></p>
 				<p class="col-md-1 col-xs-4 text-center"><?php echo $VERSION; ?></p>
 				<p id="aboutbox" class="col-md-6 col-xs-12">
 				<p id="aboutbox" class="col-md-6 col-xs-12">
-					<?php echo I18n::_('PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted <i>in the browser</i> using 256 bits AES. More information on the <a href="https://github.com/PrivateBin/PrivateBin/wiki">project page</a>.'); ?>
+					<?php echo I18n::_('PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted <i>in the browser</i> using 256 bits AES. More information on the <a href="https://github.com/PrivateBin/PrivateBin/wiki">project page</a>.'), PHP_EOL; ?>
 				</p>
 				</p>
 			</div>
 			</div>
 		</footer>
 		</footer>

+ 16 - 16
tpl/bootstrap.php

@@ -71,19 +71,19 @@ endif;
 				<ul class="nav navbar-nav">
 				<ul class="nav navbar-nav">
 					<li>
 					<li>
 						<button id="newbutton" type="button" class="reloadlink hidden btn btn-default navbar-btn">
 						<button id="newbutton" type="button" class="reloadlink hidden btn btn-default navbar-btn">
-							<span class="glyphicon glyphicon-file" aria-hidden="true"></span> <?php echo I18n::_('New'); ?>
+							<span class="glyphicon glyphicon-file" aria-hidden="true"></span> <?php echo I18n::_('New'), PHP_EOL; ?>
 						</button>
 						</button>
 <?php
 <?php
 if ($EXPIRECLONE):
 if ($EXPIRECLONE):
 ?>
 ?>
 						<button id="clonebutton" type="button" class="hidden btn btn-default navbar-btn">
 						<button id="clonebutton" type="button" class="hidden btn btn-default navbar-btn">
-							<span class="glyphicon glyphicon-duplicate" aria-hidden="true"></span> <?php echo I18n::_('Clone'); ?>
+							<span class="glyphicon glyphicon-duplicate" aria-hidden="true"></span> <?php echo I18n::_('Clone'), PHP_EOL; ?>
 						</button>
 						</button>
 <?php
 <?php
 endif;
 endif;
 ?>
 ?>
 						<button id="rawtextbutton" type="button" class="hidden btn btn-default navbar-btn">
 						<button id="rawtextbutton" type="button" class="hidden btn btn-default navbar-btn">
-							<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> <?php echo I18n::_('Raw text'); ?>
+							<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> <?php echo I18n::_('Raw text'), PHP_EOL; ?>
 						</button>
 						</button>
 					</li>
 					</li>
 					<li class="dropdown">
 					<li class="dropdown">
@@ -107,7 +107,7 @@ foreach ($EXPIRE as $key => $value):
 ?>
 ?>
 							<li>
 							<li>
 								<a href="#" data-expiration="<?php echo $key; ?>">
 								<a href="#" data-expiration="<?php echo $key; ?>">
-									<?php echo $value; ?>
+									<?php echo $value, PHP_EOL; ?>
 								</a>
 								</a>
 							</li>
 							</li>
 <?php
 <?php
@@ -118,12 +118,12 @@ endforeach;
 					<li>
 					<li>
 						<div id="burnafterreadingoption" class="navbar-text checkbox hidden">
 						<div id="burnafterreadingoption" class="navbar-text checkbox hidden">
 							<label>
 							<label>
-								<input type="checkbox" id="burnafterreading" name="burnafterreading" <?php
+								<input type="checkbox" id="burnafterreading" name="burnafterreading"<?php
 if ($BURNAFTERREADINGSELECTED):
 if ($BURNAFTERREADINGSELECTED):
 ?> checked="checked"<?php
 ?> checked="checked"<?php
 endif;
 endif;
 ?> />
 ?> />
-								<?php echo I18n::_('Burn after reading'); ?>
+								<?php echo I18n::_('Burn after reading'), PHP_EOL; ?>
 							</label>
 							</label>
 						</div>
 						</div>
 					</li>
 					</li>
@@ -133,12 +133,12 @@ if ($DISCUSSION):
 					<li>
 					<li>
 						<div id="opendisc" class="navbar-text checkbox hidden">
 						<div id="opendisc" class="navbar-text checkbox hidden">
 							<label>
 							<label>
-								<input type="checkbox" id="opendiscussion" name="opendiscussion" <?php
+								<input type="checkbox" id="opendiscussion" name="opendiscussion"<?php
     if ($OPENDISCUSSION):
     if ($OPENDISCUSSION):
 ?> checked="checked"<?php
 ?> checked="checked"<?php
     endif;
     endif;
 ?> />
 ?> />
-								<?php echo I18n::_('Open discussion'); ?>
+								<?php echo I18n::_('Open discussion'), PHP_EOL; ?>
 						 	</label>
 						 	</label>
 						</div>
 						</div>
 					</li>
 					</li>
@@ -165,7 +165,7 @@ if ($FILEUPLOAD):
 							</li>
 							</li>
 							<li>
 							<li>
 								<a id="fileremovebutton"  href="#">
 								<a id="fileremovebutton"  href="#">
-									<?php echo I18n::_('Remove attachment'); ?>
+									<?php echo I18n::_('Remove attachment'), PHP_EOL; ?>
 								</a>
 								</a>
 							</li>
 							</li>
 						</ul>
 						</ul>
@@ -194,7 +194,7 @@ foreach ($FORMATTER as $key => $value):
 ?>
 ?>
 							<li>
 							<li>
 								<a href="#" data-format="<?php echo $key; ?>">
 								<a href="#" data-format="<?php echo $key; ?>">
-									<?php echo $value; ?>
+									<?php echo $value, PHP_EOL; ?>
 								</a>
 								</a>
 							</li>
 							</li>
 <?php
 <?php
@@ -228,7 +228,7 @@ endif;
 ?>
 ?>
 					<li>
 					<li>
 						<button id="sendbutton" type="button" class="hidden btn btn-primary navbar-btn">
 						<button id="sendbutton" type="button" class="hidden btn btn-primary navbar-btn">
-							<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Send'); ?>
+							<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Send'), PHP_EOL; ?>
 						</button>
 						</button>
 					</li>
 					</li>
 				</ul>
 				</ul>
@@ -239,7 +239,7 @@ endif;
 if (strlen($NOTICE)):
 if (strlen($NOTICE)):
 ?>
 ?>
 			<div role="alert" class="alert alert-info">
 			<div role="alert" class="alert alert-info">
-				<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> <?php echo htmlspecialchars($NOTICE); ?>
+				<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> <?php echo htmlspecialchars($NOTICE), PHP_EOL; ?>
 			</div>
 			</div>
 <?php
 <?php
 endif;
 endif;
@@ -258,7 +258,7 @@ endif;
 if (strlen($STATUS)):
 if (strlen($STATUS)):
 ?>
 ?>
 			<div id="status" role="alert" class="alert alert-success">
 			<div id="status" role="alert" class="alert alert-success">
-				<span class="glyphicon glyphicon-ok" aria-hidden="true"></span> <?php echo htmlspecialchars($STATUS); ?>
+				<span class="glyphicon glyphicon-ok" aria-hidden="true"></span> <?php echo htmlspecialchars($STATUS), PHP_EOL; ?>
 			</div>
 			</div>
 <?php
 <?php
 endif;
 endif;
@@ -270,7 +270,7 @@ endif;
 ?>alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo htmlspecialchars($ERROR); ?></div>
 ?>alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo htmlspecialchars($ERROR); ?></div>
 			<noscript><div id="noscript" role="alert" class="nonworking alert alert-warning"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <?php echo I18n::_('Javascript is required for PrivateBin to work.<br />Sorry for the inconvenience.'); ?></div></noscript>
 			<noscript><div id="noscript" role="alert" class="nonworking alert alert-warning"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <?php echo I18n::_('Javascript is required for PrivateBin to work.<br />Sorry for the inconvenience.'); ?></div></noscript>
 			<div id="oldienotice" role="alert" class="hidden nonworking alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo I18n::_('PrivateBin requires a modern browser to work.'); ?></div>
 			<div id="oldienotice" role="alert" class="hidden nonworking alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <?php echo I18n::_('PrivateBin requires a modern browser to work.'); ?></div>
-			<div id="ienotice" role="alert" class="hidden alert alert-warning"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span> <?php echo I18n::_('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:'); ?>
+			<div id="ienotice" role="alert" class="hidden alert alert-warning"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span> <?php echo I18n::_('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:'), PHP_EOL; ?>
 				<a href="https://www.mozilla.org/firefox/">Firefox</a>,
 				<a href="https://www.mozilla.org/firefox/">Firefox</a>,
 				<a href="https://www.opera.com/">Opera</a>,
 				<a href="https://www.opera.com/">Opera</a>,
 				<a href="https://www.google.com/chrome">Chrome</a>,
 				<a href="https://www.google.com/chrome">Chrome</a>,
@@ -284,7 +284,7 @@ endif;
 if (strlen($URLSHORTENER)):
 if (strlen($URLSHORTENER)):
 ?>
 ?>
 					<button id="shortenbutton" data-shortener="<?php echo htmlspecialchars($URLSHORTENER); ?>" type="button" class="btn btn-primary">
 					<button id="shortenbutton" data-shortener="<?php echo htmlspecialchars($URLSHORTENER); ?>" type="button" class="btn btn-primary">
-						<span class="glyphicon glyphicon-send" aria-hidden="true"></span> <?php echo I18n::_('Shorten URL'); ?>
+						<span class="glyphicon glyphicon-send" aria-hidden="true"></span> <?php echo I18n::_('Shorten URL'), PHP_EOL; ?>
 					</button>
 					</button>
 <?php
 <?php
 endif;
 endif;
@@ -317,7 +317,7 @@ endif;
 				<h4 class="col-md-5 col-xs-8"><?php echo I18n::_('PrivateBin'); ?> <small>- <?php echo I18n::_('Because ignorance is bliss'); ?></small></h4>
 				<h4 class="col-md-5 col-xs-8"><?php echo I18n::_('PrivateBin'); ?> <small>- <?php echo I18n::_('Because ignorance is bliss'); ?></small></h4>
 				<p class="col-md-1 col-xs-4 text-center"><?php echo $VERSION; ?></p>
 				<p class="col-md-1 col-xs-4 text-center"><?php echo $VERSION; ?></p>
 				<p id="aboutbox" class="col-md-6 col-xs-12">
 				<p id="aboutbox" class="col-md-6 col-xs-12">
-					<?php echo I18n::_('PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted <i>in the browser</i> using 256 bits AES. More information on the <a href="https://github.com/PrivateBin/PrivateBin/wiki">project page</a>.'); ?>
+					<?php echo I18n::_('PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted <i>in the browser</i> using 256 bits AES. More information on the <a href="https://github.com/PrivateBin/PrivateBin/wiki">project page</a>.'), PHP_EOL; ?>
 				</p>
 				</p>
 			</div>
 			</div>
 		</footer>
 		</footer>

+ 3 - 3
tpl/page.php

@@ -65,7 +65,7 @@ endif;
 			<h3 class="title"><?php echo $VERSION; ?></h3>
 			<h3 class="title"><?php echo $VERSION; ?></h3>
 			<noscript><div id="noscript" class="nonworking"><?php echo I18n::_('Javascript is required for PrivateBin to work.<br />Sorry for the inconvenience.'); ?></div></noscript>
 			<noscript><div id="noscript" class="nonworking"><?php echo I18n::_('Javascript is required for PrivateBin to work.<br />Sorry for the inconvenience.'); ?></div></noscript>
 			<div id="oldienotice" class="nonworking"><?php echo I18n::_('PrivateBin requires a modern browser to work.'); ?></div>
 			<div id="oldienotice" class="nonworking"><?php echo I18n::_('PrivateBin requires a modern browser to work.'); ?></div>
-			<div id="ienotice"><?php echo I18n::_('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:'); ?>
+			<div id="ienotice"><?php echo I18n::_('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:'), PHP_EOL; ?>
 				<a href="https://www.mozilla.org/firefox/">Firefox</a>,
 				<a href="https://www.mozilla.org/firefox/">Firefox</a>,
 				<a href="https://www.opera.com/">Opera</a>,
 				<a href="https://www.opera.com/">Opera</a>,
 				<a href="https://www.google.com/chrome">Chrome</a>,
 				<a href="https://www.google.com/chrome">Chrome</a>,
@@ -104,7 +104,7 @@ endforeach;
 					</div>
 					</div>
 					<div id="remainingtime" class="hidden"></div>
 					<div id="remainingtime" class="hidden"></div>
 					<div id="burnafterreadingoption" class="button hidden">
 					<div id="burnafterreadingoption" class="button hidden">
-						<input type="checkbox" id="burnafterreading" name="burnafterreading" <?php
+						<input type="checkbox" id="burnafterreading" name="burnafterreading"<?php
 if ($BURNAFTERREADINGSELECTED):
 if ($BURNAFTERREADINGSELECTED):
 ?> checked="checked"<?php
 ?> checked="checked"<?php
 endif;
 endif;
@@ -115,7 +115,7 @@ endif;
 if ($DISCUSSION):
 if ($DISCUSSION):
 ?>
 ?>
 					<div id="opendisc" class="button hidden">
 					<div id="opendisc" class="button hidden">
-						<input type="checkbox" id="opendiscussion" name="opendiscussion" <?php
+						<input type="checkbox" id="opendiscussion" name="opendiscussion"<?php
     if ($OPENDISCUSSION):
     if ($OPENDISCUSSION):
 ?> checked="checked"<?php
 ?> checked="checked"<?php
     endif;
     endif;

+ 30 - 1
tst/Data/FilesystemTest.php

@@ -35,7 +35,7 @@ class FilesystemTest extends PHPUnit_Framework_TestCase
 
 
         // storing comments
         // storing comments
         $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist');
         $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist');
-        $this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment()) !== false, 'store comment');
+        $this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment()), 'store comment');
         $this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment exists after storing it');
         $this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment exists after storing it');
         $comment = json_decode(json_encode(Helper::getComment()));
         $comment = json_decode(json_encode(Helper::getComment()));
         $comment->id = Helper::getCommentId();
         $comment->id = Helper::getCommentId();
@@ -93,4 +93,33 @@ class FilesystemTest extends PHPUnit_Framework_TestCase
             }
             }
         }
         }
     }
     }
+
+    /**
+     * @expectedException Exception
+     * @expectedExceptionCode 90
+     */
+    public function testErrorDetection()
+    {
+        $this->_model->delete(Helper::getPasteId());
+        $paste = Helper::getPaste(array('formatter' => "Invalid UTF-8 sequence: \xB1\x31"));
+        $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
+        $this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
+        $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist');
+    }
+
+    /**
+     * @expectedException Exception
+     * @expectedExceptionCode 90
+     */
+    public function testCommentErrorDetection()
+    {
+        $this->_model->delete(Helper::getPasteId());
+        $comment = Helper::getComment(array('formatter' => "Invalid UTF-8 sequence: \xB1\x31"));
+        $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
+        $this->assertTrue($this->_model->create(Helper::getPasteId(), Helper::getPaste()), 'store new paste');
+        $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
+        $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist');
+        $this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment), 'unable to store broken comment');
+        $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does still not exist');
+    }
 }
 }

+ 82 - 4
tst/ModelTest.php

@@ -5,7 +5,9 @@ use PrivateBin\Data\Database;
 use PrivateBin\Model;
 use PrivateBin\Model;
 use PrivateBin\Model\Paste;
 use PrivateBin\Model\Paste;
 use PrivateBin\Persistence\ServerSalt;
 use PrivateBin\Persistence\ServerSalt;
+use PrivateBin\Persistence\TrafficLimiter;
 use PrivateBin\Vizhash16x16;
 use PrivateBin\Vizhash16x16;
+use Identicon\Identicon;
 
 
 class ModelTest extends PHPUnit_Framework_TestCase
 class ModelTest extends PHPUnit_Framework_TestCase
 {
 {
@@ -167,13 +169,13 @@ class ModelTest extends PHPUnit_Framework_TestCase
         $paste->setOpendiscussion();
         $paste->setOpendiscussion();
         $paste->store();
         $paste->store();
 
 
-        $vz = new Vizhash16x16();
-        $pngdata = 'data:image/png;base64,' . base64_encode($vz->generate($_SERVER['REMOTE_ADDR']));
         $comment = $paste->getComment(Helper::getPasteId());
         $comment = $paste->getComment(Helper::getPasteId());
         $comment->setData($commentData['data']);
         $comment->setData($commentData['data']);
         $comment->setNickname($commentData['meta']['nickname']);
         $comment->setNickname($commentData['meta']['nickname']);
         $comment->store();
         $comment->store();
 
 
+        $identicon = new Identicon();
+        $pngdata = $identicon->getImageDataUri(TrafficLimiter::getHash(), 16);
         $comment = $paste->getComment(Helper::getPasteId(), Helper::getCommentId())->get();
         $comment = $paste->getComment(Helper::getPasteId(), Helper::getCommentId())->get();
         $this->assertEquals($pngdata, $comment->meta->vizhash, 'nickname triggers vizhash to be set');
         $this->assertEquals($pngdata, $comment->meta->vizhash, 'nickname triggers vizhash to be set');
     }
     }
@@ -260,9 +262,9 @@ class ModelTest extends PHPUnit_Framework_TestCase
     public function testCommentWithDisabledVizhash()
     public function testCommentWithDisabledVizhash()
     {
     {
         $options = parse_ini_file(CONF, true);
         $options = parse_ini_file(CONF, true);
-        $options['main']['vizhash'] = false;
+        $options['main']['icon'] = 'none';
         $options['model'] = array(
         $options['model'] = array(
-            'class' => 'privatebin_db',
+            'class' => 'Database',
         );
         );
         $options['model_options'] = array(
         $options['model_options'] = array(
             'dsn' => 'sqlite::memory:',
             'dsn' => 'sqlite::memory:',
@@ -311,4 +313,80 @@ class ModelTest extends PHPUnit_Framework_TestCase
         $this->assertEquals($commentData['meta']['nickname'], $comment->meta->nickname);
         $this->assertEquals($commentData['meta']['nickname'], $comment->meta->nickname);
         $this->assertFalse(property_exists($comment->meta, 'vizhash'), 'vizhash was not generated');
         $this->assertFalse(property_exists($comment->meta, 'vizhash'), 'vizhash was not generated');
     }
     }
+
+    public function testCommentIdenticon()
+    {
+        $options = parse_ini_file(CONF, true);
+        $options['main']['icon'] = 'identicon';
+        $options['model'] = array(
+            'class' => 'Database',
+        );
+        $options['model_options'] = array(
+            'dsn' => 'sqlite::memory:',
+            'usr' => null,
+            'pwd' => null,
+            'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
+        );
+        Helper::confBackup();
+        Helper::createIniFile(CONF, $options);
+        $model = new Model(new Configuration);
+
+        $pasteData = Helper::getPaste();
+        $commentData = Helper::getComment();
+        $model->getPaste(Helper::getPasteId())->delete();
+
+        $paste = $model->getPaste();
+        $paste->setData($pasteData['data']);
+        $paste->setOpendiscussion();
+        $paste->setFormatter($pasteData['meta']['formatter']);
+        $paste->store();
+
+        $comment = $paste->getComment(Helper::getPasteId());
+        $comment->setData($commentData['data']);
+        $comment->setNickname($commentData['meta']['nickname']);
+        $comment->store();
+
+        $identicon = new Identicon();
+        $pngdata = $identicon->getImageDataUri(TrafficLimiter::getHash(), 16);
+        $comment = $paste->getComment(Helper::getPasteId(), Helper::getCommentId())->get();
+        $this->assertEquals($pngdata, $comment->meta->vizhash, 'nickname triggers vizhash to be set');
+    }
+
+    public function testCommentVizhash()
+    {
+        $options = parse_ini_file(CONF, true);
+        $options['main']['icon'] = 'vizhash';
+        $options['model'] = array(
+            'class' => 'Database',
+        );
+        $options['model_options'] = array(
+            'dsn' => 'sqlite::memory:',
+            'usr' => null,
+            'pwd' => null,
+            'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
+        );
+        Helper::confBackup();
+        Helper::createIniFile(CONF, $options);
+        $model = new Model(new Configuration);
+
+        $pasteData = Helper::getPaste();
+        $commentData = Helper::getComment();
+        $model->getPaste(Helper::getPasteId())->delete();
+
+        $paste = $model->getPaste();
+        $paste->setData($pasteData['data']);
+        $paste->setOpendiscussion();
+        $paste->setFormatter($pasteData['meta']['formatter']);
+        $paste->store();
+
+        $comment = $paste->getComment(Helper::getPasteId());
+        $comment->setData($commentData['data']);
+        $comment->setNickname($commentData['meta']['nickname']);
+        $comment->store();
+
+        $vz = new Vizhash16x16();
+        $pngdata = 'data:image/png;base64,' . base64_encode($vz->generate(TrafficLimiter::getHash()));
+        $comment = $paste->getComment(Helper::getPasteId(), Helper::getCommentId())->get();
+        $this->assertEquals($pngdata, $comment->meta->vizhash, 'nickname triggers vizhash to be set');
+    }
 }
 }

+ 3 - 3
tst/Vizhash16x16Test.php

@@ -30,11 +30,11 @@ class Vizhash16x16Test extends PHPUnit_Framework_TestCase
     public function testVizhashGeneratesUniquePngsPerIp()
     public function testVizhashGeneratesUniquePngsPerIp()
     {
     {
         $vz = new Vizhash16x16();
         $vz = new Vizhash16x16();
-        $pngdata = $vz->generate('127.0.0.1');
+        $pngdata = $vz->generate(hash('sha512', '127.0.0.1'));
         file_put_contents($this->_file, $pngdata);
         file_put_contents($this->_file, $pngdata);
         $finfo = new finfo(FILEINFO_MIME_TYPE);
         $finfo = new finfo(FILEINFO_MIME_TYPE);
         $this->assertEquals('image/png', $finfo->file($this->_file));
         $this->assertEquals('image/png', $finfo->file($this->_file));
-        $this->assertNotEquals($pngdata, $vz->generate('2001:1620:2057:dead:beef::cafe:babe'));
-        $this->assertEquals($pngdata, $vz->generate('127.0.0.1'));
+        $this->assertNotEquals($pngdata, $vz->generate(hash('sha512', '2001:1620:2057:dead:beef::cafe:babe')));
+        $this->assertEquals($pngdata, $vz->generate(hash('sha512', '127.0.0.1')));
     }
     }
 }
 }

+ 7 - 1
vendor/composer/autoload_classmap.php

@@ -6,14 +6,21 @@ $vendorDir = dirname(dirname(__FILE__));
 $baseDir = dirname($vendorDir);
 $baseDir = dirname($vendorDir);
 
 
 return array(
 return array(
+    'Identicon\\Generator\\BaseGenerator' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/BaseGenerator.php',
+    'Identicon\\Generator\\GdGenerator' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/GdGenerator.php',
+    'Identicon\\Generator\\GeneratorInterface' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/GeneratorInterface.php',
+    'Identicon\\Generator\\ImageMagickGenerator' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/ImageMagickGenerator.php',
+    'Identicon\\Identicon' => $vendorDir . '/yzalis/identicon/src/Identicon/Identicon.php',
     'PrivateBin\\Configuration' => $baseDir . '/lib/Configuration.php',
     'PrivateBin\\Configuration' => $baseDir . '/lib/Configuration.php',
     'PrivateBin\\Data\\AbstractData' => $baseDir . '/lib/Data/AbstractData.php',
     'PrivateBin\\Data\\AbstractData' => $baseDir . '/lib/Data/AbstractData.php',
     'PrivateBin\\Data\\Database' => $baseDir . '/lib/Data/Database.php',
     'PrivateBin\\Data\\Database' => $baseDir . '/lib/Data/Database.php',
     'PrivateBin\\Data\\Filesystem' => $baseDir . '/lib/Data/Filesystem.php',
     'PrivateBin\\Data\\Filesystem' => $baseDir . '/lib/Data/Filesystem.php',
     'PrivateBin\\Filter' => $baseDir . '/lib/Filter.php',
     'PrivateBin\\Filter' => $baseDir . '/lib/Filter.php',
     'PrivateBin\\I18n' => $baseDir . '/lib/I18n.php',
     'PrivateBin\\I18n' => $baseDir . '/lib/I18n.php',
+    'PrivateBin\\Json' => $baseDir . '/lib/Json.php',
     'PrivateBin\\Model' => $baseDir . '/lib/Model.php',
     'PrivateBin\\Model' => $baseDir . '/lib/Model.php',
     'PrivateBin\\Model\\AbstractModel' => $baseDir . '/lib/Model/AbstractModel.php',
     'PrivateBin\\Model\\AbstractModel' => $baseDir . '/lib/Model/AbstractModel.php',
+    'PrivateBin\\Model\\Comment' => $baseDir . '/lib/Model/Comment.php',
     'PrivateBin\\Model\\Paste' => $baseDir . '/lib/Model/Paste.php',
     'PrivateBin\\Model\\Paste' => $baseDir . '/lib/Model/Paste.php',
     'PrivateBin\\Persistence\\AbstractPersistence' => $baseDir . '/lib/Persistence/AbstractPersistence.php',
     'PrivateBin\\Persistence\\AbstractPersistence' => $baseDir . '/lib/Persistence/AbstractPersistence.php',
     'PrivateBin\\Persistence\\PurgeLimiter' => $baseDir . '/lib/Persistence/PurgeLimiter.php',
     'PrivateBin\\Persistence\\PurgeLimiter' => $baseDir . '/lib/Persistence/PurgeLimiter.php',
@@ -24,5 +31,4 @@ return array(
     'PrivateBin\\Sjcl' => $baseDir . '/lib/Sjcl.php',
     'PrivateBin\\Sjcl' => $baseDir . '/lib/Sjcl.php',
     'PrivateBin\\View' => $baseDir . '/lib/View.php',
     'PrivateBin\\View' => $baseDir . '/lib/View.php',
     'PrivateBin\\Vizhash16x16' => $baseDir . '/lib/Vizhash16x16.php',
     'PrivateBin\\Vizhash16x16' => $baseDir . '/lib/Vizhash16x16.php',
-    'PrivateBin\\model\\Comment' => $baseDir . '/lib/Model/Comment.php',
 );
 );

+ 0 - 10
vendor/composer/autoload_files.php

@@ -1,10 +0,0 @@
-<?php
-
-// autoload_files.php @generated by Composer
-
-$vendorDir = dirname(dirname(__FILE__));
-$baseDir = dirname($vendorDir);
-
-return array(
-    '5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php',
-);

+ 1 - 0
vendor/composer/autoload_namespaces.php

@@ -6,4 +6,5 @@ $vendorDir = dirname(dirname(__FILE__));
 $baseDir = dirname($vendorDir);
 $baseDir = dirname($vendorDir);
 
 
 return array(
 return array(
+    'Identicon' => array($vendorDir . '/yzalis/identicon/src'),
 );
 );

+ 0 - 18
vendor/composer/autoload_real.php

@@ -47,24 +47,6 @@ class ComposerAutoloaderInitDontChange
 
 
         $loader->register(true);
         $loader->register(true);
 
 
-        if ($useStaticLoader) {
-            $includeFiles = Composer\Autoload\ComposerStaticInitDontChange::$files;
-        } else {
-            $includeFiles = require __DIR__ . '/autoload_files.php';
-        }
-        foreach ($includeFiles as $fileIdentifier => $file) {
-            composerRequireDontChange($fileIdentifier, $file);
-        }
-
         return $loader;
         return $loader;
     }
     }
 }
 }
-
-function composerRequireDontChange($fileIdentifier, $file)
-{
-    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
-        require $file;
-
-        $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
-    }
-}

+ 18 - 5
vendor/composer/autoload_static.php

@@ -6,10 +6,6 @@ namespace Composer\Autoload;
 
 
 class ComposerStaticInitDontChange
 class ComposerStaticInitDontChange
 {
 {
-    public static $files = array (
-        '5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php',
-    );
-
     public static $prefixLengthsPsr4 = array (
     public static $prefixLengthsPsr4 = array (
         'P' => 
         'P' => 
         array (
         array (
@@ -24,15 +20,32 @@ class ComposerStaticInitDontChange
         ),
         ),
     );
     );
 
 
+    public static $prefixesPsr0 = array (
+        'I' => 
+        array (
+            'Identicon' => 
+            array (
+                0 => __DIR__ . '/..' . '/yzalis/identicon/src',
+            ),
+        ),
+    );
+
     public static $classMap = array (
     public static $classMap = array (
+        'Identicon\\Generator\\BaseGenerator' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/BaseGenerator.php',
+        'Identicon\\Generator\\GdGenerator' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/GdGenerator.php',
+        'Identicon\\Generator\\GeneratorInterface' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/GeneratorInterface.php',
+        'Identicon\\Generator\\ImageMagickGenerator' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/ImageMagickGenerator.php',
+        'Identicon\\Identicon' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Identicon.php',
         'PrivateBin\\Configuration' => __DIR__ . '/../..' . '/lib/Configuration.php',
         'PrivateBin\\Configuration' => __DIR__ . '/../..' . '/lib/Configuration.php',
         'PrivateBin\\Data\\AbstractData' => __DIR__ . '/../..' . '/lib/Data/AbstractData.php',
         'PrivateBin\\Data\\AbstractData' => __DIR__ . '/../..' . '/lib/Data/AbstractData.php',
         'PrivateBin\\Data\\Database' => __DIR__ . '/../..' . '/lib/Data/Database.php',
         'PrivateBin\\Data\\Database' => __DIR__ . '/../..' . '/lib/Data/Database.php',
         'PrivateBin\\Data\\Filesystem' => __DIR__ . '/../..' . '/lib/Data/Filesystem.php',
         'PrivateBin\\Data\\Filesystem' => __DIR__ . '/../..' . '/lib/Data/Filesystem.php',
         'PrivateBin\\Filter' => __DIR__ . '/../..' . '/lib/Filter.php',
         'PrivateBin\\Filter' => __DIR__ . '/../..' . '/lib/Filter.php',
         'PrivateBin\\I18n' => __DIR__ . '/../..' . '/lib/I18n.php',
         'PrivateBin\\I18n' => __DIR__ . '/../..' . '/lib/I18n.php',
+        'PrivateBin\\Json' => __DIR__ . '/../..' . '/lib/Json.php',
         'PrivateBin\\Model' => __DIR__ . '/../..' . '/lib/Model.php',
         'PrivateBin\\Model' => __DIR__ . '/../..' . '/lib/Model.php',
         'PrivateBin\\Model\\AbstractModel' => __DIR__ . '/../..' . '/lib/Model/AbstractModel.php',
         'PrivateBin\\Model\\AbstractModel' => __DIR__ . '/../..' . '/lib/Model/AbstractModel.php',
+        'PrivateBin\\Model\\Comment' => __DIR__ . '/../..' . '/lib/Model/Comment.php',
         'PrivateBin\\Model\\Paste' => __DIR__ . '/../..' . '/lib/Model/Paste.php',
         'PrivateBin\\Model\\Paste' => __DIR__ . '/../..' . '/lib/Model/Paste.php',
         'PrivateBin\\Persistence\\AbstractPersistence' => __DIR__ . '/../..' . '/lib/Persistence/AbstractPersistence.php',
         'PrivateBin\\Persistence\\AbstractPersistence' => __DIR__ . '/../..' . '/lib/Persistence/AbstractPersistence.php',
         'PrivateBin\\Persistence\\PurgeLimiter' => __DIR__ . '/../..' . '/lib/Persistence/PurgeLimiter.php',
         'PrivateBin\\Persistence\\PurgeLimiter' => __DIR__ . '/../..' . '/lib/Persistence/PurgeLimiter.php',
@@ -43,7 +56,6 @@ class ComposerStaticInitDontChange
         'PrivateBin\\Sjcl' => __DIR__ . '/../..' . '/lib/Sjcl.php',
         'PrivateBin\\Sjcl' => __DIR__ . '/../..' . '/lib/Sjcl.php',
         'PrivateBin\\View' => __DIR__ . '/../..' . '/lib/View.php',
         'PrivateBin\\View' => __DIR__ . '/../..' . '/lib/View.php',
         'PrivateBin\\Vizhash16x16' => __DIR__ . '/../..' . '/lib/Vizhash16x16.php',
         'PrivateBin\\Vizhash16x16' => __DIR__ . '/../..' . '/lib/Vizhash16x16.php',
-        'PrivateBin\\model\\Comment' => __DIR__ . '/../..' . '/lib/Model/Comment.php',
     );
     );
 
 
     public static function getInitializer(ClassLoader $loader)
     public static function getInitializer(ClassLoader $loader)
@@ -51,6 +63,7 @@ class ComposerStaticInitDontChange
         return \Closure::bind(function () use ($loader) {
         return \Closure::bind(function () use ($loader) {
             $loader->prefixLengthsPsr4 = ComposerStaticInitDontChange::$prefixLengthsPsr4;
             $loader->prefixLengthsPsr4 = ComposerStaticInitDontChange::$prefixLengthsPsr4;
             $loader->prefixDirsPsr4 = ComposerStaticInitDontChange::$prefixDirsPsr4;
             $loader->prefixDirsPsr4 = ComposerStaticInitDontChange::$prefixDirsPsr4;
+            $loader->prefixesPsr0 = ComposerStaticInitDontChange::$prefixesPsr0;
             $loader->classMap = ComposerStaticInitDontChange::$classMap;
             $loader->classMap = ComposerStaticInitDontChange::$classMap;
 
 
         }, null, ClassLoader::class);
         }, null, ClassLoader::class);

+ 25 - 23
vendor/composer/installed.json

@@ -1,35 +1,37 @@
 [
 [
     {
     {
-        "name": "paragonie/random_compat",
-        "version": "v2.0.2",
-        "version_normalized": "2.0.2.0",
+        "name": "yzalis/identicon",
+        "version": "1.1.0",
+        "version_normalized": "1.1.0.0",
         "source": {
         "source": {
             "type": "git",
             "type": "git",
-            "url": "https://github.com/paragonie/random_compat.git",
-            "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf"
+            "url": "https://github.com/yzalis/Identicon.git",
+            "reference": "a99fc2a3d018512f7914bc6f972952536c0f309b"
         },
         },
         "dist": {
         "dist": {
             "type": "zip",
             "type": "zip",
-            "url": "https://api.github.com/repos/paragonie/random_compat/zipball/088c04e2f261c33bed6ca5245491cfca69195ccf",
-            "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf",
+            "url": "https://api.github.com/repos/yzalis/Identicon/zipball/a99fc2a3d018512f7914bc6f972952536c0f309b",
+            "reference": "a99fc2a3d018512f7914bc6f972952536c0f309b",
             "shasum": ""
             "shasum": ""
         },
         },
         "require": {
         "require": {
-            "php": ">=5.2.0"
+            "php": ">=5.3.0"
         },
         },
         "require-dev": {
         "require-dev": {
-            "phpunit/phpunit": "4.*|5.*"
+            "fzaninotto/faker": "1.2.*@dev"
         },
         },
-        "suggest": {
-            "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
-        },
-        "time": "2016-04-03 06:00:07",
+        "time": "2014-07-13 09:19:12",
         "type": "library",
         "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "1.1-dev"
+            }
+        },
         "installation-source": "dist",
         "installation-source": "dist",
         "autoload": {
         "autoload": {
-            "files": [
-                "lib/random.php"
-            ]
+            "psr-0": {
+                "Identicon": "src/"
+            }
         },
         },
         "notification-url": "https://packagist.org/downloads/",
         "notification-url": "https://packagist.org/downloads/",
         "license": [
         "license": [
@@ -37,16 +39,16 @@
         ],
         ],
         "authors": [
         "authors": [
             {
             {
-                "name": "Paragon Initiative Enterprises",
-                "email": "security@paragonie.com",
-                "homepage": "https://paragonie.com"
+                "name": "Benjamin Laugueux",
+                "email": "benjamin@yzalis.com"
             }
             }
         ],
         ],
-        "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+        "description": "Create awesome unique avatar.",
+        "homepage": "http://identicon-php.org",
         "keywords": [
         "keywords": [
-            "csprng",
-            "pseudorandom",
-            "random"
+            "avatar",
+            "identicon",
+            "image"
         ]
         ]
     }
     }
 ]
 ]

+ 241 - 0
vendor/yzalis/identicon/src/Identicon/Generator/BaseGenerator.php

@@ -0,0 +1,241 @@
+<?php
+
+namespace Identicon\Generator;
+
+use Identicon\Generator\GeneratorInterface;
+
+/**
+ * @author Benjamin Laugueux <benjamin@yzalis.com>
+ */
+class BaseGenerator
+{
+    /**
+     * @var mixed
+     */
+    protected $generatedImage;
+
+    /**
+     * @var integer
+     */
+    protected $color;
+
+    /**
+     * @var integer
+     */
+    protected $backgroundColor;
+
+    /**
+     * @var integer
+     */
+    protected $size;
+
+    /**
+     * @var integer
+     */
+    protected $pixelRatio;
+
+    /**
+     * @var string
+     */
+    private $hash;
+
+    /**
+     * @var array
+     */
+    private $arrayOfSquare = array();
+
+    /**
+     * Set the image color
+     *
+     * @param string|array $color The color in hexa (6 chars) or rgb array
+     *
+     * @return this
+     */
+    public function setColor($color)
+    {
+        if (null === $color) {
+            return $this;
+        }
+
+        $this->color = $this->convertColor($color);
+
+        return $this;
+    }
+
+    /**
+     * Set the image background color
+     *
+     * @param string|array $backgroundColor The color in hexa (6 chars) or rgb array
+     *
+     * @return this
+     */
+    public function setBackgroundColor($backgroundColor)
+    {
+        if (null === $backgroundColor) {
+            return $this;
+        }
+
+        $this->backgroundColor = $this->convertColor($backgroundColor);
+
+        return $this;
+    }
+
+    private function convertColor($color)
+    {
+        $convertedColor = array();
+        if (is_array($color)) {
+            $convertedColor[0] = $color[0];
+            $convertedColor[1] = $color[1];
+            $convertedColor[2] = $color[2];
+        } else {
+            if (false !== strpos($color, '#')) {
+                $color = substr($color, 1);
+            }
+            $convertedColor[0] = hexdec(substr($color, 0, 2));
+            $convertedColor[1] = hexdec(substr($color, 2, 2));
+            $convertedColor[2] = hexdec(substr($color, 4, 2));
+        }
+
+        return $convertedColor;
+    }
+
+    /**
+     * Get the color
+     *
+     * @return array
+     */
+    public function getColor()
+    {
+        return $this->color;
+    }
+
+
+    /**
+     * Get the background color
+     *
+     * @return array
+     */
+    public function getBackgroundColor()
+    {
+        return $this->backgroundColor;
+    }
+
+    /**
+     * Convert the hash into an multidimensionnal array of boolean
+     *
+     * @return this
+     */
+    private function convertHashToArrayOfBoolean()
+    {
+        preg_match_all('/(\w)(\w)/', $this->hash, $chars);
+        foreach ($chars[1] as $i => $char) {
+            if ($i % 3 == 0) {
+                $this->arrayOfSquare[$i/3][0] = $this->convertHexaToBoolean($char);
+                $this->arrayOfSquare[$i/3][4] = $this->convertHexaToBoolean($char);
+            } elseif ($i % 3 == 1) {
+                $this->arrayOfSquare[$i/3][1] = $this->convertHexaToBoolean($char);
+                $this->arrayOfSquare[$i/3][3] = $this->convertHexaToBoolean($char);
+            } else {
+                $this->arrayOfSquare[$i/3][2] = $this->convertHexaToBoolean($char);
+            }
+            ksort($this->arrayOfSquare[$i/3]);
+        }
+
+        $this->color[0] = hexdec(array_pop($chars[1]))*16;
+        $this->color[1] = hexdec(array_pop($chars[1]))*16;
+        $this->color[2] = hexdec(array_pop($chars[1]))*16;
+
+        return $this;
+    }
+
+    /**
+     * Convert an heaxecimal number into a boolean
+     *
+     * @param string $hexa
+     *
+     * @return boolean
+     */
+    private function convertHexaToBoolean($hexa)
+    {
+        return (bool) intval(round(hexdec($hexa)/10));
+    }
+
+    /**
+     *
+     *
+     * @return array
+     */
+    public function getArrayOfSquare()
+    {
+        return $this->arrayOfSquare;
+    }
+
+    /**
+     * Get the identicon string hash
+     *
+     * @return string
+     */
+    public function getHash()
+    {
+        return $this->hash;
+    }
+
+    /**
+     * Generate a hash fron the original string
+     *
+     * @param string $string
+     *
+     * @return this
+     */
+    public function setString($string)
+    {
+        if (null === $string) {
+            throw new \Exception('The string cannot be null.');
+        }
+
+        $this->hash = md5($string);
+
+        $this->convertHashToArrayOfBoolean();
+
+        return $this;
+    }
+
+    /**
+     * Set the image size
+     *
+     * @param integer $size
+     *
+     * @return this
+     */
+    public function setSize($size)
+    {
+        if (null === $size) {
+            return $this;
+        }
+
+        $this->size = $size;
+        $this->pixelRatio = round($size / 5);
+
+        return $this;
+    }
+
+    /**
+     * Get the image size
+     *
+     * @return integer
+     */
+    public function getSize()
+    {
+        return $this->size;
+    }
+
+    /**
+     * Get the pixel ratio
+     *
+     * @return array
+     */
+    public function getPixelRatio()
+    {
+        return $this->pixelRatio;
+    }
+}

+ 76 - 0
vendor/yzalis/identicon/src/Identicon/Generator/GdGenerator.php

@@ -0,0 +1,76 @@
+<?php
+
+namespace Identicon\Generator;
+
+use Identicon\Generator\GeneratorInterface;
+
+/**
+ * @author Benjamin Laugueux <benjamin@yzalis.com>
+ */
+class GdGenerator extends BaseGenerator implements GeneratorInterface
+{
+    public function __construct()
+    {
+        if (!extension_loaded('gd')) {
+            throw new \Exception('GD does not appear to be avaliable in your PHP installation. Please try another generator');
+        }
+    }
+
+    private function generateImage()
+    {
+        // prepare image
+        $this->generatedImage = imagecreatetruecolor($this->getPixelRatio() * 5, $this->getPixelRatio() * 5);
+
+        $rgbBackgroundColor = $this->getBackgroundColor();
+        if (null === $rgbBackgroundColor) {
+            $background = imagecolorallocate($this->generatedImage, 0, 0, 0);
+            imagecolortransparent($this->generatedImage, $background);
+        } else {
+            $background = imagecolorallocate($this->generatedImage, $rgbBackgroundColor[0], $rgbBackgroundColor[1], $rgbBackgroundColor[2]);
+            imagefill($this->generatedImage, 0, 0, $background);
+        }
+
+        // prepage color
+        $rgbColor = $this->getColor();
+        $gdColor = imagecolorallocate($this->generatedImage, $rgbColor[0], $rgbColor[1], $rgbColor[2]);
+
+        // draw content
+        foreach ($this->getArrayOfSquare() as $lineKey => $lineValue) {
+            foreach ($lineValue as $colKey => $colValue) {
+                if (true === $colValue) {
+                    imagefilledrectangle($this->generatedImage, $colKey * $this->getPixelRatio(), $lineKey * $this->getPixelRatio(), ($colKey + 1) * $this->getPixelRatio(), ($lineKey + 1) * $this->getPixelRatio(), $gdColor);
+                }
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getImageBinaryData($string, $size = null, $color = null, $backgroundColor = null)
+    {
+        ob_start();
+        imagepng($this->getImageResource($string, $size, $color, $backgroundColor));
+        $imageData = ob_get_contents();
+        ob_end_clean();
+
+        return $imageData;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getImageResource($string, $size = null, $color = null, $backgroundColor = null)
+    {
+        $this
+            ->setString($string)
+            ->setSize($size)
+            ->setColor($color)
+            ->setBackgroundColor($backgroundColor)
+            ->generateImage();
+
+        return $this->generatedImage;
+    }
+}

+ 33 - 0
vendor/yzalis/identicon/src/Identicon/Generator/GeneratorInterface.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace Identicon\Generator;
+
+/**
+ * @author Benjamin Laugueux <benjamin@yzalis.com>
+ */
+interface GeneratorInterface
+{
+    /**
+     *
+     *
+     * @param  string       $string
+     * @param  integer      $size
+     * @param  array|string $color
+     * @param  array|string $backgroundColor
+     *
+     * @return mixed
+     */
+    function getImageBinaryData($string, $size = null, $color = null, $backgroundColor = null);
+
+    /**
+     *
+     *
+     * @param  string       $string
+     * @param  integer      $size
+     * @param  array|string $color
+     * @param  array|string $backgroundColor
+     *
+     * @return string
+     */
+    function getImageResource($string, $size = null, $color = null, $backgroundColor = null);
+}

+ 80 - 0
vendor/yzalis/identicon/src/Identicon/Generator/ImageMagickGenerator.php

@@ -0,0 +1,80 @@
+<?php
+
+namespace Identicon\Generator;
+
+use Identicon\Generator\GeneratorInterface;
+
+/**
+ * @author Francis Chuang <francis.chuang@gmail.com>
+ */
+class ImageMagickGenerator extends BaseGenerator implements GeneratorInterface
+{
+    public function __construct()
+    {
+        if (!extension_loaded('imagick')) {
+            throw new \Exception('ImageMagick does not appear to be avaliable in your PHP installation. Please try another generator');
+        }
+    }
+
+    private function generateImage()
+    {
+        $this->generatedImage = new \Imagick();
+        $rgbBackgroundColor = $this->getBackgroundColor();
+
+        if (null === $rgbBackgroundColor) {
+            $background = 'none';
+        } else {
+            $background = new \ImagickPixel("rgb($rgbBackgroundColor[0],$rgbBackgroundColor[1],$rgbBackgroundColor[2])");
+        }
+
+        $this->generatedImage->newImage($this->pixelRatio * 5, $this->pixelRatio * 5, $background, 'png');
+
+        // prepare color
+        $rgbColor = $this->getColor();
+        $color = new \ImagickPixel("rgb($rgbColor[0],$rgbColor[1],$rgbColor[2])");
+
+        $draw = new \ImagickDraw();
+        $draw->setFillColor($color);
+
+        // draw the content
+        foreach ($this->getArrayOfSquare() as $lineKey => $lineValue) {
+            foreach ($lineValue as $colKey => $colValue) {
+                if (true === $colValue) {
+                    $draw->rectangle( $colKey * $this->pixelRatio, $lineKey * $this->pixelRatio, ($colKey + 1) * $this->pixelRatio, ($lineKey + 1) * $this->pixelRatio);
+                }
+            }
+        }
+
+        $this->generatedImage->drawImage($draw);
+
+        return $this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getImageBinaryData($string, $size = null, $color = null, $backgroundColor = null)
+    {
+        ob_start();
+        echo $this->getImageResource($string, $size, $color, $backgroundColor);
+        $imageData = ob_get_contents();
+        ob_end_clean();
+
+        return $imageData;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getImageResource($string, $size = null, $color = null, $backgroundColor = null)
+    {
+        $this
+            ->setString($string)
+            ->setSize($size)
+            ->setColor($color)
+            ->setBackgroundColor($backgroundColor)
+            ->generateImage();
+
+        return $this->generatedImage;
+    }
+}

+ 100 - 0
vendor/yzalis/identicon/src/Identicon/Identicon.php

@@ -0,0 +1,100 @@
+<?php
+
+namespace Identicon;
+
+use Identicon\Generator\GdGenerator;
+use Identicon\Generator\GeneratorInterface;
+
+/**
+ * @author Benjamin Laugueux <benjamin@yzalis.com>
+ */
+class Identicon
+{
+    /**
+     * @var GeneratorInterface
+     */
+    private $generator;
+
+    public function __construct($generator = null)
+    {
+        if (null === $generator) {
+            $this->generator = new GdGenerator();
+        } else {
+            $this->generator = $generator;
+        }
+
+    }
+
+    /**
+     * Set the image generetor
+     *
+     * @param GeneratorInterface $generator
+     *
+     * @throws \Exception
+     */
+    public function setGenerator(GeneratorInterface $generator)
+    {
+        $this->generator = $generator;
+
+        return $this;
+    }
+
+    /**
+     * Display an Identicon image
+     *
+     * @param string  $string
+     * @param integer $size
+     * @param string  $color
+     * @param string  $backgroundColor
+     */
+    public function displayImage($string, $size = 64, $color = null, $backgroundColor = null)
+    {
+        header("Content-Type: image/png");
+        echo $this->getImageData($string, $size, $color, $backgroundColor);
+    }
+
+    /**
+     * Get an Identicon PNG image data
+     *
+     * @param string  $string
+     * @param integer $size
+     * @param string  $color
+     * @param string  $backgroundColor
+     *
+     * @return string
+     */
+    public function getImageData($string, $size = 64, $color = null, $backgroundColor = null)
+    {
+        return $this->generator->getImageBinaryData($string, $size, $color, $backgroundColor);
+    }
+
+    /**
+     * Get an Identicon PNG image resource
+     *
+     * @param string  $string
+     * @param integer $size
+     * @param string  $color
+     * @param string  $backgroundColor
+     *
+     * @return string
+     */
+    public function getImageResource($string, $size = 64, $color = null, $backgroundColor = null)
+    {
+        return $this->generator->getImageResource($string, $size, $color, $backgroundColor);
+    }
+
+    /**
+     * Get an Identicon PNG image data as base 64 encoded
+     *
+     * @param string  $string
+     * @param integer $size
+     * @param string  $color
+     * @param string  $backgroundColor
+     *
+     * @return string
+     */
+    public function getImageDataUri($string, $size = 64, $color = null, $backgroundColor = null)
+    {
+        return sprintf('data:image/png;base64,%s', base64_encode($this->getImageData($string, $size, $color, $backgroundColor)));
+    }
+}