49 Commits
0.20 ... 0.21.1

Author SHA1 Message Date
El RIDO
9f68658106 incrementing version number, updating changelog 2015-09-21 22:43:00 +02:00
El RIDO
0de9f868fa improving unit tests, fixing #38 2015-09-21 22:32:52 +02:00
El RIDO
0686087cfd fixing mobile navbar triggered issue and slight adjustement to bootstrap
template for using full width of browser for navbar
2015-09-20 20:05:48 +02:00
El RIDO
2dd8b94b05 improving git archive output 2015-09-19 17:38:04 +02:00
El RIDO
608605cd54 incrementing version number, updating docs 2015-09-19 17:23:10 +02:00
El RIDO
a41d0ca4dd various fixes:
- changing default formatter option to plain text to make upgrading from
  0.19 Alpha smoother
- fixing translation message change in bootstrap templates
- adjusting how image uploads are displayed in bootstrap templates
2015-09-19 14:22:29 +02:00
El RIDO
844c4d15e9 fixes #30 2015-09-19 14:19:42 +02:00
El RIDO
a111357fae add optional (since it uses a session cookie) language selection 2015-09-19 11:21:13 +02:00
El RIDO
47efedf23c traffic limiter would fail behind a reverse proxy / load balancer.
Adding configuration option to set the trusted HTTP header to get the
visitors IP in such a case (avoiding security issue if malicious clients
just set these headers themselfs)
2015-09-18 22:31:01 +02:00
El RIDO
801cdc627e adding credit to Viktor Stanchev for the file upload support and
translators
2015-09-18 22:04:57 +02:00
El RIDO
39e865ca64 if the uploaded file is an image mime type, display it 2015-09-18 21:41:50 +02:00
El RIDO
50075ea948 fixing issue with attachment, empty paste & empty password 2015-09-18 20:25:53 +02:00
El RIDO
ed9c4f45f4 adding file name support for #20, solving issue with unencryptable file 2015-09-18 12:33:10 +02:00
El RIDO
e144739dec implement file upload UI on bootstrap templates 2015-09-18 10:49:39 +02:00
El RIDO
8de24fae67 small visual adjustement on bootstrap theme 2015-09-18 09:52:04 +02:00
El RIDO
9274564162 intermediate step for #28: revert bootstrap template, but ensuring that
the navbar does not overlap by removing its float on top property.
bootstrap-compact is now the template with the floating & always visible
navbar.
2015-09-18 09:31:17 +02:00
Hexalyse
e04e75adf3 Minor typo correction 2015-09-17 22:29:23 +02:00
El RIDO
c72932d653 Merge pull request #29 from Draky50110/patch-1
Update FR
2015-09-17 22:27:21 +02:00
Gilles
895df63206 Update FR
Mistakes / missing translations
2015-09-17 22:24:18 +02:00
El RIDO
f25661beda Working on #28, changing template to avoid multi-line navbar:
- moved "burn after reading" & "discussion" into "options" menu in
"bootstrap" template
- added seperate "bootstrap-compact" template that also moves the
  formats into the same "options" menu
- fixing horizontal scroll bar glitch in mobile navbar
2015-09-17 21:55:28 +02:00
El RIDO
ec8851e46c support < 0.21 syntax highlighting 2015-09-17 20:47:00 +02:00
El RIDO
106141efa4 merging @vikstrous file upload feature for #20 from
8a6d268278
2015-09-16 22:51:48 +02:00
El RIDO
61903665df logic cleanup 2015-09-16 20:49:28 +02:00
El RIDO
0e53d1ee86 added markdown support and a dropdown for the format selection. The
options other then markdown are plain text and source code (syntax
highlighting). Resolves #25
2015-09-12 17:33:16 +02:00
El RIDO
9dde7f034a moving remaining time / for your eyes only message from nav bar into
status alert in bootstrap theme, to ensure it is seen even with a
collapsed nav bar as in the mobile view
2015-09-12 10:38:04 +02:00
El RIDO
428a9d9c41 toggling mobile nav bar after tap on buttons "New", "Clone" and "Send"
to ensure any messages are visible for #21.
2015-09-12 10:23:12 +02:00
El RIDO
da42968d7c "New" button became untapable in the mobile nav bar. Now it looks a bit
more ugly (it is at the end of the menu) but at least can be tapped on
again.
2015-09-12 10:10:30 +02:00
El RIDO
be8883d10e resolving nav bar becoming 3 lines between medium and small screen sizes
before mobile nav is toggled by changing @grid-float-breakpoint to
@screen-md (Point at which the navbar becomes uncollapsed) in bootstrap
for #21.
2015-09-12 10:07:59 +02:00
El RIDO
b26fb08732 Fixing issues with en translation, thanks @wware for spotting it 2015-09-08 20:48:18 +02:00
El RIDO
588e01fbec Merge branch 'master' of git@github.com:elrido/ZeroBin.git
Conflicts:
	i18n/fr.json
2015-09-06 19:23:43 +02:00
El RIDO
b060d57524 - implemented php side of plural translation
- using it to generate labels dynamically for the expire options
(deprecating the [expire_labels] configuration).
- added translation of the human readable data sizes to support the
french octet
- fixed IEC label for kibibytes
2015-09-06 19:21:17 +02:00
Hexalyse
2f15d4c70a Missing double quote that broke the app !
"NEVER edit directly on Github" should be my new motto. The color highlighting didn't show the missing " !
2015-09-06 16:06:48 +02:00
Hexalyse
108cf69f8b Translated the added phrases
I chose to remove the word "extrait" which sounded weird, and use the English word "paste", because I really can't figure out a correct translation of this word.
2015-09-06 16:04:17 +02:00
El RIDO
c83ba8256f implementing a plural translation solution, currently only the JS part 2015-09-06 15:54:43 +02:00
El RIDO
eee7b0144a covering JS side of translations (#7), added the messages to the
translation files and translated the german ones
2015-09-06 13:07:46 +02:00
El RIDO
5e47feb7e1 Merge pull request #24 from Gabbalo/patch-1
Update de.json
2015-09-06 09:24:03 +02:00
El RIDO
9a370d33ea Merge pull request #23 from marsjaninzmarsa/patch-1
Added Polish translation due to #7.
2015-09-06 09:22:28 +02:00
Gabriel
9ac9f9e1a7 Update de.json
Replaced "Schnipsel" with "Text" ans some other imo better choices for words. Also correction of punctuation errors.
2015-09-06 07:30:45 +02:00
Kuba Niewiarowski
952f8b7b9a Added Polish translation due to #7. 2015-09-06 04:26:40 +02:00
Hexalyse
18f32f3625 Translated a missing sentence in fr.json 2015-09-05 18:16:20 +02:00
Hexalyse
72ace70b04 Error in de translation header : "de" => "fr" 2015-09-05 18:11:20 +02:00
Hexalyse
ce331e8271 French translation.
I did a very quick French translation. Some errors may have stayed unseen.

Also, I didn't know how to translate "paste", so I chose "extrait". But I hesitated with "document".
Do not hesitate to contribute
2015-09-05 18:10:23 +02:00
El RIDO
b883d5eb4c Merge branch 'master' of git@github.com:elrido/ZeroBin.git
Conflicts:
	js/zerobin.js
2015-09-05 17:21:05 +02:00
El RIDO
3099e10dfa refactored JS:
- moved from global namespace into anonymous function
- as onclick has no direct access to the zerobin methods, the events are
now bound in the init() method via bindEvents()
- to simplify maintenance, the functions were wrapped into 3 objects:
zerobin (display logic, event handling), filter (compression,
encryption) and helper (stateless utilities)
- some CSS and template adjustements were also done
2015-09-05 17:12:11 +02:00
Hexalyse
d74172064b Hide error message when paste is posted correctly 2015-09-05 14:45:50 +02:00
Hexalyse
9687144c92 Error messages are now replaced and not appended
Error messages are now replaced and not appended in the #errormessage div, without removing the glyphicon (which a .text() would have done).
This way, we don't have HTML code in the JS (which would be ugly). But it's still not a really elegant solution.
2015-09-05 14:38:53 +02:00
El RIDO
a2af88a36e initial work on translations, covering the PHP side of it 2015-09-05 02:24:56 +02:00
El RIDO
28776ac178 formatting RainTPL class 2015-09-05 01:55:19 +02:00
El RIDO
3edeefd799 change project homepage link in templates 2015-09-03 23:51:42 +02:00
41 changed files with 4970 additions and 1360 deletions

6
.gitattributes vendored
View File

@@ -1,4 +1,4 @@
doc/* export-ignore
tst/* export-ignore
doc/ export-ignore
tst/ export-ignore
.gitattributes export-ignore
.gitignore export-ignore
.gitignore export-ignore

View File

@@ -1,12 +1,34 @@
# ZeroBin version history #
* **0.21.1 (2015-09-21)**:
* FIXING: lost meta data when using DB model instead of flat files
* FIXING: mobile navbar getting triggered on load
* CHANGED: database table "paste" gets automatically extended with a "meta" column
* CHANGED: navbar of "bootstrap" template now spans full width of view port on large screens
* **0.21 (2015-09-19)**:
* ADDED: Translations for German, French and Polish, language selection menu (optional)
* ADDED: File upload and image display support (optional)
* ADDED: Markdown format support
* ADDED: "bootstrap-compact" template that hides some of the options in a drop down menu to ensure the nav bar fitting on one line on smaller screen sizes
* FIXING: Various usability issues with different screen sizes / device types in the "bootstrap" template
* CHANGED: Instead of having different options to enable and preselect certain formats there is now a generic `[formatter_options]` section where formats can be added to the displayed format drop down menu. A `defaultformatter` can be set, it defaults to "plaintext". The `syntaxhighlighting` configuration got deprecated.
* `zerobin.js` got a major refactoring:
* moved from global namespace into anonymous function
* events are no longer set via "onclick" attributes in the templates, but bound by from JS side
* for simpler maintenance the functions were grouped into objects: zerobin (display logic, event handling), filter (compression,
encryption), i18n (translation, counterpart of i18n.php) and helper (stateless utilities)
* Wiki pages were added to address common topics:
* [Upgrading from ZeroBin 0.19 Alpha](https://github.com/elrido/ZeroBin/wiki/Upgrading-from-ZeroBin-0.19-Alpha)
* [ZeroBin Directory of public servers](https://github.com/elrido/ZeroBin/wiki/ZeroBin-Directory)
* [Translation](https://github.com/elrido/ZeroBin/wiki/Translation)
* [Templates](https://github.com/elrido/ZeroBin/wiki/Templates)
* **0.20 (2015-09-03)**:
* ADDED: Password protected pastes (optional)
* ADDED: configuration options for highlighting, password, discussions, expiration times, rate limiting
* ADDED: JSON-only retrieval of paste incl. discussion, used to be able to refresh paste when posting a comment
* ADDED: bootstrap CSS based template
* CHANGE: "Burn after reading" pastes are now deleted only after the paste was successfully decrypted via callback. This prevents accidental deletion by chatbots following URLs and the like. Usage of a password is suggested to ensure only the desired recipient is able to encrypt it.
* CHANGE: the "opendiscussion" option now only controls if the discussion checkbox is preselected. Use "discussion = false" to disable the discussion feature completely (which also removes the checkbox from the template).
* CHANGED: "Burn after reading" pastes are now deleted only after the paste was successfully decrypted via callback. This prevents accidental deletion by chatbots following URLs and the like. Usage of a password is suggested to ensure only the desired recipient is able to encrypt it.
* CHANGED: the "opendiscussion" option now only controls if the discussion checkbox is preselected. Use "discussion = false" to disable the discussion feature completely (which also removes the checkbox from the template).
* FIXING: Behaviour of several conflicting configuration options. As a general measure unit tests for 9 of the options and all their possible configurations were added via a unit test generator.
* updated JS libraries: jquery to 1.11.3, sjcl to 1.0.2, base64.js to 2.1.9, deflate to 0.5, inflate to 0.3 and prettify to latest
* generally improved documentation, both inline phpdoc / JSdoc source code documentation, as well as Wiki pages on installation, configuration, development and JSON-API

View File

@@ -5,5 +5,12 @@ Sébastien Sauvage - original idea and main developer
Alexey Gladkov - syntax highlighting
Greg Knaddison - robots.txt
MrKooky - HTML5 markup, CSS cleanup
Simon Rupf - MVC refactoring, configuration support and unit tests
Simon Rupf - MVC refactoring, configuration, i18n and unit tests
Hexalyse - Password protection
Viktor Stanchev - File upload support
Translations:
Hexalyse - French
Kuba Niewiarowski - Polish
Gabbalo - German
Draky50110 - French

View File

@@ -1,20 +1,47 @@
Installation
============
For Administrators
------------------
## Basic installation
In the index.php in the main folder you can define a different PATH. This is
useful if you want to secure your installation and want to move the
configuration, data files, templates and PHP libraries (directories cfg, data,
lib, tpl and tst) outside of your document root. This new location must still
be accessible to your webserver / PHP process.
**TL;DR:** Download the [latest release archive](https://github.com/elrido/ZeroBin/releases/latest)
and extract it in your web hosts folder were you want to install your ZeroBin instance.
> ### PATH Example ###
> Your zerobin installation lives in a subfolder called "paste" inside of your
### Requirements
- PHP version 5.2.6 or above
- GD extension
- mcrypt extension (recommended)
- some disk space or (optional) a database supported by PDO
- A web browser with javascript support
### Configuration
In the file `cfg/conf.ini` you can configure ZeroBin. The config file is divided
into multiple sections, which are enclosed in square brackets.
In the `[main]` section you can enable or disable the discussion feature, set the
limit of stored pastes and comments in bytes. The `[traffic]` section lets you
set a time limit in seconds. Users may not post more often then this limit to
your ZeroBin installation.
More details can be found in the
[configuration documentation](https://github.com/elrido/ZeroBin/wiki/Configuration).
## Advanced installation
### Changing the path
In the index.php you can define a different `PATH`. This is useful to secure your
installation. You can move the configuration, data files, templates and PHP
libraries (directories cfg, data, lib, tpl, tmp and tst) outside of your document
root. This new location must still be accessible to your webserver / PHP process
([open_basedir setting](http://php.net/manual/en/ini.core.php#ini.open-basedir)).
> #### PATH Example
> Your zerobin installation lives in a subfolder called "paste" inside of your
> document root. The URL looks like this:
> http://example.com/paste/
> The ZeroBin folder on your webserver is really:
> The full path of ZeroBin on your webserver is:
> /home/example.com/htdocs/paste
>
> When setting the path like this:
@@ -22,29 +49,27 @@ be accessible to your webserver / PHP process.
> ZeroBin will look for your includes here:
> /home/example.com/secret/zerobin
In the file "cfg/conf.ini" you can configure ZeroBin. The config file is
divided into multiple sections, which are enclosed in square brackets. In the
"[main]" section you can enable or disable the discussion feature, set the
limit of stored pastes and comments in bytes. The "[traffic]" section lets you
set a time limit in seconds. Users may not post more often then this limit to
your ZeroBin.
### Using a database instead of flat files
Finally the "[model]" and "[model_options]" sections let you configure your
favourite way of storing the pastes and discussions on your server.
"zerobin_data" is the default model, which stores everything in files in the
data folder. This is the recommended setup for low traffic sites. Under high
load, in distributed setups or if you are not allowed to store files locally,
you might want to switch to the "zerobin_db" model. This lets you store your
data in a database. Basically all databases that are supported by PDO (PHP
data objects) may be used. Automatic table creation is provided for pdo_ibm,
pdo_informix, pdo_mssql, pdo_mysql, pdo_oci, pdo_pgsql and pdo_sqlite. You may
want to provide a table prefix, if you have to share the zerobin database with
another application. The table prefix option is called "tbl".
In the configuration file the `[model]` and `[model_options]` sections let you
configure your favourite way of storing the pastes and discussions on your server.
> ### Note ###
> The "zerobin_db" model has only been tested with SQLite and MySQL, although
> it would not be recommended to use SQLite in a production environment. If you
> gain any experience running ZeroBin on other RDBMS, please let us know.
`zerobin_data` is the default model, which stores everything in files in the data
folder. This is the recommended setup for most sites.
Under high load, in distributed setups or if you are not allowed to store files
locally, you might want to switch to the `zerobin_db` model. This lets you store
your data in a database. Basically all databases that are supported by
[PDO](http://php.net/manual/en/book.pdo.php) may be used. Automatic table
creation is provided for `pdo_ibm`, `pdo_informix`, `pdo_mssql`, `pdo_mysql`,
`pdo_oci`, `pdo_pgsql` and `pdo_sqlite`. You may want to provide a table prefix,
if you have to share the zerobin database with another application. The table
prefix option is called `tbl`.
> #### Note
> The "zerobin_db" model has only been tested with SQLite and MySQL, although it
would not be recommended to use SQLite in a production environment. If you gain
any experience running ZeroBin on other RDBMS, please let us know.
For reference or if you want to create the table schema for yourself:
@@ -66,32 +91,3 @@ For reference or if you want to create the table schema for yourself:
vizhash TEXT,
postdate INT
);
For Developers
--------------
If you want to create your own data models, you might want to know how the
arrays, that you have to store, look like:
public function create($pasteid, $paste)
{
$pasteid = substr(hash('md5', $paste['data']), 0, 16);
$paste['data'] // text
$paste['meta']['postdate'] // int UNIX timestamp
$paste['meta']['expire_date'] // int UNIX timestamp
$paste['meta']['opendiscussion'] // true (if false it is unset)
$paste['meta']['burnafterreading'] // true (if false it is unset; if true, then opendiscussion is unset)
}
public function createComment($pasteid, $parentid, $commentid, $comment)
{
$pasteid // the id of the paste this comment belongs to
$parentid // the id of the parent of this comment, may be the paste id itself
$commentid = substr(hash('md5', $paste['data']), 0, 16);
$comment['data'] // text
$comment['meta']['nickname'] // text or null (if anonymous)
$comment['meta']['vizhash'] // text or null (if anonymous)
$comment['meta']['postdate'] // int UNIX timestamp
}

View File

@@ -1,4 +1,4 @@
# ZeroBin 0.20
# ZeroBin 0.21.1
ZeroBin is a minimalist, opensource online pastebin where the server has zero
knowledge of pasted data.
@@ -12,16 +12,16 @@ without loosing any data.
## What ZeroBin provides
- As a server administrator you don't have to worry if your users post content
+ As a server administrator you don't have to worry if your users post content
that is considered illegal in your country. You have no knowledge of any
pastes content. If requested or enforced, you can delete any paste from your
system.
of the pastes content. If requested or enforced, you can delete any paste from
your system.
- Pastebin like system to store text documents, code samples, etc.
+ Pastebin-like system to store text documents, code samples, etc.
- Encryption of data sent to server, even if it does not provide HTTPS.
+ Encryption of data sent to server, even if it does not provide HTTPS.
- Possibility to set a password which is required to read the paste. It further
+ Possibility to set a password which is required to read the paste. It further
protects a paste and prevents people stumbling upon your paste's link
from being able to read it without the password.
@@ -43,48 +43,38 @@ without loosing any data.
Some features are optional and can be enabled or disabled in the [configuration
file](https://github.com/elrido/ZeroBin/wiki/Configuration):
- Password protection
* Password protection
- Discussions
* Discussions
- Expiration times, including a "forever" and "burn after reading" option
* Expiration times, including a "forever" and "burn after reading" option
- Syntax highlighting using prettify.js, including 4 prettify themes
* Markdown format support for HTML formatted pastes
- Templates: By default there is a bootstrap based and a "classic ZeroBin" theme
* Syntax highlighting for source code using prettify.js, including 4 prettify themes
* File upload support, images get displayed (disabled by default, possibility to adjust size limit)
* Templates: By default there is a bootstrap CSS and a "classic ZeroBin" theme
and it is easy to adapt these to your own websites layout or create your own.
* Translation system and automatic browser language detection (if enabled in browser)
* Language selection (disabled by default, as it uses a session cookie)
## Further resources
- [Installation guide](https://github.com/elrido/ZeroBin/wiki/Installation)
* [Installation guide](https://github.com/elrido/ZeroBin/wiki/Installation)
- [Configuration guide](https://github.com/elrido/ZeroBin/wiki/Configuration)
* [Upgrading from 0.19 Alpha](https://github.com/elrido/ZeroBin/wiki/Upgrading-from-ZeroBin-0.19-Alpha)
- [Developer guide](https://github.com/elrido/ZeroBin/wiki/Development)
* [Configuration guide](https://github.com/elrido/ZeroBin/wiki/Configuration)
* [Templates](https://github.com/elrido/ZeroBin/wiki/Templates)
* [Translation guide](https://github.com/elrido/ZeroBin/wiki/Translation)
* [Developer guide](https://github.com/elrido/ZeroBin/wiki/Development)
Run into any issues? Have ideas for further developments? Please
[report](https://github.com/elrido/ZeroBin/issues) them!
------------------------------------------------------------------------------
Copyright (c) 2012 Sébastien SAUVAGE (sebsauvage.net)
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from
the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must
not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
------------------------------------------------------------------------------

View File

@@ -5,7 +5,7 @@
; @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
; @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
; @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
; @version 0.20
; @version 0.21.1
[main]
; enable or disable the discussion feature, defaults to true
@@ -14,17 +14,21 @@ discussion = true
; preselect the discussion feature, defaults to false
opendiscussion = false
; enable or disable syntax highlighting, defaults to true
syntaxhighlighting = true
; enable or disable the password feature, defaults to true
password = true
; (optional) set a syntax highlighting theme, as found in css/prettify/
; syntaxhighlightingtheme = "sons-of-obsidian"
; enable or disable the file upload feature, defaults to false
fileupload = false
; preselect the burn-after-reading feature, defaults to false
burnafterreadingselected = false
; enable or disable the password feature, defaults to true
password = true
; which display mode to preselect by default, defaults to "plaintext"
; make sure the value exists in [formatter_options]
defaultformatter = "plaintext"
; (optional) set a syntax highlighting theme, as found in css/prettify/
; syntaxhighlightingtheme = "sons-of-obsidian"
; size limit per paste or comment in bytes, defaults to 2 Mibibytes
sizelimit = 2097152
@@ -39,6 +43,11 @@ template = "bootstrap"
; use "1.7" if you are upgrading from a ZeroBin Alpha 0.19 installation
base64version = "2.1.9"
; by default ZeroBin will guess the visitors language based on the browsers
; settings. Optionally you can enable the language selection menu, which uses
; a session cookie to store the choice until the browser is closed.
languageselection = false
[expire]
; expire value that is selected per default
; make sure the value exists in [expire_options]
@@ -57,22 +66,22 @@ default = "1week"
1year = 31536000
never = 0
[expire_labels]
; descriptive labels for the expiration times
; must match those in [expire_options]
5min = "5 minutes"
10min = "10 minutes"
1hour = "1 hour"
1day = "1 day"
1week = "1 week"
1month = "1 month"
1year = "1 year"
never = "Never"
[formatter_options]
; Set available formatters, their order and their labels
plaintext = "Plain Text"
syntaxhighlighting = "Source Code"
markdown = "Markdown"
[traffic]
; time limit between calls from the same IP address in seconds
; Set this to 0 to disable rate limiting.
limit = 10
; (optional) if your website runs behind a reverse proxy or load balancer,
; set the HTTP header containing the visitors IP address, i.e. X_FORWARDED_FOR
; header = "X_FORWARDED_FOR"
; directory to store the traffic limits in
dir = PATH "data"
[model]
@@ -99,5 +108,4 @@ dir = PATH "data"
;dsn = "sqlite:" PATH "data/db.sq3"
;usr = null
;pwd = null
;opt[12] = true ; PDO::ATTR_PERSISTENT
;opt[12] = true ; PDO::ATTR_PERSISTENT

File diff suppressed because one or more lines are too long

View File

@@ -1,8 +1,41 @@
/* ZeroBin 0.20 - http://sebsauvage.net/wiki/doku.php?id=php:zerobin */
/* ZeroBin 0.21.1 - http://sebsauvage.net/wiki/doku.php?id=php:zerobin */
body {
padding: 70px 0 30px 0;
padding: 0 0 30px;
}
body.navbar-spacing {
padding-top: 70px;
}
.navbar-nav {
margin: 0 8px;
}
.dropdown-menu > li > label, .dropdown-menu > li > div {
clear: both;
display: block;
font-weight: normal;
line-height: 1.42857;
white-space: nowrap;
}
.dropdown-menu > li > label {
color: #333;
padding: 3px 20px 3px 40px;
}
.dropdown-menu > li > div {
color: #777;
padding: 3px 20px;
cursor: default;
}
#image img {
max-width: 100%;
height: auto;
margin-bottom: 20px;
}
#deletelink {
@@ -21,8 +54,20 @@ body {
margin: 5px 0;
}
#comments, #comments button {
margin-bottom: 10px;
}
.comment {
border-left: 1px solid #ccc;
padding: 5px 0 5px 5px;
padding: 5px 0 5px 10px;
white-space: pre-wrap;
}
footer h4 {
margin-top: 0;
}
li.L0, li.L1, li.L2, li.L3, li.L5, li.L6, li.L7, li.L8 {
list-style-type: decimal !important;
}

View File

@@ -1,4 +1,4 @@
/* ZeroBin 0.20 - http://sebsauvage.net/wiki/doku.php?id=php:zerobin */
/* ZeroBin 0.21.1 - http://sebsauvage.net/wiki/doku.php?id=php:zerobin */
/* CSS Reset from YUI 3.4.1 (build 4118) - Copyright 2011 Yahoo! Inc. All rights reserved.
@@ -18,16 +18,16 @@ html {
}
body {
font-family: Arial, Helvetica, sans-serif;
font-family: Helvetica, Arial, sans-serif;
font-size: 0.9em;
margin-bottom: 15px;
padding-left: 60px;
padding-right: 60px;
}
a { color: #0f388f; }
h1 {
a { color: #0f388f; cursor:pointer; }
h1.title {
font-size: 3.5em;
font-weight: bold;
color: #000;
@@ -36,7 +36,7 @@ h1 {
cursor: pointer;
}
h1:before {
h1.title:before {
content: attr(title);
position: absolute;
color: rgba(255,255,255,0.15);
@@ -45,7 +45,7 @@ h1:before {
cursor: pointer;
}
h2 {
h2.title {
color: #000;
font-size: 1em;
display: inline;
@@ -54,18 +54,17 @@ h2 {
position: relative;
bottom: 8px;
}
h3 {
h3.title {
color: #94a3b4;
font-size: 0.7em;
display: inline;
margin-top: 10px;
position: relative;
bottom: 8px;
}
}
#aboutbox {
font-size: 1.2em;
color: #94a3b4;
padding: 4px 8px 4px 16px;
position: relative;
@@ -77,15 +76,12 @@ h3 {
#aboutbox a { color: #94a3b4; }
#message, #cleartext, .replymessage {
#message, #cleartext, #prettymessage, #attachment, .replymessage {
clear: both;
color: #000;
background-color: #fff;
white-space: pre-wrap;
font-family: Consolas, "Lucida Console", "DejaVu Sans Mono", Monaco, monospace;
font-size: 9pt;
border: 1px solid #28343F;
padding: 5px;
box-sizing: border-box;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
@@ -94,6 +90,17 @@ h3 {
width: 100%;
}
#message, .replymessage {
padding: 5px;
white-space: pre-wrap;
font-family: Consolas, "Lucida Console", "DejaVu Sans Mono", Monaco, monospace;
}
#image img {
max-width: 100%;
height: auto;
}
#status {
clear: both;
padding: 5px 10px;
@@ -119,7 +126,7 @@ h3 {
#copyhint { color: #666; font-size: 0.85em; }
button, .button, #expiration {
button, .button {
color: #fff;
background-color: #323b47;
background-repeat: no-repeat;
@@ -127,7 +134,7 @@ button, .button, #expiration {
padding: 4px 8px;
font-size: 1em;
margin-right: 5px;
display: inline;
display: inline-block;
background-image: linear-gradient(bottom, #323b47 0, #51606e 100%);
background-image: -o-linear-gradient(bottom, #323b47 0, #51606e 100%);
background-image: -moz-linear-gradient(bottom, #323b47 0, #51606e 100%);
@@ -178,7 +185,7 @@ button img {
top: 2px;
}
#expiration, #rawtextbutton, #burnafterreadingoption, #opendisc {
.button {
background-color: #414d5a;
padding: 6px 8px;
margin: 0 5px 0 0;
@@ -186,14 +193,14 @@ button img {
bottom: 1px; /* WTF ? Why is this shifted by 1 pixel ? */
}
#expiration select {
.button select {
color: #eee;
background: transparent;
border: none;
}
#expiration select option {
.button select option {
color:#eee;
background: #414d5a;
}
@@ -202,7 +209,7 @@ button img {
padding: 1px 0 1px 0;
}
#remainingtime {
#remainingtime, #password {
color: #94a3b4;
display: inline;
font-size: 0.85em;
@@ -234,7 +241,7 @@ input {
font-weight: bold !important;
}
.nonworking {
#image, .nonworking {
background-color: #fff;
color: #000;
width: 100%;
@@ -244,7 +251,7 @@ input {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
padding: 5px;
padding: 5px 0;
}
.hidden { display: none !important; }
@@ -279,7 +286,7 @@ input {
min-width: 200px;
}
h4 {
h4.title {
font-size: 1.2em;
color: #94a3b4;
font-style: italic;
@@ -386,3 +393,37 @@ img.vizhash {
color: #000000;
font-size: 1.2em;
}
#cleartext {
padding: 10px;
}
#cleartext * {
margin-bottom: 10px;
}
#cleartext ol {
list-style: auto;
margin-left: 15px;
}
#cleartext ul {
list-style: disc;
margin-left: 15px;
}
#cleartext h1, #cleartext h2, #cleartext h3, #cleartext h4, #cleartext h5, #cleartext h6 {
font-weight: bold;
}
#cleartext h1 {
font-size: 2em;
}
#cleartext h2 {
font-size: 1.5em;
}
#cleartext h3 {
font-size: 1.2em;
}

139
i18n/de.json Normal file
View File

@@ -0,0 +1,139 @@
{
"en": "de",
"Paste does not exist, has expired or has been deleted.":
"Diesen Text gibt es nicht, er ist abgelaufen oder wurde gelöscht.",
"ZeroBin requires php 5.2.6 or above to work. Sorry.":
"ZeroBin benötigt PHP 5.2.6 oder höher, um zu funktionieren. Sorry.",
"ZeroBin requires configuration section [%s] to be present in configuration file.":
"ZeroBin benötigt den Konfigurationsabschnitt [%s] in der Konfigurationsdatei um zu funktionieren.",
"Please wait %d seconds between each post.":
"Bitte warte %d Sekunden zwischen dem Absenden.",
"Paste is limited to %s of encrypted data.":
"Texte sind auf %s verschlüsselte Datenmenge beschränkt.",
"Invalid data.":
"Ungültige Daten.",
"You are unlucky. Try again.":
"Du hast Pech. Versuchs nochmal.",
"Error saving comment. Sorry.":
"Fehler beim Speichern des Kommentars. Sorry.",
"Error saving paste. Sorry.":
"Fehler beim Speichern des Textes. Sorry.",
"Invalid paste ID.":
"Ungültige Text-ID.",
"Paste is not of burn-after-reading type.":
"Text ist kein \"Einmal\"-Typ.",
"Wrong deletion token. Paste was not deleted.":
"Falscher Lösch-Code. Text wurde nicht gelöscht.",
"Paste was properly deleted.":
"Text wurde erfolgreich gelöscht.",
"ZeroBin": "ZeroBin",
"ZeroBin is a minimalist, opensource 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/elrido/ZeroBin/wiki\">project page</a>.":
"ZeroBin ist ein minimalistischer, quelloffener \"Pastebin\"-artiger Dienst, bei dem der Server keinerlei Kenntnis der Inhalte hat. Die Daten werden <i>im Browser</i> mit 256 Bit AES ver- und entschlüsselt. Weitere Informationen sind auf der <a href=\"https://github.com/elrido/ZeroBin/wiki\">Projektseite</a> zu finden.",
"Because ignorance is bliss":
"Unwissenheit ist ein Segen",
"Javascript is required for ZeroBin to work.<br />Sorry for the inconvenience.":
"Javascript ist eine Voraussetzung, um ZeroBin zu nutzen.<br />Bitte entschuldige die Unannehmlichkeiten.",
"ZeroBin requires a modern browser to work.":
"ZeroBin setzt einen modernen Browser voraus, um funktionieren zu können.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Du benutzt immer noch den Internet Explorer? Tu Dir einen Gefallen und wechsle zu einem moderneren Browser:",
"New":
"Neu",
"Send":
"Senden",
"Clone":
"Klonen",
"Raw text":
"Reiner Text",
"Expires":
"Ablaufzeit",
"Burn after reading":
"Einmal-Text",
"Open discussion":
"Diskussion eröffnen",
"Password (recommended)":
"Passwort (empfohlen)",
"Discussion":
"Diskussion",
"Toggle navigation":
"Navigation umschalten",
"%d seconds": ["%d Sekunde", "%d Sekunden"],
"%d minutes": ["%d Minute", "%d Minuten"],
"%d hours": ["%d Stunde", "%d Stunden"],
"%d days": ["%d Tag", "%d Tage"],
"%d weeks": ["%d Woche", "%d Wochen"],
"%d months": ["%d Monat", "%d Monate"],
"%d years": ["%d Jahr", "%d Jahre"],
"Never":
"Nie",
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.":
"Hinweis: Dies ist ein Versuchsdienst. Daten können jederzeit gelöscht werden. Kätzchen werden sterben wenn Du diesen Dienst missbrauchst.",
"This document will expire in %d seconds.":
["Dieses Dokument läuft in einer Sekunde ab.", "Dieses Dokument läuft in %d Sekunden ab."],
"This document will expire in %d minutes.":
["Dieses Dokument läuft in einer Minute ab.", "Dieses Dokument läuft in %d Minuten ab."],
"This document will expire in %d hours.":
["Dieses Dokument läuft in einer Stunde ab.", "Dieses Dokument läuft in %d Stunden ab."],
"This document will expire in %d days.":
["Dieses Dokument läuft in einem Tag ab.", "Dieses Dokument läuft in %d Tagen ab."],
"This document will expire in %d months.":
["Dieses Dokument läuft in einem Monat ab.", "Dieses Dokument läuft in %d Monaten ab."],
"Please enter the password for this paste:":
"Bitte gib das Passwort für diesen Text ein:",
"Could not decrypt data (Wrong key?)":
"Konnte Daten nicht entschlüsseln (Falscher Schlüssel?)",
"Could not delete the paste, it was not stored in burn after reading mode.":
"Konnte den Text nicht löschen, er wurde nicht im Einmal-Modus gespeichert.",
"FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.":
"DIESER TEXT IST NUR FÜR DICH GEDACHT. Schliesse das Fenster nicht, diese Nachricht kann nur einmal geöffnet werden.",
"Could not decrypt comment; Wrong key?":
"Konnte Kommentar nicht entschlüsseln; Falscher Schlüssel?",
"Reply":
"Antworten",
"Anonymous":
"Anonym",
"Anonymous avatar (Vizhash of the IP address)":
"Anonymer Avatar (Vizhash der IP-Addresse)",
"Add comment":
"Kommentar hinzufügen",
"Optional nickname...":
"Optionales Pseudonym...",
"Post comment":
"Kommentar absenden",
"Sending comment...":
"Sende Kommentar...",
"Comment posted.":
"Kommentar gesendet.",
"Could not refresh display: %s":
"Konnte Ansicht nicht aktualisieren: %s",
"unknown status":
"Unbekannter Grund",
"server error or not responding":
"Fehler auf dem Server oder keine Antwort vom Server",
"Could not post comment: %s":
"Konnte Kommentar nicht senden: %s",
"Sending paste (Please move your mouse for more entropy)...":
"Sende Text (Bitte bewege Deine Maus um die Entropie zu erhöhen)...",
"Sending paste...":
"Sende Text...",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>":
"Dein Text ist unter <a id=\"pasteurl\" href=\"%s\">%s</a> zu finden <span id=\"copyhint\">(Drücke [Strg]+[c] um den Link zu kopieren)</span>",
"Delete data":
"Lösche Daten",
"Could not create paste: %s":
"Konnte Text nicht erstellen: %s",
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)":
"Konnte Text nicht entschlüsseln: Der Schlüssel fehlt in der Adresse (Hast Du eine Umleitung oder einen URL-Verkürzer benutzt, der Teile der Adresse entfernt?)",
"Format": "Format",
"Plain Text": "Nur Text",
"Source Code": "Quellcode",
"Markdown": "Markdown",
"Download attachment": "Anhang herunterladen",
"Cloned file attached.": "Kopierte Datei angehängt.",
"Attach a file": "Datei anhängen",
"Remove attachment": "Anhang entfernen",
"Your browser does not support uploading encrypted files. Please use a newer browser.":
"Dein Browser unterstützt das hochladen von verschlüsselten Dateien nicht. Bitte verwende einen neueren Browser.",
"Invalid attachment.": "Ungültiger Datei-Anhang.",
"Options": "Optionen"
}

148
i18n/fr.json Normal file
View File

@@ -0,0 +1,148 @@
{
"en": "fr",
"Paste does not exist, has expired or has been deleted.":
"Le paste n'existe pas, a expiré, ou a été supprimé.",
"ZeroBin requires php 5.2.6 or above to work. Sorry.":
"Désolé, ZeroBin nécessite php 5.2.6 ou supérieur pour fonctionner.",
"ZeroBin requires configuration section [%s] to be present in configuration file.":
"ZeroBin a besoin de la section de configuration [%s] dans le fichier de configuration pour fonctionner.",
"Please wait %d seconds between each post.":
"Merci d'attendre %d secondes entre chaque publication.",
"Paste is limited to %s of encrypted data.":
"Le paste est limité à %s de données chiffrées.",
"Invalid data.":
"Données invalides.",
"You are unlucky. Try again.":
"Pas de chance. Essayez encore.",
"Error saving comment. Sorry.":
"Erreur lors de la sauvegarde du commentaire.",
"Error saving paste. Sorry.":
"Erreur lors de la sauvegarde du paste. Désolé.",
"Invalid paste ID.":
"ID du paste invalide.",
"Paste is not of burn-after-reading type.":
"Le paste n'est pas de type \"Effacer après lecture\".",
"Wrong deletion token. Paste was not deleted.":
"Jeton de suppression incorrect. Le paste n'a pas été supprimé.",
"Paste was properly deleted.":
"Le paste a été correctement supprimé.",
"ZeroBin": "ZeroBin",
"ZeroBin is a minimalist, opensource 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/elrido/ZeroBin/wiki\">project page</a>.":
"Zerobin est un 'pastebin' (ou gestionnaire d'extraits de texte et de code source) minimaliste et open source, dans lequel le serveur n'a aucune connaissance des données envoyées. Les données sont chiffrées/déchiffrées <i>dans le navigateur</i> par un chiffrage AES 256 bits. Plus d'informations sur <a href=\"https://github.com/elrido/ZeroBin/wiki\">la page du projet</a>.",
"Because ignorance is bliss":
"Parce que l'ignorance est le bonheur",
"Javascript is required for ZeroBin to work.<br />Sorry for the inconvenience.":
"Javascript est requis pour faire fonctionner ZeroBin. <br />Désolé pour cet inconvénient.",
"ZeroBin requires a modern browser to work.":
"ZeroBin nécessite un navigateur moderne pour fonctionner.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Encore sur Internet Explorer ? Faites-vous une faveur, passez à un navigateur moderne :",
"New":
"Nouveau",
"Send":
"Envoyer",
"Clone":
"Cloner",
"Raw text":
"Texte brut",
"Expires":
"Expire",
"Burn after reading":
"Effacer après lecture",
"Open discussion":
"Autoriser la discussion",
"Password (recommended)":
"Mot de passe (recommandé)",
"Discussion":
"Discussion",
"Toggle navigation":
"Basculer la navigation",
"%d seconds": ["%d seconde", "%d secondes"],
"%d minutes": ["%d minute", "%d minutes"],
"%d hours": ["%d heure", "%d heures"],
"%d days": ["%d jour", "%d jours"],
"%d weeks": ["%d semaine", "%d semaines"],
"%d months": ["%d mois", "%d mois"],
"%d years": ["%d an", "%d ans"],
"Never":
"Jamais",
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.":
"Note : Ceci est un service de test : les données peuvent être supprimées à tout moment. Des chatons mourront si vous utilisez ce service de manière abusive.",
"This document will expire in %d seconds.":
["Ce document expirera dans %d seconde.", "Ce document expirera dans %d secondes."],
"This document will expire in %d minutes.":
["Ce document expirera dans %d minute.", "Ce document expirera dans %d minutes."],
"This document will expire in %d hours.":
["Ce document expirera dans %d heure.", "Ce document expirera dans %d heures."],
"This document will expire in %d days.":
["Ce document expirera dans %d jour.", "Ce document expirera dans %d jours."],
"This document will expire in %d months.":
["Ce document expirera dans %d mois.", "Ce document expirera dans %d mois."],
"Please enter the password for this paste:":
"Entrez le mot de passe pour ce paste:",
"Could not decrypt data (Wrong key?)":
"Impossible de déchiffrer les données (mauvaise clé ?)",
"Could not delete the paste, it was not stored in burn after reading mode.":
"Impossible de supprimer le paste, car il n'a pas été stoclé en mode \"Effacer après lecture\".",
"FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.":
"POUR VOS YEUX UNIQUEMENT. Ne fermez pas cette fenêtre, ce paste ne pourra plus être affiché.",
"Could not decrypt comment; Wrong key?":
"Umpossible de déchiffrer le commentaire ; mauvaise clé ?",
"Reply":
"Répondre",
"Anonymous":
"Anonyme",
"Anonymous avatar (Vizhash of the IP address)":
"Avatar anonyme (Vizhash de l'adresse IP)",
"Add comment":
"Ajouter un commentaire",
"Optional nickname...":
"Pseudonyme optionnel...",
"Post comment":
"Poster le commentaire",
"Sending comment...":
"Envoi du commentaire...",
"Comment posted.":
"Commentaire posté.",
"Could not refresh display: %s":
"Impossible de rafraichir l'affichage : %s",
"unknown status":
"Statut inconnu",
"server error or not responding":
"Le serveur ne répond pas ou a rencontré une erreur",
"Could not post comment: %s":
"Impossible de poster le commentaire : %s",
"Sending paste (Please move your mouse for more entropy)...":
"Envoi du paste (Merci de bouger votre souris pour plus d'entropie)...",
"Sending paste...":
"Envoi du paste...",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>":
"Votre paste est disponible à l'adresse <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Appuyez sur [Ctrl]+[c] pour copier)</span>",
"Delete data":
"Supprimer les données du paste",
"Could not create paste: %s":
"Impossible de créer le paste : %s",
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)":
"Impossible de déchiffrer le paste : Clé de déchiffrage manquante dans l'URL (Avez-vous utilisé un redirecteur ou un site de réduction d'URL qui supprime une partie de l'URL ?)",
"B": "o",
"KiB": "Kio",
"MiB": "Mio",
"GiB": "Gio",
"TiB": "Tio",
"PiB": "Pio",
"EiB": "Eio",
"ZiB": "Zio",
"YiB": "Yio",
"Format": "Format",
"Plain Text": "Texte brut",
"Source Code": "Code source",
"Markdown": "Markdown",
"Download attachment": "Télécharger la pièce jointe",
"Cloned file attached.": "Cloner le fichier attaché.",
"Attach a file": "Attacher un fichier ",
"Remove attachment": "Enlever l'attachement",
"Your browser does not support uploading encrypted files. Please use a newer browser.":
"Votre navigateur ne supporte pas l'envoi de fichiers chiffrés. Merci d'utiliser un navigateur plus récent.",
"Invalid attachment.": "Attachement invalide.",
"Options": "Options"
}

181
i18n/languages.json Normal file
View File

@@ -0,0 +1,181 @@
{
"ab": ["аҧсуа бызшәа", "Abkhaz"],
"aa": ["Afaraf", "Afar"],
"af": ["Afrikaans", "Afrikaans"],
"ak": ["Akan", "Akan"],
"sq": ["Shqip", "Albanian"],
"am": ["አማርኛ", "Amharic"],
"ar": ["العربية", "Arabic"],
"an": ["aragonés", "Aragonese"],
"hy": ["Հայերեն", "Armenian"],
"as": ["অসমীয়া", "Assamese"],
"ac": ["Ástralic", "Australian"],
"av": ["авар мацӀ", "Avaric"],
"ae": ["avesta", "Avestan"],
"ay": ["aymar aru", "Aymara"],
"az": ["azərbaycan dili", "Azerbaijani"],
"bm": ["bamanankan", "Bambara"],
"ba": ["башҡорт теле", "Bashkir"],
"eu": ["euskara", "Basque"],
"be": ["беларуская мова", "Belarusian"],
"bn": ["বাংলা", "Bengali"],
"bh": ["भोजपुरी", "Bihari"],
"bi": ["Bislama", "Bislama"],
"bs": ["bosanski jezik", "Bosnian"],
"br": ["brezhoneg", "Breton"],
"bg": ["български език", "Bulgarian"],
"my": ["ဗမာစာ", "Burmese"],
"ca": ["català", "Catalan"],
"ch": ["Chamoru", "Chamorro"],
"ce": ["нохчийн мотт", "Chechen"],
"ny": ["chiCheŵa", "Chichewa"],
"zh": ["中文", "Chinese"],
"cv": ["чӑваш чӗлхи", "Chuvash"],
"kw": ["Kernewek", "Cornish"],
"co": ["corsu", "Corsican"],
"cr": ["ᓀᐦᐃᔭᐍᐏᐣ", "Cree"],
"hr": ["hrvatski jezik", "Croatian"],
"cs": ["čeština", "Czech"],
"da": ["dansk", "Danish"],
"dv": ["ދިވެހި", "Divehi"],
"nl": ["Nederlands", "Dutch"],
"dz": ["རྫོང་ཁ", "Dzongkha"],
"en": ["English", "English"],
"eo": ["Esperanto", "Esperanto"],
"et": ["eesti", "Estonian"],
"ee": ["Eʋegbe", "Ewe"],
"fo": ["føroyskt", "Faroese"],
"fj": ["vosa Vakaviti", "Fijian"],
"fi": ["suomi", "Finnish"],
"fr": ["français", "French"],
"ff": ["Fulfulde", "Fula"],
"gl": ["galego", "Galician"],
"ka": ["ქართული", "Georgian"],
"de": ["Deutsch", "German"],
"el": ["ελληνικά", "Greek"],
"gn": ["Avañe'ẽ", "Guaraní"],
"gu": ["ગુજરાતી", "Gujarati"],
"ht": ["Kreyòl ayisyen", "Haitian"],
"ha": ["هَوُسَ", "Hausa"],
"he": ["עברית", "Hebrew"],
"hz": ["Otjiherero", "Herero"],
"hi": ["हिन्दी", "Hindi"],
"ho": ["Hiri Motu", "Hiri Motu"],
"hu": ["magyar", "Hungarian"],
"ia": ["Interlingua", "Interlingua"],
"ie": ["Interlingue", "Interlingue"],
"ga": ["Gaeilge", "Irish"],
"ig": ["Asụsụ Igbo", "Igbo"],
"ik": ["Iñupiaq", "Inupiaq"],
"io": ["Ido", "Ido"],
"is": ["Íslenska", "Icelandic"],
"it": ["italiano", "Italian"],
"iu": ["ᐃᓄᒃᑎᑐᑦ", "Inuktitut"],
"ja": ["日本語", "Japanese"],
"jv": ["basa Jawa", "Javanese"],
"kl": ["kalaallisut", "Greenlandic"],
"kn": ["ಕನ್ನಡ", "Kannada"],
"kr": ["Kanuri", "Kanuri"],
"ks": ["कश्मीरी", "Kashmiri"],
"kk": ["қазақ тілі", "Kazakh"],
"km": ["ខ្មែរ", "Khmer"],
"ki": ["Gĩkũyũ", "Kikuyu"],
"rw": ["Ikinyarwanda", "Kinyarwanda"],
"ky": ["Кыргызча", "Kyrgyz"],
"kv": ["коми кыв", "Komi"],
"kg": ["Kikongo", "Kongo"],
"ko": ["한국어", "Korean"],
"ku": ["Kurdî", "Kurdish"],
"kj": ["Kuanyama", "Kwanyama"],
"la": ["lingua latina", "Latin"],
"lb": ["Lëtzebuergesch", "Luxembourgish"],
"lg": ["Luganda", "Ganda"],
"li": ["Limburgs", "Limburgish"],
"ln": ["Lingála", "Lingala"],
"lo": ["ພາສາລາວ", "Lao"],
"lt": ["lietuvių kalba", "Lithuanian"],
"lu": ["Tshiluba", "Luba-Katanga"],
"lv": ["latviešu valoda", "Latvian"],
"gv": ["Gaelg", "Manx"],
"mk": ["македонски јазик", "Macedonian"],
"mg": ["fiteny malagasy", "Malagasy"],
"ms": ["بهاس ملايو‎", "Malay"],
"ml": ["മലയാളം", "Malayalam"],
"mt": ["Malti", "Maltese"],
"mi": ["te reo Māori", "Māori"],
"mr": ["मराठी", "Marathi"],
"mh": ["Kajin M̧ajeļ", "Marshallese"],
"mn": ["Монгол хэл", "Mongolian"],
"na": ["Ekakairũ Naoero", "Nauru"],
"nv": ["Diné bizaad", "Navajo"],
"nd": ["isiNdebele", "Northern Ndebele"],
"ne": ["नेपाली", "Nepali"],
"ng": ["Owambo", "Ndonga"],
"no": ["Norsk", "Norwegian"],
"ii": ["ꆈꌠ꒿", "Nuosu"],
"nr": ["isiNdebele", "Southern Ndebele"],
"oc": ["occitan", "Occitan"],
"oj": ["ᐊᓂᔑᓈᐯᒧᐎᓐ", "Ojibwe"],
"om": ["Afaan Oromoo", "Oromo"],
"or": ["ଓଡ଼ିଆ", "Oriya"],
"os": ["ирон æвзаг", "Ossetian"],
"pa": ["ਪੰਜਾਬੀ", "Punjabi"],
"pi": ["पाऴि", "Pāli"],
"fa": ["فارسی", "Persian"],
"pl": ["polszczyzna", "Polish"],
"ps": ["پښتو", "Pashto"],
"pt": ["português", "Portuguese"],
"qu": ["Runa Simi", "Quechua"],
"rm": ["rumantsch grischun", "Romansh"],
"rn": ["Ikirundi", "Kirundi"],
"ro": ["limba română", "Romanian"],
"ru": ["Русский", "Russian"],
"sc": ["sardu", "Sardinian"],
"sd": ["सिन्धी", "Sindhi"],
"se": ["Davvisámegiella", "Northern Sami"],
"sm": ["gagana fa'a Samoa", "Samoan"],
"sg": ["yângâ tî sängö", "Sango"],
"sr": ["српски језик", "Serbian"],
"gd": ["Gàidhlig", "Gaelic"],
"sn": ["chiShona", "Shona"],
"si": ["සිංහල", "Sinhalese"],
"sk": ["slovenčina", "Slovak"],
"sl": ["slovenščina", "Slovene"],
"so": ["Soomaaliga", "Somali"],
"st": ["Sesotho", "Southern Sotho"],
"es": ["español", "Spanish"],
"su": ["Basa Sunda", "Sundanese"],
"sw": ["Kiswahili", "Swahili"],
"ss": ["SiSwati", "Swati"],
"sv": ["svenska", "Swedish"],
"ta": ["தமிழ்", "Tamil"],
"te": ["తెలుగు", "Telugu"],
"tg": ["тоҷикӣ", "Tajik"],
"th": ["ไทย", "Thai"],
"ti": ["ትግርኛ", "Tigrinya"],
"bo": ["བོད་ཡིག", "Tibetan"],
"tk": ["Түркмен", "Turkmen"],
"tl": ["ᜏᜒᜃᜅ᜔ ᜆᜄᜎᜓᜄ᜔", "Tagalog"],
"tn": ["Setswana", "Tswana"],
"to": ["faka Tonga", "Tonga"],
"tr": ["Türkçe", "Turkish"],
"ts": ["Xitsonga", "Tsonga"],
"tt": ["татар теле", "Tatar"],
"ty": ["Reo Tahiti", "Tahitian"],
"ug": ["ئۇيغۇرچە‎", "Uyghur"],
"uk": ["українська мова", "Ukrainian"],
"ur": ["اردو", "Urdu"],
"uz": ["Oʻzbek", "Uzbek"],
"ve": ["Tshivenḓa", "Venda"],
"vi": ["Việt Nam", "Vietnamese"],
"vo": ["Volapük", "Volapük"],
"wa": ["walon", "Walloon"],
"cy": ["Cymraeg", "Welsh"],
"wo": ["Wollof", "Wolof"],
"fy": ["Frysk", "Western Frisian"],
"xh": ["isiXhosa", "Xhosa"],
"yi": ["ייִדיש", "Yiddish"],
"yo": ["Yorùbá", "Yoruba"],
"za": ["Saɯ cueŋƅ", "Zhuang"],
"zu": ["isiZulu", "Zulu"]
}

139
i18n/pl.json Normal file
View File

@@ -0,0 +1,139 @@
{
"en": "pl",
"Paste does not exist, has expired or has been deleted.":
"Wklejka nie istnieje, wygasła albo została usunięta.",
"ZeroBin requires php 5.2.6 or above to work. Sorry.":
"ZeroBin wymaga PHP w wersji 5.2.6 lub nowszej, sorry.",
"ZeroBin requires configuration section [%s] to be present in configuration file.":
"ZeroBin wymaga obecności sekcji [%s] w pliku konfiguracyjnym.",
"Please wait %d seconds between each post.":
"Poczekaj %d sekund pomiędzy każdą wklejką.",
"Paste is limited to %s of encrypted data.":
"Wklejka jest limitowana do %s zaszyfrowanych danych.",
"Invalid data.":
"Nieprawidłowe dane.",
"You are unlucky. Try again.":
"Miałeś pecha. Spróbuj ponownie.",
"Error saving comment. Sorry.":
"Błąd przy zapisywaniu komentarza, sorry.",
"Error saving paste. Sorry.":
"Błąd przy zapisywaniu wklejki, sorry.",
"Invalid paste ID.":
"Nieprawidłowe ID wklejki.",
"Paste is not of burn-after-reading type.":
"Ta wklejka nie ulega autodestrukcji po przeczytaniu.",
"Wrong deletion token. Paste was not deleted.":
"Nieprawidłowy token usuwania. Wklejka nie została usunięta.",
"Paste was properly deleted.":
"Wklejka usunięta poprawnie.",
"ZeroBin": "ZeroBin",
"ZeroBin is a minimalist, opensource 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/elrido/ZeroBin/wiki\">project page</a>.":
"ZeroBin jest minimalistycznym, otwartoźródłowym serwisem typu pastebin, w którym serwer nie ma jakichkolwiek informacji o tym, co jest wklejane. Dane są szyfrowane i deszyfrowane <i>w przeglądarce</i> z użyciem 256-bitowego klucza AES. Więcej informacji na <a href=\"https://github.com/elrido/ZeroBin/wiki\">stronie projektu</a>.",
"Because ignorance is bliss":
"Ponieważ ignorancja jest cnotą",
"Javascript is required for ZeroBin to work.<br />Sorry for the inconvenience.":
"Do działania ZeroBina jest wymagany JavaScript. Przepraszamy za tę niedogodność.",
"ZeroBin requires a modern browser to work.":
"ZeroBin wymaga do działania nowoczesnej przeglądarki.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Cały czas używasz Internet Explorera? Zrób sobie przysługę, przesiądź się na nowoczesną przeglądarkę:",
"New":
"Nowa",
"Send":
"Wyślij",
"Clone":
"Sklonuj",
"Raw text":
"Czysty tekst",
"Expires":
"Wygasa",
"Burn after reading":
"Zniszcz po przeczytaniu",
"Open discussion":
"Otwarta dyskusja",
"Password (recommended)":
"Hasło (zalecane)",
"Discussion":
"Dyskusja",
"Toggle navigation":
"Przełącz nawigację",
"%d seconds": ["%d second", "%d second", "%d second"],
"%d minutes": ["%d minut", "%d minut", "%d minut"],
"%d hours": ["%d godzina", "%d godzina", "%d godzina"],
"%d days": ["%d dzień", "%d dzień", "%d dzień"],
"%d weeks": ["%d tydzień", "%d tydzień", "%d tydzień"],
"%d months": ["%d miesiąc", "%d miesiąc", "%d miesiąc"],
"%d years": ["%d rok", "%d rok", "%d rok"],
"Never":
"Nigdy",
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.":
"Notka: To jest usługa testowa. Dane mogą zostać usunięte w dowolnym momencie. Kociątka umrą, jeśli nadużyjesz tej usługi.",
"This document will expire in %d seconds.":
["This document will expire in %d second.", "This document will expire in %d seconds."],
"This document will expire in %d minutes.":
["This document will expire in %d minute.", "This document will expire in %d minutes."],
"This document will expire in %d hours.":
["This document will expire in %d hour.", "This document will expire in %d hours."],
"This document will expire in %d days.":
["This document will expire in %d day.", "This document will expire in %d days."],
"This document will expire in %d months.":
["This document will expire in %d month.", "This document will expire in %d months."],
"Please enter the password for this paste:":
"Please enter the password for this paste:",
"Could not decrypt data (Wrong key?)":
"Could not decrypt data (Wrong key?)",
"Could not delete the paste, it was not stored in burn after reading mode.":
"Could not delete the paste, it was not stored in burn after reading mode.",
"FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.":
"FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.",
"Could not decrypt comment; Wrong key?":
"Could not decrypt comment; Wrong key?",
"Reply":
"Reply",
"Anonymous":
"Anonymous",
"Anonymous avatar (Vizhash of the IP address)":
"Anonymous avatar (Vizhash of the IP address)",
"Add comment":
"Add comment",
"Optional nickname...":
"Optional nickname...",
"Post comment":
"Post comment",
"Sending comment...":
"Sending comment...",
"Comment posted.":
"Comment posted.",
"Could not refresh display: %s":
"Could not refresh display: %s",
"unknown status":
"unknown status",
"server error or not responding":
"server error or not responding",
"Could not post comment: %s":
"Could not post comment: %s",
"Sending paste (Please move your mouse for more entropy)...":
"Sending paste (Please move your mouse for more entropy)...",
"Sending paste...":
"Sending paste...",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>":
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>",
"Delete data":
"Delete data",
"Could not create paste: %s":
"Could not create paste: %s",
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)":
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)",
"Format": "Format",
"Plain Text": "Plain Text",
"Source Code": "Source Code",
"Markdown": "Markdown",
"Download attachment": "Download attachment",
"Cloned file attached.": "Cloned file attached.",
"Attach a file": "Attach a file",
"Remove attachment": "Remove attachment",
"Your browser does not support uploading encrypted files. Please use a newer browser.":
"Your browser does not support uploading encrypted files. Please use a newer browser.",
"Invalid attachment.": "Invalid attachment.",
"Options": "Options"
}

View File

@@ -7,11 +7,12 @@
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.20
* @version 0.21
*/
// change this, if your php files and data is outside of your webservers document root
define('PATH', '');
define('PUBLIC_PATH', dirname(__FILE__));
require PATH . 'lib/auto.php';
new zerobin;

1296
js/showdown.js Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -84,7 +84,7 @@ class RainTPL{
/**
* Check template
*
*
* true: checks template update time, if changed it compile them
* false: loads the compiled template. Set false if server doesn't have write permission for cache_directory.
*
@@ -133,7 +133,7 @@ class RainTPL{
*
* @var array
*/
protected $tpl = array(); //
protected $tpl = array(); //
/**
* static cache enabled / disabled
@@ -154,7 +154,7 @@ class RainTPL{
*
* @var array the file
*/
protected static $config_name_sum = array();
protected static $config_name_sum = array();
// -------------------------
@@ -207,41 +207,41 @@ class RainTPL{
}
// Cache is off and, return_string is false
// Rain just echo the template
// Rain just echo the template
if( !$this->cache && !$return_string ){
extract( $this->var );
include $this->tpl['compiled_filename'];
unset( $this->tpl );
}
if( !$this->cache && !$return_string ){
extract( $this->var );
include $this->tpl['compiled_filename'];
unset( $this->tpl );
}
// cache or return_string are enabled
// rain get the output buffer to save the output in the cache or to return it as string
// rain get the output buffer to save the output in the cache or to return it as string
else{
else{
//----------------------
// get the output buffer
//----------------------
ob_start();
extract( $this->var );
include $this->tpl['compiled_filename'];
$raintpl_contents = ob_get_clean();
//----------------------
//----------------------
// get the output buffer
//----------------------
ob_start();
extract( $this->var );
include $this->tpl['compiled_filename'];
$raintpl_contents = ob_get_clean();
//----------------------
// save the output in the cache
if( $this->cache )
file_put_contents( $this->tpl['cache_filename'], "<?php if(!class_exists('raintpl')){exit;}?>" . $raintpl_contents );
// save the output in the cache
if( $this->cache )
file_put_contents( $this->tpl['cache_filename'], "<?php if(!class_exists('raintpl')){exit;}?>" . $raintpl_contents );
// free memory
unset( $this->tpl );
// free memory
unset( $this->tpl );
// return or print the template
if( $return_string ) return $raintpl_contents; else echo $raintpl_contents;
// return or print the template
if( $return_string ) return $raintpl_contents; else echo $raintpl_contents;
}
}
}
@@ -258,15 +258,15 @@ class RainTPL{
*/
public function cache( $tpl_name, $expire_time = self::CACHE_EXPIRE_TIME, $cache_id = '' ){
// set the cache_id
$this->cache_id = $cache_id;
// set the cache_id
$this->cache_id = $cache_id;
if( !$this->check_template( $tpl_name ) && file_exists( $this->tpl['cache_filename'] ) && ( time() - filemtime( $this->tpl['cache_filename'] ) < $expire_time ) )
return substr( file_get_contents( $this->tpl['cache_filename'] ), 43 );
else{
//delete the cache of the selected template
if (file_exists($this->tpl['cache_filename']))
unlink($this->tpl['cache_filename'] );
if (file_exists($this->tpl['cache_filename']))
unlink($this->tpl['cache_filename'] );
$this->cache = true;
}
}
@@ -287,8 +287,8 @@ class RainTPL{
self::configure( $key, $value );
else if( property_exists( __CLASS__, $setting ) ){
self::$$setting = $value;
self::$config_name_sum[ $setting ] = $value; // take trace of all config
}
self::$config_name_sum[ $setting ] = $value; // take trace of all config
}
}
@@ -305,13 +305,13 @@ class RainTPL{
if( !isset($this->tpl['checked']) ){
$tpl_basename = basename( $tpl_name ); // template basename
$tpl_basedir = strpos($tpl_name,"/") ? dirname($tpl_name) . '/' : null; // template basedirectory
$tpl_dir = PATH . self::$tpl_dir . $tpl_basedir; // template directory
$this->tpl['tpl_filename'] = $tpl_dir . $tpl_basename . '.' . self::$tpl_ext; // template filename
$temp_compiled_filename = PATH . self::$cache_dir . $tpl_basename . "." . md5( $tpl_dir . serialize(self::$config_name_sum));
$this->tpl['compiled_filename'] = $temp_compiled_filename . '.rtpl.php'; // cache filename
$this->tpl['cache_filename'] = $temp_compiled_filename . '.s_' . $this->cache_id . '.rtpl.php'; // static cache filename
$tpl_basename = basename( $tpl_name ); // template basename
$tpl_basedir = strpos($tpl_name,"/") ? dirname($tpl_name) . '/' : null; // template basedirectory
$tpl_dir = PATH . self::$tpl_dir . $tpl_basedir; // template directory
$this->tpl['tpl_filename'] = $tpl_dir . $tpl_basename . '.' . self::$tpl_ext; // template filename
$temp_compiled_filename = PATH . self::$cache_dir . $tpl_basename . "." . md5( $tpl_dir . serialize(self::$config_name_sum));
$this->tpl['compiled_filename'] = $temp_compiled_filename . '.rtpl.php'; // cache filename
$this->tpl['cache_filename'] = $temp_compiled_filename . '.s_' . $this->cache_id . '.rtpl.php'; // static cache filename
// if the template doesn't exsist throw an error
if( self::$check_template_update && !file_exists( $this->tpl['tpl_filename'] ) ){
@@ -329,6 +329,7 @@ class RainTPL{
}
/**
* execute stripslaches() on the xml block. Invoqued by preg_replace_callback function below
*
@@ -337,9 +338,11 @@ class RainTPL{
* @return string
*/
protected function xml_reSubstitution($capture) {
return "<?php echo '<?xml ".stripslashes($capture[1])." ?>'; ?>";
return "<?php echo '<?xml ".stripslashes($capture[1])." ?>'; ?>";
}
/**
* Compile and write the compiled template file
*
@@ -398,20 +401,20 @@ class RainTPL{
protected function compileTemplate( $template_code, $tpl_basedir ){
//tag list
$tag_regexp = array( 'loop' => '(\{loop(?: name){0,1}="\${0,1}[^"]*"\})',
'loop_close' => '(\{\/loop\})',
'if' => '(\{if(?: condition){0,1}="[^"]*"\})',
'elseif' => '(\{elseif(?: condition){0,1}="[^"]*"\})',
'else' => '(\{else\})',
'if_close' => '(\{\/if\})',
'function' => '(\{function="[^"]*"\})',
'noparse' => '(\{noparse\})',
'noparse_close'=> '(\{\/noparse\})',
'ignore' => '(\{ignore\}|\{\*)',
'ignore_close' => '(\{\/ignore\}|\*\})',
'include' => '(\{include="[^"]*"(?: cache="[^"]*")?\})',
'template_info'=> '(\{\$template_info\})',
'function' => '(\{function="(\w*?)(?:.*?)"\})'
$tag_regexp = array( 'loop' => '(\{loop(?: name){0,1}="\${0,1}[^"]*"\})',
'loop_close' => '(\{\/loop\})',
'if' => '(\{if(?: condition){0,1}="[^"]*"\})',
'elseif' => '(\{elseif(?: condition){0,1}="[^"]*"\})',
'else' => '(\{else\})',
'if_close' => '(\{\/if\})',
'function' => '(\{function="[^"]*"\})',
'noparse' => '(\{noparse\})',
'noparse_close'=> '(\{\/noparse\})',
'ignore' => '(\{ignore\}|\{\*)',
'ignore_close' => '(\{\/ignore\}|\*\})',
'include' => '(\{include="[^"]*"(?: cache="[^"]*")?\})',
'template_info'=> '(\{\$template_info\})',
'function' => '(\{function="(\w*?)(?:.*?)"\})'
);
$tag_regexp = "/" . join( "|", $tag_regexp ) . "/";
@@ -444,35 +447,35 @@ class RainTPL{
//variables initialization
$compiled_code = $open_if = $comment_is_open = $ignore_is_open = null;
$loop_level = 0;
$loop_level = 0;
//read all parsed code
while( $html = array_shift( $parsed_code ) ){
//read all parsed code
while( $html = array_shift( $parsed_code ) ){
//close ignore tag
//close ignore tag
if( !$comment_is_open && ( strpos( $html, '{/ignore}' ) !== FALSE || strpos( $html, '*}' ) !== FALSE ) )
$ignore_is_open = false;
$ignore_is_open = false;
//code between tag ignore id deleted
elseif( $ignore_is_open ){
//ignore the code
}
//code between tag ignore id deleted
elseif( $ignore_is_open ){
//ignore the code
}
//close no parse tag
//close no parse tag
elseif( strpos( $html, '{/noparse}' ) !== FALSE )
$comment_is_open = false;
$comment_is_open = false;
//code between tag noparse is not compiled
elseif( $comment_is_open )
$compiled_code .= $html;
//code between tag noparse is not compiled
elseif( $comment_is_open )
$compiled_code .= $html;
//ignore
//ignore
elseif( strpos( $html, '{ignore}' ) !== FALSE || strpos( $html, '{*' ) !== FALSE )
$ignore_is_open = true;
$ignore_is_open = true;
//noparse
elseif( strpos( $html, '{noparse}' ) !== FALSE )
$comment_is_open = true;
//noparse
elseif( strpos( $html, '{noparse}' ) !== FALSE )
$comment_is_open = true;
//include tag
elseif( preg_match( '/\{include="([^"]*)"(?: cache="([^"]*)"){0,1}\}/', $html, $code ) ){
@@ -509,19 +512,19 @@ class RainTPL{
}
//loop
//loop
elseif( preg_match( '/\{loop(?: name){0,1}="\${0,1}([^"]*)"\}/', $html, $code ) ){
//increase the loop counter
$loop_level++;
//increase the loop counter
$loop_level++;
//replace the variable in the loop
$var = $this->var_replace( '$' . $code[ 1 ], $tag_left_delimiter=null, $tag_right_delimiter=null, $php_left_delimiter=null, $php_right_delimiter=null, $loop_level-1 );
//loop variables
$counter = "\$counter$loop_level"; // count iteration
$key = "\$key$loop_level"; // key
$value = "\$value$loop_level"; // value
$counter = "\$counter$loop_level"; // count iteration
$key = "\$key$loop_level"; // key
$value = "\$value$loop_level"; // value
//loop code
$compiled_code .= "<?php $counter=-1; if( isset($var) && is_array($var) && sizeof($var) ) foreach( $var as $key => $value ){ $counter++; ?>";
@@ -653,6 +656,7 @@ class RainTPL{
}
/**
* Reduce a path
*
@@ -672,7 +676,7 @@ class RainTPL{
/**
* replace the path of image src, link href and a href
*
*
* url => template_dir/url
* url# => url
* http://url => http://url
@@ -728,8 +732,6 @@ class RainTPL{
/**
* replace constants
*
@@ -812,28 +814,28 @@ class RainTPL{
//if there's a function
if( $function_var ){
// check if there's a function or a static method and separate, function by parameters
// check if there's a function or a static method and separate, function by parameters
$function_var = str_replace("::", "@double_dot@", $function_var );
// get the position of the first :
if( $dot_position = strpos( $function_var, ":" ) ){
// get the position of the first :
if( $dot_position = strpos( $function_var, ":" ) ){
// get the function and the parameters
$function = substr( $function_var, 0, $dot_position );
$params = substr( $function_var, $dot_position+1 );
// get the function and the parameters
$function = substr( $function_var, 0, $dot_position );
$params = substr( $function_var, $dot_position+1 );
}
else{
}
else{
//get the function
$function = str_replace( "@double_dot@", "::", $function_var );
$params = null;
//get the function
$function = str_replace( "@double_dot@", "::", $function_var );
$params = null;
}
}
// replace back the @double_dot@ with ::
$function = str_replace( "@double_dot@", "::", $function );
$params = str_replace( "@double_dot@", "::", $params );
// replace back the @double_dot@ with ::
$function = str_replace( "@double_dot@", "::", $function );
$params = str_replace( "@double_dot@", "::", $params );
}
@@ -880,105 +882,105 @@ class RainTPL{
//all variables
if( preg_match_all( '/' . $tag_left_delimiter . '\$(\w+(?:\.\${0,1}[A-Za-z0-9_]+)*(?:(?:\[\${0,1}[A-Za-z0-9_]+\])|(?:\-\>\${0,1}[A-Za-z0-9_]+))*)(.*?)' . $tag_right_delimiter . '/', $html, $matches ) ){
for( $parsed=array(), $i=0, $n=count($matches[0]); $i<$n; $i++ )
$parsed[$matches[0][$i]] = array('var'=>$matches[1][$i],'extra_var'=>$matches[2][$i]);
for( $parsed=array(), $i=0, $n=count($matches[0]); $i<$n; $i++ )
$parsed[$matches[0][$i]] = array('var'=>$matches[1][$i],'extra_var'=>$matches[2][$i]);
foreach( $parsed as $tag => $array ){
foreach( $parsed as $tag => $array ){
//variable name ex: news.title
$var = $array['var'];
//variable name ex: news.title
$var = $array['var'];
//function and parameters associate to the variable ex: substr:0,100
$extra_var = $array['extra_var'];
//function and parameters associate to the variable ex: substr:0,100
$extra_var = $array['extra_var'];
// check if there's any function disabled by black_list
$this->function_check( $tag );
// check if there's any function disabled by black_list
$this->function_check( $tag );
$extra_var = $this->var_replace( $extra_var, null, null, null, null, $loop_level );
$extra_var = $this->var_replace( $extra_var, null, null, null, null, $loop_level );
// check if there's an operator = in the variable tags, if there's this is an initialization so it will not output any value
$is_init_variable = preg_match( "/^[a-z_A-Z\.\[\](\-\>)]*=[^=]*$/", $extra_var );
// check if there's an operator = in the variable tags, if there's this is an initialization so it will not output any value
$is_init_variable = preg_match( "/^[a-z_A-Z\.\[\](\-\>)]*=[^=]*$/", $extra_var );
//function associate to variable
$function_var = ( $extra_var and $extra_var[0] == '|') ? substr( $extra_var, 1 ) : null;
//function associate to variable
$function_var = ( $extra_var and $extra_var[0] == '|') ? substr( $extra_var, 1 ) : null;
//variable path split array (ex. $news.title o $news[title]) or object (ex. $news->title)
$temp = preg_split( "/\.|\[|\-\>/", $var );
//variable path split array (ex. $news.title o $news[title]) or object (ex. $news->title)
$temp = preg_split( "/\.|\[|\-\>/", $var );
//variable name
$var_name = $temp[ 0 ];
//variable name
$var_name = $temp[ 0 ];
//variable path
$variable_path = substr( $var, strlen( $var_name ) );
//variable path
$variable_path = substr( $var, strlen( $var_name ) );
//parentesis transform [ e ] in [" e in "]
$variable_path = str_replace( '[', '["', $variable_path );
$variable_path = str_replace( ']', '"]', $variable_path );
//parentesis transform [ e ] in [" e in "]
$variable_path = str_replace( '[', '["', $variable_path );
$variable_path = str_replace( ']', '"]', $variable_path );
//transform .$variable in ["$variable"] and .variable in ["variable"]
$variable_path = preg_replace('/\.(\${0,1}\w+)/', '["\\1"]', $variable_path );
//transform .$variable in ["$variable"] and .variable in ["variable"]
$variable_path = preg_replace('/\.(\${0,1}\w+)/', '["\\1"]', $variable_path );
// if is an assignment also assign the variable to $this->var['value']
if( $is_init_variable )
$extra_var = "=\$this->var['{$var_name}']{$variable_path}" . $extra_var;
// if is an assignment also assign the variable to $this->var['value']
if( $is_init_variable )
$extra_var = "=\$this->var['{$var_name}']{$variable_path}" . $extra_var;
//if there's a function
if( $function_var ){
//if there's a function
if( $function_var ){
// check if there's a function or a static method and separate, function by parameters
$function_var = str_replace("::", "@double_dot@", $function_var );
// check if there's a function or a static method and separate, function by parameters
$function_var = str_replace("::", "@double_dot@", $function_var );
// get the position of the first :
if( $dot_position = strpos( $function_var, ":" ) ){
// get the position of the first :
if( $dot_position = strpos( $function_var, ":" ) ){
// get the function and the parameters
$function = substr( $function_var, 0, $dot_position );
$params = substr( $function_var, $dot_position+1 );
// get the function and the parameters
$function = substr( $function_var, 0, $dot_position );
$params = substr( $function_var, $dot_position+1 );
}
else{
}
else{
//get the function
$function = str_replace( "@double_dot@", "::", $function_var );
$params = null;
//get the function
$function = str_replace( "@double_dot@", "::", $function_var );
$params = null;
}
}
// replace back the @double_dot@ with ::
$function = str_replace( "@double_dot@", "::", $function );
$params = str_replace( "@double_dot@", "::", $params );
}
else
$function = $params = null;
// replace back the @double_dot@ with ::
$function = str_replace( "@double_dot@", "::", $function );
$params = str_replace( "@double_dot@", "::", $params );
}
else
$function = $params = null;
//if it is inside a loop
if( $loop_level ){
//verify the variable name
if( $var_name == 'key' )
$php_var = '$key' . $loop_level;
elseif( $var_name == 'value' )
$php_var = '$value' . $loop_level . $variable_path;
elseif( $var_name == 'counter' )
$php_var = '$counter' . $loop_level;
else
$php_var = '$' . $var_name . $variable_path;
}else
$php_var = '$' . $var_name . $variable_path;
//if it is inside a loop
if( $loop_level ){
//verify the variable name
if( $var_name == 'key' )
$php_var = '$key' . $loop_level;
elseif( $var_name == 'value' )
$php_var = '$value' . $loop_level . $variable_path;
elseif( $var_name == 'counter' )
$php_var = '$counter' . $loop_level;
else
$php_var = '$' . $var_name . $variable_path;
}else
$php_var = '$' . $var_name . $variable_path;
// compile the variable for php
if( isset( $function ) )
$php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $php_var, $params ) )" : "$function( $php_var )" ) . $php_right_delimiter;
else
$php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . $php_var . $extra_var . $php_right_delimiter;
// compile the variable for php
if( isset( $function ) )
$php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $php_var, $params ) )" : "$function( $php_var )" ) . $php_right_delimiter;
else
$php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . $php_var . $extra_var . $php_right_delimiter;
$html = str_replace( $tag, $php_var, $html );
$html = str_replace( $tag, $php_var, $html );
}
}
}
}
return $html;
}
@@ -1015,6 +1017,8 @@ class RainTPL{
}
/**
* Prints debug info about exception or passes it further if debug is disabled.
*
@@ -1053,6 +1057,7 @@ class RainTPL{
}
/**
* Basic Rain tpl exception.
*/
@@ -1085,6 +1090,8 @@ class RainTpl_Exception extends Exception{
}
}
/**
* Exception thrown when template file does not exists.
*/
@@ -1155,4 +1162,18 @@ class RainTpl_SyntaxException extends RainTpl_Exception{
}
}
/**
* shorthand translate function for use in templates
*
* alias for i18n::translate()
*
* @access public
* @param string $messageId
* @param mixed $args one or multiple parameters injected into placeholders
* @return string
*/
function t() {
return call_user_func_array(array('i18n', 'translate'), func_get_args());
}
// -- end

View File

@@ -7,7 +7,7 @@
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.20
* @version 0.21.1
*/
spl_autoload_register('auto::loader');

View File

@@ -7,7 +7,7 @@
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.20
* @version 0.21.1
*/
/**
@@ -33,7 +33,36 @@ class filter
}
/**
* format a given number of bytes
* format a given time string into a human readable label (localized)
*
* accepts times in the format "[integer][time unit]"
*
* @access public
* @static
* @param string $time
* @throws Exception
* @return string
*/
public static function time_humanreadable($time)
{
if (preg_match('/^(\d+) *(\w+)$/', $time, $matches) !== 1) {
throw new Exception("Error parsing time format '$time'", 30);
}
switch ($matches[2]) {
case 'sec':
$unit = 'second';
break;
case 'min':
$unit = 'minute';
break;
default:
$unit = rtrim($matches[2], 's');
}
return i18n::_(array('%d ' . $unit, '%d ' . $unit . 's'), (int) $matches[1]);
}
/**
* format a given number of bytes in IEC 80000-13:2008 notation (localized)
*
* @access public
* @static
@@ -42,13 +71,13 @@ class filter
*/
public static function size_humanreadable($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;
while ( ( $size / 1024 ) >= 1 ) {
$size = $size / 1024;
$i++;
}
return number_format($size, ($i ? 2 : 0), '.', ' ') . ' ' . $iec[$i];
return number_format($size, ($i ? 2 : 0), '.', ' ') . ' ' . i18n::_($iec[$i]);
}
/**

369
lib/i18n.php Normal file
View File

@@ -0,0 +1,369 @@
<?php
/**
* ZeroBin
*
* a zero-knowledge paste bin
*
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.21.1
*/
/**
* i18n
*
* provides internationalization tools like translation, browser language detection, etc.
*/
class i18n
{
/**
* language
*
* @access protected
* @static
* @var string
*/
protected static $_language = 'en';
/**
* language labels
*
* @access protected
* @static
* @var array
*/
protected static $_languageLabels = array();
/**
* available languages
*
* @access protected
* @static
* @var array
*/
protected static $_availableLanguages = array();
/**
* path to language files
*
* @access protected
* @static
* @var string
*/
protected static $_path = '';
/**
* translation cache
*
* @access protected
* @static
* @var array
*/
protected static $_translations = array();
/**
* translate a string, alias for translate()
*
* @access public
* @static
* @param string $messageId
* @param mixed $args one or multiple parameters injected into placeholders
* @return string
*/
public static function _($messageId)
{
return call_user_func_array(array('i18n', 'translate'), func_get_args());
}
/**
* translate a string
*
* @access public
* @static
* @param string $messageId
* @param mixed $args one or multiple parameters injected into placeholders
* @return string
*/
public static function translate($messageId)
{
if (empty($messageId)) return $messageId;
if (count(self::$_translations) === 0) self::loadTranslations();
$messages = $messageId;
if (is_array($messageId))
{
$messageId = count($messageId) > 1 ? $messageId[1] : $messageId[0];
}
if (!array_key_exists($messageId, self::$_translations))
{
self::$_translations[$messageId] = $messages;
}
$args = func_get_args();
if (is_array(self::$_translations[$messageId]))
{
$number = (int) $args[1];
$key = self::_getPluralForm($number);
$max = count(self::$_translations[$messageId]) - 1;
if ($key > $max) $key = $max;
$args[0] = self::$_translations[$messageId][$key];
$args[1] = $number;
}
else
{
$args[0] = self::$_translations[$messageId];
}
return call_user_func_array('sprintf', $args);
}
/**
* loads translations
*
* From: http://stackoverflow.com/questions/3770513/detect-browser-language-in-php#3771447
*
* @access public
* @static
* @return void
*/
public static function loadTranslations()
{
$availableLanguages = self::getAvailableLanguages();
// check if the lang cookie was set and that language exists
if (array_key_exists('lang', $_COOKIE) && in_array($_COOKIE['lang'], $availableLanguages))
{
$match = $_COOKIE['lang'];
}
// find a translation file matching the browsers language preferences
else
{
$match = self::_getMatchingLanguage(
self::getBrowserLanguages(), $availableLanguages
);
}
// load translations
self::$_language = $match;
self::$_translations = ($match == 'en') ? array() : json_decode(
file_get_contents(self::_getPath($match . '.json')),
true
);
}
/**
* get list of available translations based on files found
*
* @access public
* @static
* @return array
*/
public static function getAvailableLanguages()
{
if (count(self::$_availableLanguages) == 0)
{
$i18n = dir(self::_getPath());
while (false !== ($file = $i18n->read()))
{
if (preg_match('/^([a-z]{2}).json$/', $file, $match) === 1)
{
self::$_availableLanguages[] = $match[1];
}
}
self::$_availableLanguages[] = 'en';
}
return self::$_availableLanguages;
}
/**
* detect the clients supported languages and return them ordered by preference
*
* From: http://stackoverflow.com/questions/3770513/detect-browser-language-in-php#3771447
*
* @access public
* @static
* @return array
*/
public static function getBrowserLanguages()
{
$languages = array();
if (array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER))
{
$languageRanges = explode(',', trim($_SERVER['HTTP_ACCEPT_LANGUAGE']));
foreach ($languageRanges as $languageRange) {
if (preg_match(
'/(\*|[a-zA-Z0-9]{1,8}(?:-[a-zA-Z0-9]{1,8})*)(?:\s*;\s*q\s*=\s*(0(?:\.\d{0,3})|1(?:\.0{0,3})))?/',
trim($languageRange), $match
))
{
if (!isset($match[2]))
{
$match[2] = '1.0';
}
else
{
$match[2] = (string) floatval($match[2]);
}
if (!isset($languages[$match[2]]))
{
$languages[$match[2]] = array();
}
$languages[$match[2]][] = strtolower($match[1]);
}
}
krsort($languages);
}
return $languages;
}
/**
* get currently loaded language
*
* @access public
* @static
* @return string
*/
public static function getLanguage()
{
return self::$_language;
}
/**
* get list of language labels
*
* Only for given language codes, otherwise all labels.
*
* @access public
* @static
* @param array $languages
* @return array
*/
public static function getLanguageLabels($languages = array())
{
$file = self::_getPath('languages.json');
if (count(self::$_languageLabels) == 0 && is_readable($file))
{
self::$_languageLabels = json_decode(file_get_contents($file), true);
}
if (count($languages) == 0) return self::$_languageLabels;
return array_intersect_key(self::$_languageLabels, array_flip($languages));
}
/**
* get language file path
*
* @access protected
* @static
* @param string $file
* @return string
*/
protected static function _getPath($file = '')
{
if (strlen(self::$_path) == 0)
{
self::$_path = PUBLIC_PATH . DIRECTORY_SEPARATOR . 'i18n';
}
return self::$_path . (strlen($file) ? DIRECTORY_SEPARATOR . $file : '');
}
/**
* determines the plural form to use based on current language and given number
*
* From: http://localization-guide.readthedocs.org/en/latest/l10n/pluralforms.html
*
* @access protected
* @static
* @param int $n
* @return int
*/
protected static function _getPluralForm($n)
{
switch (self::$_language) {
case 'fr':
return ($n > 1 ? 1 : 0);
case 'pl':
return ($n == 1 ? 0 : $n%10 >= 2 && $n %10 <=4 && ($n%100 < 10 || $n%100 >= 20) ? 1 : 2);
// en, de
default:
return ($n != 1 ? 1 : 0);
}
}
/**
* compares two language preference arrays and returns the preferred match
*
* From: http://stackoverflow.com/questions/3770513/detect-browser-language-in-php#3771447
*
* @access protected
* @static
* @param array $acceptedLanguages
* @param array $availableLanguages
* @return string
*/
protected static function _getMatchingLanguage($acceptedLanguages, $availableLanguages) {
$matches = array();
$any = false;
foreach ($acceptedLanguages as $acceptedQuality => $acceptedValues) {
$acceptedQuality = floatval($acceptedQuality);
if ($acceptedQuality === 0.0) continue;
foreach ($availableLanguages as $availableValue)
{
$availableQuality = 1.0;
foreach ($acceptedValues as $acceptedValue)
{
if ($acceptedValue === '*')
{
$any = true;
}
$matchingGrade = self::_matchLanguage($acceptedValue, $availableValue);
if ($matchingGrade > 0)
{
$q = (string) ($acceptedQuality * $availableQuality * $matchingGrade);
if (!isset($matches[$q]))
{
$matches[$q] = array();
}
if (!in_array($availableValue, $matches[$q]))
{
$matches[$q][] = $availableValue;
}
}
}
}
}
if (count($matches) === 0 && $any)
{
if (count($availableLanguages) > 0)
{
$matches['1.0'] = $availableLanguages;
}
}
if (count($matches) === 0)
{
return 'en';
}
krsort($matches);
$topmatches = current($matches);
return current($topmatches);
}
/**
* compare two language IDs and return the degree they match
*
* From: http://stackoverflow.com/questions/3770513/detect-browser-language-in-php#3771447
*
* @access protected
* @static
* @param string $a
* @param string $b
* @return float
*/
protected static function _matchLanguage($a, $b) {
$a = explode('-', $a);
$b = explode('-', $b);
for ($i=0, $n=min(count($a), count($b)); $i<$n; $i++)
{
if ($a[$i] !== $b[$i]) break;
}
return $i === 0 ? 0 : (float) $i / count($a);
}
}

View File

@@ -7,7 +7,7 @@
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.20
* @version 0.21.1
*/
/**

View File

@@ -7,7 +7,7 @@
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.20
* @version 0.21.1
*/
/**

View File

@@ -7,7 +7,7 @@
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.20
* @version 0.21.1
*/
/**

View File

@@ -7,7 +7,7 @@
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.20
* @version 0.21.1
*/
/**

View File

@@ -8,7 +8,7 @@
* @link http://sebsauvage.net/wiki/doku.php?id=php:vizhash_gd
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.0.4 beta ZeroBin 0.20
* @version 0.0.4 beta ZeroBin 0.21.1
*/
/**

View File

@@ -7,7 +7,7 @@
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.20
* @version 0.21.1
*/
/**
@@ -22,7 +22,7 @@ class zerobin
*
* @const string
*/
const VERSION = '0.20';
const VERSION = '0.21.1';
/**
* show the same error message if the paste expired or does not exist
@@ -49,6 +49,14 @@ class zerobin
*/
private $_data = '';
/**
* formatter
*
* @access private
* @var string
*/
private $_formatter = 'plaintext';
/**
* error message
*
@@ -93,7 +101,7 @@ class zerobin
{
if (version_compare(PHP_VERSION, '5.2.6') < 0)
{
throw new Exception('ZeroBin requires php 5.2.6 or above to work. Sorry.', 1);
throw new Exception(i18n::_('ZeroBin requires php 5.2.6 or above to work. Sorry.'), 1);
}
// in case stupid admin has left magic_quotes enabled in php.ini
@@ -108,9 +116,12 @@ class zerobin
$this->_init();
// create new paste or comment
if (!empty($_POST['data']))
if (
(array_key_exists('data', $_POST) && !empty($_POST['data'])) ||
(array_key_exists('attachment', $_POST) && !empty($_POST['attachment']))
)
{
$this->_create($_POST['data']);
$this->_create();
}
// delete an existing paste
elseif (!empty($_GET['deletetoken']) && !empty($_GET['pasteid']))
@@ -156,7 +167,7 @@ class zerobin
$this->_conf = parse_ini_file(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini', true);
foreach (array('main', 'model') as $section) {
if (!array_key_exists($section, $this->_conf)) {
throw new Exception("ZeroBin requires configuration section [$section] to be present in configuration file.", 2);
throw new Exception(i18n::_('ZeroBin requires configuration section [%s] to be present in configuration file.', $section), 2);
}
}
$this->_model = $this->_conf['model']['class'];
@@ -183,71 +194,98 @@ class zerobin
/**
* Store new paste or comment
*
* POST contains:
* data (mandatory) = json encoded SJCL encrypted text (containing keys: iv,salt,ct)
* POST contains one or both:
* data = json encoded SJCL encrypted text (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
* attachment = json encoded SJCL encrypted text (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
*
* All optional data will go to meta information:
* expire (optional) = expiration delay (never,5min,10min,1hour,1day,1week,1month,1year,burn) (default:never)
* formatter (optional) = format to display the paste as (plaintext,syntaxhighlighting,markdown) (default:syntaxhighlighting)
* burnafterreading (optional) = if this paste may only viewed once ? (0/1) (default:0)
* opendiscusssion (optional) = is the discussion allowed on this paste ? (0/1) (default:0)
* nickname (optional) = in discussion, encoded SJCL encrypted text nickname of author of comment (containing keys: iv,salt,ct)
* attachmentname = json encoded SJCL encrypted text (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
* nickname (optional) = in discussion, encoded SJCL encrypted text nickname of author of comment (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
* parentid (optional) = in discussion, which comment this comment replies to.
* pasteid (optional) = in discussion, which paste this comment belongs to.
*
* @access private
* @param string $data
* @return string
*/
private function _create($data)
private function _create()
{
$error = false;
$has_attachment = array_key_exists('attachment', $_POST);
$has_attachmentname = $has_attachment && array_key_exists('attachmentname', $_POST) && !empty($_POST['attachmentname']);
$data = array_key_exists('data', $_POST) ? $_POST['data'] : '';
$attachment = $has_attachment ? $_POST['attachment'] : '';
$attachmentname = $has_attachmentname ? $_POST['attachmentname'] : '';
// Make sure last paste from the IP address was more than X seconds ago.
trafficlimiter::setLimit($this->_conf['traffic']['limit']);
trafficlimiter::setPath($this->_conf['traffic']['dir']);
if (!trafficlimiter::canPass($_SERVER['REMOTE_ADDR']))
$ipKey = 'REMOTE_ADDR';
if (array_key_exists('header', $this->_conf['traffic']))
{
$this->_return_message(
1,
'Please wait ' .
$this->_conf['traffic']['limit'] .
' seconds between each post.'
);
return;
$header = 'HTTP_' . $this->_conf['traffic']['header'];
if (array_key_exists($header, $_SERVER) && !empty($_SERVER[$header]))
{
$ipKey = $header;
}
}
if (!trafficlimiter::canPass($_SERVER[$ipKey])) return $this->_return_message(
1,
i18n::_(
'Please wait %d seconds between each post.',
$this->_conf['traffic']['limit']
)
);
// Make sure content is not too big.
$sizelimit = (int) $this->_getMainConfig('sizelimit', 2097152);
if (strlen($data) > $sizelimit)
{
$this->_return_message(
1,
'Paste is limited to ' .
filter::size_humanreadable($sizelimit) .
' of encrypted data.'
);
return;
}
if (
strlen($data) + strlen($attachment) + strlen($attachmentname) > $sizelimit
) return $this->_return_message(
1,
i18n::_(
'Paste is limited to %s of encrypted data.',
filter::size_humanreadable($sizelimit)
)
);
// Make sure format is correct.
if (!sjcl::isValid($data)) return $this->_return_message(1, 'Invalid data.');
// Make sure attachments are enabled and format is correct.
if($has_attachment)
{
if (
!$this->_getMainConfig('fileupload', false) ||
!sjcl::isValid($attachment) ||
!($has_attachmentname && sjcl::isValid($attachmentname))
) return $this->_return_message(1, 'Invalid attachment.');
}
// Read additional meta-information.
$meta=array();
$meta = array();
// Read expiration date
if (!empty($_POST['expire']))
if (array_key_exists('expire', $_POST) && !empty($_POST['expire']))
{
$selected_expire = (string) $_POST['expire'];
if (array_key_exists($selected_expire, $this->_conf['expire_options'])) {
if (array_key_exists($selected_expire, $this->_conf['expire_options']))
{
$expire = $this->_conf['expire_options'][$selected_expire];
} else {
}
else
{
$expire = $this->_conf['expire_options'][$this->_conf['expire']['default']];
}
if ($expire > 0) $meta['expire_date'] = time() + $expire;
}
// Destroy the paste when it is read.
if (!empty($_POST['burnafterreading']))
if (array_key_exists('burnafterreading', $_POST) && !empty($_POST['burnafterreading']))
{
$burnafterreading = $_POST['burnafterreading'];
if ($burnafterreading !== '0')
@@ -258,7 +296,11 @@ class zerobin
}
// Read open discussion flag.
if ($this->_conf['main']['discussion'] && !empty($_POST['opendiscussion']))
if (
$this->_getMainConfig('discussion', true) &&
array_key_exists('opendiscussion', $_POST) &&
!empty($_POST['opendiscussion'])
)
{
$opendiscussion = $_POST['opendiscussion'];
if ($opendiscussion !== '0')
@@ -268,6 +310,17 @@ class zerobin
}
}
// Read formatter flag.
if (array_key_exists('formatter', $_POST) && !empty($_POST['formatter']))
{
$formatter = $_POST['formatter'];
if (!array_key_exists($formatter, $this->_conf['formatter_options']))
{
$formatter = $this->_getMainConfig('defaultformatter', 'plaintext');
}
$meta['formatter'] = $formatter;
}
// You can't have an open discussion on a "Burn after reading" paste:
if (isset($meta['burnafterreading'])) unset($meta['opendiscussion']);
@@ -296,11 +349,7 @@ class zerobin
}
}
if ($error)
{
$this->_return_message(1, 'Invalid data.');
return;
}
if ($error) return $this->_return_message(1, 'Invalid data.');
// Add post date to meta.
$meta['postdate'] = time();
@@ -325,11 +374,7 @@ class zerobin
if (
!filter::is_valid_paste_id($pasteid) ||
!filter::is_valid_paste_id($parentid)
)
{
$this->_return_message(1, 'Invalid data.');
return;
}
) return $this->_return_message(1, 'Invalid data.');
// Comments do not expire (it's the paste that expires)
unset($storage['expire_date']);
@@ -338,43 +383,26 @@ class zerobin
// Make sure paste exists.
if (
!$this->_model()->exists($pasteid)
)
{
$this->_return_message(1, 'Invalid data.');
return;
}
) return $this->_return_message(1, 'Invalid data.');
// Make sure the discussion is opened in this paste.
$paste = $this->_model()->read($pasteid);
if (
!$paste->meta->opendiscussion
)
{
$this->_return_message(1, 'Invalid data.');
return;
}
) return $this->_return_message(1, 'Invalid data.');
// Check for improbable collision.
if (
$this->_model()->existsComment($pasteid, $parentid, $dataid)
)
{
$this->_return_message(1, 'You are unlucky. Try again.');
return;
}
) return $this->_return_message(1, 'You are unlucky. Try again.');
// New comment
if (
$this->_model()->createComment($pasteid, $parentid, $dataid, $storage) === false
)
{
$this->_return_message(1, 'Error saving comment. Sorry.');
return;
}
) return $this->_return_message(1, 'Error saving comment. Sorry.');
// 0 = no error
$this->_return_message(0, $dataid);
return;
return $this->_return_message(0, $dataid);
}
// The user posts a standard paste.
else
@@ -382,19 +410,16 @@ class zerobin
// Check for improbable collision.
if (
$this->_model()->exists($dataid)
)
{
$this->_return_message(1, 'You are unlucky. Try again.');
return;
}
) return $this->_return_message(1, 'You are unlucky. Try again.');
// Add attachment and its name, if one was sent
if ($has_attachment) $storage['attachment'] = $attachment;
if ($has_attachmentname) $storage['attachmentname'] = $attachmentname;
// New paste
if (
$this->_model()->create($dataid, $storage) === false
) {
$this->_return_message(1, 'Error saving paste. Sorry.');
return;
}
) return $this->_return_message(1, 'Error saving paste. Sorry.');
// Generate the "delete" token.
// The token is the hmac of the pasteid signed with the server salt.
@@ -402,8 +427,7 @@ class zerobin
$deletetoken = hash_hmac('sha1', $dataid, serversalt::get());
// 0 = no error
$this->_return_message(0, $dataid, array('deletetoken' => $deletetoken));
return;
return $this->_return_message(0, $dataid, array('deletetoken' => $deletetoken));
}
}
@@ -536,6 +560,21 @@ class zerobin
$this->_model()->readComments($dataid)
);
}
// set formatter for for the view.
if (!property_exists($paste->meta, 'formatter'))
{
// support < 0.21 syntax highlighting
if (property_exists($paste->meta, 'syntaxcoloring') && $paste->meta->syntaxcoloring === true)
{
$paste->meta->formatter = 'syntaxhighlighting';
}
else
{
$paste->meta->formatter = $this->_getMainConfig('defaultformatter', 'plaintext');
}
}
$this->_data = json_encode($messages);
}
}
@@ -574,27 +613,43 @@ class zerobin
// label all the expiration options
$expire = array();
foreach ($this->_conf['expire_options'] as $key => $value) {
$expire[$key] = array_key_exists($key, $this->_conf['expire_labels']) ?
$this->_conf['expire_labels'][$key] :
$key;
foreach ($this->_conf['expire_options'] as $time => $seconds)
{
$expire[$time] = ($seconds == 0) ? i18n::_(ucfirst($time)): filter::time_humanreadable($time);
}
// translate all the formatter options
$formatters = array_map(array('i18n', 'translate'), $this->_conf['formatter_options']);
// set language cookie if that functionality was enabled
$languageselection = '';
if ($this->_getMainConfig('languageselection', false))
{
$languageselection = i18n::getLanguage();
setcookie('lang', $languageselection);
}
$page = new RainTPL;
$page::$path_replace = false;
// we escape it here because ENT_NOQUOTES can't be used in RainTPL templates
$page->assign('CIPHERDATA', htmlspecialchars($this->_data, ENT_NOQUOTES));
$page->assign('ERROR', $this->_error);
$page->assign('STATUS', $this->_status);
$page->assign('ERROR', i18n::_($this->_error));
$page->assign('STATUS', i18n::_($this->_status));
$page->assign('VERSION', self::VERSION);
$page->assign('DISCUSSION', $this->_getMainConfig('discussion', true));
$page->assign('OPENDISCUSSION', $this->_getMainConfig('opendiscussion', true));
$page->assign('SYNTAXHIGHLIGHTING', $this->_getMainConfig('syntaxhighlighting', true));
$page->assign('MARKDOWN', array_key_exists('markdown', $formatters));
$page->assign('SYNTAXHIGHLIGHTING', array_key_exists('syntaxhighlighting', $formatters));
$page->assign('SYNTAXHIGHLIGHTINGTHEME', $this->_getMainConfig('syntaxhighlightingtheme', ''));
$page->assign('NOTICE', $this->_getMainConfig('notice', ''));
$page->assign('FORMATTER', $formatters);
$page->assign('FORMATTERDEFAULT', $this->_getMainConfig('defaultformatter', 'plaintext'));
$page->assign('NOTICE', i18n::_($this->_getMainConfig('notice', '')));
$page->assign('BURNAFTERREADINGSELECTED', $this->_getMainConfig('burnafterreadingselected', false));
$page->assign('PASSWORD', $this->_getMainConfig('password', true));
$page->assign('FILEUPLOAD', $this->_getMainConfig('fileupload', false));
$page->assign('BASE64JSVERSION', $this->_getMainConfig('base64version', '2.1.9'));
$page->assign('LANGUAGESELECTION', $languageselection);
$page->assign('LANGUAGES', i18n::getLanguageLabels(i18n::getAvailableLanguages()));
$page->assign('EXPIRE', $expire);
$page->assign('EXPIREDEFAULT', $this->_conf['expire']['default']);
$page->draw($this->_getMainConfig('template', 'page'));
@@ -629,7 +684,7 @@ class zerobin
$result = array('status' => $status);
if ($status)
{
$result['message'] = $message;
$result['message'] = i18n::_($message);
}
else
{

View File

@@ -7,7 +7,7 @@
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.20
* @version 0.21.1
*/
/**

View File

@@ -7,7 +7,7 @@
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.20
* @version 0.21.1
*/
/**

View File

@@ -7,7 +7,7 @@
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.20
* @version 0.21.1
*/
/**
@@ -148,9 +148,22 @@ class zerobin_db extends zerobin_abstract
'postdate INT, ' .
'expiredate INT, ' .
'opendiscussion INT, ' .
'burnafterreading INT );'
'burnafterreading INT, ' .
'meta TEXT );'
);
}
// check if the meta column exists
else
{
try {
self::$_db->exec('SELECT meta FROM ' . self::$_prefix . 'paste LIMIT 1;');
} catch (PDOException $e) {
if ($e->getCode() == 'HY000')
{
self::$_db->exec('ALTER TABLE ' . self::$_prefix . 'paste ADD COLUMN meta TEXT;');
}
}
}
// create comment table if needed
if (!array_key_exists(self::$_prefix . 'comment', $tables))
@@ -183,7 +196,7 @@ class zerobin_db extends zerobin_abstract
public function create($pasteid, $paste)
{
if (
array_key_exists($pasteid, self::$_cache)
array_key_exists($pasteid, self::$_cache)
) {
if(false !== self::$_cache[$pasteid]) {
return false;
@@ -192,21 +205,30 @@ class zerobin_db extends zerobin_abstract
}
}
if (
!array_key_exists('opendiscussion', $paste['meta'])
) $paste['meta']['opendiscussion'] = false;
if (
!array_key_exists('burnafterreading', $paste['meta'])
) $paste['meta']['burnafterreading'] = false;
$opendiscussion = $burnafterreading = false;
$meta = $paste['meta'];
unset($meta['postdate']);
unset($meta['expire_date']);
if (array_key_exists('opendiscussion', $paste['meta']))
{
$opendiscussion = (bool) $paste['meta']['opendiscussion'];
unset($meta['opendiscussion']);
}
if (array_key_exists('burnafterreading', $paste['meta']))
{
$burnafterreading = (bool) $paste['meta']['burnafterreading'];
unset($meta['burnafterreading']);
}
return self::_exec(
'INSERT INTO ' . self::$_prefix . 'paste VALUES(?,?,?,?,?,?)',
'INSERT INTO ' . self::$_prefix . 'paste VALUES(?,?,?,?,?,?,?)',
array(
$pasteid,
$paste['data'],
$paste['meta']['postdate'],
$paste['meta']['expire_date'],
(int) $paste['meta']['opendiscussion'],
(int) $paste['meta']['burnafterreading'],
(int) $opendiscussion,
(int) $burnafterreading,
json_encode($meta),
)
);
}
@@ -233,7 +255,7 @@ class zerobin_db extends zerobin_abstract
// create object
self::$_cache[$pasteid] = new stdClass;
self::$_cache[$pasteid]->data = $paste['data'];
self::$_cache[$pasteid]->meta = new stdClass;
self::$_cache[$pasteid]->meta = json_decode($paste['meta']);
self::$_cache[$pasteid]->meta->postdate = (int) $paste['postdate'];
self::$_cache[$pasteid]->meta->expire_date = (int) $paste['expiredate'];
if (

197
tpl/bootstrap-compact.html Normal file
View File

@@ -0,0 +1,197 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex" />
<title>{function="t('ZeroBin')"}</title>
<link type="text/css" rel="stylesheet" href="css/bootstrap/bootstrap-3.3.5.css" />
<link type="text/css" rel="stylesheet" href="css/bootstrap/bootstrap-theme-3.3.5.css" />
<link type="text/css" rel="stylesheet" href="css/bootstrap/zerobin.css?{$VERSION|rawurlencode}" />{if="$SYNTAXHIGHLIGHTING"}
<link type="text/css" rel="stylesheet" href="css/prettify/prettify.css?{$VERSION|rawurlencode}" />{if="strlen($SYNTAXHIGHLIGHTINGTHEME)"}
<link type="text/css" rel="stylesheet" href="css/prettify/{$SYNTAXHIGHLIGHTINGTHEME}.css?{$VERSION|rawurlencode}" />{/if}{/if}
<script type="text/javascript" src="js/jquery-1.11.3.js"></script>
<script type="text/javascript" src="js/sjcl-1.0.2.js"></script>
<script type="text/javascript" src="js/base64-{$BASE64JSVERSION}.js"></script>
<script type="text/javascript" src="js/rawdeflate-0.5.js"></script>
<script type="text/javascript" src="js/rawinflate-0.3.js"></script>
<script type="text/javascript" src="js/bootstrap-3.3.5.js"></script>{if="$SYNTAXHIGHLIGHTING"}
<script type="text/javascript" src="js/prettify.js?{$VERSION|rawurlencode}"></script>{/if}{if="$MARKDOWN"}
<script type="text/javascript" src="js/showdown.js?{$VERSION|rawurlencode}"></script>{/if}
<script type="text/javascript" src="js/zerobin.js?{$VERSION|rawurlencode}"></script>
<!--[if lt IE 10]>
<style type="text/css">#ienotice {display:block !important;} #oldienotice {display:block !important;}</style>
<![endif]-->
</head>
<body role="document" class="navbar-spacing">
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">{function="t('Toggle navigation')"}</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="reloadlink navbar-brand" href="/">{function="t('ZeroBin')"}</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>
<button id="sendbutton" type="button" class="hidden btn btn-default navbar-btn">
<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> {function="t('Send')"}
</button>
<button id="clonebutton" type="button" class="hidden btn btn-default navbar-btn">
<span class="glyphicon glyphicon-duplicate" aria-hidden="true"></span> {function="t('Clone')"}
</button>
<button id="rawtextbutton" type="button" class="hidden btn btn-default navbar-btn">
<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> {function="t('Raw text')"}
</button>
</li>
<li class="dropdown">
<select id="pasteExpiration" name="pasteExpiration" class="hidden">
{loop="EXPIRE"}
<option value="{$key}"{if="$key == $EXPIREDEFAULT"} selected="selected"{/if}>{$value}</option>{/loop}
</select>
<a id="expiration" href="#" class="hidden dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{function="t('Expires')"}: <span id="pasteExpirationDisplay">{$EXPIRE[$EXPIREDEFAULT]}</span> <span class="caret"></span></a>
<ul class="dropdown-menu">
{loop="EXPIRE"}
<li>
<a href="#" onclick="$('#pasteExpiration').val('{$key}');$('#pasteExpirationDisplay').text('{$value}');return false;">
{$value}
</a>
</li>{/loop}
</ul>
</li>
<li id="formatter" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{function="t('Options')"} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li id="burnafterreadingoption" class="checkbox hidden">
<label>
<input type="checkbox" id="burnafterreading" name="burnafterreading" {if="$BURNAFTERREADINGSELECTED"} checked="checked"{/if} />
{function="t('Burn after reading')"}
</label>
</li>{if="$DISCUSSION"}
<li id="opendisc" class="checkbox hidden">
<label>
<input type="checkbox" id="opendiscussion" name="opendiscussion" {if="$OPENDISCUSSION"} checked="checked"{/if} />
{function="t('Open discussion')"}
</label>
</li>{/if}
<li role="separator" class="divider"></li>
<li>
<div>
{function="t('Format')"}: <span id="pasteFormatterDisplay">{$FORMATTER[$FORMATTERDEFAULT]}</span> <span class="caret"></span>
</div>
</li>
{loop="FORMATTER"}
<li>
<a href="#" onclick="$('#pasteFormatter').val('{$key}');$('#pasteFormatterDisplay').text('{$value}');return false;">
{$value}
</a>
</li>{/loop}
</ul>
<select id="pasteFormatter" name="pasteFormatter" class="hidden">
{loop="FORMATTER"}
<option value="{$key}"{if="$key == $FORMATTERDEFAULT"} selected="selected"{/if}>{$value}</option>{/loop}
</select>
</li>{if="$PASSWORD"}
<li>
<div id="password" class="navbar-form hidden">
<input type="password" id="passwordinput" placeholder="{function="t('Password (recommended)')"}" class="form-control" size="19"/>
</div>
</li>{/if}{if="$FILEUPLOAD"}
<li id="attach" class="hidden dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{function="t('Attach a file')"} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li id="filewrap">
<div>
<input type="file" id="file" name="file" />
</div>
</li>
<li>
<a id="fileremovebutton" href="#">
{function="t('Remove attachment')"}
</a>
</li>
</ul>
</li>{/if}
</ul>
<ul class="nav navbar-nav pull-right">{if="strlen($LANGUAGESELECTION)"}
<li id="language" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="glyphicon glyphicon-flag" aria-hidden="true"></span> {$LANGUAGES[$LANGUAGESELECTION][0]} <span class="caret"></span></a>
<ul class="dropdown-menu">
{loop="LANGUAGES"}
<li>
<a href="#" class="reloadlink" onclick="document.cookie='lang={$key}';">
{$value[0]} ({$value[1]})
</a>
</li>{/loop}
</ul>
</li>{/if}
<li>
<button id="newbutton" type="button" class="reloadlink hidden btn btn-default navbar-btn">
<span class="glyphicon glyphicon-file" aria-hidden="true"></span> {function="t('New')"}
</button>
</li>
</ul>
</div>
</div>
</nav>
<header class="container">{if="strlen($NOTICE)"}
<div role="alert" class="alert alert-info">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> {$NOTICE|htmlspecialchars}
</div>{/if}
<div id="remainingtime" role="alert" class="hidden alert alert-info">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
</div>{if="$FILEUPLOAD"}
<div id="attachment" role="alert" class="hidden alert alert-info">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> <a>{function="t('Download attachment')"}</a> <span id="clonedfile" class="hidden">{function="t('Cloned file attached.')"}</span>
</div>{/if}{if="strlen($STATUS)"}
<div id="status" role="alert" class="alert alert-success">
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span> {$STATUS|htmlspecialchars}
</div>{/if}
<div id="errormessage" role="alert" class="{if="!strlen($ERROR)"}hidden {/if}alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> {$ERROR|htmlspecialchars}</div>
<div id="noscript" role="alert" class="nonworking alert alert-warning"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> {function="t('Javascript is required for ZeroBin to work.<br />Sorry for the inconvenience.')"}</div>
<div id="oldienotice" role="alert" class="hidden nonworking alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> {function="t('ZeroBin 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> {function="t('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:')"}
<a href="http://www.mozilla.org/firefox/">Firefox</a>,
<a href="http://www.opera.com/">Opera</a>,
<a href="http://www.google.com/chrome">Chrome</a>,
<a href="http://www.apple.com/safari">Safari</a>...
</div>
<div id="pasteresult" role="alert" class="hidden alert alert-success">
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
<div id="deletelink"></div>
<div id="pastelink"></div>
</div>
</header>
<section class="container">
<article class="row">
<div id="image" class="col-md-12 text-center hidden"></div>
<div id="prettymessage" class="col-md-12 hidden">
<pre id="prettyprint" class="col-md-12 prettyprint linenums:1"></pre>
</div>
<div id="cleartext" class="col-md-12 hidden"></div>
<p class="col-md-12"><textarea id="message" name="message" cols="80" rows="25" class="form-control hidden"></textarea></p>
</article>
</section>
<section class="container">
<div id="discussion" class="hidden">
<h4>{function="t('Discussion')"}</h4>
<div id="comments"></div>
</div>
</section>
<footer class="container">
<div class="row">
<h4 class="col-md-5 col-xs-8">{function="t('ZeroBin')"} <small>- {function="t('Because ignorance is bliss')"}</small></h4>
<p class="col-md-1 col-xs-4 text-center">{$VERSION}</p>
<p id="aboutbox" class="col-md-6 col-xs-12">
{function="t('ZeroBin is a minimalist, opensource 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/elrido/ZeroBin/wiki">project page</a>.')"}
</p>
</div>
</footer>
<div id="cipherdata" class="hidden">{$CIPHERDATA}</div>
</body>
</html>

View File

@@ -5,7 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex" />
<title>ZeroBin</title>
<title>{function="t('ZeroBin')"}</title>
<link type="text/css" rel="stylesheet" href="css/bootstrap/bootstrap-3.3.5.css" />
<link type="text/css" rel="stylesheet" href="css/bootstrap/bootstrap-theme-3.3.5.css" />
<link type="text/css" rel="stylesheet" href="css/bootstrap/zerobin.css?{$VERSION|rawurlencode}" />{if="$SYNTAXHIGHLIGHTING"}
@@ -17,42 +17,35 @@
<script type="text/javascript" src="js/rawdeflate-0.5.js"></script>
<script type="text/javascript" src="js/rawinflate-0.3.js"></script>
<script type="text/javascript" src="js/bootstrap-3.3.5.js"></script>{if="$SYNTAXHIGHLIGHTING"}
<script type="text/javascript" src="js/prettify.js?{$VERSION|rawurlencode}"></script>{/if}
<script type="text/javascript" src="js/prettify.js?{$VERSION|rawurlencode}"></script>{/if}{if="$MARKDOWN"}
<script type="text/javascript" src="js/showdown.js?{$VERSION|rawurlencode}"></script>{/if}
<script type="text/javascript" src="js/zerobin.js?{$VERSION|rawurlencode}"></script>
<!--[if lt IE 10]>
<style type="text/css">#ienotice {display:block !important;} #oldienotice {display:block !important;}</style>
<![endif]-->
</head>
<body role="document">
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<nav class="navbar navbar-default navbar-static-top">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="sr-only">{function="t('Toggle navigation')"}</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/" onclick="window.location.href=scriptLocation();return false;">ZeroBin</a>
<a class="reloadlink navbar-brand" href="/">{function="t('ZeroBin')"}</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav pull-right">
<li>
<button id="newbutton" type="button" class="hidden btn btn-default navbar-btn" onclick="window.location.href=scriptLocation();return false;">
<span class="glyphicon glyphicon-file" aria-hidden="true"></span> New
</button>
</li>
</ul>
<ul class="nav navbar-nav">
<li class="pr">
<button id="sendbutton" type="button" class="hidden btn btn-default navbar-btn" onclick="send_data();return false;">
<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> Send
<li>
<button id="sendbutton" type="button" class="hidden btn btn-default navbar-btn">
<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> {function="t('Send')"}
</button>
<button id="clonebutton" type="button" class="hidden btn btn-default navbar-btn" onclick="clonePaste();return false;">
<span class="glyphicon glyphicon-duplicate" aria-hidden="true"></span> Clone
<button id="clonebutton" type="button" class="hidden btn btn-default navbar-btn">
<span class="glyphicon glyphicon-duplicate" aria-hidden="true"></span> {function="t('Clone')"}
</button>
<button id="rawtextbutton" type="button" class="hidden btn btn-default navbar-btn" onclick="rawText();return false;">
<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> Raw text
<button id="rawtextbutton" type="button" class="hidden btn btn-default navbar-btn">
<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> {function="t('Raw text')"}
</button>
</li>
<li class="dropdown">
@@ -60,17 +53,21 @@
{loop="EXPIRE"}
<option value="{$key}"{if="$key == $EXPIREDEFAULT"} selected="selected"{/if}>{$value}</option>{/loop}
</select>
<a id="expiration" href="#" class="hidden dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Expires: <span id="pasteExpirationDisplay">{$EXPIREDEFAULT}</span> <span class="caret"></span></a>
<a id="expiration" href="#" class="hidden dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{function="t('Expires')"}: <span id="pasteExpirationDisplay">{$EXPIRE[$EXPIREDEFAULT]}</span> <span class="caret"></span></a>
<ul class="dropdown-menu">
{loop="EXPIRE"}
<li><a href="#" onclick="$('#pasteExpiration').val('{$key}');$('#pasteExpirationDisplay').text('{$value}');return false;">{$value}</a></li>{/loop}
<li>
<a href="#" onclick="$('#pasteExpiration').val('{$key}');$('#pasteExpirationDisplay').text('{$value}');return false;">
{$value}
</a>
</li>{/loop}
</ul>
</li>
<li>
<div id="burnafterreadingoption" class="navbar-text checkbox hidden">
<label>
<input type="checkbox" id="burnafterreading" name="burnafterreading" {if="$BURNAFTERREADINGSELECTED"} checked="checked"{/if} />
Burn after reading
{function="t('Burn after reading')"}
</label>
</div>
</li>{if="$DISCUSSION"}
@@ -78,31 +75,83 @@
<div id="opendisc" class="navbar-text checkbox hidden">
<label>
<input type="checkbox" id="opendiscussion" name="opendiscussion" {if="$OPENDISCUSSION"} checked="checked"{/if} />
Open discussion
{function="t('Open discussion')"}
</label>
</div>
</li>{/if}{if="$PASSWORD"}
<li>
<div id="password" class="navbar-form hidden">
<input type="password" id="passwordinput" placeholder="Password (optional)" class="form-control" size="19"/>
<input type="password" id="passwordinput" placeholder="{function="t('Password (recommended)')"}" class="form-control" size="19"/>
</div>
</li>{/if}{if="$FILEUPLOAD"}
<li id="attach" class="hidden dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{function="t('Attach a file')"} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li id="filewrap">
<div>
<input type="file" id="file" name="file" />
</div>
</li>
<li>
<a id="fileremovebutton" href="#">
{function="t('Remove attachment')"}
</a>
</li>
</ul>
</li>{/if}
<li>
<p id="remainingtime" class="hidden navbar-text"></p>
<li class="dropdown">
<select id="pasteFormatter" name="pasteFormatter" class="hidden">
{loop="FORMATTER"}
<option value="{$key}"{if="$key == $FORMATTERDEFAULT"} selected="selected"{/if}>{$value}</option>{/loop}
</select>
<a id="formatter" href="#" class="hidden dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{function="t('Format')"}: <span id="pasteFormatterDisplay">{$FORMATTER[$FORMATTERDEFAULT]}</span> <span class="caret"></span></a>
<ul class="dropdown-menu">
{loop="FORMATTER"}
<li>
<a href="#" onclick="$('#pasteFormatter').val('{$key}');$('#pasteFormatterDisplay').text('{$value}');return false;">
{$value}
</a>
</li>{/loop}
</ul>
</li>
</ul>
</div>
<ul class="nav navbar-nav pull-right">{if="strlen($LANGUAGESELECTION)"}
<li id="language" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="glyphicon glyphicon-flag" aria-hidden="true"></span> {$LANGUAGES[$LANGUAGESELECTION][0]} <span class="caret"></span></a>
<ul class="dropdown-menu">
{loop="LANGUAGES"}
<li>
<a href="#" class="reloadlink" onclick="document.cookie='lang={$key}';">
{$value[0]} ({$value[1]})
</a>
</li>{/loop}
</ul>
</li>{/if}
<li>
<button id="newbutton" type="button" class="reloadlink hidden btn btn-default navbar-btn">
<span class="glyphicon glyphicon-file" aria-hidden="true"></span> {function="t('New')"}
</button>
</li>
</ul>
</div>
</nav>
<header class="container">{if="strlen($NOTICE)"}
<div role="alert" class="alert alert-info">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> {$NOTICE|htmlspecialchars}
</div>{/if}
<div id="remainingtime" role="alert" class="hidden alert alert-info">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
</div>{if="$FILEUPLOAD"}
<div id="attachment" role="alert" class="hidden alert alert-info">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span> <a>{function="t('Download attachment')"}</a> <span id="clonedfile" class="hidden">{function="t('Cloned file attached.')"}</span>
</div>{/if}{if="strlen($STATUS)"}
<div id="status" role="alert" class="alert alert-success"><span class="glyphicon glyphicon-ok" aria-hidden="true"></span> {$STATUS|htmlspecialchars}</div>{/if}
<div id="status" role="alert" class="alert alert-success">
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span> {$STATUS|htmlspecialchars}
</div>{/if}
<div id="errormessage" role="alert" class="{if="!strlen($ERROR)"}hidden {/if}alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> {$ERROR|htmlspecialchars}</div>
<div id="noscript" role="alert" class="nonworking alert alert-warning"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> Javascript is required for ZeroBin to work.<br />Sorry for the inconvenience.</div>
<div id="oldienotice" role="alert" class="hidden nonworking alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> ZeroBin 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> Still using Internet Explorer? Do yourself a favor, switch to a modern browser:
<div id="noscript" role="alert" class="nonworking alert alert-warning"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> {function="t('Javascript is required for ZeroBin to work.<br />Sorry for the inconvenience.')"}</div>
<div id="oldienotice" role="alert" class="hidden nonworking alert alert-danger"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> {function="t('ZeroBin 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> {function="t('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:')"}
<a href="http://www.mozilla.org/firefox/">Firefox</a>,
<a href="http://www.opera.com/">Opera</a>,
<a href="http://www.google.com/chrome">Chrome</a>,
@@ -116,6 +165,7 @@
</header>
<section class="container">
<article class="row">
<div id="image" class="col-md-12 text-center hidden"></div>
<div id="prettymessage" class="col-md-12 hidden">
<pre id="prettyprint" class="col-md-12 prettyprint linenums:1"></pre>
</div>
@@ -125,18 +175,16 @@
</section>
<section class="container">
<div id="discussion" class="hidden">
<h4>Discussion</h4>
<h4>{function="t('Discussion')"}</h4>
<div id="comments"></div>
</div>
</section>
<footer class="container">
<div class="row">
<h4 class="col-md-3 col-xs-8">ZeroBin <small>- Because ignorance is bliss</small></h4>
<h4 class="col-md-5 col-xs-8">{function="t('ZeroBin')"} <small>- {function="t('Because ignorance is bliss')"}</small></h4>
<p class="col-md-1 col-xs-4 text-center">{$VERSION}</p>
<p id="aboutbox" class="col-md-8 col-xs-12">
ZeroBin is a minimalist, opensource online pastebin where the server has zero knowledge of pasted data.<br />
Data is encrypted/decrypted <em>in the browser</em> using 256 bits AES.<br />
More information on the <a href="http://sebsauvage.net/wiki/doku.php?id=php:zerobin" target="_blank">project page</a>.
<p id="aboutbox" class="col-md-6 col-xs-12">
{function="t('ZeroBin is a minimalist, opensource 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/elrido/ZeroBin/wiki">project page</a>.')"}
</p>
</div>
</footer>

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="robots" content="noindex" />
<title>ZeroBin</title>
<title>{function="t('ZeroBin')"}</title>
<link type="text/css" rel="stylesheet" href="css/zerobin.css?{$VERSION|rawurlencode}" />{if="$SYNTAXHIGHLIGHTING"}
<link type="text/css" rel="stylesheet" href="css/prettify/prettify.css?{$VERSION|rawurlencode}" />{if="strlen($SYNTAXHIGHLIGHTINGTHEME)"}
<link type="text/css" rel="stylesheet" href="css/prettify/{$SYNTAXHIGHLIGHTINGTHEME}.css?{$VERSION|rawurlencode}" />{/if}{/if}
@@ -12,7 +12,8 @@
<script type="text/javascript" src="js/base64-{$BASE64JSVERSION}.js"></script>
<script type="text/javascript" src="js/rawdeflate-0.5.js"></script>
<script type="text/javascript" src="js/rawinflate-0.3.js"></script>{if="$SYNTAXHIGHLIGHTING"}
<script type="text/javascript" src="js/prettify.js?{$VERSION|rawurlencode}"></script>{/if}
<script type="text/javascript" src="js/prettify.js?{$VERSION|rawurlencode}"></script>{/if}{if="$MARKDOWN"}
<script type="text/javascript" src="js/showdown.js?{$VERSION|rawurlencode}"></script>{/if}
<script type="text/javascript" src="js/zerobin.js?{$VERSION|rawurlencode}"></script>
<!--[if lt IE 10]>
<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
@@ -21,17 +22,15 @@
<body>
<header>
<div id="aboutbox">
ZeroBin is a minimalist, opensource 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="http://sebsauvage.net/wiki/doku.php?id=php:zerobin">project page</a>.<br />{if="strlen($NOTICE)"}
{function="t('ZeroBin is a minimalist, opensource 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/elrido/ZeroBin/wiki">project page</a>.')"}<br />{if="strlen($NOTICE)"}
<span class="blink"></span> {$NOTICE}{/if}
</div>
<h1 title="ZeroBin" onclick="window.location.href=scriptLocation();return false;">ZeroBin</h1><br />
<h2>Because ignorance is bliss</h2><br />
<h3>{$VERSION}</h3>
<div id="noscript" class="nonworking">Javascript is required for ZeroBin to work.<br />Sorry for the inconvenience.</div>
<div id="oldienotice" class="nonworking">ZeroBin requires a modern browser to work.</div>
<div id="ienotice">Still using Internet Explorer ? Do yourself a favor, switch to a modern browser:
<h1 class="title reloadlink">{function="t('ZeroBin')"}</h1><br />
<h2 class="title">{function="t('Because ignorance is bliss')"}</h2><br />
<h3 class="title">{$VERSION}</h3>
<div id="noscript" class="nonworking">{function="t('Javascript is required for ZeroBin to work.<br />Sorry for the inconvenience.')"}</div>
<div id="oldienotice" class="nonworking">{function="t('ZeroBin requires a modern browser to work.')"}</div>
<div id="ienotice">{function="t('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:')"}
<a href="http://www.mozilla.org/firefox/">Firefox</a>,
<a href="http://www.opera.com/">Opera</a>,
<a href="http://www.google.com/chrome">Chrome</a>,
@@ -43,11 +42,11 @@
<div id="status">{$STATUS|htmlspecialchars}</div>
<div id="errormessage" class="hidden">{$ERROR|htmlspecialchars}</div>
<div id="toolbar">
<button id="newbutton" onclick="window.location.href=scriptLocation();return false;" class="hidden"><img src="img/icon_new.png" width="11" height="15" alt="" />New</button>
<button id="sendbutton" onclick="send_data();return false;" class="hidden"><img src="img/icon_send.png" width="18" height="15" alt="" />Send</button>
<button id="clonebutton" onclick="clonePaste();return false;" class="hidden"><img src="img/icon_clone.png" width="15" height="17" alt="" />Clone</button>
<button id="rawtextbutton" onclick="rawText();return false;" class="hidden"><img src="img/icon_raw.png" width="15" height="15" alt="" />Raw text</button>
<div id="expiration" class="hidden">Expires:
<button id="newbutton" class="reloadlink hidden"><img src="img/icon_new.png" width="11" height="15" alt="" />{function="t('New')"}</button>
<button id="sendbutton" class="hidden"><img src="img/icon_send.png" width="18" height="15" alt="" />{function="t('Send')"}</button>
<button id="clonebutton" class="hidden"><img src="img/icon_clone.png" width="15" height="17" alt="" />{function="t('Clone')"}</button>
<button id="rawtextbutton" class="hidden"><img src="img/icon_raw.png" width="15" height="15" alt="" />{function="t('Raw text')"}</button>
<div id="expiration" class="hidden button">{function="t('Expires')"}:
<select id="pasteExpiration" name="pasteExpiration">
{loop="EXPIRE"}
<option value="{$key}"{if="$key == $EXPIREDEFAULT"} selected="selected"{/if}>{$value}</option>{/loop}
@@ -56,20 +55,39 @@
<div id="remainingtime" class="hidden"></div>
<div id="burnafterreadingoption" class="button hidden">
<input type="checkbox" id="burnafterreading" name="burnafterreading" {if="$BURNAFTERREADINGSELECTED"} checked="checked"{/if} />
<label for="burnafterreading">Burn after reading</label>
<label for="burnafterreading">{function="t('Burn after reading')"}</label>
</div>{if="$DISCUSSION"}
<div id="opendisc" class="button hidden">
<input type="checkbox" id="opendiscussion" name="opendiscussion" {if="$OPENDISCUSSION"} checked="checked"{/if} />
<label for="opendiscussion" {if="!$OPENDISCUSSION"} style="color: #BBBBBB;"{/if}>Open discussion</label>
<label for="opendiscussion" {if="!$OPENDISCUSSION"} style="color: #BBBBBB;"{/if}>{function="t('Open discussion')"}</label>
</div>{/if}{if="$PASSWORD"}
<div id="password" class="hidden">
<input id="passwordinput" placeholder="Optional password (recommended)" size="32" />
<input type="password" id="passwordinput" placeholder="{function="t('Password (recommended)')"}" size="32" />
</div>{/if}
<div id="formatter" class="button hidden">{function="t('Format')"}:
<select id="pasteFormatter" name="pasteFormatter">
{loop="FORMATTER"}
<option value="{$key}"{if="$key == $FORMATTERDEFAULT"} selected="selected"{/if}>{$value}</option>{/loop}
</select>
</div>{if="strlen($LANGUAGESELECTION)"}
<div id="language" class="button">
<select name="lang">
{loop="LANGUAGES"}
<option class="reloadlink" onclick="document.cookie='lang={$key}';" value="{$key}"{if="$key == $LANGUAGESELECTION"} selected="selected"{/if}>{$value[0]} ({$value[1]})</option>{/loop}
</select>
</div>{/if}
</div>
<div id="pasteresult" class="hidden">
<div id="deletelink"></div>
<div id="pastelink"></div>
</div>
</div>{if="$FILEUPLOAD"}
<div id="attachment" class="hidden"><a>{function="t('Download attachment')"}</a></div>
<div id="attach" class="hidden">
<span id="clonedfile" class="hidden">{function="t('Cloned file attached.')"}</span>
<span id="filewrap">{function="t('Attach a file')"}: <input type="file" id="file" name="file" /></span>
<button id="fileremovebutton">{function="t('Remove attachment')"}</button>
</div>{/if}
<div id="image" class="hidden"></div>
<div id="prettymessage" class="hidden">
<pre id="prettyprint" class="prettyprint linenums:1"></pre>
</div>
@@ -79,7 +97,7 @@
</section>
<section>
<div id="discussion" class="hidden">
<h4>Discussion</h4>
<h4 class="title">{function="t('Discussion')"}</h4>
<div id="comments"></div>
</div>
</section>

View File

@@ -1,8 +1,6 @@
<?php
class RainTPLTest extends PHPUnit_Framework_TestCase
{
private static $data = '{"iv":"EN39/wd5Nk8HAiSG2K5AsQ","salt":"QKN1DBXe5PI","ct":"8hA83xDdXjD7K2qfmw5NdA"}';
private static $error = 'foo bar';
private static $status = '!*#@?$+';
@@ -27,18 +25,22 @@ class RainTPLTest extends PHPUnit_Framework_TestCase
$page::$path_replace = false;
// We escape it here because ENT_NOQUOTES can't be used in RainTPL templates.
$page->assign('CIPHERDATA', htmlspecialchars(self::$data, ENT_NOQUOTES));
$page->assign('CIPHERDATA', htmlspecialchars(helper::getPaste()['data'], ENT_NOQUOTES));
$page->assign('ERROR', self::$error);
$page->assign('STATUS', self::$status);
$page->assign('VERSION', self::$version);
$page->assign('DISCUSSION', true);
$page->assign('OPENDISCUSSION', true);
$page->assign('MARKDOWN', true);
$page->assign('SYNTAXHIGHLIGHTING', true);
$page->assign('SYNTAXHIGHLIGHTINGTHEME', 'sons-of-obsidian');
$page->assign('BURNAFTERREADINGSELECTED', false);
$page->assign('PASSWORD', true);
$page->assign('FILEUPLOAD', false);
$page->assign('BASE64JSVERSION', '2.1.9');
$page->assign('NOTICE', 'example');
$page->assign('LANGUAGESELECTION', '');
$page->assign('LANGUAGES', i18n::getLanguageLabels(i18n::getAvailableLanguages()));
$page->assign('EXPIRE', self::$expire);
$page->assign('EXPIREDEFAULT', self::$expire_default);
ob_start();
@@ -61,7 +63,7 @@ class RainTPLTest extends PHPUnit_Framework_TestCase
$this->assertTag(
array(
'id' => 'cipherdata',
'content' => htmlspecialchars(self::$data, ENT_NOQUOTES)
'content' => htmlspecialchars(helper::getPaste()['data'], ENT_NOQUOTES)
),
$this->_content,
'outputs data correctly'

View File

@@ -3,11 +3,103 @@ error_reporting( E_ALL | E_STRICT );
// change this, if your php files and data is outside of your webservers document root
if (!defined('PATH')) define('PATH', '..' . DIRECTORY_SEPARATOR);
if (!defined('PUBLIC_PATH')) define('PUBLIC_PATH', '..');
require PATH . 'lib/auto.php';
class helper
{
/**
* example ID of a paste
*
* @var string
*/
private static $pasteid = '5e9bc25c89fb3bf9';
/**
* example paste
*
* @var array
*/
private static $paste = array(
'data' => '{"iv":"EN39/wd5Nk8HAiSG2K5AsQ","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"QKN1DBXe5PI","ct":"8hA83xDdXjD7K2qfmw5NdA"}',
'meta' => array(
'postdate' => 1344803344,
'opendiscussion' => true,
'formatter' => 'plaintext',
'attachment' => '{"iv":"Pd4pOKWkmDTT9uPwVwd5Ag","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"6nOCU3peNDclDDpFtJEBKA"}',
'attachmentname' => '{"iv":"76MkAtOGC4oFogX/aSMxRA","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"b6Ae/U1xJdsX/+lATud4sQ"}',
),
);
/**
* example ID of a comment
*
* @var string
*/
private static $commentid = '5a52eebf11c4c94b';
/**
* example comment
*
* @var array
*/
private static $comment = array(
'data' => '{"iv":"Pd4pOKWkmDTT9uPwVwd5Ag","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"6nOCU3peNDclDDpFtJEBKA"}',
'meta' => array(
'nickname' => '{"iv":"76MkAtOGC4oFogX/aSMxRA","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"b6Ae/U1xJdsX/+lATud4sQ"}',
'vizhash' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGUlEQVQokWOsl5/94983CNKQMjnxaOePf98MeKwPfNjkLZ3AgARab6b9+PeNEVnDj3/ff/z7ZiHnzsDA8Pv7H2TVPJw8EAYLAwb48OaVgIgYKycLsrYv378wMDB8//qdCVMDRA9EKSsnCwRBxNsepaLboMFlyMDAICAi9uHNK24GITQ/MDAwoNhgIGMLtwGrzegaLjw5jMz9+vUdnN17uwDCQDhJgk0O07yvX9+teDX1x79v6DYIsIjgcgMaYGFgYOBg4kJx2JejkAiBxAw+PzAwMNz4dp6wDXDw4MdNNOl0rWYsNkD89OLXI/xmo9sgzatJjAYmBgYGDiauD3/ePP18nVgb4MF89+M5ZX6js293wUMpnr8KTQMAxsCJnJ30apMAAAAASUVORK5CYII=',
'postdate' => 1344803528,
),
);
/**
* get example paste ID
*
* @return string
*/
public static function getPasteId()
{
return self::$pasteid;
}
/**
* get example paste
*
* @return array
*/
public static function getPaste($meta = array())
{
$example = self::$paste;
$example['meta'] = array_merge($example['meta'], $meta);
return $example;
}
/**
* get example paste ID
*
* @return string
*/
public static function getCommentId()
{
return self::$commentid;
}
/**
* get example comment
*
* @return array
*/
public static function getComment($meta = array())
{
$example = self::$comment;
$example['meta'] = array_merge($example['meta'], $meta);
return $example;
}
/**
* delete directory and all its contents recursively
*

View File

@@ -44,7 +44,7 @@ new configurationTestGenerator(array(
'settings' => array('$_POST["opendiscussion"] = "neither 1 nor 0"'),
'type' => 'False',
'args' => array(
'$this->_model->exists(self::$pasteid)',
'$this->_model->exists(helper::getPasteId())',
'when discussions are enabled, but invalid flag posted, paste is not created'
),
),
@@ -108,9 +108,9 @@ new configurationTestGenerator(array(
'affects' => $vrd
),
),
'main/syntaxhighlighting' => array(
'main/defaultformatter' => array(
array(
'setting' => true,
'setting' => 'syntaxhighlighting',
'tests' => array(
array(
'type' => 'Tag',
@@ -143,7 +143,7 @@ new configurationTestGenerator(array(
),
'affects' => $vrd,
), array(
'setting' => false,
'setting' => 'plaintext',
'tests' => array(
array(
'type' => 'NotTag',
@@ -593,16 +593,6 @@ class configurationTestGenerator
*/
class configurationTest extends PHPUnit_Framework_TestCase
{
private static $pasteid = '5e9bc25c89fb3bf9';
private static $paste = array(
'data' => '{"iv":"EN39/wd5Nk8HAiSG2K5AsQ","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"QKN1DBXe5PI","ct":"8hA83xDdXjD7K2qfmw5NdA"}',
'meta' => array(
'postdate' => 1344803344,
'opendiscussion' => true,
),
);
private $_model;
private $_conf;
@@ -630,8 +620,8 @@ class configurationTest extends PHPUnit_Framework_TestCase
$_POST = array();
$_GET = array();
$_SERVER = array();
if ($this->_model->exists(self::$pasteid))
$this->_model->delete(self::$pasteid);
if ($this->_model->exists(helper::getPasteId()))
$this->_model->delete(helper::getPasteId());
helper::createIniFile($this->_conf, $configuration);
}
@@ -678,22 +668,22 @@ EOT;
switch ($step) {
case 'Create':
$code .= PHP_EOL . <<<'EOT'
$_POST = self::$paste;
$_POST = helper::getPaste();
$_SERVER['REMOTE_ADDR'] = '::1';
EOT;
break;
case 'Read':
$code .= PHP_EOL . <<<'EOT'
$this->_model->create(self::$pasteid, self::$paste);
$_SERVER['QUERY_STRING'] = self::$pasteid;
$this->_model->create(helper::getPasteId(), helper::getPaste());
$_SERVER['QUERY_STRING'] = helper::getPasteId();
EOT;
break;
case 'Delete':
$code .= PHP_EOL . <<<'EOT'
$this->_model->create(self::$pasteid, self::$paste);
$this->assertTrue($this->_model->exists(self::$pasteid), 'paste exists before deleting data');
$_GET['pasteid'] = self::$pasteid;
$_GET['deletetoken'] = hash_hmac('sha1', self::$pasteid, serversalt::get());
$this->_model->create(helper::getPasteId(), helper::getPaste());
$this->assertTrue($this->_model->exists(helper::getPasteId()), 'paste exists before deleting data');
$_GET['pasteid'] = helper::getPasteId();
$_GET['deletetoken'] = hash_hmac('sha1', helper::getPasteId(), serversalt::get());
EOT;
break;
}
@@ -720,7 +710,7 @@ EOT;
$this->assertTag(
array(
'id' => 'cipherdata',
'content' => htmlspecialchars(json_encode(self::$paste), ENT_NOQUOTES)
'content' => htmlspecialchars(json_encode(helper::getPaste()), ENT_NOQUOTES)
),
$content,
'outputs data correctly'
@@ -738,7 +728,7 @@ EOT;
$content,
'outputs deleted status correctly'
);
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste successfully deleted');
$this->assertFalse($this->_model->exists(helper::getPasteId()), 'paste successfully deleted');
EOT;
break;
}

View File

@@ -9,14 +9,31 @@ class filterTest extends PHPUnit_Framework_TestCase
);
}
public function testFilterMakesTimesHumanlyReadable()
{
$this->assertEquals('5 minutes', filter::time_humanreadable('5min'));
$this->assertEquals('90 seconds', filter::time_humanreadable('90sec'));
$this->assertEquals('1 week', filter::time_humanreadable('1week'));
$this->assertEquals('6 months', filter::time_humanreadable('6months'));
}
/**
* @expectedException Exception
* @expectedExceptionCode 30
*/
public function testFilterFailTimesHumanlyReadable()
{
filter::time_humanreadable('five_minutes');
}
public function testFilterMakesSizesHumanlyReadable()
{
$this->assertEquals('1 B', filter::size_humanreadable(1));
$this->assertEquals('1 000 B', filter::size_humanreadable(1000));
$this->assertEquals('1.00 kiB', filter::size_humanreadable(1024));
$this->assertEquals('1.21 kiB', filter::size_humanreadable(1234));
$this->assertEquals('1.00 KiB', filter::size_humanreadable(1024));
$this->assertEquals('1.21 KiB', filter::size_humanreadable(1234));
$exponent = 1024;
$this->assertEquals('1 000.00 kiB', filter::size_humanreadable(1000 * $exponent));
$this->assertEquals('1 000.00 KiB', filter::size_humanreadable(1000 * $exponent));
$this->assertEquals('1.00 MiB', filter::size_humanreadable(1024 * $exponent));
$this->assertEquals('1.21 MiB', filter::size_humanreadable(1234 * $exponent));
$exponent *= 1024;

79
tst/i18n.php Normal file
View File

@@ -0,0 +1,79 @@
<?php
class i18nTest extends PHPUnit_Framework_TestCase
{
private $_translations = array();
public function setUp()
{
/* Setup Routine */
$this->_translations = json_decode(
file_get_contents(PATH . 'i18n' . DIRECTORY_SEPARATOR . 'de.json'),
true
);
}
public function tearDown()
{
/* Tear Down Routine */
}
public function testTranslationFallback()
{
$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'foobar';
$messageId = 'It does not matter if the message ID exists';
i18n::loadTranslations();
$this->assertEquals($messageId, i18n::_($messageId), 'fallback to en');
}
public function testCookieLanguageDeDetection()
{
$_COOKIE['lang'] = 'de';
i18n::loadTranslations();
$this->assertEquals($this->_translations['en'], i18n::_('en'), 'browser language de');
$this->assertEquals('0 Stunden', i18n::_('%d hours', 0), '0 hours in german');
$this->assertEquals('1 Stunde', i18n::_('%d hours', 1), '1 hour in german');
$this->assertEquals('2 Stunden', i18n::_('%d hours', 2), '2 hours in french');
}
public function testBrowserLanguageDeDetection()
{
$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'de-CH,de;q=0.8,en-GB;q=0.6,en-US;q=0.4,en;q=0.2';
i18n::loadTranslations();
$this->assertEquals($this->_translations['en'], i18n::_('en'), 'browser language de');
$this->assertEquals('0 Stunden', i18n::_('%d hours', 0), '0 hours in german');
$this->assertEquals('1 Stunde', i18n::_('%d hours', 1), '1 hour in german');
$this->assertEquals('2 Stunden', i18n::_('%d hours', 2), '2 hours in french');
}
public function testBrowserLanguageFrDetection()
{
$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'fr-CH,fr;q=0.8,en-GB;q=0.6,en-US;q=0.4,en;q=0.2';
i18n::loadTranslations();
$this->assertEquals('fr', i18n::_('en'), 'browser language fr');
$this->assertEquals('0 heure', i18n::_('%d hours', 0), '0 hours in french');
$this->assertEquals('1 heure', i18n::_('%d hours', 1), '1 hour in french');
$this->assertEquals('2 heures', i18n::_('%d hours', 2), '2 hours in french');
}
public function testBrowserLanguagePlDetection()
{
$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'pl;q=0.8,en-GB;q=0.6,en-US;q=0.4,en;q=0.2';
i18n::loadTranslations();
$this->assertEquals('pl', i18n::_('en'), 'browser language pl');
$this->assertEquals('2 godzina', i18n::_('%d hours', 2), 'hours in polish');
}
public function testBrowserLanguageAnyDetection()
{
$_SERVER['HTTP_ACCEPT_LANGUAGE'] = '*';
i18n::loadTranslations();
$this->assertTrue(strlen(i18n::_('en')) == 2, 'browser language any');
}
public function testVariableInjection()
{
$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'foobar';
i18n::loadTranslations();
$this->assertEquals('some string + 1', i18n::_('some %s + %d', 'string', 1), 'browser language en');
}
}

View File

@@ -3,6 +3,12 @@ class sjclTest extends PHPUnit_Framework_TestCase
{
public function testSjclValidatorValidatesCorrectly()
{
$paste = helper::getPaste();
$this->assertTrue(sjcl::isValid($paste['data']), 'valid sjcl');
$this->assertTrue(sjcl::isValid($paste['meta']['attachment']), 'valid sjcl');
$this->assertTrue(sjcl::isValid($paste['meta']['attachmentname']), 'valid sjcl');
$this->assertTrue(sjcl::isValid(helper::getComment()['data']), 'valid sjcl');
$this->assertTrue(sjcl::isValid('{"iv":"83Ax/OdUav3SanDW9dcQPg","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"Gx1vA2/gQ3U","ct":"j7ImByuE5xCqD2YXm6aSyA"}'), 'valid sjcl');
$this->assertFalse(sjcl::isValid('{"iv":"$","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"Gx1vA2/gQ3U","ct":"j7ImByuE5xCqD2YXm6aSyA"}'), 'invalid base64 encoding of iv');
$this->assertFalse(sjcl::isValid('{"iv":"83Ax/OdUav3SanDW9dcQPg","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"$","ct":"j7ImByuE5xCqD2YXm6aSyA"}'), 'invalid base64 encoding of salt');

View File

@@ -1,27 +1,6 @@
<?php
class zerobinTest extends PHPUnit_Framework_TestCase
{
private static $pasteid = '5e9bc25c89fb3bf9';
private static $paste = array(
'data' => '{"iv":"EN39/wd5Nk8HAiSG2K5AsQ","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"QKN1DBXe5PI","ct":"8hA83xDdXjD7K2qfmw5NdA"}',
'meta' => array(
'postdate' => 1344803344,
'opendiscussion' => true,
),
);
private static $commentid = '5a52eebf11c4c94b';
private static $comment = array(
'data' => '{"iv":"Pd4pOKWkmDTT9uPwVwd5Ag","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"6nOCU3peNDclDDpFtJEBKA"}',
'meta' => array(
'nickname' => '{"iv":"76MkAtOGC4oFogX/aSMxRA","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"b6Ae/U1xJdsX/+lATud4sQ"}',
'vizhash' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGUlEQVQokWOsl5/94983CNKQMjnxaOePf98MeKwPfNjkLZ3AgARab6b9+PeNEVnDj3/ff/z7ZiHnzsDA8Pv7H2TVPJw8EAYLAwb48OaVgIgYKycLsrYv378wMDB8//qdCVMDRA9EKSsnCwRBxNsepaLboMFlyMDAICAi9uHNK24GITQ/MDAwoNhgIGMLtwGrzegaLjw5jMz9+vUdnN17uwDCQDhJgk0O07yvX9+teDX1x79v6DYIsIjgcgMaYGFgYOBg4kJx2JejkAiBxAw+PzAwMNz4dp6wDXDw4MdNNOl0rWYsNkD89OLXI/xmo9sgzatJjAYmBgYGDiauD3/ePP18nVgb4MF89+M5ZX6js293wUMpnr8KTQMAxsCJnJ30apMAAAAASUVORK5CYII=',
'postdate' => 1344803528,
),
);
private $_conf;
private $_model;
@@ -45,8 +24,8 @@ class zerobinTest extends PHPUnit_Framework_TestCase
$_POST = array();
$_GET = array();
$_SERVER = array();
if ($this->_model->exists(self::$pasteid))
$this->_model->delete(self::$pasteid);
if ($this->_model->exists(helper::getPasteId()))
$this->_model->delete(helper::getPasteId());
if (is_file($this->_conf . '.bak'))
rename($this->_conf . '.bak', $this->_conf);
}
@@ -70,6 +49,31 @@ class zerobinTest extends PHPUnit_Framework_TestCase
);
}
/**
* @runInSeparateProcess
*/
public function testViewLanguageSelection()
{
$this->reset();
$options = parse_ini_file($this->_conf, true);
$options['main']['languageselection'] = true;
if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
rename($this->_conf, $this->_conf . '.bak');
helper::createIniFile($this->_conf, $options);
$_COOKIE['lang'] = 'de';
ob_start();
new zerobin;
$content = ob_get_contents();
$this->assertTag(
array(
'tag' => 'title',
'content' => 'ZeroBin'
),
$content,
'outputs title correctly'
);
}
/**
* @runInSeparateProcess
*/
@@ -108,30 +112,13 @@ class zerobinTest extends PHPUnit_Framework_TestCase
$content = ob_get_contents();
}
/**
* @runInSeparateProcess
*/
public function testConfMissingExpireLabel()
{
$this->reset();
$options = parse_ini_file($this->_conf, true);
$options['expire_options']['foobar123'] = 10;
if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
rename($this->_conf, $this->_conf . '.bak');
helper::createIniFile($this->_conf, $options);
ini_set('magic_quotes_gpc', 1);
ob_start();
new zerobin;
$content = ob_get_contents();
}
/**
* @runInSeparateProcess
*/
public function testCreate()
{
$this->reset();
$_POST = self::$paste;
$_POST = helper::getPaste();
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new zerobin;
@@ -152,14 +139,14 @@ class zerobinTest extends PHPUnit_Framework_TestCase
public function testCreateInvalidTimelimit()
{
$this->reset();
$_POST = self::$paste;
$_POST = helper::getPaste();
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new zerobin;
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(1, $response['status'], 'outputs error status');
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste exists after posting data');
$this->assertFalse($this->_model->exists(helper::getPasteId()), 'paste exists after posting data');
}
/**
@@ -174,14 +161,35 @@ class zerobinTest extends PHPUnit_Framework_TestCase
if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
rename($this->_conf, $this->_conf . '.bak');
helper::createIniFile($this->_conf, $options);
$_POST = self::$paste;
$_POST = helper::getPaste();
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new zerobin;
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(1, $response['status'], 'outputs error status');
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste exists after posting data');
$this->assertFalse($this->_model->exists(helper::getPasteId()), 'paste exists after posting data');
}
/**
* @runInSeparateProcess
*/
public function testCreateProxyHeader()
{
$this->reset();
$options = parse_ini_file($this->_conf, true);
$options['traffic']['header'] = 'X_FORWARDED_FOR';
if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
rename($this->_conf, $this->_conf . '.bak');
helper::createIniFile($this->_conf, $options);
$_POST = helper::getPaste();
$_SERVER['HTTP_X_FORWARDED_FOR'] = '::1';
ob_start();
new zerobin;
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(1, $response['status'], 'outputs error status');
$this->assertFalse($this->_model->exists(helper::getPasteId()), 'paste exists after posting data');
}
/**
@@ -195,15 +203,15 @@ class zerobinTest extends PHPUnit_Framework_TestCase
if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
rename($this->_conf, $this->_conf . '.bak');
helper::createIniFile($this->_conf, $options);
$this->_model->create(self::$pasteid, self::$paste);
$_POST = self::$paste;
$this->_model->create(helper::getPasteId(), helper::getPaste());
$_POST = helper::getPaste();
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new zerobin;
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(1, $response['status'], 'outputs error status');
$this->assertTrue($this->_model->exists(self::$pasteid), 'paste exists after posting data');
$this->assertTrue($this->_model->exists(helper::getPasteId()), 'paste exists after posting data');
}
/**
@@ -217,8 +225,9 @@ class zerobinTest extends PHPUnit_Framework_TestCase
if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
rename($this->_conf, $this->_conf . '.bak');
helper::createIniFile($this->_conf, $options);
$_POST = self::$paste;
$_POST = helper::getPaste();
$_POST['expire'] = '5min';
$_POST['formatter'] = 'foo';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new zerobin;
@@ -244,7 +253,7 @@ class zerobinTest extends PHPUnit_Framework_TestCase
if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
rename($this->_conf, $this->_conf . '.bak');
helper::createIniFile($this->_conf, $options);
$_POST = self::$paste;
$_POST = helper::getPaste();
$_POST['expire'] = 'foo';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
@@ -271,7 +280,7 @@ class zerobinTest extends PHPUnit_Framework_TestCase
if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
rename($this->_conf, $this->_conf . '.bak');
helper::createIniFile($this->_conf, $options);
$_POST = self::$paste;
$_POST = helper::getPaste();
$_POST['burnafterreading'] = 'neither 1 nor 0';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
@@ -279,7 +288,7 @@ class zerobinTest extends PHPUnit_Framework_TestCase
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(1, $response['status'], 'outputs error status');
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste exists after posting data');
$this->assertFalse($this->_model->exists(helper::getPasteId()), 'paste exists after posting data');
}
/**
@@ -293,7 +302,7 @@ class zerobinTest extends PHPUnit_Framework_TestCase
if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
rename($this->_conf, $this->_conf . '.bak');
helper::createIniFile($this->_conf, $options);
$_POST = self::$paste;
$_POST = helper::getPaste();
$_POST['opendiscussion'] = 'neither 1 nor 0';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
@@ -301,7 +310,34 @@ class zerobinTest extends PHPUnit_Framework_TestCase
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(1, $response['status'], 'outputs error status');
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste exists after posting data');
$this->assertFalse($this->_model->exists(helper::getPasteId()), 'paste exists after posting data');
}
/**
* @runInSeparateProcess
*/
public function testCreateAttachment()
{
$this->reset();
$options = parse_ini_file($this->_conf, true);
$options['traffic']['limit'] = 0;
$options['main']['fileupload'] = true;
if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
rename($this->_conf, $this->_conf . '.bak');
helper::createIniFile($this->_conf, $options);
$_POST = helper::getPaste();
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new zerobin;
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(0, $response['status'], 'outputs status');
$this->assertEquals(
hash_hmac('sha1', $response['id'], serversalt::get()),
$response['deletetoken'],
'outputs valid delete token'
);
$this->assertTrue($this->_model->exists($response['id']), 'paste exists after posting data');
}
/**
@@ -315,8 +351,8 @@ class zerobinTest extends PHPUnit_Framework_TestCase
if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
rename($this->_conf, $this->_conf . '.bak');
helper::createIniFile($this->_conf, $options);
$_POST = self::$paste;
$_POST['nickname'] = self::$comment['meta']['nickname'];
$_POST = helper::getPaste();
$_POST['nickname'] = helper::getComment()['meta']['nickname'];
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new zerobin;
@@ -342,7 +378,7 @@ class zerobinTest extends PHPUnit_Framework_TestCase
if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
rename($this->_conf, $this->_conf . '.bak');
helper::createIniFile($this->_conf, $options);
$_POST = self::$paste;
$_POST = helper::getPaste();
$_POST['nickname'] = 'foo';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
@@ -350,7 +386,7 @@ class zerobinTest extends PHPUnit_Framework_TestCase
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(1, $response['status'], 'outputs error status');
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste exists after posting data');
$this->assertFalse($this->_model->exists(helper::getPasteId()), 'paste exists after posting data');
}
/**
@@ -364,17 +400,17 @@ class zerobinTest extends PHPUnit_Framework_TestCase
if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
rename($this->_conf, $this->_conf . '.bak');
helper::createIniFile($this->_conf, $options);
$_POST = self::$comment;
$_POST['pasteid'] = self::$pasteid;
$_POST['parentid'] = self::$pasteid;
$_POST = helper::getComment();
$_POST['pasteid'] = helper::getPasteId();
$_POST['parentid'] = helper::getPasteId();
$_SERVER['REMOTE_ADDR'] = '::1';
$this->_model->create(self::$pasteid, self::$paste);
$this->_model->create(helper::getPasteId(), helper::getPaste());
ob_start();
new zerobin;
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(0, $response['status'], 'outputs status');
$this->assertTrue($this->_model->existsComment(self::$pasteid, self::$pasteid, $response['id']), 'paste exists after posting data');
$this->assertTrue($this->_model->existsComment(helper::getPasteId(), helper::getPasteId(), $response['id']), 'paste exists after posting data');
}
/**
@@ -388,17 +424,17 @@ class zerobinTest extends PHPUnit_Framework_TestCase
if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
rename($this->_conf, $this->_conf . '.bak');
helper::createIniFile($this->_conf, $options);
$_POST = self::$comment;
$_POST['pasteid'] = self::$pasteid;
$_POST = helper::getComment();
$_POST['pasteid'] = helper::getPasteId();
$_POST['parentid'] = 'foo';
$_SERVER['REMOTE_ADDR'] = '::1';
$this->_model->create(self::$pasteid, self::$paste);
$this->_model->create(helper::getPasteId(), helper::getPaste());
ob_start();
new zerobin;
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(1, $response['status'], 'outputs error status');
$this->assertFalse($this->_model->existsComment(self::$pasteid, self::$pasteid, self::$commentid), 'paste exists after posting data');
$this->assertFalse($this->_model->existsComment(helper::getPasteId(), helper::getPasteId(), helper::getCommentId()), 'paste exists after posting data');
}
/**
@@ -412,19 +448,18 @@ class zerobinTest extends PHPUnit_Framework_TestCase
if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
rename($this->_conf, $this->_conf . '.bak');
helper::createIniFile($this->_conf, $options);
$_POST = self::$comment;
$_POST['pasteid'] = self::$pasteid;
$_POST['parentid'] = self::$pasteid;
$_POST = helper::getComment();
$_POST['pasteid'] = helper::getPasteId();
$_POST['parentid'] = helper::getPasteId();
$_SERVER['REMOTE_ADDR'] = '::1';
$paste = self::$paste;
$paste['meta']['opendiscussion'] = false;
$this->_model->create(self::$pasteid, $paste);
$paste = helper::getPaste(array('opendiscussion' => false));
$this->_model->create(helper::getPasteId(), $paste);
ob_start();
new zerobin;
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(1, $response['status'], 'outputs error status');
$this->assertFalse($this->_model->existsComment(self::$pasteid, self::$pasteid, self::$commentid), 'paste exists after posting data');
$this->assertFalse($this->_model->existsComment(helper::getPasteId(), helper::getPasteId(), helper::getCommentId()), 'paste exists after posting data');
}
/**
@@ -438,16 +473,16 @@ class zerobinTest extends PHPUnit_Framework_TestCase
if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
rename($this->_conf, $this->_conf . '.bak');
helper::createIniFile($this->_conf, $options);
$_POST = self::$comment;
$_POST['pasteid'] = self::$pasteid;
$_POST['parentid'] = self::$pasteid;
$_POST = helper::getComment();
$_POST['pasteid'] = helper::getPasteId();
$_POST['parentid'] = helper::getPasteId();
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new zerobin;
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(1, $response['status'], 'outputs error status');
$this->assertFalse($this->_model->existsComment(self::$pasteid, self::$pasteid, self::$commentid), 'paste exists after posting data');
$this->assertFalse($this->_model->existsComment(helper::getPasteId(), helper::getPasteId(), helper::getCommentId()), 'paste exists after posting data');
}
/**
@@ -461,17 +496,19 @@ class zerobinTest extends PHPUnit_Framework_TestCase
if (!is_file($this->_conf . '.bak') && is_file($this->_conf))
rename($this->_conf, $this->_conf . '.bak');
helper::createIniFile($this->_conf, $options);
$this->_model->createComment(self::$pasteid, self::$pasteid, self::$commentid, self::$comment);
$_POST = self::$comment;
$_POST['pasteid'] = self::$pasteid;
$_POST['parentid'] = self::$pasteid;
$this->_model->create(helper::getPasteId(), helper::getPaste());
$this->_model->createComment(helper::getPasteId(), helper::getPasteId(), helper::getCommentId(), helper::getComment());
$this->assertTrue($this->_model->existsComment(helper::getPasteId(), helper::getPasteId(), helper::getCommentId()), 'comment exists before posting data');
$_POST = helper::getComment();
$_POST['pasteid'] = helper::getPasteId();
$_POST['parentid'] = helper::getPasteId();
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new zerobin;
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(1, $response['status'], 'outputs error status');
$this->assertTrue($this->_model->existsComment(self::$pasteid, self::$pasteid, self::$commentid), 'paste exists after posting data');
$this->assertTrue($this->_model->existsComment(helper::getPasteId(), helper::getPasteId(), helper::getCommentId()), 'paste exists after posting data');
}
/**
@@ -480,15 +517,15 @@ class zerobinTest extends PHPUnit_Framework_TestCase
public function testRead()
{
$this->reset();
$this->_model->create(self::$pasteid, self::$paste);
$_SERVER['QUERY_STRING'] = self::$pasteid;
$this->_model->create(helper::getPasteId(), helper::getPaste());
$_SERVER['QUERY_STRING'] = helper::getPasteId();
ob_start();
new zerobin;
$content = ob_get_contents();
$this->assertTag(
array(
'id' => 'cipherdata',
'content' => htmlspecialchars(json_encode(self::$paste), ENT_NOQUOTES)
'content' => htmlspecialchars(json_encode(helper::getPaste()), ENT_NOQUOTES)
),
$content,
'outputs data correctly'
@@ -521,7 +558,7 @@ class zerobinTest extends PHPUnit_Framework_TestCase
public function testReadNonexisting()
{
$this->reset();
$_SERVER['QUERY_STRING'] = self::$pasteid;
$_SERVER['QUERY_STRING'] = helper::getPasteId();
ob_start();
new zerobin;
$content = ob_get_contents();
@@ -541,10 +578,9 @@ class zerobinTest extends PHPUnit_Framework_TestCase
public function testReadExpired()
{
$this->reset();
$expiredPaste = self::$paste;
$expiredPaste['meta']['expire_date'] = $expiredPaste['meta']['postdate'];
$this->_model->create(self::$pasteid, $expiredPaste);
$_SERVER['QUERY_STRING'] = self::$pasteid;
$expiredPaste = helper::getPaste(array('expire_date' => 1344803344));
$this->_model->create(helper::getPasteId(), $expiredPaste);
$_SERVER['QUERY_STRING'] = helper::getPasteId();
ob_start();
new zerobin;
$content = ob_get_contents();
@@ -564,10 +600,9 @@ class zerobinTest extends PHPUnit_Framework_TestCase
public function testReadBurn()
{
$this->reset();
$burnPaste = self::$paste;
$burnPaste['meta']['burnafterreading'] = true;
$this->_model->create(self::$pasteid, $burnPaste);
$_SERVER['QUERY_STRING'] = self::$pasteid;
$burnPaste = helper::getPaste(array('burnafterreading' => true));
$this->_model->create(helper::getPasteId(), $burnPaste);
$_SERVER['QUERY_STRING'] = helper::getPasteId();
ob_start();
new zerobin;
$content = ob_get_contents();
@@ -587,14 +622,14 @@ class zerobinTest extends PHPUnit_Framework_TestCase
public function testReadJson()
{
$this->reset();
$this->_model->create(self::$pasteid, self::$paste);
$_SERVER['QUERY_STRING'] = self::$pasteid . '&json';
$this->_model->create(helper::getPasteId(), helper::getPaste());
$_SERVER['QUERY_STRING'] = helper::getPasteId() . '&json';
ob_start();
new zerobin;
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(0, $response['status'], 'outputs success status');
$this->assertEquals(array(self::$paste), $response['messages'], 'outputs data correctly');
$this->assertEquals(array(helper::getPaste()), $response['messages'], 'outputs data correctly');
}
/**
@@ -603,7 +638,7 @@ class zerobinTest extends PHPUnit_Framework_TestCase
public function testReadInvalidJson()
{
$this->reset();
$_SERVER['QUERY_STRING'] = self::$pasteid . '&json';
$_SERVER['QUERY_STRING'] = helper::getPasteId() . '&json';
ob_start();
new zerobin;
$content = ob_get_contents();
@@ -611,16 +646,64 @@ class zerobinTest extends PHPUnit_Framework_TestCase
$this->assertEquals(1, $response['status'], 'outputs error status');
}
/**
* @runInSeparateProcess
*/
public function testReadOldSyntax()
{
$this->reset();
$oldPaste = helper::getPaste(array('syntaxcoloring' => true));
unset($oldPaste['meta']['formatter']);
$this->_model->create(helper::getPasteId(), $oldPaste);
$_SERVER['QUERY_STRING'] = helper::getPasteId();
ob_start();
new zerobin;
$content = ob_get_contents();
$oldPaste['meta']['formatter'] = 'syntaxhighlighting';
$this->assertTag(
array(
'id' => 'cipherdata',
'content' => htmlspecialchars(json_encode($oldPaste), ENT_NOQUOTES)
),
$content,
'outputs data correctly'
);
}
/**
* @runInSeparateProcess
*/
public function testReadOldFormat()
{
$this->reset();
$oldPaste = helper::getPaste();
unset($oldPaste['meta']['formatter']);
$this->_model->create(helper::getPasteId(), $oldPaste);
$_SERVER['QUERY_STRING'] = helper::getPasteId();
ob_start();
new zerobin;
$content = ob_get_contents();
$oldPaste['meta']['formatter'] = 'plaintext';
$this->assertTag(
array(
'id' => 'cipherdata',
'content' => htmlspecialchars(json_encode($oldPaste), ENT_NOQUOTES)
),
$content,
'outputs data correctly'
);
}
/**
* @runInSeparateProcess
*/
public function testDelete()
{
$this->reset();
$this->_model->create(self::$pasteid, self::$paste);
$this->assertTrue($this->_model->exists(self::$pasteid), 'paste exists before deleting data');
$_GET['pasteid'] = self::$pasteid;
$_GET['deletetoken'] = hash_hmac('sha1', self::$pasteid, serversalt::get());
$this->_model->create(helper::getPasteId(), helper::getPaste());
$this->assertTrue($this->_model->exists(helper::getPasteId()), 'paste exists before deleting data');
$_GET['pasteid'] = helper::getPasteId();
$_GET['deletetoken'] = hash_hmac('sha1', helper::getPasteId(), serversalt::get());
ob_start();
new zerobin;
$content = ob_get_contents();
@@ -632,7 +715,7 @@ class zerobinTest extends PHPUnit_Framework_TestCase
$content,
'outputs deleted status correctly'
);
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste successfully deleted');
$this->assertFalse($this->_model->exists(helper::getPasteId()), 'paste successfully deleted');
}
/**
@@ -641,7 +724,7 @@ class zerobinTest extends PHPUnit_Framework_TestCase
public function testDeleteInvalidId()
{
$this->reset();
$this->_model->create(self::$pasteid, self::$paste);
$this->_model->create(helper::getPasteId(), helper::getPaste());
$_GET['pasteid'] = 'foo';
$_GET['deletetoken'] = 'bar';
ob_start();
@@ -655,7 +738,7 @@ class zerobinTest extends PHPUnit_Framework_TestCase
$content,
'outputs delete error correctly'
);
$this->assertTrue($this->_model->exists(self::$pasteid), 'paste exists after failing to delete data');
$this->assertTrue($this->_model->exists(helper::getPasteId()), 'paste exists after failing to delete data');
}
/**
@@ -664,7 +747,7 @@ class zerobinTest extends PHPUnit_Framework_TestCase
public function testDeleteInexistantId()
{
$this->reset();
$_GET['pasteid'] = self::$pasteid;
$_GET['pasteid'] = helper::getPasteId();
$_GET['deletetoken'] = 'bar';
ob_start();
new zerobin;
@@ -685,8 +768,8 @@ class zerobinTest extends PHPUnit_Framework_TestCase
public function testDeleteInvalidToken()
{
$this->reset();
$this->_model->create(self::$pasteid, self::$paste);
$_GET['pasteid'] = self::$pasteid;
$this->_model->create(helper::getPasteId(), helper::getPaste());
$_GET['pasteid'] = helper::getPasteId();
$_GET['deletetoken'] = 'bar';
ob_start();
new zerobin;
@@ -699,7 +782,7 @@ class zerobinTest extends PHPUnit_Framework_TestCase
$content,
'outputs delete error correctly'
);
$this->assertTrue($this->_model->exists(self::$pasteid), 'paste exists after failing to delete data');
$this->assertTrue($this->_model->exists(helper::getPasteId()), 'paste exists after failing to delete data');
}
/**
@@ -708,18 +791,17 @@ class zerobinTest extends PHPUnit_Framework_TestCase
public function testDeleteBurnAfterReading()
{
$this->reset();
$burnPaste = self::$paste;
$burnPaste['meta']['burnafterreading'] = true;
$this->_model->create(self::$pasteid, $burnPaste);
$this->assertTrue($this->_model->exists(self::$pasteid), 'paste exists before deleting data');
$_GET['pasteid'] = self::$pasteid;
$burnPaste = helper::getPaste(array('burnafterreading' => true));
$this->_model->create(helper::getPasteId(), $burnPaste);
$this->assertTrue($this->_model->exists(helper::getPasteId()), 'paste exists before deleting data');
$_GET['pasteid'] = helper::getPasteId();
$_GET['deletetoken'] = 'burnafterreading';
ob_start();
new zerobin;
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(0, $response['status'], 'outputs status');
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste successfully deleted');
$this->assertFalse($this->_model->exists(helper::getPasteId()), 'paste successfully deleted');
}
/**
@@ -728,16 +810,16 @@ class zerobinTest extends PHPUnit_Framework_TestCase
public function testDeleteInvalidBurnAfterReading()
{
$this->reset();
$this->_model->create(self::$pasteid, self::$paste);
$this->assertTrue($this->_model->exists(self::$pasteid), 'paste exists before deleting data');
$_GET['pasteid'] = self::$pasteid;
$this->_model->create(helper::getPasteId(), helper::getPaste());
$this->assertTrue($this->_model->exists(helper::getPasteId()), 'paste exists before deleting data');
$_GET['pasteid'] = helper::getPasteId();
$_GET['deletetoken'] = 'burnafterreading';
ob_start();
new zerobin;
$content = ob_get_contents();
$response = json_decode($content, true);
$this->assertEquals(1, $response['status'], 'outputs status');
$this->assertTrue($this->_model->exists(self::$pasteid), 'paste successfully deleted');
$this->assertTrue($this->_model->exists(helper::getPasteId()), 'paste successfully deleted');
}
/**
@@ -746,10 +828,12 @@ class zerobinTest extends PHPUnit_Framework_TestCase
public function testDeleteExpired()
{
$this->reset();
$expiredPaste = self::$paste;
$expiredPaste['meta']['expire_date'] = $expiredPaste['meta']['postdate'];
$this->_model->create(self::$pasteid, $expiredPaste);
$_SERVER['QUERY_STRING'] = self::$pasteid;
$expiredPaste = helper::getPaste(array('expire_date' => 1000));
$this->assertFalse($this->_model->exists(helper::getPasteId()), 'paste does not exist before being created');
$this->_model->create(helper::getPasteId(), $expiredPaste);
$this->assertTrue($this->_model->exists(helper::getPasteId()), 'paste exists before deleting data');
$_GET['pasteid'] = helper::getPasteId();
$_GET['deletetoken'] = 'does not matter in this context, but has to be set';
ob_start();
new zerobin;
$content = ob_get_contents();
@@ -761,6 +845,6 @@ class zerobinTest extends PHPUnit_Framework_TestCase
$content,
'outputs error correctly'
);
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste successfully deleted');
$this->assertFalse($this->_model->exists(helper::getPasteId()), 'paste successfully deleted');
}
}

View File

@@ -1,28 +1,6 @@
<?php
class zerobin_dataTest extends PHPUnit_Framework_TestCase
{
private static $pasteid = '5e9bc25c89fb3bf9';
private static $paste = array(
'data' => '{"iv":"EN39/wd5Nk8HAiSG2K5AsQ","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"QKN1DBXe5PI","ct":"8hA83xDdXjD7K2qfmw5NdA"}',
'meta' => array(
'postdate' => 1344803344,
'expire_date' => 1344803644,
'opendiscussion' => true,
),
);
private static $commentid = '5a52eebf11c4c94b';
private static $comment = array(
'data' => '{"iv":"Pd4pOKWkmDTT9uPwVwd5Ag","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"6nOCU3peNDclDDpFtJEBKA"}',
'meta' => array(
'nickname' => '{"iv":"76MkAtOGC4oFogX/aSMxRA","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"b6Ae/U1xJdsX/+lATud4sQ"}',
'vizhash' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGUlEQVQokWOsl5/94983CNKQMjnxaOePf98MeKwPfNjkLZ3AgARab6b9+PeNEVnDj3/ff/z7ZiHnzsDA8Pv7H2TVPJw8EAYLAwb48OaVgIgYKycLsrYv378wMDB8//qdCVMDRA9EKSsnCwRBxNsepaLboMFlyMDAICAi9uHNK24GITQ/MDAwoNhgIGMLtwGrzegaLjw5jMz9+vUdnN17uwDCQDhJgk0O07yvX9+teDX1x79v6DYIsIjgcgMaYGFgYOBg4kJx2JejkAiBxAw+PzAwMNz4dp6wDXDw4MdNNOl0rWYsNkD89OLXI/xmo9sgzatJjAYmBgYGDiauD3/ePP18nVgb4MF89+M5ZX6js293wUMpnr8KTQMAxsCJnJ30apMAAAAASUVORK5CYII=',
'postdate' => 1344803528,
),
);
private $_model;
private $_path;
@@ -43,28 +21,29 @@ class zerobin_dataTest extends PHPUnit_Framework_TestCase
public function testFileBasedDataStoreWorks()
{
// storing pastes
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste does not yet exist');
$this->assertTrue($this->_model->create(self::$pasteid, self::$paste), 'store new paste');
$this->assertTrue($this->_model->exists(self::$pasteid), 'paste exists after storing it');
$this->assertFalse($this->_model->create(self::$pasteid, self::$paste), 'unable to store the same paste twice');
$this->assertEquals(json_decode(json_encode(self::$paste)), $this->_model->read(self::$pasteid));
$paste = helper::getPaste(array('expire_date' => 1344803344));
$this->assertFalse($this->_model->exists(helper::getPasteId()), 'paste does not yet exist');
$this->assertTrue($this->_model->create(helper::getPasteId(), $paste), 'store new paste');
$this->assertTrue($this->_model->exists(helper::getPasteId()), 'paste exists after storing it');
$this->assertFalse($this->_model->create(helper::getPasteId(), $paste), 'unable to store the same paste twice');
$this->assertEquals(json_decode(json_encode($paste)), $this->_model->read(helper::getPasteId()));
// storing comments
$this->assertFalse($this->_model->existsComment(self::$pasteid, self::$pasteid, self::$commentid), 'comment does not yet exist');
$this->assertTrue($this->_model->createComment(self::$pasteid, self::$pasteid, self::$commentid, self::$comment) !== false, 'store comment');
$this->assertTrue($this->_model->existsComment(self::$pasteid, self::$pasteid, self::$commentid), 'comment exists after storing it');
$comment = json_decode(json_encode(self::$comment));
$comment->meta->commentid = self::$commentid;
$comment->meta->parentid = self::$pasteid;
$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->existsComment(helper::getPasteId(), helper::getPasteId(), helper::getCommentId()), 'comment exists after storing it');
$comment = json_decode(json_encode(helper::getComment()));
$comment->meta->commentid = helper::getCommentId();
$comment->meta->parentid = helper::getPasteId();
$this->assertEquals(
array($comment->meta->postdate => $comment),
$this->_model->readComments(self::$pasteid)
$this->_model->readComments(helper::getPasteId())
);
// deleting pastes
$this->_model->delete(self::$pasteid);
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste successfully deleted');
$this->assertFalse($this->_model->existsComment(self::$pasteid, self::$pasteid, self::$commentid), 'comment was deleted with paste');
$this->assertFalse($this->_model->read(self::$pasteid), 'paste can no longer be found');
$this->_model->delete(helper::getPasteId());
$this->assertFalse($this->_model->exists(helper::getPasteId()), 'paste successfully deleted');
$this->assertFalse($this->_model->existsComment(helper::getPasteId(), helper::getPasteId(), helper::getCommentId()), 'comment was deleted with paste');
$this->assertFalse($this->_model->read(helper::getPasteId()), 'paste can no longer be found');
}
}

View File

@@ -1,28 +1,6 @@
<?php
class zerobin_dbTest extends PHPUnit_Framework_TestCase
{
private static $pasteid = '5e9bc25c89fb3bf9';
private static $paste = array(
'data' => '{"iv":"EN39/wd5Nk8HAiSG2K5AsQ","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"QKN1DBXe5PI","ct":"8hA83xDdXjD7K2qfmw5NdA"}',
'meta' => array(
'postdate' => 1344803344,
'expire_date' => 1344803644,
'opendiscussion' => true,
),
);
private static $commentid = '5a52eebf11c4c94b';
private static $comment = array(
'data' => '{"iv":"Pd4pOKWkmDTT9uPwVwd5Ag","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"6nOCU3peNDclDDpFtJEBKA"}',
'meta' => array(
'nickname' => '{"iv":"76MkAtOGC4oFogX/aSMxRA","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"b6Ae/U1xJdsX/+lATud4sQ"}',
'vizhash' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGUlEQVQokWOsl5/94983CNKQMjnxaOePf98MeKwPfNjkLZ3AgARab6b9+PeNEVnDj3/ff/z7ZiHnzsDA8Pv7H2TVPJw8EAYLAwb48OaVgIgYKycLsrYv378wMDB8//qdCVMDRA9EKSsnCwRBxNsepaLboMFlyMDAICAi9uHNK24GITQ/MDAwoNhgIGMLtwGrzegaLjw5jMz9+vUdnN17uwDCQDhJgk0O07yvX9+teDX1x79v6DYIsIjgcgMaYGFgYOBg4kJx2JejkAiBxAw+PzAwMNz4dp6wDXDw4MdNNOl0rWYsNkD89OLXI/xmo9sgzatJjAYmBgYGDiauD3/ePP18nVgb4MF89+M5ZX6js293wUMpnr8KTQMAxsCJnJ30apMAAAAASUVORK5CYII=',
'postdate' => 1344803528,
),
);
private $_model;
public function setUp()
@@ -40,30 +18,30 @@ class zerobin_dbTest extends PHPUnit_Framework_TestCase
public function testDatabaseBasedDataStoreWorks()
{
// storing pastes
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste does not yet exist');
$this->assertTrue($this->_model->create(self::$pasteid, self::$paste), 'store new paste');
$this->assertTrue($this->_model->exists(self::$pasteid), 'paste exists after storing it');
$this->assertFalse($this->_model->create(self::$pasteid, self::$paste), 'unable to store the same paste twice');
$this->assertEquals(json_decode(json_encode(self::$paste)), $this->_model->read(self::$pasteid));
$paste = helper::getPaste(array('expire_date' => 1344803344));
$this->assertFalse($this->_model->exists(helper::getPasteId()), 'paste does not yet exist');
$this->assertTrue($this->_model->create(helper::getPasteId(), $paste), 'store new paste');
$this->assertTrue($this->_model->exists(helper::getPasteId()), 'paste exists after storing it');
$this->assertFalse($this->_model->create(helper::getPasteId(), $paste), 'unable to store the same paste twice');
$this->assertEquals(json_decode(json_encode($paste)), $this->_model->read(helper::getPasteId()));
// storing comments
$this->assertFalse($this->_model->existsComment(self::$pasteid, self::$pasteid, self::$commentid), 'comment does not yet exist');
$this->assertTrue($this->_model->createComment(self::$pasteid, self::$pasteid, self::$commentid, self::$comment) !== false, 'store comment');
$this->assertTrue($this->_model->existsComment(self::$pasteid, self::$pasteid, self::$commentid), 'comment exists after storing it');
$comment = json_decode(json_encode(self::$comment));
$comment->meta->commentid = self::$commentid;
$comment->meta->parentid = self::$pasteid;
$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->existsComment(helper::getPasteId(), helper::getPasteId(), helper::getCommentId()), 'comment exists after storing it');
$comment = json_decode(json_encode(helper::getComment()));
$comment->meta->commentid = helper::getCommentId();
$comment->meta->parentid = helper::getPasteId();
$this->assertEquals(
array($comment->meta->postdate => $comment),
$this->_model->readComments(self::$pasteid)
$this->_model->readComments(helper::getPasteId())
);
// deleting pastes
$this->_model->delete(self::$pasteid);
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste successfully deleted');
$this->assertFalse($this->_model->existsComment(self::$pasteid, self::$pasteid, self::$commentid), 'comment was deleted with paste');
$this->assertFalse($this->_model->read(self::$pasteid), 'paste can no longer be found');
$this->_model->delete(helper::getPasteId());
$this->assertFalse($this->_model->exists(helper::getPasteId()), 'paste successfully deleted');
$this->assertFalse($this->_model->existsComment(helper::getPasteId(), helper::getPasteId(), helper::getCommentId()), 'comment was deleted with paste');
$this->assertFalse($this->_model->read(helper::getPasteId()), 'paste can no longer be found');
}
/**