Compare commits
143 Commits
dependabot
...
jdenticons
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2ef205411 | ||
|
|
c0758e7bbb | ||
|
|
89d575ace3 | ||
|
|
1892264cf0 | ||
|
|
f5332ee6ff | ||
|
|
e39a2eeb61 | ||
|
|
405067668a | ||
|
|
922feb2779 | ||
|
|
968d7a19bf | ||
|
|
795c030bdb | ||
|
|
613e4e9d57 | ||
|
|
c91d20ae75 | ||
|
|
d5104a1d63 | ||
|
|
78b3630eb5 | ||
|
|
31f75ee138 | ||
|
|
ae3a0b19ee | ||
|
|
d5e7e6e2ab | ||
|
|
8ac69590cf | ||
|
|
ba4878056b | ||
|
|
ae6248e27e | ||
|
|
78aa70e3ab | ||
|
|
670f9ef548 | ||
|
|
1a828884d1 | ||
|
|
18a957ee54 | ||
|
|
8f8adb9b0d | ||
|
|
c3041924b6 | ||
|
|
5584fdb347 | ||
|
|
ec75ef6e36 | ||
|
|
b1f24a51c8 | ||
|
|
60b091d0e1 | ||
|
|
ed5859c6b6 | ||
|
|
cd0a7effa0 | ||
|
|
ab3e8ffd49 | ||
|
|
7269755bc2 | ||
|
|
5e48a927f2 | ||
|
|
bff4d3a016 | ||
|
|
2eab8adcd1 | ||
|
|
92c42afdc7 | ||
|
|
da48f8a9a1 | ||
|
|
7b40893497 | ||
|
|
0a1fccea11 | ||
|
|
3de21004c4 | ||
|
|
d0d0621bac | ||
|
|
3845298804 | ||
|
|
d6c5f97d58 | ||
|
|
f713b92893 | ||
|
|
f254285b01 | ||
|
|
c2d5c6fc43 | ||
|
|
3d4f9cc1b3 | ||
|
|
945435e133 | ||
|
|
d288f2ab73 | ||
|
|
7ab3f3f271 | ||
|
|
019c8b64b8 | ||
|
|
06b01c57ac | ||
|
|
b756da5839 | ||
|
|
8a9761b430 | ||
|
|
79c4ace626 | ||
|
|
534d014254 | ||
|
|
40a037b625 | ||
|
|
5cb40e1f9e | ||
|
|
c9144def9f | ||
|
|
989fe6cc3a | ||
|
|
08ac373b12 | ||
|
|
c2ec38e0a3 | ||
|
|
f31e384980 | ||
|
|
a1b4fcdefb | ||
|
|
09902b9d67 | ||
|
|
f8bb6efcf9 | ||
|
|
930063442a | ||
|
|
849c1c7cd1 | ||
|
|
5e513588db | ||
|
|
fef83a37ef | ||
|
|
4f9af21fb2 | ||
|
|
a66f170c5e | ||
|
|
44f78ffcdf | ||
|
|
2776033997 | ||
|
|
0a949d3903 | ||
|
|
78e915e049 | ||
|
|
4bd5ef9cda | ||
|
|
69034ef9d1 | ||
|
|
2a162d075c | ||
|
|
f4000150fa | ||
|
|
b768a2e8cb | ||
|
|
0a2094f069 | ||
|
|
0dc9ab7576 | ||
|
|
304ae76a04 | ||
|
|
13b4dc79b9 | ||
|
|
9d07e68e7d | ||
|
|
dce8b8d352 | ||
|
|
3115cb8883 | ||
|
|
b0f17f0a91 | ||
|
|
a36351ca37 | ||
|
|
ee212b1a33 | ||
|
|
08b6070359 | ||
|
|
2e2c70ed15 | ||
|
|
38245287d0 | ||
|
|
688574f70c | ||
|
|
8dbe60621d | ||
|
|
23e0000101 | ||
|
|
1aa93f7fb2 | ||
|
|
8dded4e8e4 | ||
|
|
ad6e802e8a | ||
|
|
c6659747ae | ||
|
|
160207b25a | ||
|
|
77409e6065 | ||
|
|
abef3ad37b | ||
|
|
0e630e14b7 | ||
|
|
0f1c2fdb04 | ||
|
|
b61b4253a6 | ||
|
|
afd84da6b2 | ||
|
|
51f5082f39 | ||
|
|
1b727f7fa4 | ||
|
|
4ea2d6020f | ||
|
|
3255a4d954 | ||
|
|
4025619236 | ||
|
|
eef9a52b69 | ||
|
|
7580155243 | ||
|
|
49b8312505 | ||
|
|
d1b53360d5 | ||
|
|
e35710ca30 | ||
|
|
123210bb8f | ||
|
|
e11c89ab85 | ||
|
|
e56b24fc3b | ||
|
|
76fe7063ca | ||
|
|
fa1e4728dc | ||
|
|
d57a849a40 | ||
|
|
d065f42785 | ||
|
|
d848ce2ed2 | ||
|
|
ac06627d9f | ||
|
|
e740d0f761 | ||
|
|
6e60efc2dd | ||
|
|
a105ba7566 | ||
|
|
67365f8602 | ||
|
|
628700afb1 | ||
|
|
5c20a424e1 | ||
|
|
1a5eafe424 | ||
|
|
925f8cb338 | ||
|
|
9e499652be | ||
|
|
61efe71e31 | ||
|
|
48bb2fdf0f | ||
|
|
b46b4300ec | ||
|
|
e536db9b7e | ||
|
|
79fd33d21f |
9
.github/workflows/tests.yml
vendored
9
.github/workflows/tests.yml
vendored
@@ -65,14 +65,13 @@ jobs:
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
# http://man7.org/linux/man-pages/man1/date.1.html
|
||||
# https://github.com/actions/cache#creating-a-cache-key
|
||||
- name: Get Date
|
||||
id: get-date
|
||||
run: |
|
||||
echo "::set-output name=date::$(/bin/date -u "+%Y%m%d")"
|
||||
run: echo "date=$(/bin/date -u "+%Y%m%d")" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Cache dependencies
|
||||
@@ -104,7 +103,7 @@ jobs:
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '12'
|
||||
node-version: '16'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'js/package-lock.json'
|
||||
|
||||
@@ -116,6 +115,6 @@ jobs:
|
||||
working-directory: js
|
||||
|
||||
- name: Run unit tests
|
||||
run: mocha
|
||||
run: npm test
|
||||
working-directory: js
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
# PrivateBin version history
|
||||
|
||||
* **1.4.1 (not yet released)**
|
||||
* ADDED: Translations for Turkish
|
||||
* ADDED: Translations for Turkish, Slovak and Greek
|
||||
* ADDED: S3 Storage backend (#994)
|
||||
* ADDED: Jdenticons as an option for comment icons (#793)
|
||||
* CHANGED: Avoid `SUPER` privilege for setting the `sql_mode` for MariaDB/MySQL (#919)
|
||||
* CHANGED: Upgrading libraries to: zlib 1.2.13
|
||||
* FIXED: Revert to CREATE INDEX without IF NOT EXISTS clauses, to support MySQL (#943)
|
||||
* FIXED: Apply table prefix to indexes as well, to support multiple instances sharing a single database (#943)
|
||||
* FIXED: YOURLS integration via new proxy, storing signature in configuration (#725)
|
||||
* **1.4 (2022-04-09)**
|
||||
* ADDED: Translations for Corsican, Estonian, Finnish and Lojban
|
||||
* ADDED: new HTTP headers improving security (#765)
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
* rodehoed - option to exempt ips from the rate-limiter
|
||||
* Mark van Holsteijn - Google Cloud Storage backend
|
||||
* Austin Huang - Oracle database support
|
||||
* Felix J. Ogris - S3 Storage backend
|
||||
* Mounir Idrassi & J. Mozdzen - secure YOURLS integration
|
||||
|
||||
## Translations
|
||||
* Hexalyse - French
|
||||
@@ -57,3 +59,5 @@
|
||||
* Patriccollu di Santa Maria è Sichè - Corsican
|
||||
* Markus Mikkonen - Finnish
|
||||
* Emir Ensar Rahmanlar - Turkish
|
||||
* Stevo984 - Slovak
|
||||
* Christos Karamolegkos - Greek
|
||||
|
||||
41
INSTALL.md
41
INSTALL.md
@@ -26,7 +26,7 @@ install and configure PrivateBin on your server. It's available on
|
||||
- `open_basedir` access to `/dev/urandom`
|
||||
- mcrypt extension AND `open_basedir` access to `/dev/urandom`
|
||||
- com_dotnet extension
|
||||
- GD extension
|
||||
- GD extension (when using identicon or vizhash icons, jdenticon works without it)
|
||||
- zlib extension
|
||||
- some disk space or a database supported by [PDO](https://php.net/manual/book.pdo.php)
|
||||
- ability to create files and folders in the installation directory and the PATH
|
||||
@@ -232,3 +232,42 @@ Platform using Google Cloud Run is easy and cheap.
|
||||
|
||||
To use the Google Cloud Storage backend you have to install the suggested
|
||||
library using the command `composer require google/cloud-storage`.
|
||||
|
||||
#### Using S3 Storage
|
||||
Similar to Google Cloud Storage, you can choose S3 as storage backend. It uses
|
||||
the AWS SDK for PHP, but can also talk to a Rados gateway as part of a CEPH
|
||||
cluster. To use this backend, you first have to install the SDK in the
|
||||
document root of PrivateBin: `composer require aws/aws-sdk-php`. You have to
|
||||
create the S3 bucket on the CEPH cluster before using the S3 backend.
|
||||
|
||||
In the `[model]` section of cfg/conf.php, set `class` to `S3Storage`.
|
||||
|
||||
You can set any combination of the following options in the `[model_options]`
|
||||
section:
|
||||
|
||||
* region
|
||||
* version
|
||||
* endpoint
|
||||
* bucket
|
||||
* prefix
|
||||
* accesskey
|
||||
* secretkey
|
||||
* use_path_style_endpoint
|
||||
|
||||
By default, prefix is empty. If set, the S3 backend will place all PrivateBin
|
||||
data beneath this prefix.
|
||||
|
||||
For AWS, you have to provide at least `region`, `bucket`, `accesskey`, and
|
||||
`secretkey`.
|
||||
|
||||
For CEPH, follow this example:
|
||||
|
||||
```
|
||||
region = ""
|
||||
version = "2006-03-01"
|
||||
endpoint = "https://s3.my-ceph.invalid"
|
||||
use_path_style_endpoint = true
|
||||
bucket = "my-bucket"
|
||||
accesskey = "my-rados-user"
|
||||
secretkey = "my-rados-pass"
|
||||
```
|
||||
|
||||
@@ -65,10 +65,11 @@ languageselection = false
|
||||
; qrcode = true
|
||||
|
||||
; (optional) IP based icons are a weak mechanism to detect if a comment was from
|
||||
; a different user when the same username was used in a comment. It might be
|
||||
; used to get the IP of a non anonymous comment poster if the server salt is
|
||||
; leaked and a SHA256 HMAC rainbow table is generated for all (relevant) IPs.
|
||||
; Can be set to one these values: "none" / "vizhash" / "identicon" (default).
|
||||
; a different user when the same username was used in a comment. It might get
|
||||
; used to get the IP of a comment poster if the server salt is leaked and a
|
||||
; SHA512 HMAC rainbow table is generated for all (relevant) IPs.
|
||||
; Can be set to one these values:
|
||||
; "none" / "identicon" (default) / "jdenticon" / "vizhash".
|
||||
; icon = "none"
|
||||
|
||||
; Content Security Policy headers allow a website to restrict what sources are
|
||||
@@ -175,6 +176,7 @@ dir = PATH "data"
|
||||
;[model_options]
|
||||
;bucket = "my-private-bin"
|
||||
;prefix = "pastes"
|
||||
;uniformacl = false
|
||||
|
||||
;[model]
|
||||
; example of DB configuration for MySQL
|
||||
@@ -204,3 +206,42 @@ dir = PATH "data"
|
||||
;usr = "privatebin"
|
||||
;pwd = "Z3r0P4ss"
|
||||
;opt[12] = true ; PDO::ATTR_PERSISTENT
|
||||
|
||||
;[model]
|
||||
; example of S3 configuration for Rados gateway / CEPH
|
||||
;class = S3Storage
|
||||
;[model_options]
|
||||
;region = ""
|
||||
;version = "2006-03-01"
|
||||
;endpoint = "https://s3.my-ceph.invalid"
|
||||
;use_path_style_endpoint = true
|
||||
;bucket = "my-bucket"
|
||||
;accesskey = "my-rados-user"
|
||||
;secretkey = "my-rados-pass"
|
||||
|
||||
;[model]
|
||||
; example of S3 configuration for AWS
|
||||
;class = S3Storage
|
||||
;[model_options]
|
||||
;region = "eu-central-1"
|
||||
;version = "latest"
|
||||
;bucket = "my-bucket"
|
||||
;accesskey = "access key id"
|
||||
;secretkey = "secret access key"
|
||||
|
||||
[yourls]
|
||||
; don't mix this up with "urlshortener" config item:
|
||||
; - when using a standard configuration, "urlshortener" will point to the YOURLS
|
||||
; API, including access credentials, and will be part of the PrivateBin public
|
||||
; web page (insecure!)
|
||||
; - when using the parameters in this section ("signature" and "apiurl"),
|
||||
; "urlshortener" will point to a fixed PrivateBin page
|
||||
; ("$basepath/shortenviayourls?link=") and that URL will in turn call YOURLS
|
||||
; server-side, using the URL from "apiurl" and the "access signature" from the
|
||||
; "signature" parameters below.
|
||||
|
||||
; (optional) the "signature" (access key) issued by YOURLS for the using account
|
||||
; signature = ""
|
||||
|
||||
; (optional) the URL of the YOURLS API, called to shorten a PrivateBin URL
|
||||
; apiurl = ""
|
||||
|
||||
@@ -27,10 +27,12 @@
|
||||
"php" : "^5.6.0 || ^7.0 || ^8.0",
|
||||
"paragonie/random_compat" : "2.0.21",
|
||||
"yzalis/identicon" : "2.0.0",
|
||||
"mlocati/ip-lib" : "1.18.0"
|
||||
"mlocati/ip-lib" : "1.18.0",
|
||||
"jdenticon/jdenticon": "^1.0"
|
||||
},
|
||||
"suggest" : {
|
||||
"google/cloud-storage" : "1.26.1"
|
||||
"google/cloud-storage" : "1.26.1",
|
||||
"aws/aws-sdk-php" : "3.239.0"
|
||||
},
|
||||
"require-dev" : {
|
||||
"phpunit/phpunit" : "^4.6 || ^5.0"
|
||||
|
||||
469
composer.lock
generated
469
composer.lock
generated
@@ -4,8 +4,57 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "fa52d4988bfe17d4b27e3a4789a1ec49",
|
||||
"content-hash": "17bceced29627163f7aa330a0697f68b",
|
||||
"packages": [
|
||||
{
|
||||
"name": "jdenticon/jdenticon",
|
||||
"version": "1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dmester/jdenticon-php.git",
|
||||
"reference": "994ee07293fb978f983393ffcb2c0250592a6ac4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/dmester/jdenticon-php/zipball/994ee07293fb978f983393ffcb2c0250592a6ac4",
|
||||
"reference": "994ee07293fb978f983393ffcb2c0250592a6ac4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.7"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Jdenticon\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Daniel Mester Pirttijärvi"
|
||||
}
|
||||
],
|
||||
"description": "Render PNG and SVG identicons.",
|
||||
"homepage": "https://jdenticon.com/",
|
||||
"keywords": [
|
||||
"avatar",
|
||||
"identicon",
|
||||
"jdenticon"
|
||||
],
|
||||
"support": {
|
||||
"docs": "https://jdenticon.com/php-api.html",
|
||||
"issues": "https://github.com/dmester/jdenticon-php/issues",
|
||||
"source": "https://github.com/dmester/jdenticon-php"
|
||||
},
|
||||
"time": "2022-07-02T11:03:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mlocati/ip-lib",
|
||||
"version": "1.18.0",
|
||||
@@ -61,6 +110,10 @@
|
||||
"range",
|
||||
"subnet"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/mlocati/ip-lib/issues",
|
||||
"source": "https://github.com/mlocati/ip-lib/tree/1.18.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sponsors/mlocati",
|
||||
@@ -120,6 +173,11 @@
|
||||
"pseudorandom",
|
||||
"random"
|
||||
],
|
||||
"support": {
|
||||
"email": "info@paragonie.com",
|
||||
"issues": "https://github.com/paragonie/random_compat/issues",
|
||||
"source": "https://github.com/paragonie/random_compat"
|
||||
},
|
||||
"time": "2022-02-16T17:07:03+00:00"
|
||||
},
|
||||
{
|
||||
@@ -172,6 +230,10 @@
|
||||
"identicon",
|
||||
"image"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/yzalis/Identicon/issues",
|
||||
"source": "https://github.com/yzalis/Identicon/tree/master"
|
||||
},
|
||||
"abandoned": true,
|
||||
"time": "2019-10-14T09:30:57+00:00"
|
||||
}
|
||||
@@ -179,31 +241,34 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
"version": "1.4.0",
|
||||
"version": "1.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/instantiator.git",
|
||||
"reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b"
|
||||
"reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b",
|
||||
"reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
|
||||
"reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0"
|
||||
"php": ">=5.3,<8.0-DEV"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^8.0",
|
||||
"athletic/athletic": "~0.1.8",
|
||||
"ext-pdo": "*",
|
||||
"ext-phar": "*",
|
||||
"phpbench/phpbench": "^0.13 || 1.0.0-alpha2",
|
||||
"phpstan/phpstan": "^0.12",
|
||||
"phpstan/phpstan-phpunit": "^0.12",
|
||||
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
|
||||
"phpunit/phpunit": "~4.0",
|
||||
"squizlabs/php_codesniffer": "~2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
|
||||
@@ -217,55 +282,42 @@
|
||||
{
|
||||
"name": "Marco Pivetta",
|
||||
"email": "ocramius@gmail.com",
|
||||
"homepage": "https://ocramius.github.io/"
|
||||
"homepage": "http://ocramius.github.com/"
|
||||
}
|
||||
],
|
||||
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
|
||||
"homepage": "https://www.doctrine-project.org/projects/instantiator.html",
|
||||
"homepage": "https://github.com/doctrine/instantiator",
|
||||
"keywords": [
|
||||
"constructor",
|
||||
"instantiate"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.doctrine-project.org/sponsorship.html",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpdoctrine",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-10T18:47:58+00:00"
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/instantiator/issues",
|
||||
"source": "https://github.com/doctrine/instantiator/tree/master"
|
||||
},
|
||||
"time": "2015-06-14T21:17:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.10.2",
|
||||
"version": "1.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220"
|
||||
"reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220",
|
||||
"reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e",
|
||||
"reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"replace": {
|
||||
"myclabs/deep-copy": "self.version"
|
||||
"php": "^5.6 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/collections": "^1.0",
|
||||
"doctrine/common": "^2.6",
|
||||
"phpunit/phpunit": "^7.1"
|
||||
"phpunit/phpunit": "^4.1"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -288,40 +340,43 @@
|
||||
"object",
|
||||
"object graph"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-13T09:40:50+00:00"
|
||||
"support": {
|
||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.x"
|
||||
},
|
||||
"time": "2017-10-19T19:58:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-common",
|
||||
"version": "2.2.0",
|
||||
"version": "1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
|
||||
"reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
|
||||
"reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
|
||||
"reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
|
||||
"reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0"
|
||||
"php": ">=5.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.6"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-2.x": "2.x-dev"
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"phpDocumentor\\Reflection\\": "src/"
|
||||
"phpDocumentor\\Reflection\\": [
|
||||
"src"
|
||||
]
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@@ -343,42 +398,42 @@
|
||||
"reflection",
|
||||
"static analysis"
|
||||
],
|
||||
"time": "2020-06-27T09:03:43+00:00"
|
||||
"support": {
|
||||
"issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
|
||||
"source": "https://github.com/phpDocumentor/ReflectionCommon/tree/master"
|
||||
},
|
||||
"time": "2017-09-11T18:02:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-docblock",
|
||||
"version": "5.3.0",
|
||||
"version": "3.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
|
||||
"reference": "622548b623e81ca6d78b721c5e029f4ce664f170"
|
||||
"reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170",
|
||||
"reference": "622548b623e81ca6d78b721c5e029f4ce664f170",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bf329f6c1aadea3299f08ee804682b7c45b326a2",
|
||||
"reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-filter": "*",
|
||||
"php": "^7.2 || ^8.0",
|
||||
"phpdocumentor/reflection-common": "^2.2",
|
||||
"phpdocumentor/type-resolver": "^1.3",
|
||||
"webmozart/assert": "^1.9.1"
|
||||
"php": "^5.6 || ^7.0",
|
||||
"phpdocumentor/reflection-common": "^1.0.0",
|
||||
"phpdocumentor/type-resolver": "^0.4.0",
|
||||
"webmozart/assert": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "~1.3.2",
|
||||
"psalm/phar": "^4.8"
|
||||
"mockery/mockery": "^0.9.4",
|
||||
"phpunit/phpunit": "^4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"phpDocumentor\\Reflection\\": "src"
|
||||
"phpDocumentor\\Reflection\\": [
|
||||
"src/"
|
||||
]
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@@ -389,46 +444,48 @@
|
||||
{
|
||||
"name": "Mike van Riel",
|
||||
"email": "me@mikevanriel.com"
|
||||
},
|
||||
{
|
||||
"name": "Jaap van Otterdijk",
|
||||
"email": "account@ijaap.nl"
|
||||
}
|
||||
],
|
||||
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
|
||||
"time": "2021-10-19T17:43:47+00:00"
|
||||
"support": {
|
||||
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
|
||||
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/release/3.x"
|
||||
},
|
||||
"time": "2017-11-10T14:09:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/type-resolver",
|
||||
"version": "1.6.0",
|
||||
"version": "0.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/TypeResolver.git",
|
||||
"reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706"
|
||||
"reference": "9c977708995954784726e25d0cd1dddf4e65b0f7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706",
|
||||
"reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7",
|
||||
"reference": "9c977708995954784726e25d0cd1dddf4e65b0f7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0",
|
||||
"phpdocumentor/reflection-common": "^2.0"
|
||||
"php": "^5.5 || ^7.0",
|
||||
"phpdocumentor/reflection-common": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-tokenizer": "*",
|
||||
"psalm/phar": "^4.8"
|
||||
"mockery/mockery": "^0.9.4",
|
||||
"phpunit/phpunit": "^5.2||^4.8.24"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-1.x": "1.x-dev"
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"phpDocumentor\\Reflection\\": "src"
|
||||
"phpDocumentor\\Reflection\\": [
|
||||
"src/"
|
||||
]
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@@ -441,8 +498,11 @@
|
||||
"email": "me@mikevanriel.com"
|
||||
}
|
||||
],
|
||||
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
|
||||
"time": "2022-01-04T19:58:01+00:00"
|
||||
"support": {
|
||||
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
|
||||
"source": "https://github.com/phpDocumentor/TypeResolver/tree/master"
|
||||
},
|
||||
"time": "2017-07-14T14:27:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
@@ -505,6 +565,10 @@
|
||||
"spy",
|
||||
"stub"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpspec/prophecy/issues",
|
||||
"source": "https://github.com/phpspec/prophecy/tree/v1.10.3"
|
||||
},
|
||||
"time": "2020-03-05T15:02:03+00:00"
|
||||
},
|
||||
{
|
||||
@@ -568,6 +632,11 @@
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"support": {
|
||||
"irc": "irc://irc.freenode.net/phpunit",
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/4.0"
|
||||
},
|
||||
"time": "2017-04-02T07:44:40+00:00"
|
||||
},
|
||||
{
|
||||
@@ -615,6 +684,11 @@
|
||||
"filesystem",
|
||||
"iterator"
|
||||
],
|
||||
"support": {
|
||||
"irc": "irc://irc.freenode.net/phpunit",
|
||||
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
|
||||
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/1.4.5"
|
||||
},
|
||||
"time": "2017-11-27T13:52:08+00:00"
|
||||
},
|
||||
{
|
||||
@@ -656,6 +730,10 @@
|
||||
"keywords": [
|
||||
"template"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-text-template/issues",
|
||||
"source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1"
|
||||
},
|
||||
"time": "2015-06-21T13:50:34+00:00"
|
||||
},
|
||||
{
|
||||
@@ -705,33 +783,37 @@
|
||||
"keywords": [
|
||||
"timer"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-timer/issues",
|
||||
"source": "https://github.com/sebastianbergmann/php-timer/tree/master"
|
||||
},
|
||||
"time": "2017-02-26T11:10:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-token-stream",
|
||||
"version": "2.0.2",
|
||||
"version": "1.4.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
|
||||
"reference": "791198a2c6254db10131eecfe8c06670700904db"
|
||||
"reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db",
|
||||
"reference": "791198a2c6254db10131eecfe8c06670700904db",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16",
|
||||
"reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-tokenizer": "*",
|
||||
"php": "^7.0"
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^6.2.4"
|
||||
"phpunit/phpunit": "~4.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0-dev"
|
||||
"dev-master": "1.4-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -754,21 +836,25 @@
|
||||
"keywords": [
|
||||
"tokenizer"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-token-stream/issues",
|
||||
"source": "https://github.com/sebastianbergmann/php-token-stream/tree/1.4"
|
||||
},
|
||||
"abandoned": true,
|
||||
"time": "2017-11-27T05:48:46+00:00"
|
||||
"time": "2017-12-04T08:55:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "5.7.27",
|
||||
"version": "5.6.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c"
|
||||
"reference": "a9de0dbafeb6b1391b391fbb034734cb0af9f67c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c",
|
||||
"reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a9de0dbafeb6b1391b391fbb034734cb0af9f67c",
|
||||
"reference": "a9de0dbafeb6b1391b391fbb034734cb0af9f67c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -779,21 +865,21 @@
|
||||
"ext-xml": "*",
|
||||
"myclabs/deep-copy": "~1.3",
|
||||
"php": "^5.6 || ^7.0",
|
||||
"phpspec/prophecy": "^1.6.2",
|
||||
"phpunit/php-code-coverage": "^4.0.4",
|
||||
"phpspec/prophecy": "^1.3.1",
|
||||
"phpunit/php-code-coverage": "^4.0.1",
|
||||
"phpunit/php-file-iterator": "~1.4",
|
||||
"phpunit/php-text-template": "~1.2",
|
||||
"phpunit/php-timer": "^1.0.6",
|
||||
"phpunit/phpunit-mock-objects": "^3.2",
|
||||
"sebastian/comparator": "^1.2.4",
|
||||
"sebastian/diff": "^1.4.3",
|
||||
"sebastian/environment": "^1.3.4 || ^2.0",
|
||||
"sebastian/exporter": "~2.0",
|
||||
"sebastian/global-state": "^1.1",
|
||||
"sebastian/object-enumerator": "~2.0",
|
||||
"sebastian/comparator": "~1.1",
|
||||
"sebastian/diff": "~1.2",
|
||||
"sebastian/environment": "^1.3 || ^2.0",
|
||||
"sebastian/exporter": "~1.2",
|
||||
"sebastian/global-state": "~1.0",
|
||||
"sebastian/object-enumerator": "~1.0",
|
||||
"sebastian/resource-operations": "~1.0",
|
||||
"sebastian/version": "^1.0.6|^2.0.1",
|
||||
"symfony/yaml": "~2.1|~3.0|~4.0"
|
||||
"sebastian/version": "~1.0|~2.0",
|
||||
"symfony/yaml": "~2.1|~3.0"
|
||||
},
|
||||
"conflict": {
|
||||
"phpdocumentor/reflection-docblock": "3.0.2"
|
||||
@@ -811,7 +897,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.7.x-dev"
|
||||
"dev-master": "5.6.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -837,7 +923,11 @@
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2018-02-01T05:50:59+00:00"
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/5.6.3"
|
||||
},
|
||||
"time": "2016-11-14T06:39:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit-mock-objects",
|
||||
@@ -896,6 +986,11 @@
|
||||
"mock",
|
||||
"xunit"
|
||||
],
|
||||
"support": {
|
||||
"irc": "irc://irc.freenode.net/phpunit",
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit-mock-objects/issues",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit-mock-objects/tree/3.4"
|
||||
},
|
||||
"abandoned": true,
|
||||
"time": "2017-06-30T09:13:00+00:00"
|
||||
},
|
||||
@@ -942,6 +1037,10 @@
|
||||
],
|
||||
"description": "Looks up which function or method a line of code belongs to",
|
||||
"homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
|
||||
"source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sebastianbergmann",
|
||||
@@ -1012,6 +1111,10 @@
|
||||
"compare",
|
||||
"equality"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/comparator/issues",
|
||||
"source": "https://github.com/sebastianbergmann/comparator/tree/1.2"
|
||||
},
|
||||
"time": "2017-01-29T09:50:25+00:00"
|
||||
},
|
||||
{
|
||||
@@ -1064,6 +1167,10 @@
|
||||
"keywords": [
|
||||
"diff"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/diff/issues",
|
||||
"source": "https://github.com/sebastianbergmann/diff/tree/1.4"
|
||||
},
|
||||
"time": "2017-05-22T07:24:03+00:00"
|
||||
},
|
||||
{
|
||||
@@ -1114,25 +1221,29 @@
|
||||
"environment",
|
||||
"hhvm"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/environment/issues",
|
||||
"source": "https://github.com/sebastianbergmann/environment/tree/master"
|
||||
},
|
||||
"time": "2016-11-26T07:53:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
"version": "2.0.0",
|
||||
"version": "1.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/exporter.git",
|
||||
"reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4"
|
||||
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
|
||||
"reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
|
||||
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"sebastian/recursion-context": "~2.0"
|
||||
"sebastian/recursion-context": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-mbstring": "*",
|
||||
@@ -1141,7 +1252,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
"dev-master": "1.3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -1181,7 +1292,11 @@
|
||||
"export",
|
||||
"exporter"
|
||||
],
|
||||
"time": "2016-11-19T08:54:04+00:00"
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/exporter/issues",
|
||||
"source": "https://github.com/sebastianbergmann/exporter/tree/master"
|
||||
},
|
||||
"time": "2016-06-17T09:04:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/global-state",
|
||||
@@ -1232,25 +1347,29 @@
|
||||
"keywords": [
|
||||
"global state"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/global-state/issues",
|
||||
"source": "https://github.com/sebastianbergmann/global-state/tree/1.1.1"
|
||||
},
|
||||
"time": "2015-10-12T03:26:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/object-enumerator",
|
||||
"version": "2.0.1",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/object-enumerator.git",
|
||||
"reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7"
|
||||
"reference": "d4ca2fb70344987502567bc50081c03e6192fb26"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7",
|
||||
"reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/d4ca2fb70344987502567bc50081c03e6192fb26",
|
||||
"reference": "d4ca2fb70344987502567bc50081c03e6192fb26",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.6",
|
||||
"sebastian/recursion-context": "~2.0"
|
||||
"sebastian/recursion-context": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~5"
|
||||
@@ -1258,7 +1377,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -1278,20 +1397,24 @@
|
||||
],
|
||||
"description": "Traverses array structures and object graphs to enumerate all referenced objects",
|
||||
"homepage": "https://github.com/sebastianbergmann/object-enumerator/",
|
||||
"time": "2017-02-18T15:18:39+00:00"
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
|
||||
"source": "https://github.com/sebastianbergmann/object-enumerator/tree/master"
|
||||
},
|
||||
"time": "2016-01-28T13:25:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/recursion-context",
|
||||
"version": "2.0.0",
|
||||
"version": "1.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/recursion-context.git",
|
||||
"reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a"
|
||||
"reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a",
|
||||
"reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
|
||||
"reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1303,7 +1426,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -1331,7 +1454,11 @@
|
||||
],
|
||||
"description": "Provides functionality to recursively process PHP variables",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
|
||||
"time": "2016-11-19T07:33:16+00:00"
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/recursion-context/issues",
|
||||
"source": "https://github.com/sebastianbergmann/recursion-context/tree/master"
|
||||
},
|
||||
"time": "2016-10-03T07:41:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/resource-operations",
|
||||
@@ -1373,6 +1500,10 @@
|
||||
],
|
||||
"description": "Provides a list of PHP built-in functions that operate on resources",
|
||||
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/resource-operations/issues",
|
||||
"source": "https://github.com/sebastianbergmann/resource-operations/tree/master"
|
||||
},
|
||||
"time": "2015-07-28T20:34:47+00:00"
|
||||
},
|
||||
{
|
||||
@@ -1416,27 +1547,28 @@
|
||||
],
|
||||
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
|
||||
"homepage": "https://github.com/sebastianbergmann/version",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/version/issues",
|
||||
"source": "https://github.com/sebastianbergmann/version/tree/master"
|
||||
},
|
||||
"time": "2016-10-03T07:35:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.24.0",
|
||||
"version": "v1.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "30885182c981ab175d4d034db0f6f469898070ab"
|
||||
"reference": "aed596913b70fae57be53d86faa2e9ef85a2297b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab",
|
||||
"reference": "30885182c981ab175d4d034db0f6f469898070ab",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/aed596913b70fae57be53d86faa2e9ef85a2297b",
|
||||
"reference": "aed596913b70fae57be53d86faa2e9ef85a2297b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"provide": {
|
||||
"ext-ctype": "*"
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-ctype": "For best performance"
|
||||
@@ -1444,7 +1576,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.23-dev"
|
||||
"dev-main": "1.19-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -1452,12 +1584,12 @@
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Ctype\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Ctype\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
@@ -1481,6 +1613,9 @@
|
||||
"polyfill",
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.19.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
@@ -1495,31 +1630,31 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-10-20T20:35:02+00:00"
|
||||
"time": "2020-10-23T09:01:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v4.4.37",
|
||||
"version": "v3.4.47",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "d7f637cc0f0cc14beb0984f2bb50da560b271311"
|
||||
"reference": "88289caa3c166321883f67fe5130188ebbb47094"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/d7f637cc0f0cc14beb0984f2bb50da560b271311",
|
||||
"reference": "d7f637cc0f0cc14beb0984f2bb50da560b271311",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/88289caa3c166321883f67fe5130188ebbb47094",
|
||||
"reference": "88289caa3c166321883f67fe5130188ebbb47094",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1.3",
|
||||
"php": "^5.5.9|>=7.0.8",
|
||||
"symfony/polyfill-ctype": "~1.8"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/console": "<3.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/console": "^3.4|^4.0|^5.0"
|
||||
"symfony/console": "~3.4|~4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/console": "For validating YAML files using the lint command"
|
||||
@@ -1547,8 +1682,11 @@
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Loads and dumps YAML files",
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/yaml/tree/v3.4.47"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
@@ -1563,39 +1701,34 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-01-24T20:11:01+00:00"
|
||||
"time": "2020-10-24T10:57:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
"version": "1.10.0",
|
||||
"version": "1.9.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/webmozarts/assert.git",
|
||||
"reference": "6964c76c7804814a842473e0c8fd15bab0f18e25"
|
||||
"reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25",
|
||||
"reference": "6964c76c7804814a842473e0c8fd15bab0f18e25",
|
||||
"url": "https://api.github.com/repos/webmozarts/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389",
|
||||
"reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0",
|
||||
"php": "^5.3.3 || ^7.0 || ^8.0",
|
||||
"symfony/polyfill-ctype": "^1.8"
|
||||
},
|
||||
"conflict": {
|
||||
"phpstan/phpstan": "<0.12.20",
|
||||
"vimeo/psalm": "<4.6.1 || 4.6.2"
|
||||
"vimeo/psalm": "<3.9.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.5.13"
|
||||
"phpunit/phpunit": "^4.8.36 || ^7.5.13"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.10-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Webmozart\\Assert\\": "src/"
|
||||
@@ -1617,7 +1750,11 @@
|
||||
"check",
|
||||
"validate"
|
||||
],
|
||||
"time": "2021-03-09T10:59:23+00:00"
|
||||
"support": {
|
||||
"issues": "https://github.com/webmozarts/assert/issues",
|
||||
"source": "https://github.com/webmozarts/assert/tree/1.9.1"
|
||||
},
|
||||
"time": "2020-07-08T17:02:28+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
@@ -1629,5 +1766,5 @@
|
||||
"php": "^5.6.0 || ^7.0 || ^8.0"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "1.1.0"
|
||||
"plugin-api-version": "2.3.0"
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Use Current Timezone",
|
||||
"Convert To UTC": "Convert To UTC",
|
||||
"Close": "Close",
|
||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
||||
"Encrypted note on %s": "Encrypted note on %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||
"Save paste": "Save paste",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Use Current Timezone",
|
||||
"Convert To UTC": "Convert To UTC",
|
||||
"Close": "Close",
|
||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
||||
"Encrypted note on %s": "Encrypted note on %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||
"Save paste": "Save paste",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Use Current Timezone",
|
||||
"Convert To UTC": "Convert To UTC",
|
||||
"Close": "Close",
|
||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
||||
"Encrypted note on %s": "Encrypted note on %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||
"Save paste": "Save paste",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Impiegà u fusu orariu attuale",
|
||||
"Convert To UTC": "Cunvertisce in UTC",
|
||||
"Close": "Chjode",
|
||||
"Encrypted note on PrivateBin": "Nota cifrata nant’à PrivateBin",
|
||||
"Encrypted note on %s": "Nota cifrata nant’à %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visitate stu liame per vede a nota. Date l’indirizzu à qualunque li permette d’accede à a nota dinù.",
|
||||
"URL shortener may expose your decrypt key in URL.": "Un ammuzzatore d’indirizzu pò palisà a vostra chjave di dicifratura in l’indirizzu.",
|
||||
"Save paste": "Arregistrà l’appiccicu",
|
||||
"Your IP is not authorized to create pastes.": "U vostru indirizzu IP ùn hè micca auturizatu à creà l’appiccichi."
|
||||
"Your IP is not authorized to create pastes.": "U vostru indirizzu IP ùn hè micca auturizatu à creà l’appiccichi.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Pruvate d’ammuzzà un indirizzu web chì ùn punta micca versu a vostra instanza.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Sbagliu à a chjama di YOURLS. Seria forse una cunfigurazione gattiva, tale una \"apiurl\" o \"signature\" falsa o assente.",
|
||||
"Error parsing YOURLS response.": "Sbagliu durante l’analisa di a risposta di YOURLS."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Použít aktuální časové pásmo",
|
||||
"Convert To UTC": "Převést na UTC",
|
||||
"Close": "Zavřít",
|
||||
"Encrypted note on PrivateBin": "Šifrovaná poznámka ve službě PrivateBin",
|
||||
"Encrypted note on %s": "Šifrovaná poznámka ve službě %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Navštivte tento odkaz pro zobrazení poznámky. Přeposláním URL umožníte také jiným lidem přístup.",
|
||||
"URL shortener may expose your decrypt key in URL.": "Zkracovač URL může odhalit váš dešifrovací klíč v URL.",
|
||||
"Save paste": "Uložit příspěvek",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Vaše IP adresa nemá oprávnění k vytvoření vložení.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Aktuelle Zeitzone verwenden",
|
||||
"Convert To UTC": "In UTC umwandeln",
|
||||
"Close": "Schliessen",
|
||||
"Encrypted note on PrivateBin": "Verschlüsselte Notiz auf PrivateBin",
|
||||
"Encrypted note on %s": "Verschlüsselte Notiz auf %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Besuche diesen Link um das Dokument zu sehen. Wird die URL an eine andere Person gegeben, so kann diese Person ebenfalls auf dieses Dokument zugreifen.",
|
||||
"URL shortener may expose your decrypt key in URL.": "Der URL-Verkürzer kann den Schlüssel in der URL enthüllen.",
|
||||
"Save paste": "Text speichern",
|
||||
"Your IP is not authorized to create pastes.": "Deine IP ist nicht berechtigt, Texte zu erstellen."
|
||||
"Your IP is not authorized to create pastes.": "Deine IP ist nicht berechtigt, Texte zu erstellen.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Versuch eine URL zu verkürzen, die nicht auf unsere Instanz zeigt.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Fehler beim Aufruf von YOURLS. Wahrscheinlich ein Konfigurationsproblem, wie eine falsche oder fehlende \"apiurl\" oder \"signature\".",
|
||||
"Error parsing YOURLS response.": "Fehler beim Verarbeiten der YOURLS-Antwort."
|
||||
}
|
||||
|
||||
303
i18n/el.json
303
i18n/el.json
@@ -1,135 +1,135 @@
|
||||
{
|
||||
"PrivateBin": "PrivateBin",
|
||||
"%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.",
|
||||
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "More information on the <a href=\"https://privatebin.info/\">project page</a>.",
|
||||
"Because ignorance is bliss": "Because ignorance is bliss",
|
||||
"%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s είναι ένα λιτό, ανοικτού λογισμικού διαδικτυακής υπηρεσίας επικόλλησης όπου ο διακομιστής έχει πλήρη άγνια του περιεχομένου που επικολλήθηκαν. Τα Δεδομένα κρυπτογραφούνται και αποκρυπτογραφούνται %sστον φιλομετρητή (browser)%s χρησιμοποιόντας 256 bits AES.",
|
||||
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "Περισσότερες πληροφορίες στον <a href=\"https://privatebin.info/\">ιστότοπο του εργαλείου</a>.",
|
||||
"Because ignorance is bliss": "Επειδή η άγνοια είναι ευτυχία",
|
||||
"en": "el",
|
||||
"Paste does not exist, has expired or has been deleted.": "Paste does not exist, has expired or has been deleted.",
|
||||
"%s requires php %s or above to work. Sorry.": "%s requires php %s or above to work. Sorry.",
|
||||
"%s requires configuration section [%s] to be present in configuration file.": "%s requires configuration section [%s] to be present in configuration file.",
|
||||
"Paste does not exist, has expired or has been deleted.": "Η επικόλληση δεν υπάρχει, έληξε ή διαγράφηκε",
|
||||
"%s requires php %s or above to work. Sorry.": "%s απαιτεί php %s ή νεότερη για να λειτουργήσει. Συγγνώμη.",
|
||||
"%s requires configuration section [%s] to be present in configuration file.": "%s απαιτεί οι ρυθμίσεις [%s] να υπάρχουν στο αρχείο ρυθμίσεων.",
|
||||
"Please wait %d seconds between each post.": [
|
||||
"Please wait %d second between each post. (singular)",
|
||||
"Please wait %d seconds between each post. (1st plural)",
|
||||
"Please wait %d seconds between each post. (2nd plural)",
|
||||
"Please wait %d seconds between each post. (3rd plural)"
|
||||
"Παρακαλώ περιμένετε %d δευτερόλεπτο μεταξύ κάθε επικόλλησης.",
|
||||
"Παρακαλώ περιμένετε %d δευτερόλεπτα μεταξύ κάθε επικόλλησης.",
|
||||
"Παρακαλώ περιμένετε %d δευτερόλεπτα μεταξύ κάθε επικόλλησης.",
|
||||
"Παρακαλώ περιμένετε %d δευτερόλεπτα μεταξύ κάθε επικόλλησης."
|
||||
],
|
||||
"Paste is limited to %s of encrypted data.": "Paste is limited to %s of encrypted data.",
|
||||
"Invalid data.": "Invalid data.",
|
||||
"You are unlucky. Try again.": "You are unlucky. Try again.",
|
||||
"Error saving comment. Sorry.": "Error saving comment. Sorry.",
|
||||
"Error saving paste. Sorry.": "Error saving paste. Sorry.",
|
||||
"Invalid paste ID.": "Invalid paste ID.",
|
||||
"Paste is not of burn-after-reading type.": "Paste is not of burn-after-reading type.",
|
||||
"Wrong deletion token. Paste was not deleted.": "Wrong deletion token. Paste was not deleted.",
|
||||
"Paste was properly deleted.": "Paste was properly deleted.",
|
||||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.",
|
||||
"%s requires a modern browser to work.": "%s requires a modern browser to work.",
|
||||
"New": "New",
|
||||
"Send": "Send",
|
||||
"Clone": "Clone",
|
||||
"Raw text": "Raw text",
|
||||
"Expires": "Expires",
|
||||
"Burn after reading": "Burn after reading",
|
||||
"Open discussion": "Open discussion",
|
||||
"Password (recommended)": "Password (recommended)",
|
||||
"Discussion": "Discussion",
|
||||
"Toggle navigation": "Toggle navigation",
|
||||
"Paste is limited to %s of encrypted data.": "Η επικόλληση είναι περιορισμένη σε %s κρυπτογραφημένων δεδομένων.",
|
||||
"Invalid data.": "Λάθος δεδομένα.",
|
||||
"You are unlucky. Try again.": "Ατυχήσατε. Προσπαθήστε πάλι.",
|
||||
"Error saving comment. Sorry.": "Λάθος στην αποθήκευση του σχόλιου. Συγγνώμη.",
|
||||
"Error saving paste. Sorry.": "Λάθος στην αποθήκευση της επικόλλησης. Συγγνώμη.",
|
||||
"Invalid paste ID.": "Λάθος αναγνωριστικό επικόλλησης.",
|
||||
"Paste is not of burn-after-reading type.": "Η επικόληση δεν είναι τύπου καταστροφή-μετά-το-διάβασμα.",
|
||||
"Wrong deletion token. Paste was not deleted.": "Λάθος αναγνωριστικό διαγραφής. Η επικόλληση δεν διαγράφηκε.",
|
||||
"Paste was properly deleted.": "Η επικόλληση διαγράφηκε επιτυχώς.",
|
||||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Η JavaScript είναι απαραίτητη για να λειτουργήσει το %s. Συγγνώμη για την ταλαιπωρία.",
|
||||
"%s requires a modern browser to work.": "%s απαιτεί σύγχρονο φυλλομετρητή (browser) για να λειτουργήσει.",
|
||||
"New": "Νέο",
|
||||
"Send": "Αποστολή",
|
||||
"Clone": "Κλωνοποίηση",
|
||||
"Raw text": "Κείμενο",
|
||||
"Expires": "Λήγει",
|
||||
"Burn after reading": "Διαγραφή μετά την ανάγνωση",
|
||||
"Open discussion": "Ανοικτή συζήτηση",
|
||||
"Password (recommended)": "Κωδικός (προτείνεται)",
|
||||
"Discussion": "Συζήτηση",
|
||||
"Toggle navigation": "Εναλλαγή πλοήγησης",
|
||||
"%d seconds": [
|
||||
"%d second (singular)",
|
||||
"%d seconds (1st plural)",
|
||||
"%d seconds (2nd plural)",
|
||||
"%d seconds (3rd plural)"
|
||||
"%d δευτερόλεπτο",
|
||||
"%d δευτερόλεπτα",
|
||||
"%d δευτερόλεπτα",
|
||||
"%d δευτερόλεπτα"
|
||||
],
|
||||
"%d minutes": [
|
||||
"%d minute (singular)",
|
||||
"%d minutes (1st plural)",
|
||||
"%d minutes (2nd plural)",
|
||||
"%d minutes (3rd plural)"
|
||||
"%d λεπτό",
|
||||
"%d λεπτά",
|
||||
"%d λεπτά",
|
||||
"%d λεπτά"
|
||||
],
|
||||
"%d hours": [
|
||||
"%d hour (singular)",
|
||||
"%d hours (1st plural)",
|
||||
"%d hours (2nd plural)",
|
||||
"%d hours (3rd plural)"
|
||||
"%d ώρα",
|
||||
"%d ώρες",
|
||||
"%d ώρες",
|
||||
"%d ώρες"
|
||||
],
|
||||
"%d days": [
|
||||
"%d day (singular)",
|
||||
"%d days (1st plural)",
|
||||
"%d days (2nd plural)",
|
||||
"%d days (3rd plural)"
|
||||
"%d ημέρα",
|
||||
"%d ημέρες",
|
||||
"%d ημέρες",
|
||||
"%d ημέρες"
|
||||
],
|
||||
"%d weeks": [
|
||||
"%d week (singular)",
|
||||
"%d weeks (1st plural)",
|
||||
"%d weeks (2nd plural)",
|
||||
"%d weeks (3rd plural)"
|
||||
"%d εβδομάδα",
|
||||
"%d εβδομάδες",
|
||||
"%d εβδομάδες",
|
||||
"%d εβδομάδες"
|
||||
],
|
||||
"%d months": [
|
||||
"%d month (singular)",
|
||||
"%d months (1st plural)",
|
||||
"%d months (2nd plural)",
|
||||
"%d months (3rd plural)"
|
||||
"%d μήνας",
|
||||
"%d μήνες",
|
||||
"%d μήνες",
|
||||
"%d μήνες"
|
||||
],
|
||||
"%d years": [
|
||||
"%d year (singular)",
|
||||
"%d years (1st plural)",
|
||||
"%d years (2nd plural)",
|
||||
"%d years (3rd plural)"
|
||||
"%d χρόνο",
|
||||
"%d χρόνια",
|
||||
"%d χρόνια",
|
||||
"%d χρόνια"
|
||||
],
|
||||
"Never": "Never",
|
||||
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.",
|
||||
"Never": "Ποτέ",
|
||||
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Σημείωση: αυτή είναι μία δοκιμαστική υπηρεσία. Τα δεδομένα μπορεί να σβηστούν ανά πάσα στιγμή.",
|
||||
"This document will expire in %d seconds.": [
|
||||
"This document will expire in %d second. (singular)",
|
||||
"This document will expire in %d seconds. (1st plural)",
|
||||
"This document will expire in %d seconds. (2nd plural)",
|
||||
"This document will expire in %d seconds. (3rd plural)"
|
||||
"Αυτό το έγγραφο θα λήξει σε %d δευτερόλεπτο.",
|
||||
"Αυτό το έγγραφο θα λήξει σε %d δευτερόλεπτα.",
|
||||
"Αυτό το έγγραφο θα λήξει σε %d δευτερόλεπτα.",
|
||||
"Αυτό το έγγραφο θα λήξει σε %d δευτερόλεπτα."
|
||||
],
|
||||
"This document will expire in %d minutes.": [
|
||||
"This document will expire in %d minute. (singular)",
|
||||
"This document will expire in %d minutes. (1st plural)",
|
||||
"This document will expire in %d minutes. (2nd plural)",
|
||||
"This document will expire in %d minutes. (3rd plural)"
|
||||
"Αυτό το έγγραφο θα λήξει σε %d λεπτό.",
|
||||
"Αυτό το έγγραφο θα λήξει σε %d λεπτά.",
|
||||
"Αυτό το έγγραφο θα λήξει σε %d λεπτά.",
|
||||
"Αυτό το έγγραφο θα λήξει σε %d λεπτά."
|
||||
],
|
||||
"This document will expire in %d hours.": [
|
||||
"This document will expire in %d hour. (singular)",
|
||||
"This document will expire in %d hours. (1st plural)",
|
||||
"This document will expire in %d hours. (2nd plural)",
|
||||
"This document will expire in %d hours. (3rd plural)"
|
||||
"Αυτό το έγγραφο θα λήξει σε %d ώρα.",
|
||||
"Αυτό το έγγραφο θα λήξει σε %d ώρες.",
|
||||
"Αυτό το έγγραφο θα λήξει σε %d ώρες.",
|
||||
"Αυτό το έγγραφο θα λήξει σε %d ώρες."
|
||||
],
|
||||
"This document will expire in %d days.": [
|
||||
"This document will expire in %d day. (singular)",
|
||||
"This document will expire in %d days. (1st plural)",
|
||||
"This document will expire in %d days. (2nd plural)",
|
||||
"This document will expire in %d days. (3rd plural)"
|
||||
"Αυτό το έγγραφο θα λήξει σε %d ημέρα.",
|
||||
"Αυτό το έγγραφο θα λήξει σε %d ημέρες.",
|
||||
"Αυτό το έγγραφο θα λήξει σε %d ημέρες.",
|
||||
"Αυτό το έγγραφο θα λήξει σε %d ημέρες."
|
||||
],
|
||||
"This document will expire in %d months.": [
|
||||
"This document will expire in %d month. (singular)",
|
||||
"This document will expire in %d months. (1st plural)",
|
||||
"This document will expire in %d months. (2nd plural)",
|
||||
"This document will expire in %d months. (3rd plural)"
|
||||
"Αυτό το έγγραφο θα λήξει σε %d μήνα.",
|
||||
"Αυτό το έγγραφο θα λήξει σε %d μήνες.",
|
||||
"Αυτό το έγγραφο θα λήξει σε %d μήνες.",
|
||||
"Αυτό το έγγραφο θα λήξει σε %d μήνες."
|
||||
],
|
||||
"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",
|
||||
"Avatar generated from IP address": "Avatar generated from 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…": "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?)",
|
||||
"Please enter the password for this paste:": "Παρακαλώ εισάγετε τον κωδικό για αυτή την επικόληση:",
|
||||
"Could not decrypt data (Wrong key?)": "Δεν ήταν δυνατή η αποκρυπτογράφηση των δεδομένων (πιθανώς λανθασμένο κλειδί;)",
|
||||
"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.": "ΜΟΝΟ ΓΙΑ ΕΣΑΣ. Μην κλείσετε το αυτό το παράθυρο, αυτό το μήνυμα δεν μπορεί να εμφανιστεί ξανά.",
|
||||
"Could not decrypt comment; Wrong key?": "Δεν ήταν δυνατή η αποκρυπτογράφηση του σχολίου. Λάθος κλειδί;",
|
||||
"Reply": "Απάντηση",
|
||||
"Anonymous": "Ανώνυμος",
|
||||
"Avatar generated from IP address": "το avatar δημιουργήθηκε από τη διεύθυνση IP",
|
||||
"Add comment": "Σχολιάστε",
|
||||
"Optional nickname…": "Προαιρετικό ψευδώνυμο…",
|
||||
"Post comment": "Αποστολή σχολίου",
|
||||
"Sending comment…": "Το σχόλιο αποστέλλεται…",
|
||||
"Comment posted.": "Το σχόλιο δημοσιεύτηκε.",
|
||||
"Could not refresh display: %s": "Δεν ήταν δυνατή η ανανέωση της σελίδας: %s",
|
||||
"unknown status": "άγνωστη κατάσταση",
|
||||
"server error or not responding": "Πρόβλημα του διακομιστή ή δεν υπάρχει απάντηση",
|
||||
"Could not post comment: %s": "Δεν ήταν δυνατή η δημοσίευση του σχολίου: %s",
|
||||
"Sending paste…": "Η επικόλληση αποστέλλεται…",
|
||||
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>": "Η επικόλλησή σας είναι <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Πληκτρολογήστε [Ctrl]+[c] για αντιγραφή)</span>",
|
||||
"Delete data": "Διαγραφή δεδομένων",
|
||||
"Could not create paste: %s": "Δεν ήταν δυνατή η δημιουργία επικόλλησης: %s",
|
||||
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Δεν ήταν δυνατή η αποκρυπτογράφηση της επικόλλησης: Το κλειδί αποκρυπτογράφησης λείπει από τον σύνδεσμο (Μήπως χρησιμοποιήσατε ανακατεύθυνση συνδέσμου ή υπηρεσία συντόμευσης συνδέσμου;)",
|
||||
"B": "B",
|
||||
"KiB": "KiB",
|
||||
"MiB": "MiB",
|
||||
@@ -139,52 +139,55 @@
|
||||
"EiB": "EiB",
|
||||
"ZiB": "ZiB",
|
||||
"YiB": "YiB",
|
||||
"Format": "Format",
|
||||
"Plain Text": "Plain Text",
|
||||
"Source Code": "Source Code",
|
||||
"Format": "Μορφοποίηση",
|
||||
"Plain Text": "Απλό κείμενο",
|
||||
"Source Code": "Πηγαίος Κώδικας",
|
||||
"Markdown": "Markdown",
|
||||
"Download attachment": "Download attachment",
|
||||
"Cloned: '%s'": "Cloned: '%s'",
|
||||
"The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.",
|
||||
"Attach a file": "Attach a file",
|
||||
"alternatively drag & drop a file or paste an image from the clipboard": "alternatively drag & drop a file or paste an image from the clipboard",
|
||||
"File too large, to display a preview. Please download the attachment.": "File too large, to display a preview. Please download the attachment.",
|
||||
"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",
|
||||
"Shorten URL": "Shorten URL",
|
||||
"Editor": "Editor",
|
||||
"Preview": "Preview",
|
||||
"%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.",
|
||||
"Decrypt": "Decrypt",
|
||||
"Enter password": "Enter password",
|
||||
"Loading…": "Loading…",
|
||||
"Decrypting paste…": "Decrypting paste…",
|
||||
"Preparing new paste…": "Preparing new paste…",
|
||||
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.": "In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.",
|
||||
"+++ no paste text +++": "+++ no paste text +++",
|
||||
"Could not get paste data: %s": "Could not get paste data: %s",
|
||||
"QR code": "QR code",
|
||||
"This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.",
|
||||
"For more information <a href=\"%s\">see this FAQ entry</a>.": "For more information <a href=\"%s\">see this FAQ entry</a>.",
|
||||
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
|
||||
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.",
|
||||
"waiting on user to provide a password": "waiting on user to provide a password",
|
||||
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.",
|
||||
"Retry": "Retry",
|
||||
"Showing raw text…": "Showing raw text…",
|
||||
"Notice:": "Notice:",
|
||||
"This link will expire after %s.": "This link will expire after %s.",
|
||||
"This link can only be accessed once, do not use back or refresh button in your browser.": "This link can only be accessed once, do not use back or refresh button in your browser.",
|
||||
"Link:": "Link:",
|
||||
"Recipient may become aware of your timezone, convert time to UTC?": "Recipient may become aware of your timezone, convert time to UTC?",
|
||||
"Use Current Timezone": "Use Current Timezone",
|
||||
"Convert To UTC": "Convert To UTC",
|
||||
"Close": "Close",
|
||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||
"Save paste": "Save paste",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Download attachment": "Λήψη επισυναπτόμενου",
|
||||
"Cloned: '%s'": "Κλώνος: '%s'",
|
||||
"The cloned file '%s' was attached to this paste.": "Το κλωνοποιημένο αρχείο '%s' επισυνάφθηκε στ αυτή την επικόλληση.",
|
||||
"Attach a file": "Επισύναψη αρχείου",
|
||||
"alternatively drag & drop a file or paste an image from the clipboard": "εναλλακτικά σύρετε το αρχείο ή επικολλήστε μία εικόνα από το clipboard",
|
||||
"File too large, to display a preview. Please download the attachment.": "Πολύ μεγάλο αρχείο για προεπισκόπηση. Παρακαλώ κατεβάστε το επισυναπτόμενο.",
|
||||
"Remove attachment": "Αφαίρεση επισυναπτόμενου",
|
||||
"Your browser does not support uploading encrypted files. Please use a newer browser.": "Ο φυλλομετρητής (browser) σας δεν υποστηρίζει κρυπτογραφημένα αρχεία. Παρακαλώ χρησιμοποιήστε νεότερο φιλομετρητή.",
|
||||
"Invalid attachment.": "Λάθος επισυναπτόμενο.",
|
||||
"Options": "Επιλογές",
|
||||
"Shorten URL": "Συντόμευση σύνδεσμου",
|
||||
"Editor": "Διορθωτής",
|
||||
"Preview": "Προεπισκόπηση",
|
||||
"%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s απαιτεί το PATH να τελειώνει σε \"%s\". Παρακαλώ ενημερώστε το PATH στο index.php σας.",
|
||||
"Decrypt": "Αποκρυπτογράφηση",
|
||||
"Enter password": "Εισαγωγή κωδικού",
|
||||
"Loading…": "Φόρτωση…",
|
||||
"Decrypting paste…": "Η επικόλληση αποκρυπτογραφείται…",
|
||||
"Preparing new paste…": "Προετοιμασία νέας επικόλλησης…",
|
||||
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.": "Σε περίπτωση που αυτό το μήνυμα δεν εξαφανίζεται παρακαλώ κοιτάξτε στις <a href=\"%s\">Ερωταποκρίσεις για πληροφορίες στην αντιμετώπιση προβλημάτων</a>.",
|
||||
"+++ no paste text +++": "+++ Δεν υπάρχει επικόλληση +++",
|
||||
"Could not get paste data: %s": "Δεν ήταν δυνατή η λήψη της επικόλλησης: %s",
|
||||
"QR code": "QR εικονοστοιχειοσειρά",
|
||||
"This website is using an insecure HTTP connection! Please use it only for testing.": "Αυτός ο ιστότοπος χρησιμοποιεί μη ασφαλή HTTP σύνδεση! Παρακαλώ χρησιμοποιήστε το μόνο δοκιμαστικά.",
|
||||
"For more information <a href=\"%s\">see this FAQ entry</a>.": "Για περισσότερες πληροφορίες <a href=\"%s\">δείτε τις ερωταπαντήσεις</a>.",
|
||||
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Ο φυλλομετρητής σας μπορεί να απαιτεί HTTPS σύνδεση για να υποστηρίξει το WebCrypto API. Δοκιμάστε <a href=\"%s\">το HTTPS</a>.",
|
||||
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Ο φυλλομετρητής σας δεν υποστηρίζει WebAssembly, που χρησιμοποιήθηκε για zlib συμπίεση. Μπορείτε να δημιουργήσετε ασυμπίεστα αρχεία αλλά δεν μπορείτε να διαβάσετε συμπιεσμένα.",
|
||||
"waiting on user to provide a password": "Αναμονή ο χρήστης να δώσει τον κωδικό",
|
||||
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Δεν ήταν δυνατή η αποκρυπτογράφηση των δεδομένων. Μήπως εισάγατε λάθος κωδικό; Προσπαθήστε με το κουμπί στο επάνω μέρος.",
|
||||
"Retry": "Επαναπροσπάθεια",
|
||||
"Showing raw text…": "Προβολή κειμένου…",
|
||||
"Notice:": "Επισήμανση:",
|
||||
"This link will expire after %s.": "Ο σύνδεσμος θα λήξει σε %s.",
|
||||
"This link can only be accessed once, do not use back or refresh button in your browser.": "Αυτός ο σύνδεσμος μπορεί να προσπελαστεί μόνο μία φορά, μην χρησιμοποιήσετε το κουμπί επιστροφή ή ανανέωση στον φυλλομετρητή σας.",
|
||||
"Link:": "Σύνδεσμος:",
|
||||
"Recipient may become aware of your timezone, convert time to UTC?": "Ο παραλήπτης μπορεί να αναγνωρίσει τη ζώνη ώρας σας, θέλετε μετατροπή της ώρας σε UTC;",
|
||||
"Use Current Timezone": "Χρήση τρέχουσας ζώνης ώρας",
|
||||
"Convert To UTC": "Μετατροπή σε UTC",
|
||||
"Close": "Κλείσιμο",
|
||||
"Encrypted note on %s": "Κρυπτογραφημένο μήνυμα από το %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Επισκεφτείτε αυτόν τον σύνδεσμο για να δείτε το μήνυμα. Δίνοντας τον σύνδεσμο σε οποιονδήποτε, του επιτρέπετε να επισκεφτεί το μήνυμα επίσης.",
|
||||
"URL shortener may expose your decrypt key in URL.": "Συντομευτές συνδέσμων πιθανώς να δημοσιοποιήσουν το κλειδί αποκρυπτογράφισης στον σύνδεσμο.",
|
||||
"Save paste": "Αποθήκευση επικόλλησης",
|
||||
"Your IP is not authorized to create pastes.": "Η IP σας δεν επιτρέπεται να δημιουργεί επικολλήσεις.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Use Current Timezone",
|
||||
"Convert To UTC": "Convert To UTC",
|
||||
"Close": "Close",
|
||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
||||
"Encrypted note on %s": "Encrypted note on %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||
"Save paste": "Save paste",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"PrivateBin": "PrivateBin",
|
||||
"%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s es un \"pastebin\" en línea minimalista de código abierto, donde el servidor no tiene ningún conocimiento de los datos guardados. Los datos son cifrados/descifrados %sen el navegador%s usando 256 bits AES.",
|
||||
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "Más información en la <a href=\"https://privatebin.info/\">página del proyecto</a>.",
|
||||
"Because ignorance is bliss": "Porque la ignorancia es dicha",
|
||||
"Because ignorance is bliss": "Porque la ignorancia es felicidad",
|
||||
"en": "es",
|
||||
"Paste does not exist, has expired or has been deleted.": "El \"paste\" no existe, ha caducado o ha sido eliminado.",
|
||||
"%s requires php %s or above to work. Sorry.": "%s requiere php %s o superior para funcionar. Lo siento.",
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Usar Zona Horaria Actual",
|
||||
"Convert To UTC": "Convertir A UTC",
|
||||
"Close": "Cerrar",
|
||||
"Encrypted note on PrivateBin": "Nota cifrada en PrivateBin",
|
||||
"Encrypted note on %s": "Nota cifrada en %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visite este enlace para ver la nota. Dar la URL a cualquier persona también les permite acceder a la nota.",
|
||||
"URL shortener may expose your decrypt key in URL.": "El acortador de URL puede exponer su clave de descifrado en el URL.",
|
||||
"Save paste": "Guardar \"paste\"",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Tu IP no está autorizada para crear contenido.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Kasuta praegust ajavööndit",
|
||||
"Convert To UTC": "Teisenda UTC-ks",
|
||||
"Close": "Sulge",
|
||||
"Encrypted note on PrivateBin": "Krüpteeritud kiri PrivateBin-is",
|
||||
"Encrypted note on %s": "Krüpteeritud kiri %s-is",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Kirja nägemiseks külasta seda linki. Teistele URL-i andmine lubab ka neil ligi pääseda kirjale.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL-i lühendaja võib paljastada sinu dekrüpteerimisvõtme URL-is.",
|
||||
"Save paste": "Salvesta kleebe",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Käytä nykyistä aikavyöhykettä",
|
||||
"Convert To UTC": "Muuta UTC:ksi",
|
||||
"Close": "Sulje",
|
||||
"Encrypted note on PrivateBin": "Salattu viesti PrivateBinissä",
|
||||
"Encrypted note on %s": "Salattu viesti %sissä",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Käy tässä linkissä nähdäksesi viestin. URL:n antaminen kenellekään antaa heidänkin päästä katsomeen viestiä. ",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL-lyhentäjä voi paljastaa purkuavaimesi URL:ssä.",
|
||||
"Save paste": "Tallenna paste",
|
||||
"Your IP is not authorized to create pastes.": "IP:llesi ei ole annettu oikeutta luoda pasteja."
|
||||
"Your IP is not authorized to create pastes.": "IP:llesi ei ole annettu oikeutta luoda pasteja.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Conserver l'actuel",
|
||||
"Convert To UTC": "Convertir en UTC",
|
||||
"Close": "Fermer",
|
||||
"Encrypted note on PrivateBin": "Message chiffré sur PrivateBin",
|
||||
"Encrypted note on %s": "Message chiffré sur %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visiter ce lien pour voir la note. Donner l'URL à une autre personne lui permet également d'accéder à la note.",
|
||||
"URL shortener may expose your decrypt key in URL.": "Raccourcir l'URL peut exposer votre clé de déchiffrement dans l'URL.",
|
||||
"Save paste": "Sauver le paste",
|
||||
"Your IP is not authorized to create pastes.": "Votre adresse IP n'est pas autorisée à créer des pastes."
|
||||
"Your IP is not authorized to create pastes.": "Votre adresse IP n'est pas autorisée à créer des pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "להשתמש באזור הזמן הנוכחי",
|
||||
"Convert To UTC": "המרה ל־UTC",
|
||||
"Close": "סגירה",
|
||||
"Encrypted note on PrivateBin": "הערה מוצפנת ב־PrivateBin",
|
||||
"Encrypted note on %s": "%sהערה מוצפנת ב־",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "נא לבקר בקישור כדי לצפות בהערה. מסירת הקישור לאנשים כלשהם תאפשר גם להם לגשת להערה.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||
"Save paste": "Save paste",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Use Current Timezone",
|
||||
"Convert To UTC": "Convert To UTC",
|
||||
"Close": "Close",
|
||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
||||
"Encrypted note on %s": "Encrypted note on %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||
"Save paste": "Save paste",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Az aktuális időzóna használata",
|
||||
"Convert To UTC": "Átalakítás UTC időzónára",
|
||||
"Close": "Bezárás",
|
||||
"Encrypted note on PrivateBin": "Titkosított jegyzet a PrivateBinen",
|
||||
"Encrypted note on %s": "Titkosított jegyzet a %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Látogasd meg ezt a hivatkozást a bejegyzés megtekintéséhez. Ha mások számára is megadod ezt a linket, azzal hozzáférnek ők is.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||
"Save paste": "Save paste",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Gunakan Zonawaktu Saat Ini",
|
||||
"Convert To UTC": "Konversi Ke UTC",
|
||||
"Close": "Tutup",
|
||||
"Encrypted note on PrivateBin": "Catatan ter-ekrip di PrivateBin",
|
||||
"Encrypted note on %s": "Catatan ter-ekrip di %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Kunjungi tautan ini untuk melihat catatan. Memberikan alamat URL pada siapapun juga, akan mengizinkan mereka untuk mengakses catatan, so pasti gitu loh Kaka.",
|
||||
"URL shortener may expose your decrypt key in URL.": "Pemendek URL mungkin akan menampakkan kunci dekrip Anda dalam URL.",
|
||||
"Save paste": "Simpan paste",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Usa Fuso Orario Corrente",
|
||||
"Convert To UTC": "Converti a UTC",
|
||||
"Close": "Chiudi",
|
||||
"Encrypted note on PrivateBin": "Nota crittografata su PrivateBin",
|
||||
"Encrypted note on %s": "Nota crittografata su %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visita questo collegamento per vedere la nota. Dare l'URL a chiunque consente anche a loro di accedere alla nota.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener può esporre la tua chiave decrittografata nell'URL.",
|
||||
"Save paste": "Salva il messagio",
|
||||
"Your IP is not authorized to create pastes.": "Il tuo IP non è autorizzato a creare dei messaggi."
|
||||
"Your IP is not authorized to create pastes.": "Il tuo IP non è autorizzato a creare dei messaggi.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Use Current Timezone",
|
||||
"Convert To UTC": "Convert To UTC",
|
||||
"Close": "Close",
|
||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
||||
"Encrypted note on %s": "Encrypted note on %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||
"Save paste": "Save paste",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Use Current Timezone",
|
||||
"Convert To UTC": "galfi lo cabni la utc",
|
||||
"Close": "ganlo",
|
||||
"Encrypted note on PrivateBin": ".i lo lo notci ku mifra cu zvati sivlolnitvanku'a",
|
||||
"Encrypted note on %s": ".i lo lo notci ku mifra cu zvati %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||
"Save paste": "rejgau fukpi",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Use Current Timezone",
|
||||
"Convert To UTC": "Convert To UTC",
|
||||
"Close": "Close",
|
||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
||||
"Encrypted note on %s": "Encrypted note on %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||
"Save paste": "Save paste",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Use Current Timezone",
|
||||
"Convert To UTC": "Convert To UTC",
|
||||
"Close": "Close",
|
||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
||||
"Encrypted note on %s": "Encrypted note on %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||
"Save paste": "Save paste",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Naudoti esamą laiko juostą",
|
||||
"Convert To UTC": "Konvertuoti į UTC",
|
||||
"Close": "Užverti",
|
||||
"Encrypted note on PrivateBin": "Šifruoti užrašai ties PrivateBin",
|
||||
"Encrypted note on %s": "Šifruoti užrašai ties %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Norėdami matyti užrašus, aplankykite šį tinklalapį. Pasidalinus šiuo URL adresu su kitais žmonėmis, jiems taip pat bus leidžiama prieiga prie šių užrašų.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL trumpinimo įrankis gali atskleisti URL adrese jūsų iššifravimo raktą.",
|
||||
"Save paste": "Įrašyti įdėjimą",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Jūsų IP adresas neturi įgaliojimų kurti įdėjimų.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
13
i18n/nl.json
13
i18n/nl.json
@@ -26,7 +26,7 @@
|
||||
"%s requires a modern browser to work.": "%s vereist een moderne browser om te kunnen werken ",
|
||||
"New": "Nieuw",
|
||||
"Send": "Verzenden",
|
||||
"Clone": "Klonen",
|
||||
"Clone": "Clonen",
|
||||
"Raw text": "Onbewerkte tekst",
|
||||
"Expires": "Verloopt",
|
||||
"Burn after reading": "Vernietig na lezen",
|
||||
@@ -129,7 +129,7 @@
|
||||
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>": "Uw geplakte tekst is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Druk [Ctrl]+[c] om te kopiëren)</span>",
|
||||
"Delete data": "Gegevens wissen",
|
||||
"Could not create paste: %s": "Kon de geplakte tekst niet aanmaken: %s",
|
||||
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Kon de geplakte tekst niet decoderen: Decoderingssleutel ontbreekt in URL (heeft u een redirector of een URL-verkorter gebruikt die een deel van de URL verwijdert?)",
|
||||
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Kon de geplakte tekst niet decoderen: Decoderingssleutel ontbreekt in URL (Hebt u een redirector of een URL-verkorter gebruikt die een deel van de URL verwijdert?)",
|
||||
"B": "B",
|
||||
"KiB": "KiB",
|
||||
"MiB": "MiB",
|
||||
@@ -170,7 +170,7 @@
|
||||
"For more information <a href=\"%s\">see this FAQ entry</a>.": "Voor meer informatie <a href=\"%s\">zie dit FAQ-artikel</a>.",
|
||||
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Uw browser kan een HTTPS-verbinding nodig hebben om de WebCrypto API te ondersteunen. Probeer <a href=\"%s\">het met HTTPS</a>.",
|
||||
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Uw browser ondersteunt WebAssembly niet, wat wordt gebruikt voor zlib compressie. U kunt niet-gecomprimeerde documenten maken, maar geen gecomprimeerde documenten lezen.",
|
||||
"waiting on user to provide a password": "Wachtend op gebruiker om een wachtwoord te geven",
|
||||
"waiting on user to provide a password": "wachtend op gebruiker om een wachtwoord te geven",
|
||||
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Kon de gegevens niet decoderen. Heeft u een verkeerd wachtwoord ingevoerd? Probeer het opnieuw met de knop bovenaan.",
|
||||
"Retry": "Opnieuw proberen",
|
||||
"Showing raw text…": "Platte tekst tonen…",
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Gebruik huidige tijdzone",
|
||||
"Convert To UTC": "Omzetten naar UTC",
|
||||
"Close": "Sluiten",
|
||||
"Encrypted note on PrivateBin": "Versleutelde notitie op PrivateBin",
|
||||
"Encrypted note on %s": "Versleutelde notitie op %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Bezoek deze link om de notitie te bekijken. Als je de URL aan iemand geeft, kan die de notitie ook bekijken.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL-verkorter kan uw ontcijferingssleutel in URL blootleggen.",
|
||||
"Save paste": "Notitie opslaan",
|
||||
"Your IP is not authorized to create pastes.": "Uw IP-adres is niet gemachtigd om geplakte tekst te maken."
|
||||
"Your IP is not authorized to create pastes.": "Uw IP-adres is niet gemachtigd om geplakte tekst te maken.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Bruk gjeldende tidssone",
|
||||
"Convert To UTC": "Konverter til UTC",
|
||||
"Close": "Steng",
|
||||
"Encrypted note on PrivateBin": "Kryptert notat på PrivateBin",
|
||||
"Encrypted note on %s": "Kryptert notat på %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Besøk denne lenken for å se notatet. Hvis lenken deles med andre, vil de også kunne se notatet.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL forkorter kan avsløre dekrypteringsnøkkelen.",
|
||||
"Save paste": "Lagre utklipp",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Utilizar l’actual",
|
||||
"Convert To UTC": "Convertir en UTC",
|
||||
"Close": "Tampar",
|
||||
"Encrypted note on PrivateBin": "Nòtas chifradas sus PrivateBin",
|
||||
"Encrypted note on %s": "Nòtas chifradas sus %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visitatz aqueste ligam per veire la nòta. Fornir lo ligam a qualqu’un mai li permet tanben d’accedir a la nòta.",
|
||||
"URL shortener may expose your decrypt key in URL.": "Los espleches d’acorchiment d’URL pòdon expausar la clau de deschiframent dins l’URL.",
|
||||
"Save paste": "Enregistrar lo tèxt",
|
||||
"Your IP is not authorized to create pastes.": "Vòstra adreça IP a pas l’autorizacion de crear de tèxtes."
|
||||
"Your IP is not authorized to create pastes.": "Vòstra adreça IP a pas l’autorizacion de crear de tèxtes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Use Current Timezone",
|
||||
"Convert To UTC": "Convert To UTC",
|
||||
"Close": "Close",
|
||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
||||
"Encrypted note on %s": "Encrypted note on %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||
"Save paste": "Save paste",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Usar Fuso Horário Atual",
|
||||
"Convert To UTC": "Converter para UTC",
|
||||
"Close": "Fechar",
|
||||
"Encrypted note on PrivateBin": "Nota criptografada no PrivateBin",
|
||||
"Encrypted note on %s": "Nota criptografada no %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visite esse link para ver a nota. Dar a URL para qualquer um permite que eles também acessem a nota.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||
"Save paste": "Save paste",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Использовать текущий часовой пояс",
|
||||
"Convert To UTC": "Конвертировать в UTC",
|
||||
"Close": "Закрыть",
|
||||
"Encrypted note on PrivateBin": "Зашифрованная запись на PrivateBin",
|
||||
"Encrypted note on %s": "Зашифрованная запись на %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Посетите эту ссылку чтобы просмотреть запись. Передача ссылки кому либо позволит им получить доступ к записи тоже.",
|
||||
"URL shortener may expose your decrypt key in URL.": "Сервис сокращения ссылок может получить ваш ключ расшифровки из ссылки.",
|
||||
"Save paste": "Сохранить запись",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Вашему IP адресу не разрешено создавать записи.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
193
i18n/sk.json
Normal file
193
i18n/sk.json
Normal file
@@ -0,0 +1,193 @@
|
||||
{
|
||||
"PrivateBin": "PrivateBin",
|
||||
"%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s je minimalistický, open source online pastebin, kde server nemá žiadne znalosti o vložených údajoch. Údaje sú šifrované/dešifrované %sv prehliadači%s pomocou 256-bitového AES.",
|
||||
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "Viac informácií na <a href=\"https://privatebin.info/\">stránke projektu</a>.",
|
||||
"Because ignorance is bliss": "Pretože nevedomosť je sladká",
|
||||
"en": "sk",
|
||||
"Paste does not exist, has expired or has been deleted.": "Vložený text neexistuje, jeho platnosť vypršala alebo bol vymazaný.",
|
||||
"%s requires php %s or above to work. Sorry.": "%s vyžaduje php %s alebo vyššie. Prepáčte.",
|
||||
"%s requires configuration section [%s] to be present in configuration file.": "%s vyžaduje, aby bola v konfiguračnom súbore prítomná sekcia [%s].",
|
||||
"Please wait %d seconds between each post.": [
|
||||
"Počet sekúnd do ďalšieho príspevku: %d",
|
||||
"Počet sekúnd do ďalšieho príspevku: %d",
|
||||
"Počet sekúnd do ďalšieho príspevku: %d",
|
||||
"Počet sekúnd do ďalšieho príspevku: %d"
|
||||
],
|
||||
"Paste is limited to %s of encrypted data.": "Príspevok je obmedzený na %s zašifrovaných údajov.",
|
||||
"Invalid data.": "Neplatné údaje.",
|
||||
"You are unlucky. Try again.": "Ľutujem. Skúste to znova.",
|
||||
"Error saving comment. Sorry.": "Pri ukladaní komentára sa vyskytla chyba.",
|
||||
"Error saving paste. Sorry.": "Pri ukladaní príspevku sa vyskytla chyba.",
|
||||
"Invalid paste ID.": "Chybne vložené ID.",
|
||||
"Paste is not of burn-after-reading type.": "Príspevok nieje nastavený na zmazanie po prečítaní.",
|
||||
"Wrong deletion token. Paste was not deleted.": "Nesprávny token odstránenia. Príspevok nebol odstránený.",
|
||||
"Paste was properly deleted.": "Príspevok bol správne vymazaný.",
|
||||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Na fungovanie %s je potrebný JavaScript. Ospravedlňujeme sa za nepríjemnosti.",
|
||||
"%s requires a modern browser to work.": "%s vyžaduje na fungovanie moderný prehliadač.",
|
||||
"New": "Nový",
|
||||
"Send": "Odoslať",
|
||||
"Clone": "Klonovať",
|
||||
"Raw text": "Surový text",
|
||||
"Expires": "Expirácia",
|
||||
"Burn after reading": "Po prečítaní zmazať",
|
||||
"Open discussion": "Povoliť komentáre",
|
||||
"Password (recommended)": "Heslo (doporučené)",
|
||||
"Discussion": "Komentáre",
|
||||
"Toggle navigation": "Prepnúť navigáciu",
|
||||
"%d seconds": [
|
||||
"%d sekunda",
|
||||
"%d sekundy",
|
||||
"%d sekúnd",
|
||||
"%d sekúnd"
|
||||
],
|
||||
"%d minutes": [
|
||||
"%d minúta",
|
||||
"%d minúty",
|
||||
"%d minút",
|
||||
"%d minút"
|
||||
],
|
||||
"%d hours": [
|
||||
"%d hodina",
|
||||
"%d hodiny",
|
||||
"%d hodín",
|
||||
"%d hodín"
|
||||
],
|
||||
"%d days": [
|
||||
"%d deň",
|
||||
"%d dni",
|
||||
"%d dní",
|
||||
"%d dní"
|
||||
],
|
||||
"%d weeks": [
|
||||
"%d týždeň",
|
||||
"%d týždne",
|
||||
"%d týždňov",
|
||||
"%d týždňov"
|
||||
],
|
||||
"%d months": [
|
||||
"%d mesiac",
|
||||
"%d mesiace",
|
||||
"%d mesiacov",
|
||||
"%d mesiacov"
|
||||
],
|
||||
"%d years": [
|
||||
"%d rok",
|
||||
"%d roky",
|
||||
"%d rokov",
|
||||
"%d rokov"
|
||||
],
|
||||
"Never": "Nikdy",
|
||||
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Poznámka: Toto je testovacia služba: Údaje môžu byť kedykoľvek vymazané. Pri zneužití tejto služby zomrú mačiatka.",
|
||||
"This document will expire in %d seconds.": [
|
||||
"Platnosť tohto dokumentu vyprší o %d sekundu.",
|
||||
"Platnosť tohto dokumentu vyprší o %d sekundy.",
|
||||
"Platnosť tohto dokumentu vyprší o %d sekúnd.",
|
||||
"Platnosť tohto dokumentu vyprší o %d sekúnd."
|
||||
],
|
||||
"This document will expire in %d minutes.": [
|
||||
"Platnosť tohto dokumentu vyprší o %d minútu.",
|
||||
"Platnosť tohto dokumentu vyprší o %d minúty.",
|
||||
"Platnosť tohto dokumentu vyprší o %d minút.",
|
||||
"Platnosť tohto dokumentu vyprší o %d minút."
|
||||
],
|
||||
"This document will expire in %d hours.": [
|
||||
"Platnosť tohto dokumentu vyprší o %d hodinu.",
|
||||
"Platnosť tohto dokumentu vyprší o %d hodiny.",
|
||||
"Platnosť tohto dokumentu vyprší o %d hodín.",
|
||||
"Platnosť tohto dokumentu vyprší o %d hodín."
|
||||
],
|
||||
"This document will expire in %d days.": [
|
||||
"Platnosť tohto dokumentu vyprší o %d deň.",
|
||||
"Platnosť tohto dokumentu vyprší o %d dni.",
|
||||
"Platnosť tohto dokumentu vyprší o %d dní.",
|
||||
"Platnosť tohto dokumentu vyprší o %d dní."
|
||||
],
|
||||
"This document will expire in %d months.": [
|
||||
"Platnosť tohto dokumentu vyprší o %d mesiac.",
|
||||
"Platnosť tohto dokumentu vyprší o %d mesiace.",
|
||||
"Platnosť tohto dokumentu vyprší o %d mesiacov.",
|
||||
"Platnosť tohto dokumentu vyprší o %d mesiacov."
|
||||
],
|
||||
"Please enter the password for this paste:": "Zadajte prosím heslo:",
|
||||
"Could not decrypt data (Wrong key?)": "Nepodarilo sa dešifrovať údaje (nesprávny kľúč?)",
|
||||
"Could not delete the paste, it was not stored in burn after reading mode.": "Nepodarilo sa odstrániť príspevok, nebol uložený v režime zmazania po prečítaní.",
|
||||
"FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "IBA PRE VAŠE OČI. Toto okno nezatvárajte, táto správa sa nedá znova zobraziť.",
|
||||
"Could not decrypt comment; Wrong key?": "Nepodarilo sa dešifrovať komentár. Nesprávny kľúč?",
|
||||
"Reply": "Odpovedať",
|
||||
"Anonymous": "Anonymný",
|
||||
"Avatar generated from IP address": "Avatar vygenerovaný z IP adresy",
|
||||
"Add comment": "Pridať komentár",
|
||||
"Optional nickname…": "Voliteľná prezývka…",
|
||||
"Post comment": "Odoslať komentár",
|
||||
"Sending comment…": "Odosielanie komentára…",
|
||||
"Comment posted.": "Komentár odoslaný.",
|
||||
"Could not refresh display: %s": "Nepodarilo sa obnoviť zobrazenie: %s",
|
||||
"unknown status": "neznámy stav",
|
||||
"server error or not responding": "chyba servera alebo server neodpovedá",
|
||||
"Could not post comment: %s": "Nepodarilo sa pridať komentár: %s",
|
||||
"Sending paste…": "Odosiela sa príspevok…",
|
||||
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>": "Váš príspevok je <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(skopírujte stlačením [Ctrl]+[c])</span>",
|
||||
"Delete data": "Odstrániť dáta",
|
||||
"Could not create paste: %s": "Nepodarilo sa vytvoriť príspevok: %s",
|
||||
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nie je možné dešifrovať príspevok: V URL adrese chýba dešifrovací kľúč (Použili ste presmerovač alebo skracovač adresy, ktorý odstráni časť adresy URL?)",
|
||||
"B": "B",
|
||||
"KiB": "KiB",
|
||||
"MiB": "MiB",
|
||||
"GiB": "GiB",
|
||||
"TiB": "TiB",
|
||||
"PiB": "PiB",
|
||||
"EiB": "EiB",
|
||||
"ZiB": "ZiB",
|
||||
"YiB": "YiB",
|
||||
"Format": "Formát",
|
||||
"Plain Text": "Čistý text",
|
||||
"Source Code": "Zdrojový kód",
|
||||
"Markdown": "Markdown",
|
||||
"Download attachment": "Stiahnuť prílohu",
|
||||
"Cloned: '%s'": "Naklonované: '%s'",
|
||||
"The cloned file '%s' was attached to this paste.": "K tomuto príspevku bol pripojený klonovaný súbor '%s'.",
|
||||
"Attach a file": "Priložiť súbor",
|
||||
"alternatively drag & drop a file or paste an image from the clipboard": "prípadne presuňte súbor myšou alebo vložte obrázok zo schránky",
|
||||
"File too large, to display a preview. Please download the attachment.": "Súbor je príliš veľký na zobrazenie ukážky. Stiahnite si prosím prílohu.",
|
||||
"Remove attachment": "Odstrániť prílohu",
|
||||
"Your browser does not support uploading encrypted files. Please use a newer browser.": "Váš prehliadač nepodporuje nahrávanie šifrovaných súborov. Použite prosím novší prehliadač.",
|
||||
"Invalid attachment.": "Neplatná príloha.",
|
||||
"Options": "Možnosti",
|
||||
"Shorten URL": "Skrátiť URL",
|
||||
"Editor": "Editor",
|
||||
"Preview": "Náhľad",
|
||||
"%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s vyžaduje, aby PATH končila na \"%s\". Aktualizujte prosím PATH vo svojom index.php.",
|
||||
"Decrypt": "Dešifrovať",
|
||||
"Enter password": "Zadajte heslo",
|
||||
"Loading…": "Načítava sa…",
|
||||
"Decrypting paste…": "Dešifrovanie príspevku…",
|
||||
"Preparing new paste…": "Príprava nového príspevku…",
|
||||
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.": "V prípade, že táto správa nezmizne, pozrite si <a href=\"%s\">tieto často kladené otázky, kde nájdete informácie na riešenie problémov</a>.",
|
||||
"+++ no paste text +++": "+++ žiadny vložený text +++",
|
||||
"Could not get paste data: %s": "Nepodarilo sa načítať údaje príspevku: %s",
|
||||
"QR code": "QR kód",
|
||||
"This website is using an insecure HTTP connection! Please use it only for testing.": "Táto webová stránka používa nezabezpečené pripojenie HTTP! Používajte ju len na testovanie.",
|
||||
"For more information <a href=\"%s\">see this FAQ entry</a>.": "Pre viac informácií si pozrite <a href=\"%s\">tento záznam FAQ</a>.",
|
||||
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Váš prehliadač môže na podporu rozhrania WebCrypto API vyžadovať pripojenie HTTPS. Skúste <a href=\"%s\">prepnúť na HTTPS</a>.",
|
||||
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Váš prehliadač nepodporuje WebAssembly, ktorý sa používa na kompresiu zlib. Môžete vytvárať nekomprimované dokumenty, ale nemôžete čítať komprimované.",
|
||||
"waiting on user to provide a password": "čakám na zadanie hesla",
|
||||
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Údaje sa nepodarilo dešifrovať. Zadali ste nesprávne heslo? Skúste to znova pomocou tlačidla v hornej časti.",
|
||||
"Retry": "Opakovať",
|
||||
"Showing raw text…": "Zobrazuje sa surový text…",
|
||||
"Notice:": "Upozornenie:",
|
||||
"This link will expire after %s.": "Platnosť odkazu vyprší za %s.",
|
||||
"This link can only be accessed once, do not use back or refresh button in your browser.": "Tento odkaz je prístupný iba raz, nepoužívajte v prehliadači tlačidlo Späť ani Obnoviť.",
|
||||
"Link:": "Odkaz:",
|
||||
"Recipient may become aware of your timezone, convert time to UTC?": "Príjemca sa môže dozvedieť o vašom časovom pásme, previesť čas na UTC?",
|
||||
"Use Current Timezone": "Použiť aktuálne časové pásmo",
|
||||
"Convert To UTC": "Previesť na UTC",
|
||||
"Close": "Zavrieť",
|
||||
"Encrypted note on %s": "Zašifrovaná poznámka na %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Ak chcete zobraziť poznámku, navštívte tento odkaz. Poskytnutie adresy URL komukoľvek im umožní prístup aj k poznámke.",
|
||||
"URL shortener may expose your decrypt key in URL.": "Skracovač adries URL môže odhaliť váš dešifrovací kľúč v adrese URL.",
|
||||
"Save paste": "Uložiť príspevok",
|
||||
"Your IP is not authorized to create pastes.": "Vaša IP adresa nie je oprávnená vytvárať príspevky.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Pokúšate sa skrátiť adresu URL, ktorá neukazuje na túto inštanciu.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Use Current Timezone",
|
||||
"Convert To UTC": "Convert To UTC",
|
||||
"Close": "Close",
|
||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
||||
"Encrypted note on %s": "Encrypted note on %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||
"Save paste": "Save paste",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Use Current Timezone",
|
||||
"Convert To UTC": "Convert To UTC",
|
||||
"Close": "Close",
|
||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
||||
"Encrypted note on %s": "Encrypted note on %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||
"Save paste": "Save paste",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
61
i18n/tr.json
61
i18n/tr.json
@@ -60,7 +60,7 @@
|
||||
],
|
||||
"%d weeks": [
|
||||
"%d hafta",
|
||||
"%d hafta",
|
||||
"%d haftalar",
|
||||
"%d hafta",
|
||||
"%d hafta"
|
||||
],
|
||||
@@ -79,34 +79,34 @@
|
||||
"Never": "Asla",
|
||||
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.",
|
||||
"This document will expire in %d seconds.": [
|
||||
"Bu belge %s saniyede silinecektir.",
|
||||
"Bu belge %s saniyede silinecektir.",
|
||||
"Bu belge %s saniyede silinecektir.",
|
||||
"Bu belge %s saniyede silinecektir."
|
||||
"Bu belge %d saniyede silinecektir.",
|
||||
"Bu belge %d saniyede silinecektir.",
|
||||
"Bu belge %d saniyede silinecektir.",
|
||||
"Bu belge %d saniyede silinecektir."
|
||||
],
|
||||
"This document will expire in %d minutes.": [
|
||||
"Bu belge %s dakikada silinecektir.",
|
||||
"Bu belge %s dakikada silinecektir.",
|
||||
"Bu belge %s dakikada silinecektir.",
|
||||
"Bu belge %s dakikada silinecektir."
|
||||
"Bu belge %d dakikada silinecektir.",
|
||||
"Bu belge %d dakikada silinecektir.",
|
||||
"Bu belge %d dakikada silinecektir.",
|
||||
"Bu belge %d dakikada silinecektir."
|
||||
],
|
||||
"This document will expire in %d hours.": [
|
||||
"Bu belge %s saatte silinecektir.",
|
||||
"Bu belge %s saatte silinecektir.",
|
||||
"Bu belge %s saatte silinecektir.",
|
||||
"Bu belge %s saatte silinecektir.."
|
||||
"Bu belge %d saatte silinecektir.",
|
||||
"Bu belge %d saatte silinecektir.",
|
||||
"Bu belge %d saatte silinecektir.",
|
||||
"Bu belge %d saatte silinecektir."
|
||||
],
|
||||
"This document will expire in %d days.": [
|
||||
"Bu belge %s günde silinecektir.",
|
||||
"Bu belge %s günde silinecektir.",
|
||||
"Bu belge %s günde silinecektir.",
|
||||
"Bu belge %s günde silinecektir.(3rd plural)"
|
||||
"Bu belge %d günde silinecektir.",
|
||||
"Bu belge %d günde silinecektir.",
|
||||
"Bu belge %d günde silinecektir.",
|
||||
"Bu belge %d günde silinecektir."
|
||||
],
|
||||
"This document will expire in %d months.": [
|
||||
"Bu belge %s ayda silinecektir.",
|
||||
"Bu belge %s ayda silinecektir",
|
||||
"Bu belge %s ayda silinecektir",
|
||||
"Bu belge %s ayda silinecektir"
|
||||
"Bu belge %d ayda silinecektir.",
|
||||
"Bu belge %d ayda silinecektir.",
|
||||
"Bu belge %d ayda silinecektir.",
|
||||
"Bu belge %d ayda silinecektir."
|
||||
],
|
||||
"Please enter the password for this paste:": "Lütfen bu yazı için şifrenizi girin:",
|
||||
"Could not decrypt data (Wrong key?)": "Şifre çözülemedi (Yanlış anahtar mı kullandınız?)",
|
||||
@@ -117,9 +117,9 @@
|
||||
"Anonymous": "Anonim",
|
||||
"Avatar generated from IP address": "IP adresinden oluşturulmuş avatar",
|
||||
"Add comment": "Yorum ekle",
|
||||
"Optional nickname…": "İsteğe bağlı takma isim...",
|
||||
"Optional nickname…": "İsteğe bağlı takma isim…",
|
||||
"Post comment": "Yorumu gönder",
|
||||
"Sending comment…": "Yorum gönderiliyor...",
|
||||
"Sending comment…": "Yorum gönderiliyor…",
|
||||
"Comment posted.": "Yorum gönderildi.",
|
||||
"Could not refresh display: %s": "Görüntü yenilenemedi: %s",
|
||||
"unknown status": "bilinmeyen durum",
|
||||
@@ -147,7 +147,7 @@
|
||||
"Cloned: '%s'": "Klonlandı: '%s'",
|
||||
"The cloned file '%s' was attached to this paste.": "Klonlanmış dosya '%s' bu yazıya eklendi.",
|
||||
"Attach a file": "Dosya ekle",
|
||||
"alternatively drag & drop a file or paste an image from the clipboard": "alternatif olarak dosyasyı yapıştırabilir veya sürükleyip bırakabilirsin.z",
|
||||
"alternatively drag & drop a file or paste an image from the clipboard": "alternatif olarak dosyasyı yapıştırabilir veya sürükleyip bırakabilirsin",
|
||||
"File too large, to display a preview. Please download the attachment.": "Dosya önizleme için çok büyük. Lütfen eki indirin.",
|
||||
"Remove attachment": "Eki sil",
|
||||
"Your browser does not support uploading encrypted files. Please use a newer browser.": "Tarayıcınız şifreli dosyaları desteklemiyor.",
|
||||
@@ -160,8 +160,8 @@
|
||||
"Decrypt": "Şifreyi çöz",
|
||||
"Enter password": "Şifreyi girin",
|
||||
"Loading…": "Yükleniyor…",
|
||||
"Decrypting paste…": "Yazı şifresi çözülüyor...",
|
||||
"Preparing new paste…": "Yeni yazı hazırlanıyor...",
|
||||
"Decrypting paste…": "Yazı şifresi çözülüyor…",
|
||||
"Preparing new paste…": "Yeni yazı hazırlanıyor…",
|
||||
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.": "In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.",
|
||||
"+++ no paste text +++": "+++ no paste text +++",
|
||||
"Could not get paste data: %s": "Yazı verisi alınamıyor: %s",
|
||||
@@ -173,7 +173,7 @@
|
||||
"waiting on user to provide a password": "waiting on user to provide a password",
|
||||
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Dosya şifresi çözülemedi, doğru şifreyi kullandığınıza emin misiniz? Üstteki buton ile tekrar deneyin.",
|
||||
"Retry": "Yeniden Dene",
|
||||
"Showing raw text…": "Açık yazı gösteriliyor...",
|
||||
"Showing raw text…": "Açık yazı gösteriliyor…",
|
||||
"Notice:": "Bildirim:",
|
||||
"This link will expire after %s.": "Bu bağlantı şu kadar zaman sonra etkisiz kalacaktır: %s.",
|
||||
"This link can only be accessed once, do not use back or refresh button in your browser.": "Bu bağlantı sadece bir kere erişilebilir, lütfen sayfayı yenilemeyiniz.",
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "Şuanki zaman dilimini kullan",
|
||||
"Convert To UTC": "UTC zaman dilimine çevir",
|
||||
"Close": "Kapat",
|
||||
"Encrypted note on PrivateBin": "PrivateBin üzerinde şifrelenmiş not",
|
||||
"Encrypted note on %s": "%s üzerinde şifrelenmiş not",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Notu görmek için bu bağlantıyı ziyaret et. Bağlantıya sahip olan birisi notu görebilir.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL kısaltıcı şifreleme anahtarınızı URL içerisinde gösterebilir.",
|
||||
"Save paste": "Yazıyı kaydet",
|
||||
"Your IP is not authorized to create pastes.": "IP adresinizin yazı oluşturmaya yetkisi yoktur."
|
||||
"Your IP is not authorized to create pastes.": "IP adresinizin yazı oluşturmaya yetkisi yoktur.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
45
i18n/uk.json
45
i18n/uk.json
@@ -8,10 +8,10 @@
|
||||
"%s requires php %s or above to work. Sorry.": "Для роботи %s потрібен php %s и вище. Вибачте.",
|
||||
"%s requires configuration section [%s] to be present in configuration file.": "%s потрібна секція [%s] в конфігураційному файлі.",
|
||||
"Please wait %d seconds between each post.": [
|
||||
"Please wait %d second between each post. (singular)",
|
||||
"Please wait %d seconds between each post. (1st plural)",
|
||||
"Please wait %d seconds between each post. (2nd plural)",
|
||||
"Please wait %d seconds between each post. (3rd plural)"
|
||||
"Будь ласка, зачекайте %d секунду між створеннями.",
|
||||
"Будь ласка, зачекайте %d секунди між створеннями.",
|
||||
"Будь ласка, зачекайте %d секунд між створеннями.",
|
||||
"Будь ласка, зачекайте %d секунд між створеннями."
|
||||
],
|
||||
"Paste is limited to %s of encrypted data.": "Розмір допису обмежений %s зашифрованих даних.",
|
||||
"Invalid data.": "Неправильні дані.",
|
||||
@@ -170,21 +170,24 @@
|
||||
"For more information <a href=\"%s\">see this FAQ entry</a>.": "Для подробиць <a href=\"%s\">дивіться інформацію в FAQ</a>.",
|
||||
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Ваш переглядач вимагає підключення HTTPS для підтримки WebCrypto API. Спробуйте <a href=\"%s\">перемкнутися на HTTPS</a>.",
|
||||
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Ваш переглядач не підтримує WebAssembly, що використовується для стиснення zlib. Ви можете створювати нестиснені документи, але не зможете читати стиснені.",
|
||||
"waiting on user to provide a password": "waiting on user to provide a password",
|
||||
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.",
|
||||
"Retry": "Retry",
|
||||
"Showing raw text…": "Showing raw text…",
|
||||
"Notice:": "Notice:",
|
||||
"This link will expire after %s.": "This link will expire after %s.",
|
||||
"This link can only be accessed once, do not use back or refresh button in your browser.": "This link can only be accessed once, do not use back or refresh button in your browser.",
|
||||
"Link:": "Link:",
|
||||
"Recipient may become aware of your timezone, convert time to UTC?": "Recipient may become aware of your timezone, convert time to UTC?",
|
||||
"Use Current Timezone": "Use Current Timezone",
|
||||
"Convert To UTC": "Convert To UTC",
|
||||
"Close": "Close",
|
||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||
"Save paste": "Save paste",
|
||||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
|
||||
"waiting on user to provide a password": "очікування користувача для вводу паролю",
|
||||
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Не вдалося розшифрувати дані. Може, ви ввели неправильний пароль? Спробуйте знову за допомогою верхньої кнопки.",
|
||||
"Retry": "Спробуйте ще раз",
|
||||
"Showing raw text…": "Відображається неформатований текст…",
|
||||
"Notice:": "Зверніть увагу:",
|
||||
"This link will expire after %s.": "Термін дії цього посилання сплине через %s.",
|
||||
"This link can only be accessed once, do not use back or refresh button in your browser.": "Дане посилання доступна тільки один раз, не натискайте кнопку назад та не обновляйте сторінку браузера.",
|
||||
"Link:": "Посилання:",
|
||||
"Recipient may become aware of your timezone, convert time to UTC?": "Отримувач дізнається ваш часовий пояс, перетворити час в UTC?",
|
||||
"Use Current Timezone": "Використовувати поточний часовий пояс",
|
||||
"Convert To UTC": "Конвертувати в UTC",
|
||||
"Close": "Закрити",
|
||||
"Encrypted note on %s": "Зашифрована нотатка на %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Відвідайте посилання, щоб переглянути нотатку. Передача посилання будь-кому дозволить їм переглянути нотатку.",
|
||||
"URL shortener may expose your decrypt key in URL.": "Сервіс скорочення посилань може викрити ваш ключ дешифрування з URL.",
|
||||
"Save paste": "Зберегти вставку",
|
||||
"Your IP is not authorized to create pastes.": "Вашому IP не дозволено створювати вставки.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -182,9 +182,12 @@
|
||||
"Use Current Timezone": "使用当前时区",
|
||||
"Convert To UTC": "转换为 UTC",
|
||||
"Close": "关闭",
|
||||
"Encrypted note on PrivateBin": "PrivateBin 上的加密笔记",
|
||||
"Encrypted note on %s": "%s 上的加密笔记",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "访问此链接来查看该笔记。将此 URL 发送给任何人即可允许其访问该笔记。",
|
||||
"URL shortener may expose your decrypt key in URL.": "短链接服务可能会暴露您在 URL 中的解密密钥。",
|
||||
"Save paste": "保存内容",
|
||||
"Your IP is not authorized to create pastes.": "您的 IP 无权创建粘贴。"
|
||||
"Your IP is not authorized to create pastes.": "您的 IP 无权创建粘贴。",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ global.WebCrypto = require('@peculiar/webcrypto').Crypto;
|
||||
// application libraries to test
|
||||
global.$ = global.jQuery = require('./jquery-3.6.0');
|
||||
global.RawDeflate = require('./rawinflate-0.3').RawDeflate;
|
||||
global.zlib = require('./zlib-1.2.12').zlib;
|
||||
global.zlib = require('./zlib-1.2.13').zlib;
|
||||
require('./prettify');
|
||||
global.prettyPrint = window.PR.prettyPrint;
|
||||
global.prettyPrintOne = window.PR.prettyPrintOne;
|
||||
|
||||
@@ -627,7 +627,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
||||
* @prop {string[]}
|
||||
* @readonly
|
||||
*/
|
||||
const supportedLanguages = ['bg', 'ca', 'co', 'cs', 'de', 'es', 'et', 'fi', 'fr', 'he', 'hu', 'id', 'it', 'jbo', 'lt', 'no', 'nl', 'pl', 'pt', 'oc', 'ru', 'sl', 'tr', 'uk', 'zh'];
|
||||
const supportedLanguages = ['bg', 'ca', 'co', 'cs', 'de', 'el', 'es', 'et', 'fi', 'fr', 'he', 'hu', 'id', 'it', 'jbo', 'lt', 'no', 'nl', 'pl', 'pt', 'oc', 'ru', 'sk', 'sl', 'tr', 'uk', 'zh'];
|
||||
|
||||
/**
|
||||
* built in language
|
||||
@@ -803,7 +803,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
||||
switch (language)
|
||||
{
|
||||
case 'cs':
|
||||
return n === 1 ? 0 : (n >= 2 && n <=4 ? 1 : 2);
|
||||
case 'sk':
|
||||
return n === 1 ? 0 : (n >= 2 && n <= 4 ? 1 : 2);
|
||||
case 'co':
|
||||
case 'fr':
|
||||
case 'oc':
|
||||
@@ -818,13 +819,13 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
||||
case 'lt':
|
||||
return n % 10 === 1 && n % 100 !== 11 ? 0 : ((n % 10 >= 2 && n % 100 < 10 || n % 100 >= 20) ? 1 : 2);
|
||||
case 'pl':
|
||||
return n === 1 ? 0 : (n % 10 >= 2 && n %10 <=4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2);
|
||||
return n === 1 ? 0 : (n % 10 >= 2 && n %10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2);
|
||||
case 'ru':
|
||||
case 'uk':
|
||||
return n % 10 === 1 && n % 100 !== 11 ? 0 : (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2);
|
||||
case 'sl':
|
||||
return n % 100 === 1 ? 1 : (n % 100 === 2 ? 2 : (n % 100 === 3 || n % 100 === 4 ? 3 : 0));
|
||||
// bg, ca, de, en, es, et, fi, hu, it, nl, no, pt
|
||||
// bg, ca, de, el, en, es, et, fi, hu, it, nl, no, pt
|
||||
default:
|
||||
return n !== 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
|
||||
let buff;
|
||||
if (typeof fetch === 'undefined') {
|
||||
buff = fs.readFileSync('zlib-1.2.12.wasm');
|
||||
buff = fs.readFileSync('zlib-1.2.13.wasm');
|
||||
} else {
|
||||
const resp = await fetch('js/zlib-1.2.12.wasm');
|
||||
const resp = await fetch('js/zlib-1.2.13.wasm');
|
||||
buff = await resp.arrayBuffer();
|
||||
}
|
||||
const module = await WebAssembly.compile(buff);
|
||||
Binary file not shown.
@@ -93,6 +93,10 @@ class Configuration
|
||||
'model_options' => array(
|
||||
'dir' => 'data',
|
||||
),
|
||||
'yourls' => array(
|
||||
'signature' => '',
|
||||
'apiurl' => '',
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -153,8 +157,25 @@ class Configuration
|
||||
)
|
||||
) {
|
||||
$values = array(
|
||||
'bucket' => getenv('PRIVATEBIN_GCS_BUCKET') ? getenv('PRIVATEBIN_GCS_BUCKET') : null,
|
||||
'prefix' => 'pastes',
|
||||
'bucket' => getenv('PRIVATEBIN_GCS_BUCKET') ? getenv('PRIVATEBIN_GCS_BUCKET') : null,
|
||||
'prefix' => 'pastes',
|
||||
'uniformacl' => false,
|
||||
);
|
||||
} elseif (
|
||||
$section == 'model_options' && in_array(
|
||||
$this->_configuration['model']['class'],
|
||||
array('S3Storage')
|
||||
)
|
||||
) {
|
||||
$values = array(
|
||||
'region' => null,
|
||||
'version' => null,
|
||||
'endpoint' => null,
|
||||
'accesskey' => null,
|
||||
'secretkey' => null,
|
||||
'use_path_style_endpoint' => null,
|
||||
'bucket' => null,
|
||||
'prefix' => '',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -136,6 +136,9 @@ class Controller
|
||||
case 'jsonld':
|
||||
$this->_jsonld($this->_request->getParam('jsonld'));
|
||||
return;
|
||||
case 'yourlsproxy':
|
||||
$this->_yourlsproxy($this->_request->getParam('link'));
|
||||
break;
|
||||
}
|
||||
|
||||
// output JSON or HTML
|
||||
@@ -341,7 +344,10 @@ class Controller
|
||||
header('Content-Security-Policy: ' . $this->_conf->getKey('cspheader'));
|
||||
header('Cross-Origin-Resource-Policy: same-origin');
|
||||
header('Cross-Origin-Embedder-Policy: require-corp');
|
||||
header('Cross-Origin-Opener-Policy: same-origin');
|
||||
// disabled, because it prevents links from a paste to the same site to
|
||||
// be opened. Didn't work with `same-origin-allow-popups` either.
|
||||
// See issue https://github.com/PrivateBin/PrivateBin/issues/970 for details.
|
||||
// header('Cross-Origin-Opener-Policy: same-origin');
|
||||
header('Permissions-Policy: browsing-topics=()');
|
||||
header('Referrer-Policy: no-referrer');
|
||||
header('X-Content-Type-Options: nosniff');
|
||||
@@ -375,9 +381,15 @@ class Controller
|
||||
);
|
||||
|
||||
$page = new View;
|
||||
$page->assign('NAME', $this->_conf->getKey('name'));
|
||||
$page->assign('BASEPATH', I18n::_($this->_conf->getKey('basepath')));
|
||||
$page->assign('CSPHEADER', $metacspheader);
|
||||
$page->assign('ERROR', I18n::_($this->_error));
|
||||
$page->assign('NAME', $this->_conf->getKey('name'));
|
||||
if ($this->_request->getOperation() === 'yourlsproxy') {
|
||||
$page->assign('SHORTURL', $this->_status);
|
||||
$page->draw('yourlsproxy');
|
||||
return;
|
||||
}
|
||||
$page->assign('BASEPATH', I18n::_($this->_conf->getKey('basepath')));
|
||||
$page->assign('STATUS', I18n::_($this->_status));
|
||||
$page->assign('VERSION', self::VERSION);
|
||||
$page->assign('DISCUSSION', $this->_conf->getKey('discussion'));
|
||||
@@ -402,7 +414,6 @@ class Controller
|
||||
$page->assign('HTTPWARNING', $this->_conf->getKey('httpwarning'));
|
||||
$page->assign('HTTPSLINK', 'https://' . $this->_request->getHost() . $this->_request->getRequestUri());
|
||||
$page->assign('COMPRESSION', $this->_conf->getKey('compression'));
|
||||
$page->assign('CSPHEADER', $metacspheader);
|
||||
$page->draw($this->_conf->getKey('template'));
|
||||
}
|
||||
|
||||
@@ -436,6 +447,22 @@ class Controller
|
||||
echo $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* proxies link to YOURLS, updates status or error with response
|
||||
*
|
||||
* @access private
|
||||
* @param string $link
|
||||
*/
|
||||
private function _yourlsproxy($link)
|
||||
{
|
||||
$yourls = new YourlsProxy($this->_conf, $link);
|
||||
if ($yourls->isError()) {
|
||||
$this->_error = $yourls->getError();
|
||||
} else {
|
||||
$this->_status = $yourls->getUrl();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* prepares JSON encoded status message
|
||||
*
|
||||
|
||||
@@ -584,7 +584,7 @@ class Database extends AbstractData
|
||||
// workaround for https://bugs.php.net/bug.php?id=46728
|
||||
$result = array();
|
||||
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
|
||||
$result[] = array_map('self::_sanitizeClob', $row);
|
||||
$result[] = array_map('PrivateBin\Data\Database::_sanitizeClob', $row);
|
||||
}
|
||||
} else {
|
||||
$result = $statement->fetchAll(PDO::FETCH_ASSOC);
|
||||
@@ -593,7 +593,7 @@ class Database extends AbstractData
|
||||
if (self::$_type === 'oci' && is_array($result)) {
|
||||
// returned CLOB values are streams, convert these into strings
|
||||
$result = $firstOnly ?
|
||||
array_map('self::_sanitizeClob', $result) :
|
||||
array_map('PrivateBin\Data\Database::_sanitizeClob', $result) :
|
||||
$result;
|
||||
}
|
||||
return $result;
|
||||
|
||||
@@ -351,7 +351,7 @@ class Filesystem extends AbstractData
|
||||
$pastes = array();
|
||||
$firstLevel = array_filter(
|
||||
scandir(self::$_path),
|
||||
'self::_isFirstLevelDir'
|
||||
'PrivateBin\Data\Filesystem::_isFirstLevelDir'
|
||||
);
|
||||
if (count($firstLevel) > 0) {
|
||||
// try at most 10 times the $batchsize pastes before giving up
|
||||
@@ -359,7 +359,7 @@ class Filesystem extends AbstractData
|
||||
$firstKey = array_rand($firstLevel);
|
||||
$secondLevel = array_filter(
|
||||
scandir(self::$_path . DIRECTORY_SEPARATOR . $firstLevel[$firstKey]),
|
||||
'self::_isSecondLevelDir'
|
||||
'PrivateBin\Data\Filesystem::_isSecondLevelDir'
|
||||
);
|
||||
|
||||
// skip this folder in the next checks if it is empty
|
||||
|
||||
@@ -37,6 +37,15 @@ class GoogleCloudStorage extends AbstractData
|
||||
*/
|
||||
private static $_prefix = 'pastes';
|
||||
|
||||
/**
|
||||
* bucket acl type
|
||||
*
|
||||
* @access private
|
||||
* @static
|
||||
* @var bool
|
||||
*/
|
||||
private static $_uniformacl = false;
|
||||
|
||||
/**
|
||||
* returns a Google Cloud Storage data backend.
|
||||
*
|
||||
@@ -62,6 +71,9 @@ class GoogleCloudStorage extends AbstractData
|
||||
if (is_array($options) && array_key_exists('prefix', $options)) {
|
||||
self::$_prefix = $options['prefix'];
|
||||
}
|
||||
if (is_array($options) && array_key_exists('uniformacl', $options)) {
|
||||
self::$_uniformacl = $options['uniformacl'];
|
||||
}
|
||||
|
||||
if (empty(self::$_client)) {
|
||||
self::$_client = class_exists('StorageClientStub', false) ?
|
||||
@@ -106,15 +118,18 @@ class GoogleCloudStorage extends AbstractData
|
||||
$metadata[$k] = strval($v);
|
||||
}
|
||||
try {
|
||||
self::$_bucket->upload(Json::encode($payload), array(
|
||||
$data = array(
|
||||
'name' => $key,
|
||||
'chunkSize' => 262144,
|
||||
'predefinedAcl' => 'private',
|
||||
'metadata' => array(
|
||||
'content-type' => 'application/json',
|
||||
'metadata' => $metadata,
|
||||
),
|
||||
));
|
||||
);
|
||||
if (!self::$_uniformacl) {
|
||||
$data['predefinedAcl'] = 'private';
|
||||
}
|
||||
self::$_bucket->upload(Json::encode($payload), $data);
|
||||
} catch (Exception $e) {
|
||||
error_log('failed to upload ' . $key . ' to ' . self::$_bucket->name() . ', ' .
|
||||
trim(preg_replace('/\s\s+/', ' ', $e->getMessage())));
|
||||
@@ -277,15 +292,18 @@ class GoogleCloudStorage extends AbstractData
|
||||
$metadata['value'] = strval($value);
|
||||
}
|
||||
try {
|
||||
self::$_bucket->upload($value, array(
|
||||
$data = array(
|
||||
'name' => $key,
|
||||
'chunkSize' => 262144,
|
||||
'predefinedAcl' => 'private',
|
||||
'metadata' => array(
|
||||
'content-type' => 'application/json',
|
||||
'metadata' => $metadata,
|
||||
),
|
||||
));
|
||||
);
|
||||
if (!self::$_uniformacl) {
|
||||
$data['predefinedAcl'] = 'private';
|
||||
}
|
||||
self::$_bucket->upload($value, $data);
|
||||
} catch (Exception $e) {
|
||||
error_log('failed to set key ' . $key . ' to ' . self::$_bucket->name() . ', ' .
|
||||
trim(preg_replace('/\s\s+/', ' ', $e->getMessage())));
|
||||
|
||||
464
lib/Data/S3Storage.php
Normal file
464
lib/Data/S3Storage.php
Normal file
@@ -0,0 +1,464 @@
|
||||
<?php
|
||||
/**
|
||||
* S3.php
|
||||
*
|
||||
* an S3 compatible data backend for PrivateBin with CEPH/RadosGW in mind
|
||||
* see https://docs.ceph.com/en/latest/radosgw/s3/php/
|
||||
* based on lib/Data/GoogleCloudStorage.php from PrivateBin version 1.4.0
|
||||
*
|
||||
* @link https://github.com/PrivateBin/PrivateBin
|
||||
* @copyright 2022 Felix J. Ogris (https://ogris.de/)
|
||||
* @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
|
||||
* @version 1.4.1
|
||||
*
|
||||
* Installation:
|
||||
* 1. Make sure you have composer.lock and composer.json in the document root of your PasteBin
|
||||
* 2. If not, grab a copy from https://github.com/PrivateBin/PrivateBin
|
||||
* 3. As non-root user, install the AWS SDK for PHP:
|
||||
* composer require aws/aws-sdk-php
|
||||
* (On FreeBSD, install devel/php-composer2 prior, e.g.: make -C /usr/ports/devel/php-composer2 install clean)
|
||||
* 4. In cfg/conf.php, comment out all [model] and [model_options] settings
|
||||
* 5. Still in cfg/conf.php, add a new [model] section:
|
||||
* [model]
|
||||
* class = S3Storage
|
||||
* 6. Add a new [model_options] as well, e.g. for a Rados gateway as part of your CEPH cluster:
|
||||
* [model_options]
|
||||
* region = ""
|
||||
* version = "2006-03-01"
|
||||
* endpoint = "https://s3.my-ceph.invalid"
|
||||
* use_path_style_endpoint = true
|
||||
* bucket = "my-bucket"
|
||||
* prefix = "privatebin" (place all PrivateBin data beneath this prefix)
|
||||
* accesskey = "my-rados-user"
|
||||
* secretkey = "my-rados-pass"
|
||||
*/
|
||||
|
||||
namespace PrivateBin\Data;
|
||||
|
||||
use Aws\S3\Exception\S3Exception;
|
||||
use Aws\S3\S3Client;
|
||||
use PrivateBin\Json;
|
||||
|
||||
class S3Storage extends AbstractData
|
||||
{
|
||||
/**
|
||||
* S3 client
|
||||
*
|
||||
* @access private
|
||||
* @static
|
||||
* @var S3Client
|
||||
*/
|
||||
private static $_client = null;
|
||||
|
||||
/**
|
||||
* S3 client options
|
||||
*
|
||||
* @access private
|
||||
* @static
|
||||
* @var array
|
||||
*/
|
||||
private static $_options = array();
|
||||
|
||||
/**
|
||||
* S3 bucket
|
||||
*
|
||||
* @access private
|
||||
* @static
|
||||
* @var string
|
||||
*/
|
||||
private static $_bucket = null;
|
||||
|
||||
/**
|
||||
* S3 prefix for all PrivateBin data in this bucket
|
||||
*
|
||||
* @access private
|
||||
* @static
|
||||
* @var string
|
||||
*/
|
||||
private static $_prefix = '';
|
||||
|
||||
/**
|
||||
* returns an S3 data backend.
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
* @param array $options
|
||||
* @return S3Storage
|
||||
*/
|
||||
public static function getInstance(array $options)
|
||||
{
|
||||
// if needed initialize the singleton
|
||||
if (!(self::$_instance instanceof self)) {
|
||||
self::$_instance = new self;
|
||||
}
|
||||
|
||||
self::$_options = array();
|
||||
self::$_options['credentials'] = array();
|
||||
|
||||
if (is_array($options) && array_key_exists('region', $options)) {
|
||||
self::$_options['region'] = $options['region'];
|
||||
}
|
||||
if (is_array($options) && array_key_exists('version', $options)) {
|
||||
self::$_options['version'] = $options['version'];
|
||||
}
|
||||
if (is_array($options) && array_key_exists('endpoint', $options)) {
|
||||
self::$_options['endpoint'] = $options['endpoint'];
|
||||
}
|
||||
if (is_array($options) && array_key_exists('accesskey', $options)) {
|
||||
self::$_options['credentials']['key'] = $options['accesskey'];
|
||||
}
|
||||
if (is_array($options) && array_key_exists('secretkey', $options)) {
|
||||
self::$_options['credentials']['secret'] = $options['secretkey'];
|
||||
}
|
||||
if (is_array($options) && array_key_exists('use_path_style_endpoint', $options)) {
|
||||
self::$_options['use_path_style_endpoint'] = filter_var($options['use_path_style_endpoint'], FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
if (is_array($options) && array_key_exists('bucket', $options)) {
|
||||
self::$_bucket = $options['bucket'];
|
||||
}
|
||||
if (is_array($options) && array_key_exists('prefix', $options)) {
|
||||
self::$_prefix = $options['prefix'];
|
||||
}
|
||||
|
||||
if (empty(self::$_client)) {
|
||||
self::$_client = new S3Client(self::$_options);
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns all objects in the given prefix.
|
||||
*
|
||||
* @access private
|
||||
* @param $prefix string with prefix
|
||||
* @return array all objects in the given prefix
|
||||
*/
|
||||
private function _listAllObjects($prefix)
|
||||
{
|
||||
$allObjects = array();
|
||||
$options = array(
|
||||
'Bucket' => self::$_bucket,
|
||||
'Prefix' => $prefix,
|
||||
);
|
||||
|
||||
do {
|
||||
$objectsListResponse = self::$_client->listObjects($options);
|
||||
$objects = $objectsListResponse['Contents'] ?? array();
|
||||
foreach ($objects as $object) {
|
||||
$allObjects[] = $object;
|
||||
$options['Marker'] = $object['Key'];
|
||||
}
|
||||
} while ($objectsListResponse['IsTruncated']);
|
||||
|
||||
return $allObjects;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the S3 storage object key for $pasteid in self::$_bucket.
|
||||
*
|
||||
* @access private
|
||||
* @param $pasteid string to get the key for
|
||||
* @return string
|
||||
*/
|
||||
private function _getKey($pasteid)
|
||||
{
|
||||
if (self::$_prefix != '') {
|
||||
return self::$_prefix . '/' . $pasteid;
|
||||
}
|
||||
return $pasteid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads the payload in the self::$_bucket under the specified key.
|
||||
* The entire payload is stored as a JSON document. The metadata is replicated
|
||||
* as the S3 object's metadata except for the fields attachment, attachmentname
|
||||
* and salt.
|
||||
*
|
||||
* @param $key string to store the payload under
|
||||
* @param $payload array to store
|
||||
* @return bool true if successful, otherwise false.
|
||||
*/
|
||||
private function _upload($key, $payload)
|
||||
{
|
||||
$metadata = array_key_exists('meta', $payload) ? $payload['meta'] : array();
|
||||
unset($metadata['attachment'], $metadata['attachmentname'], $metadata['salt']);
|
||||
foreach ($metadata as $k => $v) {
|
||||
$metadata[$k] = strval($v);
|
||||
}
|
||||
try {
|
||||
self::$_client->putObject(array(
|
||||
'Bucket' => self::$_bucket,
|
||||
'Key' => $key,
|
||||
'Body' => Json::encode($payload),
|
||||
'ContentType' => 'application/json',
|
||||
'Metadata' => $metadata,
|
||||
));
|
||||
} catch (S3Exception $e) {
|
||||
error_log('failed to upload ' . $key . ' to ' . self::$_bucket . ', ' .
|
||||
trim(preg_replace('/\s\s+/', ' ', $e->getMessage())));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function create($pasteid, array $paste)
|
||||
{
|
||||
if ($this->exists($pasteid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->_upload($this->_getKey($pasteid), $paste);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function read($pasteid)
|
||||
{
|
||||
try {
|
||||
$object = self::$_client->getObject(array(
|
||||
'Bucket' => self::$_bucket,
|
||||
'Key' => $this->_getKey($pasteid),
|
||||
));
|
||||
$data = $object['Body']->getContents();
|
||||
return Json::decode($data);
|
||||
} catch (S3Exception $e) {
|
||||
error_log('failed to read ' . $pasteid . ' from ' . self::$_bucket . ', ' .
|
||||
trim(preg_replace('/\s\s+/', ' ', $e->getMessage())));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function delete($pasteid)
|
||||
{
|
||||
$name = $this->_getKey($pasteid);
|
||||
|
||||
try {
|
||||
$comments = $this->_listAllObjects($name . '/discussion/');
|
||||
foreach ($comments as $comment) {
|
||||
try {
|
||||
self::$_client->deleteObject(array(
|
||||
'Bucket' => self::$_bucket,
|
||||
'Key' => $comment['Key'],
|
||||
));
|
||||
} catch (S3Exception $e) {
|
||||
// ignore if already deleted.
|
||||
}
|
||||
}
|
||||
} catch (S3Exception $e) {
|
||||
// there are no discussions associated with the paste
|
||||
}
|
||||
|
||||
try {
|
||||
self::$_client->deleteObject(array(
|
||||
'Bucket' => self::$_bucket,
|
||||
'Key' => $name,
|
||||
));
|
||||
} catch (S3Exception $e) {
|
||||
// ignore if already deleted
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function exists($pasteid)
|
||||
{
|
||||
return self::$_client->doesObjectExistV2(self::$_bucket, $this->_getKey($pasteid));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function createComment($pasteid, $parentid, $commentid, array $comment)
|
||||
{
|
||||
if ($this->existsComment($pasteid, $parentid, $commentid)) {
|
||||
return false;
|
||||
}
|
||||
$key = $this->_getKey($pasteid) . '/discussion/' . $parentid . '/' . $commentid;
|
||||
return $this->_upload($key, $comment);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function readComments($pasteid)
|
||||
{
|
||||
$comments = array();
|
||||
$prefix = $this->_getKey($pasteid) . '/discussion/';
|
||||
try {
|
||||
$entries = $this->_listAllObjects($prefix);
|
||||
foreach ($entries as $entry) {
|
||||
$object = self::$_client->getObject(array(
|
||||
'Bucket' => self::$_bucket,
|
||||
'Key' => $entry['Key'],
|
||||
));
|
||||
$body = JSON::decode($object['Body']->getContents());
|
||||
$items = explode('/', $entry['Key']);
|
||||
$body['id'] = $items[3];
|
||||
$body['parentid'] = $items[2];
|
||||
$slot = $this->getOpenSlot($comments, (int) $object['Metadata']['created']);
|
||||
$comments[$slot] = $body;
|
||||
}
|
||||
} catch (S3Exception $e) {
|
||||
// no comments found
|
||||
}
|
||||
return $comments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function existsComment($pasteid, $parentid, $commentid)
|
||||
{
|
||||
$name = $this->_getKey($pasteid) . '/discussion/' . $parentid . '/' . $commentid;
|
||||
return self::$_client->doesObjectExistV2(self::$_bucket, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function purgeValues($namespace, $time)
|
||||
{
|
||||
$path = self::$_prefix;
|
||||
if ($path != '') {
|
||||
$path .= '/';
|
||||
}
|
||||
$path .= 'config/' . $namespace;
|
||||
|
||||
try {
|
||||
foreach ($this->_listAllObjects($path) as $object) {
|
||||
$name = $object['Key'];
|
||||
if (strlen($name) > strlen($path) && substr($name, strlen($path), 1) !== '/') {
|
||||
continue;
|
||||
}
|
||||
$head = self::$_client->headObject(array(
|
||||
'Bucket' => self::$_bucket,
|
||||
'Key' => $name,
|
||||
));
|
||||
if (array_key_exists('Metadata', $head) && array_key_exists('value', $head['Metadata'])) {
|
||||
$value = $head['Metadata']['value'];
|
||||
if (is_numeric($value) && intval($value) < $time) {
|
||||
try {
|
||||
self::$_client->deleteObject(array(
|
||||
'Bucket' => self::$_bucket,
|
||||
'Key' => $name,
|
||||
));
|
||||
} catch (S3Exception $e) {
|
||||
// deleted by another instance.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (S3Exception $e) {
|
||||
// no objects in the bucket yet
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For S3, the value will also be stored in the metadata for the
|
||||
* namespaces traffic_limiter and purge_limiter.
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function setValue($value, $namespace, $key = '')
|
||||
{
|
||||
$prefix = self::$_prefix;
|
||||
if ($prefix != '') {
|
||||
$prefix .= '/';
|
||||
}
|
||||
|
||||
if ($key === '') {
|
||||
$key = $prefix . 'config/' . $namespace;
|
||||
} else {
|
||||
$key = $prefix . 'config/' . $namespace . '/' . $key;
|
||||
}
|
||||
|
||||
$metadata = array('namespace' => $namespace);
|
||||
if ($namespace != 'salt') {
|
||||
$metadata['value'] = strval($value);
|
||||
}
|
||||
try {
|
||||
self::$_client->putObject(array(
|
||||
'Bucket' => self::$_bucket,
|
||||
'Key' => $key,
|
||||
'Body' => $value,
|
||||
'ContentType' => 'application/json',
|
||||
'Metadata' => $metadata,
|
||||
));
|
||||
} catch (S3Exception $e) {
|
||||
error_log('failed to set key ' . $key . ' to ' . self::$_bucket . ', ' .
|
||||
trim(preg_replace('/\s\s+/', ' ', $e->getMessage())));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getValue($namespace, $key = '')
|
||||
{
|
||||
$prefix = self::$_prefix;
|
||||
if ($prefix != '') {
|
||||
$prefix .= '/';
|
||||
}
|
||||
|
||||
if ($key === '') {
|
||||
$key = $prefix . 'config/' . $namespace;
|
||||
} else {
|
||||
$key = $prefix . 'config/' . $namespace . '/' . $key;
|
||||
}
|
||||
|
||||
try {
|
||||
$object = self::$_client->getObject(array(
|
||||
'Bucket' => self::$_bucket,
|
||||
'Key' => $key,
|
||||
));
|
||||
return $object['Body']->getContents();
|
||||
} catch (S3Exception $e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function _getExpiredPastes($batchsize)
|
||||
{
|
||||
$expired = array();
|
||||
$now = time();
|
||||
$prefix = self::$_prefix;
|
||||
if ($prefix != '') {
|
||||
$prefix .= '/';
|
||||
}
|
||||
|
||||
try {
|
||||
foreach ($this->_listAllObjects($prefix) as $object) {
|
||||
$head = self::$_client->headObject(array(
|
||||
'Bucket' => self::$_bucket,
|
||||
'Key' => $object['Key'],
|
||||
));
|
||||
if (array_key_exists('Metadata', $head) && array_key_exists('expire_date', $head['Metadata'])) {
|
||||
$expire_at = intval($head['Metadata']['expire_date']);
|
||||
if ($expire_at != 0 && $expire_at < $now) {
|
||||
array_push($expired, $object['Key']);
|
||||
}
|
||||
}
|
||||
|
||||
if (count($expired) > $batchsize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (S3Exception $e) {
|
||||
// no objects in the bucket yet
|
||||
}
|
||||
return $expired;
|
||||
}
|
||||
}
|
||||
15
lib/I18n.php
15
lib/I18n.php
@@ -84,7 +84,7 @@ class I18n
|
||||
*/
|
||||
public static function _($messageId)
|
||||
{
|
||||
return forward_static_call_array('self::translate', func_get_args());
|
||||
return forward_static_call_array('PrivateBin\I18n::translate', func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -316,7 +316,8 @@ class I18n
|
||||
{
|
||||
switch (self::$_language) {
|
||||
case 'cs':
|
||||
return $n == 1 ? 0 : ($n >= 2 && $n <= 4 ? 1 : 2);
|
||||
case 'sk':
|
||||
return $n === 1 ? 0 : ($n >= 2 && $n <= 4 ? 1 : 2);
|
||||
case 'co':
|
||||
case 'fr':
|
||||
case 'oc':
|
||||
@@ -331,15 +332,15 @@ class I18n
|
||||
case 'lt':
|
||||
return $n % 10 === 1 && $n % 100 !== 11 ? 0 : (($n % 10 >= 2 && $n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
|
||||
case 'pl':
|
||||
return $n == 1 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
|
||||
return $n === 1 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
|
||||
case 'ru':
|
||||
case 'uk':
|
||||
return $n % 10 == 1 && $n % 100 != 11 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
|
||||
return $n % 10 === 1 && $n % 100 != 11 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
|
||||
case 'sl':
|
||||
return $n % 100 == 1 ? 1 : ($n % 100 == 2 ? 2 : ($n % 100 == 3 || $n % 100 == 4 ? 3 : 0));
|
||||
// bg, ca, de, en, es, et, fi, hu, it, nl, no, pt
|
||||
return $n % 100 === 1 ? 1 : ($n % 100 === 2 ? 2 : ($n % 100 === 3 || $n % 100 === 4 ? 3 : 0));
|
||||
// bg, ca, de, el, en, es, et, fi, hu, it, nl, no, pt
|
||||
default:
|
||||
return $n != 1 ? 1 : 0;
|
||||
return $n !== 1 ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace PrivateBin\Model;
|
||||
|
||||
use Exception;
|
||||
use Identicon\Identicon;
|
||||
use Jdenticon\Identicon as Jdenticon;
|
||||
use PrivateBin\Persistence\TrafficLimiter;
|
||||
use PrivateBin\Vizhash16x16;
|
||||
|
||||
@@ -167,6 +168,16 @@ class Comment extends AbstractModel
|
||||
if ($icon == 'identicon') {
|
||||
$identicon = new Identicon();
|
||||
$pngdata = $identicon->getImageDataUri($hmac, 16);
|
||||
} elseif ($icon == 'jdenticon') {
|
||||
$jdenticon = new Jdenticon(array(
|
||||
'hash' => $hmac,
|
||||
'size' => 16,
|
||||
'style' => array(
|
||||
'backgroundColor' => '#fff0', // fully transparent, for dark mode
|
||||
'padding' => 0,
|
||||
),
|
||||
));
|
||||
$pngdata = $jdenticon->getImageDataUri('png');
|
||||
} elseif ($icon == 'vizhash') {
|
||||
$vh = new Vizhash16x16();
|
||||
$pngdata = 'data:image/png;base64,' . base64_encode(
|
||||
|
||||
@@ -120,6 +120,7 @@ class Request
|
||||
if (
|
||||
!array_key_exists('pasteid', $this->_params) &&
|
||||
!array_key_exists('jsonld', $this->_params) &&
|
||||
!array_key_exists('link', $this->_params) &&
|
||||
array_key_exists('QUERY_STRING', $_SERVER) &&
|
||||
!empty($_SERVER['QUERY_STRING'])
|
||||
) {
|
||||
@@ -135,6 +136,10 @@ class Request
|
||||
}
|
||||
} elseif (array_key_exists('jsonld', $this->_params) && !empty($this->_params['jsonld'])) {
|
||||
$this->_operation = 'jsonld';
|
||||
} elseif (array_key_exists('link', $this->_params) && !empty($this->_params['link'])) {
|
||||
if (strpos($this->getRequestUri(), '/shortenviayourls') !== false) {
|
||||
$this->_operation = 'yourlsproxy';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
132
lib/YourlsProxy.php
Normal file
132
lib/YourlsProxy.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
/**
|
||||
* PrivateBin
|
||||
*
|
||||
* a zero-knowledge paste bin
|
||||
*
|
||||
* @link https://github.com/PrivateBin/PrivateBin
|
||||
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
|
||||
* @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
|
||||
* @version 1.4.0
|
||||
*/
|
||||
|
||||
namespace PrivateBin;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* YourlsProxy
|
||||
*
|
||||
* Forwards a URL for shortening to YOURLS (your own URL shortener) and stores
|
||||
* the result.
|
||||
*/
|
||||
class YourlsProxy
|
||||
{
|
||||
/**
|
||||
* error message
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
private $_error = '';
|
||||
|
||||
/**
|
||||
* shortened URL
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
private $_url = '';
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* initializes and runs PrivateBin
|
||||
*
|
||||
* @access public
|
||||
* @param string $link
|
||||
*/
|
||||
public function __construct(Configuration $conf, $link)
|
||||
{
|
||||
if (strpos($link, $conf->getKey('basepath') . '/?') === false) {
|
||||
$this->_error = 'Trying to shorten a URL that isn\'t pointing at our instance.';
|
||||
return;
|
||||
}
|
||||
|
||||
$yourls_api_url = $conf->getKey('apiurl', 'yourls');
|
||||
if (empty($yourls_api_url)) {
|
||||
$this->_error = 'Error calling YOURLS. Probably a configuration issue, like wrong or missing "apiurl" or "signature".';
|
||||
return;
|
||||
}
|
||||
|
||||
$data = file_get_contents(
|
||||
$yourls_api_url, false, stream_context_create(
|
||||
array(
|
||||
'http' => array(
|
||||
'method' => 'POST',
|
||||
'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
|
||||
'content' => http_build_query(
|
||||
array(
|
||||
'signature' => $conf->getKey('signature', 'yourls'),
|
||||
'format' => 'json',
|
||||
'action' => 'shorturl',
|
||||
'url' => $link,
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
);
|
||||
try {
|
||||
$data = Json::decode($data);
|
||||
} catch (Exception $e) {
|
||||
$this->_error = 'Error calling YOURLS. Probably a configuration issue, like wrong or missing "apiurl" or "signature".';
|
||||
error_log('Error calling YOURLS: ' . $e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!is_null($data) &&
|
||||
array_key_exists('statusCode', $data) &&
|
||||
$data['statusCode'] == 200 &&
|
||||
array_key_exists('shorturl', $data)
|
||||
) {
|
||||
$this->_url = $data['shorturl'];
|
||||
} else {
|
||||
$this->_error = 'Error parsing YOURLS response.';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the (untranslated) error message
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getError()
|
||||
{
|
||||
return $this->_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shortened URL
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getUrl()
|
||||
{
|
||||
return $this->_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if any error has occurred
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function isError()
|
||||
{
|
||||
return !empty($this->_error);
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ if ($ZEROBINCOMPATIBILITY) :
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.2.12.js" integrity="sha512-Ewve1dyEW/Vf97OY91/aWqMx9NaaUK5d8Z6JB1RR5gFXtMhse/Ya7D/5CE/UrQTwOWqmkvn97JjP4YDUrmq/yA==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.2.13.js" integrity="sha512-Lv4PCbSge8B4odE2blatgggJ/mkX1Ak21e7jL8mY3vzrVHS8FGsrEoqCrizxIJB4sW3T2w5Q+RG7hhUvp7+9tw==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/base-x-4.0.0.js" integrity="sha512-nNPg5IGCwwrveZ8cA/yMGr5HiRS5Ps2H+s0J/mKTPjCPWUgFGGw7M5nqdnPD3VsRwCVysUh3Y8OWjeSKGkEQJQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/rawinflate-0.3.js" integrity="sha512-g8uelGgJW9A/Z1tB6Izxab++oj5kdD7B4qC7DHwZkB6DGMXKyzx7v5mvap2HXueI2IIn08YlRYM56jwWdm2ucQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/bootstrap-3.4.1.js" integrity="sha512-oBTprMeNEKCnqfuqKd6sbvFzmFQtlXS3e0C/RGFV0hD6QzhHV+ODfaQbAlmY6/q0ubbwlAM/nCJjkrgA3waLzg==" crossorigin="anonymous"></script>
|
||||
@@ -73,7 +73,7 @@ endif;
|
||||
?>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/purify-2.3.6.js" integrity="sha512-N1GGPjbqLbwK821ZN7C925WuTwU4aDxz2CEEOXQ6/s6m6MBwVj8fh5fugiE2hzsm0xud3q7jpjZQ4ILnpMREYQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-CbXFfxyGfdXnwMumt2sMdPs/Pxnk3Ahkpw8JulqRIGYZPq7O/hM0YT/xjHG9IcaigdKC0aL42uzlxoBXLI11gw==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-sQhu+q8ayRj0LO80orHnhEudlTf5Qx+Yhb/+U84ixMvSdwijuLEHGiEuWctqUPOFSe56L6aeq6z7K0ONpbgaew==" crossorigin="anonymous"></script>
|
||||
<!-- icon -->
|
||||
<link rel="apple-touch-icon" href="<?php echo I18n::encode($BASEPATH); ?>img/apple-touch-icon.png" sizes="180x180" />
|
||||
<link rel="icon" type="image/png" href="img/favicon-32x32.png" sizes="32x32" />
|
||||
@@ -85,7 +85,7 @@ endif;
|
||||
<meta name="theme-color" content="#ffe57e" />
|
||||
<!-- Twitter/social media cards -->
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:title" content="<?php echo I18n::_('Encrypted note on PrivateBin') ?>" />
|
||||
<meta name="twitter:title" content="<?php echo I18n::_('Encrypted note on %s', I18n::_($NAME)) ?>" />
|
||||
<meta name="twitter:description" content="<?php echo I18n::_('Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.') ?>" />
|
||||
<meta name="twitter:image" content="<?php echo I18n::encode($BASEPATH); ?>img/apple-touch-icon.png" />
|
||||
<meta property="og:title" content="<?php echo I18n::_($NAME); ?>" />
|
||||
|
||||
@@ -34,7 +34,7 @@ if ($ZEROBINCOMPATIBILITY):
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.2.12.js" integrity="sha512-Ewve1dyEW/Vf97OY91/aWqMx9NaaUK5d8Z6JB1RR5gFXtMhse/Ya7D/5CE/UrQTwOWqmkvn97JjP4YDUrmq/yA==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.2.13.js" integrity="sha512-Lv4PCbSge8B4odE2blatgggJ/mkX1Ak21e7jL8mY3vzrVHS8FGsrEoqCrizxIJB4sW3T2w5Q+RG7hhUvp7+9tw==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/base-x-4.0.0.js" integrity="sha512-nNPg5IGCwwrveZ8cA/yMGr5HiRS5Ps2H+s0J/mKTPjCPWUgFGGw7M5nqdnPD3VsRwCVysUh3Y8OWjeSKGkEQJQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/rawinflate-0.3.js" integrity="sha512-g8uelGgJW9A/Z1tB6Izxab++oj5kdD7B4qC7DHwZkB6DGMXKyzx7v5mvap2HXueI2IIn08YlRYM56jwWdm2ucQ==" crossorigin="anonymous"></script>
|
||||
<?php
|
||||
@@ -51,7 +51,7 @@ endif;
|
||||
?>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/purify-2.3.6.js" integrity="sha512-N1GGPjbqLbwK821ZN7C925WuTwU4aDxz2CEEOXQ6/s6m6MBwVj8fh5fugiE2hzsm0xud3q7jpjZQ4ILnpMREYQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-CbXFfxyGfdXnwMumt2sMdPs/Pxnk3Ahkpw8JulqRIGYZPq7O/hM0YT/xjHG9IcaigdKC0aL42uzlxoBXLI11gw==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-sQhu+q8ayRj0LO80orHnhEudlTf5Qx+Yhb/+U84ixMvSdwijuLEHGiEuWctqUPOFSe56L6aeq6z7K0ONpbgaew==" crossorigin="anonymous"></script>
|
||||
<!-- icon -->
|
||||
<link rel="apple-touch-icon" href="img/apple-touch-icon.png?<?php echo rawurlencode($VERSION); ?>" sizes="180x180" />
|
||||
<link rel="icon" type="image/png" href="img/favicon-32x32.png?<?php echo rawurlencode($VERSION); ?>" sizes="32x32" />
|
||||
@@ -63,7 +63,7 @@ endif;
|
||||
<meta name="theme-color" content="#ffe57e" />
|
||||
<!-- Twitter/social media cards -->
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:title" content="<?php echo I18n::_('Encrypted note on PrivateBin') ?>" />
|
||||
<meta name="twitter:title" content="<?php echo I18n::_('Encrypted note on %s', I18n::_($NAME)) ?>" />
|
||||
<meta name="twitter:description" content="<?php echo I18n::_('Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.') ?>" />
|
||||
<meta name="twitter:image" content="img/apple-touch-icon.png?<?php echo rawurlencode($VERSION); ?>" />
|
||||
<meta property="og:title" content="<?php echo I18n::_($NAME); ?>" />
|
||||
|
||||
27
tpl/yourlsproxy.php
Normal file
27
tpl/yourlsproxy.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
use PrivateBin\I18n;
|
||||
?><!DOCTYPE html>
|
||||
<html lang="<?php echo I18n::_('en'); ?>">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Security-Policy" content="<?php echo I18n::encode($CSPHEADER); ?>">
|
||||
<meta name="robots" content="noindex" />
|
||||
<meta name="google" content="notranslate">
|
||||
<title><?php echo I18n::_($NAME); ?></title>
|
||||
</head>
|
||||
<body>
|
||||
<?php
|
||||
if (empty($ERROR)) :
|
||||
?>
|
||||
<p><?php echo I18n::_('Your paste is <a id="pasteurl" href="%s">%s</a> <span id="copyhint">(Hit [Ctrl]+[c] to copy)</span>', $SHORTURL, $SHORTURL); ?></p>
|
||||
<?php
|
||||
else:
|
||||
?>
|
||||
<div id="errormessage">
|
||||
<p><?php echo I18n::_('Could not create paste: %s', $ERROR); ?></p>
|
||||
</div>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -48,6 +48,7 @@ class ControllerTest extends PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testView()
|
||||
{
|
||||
$_SERVER['HTTP_HOST'] = 'example.com';
|
||||
$_SERVER['QUERY_STRING'] = Helper::getPasteId();
|
||||
$_GET[Helper::getPasteId()] = '';
|
||||
ob_start();
|
||||
@@ -64,6 +65,11 @@ class ControllerTest extends PHPUnit_Framework_TestCase
|
||||
$content,
|
||||
'doesn\'t output shortener button'
|
||||
);
|
||||
$this->assertRegExp(
|
||||
'# href="https://' . preg_quote($_SERVER['HTTP_HOST']) . '/">switching to HTTPS#',
|
||||
$content,
|
||||
'outputs configured https URL correctly'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
72
tst/IconTest
72
tst/IconTest
@@ -9,6 +9,7 @@ use Identicon\Generator\GdGenerator;
|
||||
use Identicon\Generator\ImageMagickGenerator;
|
||||
use Identicon\Generator\SvgGenerator;
|
||||
use Identicon\Identicon;
|
||||
use Jdenticon\Identicon as Jdenticon;
|
||||
use PrivateBin\Vizhash16x16;
|
||||
|
||||
|
||||
@@ -17,7 +18,19 @@ $vizhash = new Vizhash16x16();
|
||||
$identiconGenerators = array(
|
||||
'identicon GD' => new Identicon(new GdGenerator()),
|
||||
'identicon ImageMagick' => new Identicon(new ImageMagickGenerator()),
|
||||
'identicon SVG' => new Identicon(new SvgGenerator())
|
||||
'identicon SVG' => new Identicon(new SvgGenerator()),
|
||||
);
|
||||
$jdenticon = new Jdenticon(array(
|
||||
'size' => 16,
|
||||
'style' => array(
|
||||
'backgroundColor' => '#fff0', // fully transparent, for dark mode
|
||||
'padding' => 0,
|
||||
),
|
||||
));
|
||||
$jdenticonGenerators = array(
|
||||
'jdenticon' => 'png',
|
||||
'jdenticon ImageMagick' => 'png',
|
||||
'jdenticon SVG' => 'svg',
|
||||
);
|
||||
$results = array(
|
||||
'vizhash' => array(
|
||||
@@ -35,21 +48,30 @@ $results = array(
|
||||
'identicon SVG' => array(
|
||||
'lengths' => array(),
|
||||
'time' => 0
|
||||
)
|
||||
),
|
||||
'jdenticon' => array(
|
||||
'lengths' => array(),
|
||||
'time' => 0
|
||||
),
|
||||
'jdenticon ImageMagick' => array(
|
||||
'lengths' => array(),
|
||||
'time' => 0
|
||||
),
|
||||
'jdenticon SVG' => array(
|
||||
'lengths' => array(),
|
||||
'time' => 0
|
||||
),
|
||||
);
|
||||
$hmacs = array();
|
||||
|
||||
echo 'generate ', ITERATIONS, ' hmacs and pre-populate the result array, so tests wont be slowed down', PHP_EOL;
|
||||
for ($i = 0; $i < ITERATIONS; ++$i) {
|
||||
$hmacs[$i] = hash_hmac('sha512', '127.0.0.1', bin2hex(random_bytes(256)));
|
||||
$results['vizhash']['lengths'][$i] = 0;
|
||||
$results['identicon GD']['lengths'][$i] = 0;
|
||||
$results['identicon ImageMagick']['lengths'][$i] = 0;
|
||||
$results['identicon SVG']['lengths'][$i] = 0;
|
||||
foreach (array_keys($results) as $test) {
|
||||
$results[$test]['lengths'][$i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
echo 'run vizhash tests', PHP_EOL;
|
||||
$start = microtime(true);
|
||||
foreach ($hmacs as $i => $hmac) {
|
||||
@@ -60,7 +82,6 @@ foreach ($hmacs as $i => $hmac) {
|
||||
}
|
||||
$results['vizhash']['time'] = microtime(true) - $start;
|
||||
|
||||
|
||||
foreach ($identiconGenerators as $key => $identicon) {
|
||||
echo 'run ', $key,' tests', PHP_EOL;
|
||||
$start = microtime(true);
|
||||
@@ -71,9 +92,35 @@ foreach ($identiconGenerators as $key => $identicon) {
|
||||
$results[$key]['time'] = microtime(true) - $start;
|
||||
}
|
||||
|
||||
foreach ($jdenticonGenerators as $key => $format) {
|
||||
echo 'run ', $key,' tests', PHP_EOL;
|
||||
if ($key === 'jdenticon ImageMagick') {
|
||||
$jdenticon->enableImageMagick = true;
|
||||
} else {
|
||||
$jdenticon->enableImageMagick = false;
|
||||
}
|
||||
$start = microtime(true);
|
||||
foreach ($hmacs as $i => $hmac) {
|
||||
$jdenticon->setHash($hmac);
|
||||
$data = $jdenticon->getImageDataUri($format);
|
||||
$results[$key]['lengths'][$i] = strlen($data);
|
||||
}
|
||||
$results[$key]['time'] = microtime(true) - $start;
|
||||
}
|
||||
|
||||
|
||||
define('PADDING_LENGTH', max(array_map(function ($key) { return strlen($key); }, array_keys($results))) + 1);
|
||||
define(
|
||||
'PADDING_LENGTH',
|
||||
max(
|
||||
array_map(
|
||||
function ($key) {
|
||||
return strlen($key);
|
||||
},
|
||||
array_keys($results)
|
||||
)
|
||||
) + 1
|
||||
);
|
||||
|
||||
function format_result_line($generator, $min, $max, $avg, $sec) {
|
||||
echo str_pad($generator, PADDING_LENGTH, ' '), "\t",
|
||||
str_pad($min, 4, ' ', STR_PAD_LEFT), "\t",
|
||||
@@ -84,7 +131,10 @@ function format_result_line($generator, $min, $max, $avg, $sec) {
|
||||
|
||||
echo PHP_EOL;
|
||||
format_result_line('Generator:', 'min', 'max', 'avg', 'seconds');
|
||||
format_result_line(str_repeat('─', PADDING_LENGTH), str_repeat('─', 4), str_repeat('─', 4), str_repeat('─', 4), str_repeat('─', 7));
|
||||
format_result_line(
|
||||
str_repeat('─', PADDING_LENGTH), str_repeat('─', 4), str_repeat('─', 4),
|
||||
str_repeat('─', 4), str_repeat('─', 7)
|
||||
);
|
||||
foreach ($results as $generator => $result) {
|
||||
sort($result['lengths']);
|
||||
format_result_line(
|
||||
|
||||
@@ -15,6 +15,9 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
/* Setup Routine */
|
||||
$this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
|
||||
if (!is_dir($this->_path)) {
|
||||
mkdir($this->_path);
|
||||
}
|
||||
$this->_model = Filesystem::getInstance(array('dir' => $this->_path));
|
||||
ServerSalt::setStore($this->_model);
|
||||
|
||||
@@ -186,8 +189,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testJsonLdPaste()
|
||||
{
|
||||
$paste = Helper::getPaste();
|
||||
$this->_model->create(Helper::getPasteId(), $paste);
|
||||
$_GET['jsonld'] = 'paste';
|
||||
ob_start();
|
||||
new Controller;
|
||||
@@ -205,8 +206,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testJsonLdComment()
|
||||
{
|
||||
$paste = Helper::getPaste();
|
||||
$this->_model->create(Helper::getPasteId(), $paste);
|
||||
$_GET['jsonld'] = 'comment';
|
||||
ob_start();
|
||||
new Controller;
|
||||
@@ -224,8 +223,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testJsonLdPasteMeta()
|
||||
{
|
||||
$paste = Helper::getPaste();
|
||||
$this->_model->create(Helper::getPasteId(), $paste);
|
||||
$_GET['jsonld'] = 'pastemeta';
|
||||
ob_start();
|
||||
new Controller;
|
||||
@@ -243,8 +240,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testJsonLdCommentMeta()
|
||||
{
|
||||
$paste = Helper::getPaste();
|
||||
$this->_model->create(Helper::getPasteId(), $paste);
|
||||
$_GET['jsonld'] = 'commentmeta';
|
||||
ob_start();
|
||||
new Controller;
|
||||
@@ -262,8 +257,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testJsonLdInvalid()
|
||||
{
|
||||
$paste = Helper::getPaste();
|
||||
$this->_model->create(Helper::getPasteId(), $paste);
|
||||
$_GET['jsonld'] = CONF;
|
||||
ob_start();
|
||||
new Controller;
|
||||
@@ -271,4 +264,42 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
|
||||
ob_end_clean();
|
||||
$this->assertEquals('{}', $content, 'does not output nasty data');
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
*/
|
||||
public function testShortenViaYourls()
|
||||
{
|
||||
$mock_yourls_service = $this->_path . DIRECTORY_SEPARATOR . 'yourls.json';
|
||||
$options = parse_ini_file(CONF, true);
|
||||
$options['main']['basepath'] = 'https://example.com/path';
|
||||
$options['main']['urlshortener'] = 'https://example.com/path/shortenviayourls?link=';
|
||||
$options['yourls']['apiurl'] = $mock_yourls_service;
|
||||
Helper::createIniFile(CONF, $options);
|
||||
|
||||
// the real service answer is more complex, but we only look for the shorturl & statusCode
|
||||
file_put_contents($mock_yourls_service, '{"shorturl":"https:\/\/example.com\/1","statusCode":200}');
|
||||
|
||||
$_SERVER['REQUEST_URI'] = '/path/shortenviayourls?link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar';
|
||||
$_GET['link'] = 'https://example.com/path/?foo#bar';
|
||||
ob_start();
|
||||
new Controller;
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$this->assertContains('id="pasteurl" href="https://example.com/1"', $content, 'outputs shortened URL correctly');
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
*/
|
||||
public function testShortenViaYourlsFailure()
|
||||
{
|
||||
$_SERVER['REQUEST_URI'] = '/path/shortenviayourls?link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar';
|
||||
$_GET['link'] = 'https://example.com/path/?foo#bar';
|
||||
ob_start();
|
||||
new Controller;
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$this->assertContains('Error calling YOURLS.', $content, 'outputs error correctly');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +106,10 @@ class ViewTest extends PHPUnit_Framework_TestCase
|
||||
$content,
|
||||
$template . ': outputs error correctly'
|
||||
);
|
||||
if ($template === 'yourlsproxy') {
|
||||
// yourlsproxy template only displays error message
|
||||
continue;
|
||||
}
|
||||
$this->assertRegExp(
|
||||
'#<[^>]+id="password"[^>]*>#',
|
||||
$content,
|
||||
|
||||
75
tst/YourlsProxyTest.php
Normal file
75
tst/YourlsProxyTest.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
use PrivateBin\Configuration;
|
||||
use PrivateBin\YourlsProxy;
|
||||
|
||||
class YourlsProxyTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
private $_conf;
|
||||
|
||||
private $_path;
|
||||
|
||||
private $_mock_yourls_service;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
/* Setup Routine */
|
||||
$this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
|
||||
if (!is_dir($this->_path)) {
|
||||
mkdir($this->_path);
|
||||
}
|
||||
$this->_mock_yourls_service = $this->_path . DIRECTORY_SEPARATOR . 'yourls.json';
|
||||
$options = parse_ini_file(CONF_SAMPLE, true);
|
||||
$options['main']['basepath'] = 'https://example.com';
|
||||
$options['main']['urlshortener'] = 'https://example.com/shortenviayourls?link=';
|
||||
$options['yourls']['apiurl'] = $this->_mock_yourls_service;
|
||||
Helper::confBackup();
|
||||
Helper::createIniFile(CONF, $options);
|
||||
$this->_conf = new Configuration;
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
/* Tear Down Routine */
|
||||
unlink(CONF);
|
||||
Helper::confRestore();
|
||||
Helper::rmDir($this->_path);
|
||||
}
|
||||
|
||||
public function testYourlsProxy()
|
||||
{
|
||||
// the real service answer is more complex, but we only look for the shorturl & statusCode
|
||||
file_put_contents($this->_mock_yourls_service, '{"shorturl":"https:\/\/example.com\/1","statusCode":200}');
|
||||
|
||||
$yourls = new YourlsProxy($this->_conf, 'https://example.com/?foo#bar');
|
||||
$this->assertFalse($yourls->isError());
|
||||
$this->assertEquals($yourls->getUrl(), 'https://example.com/1');
|
||||
}
|
||||
|
||||
public function testForeignUrl()
|
||||
{
|
||||
$yourls = new YourlsProxy($this->_conf, 'https://other.example.com/?foo#bar');
|
||||
$this->assertTrue($yourls->isError());
|
||||
$this->assertEquals($yourls->getError(), 'Trying to shorten a URL that isn\'t pointing at our instance.');
|
||||
}
|
||||
|
||||
public function testYourlsError()
|
||||
{
|
||||
// when statusCode is not 200, shorturl may not have been set
|
||||
file_put_contents($this->_mock_yourls_service, '{"statusCode":403}');
|
||||
|
||||
$yourls = new YourlsProxy($this->_conf, 'https://example.com/?foo#bar');
|
||||
$this->assertTrue($yourls->isError());
|
||||
$this->assertEquals($yourls->getError(), 'Error parsing YOURLS response.');
|
||||
}
|
||||
|
||||
public function testServerError()
|
||||
{
|
||||
// simulate some other server error that results in a non-JSON reply
|
||||
file_put_contents($this->_mock_yourls_service, '500 Internal Server Error');
|
||||
|
||||
$yourls = new YourlsProxy($this->_conf, 'https://example.com/?foo#bar');
|
||||
$this->assertTrue($yourls->isError());
|
||||
$this->assertEquals($yourls->getError(), 'Error calling YOURLS. Probably a configuration issue, like wrong or missing "apiurl" or "signature".');
|
||||
}
|
||||
}
|
||||
157
vendor/composer/ClassLoader.php
vendored
157
vendor/composer/ClassLoader.php
vendored
@@ -37,57 +37,130 @@ namespace Composer\Autoload;
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see http://www.php-fig.org/psr/psr-0/
|
||||
* @see http://www.php-fig.org/psr/psr-4/
|
||||
* @see https://www.php-fig.org/psr/psr-0/
|
||||
* @see https://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
/** @var ?string */
|
||||
private $vendorDir;
|
||||
|
||||
// PSR-4
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<string, int>>
|
||||
*/
|
||||
private $prefixLengthsPsr4 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<int, string>>
|
||||
*/
|
||||
private $prefixDirsPsr4 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<string, string[]>>
|
||||
*/
|
||||
private $prefixesPsr0 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
/** @var bool */
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $classMap = array();
|
||||
|
||||
/** @var bool */
|
||||
private $classMapAuthoritative = false;
|
||||
|
||||
/**
|
||||
* @var bool[]
|
||||
* @psalm-var array<string, bool>
|
||||
*/
|
||||
private $missingClasses = array();
|
||||
|
||||
/** @var ?string */
|
||||
private $apcuPrefix;
|
||||
|
||||
/**
|
||||
* @var self[]
|
||||
*/
|
||||
private static $registeredLoaders = array();
|
||||
|
||||
/**
|
||||
* @param ?string $vendorDir
|
||||
*/
|
||||
public function __construct($vendorDir = null)
|
||||
{
|
||||
$this->vendorDir = $vendorDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', $this->prefixesPsr0);
|
||||
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, array<int, string>>
|
||||
*/
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[] Array of classname => path
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $classMap Class to filename map
|
||||
* @param string[] $classMap Class to filename map
|
||||
* @psalm-param array<string, string> $classMap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
@@ -102,9 +175,11 @@ class ClassLoader
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
* @param string $prefix The prefix
|
||||
* @param string[]|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
@@ -147,11 +222,13 @@ class ClassLoader
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param string[]|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
@@ -195,8 +272,10 @@ class ClassLoader
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 base directories
|
||||
* @param string $prefix The prefix
|
||||
* @param string[]|string $paths The PSR-0 base directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
@@ -211,10 +290,12 @@ class ClassLoader
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param string[]|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
@@ -234,6 +315,8 @@ class ClassLoader
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
@@ -256,6 +339,8 @@ class ClassLoader
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
@@ -276,6 +361,8 @@ class ClassLoader
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
@@ -296,25 +383,44 @@ class ClassLoader
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
|
||||
if (null === $this->vendorDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($prepend) {
|
||||
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||
} else {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
|
||||
if (null !== $this->vendorDir) {
|
||||
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return bool|null True if loaded, null otherwise
|
||||
* @return true|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
@@ -323,6 +429,8 @@ class ClassLoader
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -367,6 +475,21 @@ class ClassLoader
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently registered loaders indexed by their corresponding vendor directories.
|
||||
*
|
||||
* @return self[]
|
||||
*/
|
||||
public static function getRegisteredLoaders()
|
||||
{
|
||||
return self::$registeredLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $ext
|
||||
* @return string|false
|
||||
*/
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
@@ -438,6 +561,10 @@ class ClassLoader
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
* @private
|
||||
*/
|
||||
function includeFile($file)
|
||||
{
|
||||
|
||||
350
vendor/composer/InstalledVersions.php
vendored
Normal file
350
vendor/composer/InstalledVersions.php
vendored
Normal file
@@ -0,0 +1,350 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Composer\Semver\VersionParser;
|
||||
|
||||
/**
|
||||
* This class is copied in every Composer installed project and available to all
|
||||
*
|
||||
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||
*
|
||||
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||
*/
|
||||
class InstalledVersions
|
||||
{
|
||||
/**
|
||||
* @var mixed[]|null
|
||||
* @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
|
||||
*/
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
private static $canGetVendors;
|
||||
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
|
||||
*/
|
||||
private static $installedByVendor = array();
|
||||
|
||||
/**
|
||||
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||
*
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackages()
|
||||
{
|
||||
$packages = array();
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
$packages[] = array_keys($installed['versions']);
|
||||
}
|
||||
|
||||
if (1 === \count($packages)) {
|
||||
return $packages[0];
|
||||
}
|
||||
|
||||
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all package names with a specific type e.g. 'library'
|
||||
*
|
||||
* @param string $type
|
||||
* @return string[]
|
||||
* @psalm-return list<string>
|
||||
*/
|
||||
public static function getInstalledPackagesByType($type)
|
||||
{
|
||||
$packagesByType = array();
|
||||
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
foreach ($installed['versions'] as $name => $package) {
|
||||
if (isset($package['type']) && $package['type'] === $type) {
|
||||
$packagesByType[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $packagesByType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package is installed
|
||||
*
|
||||
* This also returns true if the package name is provided or replaced by another package
|
||||
*
|
||||
* @param string $packageName
|
||||
* @param bool $includeDevRequirements
|
||||
* @return bool
|
||||
*/
|
||||
public static function isInstalled($packageName, $includeDevRequirements = true)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (isset($installed['versions'][$packageName])) {
|
||||
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given package satisfies a version constraint
|
||||
*
|
||||
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
||||
*
|
||||
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
||||
*
|
||||
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||
* @param string $packageName
|
||||
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
||||
* @return bool
|
||||
*/
|
||||
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||
{
|
||||
$constraint = $parser->parseConstraints($constraint);
|
||||
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||
|
||||
return $provided->matches($constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a version constraint representing all the range(s) which are installed for a given package
|
||||
*
|
||||
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
||||
* whether a given version of a package is installed, and not just whether it exists
|
||||
*
|
||||
* @param string $packageName
|
||||
* @return string Version constraint usable with composer/semver
|
||||
*/
|
||||
public static function getVersionRanges($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ranges = array();
|
||||
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||
}
|
||||
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||
}
|
||||
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||
}
|
||||
|
||||
return implode(' || ', $ranges);
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||
*/
|
||||
public static function getPrettyVersion($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['pretty_version'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
||||
*/
|
||||
public static function getReference($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $installed['versions'][$packageName]['reference'];
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $packageName
|
||||
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
||||
*/
|
||||
public static function getInstallPath($packageName)
|
||||
{
|
||||
foreach (self::getInstalled() as $installed) {
|
||||
if (!isset($installed['versions'][$packageName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
|
||||
*/
|
||||
public static function getRootPackage()
|
||||
{
|
||||
$installed = self::getInstalled();
|
||||
|
||||
return $installed[0]['root'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw installed.php data for custom implementations
|
||||
*
|
||||
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||
* @return array[]
|
||||
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
|
||||
*/
|
||||
public static function getRawData()
|
||||
{
|
||||
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
self::$installed = include __DIR__ . '/installed.php';
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
|
||||
return self::$installed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||
*
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
|
||||
*/
|
||||
public static function getAllRawData()
|
||||
{
|
||||
return self::getInstalled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets you reload the static array from another file
|
||||
*
|
||||
* This is only useful for complex integrations in which a project needs to use
|
||||
* this class but then also needs to execute another project's autoloader in process,
|
||||
* and wants to ensure both projects have access to their version of installed.php.
|
||||
*
|
||||
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
||||
* the data it needs from this class, then call reload() with
|
||||
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
||||
* the project in which it runs can then also use this class safely, without
|
||||
* interference between PHPUnit's dependencies and the project's dependencies.
|
||||
*
|
||||
* @param array[] $data A vendor/composer/installed.php data set
|
||||
* @return void
|
||||
*
|
||||
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
|
||||
*/
|
||||
public static function reload($data)
|
||||
{
|
||||
self::$installed = $data;
|
||||
self::$installedByVendor = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
|
||||
*/
|
||||
private static function getInstalled()
|
||||
{
|
||||
if (null === self::$canGetVendors) {
|
||||
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||
}
|
||||
|
||||
$installed = array();
|
||||
|
||||
if (self::$canGetVendors) {
|
||||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir];
|
||||
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
|
||||
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
||||
self::$installed = $installed[count($installed) - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null === self::$installed) {
|
||||
// only require the installed.php file if this file is loaded from its dumped location,
|
||||
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||
self::$installed = require __DIR__ . '/installed.php';
|
||||
} else {
|
||||
self::$installed = array();
|
||||
}
|
||||
}
|
||||
$installed[] = self::$installed;
|
||||
|
||||
return $installed;
|
||||
}
|
||||
}
|
||||
39
vendor/composer/autoload_classmap.php
vendored
39
vendor/composer/autoload_classmap.php
vendored
@@ -6,6 +6,7 @@ $vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||
'IPLib\\Address\\AddressInterface' => $vendorDir . '/mlocati/ip-lib/src/Address/AddressInterface.php',
|
||||
'IPLib\\Address\\AssignedRange' => $vendorDir . '/mlocati/ip-lib/src/Address/AssignedRange.php',
|
||||
'IPLib\\Address\\IPv4' => $vendorDir . '/mlocati/ip-lib/src/Address/IPv4.php',
|
||||
@@ -28,12 +29,49 @@ return array(
|
||||
'Identicon\\Generator\\ImageMagickGenerator' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/ImageMagickGenerator.php',
|
||||
'Identicon\\Generator\\SvgGenerator' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/SvgGenerator.php',
|
||||
'Identicon\\Identicon' => $vendorDir . '/yzalis/identicon/src/Identicon/Identicon.php',
|
||||
'Jdenticon\\Canvas\\Canvas' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Canvas.php',
|
||||
'Jdenticon\\Canvas\\CanvasContext' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/CanvasContext.php',
|
||||
'Jdenticon\\Canvas\\ColorUtils' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/ColorUtils.php',
|
||||
'Jdenticon\\Canvas\\Matrix' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Matrix.php',
|
||||
'Jdenticon\\Canvas\\Png\\PngBuffer' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Png/PngBuffer.php',
|
||||
'Jdenticon\\Canvas\\Png\\PngEncoder' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Png/PngEncoder.php',
|
||||
'Jdenticon\\Canvas\\Png\\PngPalette' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Png/PngPalette.php',
|
||||
'Jdenticon\\Canvas\\Point' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Point.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\Edge' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/Edge.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\EdgeIntersection' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeIntersection.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\EdgeSuperSampleIntersection' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeSuperSampleIntersection.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\EdgeTable' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeTable.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\Layer' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/Layer.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\LayerManager' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/LayerManager.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\Rasterizer' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/Rasterizer.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\SuperSampleBuffer' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleBuffer.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\SuperSampleRange' => $vendorDir . '/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleRange.php',
|
||||
'Jdenticon\\Color' => $vendorDir . '/jdenticon/jdenticon/src/Color.php',
|
||||
'Jdenticon\\Identicon' => $vendorDir . '/jdenticon/jdenticon/src/Identicon.php',
|
||||
'Jdenticon\\IdenticonStyle' => $vendorDir . '/jdenticon/jdenticon/src/IdenticonStyle.php',
|
||||
'Jdenticon\\Rendering\\AbstractRenderer' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/AbstractRenderer.php',
|
||||
'Jdenticon\\Rendering\\ColorTheme' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/ColorTheme.php',
|
||||
'Jdenticon\\Rendering\\IconGenerator' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/IconGenerator.php',
|
||||
'Jdenticon\\Rendering\\ImagickRenderer' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php',
|
||||
'Jdenticon\\Rendering\\InternalPngRenderer' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/InternalPngRenderer.php',
|
||||
'Jdenticon\\Rendering\\Point' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/Point.php',
|
||||
'Jdenticon\\Rendering\\Rectangle' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/Rectangle.php',
|
||||
'Jdenticon\\Rendering\\RendererInterface' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/RendererInterface.php',
|
||||
'Jdenticon\\Rendering\\SvgPath' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/SvgPath.php',
|
||||
'Jdenticon\\Rendering\\SvgRenderer' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/SvgRenderer.php',
|
||||
'Jdenticon\\Rendering\\Transform' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/Transform.php',
|
||||
'Jdenticon\\Rendering\\TriangleDirection' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/TriangleDirection.php',
|
||||
'Jdenticon\\Shapes\\Shape' => $vendorDir . '/jdenticon/jdenticon/src/Shapes/Shape.php',
|
||||
'Jdenticon\\Shapes\\ShapeCategory' => $vendorDir . '/jdenticon/jdenticon/src/Shapes/ShapeCategory.php',
|
||||
'Jdenticon\\Shapes\\ShapeDefinitions' => $vendorDir . '/jdenticon/jdenticon/src/Shapes/ShapeDefinitions.php',
|
||||
'Jdenticon\\Shapes\\ShapePosition' => $vendorDir . '/jdenticon/jdenticon/src/Shapes/ShapePosition.php',
|
||||
'PrivateBin\\Configuration' => $baseDir . '/lib/Configuration.php',
|
||||
'PrivateBin\\Controller' => $baseDir . '/lib/Controller.php',
|
||||
'PrivateBin\\Data\\AbstractData' => $baseDir . '/lib/Data/AbstractData.php',
|
||||
'PrivateBin\\Data\\Database' => $baseDir . '/lib/Data/Database.php',
|
||||
'PrivateBin\\Data\\Filesystem' => $baseDir . '/lib/Data/Filesystem.php',
|
||||
'PrivateBin\\Data\\GoogleCloudStorage' => $baseDir . '/lib/Data/GoogleCloudStorage.php',
|
||||
'PrivateBin\\Data\\S3Storage' => $baseDir . '/lib/Data/S3Storage.php',
|
||||
'PrivateBin\\Filter' => $baseDir . '/lib/Filter.php',
|
||||
'PrivateBin\\FormatV2' => $baseDir . '/lib/FormatV2.php',
|
||||
'PrivateBin\\I18n' => $baseDir . '/lib/I18n.php',
|
||||
@@ -49,4 +87,5 @@ return array(
|
||||
'PrivateBin\\Request' => $baseDir . '/lib/Request.php',
|
||||
'PrivateBin\\View' => $baseDir . '/lib/View.php',
|
||||
'PrivateBin\\Vizhash16x16' => $baseDir . '/lib/Vizhash16x16.php',
|
||||
'PrivateBin\\YourlsProxy' => $baseDir . '/lib/YourlsProxy.php',
|
||||
);
|
||||
|
||||
1
vendor/composer/autoload_psr4.php
vendored
1
vendor/composer/autoload_psr4.php
vendored
@@ -7,6 +7,7 @@ $baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'PrivateBin\\' => array($baseDir . '/lib'),
|
||||
'Jdenticon\\' => array($vendorDir . '/jdenticon/jdenticon/src'),
|
||||
'Identicon\\' => array($vendorDir . '/yzalis/identicon/src/Identicon'),
|
||||
'IPLib\\' => array($vendorDir . '/mlocati/ip-lib/src'),
|
||||
);
|
||||
|
||||
15
vendor/composer/autoload_real.php
vendored
15
vendor/composer/autoload_real.php
vendored
@@ -22,13 +22,15 @@ class ComposerAutoloaderInitDontChange
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
require __DIR__ . '/platform_check.php';
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInitDontChange', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInitDontChange', 'loadClassLoader'));
|
||||
|
||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||
if ($useStaticLoader) {
|
||||
require_once __DIR__ . '/autoload_static.php';
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInitDontChange::getInitializer($loader));
|
||||
} else {
|
||||
@@ -63,11 +65,16 @@ class ComposerAutoloaderInitDontChange
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileIdentifier
|
||||
* @param string $file
|
||||
* @return void
|
||||
*/
|
||||
function composerRequireDontChange($fileIdentifier, $file)
|
||||
{
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
require $file;
|
||||
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
|
||||
require $file;
|
||||
}
|
||||
}
|
||||
|
||||
47
vendor/composer/autoload_static.php
vendored
47
vendor/composer/autoload_static.php
vendored
@@ -15,6 +15,10 @@ class ComposerStaticInitDontChange
|
||||
array (
|
||||
'PrivateBin\\' => 11,
|
||||
),
|
||||
'J' =>
|
||||
array (
|
||||
'Jdenticon\\' => 10,
|
||||
),
|
||||
'I' =>
|
||||
array (
|
||||
'Identicon\\' => 10,
|
||||
@@ -27,6 +31,10 @@ class ComposerStaticInitDontChange
|
||||
array (
|
||||
0 => __DIR__ . '/../..' . '/lib',
|
||||
),
|
||||
'Jdenticon\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/jdenticon/jdenticon/src',
|
||||
),
|
||||
'Identicon\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon',
|
||||
@@ -38,6 +46,7 @@ class ComposerStaticInitDontChange
|
||||
);
|
||||
|
||||
public static $classMap = array (
|
||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||
'IPLib\\Address\\AddressInterface' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/AddressInterface.php',
|
||||
'IPLib\\Address\\AssignedRange' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/AssignedRange.php',
|
||||
'IPLib\\Address\\IPv4' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/IPv4.php',
|
||||
@@ -60,12 +69,49 @@ class ComposerStaticInitDontChange
|
||||
'Identicon\\Generator\\ImageMagickGenerator' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/ImageMagickGenerator.php',
|
||||
'Identicon\\Generator\\SvgGenerator' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/SvgGenerator.php',
|
||||
'Identicon\\Identicon' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Identicon.php',
|
||||
'Jdenticon\\Canvas\\Canvas' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Canvas.php',
|
||||
'Jdenticon\\Canvas\\CanvasContext' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/CanvasContext.php',
|
||||
'Jdenticon\\Canvas\\ColorUtils' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/ColorUtils.php',
|
||||
'Jdenticon\\Canvas\\Matrix' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Matrix.php',
|
||||
'Jdenticon\\Canvas\\Png\\PngBuffer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Png/PngBuffer.php',
|
||||
'Jdenticon\\Canvas\\Png\\PngEncoder' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Png/PngEncoder.php',
|
||||
'Jdenticon\\Canvas\\Png\\PngPalette' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Png/PngPalette.php',
|
||||
'Jdenticon\\Canvas\\Point' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Point.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\Edge' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/Edge.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\EdgeIntersection' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeIntersection.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\EdgeSuperSampleIntersection' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeSuperSampleIntersection.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\EdgeTable' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeTable.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\Layer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/Layer.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\LayerManager' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/LayerManager.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\Rasterizer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/Rasterizer.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\SuperSampleBuffer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleBuffer.php',
|
||||
'Jdenticon\\Canvas\\Rasterization\\SuperSampleRange' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleRange.php',
|
||||
'Jdenticon\\Color' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Color.php',
|
||||
'Jdenticon\\Identicon' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Identicon.php',
|
||||
'Jdenticon\\IdenticonStyle' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/IdenticonStyle.php',
|
||||
'Jdenticon\\Rendering\\AbstractRenderer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/AbstractRenderer.php',
|
||||
'Jdenticon\\Rendering\\ColorTheme' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/ColorTheme.php',
|
||||
'Jdenticon\\Rendering\\IconGenerator' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/IconGenerator.php',
|
||||
'Jdenticon\\Rendering\\ImagickRenderer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php',
|
||||
'Jdenticon\\Rendering\\InternalPngRenderer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/InternalPngRenderer.php',
|
||||
'Jdenticon\\Rendering\\Point' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/Point.php',
|
||||
'Jdenticon\\Rendering\\Rectangle' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/Rectangle.php',
|
||||
'Jdenticon\\Rendering\\RendererInterface' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/RendererInterface.php',
|
||||
'Jdenticon\\Rendering\\SvgPath' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/SvgPath.php',
|
||||
'Jdenticon\\Rendering\\SvgRenderer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/SvgRenderer.php',
|
||||
'Jdenticon\\Rendering\\Transform' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/Transform.php',
|
||||
'Jdenticon\\Rendering\\TriangleDirection' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/TriangleDirection.php',
|
||||
'Jdenticon\\Shapes\\Shape' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Shapes/Shape.php',
|
||||
'Jdenticon\\Shapes\\ShapeCategory' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Shapes/ShapeCategory.php',
|
||||
'Jdenticon\\Shapes\\ShapeDefinitions' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Shapes/ShapeDefinitions.php',
|
||||
'Jdenticon\\Shapes\\ShapePosition' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Shapes/ShapePosition.php',
|
||||
'PrivateBin\\Configuration' => __DIR__ . '/../..' . '/lib/Configuration.php',
|
||||
'PrivateBin\\Controller' => __DIR__ . '/../..' . '/lib/Controller.php',
|
||||
'PrivateBin\\Data\\AbstractData' => __DIR__ . '/../..' . '/lib/Data/AbstractData.php',
|
||||
'PrivateBin\\Data\\Database' => __DIR__ . '/../..' . '/lib/Data/Database.php',
|
||||
'PrivateBin\\Data\\Filesystem' => __DIR__ . '/../..' . '/lib/Data/Filesystem.php',
|
||||
'PrivateBin\\Data\\GoogleCloudStorage' => __DIR__ . '/../..' . '/lib/Data/GoogleCloudStorage.php',
|
||||
'PrivateBin\\Data\\S3Storage' => __DIR__ . '/../..' . '/lib/Data/S3Storage.php',
|
||||
'PrivateBin\\Filter' => __DIR__ . '/../..' . '/lib/Filter.php',
|
||||
'PrivateBin\\FormatV2' => __DIR__ . '/../..' . '/lib/FormatV2.php',
|
||||
'PrivateBin\\I18n' => __DIR__ . '/../..' . '/lib/I18n.php',
|
||||
@@ -81,6 +127,7 @@ class ComposerStaticInitDontChange
|
||||
'PrivateBin\\Request' => __DIR__ . '/../..' . '/lib/Request.php',
|
||||
'PrivateBin\\View' => __DIR__ . '/../..' . '/lib/View.php',
|
||||
'PrivateBin\\Vizhash16x16' => __DIR__ . '/../..' . '/lib/Vizhash16x16.php',
|
||||
'PrivateBin\\YourlsProxy' => __DIR__ . '/../..' . '/lib/YourlsProxy.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
|
||||
59
vendor/composer/installed.php
vendored
Normal file
59
vendor/composer/installed.php
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php return array(
|
||||
'root' => array(
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'reference' => '78aa70e3ab9277172489f9d88f8fd08cc1d03c97',
|
||||
'name' => 'privatebin/privatebin',
|
||||
'dev' => false,
|
||||
),
|
||||
'versions' => array(
|
||||
'jdenticon/jdenticon' => array(
|
||||
'pretty_version' => '1.0.1',
|
||||
'version' => '1.0.1.0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../jdenticon/jdenticon',
|
||||
'aliases' => array(),
|
||||
'reference' => '994ee07293fb978f983393ffcb2c0250592a6ac4',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'mlocati/ip-lib' => array(
|
||||
'pretty_version' => '1.18.0',
|
||||
'version' => '1.18.0.0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../mlocati/ip-lib',
|
||||
'aliases' => array(),
|
||||
'reference' => 'c77bd0b1f3e3956c7e9661e75cb1f54ed67d95d2',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'paragonie/random_compat' => array(
|
||||
'pretty_version' => 'v2.0.21',
|
||||
'version' => '2.0.21.0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../paragonie/random_compat',
|
||||
'aliases' => array(),
|
||||
'reference' => '96c132c7f2f7bc3230723b66e89f8f150b29d5ae',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'privatebin/privatebin' => array(
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'reference' => '78aa70e3ab9277172489f9d88f8fd08cc1d03c97',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'yzalis/identicon' => array(
|
||||
'pretty_version' => '2.0.0',
|
||||
'version' => '2.0.0.0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../yzalis/identicon',
|
||||
'aliases' => array(),
|
||||
'reference' => 'ff5ed090129cab9bfa2a322857d4a01d107aa0ae',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
),
|
||||
);
|
||||
26
vendor/composer/platform_check.php
vendored
Normal file
26
vendor/composer/platform_check.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
// platform_check.php @generated by Composer
|
||||
|
||||
$issues = array();
|
||||
|
||||
if (!(PHP_VERSION_ID >= 50600)) {
|
||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 5.6.0". You are running ' . PHP_VERSION . '.';
|
||||
}
|
||||
|
||||
if ($issues) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||
} elseif (!headers_sent()) {
|
||||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
130
vendor/jdenticon/jdenticon/src/Canvas/Canvas.php
vendored
Normal file
130
vendor/jdenticon/jdenticon/src/Canvas/Canvas.php
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Canvas;
|
||||
|
||||
use Jdenticon\Canvas\Rasterization\Edge;
|
||||
use Jdenticon\Canvas\Rasterization\EdgeTable;
|
||||
use Jdenticon\Canvas\Rasterization\Rasterizer;
|
||||
use Jdenticon\Canvas\Png\PngPalette;
|
||||
use Jdenticon\Canvas\Png\PngEncoder;
|
||||
use Jdenticon\Canvas\CanvasContext;
|
||||
use Jdenticon\Canvas\ColorUtils;
|
||||
|
||||
class Canvas
|
||||
{
|
||||
private $edges;
|
||||
|
||||
/**
|
||||
* Creates a new canvas with the specified dimensions given in pixels.
|
||||
*
|
||||
* @param integer $width Canvas width in pixels.
|
||||
* @param integer $height Canvas height in pixels.
|
||||
*/
|
||||
public function __construct($width, $height)
|
||||
{
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
$this->edges = new EdgeTable($width, $height);
|
||||
}
|
||||
|
||||
/**
|
||||
* The width of the canvas in pixels.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $width = 0;
|
||||
|
||||
/**
|
||||
* The height of the canvas in pixels.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $height = 0;
|
||||
|
||||
/**
|
||||
* Specifies the background color. Allowed values are:
|
||||
* - 32 bit integers on the format 0xRRGGBBAA
|
||||
* - strings on the format #RGB
|
||||
* - strings on the format #RRGGBB
|
||||
* - strings on the format #RRGGBBAA
|
||||
*
|
||||
* @var integer|string
|
||||
*/
|
||||
public $backColor = 0x00000000;
|
||||
|
||||
/**
|
||||
* Gets a context used to draw polygons on this canvas.
|
||||
*
|
||||
* @returns \Jdenticon\Canvas\CanvasContext
|
||||
*/
|
||||
public function getContext()
|
||||
{
|
||||
return new CanvasContext($this, $this->edges);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the canvas as a PNG data stream.
|
||||
*
|
||||
* @param array $keywords Keywords to be written to the PNG stream.
|
||||
* See https://www.w3.org/TR/PNG/#11keywords.
|
||||
* @returns string
|
||||
*/
|
||||
public function toPng($keywords = array())
|
||||
{
|
||||
$colorRanges = array();
|
||||
|
||||
Rasterizer::rasterize(
|
||||
$colorRanges, $this->edges,
|
||||
$this->width, $this->height);
|
||||
|
||||
$backColor = ColorUtils::parse($this->backColor);
|
||||
if (ColorUtils::alpha($backColor) > 0) {
|
||||
$isColor = false;
|
||||
|
||||
foreach ($colorRanges as & $value) {
|
||||
if ($isColor) {
|
||||
$value = ColorUtils::over($value, $backColor);
|
||||
$isColor = false;
|
||||
} else {
|
||||
$isColor = true;
|
||||
}
|
||||
}
|
||||
|
||||
unset($value);
|
||||
}
|
||||
|
||||
$palette = new PngPalette($colorRanges);
|
||||
$png = new PngEncoder();
|
||||
|
||||
$png->writeImageHeader($this->width, $this->height, $palette->isValid ?
|
||||
PngEncoder::INDEXED_COLOR : PngEncoder::TRUE_COLOR_WITH_ALPHA);
|
||||
|
||||
$png->writeImageGamma();
|
||||
|
||||
foreach ($keywords as $key => $value) {
|
||||
$png->writeTextualData($key, $value);
|
||||
}
|
||||
|
||||
if ($palette && $palette->isValid) {
|
||||
$png->writePalette($palette);
|
||||
$png->writeTransparency($palette);
|
||||
$png->writeIndexed($colorRanges, $palette,
|
||||
$this->width, $this->height);
|
||||
} else {
|
||||
$png->writeTrueColorWithAlpha($colorRanges,
|
||||
$this->width, $this->height);
|
||||
}
|
||||
|
||||
$png->writeImageEnd();
|
||||
return $png->getBuffer();
|
||||
}
|
||||
}
|
||||
408
vendor/jdenticon/jdenticon/src/Canvas/CanvasContext.php
vendored
Normal file
408
vendor/jdenticon/jdenticon/src/Canvas/CanvasContext.php
vendored
Normal file
@@ -0,0 +1,408 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Canvas;
|
||||
|
||||
use Jdenticon\Canvas\ColorUtils;
|
||||
use Jdenticon\Canvas\CanvasState;
|
||||
use Jdenticon\Canvas\Rasterization\EdgeTable;
|
||||
use Jdenticon\Canvas\Rasterization\Edge;
|
||||
use Jdenticon\Canvas\Matrix;
|
||||
|
||||
class CanvasContext
|
||||
{
|
||||
private $savedStates = array();
|
||||
private $edges;
|
||||
private $transform;
|
||||
private $paths;
|
||||
private $canvas;
|
||||
|
||||
/**
|
||||
* Creates a new canvas with the specified dimensions given in pixels.
|
||||
*
|
||||
* @param \Jdenticon\Canvas\Canvas $canvas The owner canvas.
|
||||
* @param array $edges The owner canvas' edge buffer.
|
||||
*/
|
||||
public function __construct($canvas, &$edges)
|
||||
{
|
||||
$this->edges = $edges;
|
||||
$this->canvas = $canvas;
|
||||
$this->beginPath();
|
||||
$this->resetTransform();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the fill color that is used when the fill method is called. Allowed values are:
|
||||
* - 32 bit integers on the format 0xRRGGBBAA
|
||||
* - strings on the format #RGB
|
||||
* - strings on the format #RRGGBB
|
||||
* - strings on the format #RRGGBBAA
|
||||
*
|
||||
* @var integer|string
|
||||
*/
|
||||
public $fillStyle = 0x000000ff;
|
||||
|
||||
/**
|
||||
* Saves the current state to the state stack.
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
array_push($this->savedStates, array(
|
||||
'transform' => $this->transform,
|
||||
'fillStyle' => $this->fillStyle
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the last saved state of the CanvasContext.
|
||||
*/
|
||||
public function restore()
|
||||
{
|
||||
$state = array_pop($this->savedStates);
|
||||
if ($state != NULL) {
|
||||
$this->transform = $state['transform'];
|
||||
$this->fillStyle = $state['fillStyle'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the internal path buffer and begins a new path.
|
||||
*/
|
||||
public function resetTransform()
|
||||
{
|
||||
$this->transform = new Matrix(1, 0, 0, 1, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies the current transformation matrix with the specified values.
|
||||
*/
|
||||
public function transform($a, $b, $c, $d, $e, $f)
|
||||
{
|
||||
if (gettype($a) != 'integer' ||
|
||||
gettype($b) != 'integer' ||
|
||||
gettype($c) != 'integer' ||
|
||||
gettype($d) != 'integer' ||
|
||||
gettype($e) != 'integer' ||
|
||||
gettype($f) != 'integer'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->transform = $this->transform->multiply($a, $b, $c, $d, $e, $f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the transformation matrix to the specified matrix.
|
||||
*/
|
||||
public function setTransform($a, $b, $c, $d, $e, $f)
|
||||
{
|
||||
if (gettype($a) != 'integer' ||
|
||||
gettype($b) != 'integer' ||
|
||||
gettype($c) != 'integer' ||
|
||||
gettype($d) != 'integer' ||
|
||||
gettype($e) != 'integer' ||
|
||||
gettype($f) != 'integer'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->transform = new Matrix($a, $b, $c, $d, $e, $f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a translation transformation to the CanvasContext.
|
||||
*
|
||||
* @param float $x Distance to move in the horizontal direction in pixels.
|
||||
* @param float $y Distance to move in the vertical direction in pixels.
|
||||
*/
|
||||
public function translate($x, $y)
|
||||
{
|
||||
$this->transform = $this->transform->translate($x, $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a scale transformation to the CanvasContext.
|
||||
*
|
||||
* @param float $x Scale in the horizontal direction. 1 means no scale.
|
||||
* @param float $y Scale in the vertical direction. 1 means no scale.
|
||||
*/
|
||||
public function scale($x, $y)
|
||||
{
|
||||
$this->transform = $this->transform->scale($x, $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a rotation transformation to the canvas around its current origo.
|
||||
*
|
||||
* @param float $angle Angle in radians measured clockwise from the
|
||||
* positive x axis.
|
||||
*/
|
||||
public function rotate($angle)
|
||||
{
|
||||
$this->transform = $this->transform->rotate($angle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all existing subpaths and begins a new path.
|
||||
*/
|
||||
public function beginPath()
|
||||
{
|
||||
$this->paths = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new subpath that begins in the same point as the start and end
|
||||
* point of the previous one.
|
||||
*/
|
||||
public function closePath()
|
||||
{
|
||||
$pathsCount = count($this->paths);
|
||||
if ($pathsCount > 0) {
|
||||
$path = $this->paths[$pathsCount - 1];
|
||||
$pathCount = count($path);
|
||||
|
||||
if ($pathCount > 2) {
|
||||
// Close path
|
||||
if ($path[0] != $path[$pathCount - 2] ||
|
||||
$path[1] != $path[$pathCount - 1]
|
||||
) {
|
||||
$path[] = $path[0];
|
||||
$path[] = $path[1];
|
||||
}
|
||||
|
||||
// Begin a new path
|
||||
$this->paths[] = array($path[0], $path[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins a new subpath by moving the cursor to the specified position.
|
||||
*
|
||||
* @param float $x X coordinate.
|
||||
* @param float $y Y coordinate.
|
||||
*/
|
||||
public function moveTo($x, $y)
|
||||
{
|
||||
$p = $this->transform->multiplyPoint($x, $y);
|
||||
$this->paths[] = array($p->x, $p->y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an edge between the last and specified position.
|
||||
*
|
||||
* @param float $x Target X coordinate.
|
||||
* @param float $y Target Y coordinate.
|
||||
* @public
|
||||
*/
|
||||
public function lineTo($x, $y)
|
||||
{
|
||||
$pathsCount = count($this->paths);
|
||||
if ($pathsCount == 0) {
|
||||
$this->paths[] = array();
|
||||
$pathsCount++;
|
||||
}
|
||||
|
||||
$p = $this->transform->multiplyPoint($x, $y);
|
||||
$path = &$this->paths[$pathsCount - 1];
|
||||
$path[] = $p->x;
|
||||
$path[] = $p->y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an arc to the current path.
|
||||
*
|
||||
* @param float $x X coordinate of the center of the arc.
|
||||
* @param float $y Y coordinate of the center of the arc.
|
||||
* @param float $radius Radius of the arc.
|
||||
* @param float $startAngle The angle in radians at which the arc starts,
|
||||
* measured clockwise from the positive x axis.
|
||||
* @param float $endAngle The angle in radians at which the arc end,
|
||||
* measured clockwise from the positive x axis.
|
||||
* @param boolean $anticlockwise Specifies whether the arc will be drawn
|
||||
* counter clockwise. Default is clockwise.
|
||||
*/
|
||||
public function arc($x, $y, $radius, $startAngle, $endAngle, $anticlockwise)
|
||||
{
|
||||
$TARGET_CHORD_LENGTH_PIXELS = 3;
|
||||
|
||||
$sectors = floor((M_PI * $radius * 2) / $TARGET_CHORD_LENGTH_PIXELS);
|
||||
if ($sectors < 9) {
|
||||
$sectors = 9;
|
||||
}
|
||||
|
||||
$sectorAngle = M_PI * 2 / $sectors;
|
||||
|
||||
if ($startAngle == $endAngle) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($anticlockwise) {
|
||||
$sectorAngle = -$sectorAngle;
|
||||
|
||||
if ($startAngle - $endAngle >= M_PI * 2) {
|
||||
$endAngle = $startAngle - M_PI * 2;
|
||||
} else {
|
||||
// Normalize end angle so that the sweep angle is in the range
|
||||
// (0, -2PI]
|
||||
$endAngle +=
|
||||
M_PI * 2 * ceil(($startAngle - $endAngle) /
|
||||
(M_PI * 2) - 1);
|
||||
}
|
||||
} else {
|
||||
if ($endAngle - $startAngle >= M_PI * 2) {
|
||||
$endAngle = $startAngle + M_PI * 2;
|
||||
} else {
|
||||
// Normalize end angle so that the sweep angle is in the range
|
||||
// (0, 2PI]
|
||||
$endAngle -=
|
||||
M_PI * 2 * ceil(($endAngle - $startAngle) /
|
||||
(M_PI * 2) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
$dx;
|
||||
$dy;
|
||||
$sectors = ($endAngle - $startAngle) / $sectorAngle;
|
||||
|
||||
$angle = $startAngle;
|
||||
|
||||
for ($i = 0; $i < $sectors; $i++) {
|
||||
$dx = cos($angle) * $radius;
|
||||
$dy = sin($angle) * $radius;
|
||||
$this->lineTo($x + $dx, $y + $dy);
|
||||
$angle += $sectorAngle;
|
||||
}
|
||||
|
||||
$dx = cos($endAngle) * $radius;
|
||||
$dy = sin($endAngle) * $radius;
|
||||
$this->lineTo($x + $dx, $y + $dy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the specified rectangle with fully transparent black without
|
||||
* affecting the current paths.
|
||||
*
|
||||
* @param float $x X coordinate of the left side of the rectangle.
|
||||
* @param float $y Y coordinate of the top of the rectangle.
|
||||
* @param float $width Width of the rectangle.
|
||||
* @param float $height Height of the rectangle.
|
||||
*/
|
||||
public function clearRect($x, $y, $width, $height)
|
||||
{
|
||||
$fullCanvas = false;
|
||||
|
||||
if (!$this->transform->hasSkewing()) {
|
||||
// Check if the whole canvas is cleared
|
||||
$topLeft = $this->transform->multiplyPoint($x, $y);
|
||||
if ($topLeft->x <= 0 && $topLeft->y <= 0) {
|
||||
$bottomRight = $this->transform->multiplyPoint(
|
||||
$x + $width, $y + $height);
|
||||
if ($bottomRight->x >= $this->canvas->width &&
|
||||
$bottomRight->y >= $this->canvas->height
|
||||
) {
|
||||
$fullCanvas = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($fullCanvas) {
|
||||
$this->edges->clear();
|
||||
} else {
|
||||
$this->_fillRect(ColorUtils::FORCE_TRANSPARENT,
|
||||
$x, $y, $width, $height);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the specified rectangle without affecting the current paths.
|
||||
*
|
||||
* @param float $x X coordinate of the left side of the rectangle.
|
||||
* @param float $y Y coordinate of the top of the rectangle.
|
||||
* @param float $width Width of the rectangle.
|
||||
* @param float $height Height of the rectangle.
|
||||
*/
|
||||
public function fillRect($x, $y, $width, $height)
|
||||
{
|
||||
$fillColor = ColorUtils::parse($this->fillStyle);
|
||||
$this->_fillRect($fillColor, $x, $y, $width, $height);
|
||||
}
|
||||
|
||||
private function _fillRect($fillColor, $x, $y, $width, $height)
|
||||
{
|
||||
$polygonId = $this->edges->getNextPolygonId();
|
||||
|
||||
$points = array(
|
||||
$this->transform->multiplyPoint($x, $y),
|
||||
$this->transform->multiplyPoint($x + $width, $y),
|
||||
$this->transform->multiplyPoint($x + $width, $y + $height),
|
||||
$this->transform->multiplyPoint($x, $y + $height),
|
||||
$this->transform->multiplyPoint($x, $y)
|
||||
);
|
||||
|
||||
$pointsCount = count($points);
|
||||
for ($i = 1; $i < $pointsCount; $i++) {
|
||||
$this->edges->add(new Edge(
|
||||
$polygonId,
|
||||
$points[$i - 1]->x,
|
||||
$points[$i - 1]->y,
|
||||
$points[$i]->x,
|
||||
$points[$i]->y,
|
||||
$fillColor));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the defined paths.
|
||||
*
|
||||
* @param string $windingRule The winding rule to be used for determining
|
||||
* which areas are covered by the current path. Valid values are
|
||||
* "evenodd" and "nonzero". Default is "nonzero".
|
||||
*/
|
||||
public function fill($windingRule = "nonzero")
|
||||
{
|
||||
$polygonId = $this->edges->getNextPolygonId();
|
||||
$fillColor = ColorUtils::parse($this->fillStyle);
|
||||
|
||||
foreach ($this->paths as $points) {
|
||||
$pointsCount = count($points);
|
||||
if ($pointsCount <= 2) {
|
||||
// Nothing to fill
|
||||
continue;
|
||||
}
|
||||
|
||||
for ($i = 2; $i < $pointsCount; $i += 2) {
|
||||
$this->edges->add(new Edge(
|
||||
$polygonId,
|
||||
$points[$i - 2],
|
||||
$points[$i - 1],
|
||||
$points[$i],
|
||||
$points[$i + 1],
|
||||
$fillColor,
|
||||
$windingRule));
|
||||
}
|
||||
|
||||
// Close path
|
||||
if ($points[0] != $points[$pointsCount - 2] ||
|
||||
$points[1] != $points[$pointsCount - 1]
|
||||
) {
|
||||
$this->edges->add(new Edge(
|
||||
$polygonId,
|
||||
$points[$pointsCount - 2],
|
||||
$points[$pointsCount - 1],
|
||||
$points[0],
|
||||
$points[1],
|
||||
$fillColor,
|
||||
$windingRule));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
228
vendor/jdenticon/jdenticon/src/Canvas/ColorUtils.php
vendored
Normal file
228
vendor/jdenticon/jdenticon/src/Canvas/ColorUtils.php
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Canvas;
|
||||
|
||||
class ColorUtils
|
||||
{
|
||||
/**
|
||||
* Transparent color.
|
||||
* @var integer
|
||||
*/
|
||||
const TRANSPARENT = 0;
|
||||
|
||||
/**
|
||||
* Specifies a transparent color that will not blend with layers below the
|
||||
* current layer.
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
const FORCE_TRANSPARENT = INF;
|
||||
|
||||
/**
|
||||
* Creates a color on the format 0xRRGGBBAA from the specified
|
||||
* color components.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public static function from($a, $r, $g, $b)
|
||||
{
|
||||
return ($r << 24) | ($g << 16) | ($b << 8) | $a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the alpha component of a color.
|
||||
*
|
||||
* @param integer $color 32-bit color value on the format 0xRRGGBBAA.
|
||||
* @return integer Alpha in the range [0, 255].
|
||||
*/
|
||||
public static function alpha($color)
|
||||
{
|
||||
return $color & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the red component of a color.
|
||||
*
|
||||
* @param integer $color 32-bit color value on the format 0xRRGGBBAA.
|
||||
* @return integer Red component in the range [0, 255].
|
||||
*/
|
||||
public static function red($color)
|
||||
{
|
||||
return ($color >> 24) & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the green component of a color.
|
||||
*
|
||||
* @param integer $color 32-bit color value on the format 0xRRGGBBAA.
|
||||
* @return integer Green component in the range [0, 255].
|
||||
*/
|
||||
public static function green($color)
|
||||
{
|
||||
return ($color >> 16) & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the blue component of a color.
|
||||
*
|
||||
* @param integer $color 32-bit color value on the format 0xRRGGBBAA.
|
||||
* @return integer Blue component in the range [0, 255].
|
||||
*/
|
||||
public static function blue($color)
|
||||
{
|
||||
return ($color >> 8) & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a color as a string.
|
||||
*
|
||||
* @param integer $color Color to format.
|
||||
* @return string
|
||||
*/
|
||||
public static function format($color)
|
||||
{
|
||||
return bin2hex(pack('N', $color));
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a mix of the two specified colors, with the proportion given
|
||||
* by the specified weight.
|
||||
*
|
||||
* @param integer $color1 First color to mix.
|
||||
* @param integer $color2 Second color to mix.
|
||||
* @param float $weight Weight in the range [0,1].
|
||||
* 0 gives $color1, 1 gives $color2.
|
||||
* @return integer Mixed color.
|
||||
*/
|
||||
public static function mix($color1, $color2, $weight)
|
||||
{
|
||||
if ($weight < 0) {
|
||||
$weight = 0;
|
||||
} elseif ($weight > 1) {
|
||||
$weight = 1;
|
||||
}
|
||||
|
||||
$a = ($color1 & 0xff) * (1 - $weight) + ($color2 & 0xff) * $weight;
|
||||
if ($a <= 0.1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$r = (
|
||||
($color1 >> 24) * ($color1 & 0xff) * (1 - $weight) +
|
||||
($color2 >> 24) * ($color2 & 0xff) * $weight
|
||||
) / $a;
|
||||
|
||||
$g = (
|
||||
(($color1 >> 16) & 0xff) * ($color1 & 0xff) * (1 - $weight) +
|
||||
(($color2 >> 16) & 0xff) * ($color2 & 0xff) * $weight
|
||||
) / $a;
|
||||
|
||||
$b = (
|
||||
(($color1 >> 8) & 0xff) * ($color1 & 0xff) * (1 - $weight) +
|
||||
(($color2 >> 8) & 0xff) * ($color2 & 0xff) * $weight
|
||||
) / $a;
|
||||
|
||||
if ($a > 255) $a = 255;
|
||||
if ($r > 255) $r = 255;
|
||||
if ($g > 255) $g = 255;
|
||||
if ($b > 255) $b = 255;
|
||||
|
||||
return ((int)$r << 24) | ((int)$g << 16) | ((int)$b << 8) | (int)$a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a value to a 32-bit color on the format 0xRRGGBBAA.
|
||||
*
|
||||
* @param integer|string $color The value to parse.
|
||||
* @return integer
|
||||
*/
|
||||
public static function parse($color)
|
||||
{
|
||||
if (gettype($color) == "integer") {
|
||||
return $color & 0xffffffff;
|
||||
}
|
||||
|
||||
$color = "$color";
|
||||
|
||||
if (preg_match('/^#?[0-9a-fA-F]+$/', $color)) {
|
||||
$hexColor = $color;
|
||||
if ($hexColor[0] == '#') {
|
||||
$hexColor = substr($hexColor, 1);
|
||||
}
|
||||
|
||||
switch (strlen($hexColor)) {
|
||||
case 3:
|
||||
$numeric = intval($hexColor, 16);
|
||||
return (
|
||||
(($numeric & 0xf00) << 20) |
|
||||
(($numeric & 0xf00) << 16) |
|
||||
(($numeric & 0x0f0) << 16) |
|
||||
(($numeric & 0x0f0) << 12) |
|
||||
(($numeric & 0x00f) << 12) |
|
||||
(($numeric & 0x00f) << 8) |
|
||||
0xff);
|
||||
case 6:
|
||||
return (intval($hexColor, 16) << 8) | 0xff;
|
||||
case 8:
|
||||
// Workaround to cope with PHP limitation of intval
|
||||
$numeric =
|
||||
(intval(substr($hexColor, 0, 4), 16) << 16) |
|
||||
(intval(substr($hexColor, 4, 4), 16));
|
||||
return $numeric;
|
||||
}
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException("Invalid color '$color'.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Blends this color with another color using the over blending operation.
|
||||
*
|
||||
* @param integer $fore The foreground color.
|
||||
* @param integer $back The background color.
|
||||
* @return integer
|
||||
*/
|
||||
public static function over($fore, $back)
|
||||
{
|
||||
$foreA = ($fore & 0xff);
|
||||
$backA = ($back & 0xff);
|
||||
|
||||
if ($foreA < 1) {
|
||||
return $back;
|
||||
} elseif ($foreA > 254 || $backA < 1) {
|
||||
return $fore;
|
||||
}
|
||||
|
||||
// Source:
|
||||
// https://en.wikipedia.org/wiki/Alpha_compositing#Description
|
||||
$forePA = $foreA * 255;
|
||||
$backPA = $backA * (255 - $foreA);
|
||||
$pa = ($forePA + $backPA);
|
||||
|
||||
$b = (int) (
|
||||
($forePA * (($fore >> 8) & 0xff) + $backPA * (($back >> 8) & 0xff)) /
|
||||
$pa);
|
||||
|
||||
$g = (int) (
|
||||
($forePA * (($fore >> 16) & 0xff) + $backPA * (($back >> 16) & 0xff)) /
|
||||
$pa);
|
||||
|
||||
$r = (int) (
|
||||
($forePA * (($fore >> 24) & 0xff) + $backPA * (($back >> 24) & 0xff)) /
|
||||
$pa);
|
||||
|
||||
$a = (int) ($pa / 255);
|
||||
|
||||
return ($r << 24) | ($g << 16) | ($b << 8) | $a;
|
||||
}
|
||||
};
|
||||
|
||||
141
vendor/jdenticon/jdenticon/src/Canvas/Matrix.php
vendored
Normal file
141
vendor/jdenticon/jdenticon/src/Canvas/Matrix.php
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Canvas;
|
||||
|
||||
use Jdenticon\Canvas\Point;
|
||||
|
||||
class Matrix
|
||||
{
|
||||
private $a;
|
||||
private $b;
|
||||
private $c;
|
||||
private $d;
|
||||
private $e;
|
||||
private $f;
|
||||
|
||||
/**
|
||||
* Creates a new transformation matrix.
|
||||
*/
|
||||
public function __construct($a, $b, $c, $d, $e, $f)
|
||||
{
|
||||
$this->a = $a;
|
||||
$this->b = $b;
|
||||
$this->c = $c;
|
||||
$this->d = $d;
|
||||
$this->e = $e;
|
||||
$this->f = $f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value determining if this matrix has skewing values.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasSkewing()
|
||||
{
|
||||
return $this->b || $this->c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value determining if this matrix has translation values.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasTranslation()
|
||||
{
|
||||
return $this->e || $this->f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value determining if this matrix has scaling values.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasScaling()
|
||||
{
|
||||
return $this->a != 1 || $this->d != 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new matrix based on the current matrix multiplied with the
|
||||
* specified matrix values.
|
||||
*
|
||||
* @return \Jdenticon\Canvas\Matrix
|
||||
*/
|
||||
public function multiply($a, $b, $c, $d, $e, $f)
|
||||
{
|
||||
return new Matrix(
|
||||
$this->a * $a + $this->c * $b,
|
||||
$this->b * $a + $this->d * $b,
|
||||
$this->a * $c + $this->c * $d,
|
||||
$this->b * $c + $this->d * $d,
|
||||
$this->a * $e + $this->c * $f + $this->e,
|
||||
$this->b * $e + $this->d * $f + $this->f
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies the specified point with the current matrix and returns the
|
||||
* resulting point.
|
||||
*
|
||||
* @param float $x X coordinate.
|
||||
* @param float $y Y coordinate.
|
||||
* @return \Jdenticon\Canvas\Point
|
||||
*/
|
||||
public function multiplyPoint($x, $y)
|
||||
{
|
||||
return new Point(
|
||||
$this->a * $x + $this->c * $y + $this->e,
|
||||
$this->b * $x + $this->d * $y + $this->f
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new matrix based on the current matrix with a rotation
|
||||
* transformation applied.
|
||||
*
|
||||
* @param float $angle Rotation angle in radians.
|
||||
* @return \Jdenticon\Canvas\Matrix
|
||||
*/
|
||||
public function rotate($angle)
|
||||
{
|
||||
$sin = sin($angle);
|
||||
$cos = cos($angle);
|
||||
return $this->multiply($cos, $sin, -$sin, $cos, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new matrix based on the current matrix with a translation
|
||||
* transformation applied.
|
||||
*
|
||||
* @param float $x Horizontal move distance.
|
||||
* @param float $y Vertical move distance.
|
||||
* @return \Jdenticon\Canvas\Matrix
|
||||
*/
|
||||
public function translate($x, $y)
|
||||
{
|
||||
return $this->multiply(1, 0, 0, 1, $x, $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new matrix based on the current matrix with a scaling
|
||||
* transformation applied.
|
||||
*
|
||||
* @param float $x Horizontal scale.
|
||||
* @param float $y Vertical scale.
|
||||
* @return \Jdenticon\Canvas\Matrix
|
||||
*/
|
||||
public function scale($x, $y)
|
||||
{
|
||||
return $this->multiply($x, 0, 0, $y, 0, 0);
|
||||
}
|
||||
}
|
||||
92
vendor/jdenticon/jdenticon/src/Canvas/Png/PngBuffer.php
vendored
Normal file
92
vendor/jdenticon/jdenticon/src/Canvas/Png/PngBuffer.php
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Canvas\Png;
|
||||
|
||||
class PngBuffer
|
||||
{
|
||||
private $buffer = '';
|
||||
private $chunkPreviousBuffer = '';
|
||||
|
||||
/**
|
||||
* Writes a string to the buffer.
|
||||
*
|
||||
* @param string $str String to write.
|
||||
*/
|
||||
public function writeString($str)
|
||||
{
|
||||
$this->buffer .= $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a 32 bit unsigned int to the buffer in Big Endian format.
|
||||
*
|
||||
* @param integer $value Value to write.
|
||||
*/
|
||||
public function writeUInt32BE($value)
|
||||
{
|
||||
$this->buffer .= pack('N', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an 8 bit unsigned int to the buffer.
|
||||
*
|
||||
* @param integer $value Value to write.
|
||||
*/
|
||||
public function writeUInt8($value)
|
||||
{
|
||||
$this->buffer .= pack('C', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new PNG chunk.
|
||||
*
|
||||
* @param string $type Name of the chunk. Must contain exactly 4
|
||||
* ASCII characters.
|
||||
*/
|
||||
public function startChunk($type)
|
||||
{
|
||||
$this->chunkPreviousBuffer = $this->buffer;
|
||||
$this->buffer = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the current PNG chunk.
|
||||
*/
|
||||
public function endChunk()
|
||||
{
|
||||
// Compute Crc32 for type + data
|
||||
$data = $this->buffer;
|
||||
$crc = crc32($data);
|
||||
|
||||
$this->buffer =
|
||||
$this->chunkPreviousBuffer .
|
||||
|
||||
// Length
|
||||
pack('N', strlen($data) - 4) .
|
||||
|
||||
// Content
|
||||
$data .
|
||||
|
||||
// Crc32
|
||||
pack('N', $crc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string containing the PNG encoded data.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBuffer()
|
||||
{
|
||||
return $this->buffer;
|
||||
}
|
||||
}
|
||||
238
vendor/jdenticon/jdenticon/src/Canvas/Png/PngEncoder.php
vendored
Normal file
238
vendor/jdenticon/jdenticon/src/Canvas/Png/PngEncoder.php
vendored
Normal file
@@ -0,0 +1,238 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Canvas\Png;
|
||||
|
||||
use Jdenticon\Canvas\Png\PngPalette;
|
||||
use Jdenticon\Canvas\Png\PngBuffer;
|
||||
use Jdenticon\Canvas\ColorUtils;
|
||||
|
||||
class PngEncoder
|
||||
{
|
||||
const GRAYSCALE = 0;
|
||||
const TRUE_COLOR = 2;
|
||||
const INDEXED_COLOR = 3;
|
||||
const GRAYSCALE_WITH_ALPHA = 4;
|
||||
const TRUE_COLOR_WITH_ALPHA = 6;
|
||||
|
||||
private $buffer;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->buffer = new PngBuffer();
|
||||
$this->buffer->writeString("\x89\x50\x4e\x47\xd\xa\x1a\xa");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an IHDR chunk to the png data stream.
|
||||
*
|
||||
* @param int $width Image width in pixels.
|
||||
* @param int $height Image height in pixels.
|
||||
* @param int $colorType Color depth, speocfy one of the constants in
|
||||
* PngEncoder.
|
||||
*/
|
||||
public function writeImageHeader($width, $height, $colorType)
|
||||
{
|
||||
$this->buffer->startChunk("IHDR");
|
||||
$this->buffer->writeUInt32BE($width);
|
||||
$this->buffer->writeUInt32BE($height);
|
||||
$this->buffer->writeUInt8(8); // Bit depth
|
||||
$this->buffer->writeUInt8($colorType);
|
||||
$this->buffer->writeUInt8(0); // Compression
|
||||
$this->buffer->writeUInt8(0); // Filter
|
||||
$this->buffer->writeUInt8(0); // Interlace
|
||||
$this->buffer->endChunk();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a gAMA chunk to the png data stream.
|
||||
*
|
||||
* @param int $gamma Gamma value.
|
||||
*/
|
||||
public function writeImageGamma($gamma = 45455)
|
||||
{
|
||||
$this->buffer->startChunk("gAMA");
|
||||
$this->buffer->writeUInt32BE($gamma);
|
||||
$this->buffer->endChunk();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an IDAT chunk of truecolor encoded image data.
|
||||
*
|
||||
* @param array $colorRanges Image data on the format
|
||||
* array(count0, color0, count1, color1, ...)
|
||||
* @param int $width Image width in pixels.
|
||||
* @param int $height Image height in pixels.
|
||||
*/
|
||||
public function writeTrueColorWithAlpha(
|
||||
array & $colorRanges, $width, $height)
|
||||
{
|
||||
$this->buffer->startChunk("IDAT");
|
||||
|
||||
$uncompressed = '';
|
||||
$count = -1;
|
||||
$x = 0;
|
||||
|
||||
foreach ($colorRanges as $value) {
|
||||
if ($count === -1) {
|
||||
$count = $value;
|
||||
} else {
|
||||
if ($count !== 0) {
|
||||
if ($x === $width) {
|
||||
$x = 0;
|
||||
}
|
||||
if ($x === 0) {
|
||||
$uncompressed .= pack('C', 0); // No filtering
|
||||
}
|
||||
|
||||
$uncompressed .= str_repeat(pack('N', $value), $count);
|
||||
$x += $count;
|
||||
}
|
||||
|
||||
$count = -1;
|
||||
}
|
||||
}
|
||||
|
||||
$compressed = gzcompress($uncompressed, 2);
|
||||
$this->buffer->writeString($compressed);
|
||||
|
||||
$this->buffer->endChunk();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an IDAT chunk of indexed image data.
|
||||
*
|
||||
* @param array $colorRanges Image data on the format
|
||||
* array(count0, color0, count1, color1, ...)
|
||||
* @param \Jdenticon\Canvas\Png\PngPalette $palette Palette containing the
|
||||
* indexed colors.
|
||||
* @param int $width Image width in pixels.
|
||||
* @param int $height Image height in pixels.
|
||||
*/
|
||||
public function writeIndexed(
|
||||
array & $colorRanges,
|
||||
PngPalette $palette,
|
||||
$width, $height)
|
||||
{
|
||||
$this->buffer->startChunk("IDAT");
|
||||
|
||||
$uncompressed = '';
|
||||
|
||||
$count = -1;
|
||||
$x = 0;
|
||||
|
||||
foreach ($colorRanges as $value) {
|
||||
if ($count === -1) {
|
||||
$count = $value;
|
||||
} else {
|
||||
if ($count !== 0) {
|
||||
if ($x === $width) {
|
||||
$x = 0;
|
||||
}
|
||||
if ($x === 0) {
|
||||
$uncompressed .= pack('C', 0); // No filtering
|
||||
}
|
||||
|
||||
$colorIndex = $palette->lookup[$value];
|
||||
$uncompressed .= str_repeat(pack('C', $colorIndex), $count);
|
||||
$x += $count;
|
||||
}
|
||||
|
||||
$count = -1;
|
||||
}
|
||||
}
|
||||
|
||||
$compressed = gzcompress($uncompressed, 2);
|
||||
$this->buffer->writeString($compressed);
|
||||
|
||||
$this->buffer->endChunk();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a PLTE chunk containing the indexed colors.
|
||||
*
|
||||
* @param \Jdenticon\Canvas\Png\PngPalette $palette Palette containing the
|
||||
* indexed colors.
|
||||
*/
|
||||
public function writePalette(PngPalette $palette)
|
||||
{
|
||||
if ($palette && $palette->isValid) {
|
||||
$this->buffer->startChunk("PLTE");
|
||||
|
||||
foreach ($palette->colors as $color) {
|
||||
$this->buffer->writeString(
|
||||
pack('C', ($color >> 24) & 0xff) .
|
||||
pack('C', ($color >> 16) & 0xff) .
|
||||
pack('C', ($color >> 8) & 0xff));
|
||||
}
|
||||
|
||||
$this->buffer->endChunk();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a tRNS chunk containing the alpha values of indexed colors.
|
||||
*
|
||||
* @param \Jdenticon\Canvas\Png\PngPalette $palette Palette containing the
|
||||
* indexed colors.
|
||||
*/
|
||||
public function writeTransparency(PngPalette $palette)
|
||||
{
|
||||
if ($palette && $palette->isValid && $palette->hasAlphaChannel) {
|
||||
$this->buffer->startChunk("tRNS");
|
||||
|
||||
$alpha = '';
|
||||
|
||||
foreach ($palette->colors as $color) {
|
||||
$alpha .= pack('C', $color & 0xff);
|
||||
}
|
||||
|
||||
$this->buffer->writeString($alpha);
|
||||
|
||||
$this->buffer->endChunk();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a tEXt chunk containing the specified strings.
|
||||
*
|
||||
* @param string $key Key, one of
|
||||
* {@link https://www.w3.org/TR/2003/REC-PNG-20031110/#11keywords}
|
||||
* @param string $value Value.
|
||||
*/
|
||||
public function writeTextualData($key, $value)
|
||||
{
|
||||
$this->buffer->startChunk("tEXt");
|
||||
$this->buffer->writeString($key);
|
||||
$this->buffer->writeUInt8(0);
|
||||
$this->buffer->writeString($value);
|
||||
$this->buffer->endChunk();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an IEND chunk to the png data stream.
|
||||
*/
|
||||
public function writeImageEnd()
|
||||
{
|
||||
$this->buffer->startChunk("IEND");
|
||||
$this->buffer->endChunk();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a binary string containing the PNG data.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBuffer()
|
||||
{
|
||||
return $this->buffer->getBuffer();
|
||||
}
|
||||
}
|
||||
92
vendor/jdenticon/jdenticon/src/Canvas/Png/PngPalette.php
vendored
Normal file
92
vendor/jdenticon/jdenticon/src/Canvas/Png/PngPalette.php
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Canvas\Png;
|
||||
|
||||
use Jdenticon\Canvas\ColorUtils;
|
||||
|
||||
/**
|
||||
* Contains the colors of a PNG color palette.
|
||||
*/
|
||||
class PngPalette
|
||||
{
|
||||
/**
|
||||
* Creates a PNG color palette for the specified bitmap data.
|
||||
*
|
||||
* @param array(integer) $colorRanges Array of interleaved values on the
|
||||
* format array(count0, color0, count1, color1, ...).
|
||||
*/
|
||||
function __construct(& $colorRanges)
|
||||
{
|
||||
$lookup = array();
|
||||
$colors = array();
|
||||
$hasAlphaChannel = false;
|
||||
$colorsCount = 0;
|
||||
|
||||
$count = -1;
|
||||
|
||||
foreach ($colorRanges as $value) {
|
||||
if ($count === -1) {
|
||||
$count = $value;
|
||||
} else {
|
||||
// Ignore empty ranges and already indexed colors
|
||||
if ($count > 0 && !isset($lookup[$value])) {
|
||||
if (!$hasAlphaChannel && ($value & 0xff) < 255) {
|
||||
$hasAlphaChannel = true;
|
||||
}
|
||||
|
||||
$lookup[$value] = $colorsCount++;
|
||||
$colors[] = $value;
|
||||
|
||||
if ($colorsCount > 256) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$count = -1;
|
||||
}
|
||||
}
|
||||
|
||||
$this->hasAlphaChannel = $hasAlphaChannel;
|
||||
$this->colors = & $colors;
|
||||
$this->lookup = & $lookup;
|
||||
$this->isValid = $colorsCount <= 256;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies if the palette is valid to be used for encoding a PNG image.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $isValid;
|
||||
|
||||
/**
|
||||
* Specifies if the palette has any partial or fully transparent
|
||||
* colors.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $hasAlphaChannel;
|
||||
|
||||
/**
|
||||
* Array of colors in the palette.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $colors;
|
||||
|
||||
/**
|
||||
* Lookup table from 32-bit color value to color index.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $lookup;
|
||||
}
|
||||
41
vendor/jdenticon/jdenticon/src/Canvas/Point.php
vendored
Normal file
41
vendor/jdenticon/jdenticon/src/Canvas/Point.php
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Canvas;
|
||||
|
||||
class Point
|
||||
{
|
||||
/**
|
||||
* X coordinate.
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
public $x;
|
||||
|
||||
/**
|
||||
* Y coordinate.
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
public $y;
|
||||
|
||||
/**
|
||||
* Creates a new 2D point.
|
||||
*
|
||||
* @param float $x X coordinate.
|
||||
* @param float $y Y coordinate.
|
||||
*/
|
||||
public function __construct($x, $y)
|
||||
{
|
||||
$this->x = $x;
|
||||
$this->y = $y;
|
||||
}
|
||||
}
|
||||
44
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Edge.php
vendored
Normal file
44
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Edge.php
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Canvas\Rasterization;
|
||||
|
||||
class Edge
|
||||
{
|
||||
public $polygonId;
|
||||
public $x0;
|
||||
public $x1;
|
||||
public $y0;
|
||||
public $y1;
|
||||
public $color;
|
||||
public $windingRule;
|
||||
|
||||
public function __construct(
|
||||
$polygonId, $x0, $y0, $x1, $y1, $color, $windingRule = null)
|
||||
{
|
||||
$this->polygonId = $polygonId;
|
||||
$this->x0 = $x0;
|
||||
$this->x1 = $x1;
|
||||
$this->y0 = $y0;
|
||||
$this->y1 = $y1;
|
||||
$this->color = $color;
|
||||
$this->windingRule = $windingRule;
|
||||
}
|
||||
|
||||
public function intersection($y)
|
||||
{
|
||||
$dx =
|
||||
($this->x1 - $this->x0) * ($this->y0 - $y) /
|
||||
($this->y0 - $this->y1);
|
||||
return $this->x0 + $dx;
|
||||
}
|
||||
}
|
||||
|
||||
27
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeIntersection.php
vendored
Normal file
27
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeIntersection.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Canvas\Rasterization;
|
||||
|
||||
class EdgeIntersection
|
||||
{
|
||||
public $fromX;
|
||||
public $width;
|
||||
public $edge;
|
||||
|
||||
public function __construct($fromX, $width, $edge)
|
||||
{
|
||||
$this->fromX = $fromX;
|
||||
$this->width = $width;
|
||||
$this->edge = $edge;
|
||||
}
|
||||
}
|
||||
|
||||
24
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeSuperSampleIntersection.php
vendored
Normal file
24
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeSuperSampleIntersection.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Canvas\Rasterization;
|
||||
|
||||
class EdgeSuperSampleIntersection
|
||||
{
|
||||
public $x;
|
||||
public $edge;
|
||||
|
||||
public function __construct($x, $edge)
|
||||
{
|
||||
$this->x = $x;
|
||||
$this->edge = $edge;
|
||||
}
|
||||
}
|
||||
158
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeTable.php
vendored
Normal file
158
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/EdgeTable.php
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Canvas\Rasterization;
|
||||
|
||||
class EdgeTable
|
||||
{
|
||||
private $scanlines;
|
||||
private $nextPolygonId;
|
||||
private $width;
|
||||
private $height;
|
||||
|
||||
/**
|
||||
* Keeps a list of edges per scanline.
|
||||
*
|
||||
* @param integer $width Clipping width.
|
||||
* @param integer $height Clipping height.
|
||||
*/
|
||||
public function __construct($width, $height)
|
||||
{
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
$this->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the edges of each scanline in ascending x coordinates.
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->scanlines = array();
|
||||
$this->nextPolygonId = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an id for the next polygon.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNextPolygonId()
|
||||
{
|
||||
return $this->nextPolygonId++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scaline for the specified Y coordinate, or NULL if there are
|
||||
* no edges for the specified Y coordinate.
|
||||
*
|
||||
* @return array|null.
|
||||
*/
|
||||
public function getScanline($y)
|
||||
{
|
||||
return isset($this->scanlines[$y]) ? $this->scanlines[$y] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an edge to the table.
|
||||
*
|
||||
* @param \Jdenticon\Canvas\Rasterization\Edge $edge
|
||||
*/
|
||||
public function add(\Jdenticon\Canvas\Rasterization\Edge $edge)
|
||||
{
|
||||
$minY = 0;
|
||||
$maxY = 0;
|
||||
|
||||
if ($edge->y0 == $edge->y1) {
|
||||
// Skip horizontal lines
|
||||
return;
|
||||
} elseif ($edge->y0 < $edge->y1) {
|
||||
$minY = (int)($edge->y0);
|
||||
$maxY = (int)($edge->y1 + 0.996 /* 1/255 */);
|
||||
} else {
|
||||
$minY = (int)($edge->y1);
|
||||
$maxY = (int)($edge->y0 + 0.996 /* 1/255 */);
|
||||
}
|
||||
|
||||
if ($maxY < 0 || $minY >= $this->height) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($minY < 0) {
|
||||
$minY = 0;
|
||||
}
|
||||
if ($maxY > $this->height) {
|
||||
$maxY = $this->height;
|
||||
}
|
||||
|
||||
if ($minY < $maxY) {
|
||||
$y = $minY;
|
||||
$x1 = $edge->intersection($y);
|
||||
|
||||
while ($y < $maxY) {
|
||||
$x2 = $edge->intersection($y + 1);
|
||||
|
||||
$fromX;
|
||||
$width;
|
||||
if ($x1 < $x2) {
|
||||
$fromX = (int)($x1);
|
||||
$width = (int)($x2 + 0.9999) - $fromX;
|
||||
} else {
|
||||
$fromX = (int)($x2);
|
||||
$width = (int)($x1 + 0.9999) - $fromX;
|
||||
}
|
||||
|
||||
if ($fromX < 0) {
|
||||
$width += $fromX;
|
||||
$fromX = 0;
|
||||
|
||||
if ($width < 0) {
|
||||
$width = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ($fromX < $this->width) {
|
||||
if (!isset($this->scanlines[$y])) {
|
||||
$this->scanlines[$y] = array();
|
||||
}
|
||||
|
||||
$this->scanlines[$y][] = new EdgeIntersection(
|
||||
$fromX, $width, $edge);
|
||||
}
|
||||
|
||||
$x1 = $x2;
|
||||
$y++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function edge_cmp($x, $y)
|
||||
{
|
||||
if ($x->fromX < $y->fromX) {
|
||||
return -1;
|
||||
}
|
||||
if ($x->fromX > $y->fromX) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the edges of each scanline in ascending x coordinates.
|
||||
*/
|
||||
public function sort()
|
||||
{
|
||||
foreach ($this->scanlines as $i => &$scanline) {
|
||||
usort($scanline, array(
|
||||
'Jdenticon\\Canvas\\Rasterization\\EdgeTable', 'edge_cmp'));
|
||||
}
|
||||
}
|
||||
}
|
||||
30
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Layer.php
vendored
Normal file
30
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Layer.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Canvas\Rasterization;
|
||||
|
||||
class Layer
|
||||
{
|
||||
public $polygonId;
|
||||
public $color;
|
||||
public $winding;
|
||||
public $windingRule;
|
||||
|
||||
public $nextLayer;
|
||||
|
||||
public function __construct($polygonId, $color, $winding, $windingRule)
|
||||
{
|
||||
$this->polygonId = $polygonId;
|
||||
$this->color = $color;
|
||||
$this->winding = $winding;
|
||||
$this->windingRule = $windingRule;
|
||||
}
|
||||
}
|
||||
150
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/LayerManager.php
vendored
Normal file
150
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/LayerManager.php
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Canvas\Rasterization;
|
||||
|
||||
use Jdenticon\Canvas\ColorUtils;
|
||||
use Jdenticon\Canvas\Rasterization\Layer;
|
||||
use Jdenticon\Canvas\Rasterization\Edge;
|
||||
|
||||
/**
|
||||
* Keeps track of the z-order of the currently rendered polygons,
|
||||
* and computes the final color from the stack of layers.
|
||||
*/
|
||||
class LayerManager
|
||||
{
|
||||
public $topLayer;
|
||||
|
||||
/**
|
||||
* The current visible color.
|
||||
* @var integer
|
||||
*/
|
||||
public $color;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->color = ColorUtils::TRANSPARENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all layers in this manager to another LayerManager.
|
||||
*
|
||||
* @param \Jdenticon\Canvas\Rasterization\LayerManager $other The
|
||||
* LayerManager to copy all layers to.
|
||||
*/
|
||||
public function copyTo(LayerManager $other)
|
||||
{
|
||||
$other->color = $this->color;
|
||||
|
||||
$layer = $this->topLayer;
|
||||
$previousCopy = null;
|
||||
|
||||
while ($layer !== null) {
|
||||
$copy = new Layer(
|
||||
$layer->polygonId,
|
||||
$layer->color,
|
||||
$layer->winding,
|
||||
$layer->windingRule
|
||||
);
|
||||
|
||||
if ($previousCopy === null) {
|
||||
$other->topLayer = $copy;
|
||||
}
|
||||
else {
|
||||
$previousCopy->nextLayer = $copy;
|
||||
}
|
||||
|
||||
$previousCopy = $copy;
|
||||
$layer = $layer->nextLayer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a layer for the specified edge. The z-order is defined by its id.
|
||||
*
|
||||
* @param \Jdenticon\Canvas\Rasterization\Edge edge
|
||||
*/
|
||||
public function add(Edge $edge)
|
||||
{
|
||||
$dwinding = $edge->y0 < $edge->y1 ? 1 : -1;
|
||||
|
||||
$layer = $this->topLayer;
|
||||
$previousLayer = null;
|
||||
|
||||
while ($layer !== null) {
|
||||
if ($layer->polygonId === $edge->polygonId) {
|
||||
$layer->winding += $dwinding;
|
||||
|
||||
$inPath = $layer->windingRule == 'evenodd' ?
|
||||
($layer->winding % 2 === 1) : ($layer->winding !== 0);
|
||||
|
||||
if (!$inPath) {
|
||||
// Remove layer
|
||||
if ($previousLayer === null) {
|
||||
$this->topLayer = $layer->nextLayer;
|
||||
}
|
||||
else {
|
||||
$previousLayer->nextLayer = $layer->nextLayer;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} elseif ($layer->polygonId < $edge->polygonId) {
|
||||
// Insert here
|
||||
$newLayer = new Layer(
|
||||
$edge->polygonId,
|
||||
$edge->color,
|
||||
$dwinding,
|
||||
$edge->windingRule
|
||||
);
|
||||
$newLayer->nextLayer = $layer;
|
||||
|
||||
if ($previousLayer === null) {
|
||||
$this->topLayer = $newLayer;
|
||||
} else {
|
||||
$previousLayer->nextLayer = $newLayer;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$previousLayer = $layer;
|
||||
$layer = $layer->nextLayer;
|
||||
}
|
||||
|
||||
if ($layer === null) {
|
||||
$newLayer = new Layer(
|
||||
$edge->polygonId,
|
||||
$edge->color,
|
||||
$dwinding,
|
||||
$edge->windingRule
|
||||
);
|
||||
|
||||
if ($previousLayer === null) {
|
||||
$this->topLayer = $newLayer;
|
||||
} else {
|
||||
$previousLayer->nextLayer = $newLayer;
|
||||
}
|
||||
}
|
||||
|
||||
// Update current color
|
||||
$color = ColorUtils::TRANSPARENT;
|
||||
$layer = $this->topLayer;
|
||||
|
||||
while ($layer !== null && ($color & 0xff) < 255) {
|
||||
if ($layer->color === ColorUtils::FORCE_TRANSPARENT) {
|
||||
break;
|
||||
}
|
||||
|
||||
$color = ColorUtils::over($layer->color, $color);
|
||||
}
|
||||
|
||||
$this->color = $color;
|
||||
}
|
||||
}
|
||||
379
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Rasterizer.php
vendored
Normal file
379
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/Rasterizer.php
vendored
Normal file
@@ -0,0 +1,379 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Canvas\Rasterization;
|
||||
|
||||
use Jdenticon\Canvas\ColorUtils;
|
||||
use Jdenticon\Canvas\Rasterization\LayerManager;
|
||||
use Jdenticon\Canvas\Rasterization\SuperSampleBuffer;
|
||||
use Jdenticon\Canvas\Rasterization\SuperSampleRange;
|
||||
use Jdenticon\Canvas\Rasterization\EdgeSuperSampleIntersection;
|
||||
|
||||
class Rasterizer
|
||||
{
|
||||
/**
|
||||
* A higher number of samples per pixel horizontally does not affect the
|
||||
* performance in the same way as SAMPLES_PER_PIXEL_Y, since the rasterizer
|
||||
* does not scan every subpixel horizontally.
|
||||
*/
|
||||
const SAMPLES_PER_PIXEL_X = 10;
|
||||
|
||||
/**
|
||||
* A higher number of samples vertically means lower performance, since
|
||||
* the rasterizer does a scan for every subpixel vertically.
|
||||
*/
|
||||
const SAMPLES_PER_PIXEL_Y = 3;
|
||||
|
||||
const SAMPLE_HEIGHT = 0.33333; // 1 / self::SAMPLES_PER_PIXEL_Y
|
||||
|
||||
/**
|
||||
* Rasterizes the edges in the edge table to a list of color ranges. No
|
||||
* range will span multiple scanlines.
|
||||
*/
|
||||
public static function rasterize(& $colorData, $edgeTable, $width, $height)
|
||||
{
|
||||
$edgeTable->sort();
|
||||
|
||||
$superSampleBuffer = new SuperSampleBuffer(
|
||||
$width, self::SAMPLES_PER_PIXEL_X);
|
||||
|
||||
$layers = array();
|
||||
$color = 0;
|
||||
|
||||
// Keeps track of how many of the subpixellayers that are used for
|
||||
// the currently rendered scanline. Until a range requiring
|
||||
// supersampling is encountered only a single layer is needed.
|
||||
$usedLayers = 0;
|
||||
|
||||
for ($i = 0; $i < self::SAMPLES_PER_PIXEL_Y; $i++) {
|
||||
$layers[] = new LayerManager();
|
||||
}
|
||||
|
||||
for ($ey = 0; $ey < $height; $ey++) {
|
||||
$scanline = $edgeTable->getScanline($ey);
|
||||
if ($scanline === null) {
|
||||
$colorData[] = $width;
|
||||
$colorData[] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
$superSampleRanges = self::getSuperSampleRanges($scanline, $width);
|
||||
$superSampleRangeCount = count($superSampleRanges);
|
||||
|
||||
foreach ($layers as $layer) {
|
||||
$layer->topLayer = null;
|
||||
$layer->color = ColorUtils::TRANSPARENT;
|
||||
}
|
||||
|
||||
$usedLayers = 1;
|
||||
|
||||
if ($superSampleRanges[0]->fromX) {
|
||||
$colorData[] = $superSampleRanges[0]->fromX;
|
||||
$colorData[] = 0;
|
||||
}
|
||||
|
||||
for (
|
||||
$rangeIndex = 0;
|
||||
$rangeIndex < $superSampleRangeCount;
|
||||
$rangeIndex++
|
||||
) {
|
||||
$superSampleRange = $superSampleRanges[$rangeIndex];
|
||||
$edge = $superSampleRange->edges[0];
|
||||
|
||||
// If there is exactly one edge in the supersample range, and it
|
||||
// is crossing the entire scanline, we can perform the
|
||||
// antialiasing by integrating the edge function.
|
||||
if (!isset($superSampleRange->edges[1]) && (
|
||||
$edge->y0 <= $ey && $edge->y1 >= $ey + 1 ||
|
||||
$edge->y0 >= $ey + 1 && $edge->y1 <= $ey
|
||||
)) {
|
||||
// Determine the lower and upper x value where the edge
|
||||
// intersects the scanline.
|
||||
$xey = $edge->intersection($ey);
|
||||
$xey1 = $edge->intersection($ey + 1);
|
||||
|
||||
if ($xey < $xey1) {
|
||||
$x0 = $xey;
|
||||
$x1 = $xey1;
|
||||
} else {
|
||||
$x0 = $xey1;
|
||||
$x1 = $xey;
|
||||
}
|
||||
|
||||
$rangeWidth = $x1 - $x0;
|
||||
|
||||
if ($usedLayers === 1) {
|
||||
$subScanlineLayers = $layers[0];
|
||||
$fromColor = $subScanlineLayers->color;
|
||||
$subScanlineLayers->add($edge);
|
||||
$toColor = $subScanlineLayers->color;
|
||||
} else {
|
||||
$fromColorR = 0;
|
||||
$fromColorG = 0;
|
||||
$fromColorB = 0;
|
||||
$fromColorA = 0;
|
||||
$toColorR = 0;
|
||||
$toColorG = 0;
|
||||
$toColorB = 0;
|
||||
$toColorA = 0;
|
||||
|
||||
// Compute the average color of all subpixel layers
|
||||
// before and after the edge intersection.
|
||||
// The calculation is inlined for increased performance.
|
||||
for ($i = 0; $i < $usedLayers; $i++) {
|
||||
$subScanlineLayers = $layers[$i];
|
||||
|
||||
// Add to average from-color
|
||||
$color = $subScanlineLayers->color;
|
||||
$alpha = $color & 0xff;
|
||||
if ($alpha > 0) {
|
||||
$fromColorA += $alpha;
|
||||
$fromColorR += (($color >> 24) & 0xff) * $alpha;
|
||||
$fromColorG += (($color >> 16) & 0xff) * $alpha;
|
||||
$fromColorB += (($color >> 8) & 0xff) * $alpha;
|
||||
}
|
||||
|
||||
// Add the new layer
|
||||
$subScanlineLayers->add($edge);
|
||||
|
||||
// Add to average to-color
|
||||
$color = $subScanlineLayers->color;
|
||||
$alpha = $color & 0xff;
|
||||
if ($alpha > 0) {
|
||||
$toColorA += $alpha;
|
||||
$toColorR += (($color >> 24) & 0xff) * $alpha;
|
||||
$toColorG += (($color >> 16) & 0xff) * $alpha;
|
||||
$toColorB += (($color >> 8) & 0xff) * $alpha;
|
||||
}
|
||||
}
|
||||
|
||||
$fromColor = $fromColorA === 0 ? 0 : ColorUtils::from(
|
||||
(int)($fromColorA / $usedLayers),
|
||||
(int)($fromColorR / $fromColorA),
|
||||
(int)($fromColorG / $fromColorA),
|
||||
(int)($fromColorB / $fromColorA));
|
||||
|
||||
$toColor = $toColorA === 0 ? 0 : ColorUtils::from(
|
||||
(int)($toColorA / $usedLayers),
|
||||
(int)($toColorR / $toColorA),
|
||||
(int)($toColorG / $toColorA),
|
||||
(int)($toColorB / $toColorA));
|
||||
}
|
||||
|
||||
// Render pixels
|
||||
for (
|
||||
$x = $superSampleRange->fromX;
|
||||
$x < $superSampleRange->toXExcl;
|
||||
$x++
|
||||
) {
|
||||
if ($x0 >= $x + 1) {
|
||||
// Pixel not covered
|
||||
$colorData[] = 1;
|
||||
$colorData[] = $fromColor;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($x1 <= $x) {
|
||||
// Pixel fully covered
|
||||
$colorData[] = 1;
|
||||
$colorData[] = $toColor;
|
||||
continue;
|
||||
}
|
||||
|
||||
// toColor coverage in the range [0.0, 1.0]
|
||||
// Initialize to the fully covered range of the pixel.
|
||||
$coverage = $x1 < $x + 1 ? $x + 1 - $x1 : 0;
|
||||
|
||||
// Compute integral for non-vertical edges
|
||||
if ($rangeWidth > 0.001) {
|
||||
// Range to integrate
|
||||
$integralFrom = $x0 > $x ? $x0 : $x;;
|
||||
$integralTo = $x1 < $x + 1 ? $x1 : $x + 1;
|
||||
|
||||
$coverage +=
|
||||
(
|
||||
(
|
||||
$integralTo * $integralTo -
|
||||
$integralFrom * $integralFrom
|
||||
) / 2 +
|
||||
$x0 * ($integralFrom - $integralTo)
|
||||
) / $rangeWidth;
|
||||
}
|
||||
|
||||
$colorData[] = 1;
|
||||
$colorData[] = ColorUtils::mix(
|
||||
$fromColor, $toColor, $coverage);
|
||||
}
|
||||
|
||||
$color = $toColor;
|
||||
|
||||
} // /simplified antialiasing
|
||||
else {
|
||||
// Super sampling
|
||||
$y = $ey + self::SAMPLE_HEIGHT / 2;
|
||||
|
||||
// Ensure all subpixel layers are initialized
|
||||
while ($usedLayers < self::SAMPLES_PER_PIXEL_Y) {
|
||||
$layers[0]->copyTo($layers[$usedLayers]);
|
||||
$usedLayers++;
|
||||
}
|
||||
|
||||
foreach ($layers as $subScanlineLayers) {
|
||||
$color = $subScanlineLayers->color;
|
||||
|
||||
$intersections = self::getIntersections(
|
||||
$superSampleRange->edges, $y);
|
||||
|
||||
foreach ($intersections as $intersection) {
|
||||
$superSampleBuffer->add($color,
|
||||
$intersection->x - $superSampleRange->fromX);
|
||||
$subScanlineLayers->add($intersection->edge);
|
||||
$color = $subScanlineLayers->color;
|
||||
}
|
||||
|
||||
$superSampleBuffer->add(
|
||||
$color, $superSampleRange->width + 1);
|
||||
$superSampleBuffer->rewind();
|
||||
|
||||
$y += self::SAMPLE_HEIGHT;
|
||||
} // /subpixel
|
||||
|
||||
// Blend subpixels
|
||||
$color = $superSampleBuffer->colorAt(
|
||||
$superSampleRange->width);
|
||||
$superSampleBuffer->emptyTo(
|
||||
$colorData, $superSampleRange->width);
|
||||
|
||||
//$color = end($colorData);
|
||||
} // /super sampling
|
||||
|
||||
// Forward last color
|
||||
if ($rangeIndex + 1 < $superSampleRangeCount) {
|
||||
$count =
|
||||
$superSampleRanges[$rangeIndex + 1]->fromX -
|
||||
$superSampleRange->toXExcl;
|
||||
|
||||
if ($count > 0) {
|
||||
$colorData[] = $count;
|
||||
$colorData[] = $color;
|
||||
}
|
||||
} else {
|
||||
$count = $width - $superSampleRange->toXExcl;
|
||||
if ($count > 0) {
|
||||
$colorData[] = $count;
|
||||
$colorData[] = $color;
|
||||
}
|
||||
}
|
||||
} // /range
|
||||
}
|
||||
|
||||
return $colorData;
|
||||
}
|
||||
|
||||
private static function intersection_cmp($a, $b)
|
||||
{
|
||||
if ($a->x < $b->x) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ($a->x > $b->x) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines what edges that intersect a horizontal line with the specified
|
||||
* y coordinate. For each intersecting edge the intersecting x coordinate is
|
||||
* returned.
|
||||
*
|
||||
* @param array $edges Array of edges in the current scanline.
|
||||
* @param int $y Y coordinate of the current scanline.
|
||||
* @return array Array containing EdgeSuperSampleIntersection. Objects
|
||||
* are sorted ascending by x coordinate.
|
||||
*/
|
||||
private static function getIntersections($edges, $y)
|
||||
{
|
||||
$intersections = array();
|
||||
|
||||
foreach ($edges as $edge) {
|
||||
if ($edge->y0 < $y && $edge->y1 >= $y ||
|
||||
$edge->y0 >= $y && $edge->y1 < $y
|
||||
) {
|
||||
$x = $edge->x0 +
|
||||
($edge->x1 - $edge->x0) * ($y - $edge->y0) /
|
||||
($edge->y1 - $edge->y0);
|
||||
|
||||
$intersections[] = new EdgeSuperSampleIntersection($x, $edge);
|
||||
}
|
||||
}
|
||||
|
||||
usort($intersections, array(
|
||||
'Jdenticon\\Canvas\\Rasterization\\Rasterizer',
|
||||
'intersection_cmp'));
|
||||
|
||||
return $intersections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines what ranges of a scanline that needs to be supersampled.
|
||||
*
|
||||
* @param array $scanline Array of edges in the current scanline.
|
||||
* @return array Array of SuperSampleRange.
|
||||
*/
|
||||
private static function getSuperSampleRanges(&$scanline, $width)
|
||||
{
|
||||
$superSampleRanges = array();
|
||||
|
||||
$rangeIndex = 0;
|
||||
$scanlineCount = count($scanline);
|
||||
|
||||
while ($rangeIndex < $scanlineCount) {
|
||||
$range = $scanline[$rangeIndex];
|
||||
|
||||
if ($range->fromX >= $width) {
|
||||
break;
|
||||
}
|
||||
|
||||
$superSampleRange = new SuperSampleRange(
|
||||
$range->fromX,
|
||||
$range->fromX + $range->width
|
||||
);
|
||||
$superSampleRange->edges[] = $range->edge;
|
||||
|
||||
$rangeIndex++;
|
||||
|
||||
for ($i = $rangeIndex; $i < $scanlineCount; $i++) {
|
||||
$range = $scanline[$i];
|
||||
|
||||
if ($range->fromX < $superSampleRange->toXExcl) {
|
||||
$superSampleRange->toXExcl = max(
|
||||
$superSampleRange->toXExcl,
|
||||
$range->fromX + $range->width);
|
||||
$superSampleRange->edges[] = $range->edge;
|
||||
$rangeIndex++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$superSampleRange->toXExcl = min($superSampleRange->toXExcl, $width);
|
||||
$superSampleRange->width =
|
||||
$superSampleRange->toXExcl - $superSampleRange->fromX;
|
||||
|
||||
$superSampleRanges[] = $superSampleRange;
|
||||
}
|
||||
|
||||
return $superSampleRanges;
|
||||
}
|
||||
}
|
||||
|
||||
198
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleBuffer.php
vendored
Normal file
198
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleBuffer.php
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Canvas\Rasterization;
|
||||
|
||||
use Jdenticon\Canvas\ColorUtils;
|
||||
|
||||
class SuperSampleBuffer
|
||||
{
|
||||
const IDX_COUNT = 0;
|
||||
const IDX_A = 1;
|
||||
const IDX_R = 2;
|
||||
const IDX_G = 3;
|
||||
const IDX_B = 4;
|
||||
|
||||
/**
|
||||
* Creates a color buffer keeping an average color out of several
|
||||
* color samples per pixel.
|
||||
*
|
||||
* @param integer $width Width of the buffer in pixels.
|
||||
* @param integer $samplesPerPixel Number of samples to keep per pixel.
|
||||
*/
|
||||
public function __construct($width, $samplesPerPixel)
|
||||
{
|
||||
$this->samples = array();
|
||||
$this->samplesPerPixel = $samplesPerPixel;
|
||||
|
||||
$this->pixelOffset = 0;
|
||||
$this->subPixelOffset = 0;
|
||||
|
||||
$this->width = $width;
|
||||
$this->used = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewinds the cursor to the beginning of the buffer.
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
$this->pixelOffset = 0;
|
||||
$this->subPixelOffset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the samples in this buffer.
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->pixelOffset = 0;
|
||||
$this->subPixelOffset = 0;
|
||||
$this->used = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the average color of each pixel to a specified color array.
|
||||
*
|
||||
* @param array $colorData The average colors will be written to this
|
||||
* color array.
|
||||
* @param integer $count Number of pixels to write.
|
||||
*/
|
||||
public function emptyTo(& $colorData, $count)
|
||||
{
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$sampleCount = $this->samples[$i * 5 + self::IDX_COUNT];
|
||||
$a = $this->samples[$i * 5 + self::IDX_A];
|
||||
$color = $sampleCount == 0 || $a == 0 ? 0 :
|
||||
ColorUtils::from(
|
||||
(int)($a / $sampleCount),
|
||||
(int)($this->samples[$i * 5 + self::IDX_R] / $a),
|
||||
(int)($this->samples[$i * 5 + self::IDX_G] / $a),
|
||||
(int)($this->samples[$i * 5 + self::IDX_B] / $a)
|
||||
);
|
||||
|
||||
$colorData[] = 1;
|
||||
$colorData[] = $color;
|
||||
}
|
||||
|
||||
$this->pixelOffset = 0;
|
||||
$this->subPixelOffset = 0;
|
||||
$this->used = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the average color of the pixel at a specified index.
|
||||
*
|
||||
* @param integer $index The index of the pixel.
|
||||
* @return integer
|
||||
*/
|
||||
public function colorAt($index)
|
||||
{
|
||||
$sampleCount = $this->samples[$index * 5 + self::IDX_COUNT];
|
||||
$alphaSum = $this->samples[$index * 5 + self::IDX_A];
|
||||
return $sampleCount == 0 || $alphaSum == 0 ? 0 :
|
||||
ColorUtils::from(
|
||||
(int)($alphaSum / $sampleCount),
|
||||
(int)($this->samples[$index * 5 + self::IDX_R] / $alphaSum),
|
||||
(int)($this->samples[$index * 5 + self::IDX_G] / $alphaSum),
|
||||
(int)($this->samples[$index * 5 + self::IDX_B] / $alphaSum)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a color to the current pixel in the buffer.
|
||||
*
|
||||
* @param integer $count Number of samples of the color to be added to
|
||||
* the buffer.
|
||||
*/
|
||||
private function _add($count, $a, $r, $g, $b)
|
||||
{
|
||||
if ($this->used < $this->pixelOffset) {
|
||||
$this->used = $this->pixelOffset;
|
||||
|
||||
$this->samples[$this->pixelOffset * 5 + self::IDX_COUNT] = $count;
|
||||
$this->samples[$this->pixelOffset * 5 + self::IDX_A] = $a * $count;
|
||||
$this->samples[$this->pixelOffset * 5 + self::IDX_R] = $a * $r * $count;
|
||||
$this->samples[$this->pixelOffset * 5 + self::IDX_G] = $a * $g * $count;
|
||||
$this->samples[$this->pixelOffset * 5 + self::IDX_B] = $a * $b * $count;
|
||||
} else {
|
||||
$this->samples[$this->pixelOffset * 5 + self::IDX_COUNT] += $count;
|
||||
|
||||
if ($a > 0) {
|
||||
$this->samples[$this->pixelOffset * 5 + self::IDX_A] += $a * $count;
|
||||
$this->samples[$this->pixelOffset * 5 + self::IDX_R] += $a * $r * $count;
|
||||
$this->samples[$this->pixelOffset * 5 + self::IDX_G] += $a * $g * $count;
|
||||
$this->samples[$this->pixelOffset * 5 + self::IDX_B] += $a * $b * $count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a color to the buffer up until the specified x index.
|
||||
*
|
||||
* @param integer $color Color to write.
|
||||
* @param float $untilX Samples of the color will be added the buffer until
|
||||
* the cursor reaches this coordinate.
|
||||
*/
|
||||
public function add($color, $untilX)
|
||||
{
|
||||
$samplesLeft =
|
||||
(int)($untilX * $this->samplesPerPixel) -
|
||||
$this->subPixelOffset -
|
||||
$this->pixelOffset * $this->samplesPerPixel;
|
||||
|
||||
// ColorUtils methods inlined for performance reasons
|
||||
$a = ($color) & 0xff;
|
||||
$r = ($color >> 24) & 0xff;
|
||||
$g = ($color >> 16) & 0xff;
|
||||
$b = ($color >> 8) & 0xff;
|
||||
|
||||
// First partial pixel
|
||||
if ($this->subPixelOffset > 0) {
|
||||
$samples = $this->samplesPerPixel - $this->subPixelOffset;
|
||||
if ($samples > $samplesLeft) {
|
||||
$samples = $samplesLeft;
|
||||
}
|
||||
$samplesLeft -= $samples;
|
||||
|
||||
$this->_add($samples, $a, $r, $g, $b);
|
||||
|
||||
$this->subPixelOffset += $samples;
|
||||
if ($this->subPixelOffset == $this->samplesPerPixel) {
|
||||
$this->subPixelOffset = 0;
|
||||
$this->pixelOffset++;
|
||||
}
|
||||
}
|
||||
|
||||
// Full pixels
|
||||
$fullPixels = (int)($samplesLeft / $this->samplesPerPixel);
|
||||
if ($fullPixels > 0) {
|
||||
for ($i = 0; $i < $fullPixels; $i++) {
|
||||
$this->_add($this->samplesPerPixel, $a, $r, $g, $b);
|
||||
$this->pixelOffset++;
|
||||
}
|
||||
|
||||
$samplesLeft -= $fullPixels * $this->samplesPerPixel;
|
||||
}
|
||||
|
||||
// Last partial pixel
|
||||
if ($samplesLeft > 0) {
|
||||
$this->_add($samplesLeft, $a, $r, $g, $b);
|
||||
|
||||
$this->subPixelOffset += $samplesLeft;
|
||||
|
||||
if ($this->subPixelOffset == $this->samplesPerPixel) {
|
||||
$this->subPixelOffset = 0;
|
||||
$this->pixelOffset++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleRange.php
vendored
Normal file
27
vendor/jdenticon/jdenticon/src/Canvas/Rasterization/SuperSampleRange.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Canvas\Rasterization;
|
||||
|
||||
class SuperSampleRange
|
||||
{
|
||||
public $fromX;
|
||||
public $toXExcl;
|
||||
public $edges;
|
||||
public $width;
|
||||
|
||||
public function __construct($fromX, $toXExcl)
|
||||
{
|
||||
$this->fromX = $fromX;
|
||||
$this->toXExcl = $toXExcl;
|
||||
$this->edges = array();
|
||||
}
|
||||
}
|
||||
605
vendor/jdenticon/jdenticon/src/Color.php
vendored
Normal file
605
vendor/jdenticon/jdenticon/src/Color.php
vendored
Normal file
@@ -0,0 +1,605 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon;
|
||||
|
||||
/**
|
||||
* Represents a 24-bit color with a 8-bit alpha channel.
|
||||
*/
|
||||
class Color
|
||||
{
|
||||
private static $lightnessCompensations = array(
|
||||
0.55, 0.5, 0.5, 0.46, 0.6, 0.55, 0.55);
|
||||
|
||||
/**
|
||||
* The red component of the color in the range [0, 255].
|
||||
* @var int
|
||||
*/
|
||||
public $r;
|
||||
|
||||
/**
|
||||
* The green component of the color in the range [0, 255].
|
||||
* @var int
|
||||
*/
|
||||
public $g;
|
||||
|
||||
/**
|
||||
* The blue component of the color in the range [0, 255].
|
||||
* @var int
|
||||
*/
|
||||
public $b;
|
||||
|
||||
/**
|
||||
* The alpha component of the color in the range [0, 255].
|
||||
* @var int
|
||||
*/
|
||||
public $a;
|
||||
|
||||
// Users of the struct should use the static factory methods
|
||||
// to create Color value.
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Color from an RGB value.
|
||||
*
|
||||
* @param int $alpha Alpha channel value in the range [0, 255].
|
||||
* @param int $red Red component in the range [0, 255].
|
||||
* @param int $green GReen component in the range [0, 255].
|
||||
* @param int $blue Blue component in the range [0, 255].
|
||||
*/
|
||||
public static function fromRgb($red, $green, $blue, $alpha = 255)
|
||||
{
|
||||
$color = new Color();
|
||||
$color->r = $red;
|
||||
$color->g = $green;
|
||||
$color->b = $blue;
|
||||
$color->a = $alpha;
|
||||
return $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Color instance from HSL color parameters.
|
||||
*
|
||||
* @param float $hue Hue in the range [0, 1]
|
||||
* @param float $saturation Saturation in the range [0, 1]
|
||||
* @param float $lightness Lightness in the range [0, 1]
|
||||
* @param float $alpha Alpha channel value in the range [0, 1].
|
||||
*/
|
||||
public static function fromHsl($hue, $saturation, $lightness, $alpha = 1.0)
|
||||
{
|
||||
if ($hue < 0) $hue = 0;
|
||||
if ($hue > 1) $hue = 1;
|
||||
|
||||
if ($saturation < 0) $saturation = 0;
|
||||
if ($saturation > 1) $saturation = 1;
|
||||
|
||||
if ($lightness < 0) $lightness = 0;
|
||||
if ($lightness > 1) $lightness = 1;
|
||||
|
||||
if ($alpha < 0) $alpha = 0;
|
||||
if ($alpha > 1) $alpha = 1;
|
||||
|
||||
// Based on http://www.w3.org/TR/2011/REC-css3-color-20110607/#hsl-color
|
||||
if ($saturation == 0) {
|
||||
$value = (int)($lightness * 255);
|
||||
return self::fromRgb($value, $value, $value, (int)($alpha * 255));
|
||||
} else {
|
||||
if ($lightness <= 0.5) {
|
||||
$m2 = $lightness * ($saturation + 1);
|
||||
} else {
|
||||
$m2 = $lightness + $saturation - $lightness * $saturation;
|
||||
}
|
||||
|
||||
$m1 = $lightness * 2 - $m2;
|
||||
|
||||
return self::fromRgb(
|
||||
self::hueToRgb($m1, $m2, $hue * 6 + 2),
|
||||
self::hueToRgb($m1, $m2, $hue * 6),
|
||||
self::hueToRgb($m1, $m2, $hue * 6 - 2),
|
||||
(int)($alpha * 255));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Color> instance from HSL color parameters and will compensate
|
||||
* the lightness for hues that appear to be darker than others.
|
||||
*
|
||||
* @param float $hue Hue in the range [0, 1].
|
||||
* @param float $saturation Saturation in the range [0, 1].
|
||||
* @param float $lightness Lightness in the range [0, 1].
|
||||
* @param float $alpha Alpha channel value in the range [0, 1].
|
||||
*/
|
||||
public static function fromHslCompensated($hue, $saturation, $lightness, $alpha = 1.0)
|
||||
{
|
||||
if ($hue < 0) $hue = 0;
|
||||
if ($hue > 1) $hue = 1;
|
||||
|
||||
$lightnessCompensation = self::$lightnessCompensations[(int)($hue * 6 + 0.5)];
|
||||
|
||||
// Adjust the input lightness relative to the compensation
|
||||
$lightness = $lightness < 0.5 ?
|
||||
$lightness * $lightnessCompensation * 2 :
|
||||
$lightnessCompensation + ($lightness - 0.5) * (1 - $lightnessCompensation) * 2;
|
||||
|
||||
return self::fromHsl($hue, $saturation, $lightness, $alpha);
|
||||
}
|
||||
|
||||
// Helper method for FromHsl
|
||||
private static function hueToRgb($m1, $m2, $h)
|
||||
{
|
||||
if ($h < 0) {
|
||||
$h = $h + 6;
|
||||
} elseif ($h > 6) {
|
||||
$h = $h - 6;
|
||||
}
|
||||
|
||||
if ($h < 1) {
|
||||
$r = $m1 + ($m2 - $m1) * $h;
|
||||
} elseif ($h < 3) {
|
||||
$r = $m2;
|
||||
} elseif ($h < 4) {
|
||||
$r = $m1 + ($m2 - $m1) * (4 - $h);
|
||||
} else {
|
||||
$r = $m1;
|
||||
}
|
||||
|
||||
return (int)(255 * $r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the argb value of this color.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function toRgba()
|
||||
{
|
||||
return
|
||||
($this->r << 24) |
|
||||
($this->g << 16) |
|
||||
($this->b << 8) |
|
||||
($this->a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a hexadecimal representation of this color on the format #rrggbbaa.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return '#' . bin2hex(pack('N', $this->toRgba()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a hexadecimal representation of this color on the format #rrggbbaa.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toHexString($length = 8)
|
||||
{
|
||||
if ($length === 8) {
|
||||
return $this->__toString();
|
||||
}
|
||||
return '#' . substr(bin2hex(pack('N', $this->toRgba())), 0, 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to parse a value as a Color.
|
||||
*
|
||||
* @param mixed $value Value to parse.
|
||||
* @throws InvalidArgumentException
|
||||
* @return \Jdenticon\Color
|
||||
*/
|
||||
public static function parse($value) {
|
||||
if ($value instanceof Color) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$value = strtolower("$value");
|
||||
|
||||
if (preg_match('/^#?[0-9a-f]{3,8}$/', $value) &&
|
||||
self::parseHexColor($value, $result)
|
||||
) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if (preg_match(
|
||||
'/^rgba?\\(([^,]+),([^,]+),([^,]+)(?:,([^,]+))?\\)$/',
|
||||
$value, $matches) &&
|
||||
self::parseRgbComponent($matches[1], $r) &&
|
||||
self::parseRgbComponent($matches[2], $g) &&
|
||||
self::parseRgbComponent($matches[3], $b) &&
|
||||
self::parseAlpha(isset($matches[4]) ? $matches[4] : null, $a)
|
||||
) {
|
||||
return self::fromRgb($r, $g, $b, (int)(255 * $a));
|
||||
}
|
||||
|
||||
if (preg_match(
|
||||
'/^hsla?\\(([^,]+),([^,]+),([^,]+)(?:,([^,]+))?\\)$/',
|
||||
$value, $matches) &&
|
||||
self::parseHue($matches[1], $h) &&
|
||||
self::parsePercent($matches[2], $s) &&
|
||||
self::parsePercent($matches[3], $l) &&
|
||||
self::parseAlpha(isset($matches[4]) ? $matches[4] : null, $a)
|
||||
) {
|
||||
return self::fromHsl($h, $s, $l, $a);
|
||||
}
|
||||
|
||||
$result = self::parseNamedColor($value);
|
||||
if ($result !== null) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(
|
||||
"Cannot parse '$value' as a color.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a percent value.
|
||||
*
|
||||
* @param string $input Input string.
|
||||
* @param float $result Resulting value in range [0, 1].
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private static function parsePercent($input, &$result)
|
||||
{
|
||||
// Detect and remove percent sign
|
||||
if (preg_match('/^\\s*(\\d*(?:\\.\\d*)?)%\\s*$/', $input, $matches)) {
|
||||
$result = floatval($matches[1]) / 100;
|
||||
|
||||
if ($result < 0) $result = 0;
|
||||
if ($result > 1) $result = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an alpha value.
|
||||
*
|
||||
* @param string $input Input string.
|
||||
* @param float $result Resulting alpha in range [0, 1].
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private static function parseAlpha($input, &$result)
|
||||
{
|
||||
if ($input === null ||
|
||||
$input === ''
|
||||
) {
|
||||
$result = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (preg_match('/^\\s*(\\d*(?:\\.\\d*)?)(%?)\\s*$/', $input, $matches)) {
|
||||
$result = floatval($matches[1]);
|
||||
|
||||
// Percentage
|
||||
if ($matches[2] !== '') {
|
||||
$result = $result / 100;
|
||||
}
|
||||
|
||||
if ($result < 0) $result = 0;
|
||||
if ($result > 1) $result = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an RGB component.
|
||||
*
|
||||
* @param string $input Input string.
|
||||
* @param float $result Hue in range [0, 255].
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private static function parseRgbComponent($input, &$result)
|
||||
{
|
||||
if (preg_match('/^\\s*(\\d*(?:\\.\\d*)?)(%?)\\s*$/', $input, $matches)) {
|
||||
$result = floatval($matches[1]);
|
||||
|
||||
if ($matches[2] === '%') {
|
||||
$result = 255 * $result / 100;
|
||||
}
|
||||
|
||||
$result = (int)$result;
|
||||
|
||||
if ($result < 0) $result = 0;
|
||||
if ($result > 255) $result = 255;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a hue component.
|
||||
*
|
||||
* @param string $input Input string.
|
||||
* @param float $result Hue in range [0, 1].
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private static function parseHue($input, &$result)
|
||||
{
|
||||
if (preg_match(
|
||||
'/^\s*(\d*(?:\.\d*)?)(deg|grad|rad|turn|)\s*$/',
|
||||
$input, $matches)
|
||||
) {
|
||||
$result = floatval($matches[1]);
|
||||
|
||||
// Percentage
|
||||
switch ($matches[2]) {
|
||||
case "grad":
|
||||
// Gradians: range 0 - 400
|
||||
$result = $result / 400;
|
||||
break;
|
||||
case "rad":
|
||||
// Radians: range 0 - 2pi
|
||||
$result = $result / M_PI / 2;
|
||||
break;
|
||||
case "turn":
|
||||
// Turns: range 0 - 1
|
||||
$result = $result;
|
||||
break;
|
||||
default:
|
||||
// Degree: range 0 - 360
|
||||
$result = $result / 360;
|
||||
break;
|
||||
}
|
||||
|
||||
$result = fmod($result, 1);
|
||||
|
||||
if ($result < 0) {
|
||||
$result += 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a hex color string.
|
||||
*
|
||||
* @param string $input Input string.
|
||||
* @param float $result Hue in range [0, 1].
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private static function parseHexColor($input, &$result)
|
||||
{
|
||||
if ($input[0] === '#') {
|
||||
$input = substr($input, 1);
|
||||
}
|
||||
|
||||
// intval does not support unsigned 32-bit integers
|
||||
// so we need to parse large numbers stepwise
|
||||
$numeric24bit = intval(substr($input, 0, 6), 16);
|
||||
$alpha8bit = intval(substr($input, 6, 2), 16);
|
||||
|
||||
switch (strlen($input)) {
|
||||
case 3:
|
||||
$result = self::fromRgb(
|
||||
(($numeric24bit & 0xf00) >> 8) |
|
||||
(($numeric24bit & 0xf00) >> 4),
|
||||
(($numeric24bit & 0x0f0) >> 4) |
|
||||
(($numeric24bit & 0x0f0)),
|
||||
(($numeric24bit & 0x00f) << 4) |
|
||||
(($numeric24bit & 0x00f))
|
||||
);
|
||||
return true;
|
||||
|
||||
case 4:
|
||||
$result = self::fromRgb(
|
||||
(($numeric24bit & 0xf000) >> 12) |
|
||||
(($numeric24bit & 0xf000) >> 8),
|
||||
(($numeric24bit & 0x0f00) >> 8) |
|
||||
(($numeric24bit & 0x0f00) >> 4),
|
||||
(($numeric24bit & 0x00f0) >> 4) |
|
||||
(($numeric24bit & 0x00f0)),
|
||||
(($numeric24bit & 0x000f) << 4) |
|
||||
(($numeric24bit & 0x000f))
|
||||
);
|
||||
return true;
|
||||
|
||||
case 6:
|
||||
$result = self::fromRgb(
|
||||
0xff & ($numeric24bit >> 16),
|
||||
0xff & ($numeric24bit >> 8),
|
||||
0xff & ($numeric24bit)
|
||||
);
|
||||
return true;
|
||||
|
||||
case 8:
|
||||
$result = self::fromRgb(
|
||||
0xff & ($numeric24bit >> 16),
|
||||
0xff & ($numeric24bit >> 8),
|
||||
0xff & ($numeric24bit),
|
||||
0xff & ($alpha8bit)
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a named color to a Color instance.
|
||||
*
|
||||
* @param string $input Input string.
|
||||
*
|
||||
* @return \Jdenticon\Color
|
||||
*/
|
||||
private static function parseNamedColor($input)
|
||||
{
|
||||
// Source: https://www.w3.org/TR/css-color-4/#named-colors
|
||||
switch ($input) {
|
||||
case 'aliceblue': return self::fromRgb(240,248,255);
|
||||
case 'antiquewhite': return self::fromRgb(250,235,215);
|
||||
case 'aqua': return self::fromRgb(0,255,255);
|
||||
case 'aquamarine': return self::fromRgb(127,255,212);
|
||||
case 'azure': return self::fromRgb(240,255,255);
|
||||
case 'beige': return self::fromRgb(245,245,220);
|
||||
case 'bisque': return self::fromRgb(255,228,196);
|
||||
case 'black': return self::fromRgb(0,0,0);
|
||||
case 'blanchedalmond': return self::fromRgb(255,235,205);
|
||||
case 'blue': return self::fromRgb(0,0,255);
|
||||
case 'blueviolet': return self::fromRgb(138,43,226);
|
||||
case 'brown': return self::fromRgb(165,42,42);
|
||||
case 'burlywood': return self::fromRgb(222,184,135);
|
||||
case 'cadetblue': return self::fromRgb(95,158,160);
|
||||
case 'chartreuse': return self::fromRgb(127,255,0);
|
||||
case 'chocolate': return self::fromRgb(210,105,30);
|
||||
case 'coral': return self::fromRgb(255,127,80);
|
||||
case 'cornflowerblue': return self::fromRgb(100,149,237);
|
||||
case 'cornsilk': return self::fromRgb(255,248,220);
|
||||
case 'crimson': return self::fromRgb(220,20,60);
|
||||
case 'cyan': return self::fromRgb(0,255,255);
|
||||
case 'darkblue': return self::fromRgb(0,0,139);
|
||||
case 'darkcyan': return self::fromRgb(0,139,139);
|
||||
case 'darkgoldenrod': return self::fromRgb(184,134,11);
|
||||
case 'darkgray': return self::fromRgb(169,169,169);
|
||||
case 'darkgreen': return self::fromRgb(0,100,0);
|
||||
case 'darkgrey': return self::fromRgb(169,169,169);
|
||||
case 'darkkhaki': return self::fromRgb(189,183,107);
|
||||
case 'darkmagenta': return self::fromRgb(139,0,139);
|
||||
case 'darkolivegreen': return self::fromRgb(85,107,47);
|
||||
case 'darkorange': return self::fromRgb(255,140,0);
|
||||
case 'darkorchid': return self::fromRgb(153,50,204);
|
||||
case 'darkred': return self::fromRgb(139,0,0);
|
||||
case 'darksalmon': return self::fromRgb(233,150,122);
|
||||
case 'darkseagreen': return self::fromRgb(143,188,143);
|
||||
case 'darkslateblue': return self::fromRgb(72,61,139);
|
||||
case 'darkslategray': return self::fromRgb(47,79,79);
|
||||
case 'darkslategrey': return self::fromRgb(47,79,79);
|
||||
case 'darkturquoise': return self::fromRgb(0,206,209);
|
||||
case 'darkviolet': return self::fromRgb(148,0,211);
|
||||
case 'deeppink': return self::fromRgb(255,20,147);
|
||||
case 'deepskyblue': return self::fromRgb(0,191,255);
|
||||
case 'dimgray': return self::fromRgb(105,105,105);
|
||||
case 'dimgrey': return self::fromRgb(105,105,105);
|
||||
case 'dodgerblue': return self::fromRgb(30,144,255);
|
||||
case 'firebrick': return self::fromRgb(178,34,34);
|
||||
case 'floralwhite': return self::fromRgb(255,250,240);
|
||||
case 'forestgreen': return self::fromRgb(34,139,34);
|
||||
case 'fuchsia': return self::fromRgb(255,0,255);
|
||||
case 'gainsboro': return self::fromRgb(220,220,220);
|
||||
case 'ghostwhite': return self::fromRgb(248,248,255);
|
||||
case 'gold': return self::fromRgb(255,215,0);
|
||||
case 'goldenrod': return self::fromRgb(218,165,32);
|
||||
case 'gray': return self::fromRgb(128,128,128);
|
||||
case 'green': return self::fromRgb(0,128,0);
|
||||
case 'greenyellow': return self::fromRgb(173,255,47);
|
||||
case 'grey': return self::fromRgb(128,128,128);
|
||||
case 'honeydew': return self::fromRgb(240,255,240);
|
||||
case 'hotpink': return self::fromRgb(255,105,180);
|
||||
case 'indianred': return self::fromRgb(205,92,92);
|
||||
case 'indigo': return self::fromRgb(75,0,130);
|
||||
case 'ivory': return self::fromRgb(255,255,240);
|
||||
case 'khaki': return self::fromRgb(240,230,140);
|
||||
case 'lavender': return self::fromRgb(230,230,250);
|
||||
case 'lavenderblush': return self::fromRgb(255,240,245);
|
||||
case 'lawngreen': return self::fromRgb(124,252,0);
|
||||
case 'lemonchiffon': return self::fromRgb(255,250,205);
|
||||
case 'lightblue': return self::fromRgb(173,216,230);
|
||||
case 'lightcoral': return self::fromRgb(240,128,128);
|
||||
case 'lightcyan': return self::fromRgb(224,255,255);
|
||||
case 'lightgoldenrodyellow': return self::fromRgb(250,250,210);
|
||||
case 'lightgray': return self::fromRgb(211,211,211);
|
||||
case 'lightgreen': return self::fromRgb(144,238,144);
|
||||
case 'lightgrey': return self::fromRgb(211,211,211);
|
||||
case 'lightpink': return self::fromRgb(255,182,193);
|
||||
case 'lightsalmon': return self::fromRgb(255,160,122);
|
||||
case 'lightseagreen': return self::fromRgb(32,178,170);
|
||||
case 'lightskyblue': return self::fromRgb(135,206,250);
|
||||
case 'lightslategray': return self::fromRgb(119,136,153);
|
||||
case 'lightslategrey': return self::fromRgb(119,136,153);
|
||||
case 'lightsteelblue': return self::fromRgb(176,196,222);
|
||||
case 'lightyellow': return self::fromRgb(255,255,224);
|
||||
case 'lime': return self::fromRgb(0,255,0);
|
||||
case 'limegreen': return self::fromRgb(50,205,50);
|
||||
case 'linen': return self::fromRgb(250,240,230);
|
||||
case 'magenta': return self::fromRgb(255,0,255);
|
||||
case 'maroon': return self::fromRgb(128,0,0);
|
||||
case 'mediumaquamarine': return self::fromRgb(102,205,170);
|
||||
case 'mediumblue': return self::fromRgb(0,0,205);
|
||||
case 'mediumorchid': return self::fromRgb(186,85,211);
|
||||
case 'mediumpurple': return self::fromRgb(147,112,219);
|
||||
case 'mediumseagreen': return self::fromRgb(60,179,113);
|
||||
case 'mediumslateblue': return self::fromRgb(123,104,238);
|
||||
case 'mediumspringgreen': return self::fromRgb(0,250,154);
|
||||
case 'mediumturquoise': return self::fromRgb(72,209,204);
|
||||
case 'mediumvioletred': return self::fromRgb(199,21,133);
|
||||
case 'midnightblue': return self::fromRgb(25,25,112);
|
||||
case 'mintcream': return self::fromRgb(245,255,250);
|
||||
case 'mistyrose': return self::fromRgb(255,228,225);
|
||||
case 'moccasin': return self::fromRgb(255,228,181);
|
||||
case 'navajowhite': return self::fromRgb(255,222,173);
|
||||
case 'navy': return self::fromRgb(0,0,128);
|
||||
case 'oldlace': return self::fromRgb(253,245,230);
|
||||
case 'olive': return self::fromRgb(128,128,0);
|
||||
case 'olivedrab': return self::fromRgb(107,142,35);
|
||||
case 'orange': return self::fromRgb(255,165,0);
|
||||
case 'orangered': return self::fromRgb(255,69,0);
|
||||
case 'orchid': return self::fromRgb(218,112,214);
|
||||
case 'palegoldenrod': return self::fromRgb(238,232,170);
|
||||
case 'palegreen': return self::fromRgb(152,251,152);
|
||||
case 'paleturquoise': return self::fromRgb(175,238,238);
|
||||
case 'palevioletred': return self::fromRgb(219,112,147);
|
||||
case 'papayawhip': return self::fromRgb(255,239,213);
|
||||
case 'peachpuff': return self::fromRgb(255,218,185);
|
||||
case 'peru': return self::fromRgb(205,133,63);
|
||||
case 'pink': return self::fromRgb(255,192,203);
|
||||
case 'plum': return self::fromRgb(221,160,221);
|
||||
case 'powderblue': return self::fromRgb(176,224,230);
|
||||
case 'purple': return self::fromRgb(128,0,128);
|
||||
case 'rebeccapurple': return self::fromRgb(102,51,153);
|
||||
case 'red': return self::fromRgb(255,0,0);
|
||||
case 'rosybrown': return self::fromRgb(188,143,143);
|
||||
case 'royalblue': return self::fromRgb(65,105,225);
|
||||
case 'saddlebrown': return self::fromRgb(139,69,19);
|
||||
case 'salmon': return self::fromRgb(250,128,114);
|
||||
case 'sandybrown': return self::fromRgb(244,164,96);
|
||||
case 'seagreen': return self::fromRgb(46,139,87);
|
||||
case 'seashell': return self::fromRgb(255,245,238);
|
||||
case 'sienna': return self::fromRgb(160,82,45);
|
||||
case 'silver': return self::fromRgb(192,192,192);
|
||||
case 'skyblue': return self::fromRgb(135,206,235);
|
||||
case 'slateblue': return self::fromRgb(106,90,205);
|
||||
case 'slategray': return self::fromRgb(112,128,144);
|
||||
case 'slategrey': return self::fromRgb(112,128,144);
|
||||
case 'snow': return self::fromRgb(255,250,250);
|
||||
case 'springgreen': return self::fromRgb(0,255,127);
|
||||
case 'steelblue': return self::fromRgb(70,130,180);
|
||||
case 'tan': return self::fromRgb(210,180,140);
|
||||
case 'teal': return self::fromRgb(0,128,128);
|
||||
case 'thistle': return self::fromRgb(216,191,216);
|
||||
case 'tomato': return self::fromRgb(255,99,71);
|
||||
case 'transparent': return self::fromRgb(0,0,0,0);
|
||||
case 'turquoise': return self::fromRgb(64,224,208);
|
||||
case 'violet': return self::fromRgb(238,130,238);
|
||||
case 'wheat': return self::fromRgb(245,222,179);
|
||||
case 'white': return self::fromRgb(255,255,255);
|
||||
case 'whitesmoke': return self::fromRgb(245,245,245);
|
||||
case 'yellow': return self::fromRgb(255,255,0);
|
||||
case 'yellowgreen': return self::fromRgb(154,205,50);
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
492
vendor/jdenticon/jdenticon/src/Identicon.php
vendored
Normal file
492
vendor/jdenticon/jdenticon/src/Identicon.php
vendored
Normal file
@@ -0,0 +1,492 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon;
|
||||
|
||||
use Jdenticon\IdenticonStyle;
|
||||
use Jdenticon\Rendering\Rectangle;
|
||||
use Jdenticon\Rendering\RendererInterface;
|
||||
use Jdenticon\Rendering\IconGenerator;
|
||||
use Jdenticon\Rendering\InternalPngRenderer;
|
||||
use Jdenticon\Rendering\ImagickRenderer;
|
||||
use Jdenticon\Rendering\SvgRenderer;
|
||||
|
||||
/**
|
||||
* Represents an identicon and its style. This is the entry class to Jdenticon.
|
||||
*/
|
||||
class Identicon
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
private $valueSet = false;
|
||||
|
||||
/**
|
||||
* Defaults to hash of an empty string.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $hash = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $size = 100;
|
||||
|
||||
/**
|
||||
* @var Jdenticon\Rendering\IconGenerator
|
||||
*/
|
||||
private $iconGenerator;
|
||||
|
||||
/**
|
||||
* @var Jdenticon\IdenticonStyle
|
||||
*/
|
||||
private $style;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $enableImageMagick;
|
||||
|
||||
/**
|
||||
* Creates an Identicon instance with the specified hash.
|
||||
*
|
||||
* @param string $hash A binary string containing the hash that will be used
|
||||
* as base for this icon. The hash must contain at least 6 bytes.
|
||||
* @param int|float|double $size The size of the icon in pixels (the icon
|
||||
* is quadratic).
|
||||
*/
|
||||
public function __construct($options = null)
|
||||
{
|
||||
$this->iconGenerator = IconGenerator::getDefaultGenerator();
|
||||
|
||||
if ($options !== null) {
|
||||
$this->setOptions($options);
|
||||
}
|
||||
|
||||
if ($this->style === null) {
|
||||
$this->style = new IdenticonStyle();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an Identicon instance from a specified hash.
|
||||
*
|
||||
* @param string $hash A binary string containing the hash that will be used
|
||||
* as base for this icon. The hash must contain at least 6 bytes.
|
||||
* @param int $size The size of the icon in pixels (the icon is quadratic).
|
||||
* @return \Jdenticon\Identicon
|
||||
*/
|
||||
public static function fromHash($hash, $size)
|
||||
{
|
||||
return new Identicon(array('hash' => $hash, 'size' => $size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an Identicon instance from a specified value.
|
||||
*
|
||||
* @param mixed $value The value that will be used as base for this icon.
|
||||
* The value will be converted to a UTF8 encoded string and then hashed
|
||||
* using SHA1.
|
||||
* @param int $size The size of the icon in pixels (the icon is quadratic).
|
||||
* @return \Jdenticon\Identicon
|
||||
*/
|
||||
public static function fromValue($value, $size)
|
||||
{
|
||||
return new Identicon(array('value' => $value, 'size' => $size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an associative array of all options of this identicon.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
$options = array();
|
||||
|
||||
if ($this->valueSet) {
|
||||
$options['value'] = $this->getValue();
|
||||
} elseif ($this->hash !== null) {
|
||||
$options['hash'] = $this->getHash();
|
||||
}
|
||||
|
||||
$options['size'] = $this->getSize();
|
||||
$options['style'] = $this->getStyle()->getOptions();
|
||||
|
||||
if ($this->enableImageMagick !== null) {
|
||||
$options['enableImageMagick'] = $this->getEnableImageMagick();
|
||||
}
|
||||
|
||||
if ($this->iconGenerator !== IconGenerator::getDefaultGenerator()) {
|
||||
$options['iconGenerator'] = $this->getIconGenerator();
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets options in this identicon by specifying an associative array of
|
||||
* option values.
|
||||
*
|
||||
* @param array $options Options to set.
|
||||
* @return self
|
||||
*/
|
||||
public function setOptions(array $options)
|
||||
{
|
||||
foreach ($options as $key => $value) {
|
||||
$this->__set($key, $value);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
switch (strtolower($name)) {
|
||||
case 'size':
|
||||
return $this->getSize();
|
||||
case 'hash':
|
||||
return $this->getHash();
|
||||
case 'value':
|
||||
return $this->getValue();
|
||||
case 'style':
|
||||
return $this->getStyle();
|
||||
case 'icongenerator':
|
||||
return $this->getIconGenerator();
|
||||
case 'enableimagemagick':
|
||||
return $this->getEnableImageMagick();
|
||||
default:
|
||||
throw new \InvalidArgumentException(
|
||||
"Unknown Identicon option '$name'.");
|
||||
}
|
||||
}
|
||||
|
||||
public function __set($name, $value)
|
||||
{
|
||||
switch (strtolower($name)) {
|
||||
case 'size':
|
||||
$this->setSize($value);
|
||||
break;
|
||||
case 'hash':
|
||||
$this->setHash($value);
|
||||
break;
|
||||
case 'value':
|
||||
$this->setValue($value);
|
||||
break;
|
||||
case 'style':
|
||||
$this->setStyle($value);
|
||||
break;
|
||||
case 'icongenerator':
|
||||
$this->setIconGenerator($value);
|
||||
break;
|
||||
case 'enableimagemagick':
|
||||
$this->setEnableImageMagick($value);
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException(
|
||||
"Unknown Identicon option '$name'.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the icon in pixels.
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
return $this->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the size of this icon in pixels.
|
||||
*
|
||||
* @param int|float|double $size The width and height of the icon.
|
||||
*/
|
||||
public function setSize($size)
|
||||
{
|
||||
if (!is_numeric($size) || $size < 1) {
|
||||
throw new \InvalidArgumentException(
|
||||
"An invalid identicon size was specified. ".
|
||||
"A numeric value >= 1 was expected. Specified value: $size.");
|
||||
}
|
||||
|
||||
$this->size = (int)$size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the icon in pixels.
|
||||
*/
|
||||
public function getEnableImageMagick()
|
||||
{
|
||||
// Enable ImageMagick on PHP < 7. On PHP 7 the performance increase
|
||||
// is not as obvious as on PHP 5. Since the ImageMagick renderer has a
|
||||
// lot of quirks, we don't want to use it unless really needed.
|
||||
if ($this->enableImageMagick === null) {
|
||||
return PHP_MAJOR_VERSION < 7 && extension_loaded('imagick');
|
||||
}
|
||||
|
||||
return $this->enableImageMagick;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether ImageMagick should be used to generate PNG icons.
|
||||
*
|
||||
* @param bool $enable true to enable ImageMagick.
|
||||
*/
|
||||
public function setEnableImageMagick($enable)
|
||||
{
|
||||
if (!is_bool($enable)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"enableImageMagick can only assume boolean values. Specified value: $enable.");
|
||||
}
|
||||
|
||||
// Verify that the Imagick extension is installed
|
||||
if ($enable && !extension_loaded('imagick')) {
|
||||
throw new \Exception(
|
||||
'Failed to enable ImageMagick. '.
|
||||
'The Imagick PHP extension was not found on this system.');
|
||||
}
|
||||
|
||||
$this->enableImageMagick = $enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@see IconGenerator} used to generate icons.
|
||||
*
|
||||
* @return \Jdenticon\Rendering\IconGenerator
|
||||
*/
|
||||
public function getIconGenerator()
|
||||
{
|
||||
return $this->iconGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@see IconGenerator} used to generate icons.
|
||||
*
|
||||
* @param \Jdenticon\Rendering\IconGenerator $iconGenerator Icon generator
|
||||
* that will render the shapes of the identicon.
|
||||
* @return \Jdenticon\Identicon
|
||||
*/
|
||||
public function setIconGenerator(IconGenerator $iconGenerator)
|
||||
{
|
||||
if ($iconGenerator === null) {
|
||||
$iconGenerator = IconGenerator::getDefaultGenerator();
|
||||
}
|
||||
$this->iconGenerator = $iconGenerator;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or sets the style of the icon.
|
||||
*
|
||||
* @return \Jdenticon\IdenticonStyle
|
||||
*/
|
||||
public function getStyle()
|
||||
{
|
||||
return $this->style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or sets the style of the icon.
|
||||
*
|
||||
* @param array|\Jdenticon\IdenticonStyle $style The new style of the icon.
|
||||
* NULL will revert the identicon to use the default style.
|
||||
* @return self
|
||||
*/
|
||||
public function setStyle($style)
|
||||
{
|
||||
if ($style == null) {
|
||||
$this->style = new IdenticonStyle();
|
||||
} elseif ($style instanceof IdenticonStyle) {
|
||||
$this->style = $style;
|
||||
} elseif (is_array($style)) {
|
||||
$this->style = new IdenticonStyle($style);
|
||||
} else {
|
||||
throw new \InvalidArgumentException(
|
||||
"Invalid indenticon style was specified. ".
|
||||
"Allowed values are IdenticonStyle instances and associative ".
|
||||
"arrays containing IdenticonStyle options.");
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a binary string containing the hash that is used as base for this
|
||||
* icon.
|
||||
*/
|
||||
public function getHash()
|
||||
{
|
||||
return $this->hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a binary string containing the hash that is used as base for this
|
||||
* icon. The string should contain at least 6 bytes.
|
||||
*
|
||||
* @param string $hash Binary string containing the hash.
|
||||
*/
|
||||
public function setHash($hash)
|
||||
{
|
||||
if (!is_string($hash)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'An invalid $hash was passed to Identicon. ' .
|
||||
'A binary string was expected.');
|
||||
}
|
||||
if (strlen($hash) < 6) {
|
||||
throw new \InvalidArgumentException(
|
||||
'An invalid $hash was passed to Identicon. ' .
|
||||
'The hash was expected to contain at least 6 bytes.');
|
||||
}
|
||||
|
||||
$this->hash = $hash;
|
||||
$this->value = null;
|
||||
$this->valueSet = false;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a binary string containing the hash that is used as base for this
|
||||
* icon.
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a value that will be used as base for this icon. The value will
|
||||
* be converted to a string and then hashed using SHA1.
|
||||
*
|
||||
* @param mixed $value Value that will be hashed.
|
||||
*/
|
||||
public function setValue($value)
|
||||
{
|
||||
$this->hash = sha1("$value");
|
||||
$this->value = $value;
|
||||
$this->valueSet = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bounds of the icon excluding its padding.
|
||||
*
|
||||
* @return \Jdenticon\Rendering\Rectangle
|
||||
*/
|
||||
public function getIconBounds()
|
||||
{
|
||||
// Round padding to nearest integer
|
||||
$padding = (int)($this->style->getPadding() * $this->size + 0.5);
|
||||
|
||||
return new Rectangle(
|
||||
$padding, $padding,
|
||||
$this->size - $padding * 2,
|
||||
$this->size - $padding * 2);
|
||||
}
|
||||
|
||||
private function getRenderer($imageFormat)
|
||||
{
|
||||
switch (strtolower($imageFormat)) {
|
||||
case 'svg':
|
||||
return new SvgRenderer($this->size, $this->size);
|
||||
|
||||
default:
|
||||
return $this->getEnableImageMagick() ?
|
||||
new ImagickRenderer($this->size, $this->size) :
|
||||
new InternalPngRenderer($this->size, $this->size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws this icon using a specified renderer.
|
||||
*
|
||||
* This method is only intended for usage with custom renderers. A custom
|
||||
* renderer could as an example render an Identicon in a file format not
|
||||
* natively supported by Jdenticon. To implement a new file format,
|
||||
* implement {@see \Jdenticon\Rendering\RendererInterface}.
|
||||
*
|
||||
* @param \Jdenticon\Rendering\RendererInterface $renderer The renderer used
|
||||
* to render this icon.
|
||||
* @param \Jdenticon\Rendering\Rectangle $rect The bounds of the rendered
|
||||
* icon. No padding will be applied to the rectangle. If the parameter
|
||||
* is omitted, the rectangle is calculated from the current icon
|
||||
* size and padding.
|
||||
*/
|
||||
public function draw(
|
||||
\Jdenticon\Rendering\RendererInterface $renderer,
|
||||
\Jdenticon\Rendering\Rectangle $rect = null)
|
||||
{
|
||||
if ($rect === null) {
|
||||
$rect = $this->getIconBounds();
|
||||
}
|
||||
$this->iconGenerator->generate(
|
||||
$renderer, $rect, $this->style, $this->hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the icon directly to the page output.
|
||||
*
|
||||
* The method will set the 'Content-Type' HTTP header. You are recommended
|
||||
* to set an appropriate 'Cache-Control' header before calling this method
|
||||
* to ensure the icon is cached client side.
|
||||
*
|
||||
* @param string $imageFormat The image format of the output.
|
||||
* Supported values are 'png' and 'svg'.
|
||||
*/
|
||||
public function displayImage($imageFormat = 'png')
|
||||
{
|
||||
$renderer = $this->getRenderer($imageFormat);
|
||||
$this->draw($renderer, $this->getIconBounds());
|
||||
$mimeType = $renderer->getMimeType();
|
||||
$data = $renderer->getData();
|
||||
header("Content-Type: $mimeType");
|
||||
echo $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the icon to a binary string.
|
||||
*
|
||||
* @param string $imageFormat The image format of the output string.
|
||||
* Supported values are 'png' and 'svg'.
|
||||
* @return string
|
||||
*/
|
||||
public function getImageData($imageFormat = 'png')
|
||||
{
|
||||
$renderer = $this->getRenderer($imageFormat);
|
||||
$this->draw($renderer, $this->getIconBounds());
|
||||
return $renderer->getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the icon as a data URI. It is recommended to avoid using this
|
||||
* method unless really necessary, since it will effectively disable client
|
||||
* caching of generated icons, and will also cause the same icon to be
|
||||
* rendered multiple times, when used multiple times on a single page.
|
||||
*
|
||||
* @param string $imageFormat The image format of the data URI.
|
||||
* Supported values are 'png' and 'svg'.
|
||||
* @return string
|
||||
*/
|
||||
public function getImageDataUri($imageFormat = 'png')
|
||||
{
|
||||
$renderer = $this->getRenderer($imageFormat);
|
||||
$this->draw($renderer, $this->getIconBounds());
|
||||
$mimeType = $renderer->getMimeType();
|
||||
$base64 = base64_encode($renderer->getData());
|
||||
return "data:$mimeType;base64,$base64";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
460
vendor/jdenticon/jdenticon/src/IdenticonStyle.php
vendored
Normal file
460
vendor/jdenticon/jdenticon/src/IdenticonStyle.php
vendored
Normal file
@@ -0,0 +1,460 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon;
|
||||
|
||||
use Jdenticon\Color;
|
||||
|
||||
/**
|
||||
* Specifies the color style of an identicon.
|
||||
*/
|
||||
class IdenticonStyle
|
||||
{
|
||||
/**
|
||||
* @var \Jdenticon\Color
|
||||
*/
|
||||
private $backgroundColor;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
private $padding;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
private $colorSaturation;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
private $grayscaleSaturation;
|
||||
|
||||
/**
|
||||
* @var array(float)
|
||||
*/
|
||||
private $colorLightness;
|
||||
|
||||
/**
|
||||
* @var array(float)
|
||||
*/
|
||||
private $grayscaleLightness;
|
||||
|
||||
/**
|
||||
* @var array(integer)
|
||||
*/
|
||||
private $hues;
|
||||
|
||||
public function __construct(array $options = null)
|
||||
{
|
||||
$this->backgroundColor = self::getDefaultBackgroundColor();
|
||||
$this->padding = self::getDefaultPadding();
|
||||
$this->colorSaturation = self::getDefaultColorSaturation();
|
||||
$this->grayscaleSaturation = self::getDefaultGrayscaleSaturation();
|
||||
$this->colorLightness = self::getDefaultColorLightness();
|
||||
$this->grayscaleLightness = self::getDefaultGrayscaleLightness();
|
||||
|
||||
if ($options !== null) {
|
||||
$this->setOptions($options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an associative array of all options of this style.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
$options = array();
|
||||
|
||||
$options['backgroundColor'] = $this->getBackgroundColor()->__toString();
|
||||
$options['padding'] = $this->getPadding();
|
||||
$options['colorSaturation'] = $this->getColorSaturation();
|
||||
$options['grayscaleSaturation'] = $this->getGrayscaleSaturation();
|
||||
$options['colorLightness'] = $this->getColorLightness();
|
||||
$options['grayscaleLightness'] = $this->getGrayscaleLightness();
|
||||
|
||||
if ($this->hues !== null) {
|
||||
$options['hues'] = $this->getHues();
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets options in this style by specifying an associative array of option
|
||||
* values.
|
||||
*
|
||||
* @param array $options Options to set.
|
||||
* @return self
|
||||
*/
|
||||
public function setOptions(array $options)
|
||||
{
|
||||
foreach ($options as $key => $value) {
|
||||
$this->__set($key, $value);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
switch (strtolower($name)) {
|
||||
case 'backgroundcolor':
|
||||
return $this->getBackgroundColor();
|
||||
case 'padding':
|
||||
return $this->getPadding();
|
||||
case 'colorsaturation':
|
||||
return $this->getColorSaturation();
|
||||
case 'grayscalesaturation':
|
||||
return $this->getGrayscaleSaturation();
|
||||
case 'colorlightness':
|
||||
return $this->getColorLightness();
|
||||
case 'grayscalelightness':
|
||||
return $this->getGrayscaleLightness();
|
||||
case 'hues':
|
||||
return $this->getHues();
|
||||
default:
|
||||
throw new \InvalidArgumentException(
|
||||
"Unknown IdenticonStyle option '$name'.");
|
||||
}
|
||||
}
|
||||
|
||||
public function __set($name, $value)
|
||||
{
|
||||
switch (strtolower($name)) {
|
||||
case 'backgroundcolor':
|
||||
$this->setBackgroundColor($value);
|
||||
break;
|
||||
case 'padding':
|
||||
$this->setPadding($value);
|
||||
break;
|
||||
case 'colorsaturation':
|
||||
$this->setColorSaturation($value);
|
||||
break;
|
||||
case 'grayscalesaturation':
|
||||
$this->setGrayscaleSaturation($value);
|
||||
break;
|
||||
case 'colorlightness':
|
||||
$this->setColorLightness($value);
|
||||
break;
|
||||
case 'grayscalelightness':
|
||||
$this->setGrayscaleLightness($value);
|
||||
break;
|
||||
case 'hues':
|
||||
$this->setHues($value);
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException(
|
||||
"Unknown IdenticonStyle option '$name'.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a hue to the first turn [0, 360).
|
||||
*
|
||||
* @param mixed $hue
|
||||
* @return integer
|
||||
*/
|
||||
private static function normalizeHue($hue)
|
||||
{
|
||||
if (!is_numeric($hue)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"'$hue' is not a valid hue.");
|
||||
}
|
||||
|
||||
$hue = $hue % 360;
|
||||
if ($hue < 0) {
|
||||
$hue += 360;
|
||||
}
|
||||
|
||||
return $hue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of allowed hues, or null if there are no restrictions.
|
||||
*
|
||||
* @return array(int)|null
|
||||
*/
|
||||
public function getHues()
|
||||
{
|
||||
return $this->hues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the allowed hues of generated icons.
|
||||
*
|
||||
* @param array(integer)|integer|null $value A hue specified in degrees,
|
||||
* or an array of hues specified in degrees. If set to null, the hue
|
||||
* list is cleared.
|
||||
* @return self
|
||||
*/
|
||||
public function setHues($value)
|
||||
{
|
||||
$hues = array();
|
||||
|
||||
if ($value !== null) {
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $hue) {
|
||||
$hues[] = self::normalizeHue($hue);
|
||||
}
|
||||
} else {
|
||||
$hues[] = self::normalizeHue($value);
|
||||
}
|
||||
}
|
||||
|
||||
$this->hues = empty($hues) ? null : $hues;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the padding of an icon in percents in the range [0.0, 0.4].
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getPadding()
|
||||
{
|
||||
return $this->padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the padding of an icon in percents.
|
||||
*
|
||||
* @param float $value New padding in the range [0.0, 0.4].
|
||||
* @return self
|
||||
*/
|
||||
public function setPadding($value)
|
||||
{
|
||||
if (!is_numeric($value) || $value < 0 || $value > 0.4) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Padding '$value' out of range. ".
|
||||
"Values in the range [0.0, 0.4] are allowed.");
|
||||
}
|
||||
$this->padding = (float)$value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the color of the identicon background.
|
||||
*
|
||||
* @return \Jdenticon\Color
|
||||
*/
|
||||
public function getBackgroundColor()
|
||||
{
|
||||
return $this->backgroundColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color of the identicon background.
|
||||
*
|
||||
* @param \Jdenticon\Color|string $value New background color.
|
||||
* @return \Jdenticon\IdenticonStyle
|
||||
*/
|
||||
public function setBackgroundColor($value)
|
||||
{
|
||||
if ($value instanceof Color) {
|
||||
$this->backgroundColor = $value;
|
||||
} else {
|
||||
$this->backgroundColor = Color::parse($value);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the saturation of the originally grayscale identicon shapes.
|
||||
*
|
||||
* @return float Saturation in the range [0.0, 1.0].
|
||||
*/
|
||||
public function getGrayscaleSaturation()
|
||||
{
|
||||
return $this->grayscaleSaturation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the saturation of the originally grayscale identicon shapes.
|
||||
*
|
||||
* @param $value float Saturation in the range [0.0, 1.0].
|
||||
* @return self
|
||||
*/
|
||||
public function setGrayscaleSaturation($value)
|
||||
{
|
||||
if (!is_numeric($value) ||
|
||||
$value < 0 || $value > 1
|
||||
) {
|
||||
throw new \InvalidArgumentException(
|
||||
"The grayscale saturation was invalid. ".
|
||||
"Only values in the range [0.0, 1.0] are allowed.");
|
||||
}
|
||||
$this->grayscaleSaturation = (float)$value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the saturation of the colored identicon shapes.
|
||||
*
|
||||
* @return float Saturation in the range [0.0, 1.0].
|
||||
*/
|
||||
public function getColorSaturation()
|
||||
{
|
||||
return $this->colorSaturation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the saturation of the colored identicon shapes.
|
||||
*
|
||||
* @param $value float Saturation in the range [0.0, 1.0].
|
||||
* @return self
|
||||
*/
|
||||
public function setColorSaturation($value)
|
||||
{
|
||||
if (!is_numeric($value) ||
|
||||
$value < 0 || $value > 1
|
||||
) {
|
||||
throw new \InvalidArgumentException(
|
||||
"The color saturation was invalid. ".
|
||||
"Only values in the range [0.0, 1.0] are allowed.");
|
||||
}
|
||||
$this->colorSaturation = (float)$value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the ColorLightness property.
|
||||
*
|
||||
* @return array(float, float)
|
||||
*/
|
||||
public function getColorLightness()
|
||||
{
|
||||
return $this->colorLightness;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the ColorLightness property.
|
||||
*
|
||||
* @param $value array(float, float) Lightness range.
|
||||
* @return self
|
||||
*/
|
||||
public function setColorLightness($value)
|
||||
{
|
||||
if (!is_array($value) ||
|
||||
!array_key_exists(0, $value) ||
|
||||
!array_key_exists(1, $value) ||
|
||||
!is_numeric($value[0]) ||
|
||||
!is_numeric($value[1]) ||
|
||||
$value[0] < 0 || $value[0] > 1 ||
|
||||
$value[1] < 0 || $value[1] > 1
|
||||
) {
|
||||
throw new \InvalidArgumentException(
|
||||
"The value passed to setColorLightness was invalid. ".
|
||||
"Please check the documentation.");
|
||||
}
|
||||
|
||||
$this->colorLightness = array((float)$value[0], (float)$value[1]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the GrayscaleLightness property.
|
||||
*
|
||||
* @return array(float, float)
|
||||
*/
|
||||
public function getGrayscaleLightness()
|
||||
{
|
||||
return $this->grayscaleLightness;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the GrayscaleLightness property.
|
||||
*
|
||||
* @param $value array(float, float) Lightness range.
|
||||
* @return self
|
||||
*/
|
||||
public function setGrayscaleLightness($value)
|
||||
{
|
||||
if (!is_array($value) ||
|
||||
!array_key_exists(0, $value) ||
|
||||
!array_key_exists(1, $value) ||
|
||||
!is_numeric($value[0]) ||
|
||||
!is_numeric($value[1]) ||
|
||||
$value[0] < 0 || $value[0] > 1 ||
|
||||
$value[1] < 0 || $value[1] > 1
|
||||
) {
|
||||
throw new \InvalidArgumentException(
|
||||
"The value passed to setGrayscaleLightness was invalid. ".
|
||||
"Please check the documentation.");
|
||||
}
|
||||
$this->grayscaleLightness = array((float)$value[0], (float)$value[1]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the default value of the BackgroundColor property. Resolves to transparent.
|
||||
*
|
||||
* @return \Jdenticon\Color
|
||||
*/
|
||||
public static function getDefaultBackgroundColor()
|
||||
{
|
||||
return Color::fromRgb(255, 255, 255, 255);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default value of the Padding property. Resolves to 0.08.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function getDefaultPadding()
|
||||
{
|
||||
return 0.08;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default value of the ColorSaturation property. Resolves to 0.5.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function getDefaultColorSaturation()
|
||||
{
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default value of the GrayscaleSaturation property. Resolves to 0.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function getDefaultGrayscaleSaturation()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default value of the ColorLightness property. Resolves to [0.4, 0.8].
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getDefaultColorLightness()
|
||||
{
|
||||
return array(0.4, 0.8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default value of the GrayscaleLightness property. Resolves to [0.3, 0.9].
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getDefaultGrayscaleLightness()
|
||||
{
|
||||
return array(0.3, 0.9);
|
||||
}
|
||||
}
|
||||
209
vendor/jdenticon/jdenticon/src/Rendering/AbstractRenderer.php
vendored
Normal file
209
vendor/jdenticon/jdenticon/src/Rendering/AbstractRenderer.php
vendored
Normal file
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Rendering;
|
||||
|
||||
/**
|
||||
* Base class for rendering shapes in an identicon. Implement this class to e.g.
|
||||
* support a new file format that is not natively supported by Jdenticon. To
|
||||
* invoke the new Renderer, pass the renderer as an argument to the
|
||||
* {@see \Jdenticon\Identicon::Draw} method.
|
||||
*/
|
||||
abstract class AbstractRenderer implements RendererInterface
|
||||
{
|
||||
private $transform;
|
||||
protected $backgroundColor;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->transform = Transform::getEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current transform that will be applied on all coordinates before
|
||||
* being rendered to the target image.
|
||||
*
|
||||
* @param \Jdenticon\Rendering\Transform $transform The transform to set.
|
||||
* If NULL is specified any existing transform is removed.
|
||||
*/
|
||||
public function setTransform(\Jdenticon\Rendering\Transform $transform)
|
||||
{
|
||||
$this->transform = $transform === null ?
|
||||
Transform::getEmpty() : $transform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current transform that will be applied on all coordinates before
|
||||
* being rendered to the target image.
|
||||
*
|
||||
* @return \Jdenticon\Rendering\Transform
|
||||
*/
|
||||
public function getTransform()
|
||||
{
|
||||
return $this->transform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a polygon without translating its coordinates.
|
||||
*
|
||||
* @param array $points An array of the points that the polygon consists of.
|
||||
*/
|
||||
abstract protected function addPolygonNoTransform($points);
|
||||
|
||||
/**
|
||||
* Adds a circle without translating its coordinates.
|
||||
*
|
||||
* @param float $x The x-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $y The y-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $size The size of the bounding rectangle.
|
||||
* @param bool $counterClockwise If true the circle will be drawn
|
||||
* counter clockwise.
|
||||
*/
|
||||
abstract protected function addCircleNoTransform($x, $y, $size, $counterClockwise);
|
||||
|
||||
/**
|
||||
* Sets the background color of the image.
|
||||
*
|
||||
* @param \Jdenticon\Color $color The image background color.
|
||||
*/
|
||||
public function setBackgroundColor(\Jdenticon\Color $color)
|
||||
{
|
||||
$this->backgroundColor = $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the background color of the image.
|
||||
*
|
||||
* @return \Jdenticon\Color
|
||||
*/
|
||||
public function getBackgroundColor()
|
||||
{
|
||||
return $this->backgroundColor;
|
||||
}
|
||||
|
||||
private function addPolygonCore(array $points, $invert)
|
||||
{
|
||||
$transformedPoints = array();
|
||||
foreach ($points as $point) {
|
||||
$transformedPoints[] =
|
||||
$this->transform->transformPoint($point->x, $point->y);
|
||||
}
|
||||
|
||||
if ($invert) {
|
||||
$transformedPoints = array_reverse($transformedPoints);
|
||||
}
|
||||
|
||||
//var_dump($transformedPoints);
|
||||
|
||||
$this->addPolygonNoTransform($transformedPoints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a rectangle to the image.
|
||||
*
|
||||
* @param float $x The x-coordinate of the rectangle upper-left corner.
|
||||
* @param float $y The y-coordinate of the rectangle upper-left corner.
|
||||
* @param float $width The width of the rectangle.
|
||||
* @param float $height The height of the rectangle.
|
||||
* @param bool $invert If true the area of the rectangle will be removed
|
||||
* from the filled area.
|
||||
*/
|
||||
public function addRectangle($x, $y, $width, $height, $invert = false)
|
||||
{
|
||||
$this->addPolygonCore(array(
|
||||
new Point($x, $y),
|
||||
new Point($x + $width, $y),
|
||||
new Point($x + $width, $y + $height),
|
||||
new Point($x, $y + $height),
|
||||
), $invert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a circle to the image.
|
||||
*
|
||||
* @param float $x The x-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $y The y-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $size The size of the bounding rectangle.
|
||||
* @param bool $invert If true the area of the circle will be removed
|
||||
* from the filled area.
|
||||
*/
|
||||
public function addCircle($x, $y, $size, $invert = false)
|
||||
{
|
||||
$northWest = $this->transform->transformPoint($x, $y, $size, $size);
|
||||
$this->addCircleNoTransform($northWest->x, $northWest->y, $size, $invert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a polygon to the image.
|
||||
*
|
||||
* @param array $points Array of points that the polygon consists of.
|
||||
* @param bool $invert If true the area of the polygon will be removed
|
||||
* from the filled area.
|
||||
*/
|
||||
public function addPolygon($points, $invert = false)
|
||||
{
|
||||
$this->addPolygonCore($points, $invert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a triangle to the image.
|
||||
*
|
||||
* @param float $x The x-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $y The y-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $width The width of the bounding rectangle.
|
||||
* @param float $height The height of the bounding rectangle.
|
||||
* @param float $direction The direction of the 90 degree corner of the
|
||||
* triangle.
|
||||
* @param bool $invert If true the area of the triangle will be removed
|
||||
* from the filled area.
|
||||
*/
|
||||
public function addTriangle($x, $y, $width, $height, $direction, $invert = false)
|
||||
{
|
||||
$points = array(
|
||||
new Point($x + $width, $y),
|
||||
new Point($x + $width, $y + $height),
|
||||
new Point($x, $y + $height),
|
||||
new Point($x, $y)
|
||||
);
|
||||
|
||||
array_splice($points, $direction, 1);
|
||||
|
||||
$this->addPolygonCore($points, $invert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a rhombus to the image.
|
||||
*
|
||||
* @param float $x The x-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $y The y-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $width The width of the bounding rectangle.
|
||||
* @param float $height The height of the bounding rectangle.
|
||||
* @param bool $invert If true the area of the rhombus will be removed
|
||||
* from the filled area.
|
||||
*/
|
||||
public function addRhombus($x, $y, $width, $height, $invert = false)
|
||||
{
|
||||
$this->addPolygonCore(array(
|
||||
new Point($x + $width / 2, $y),
|
||||
new Point($x + $width, $y + $height / 2),
|
||||
new Point($x + $width / 2, $y + $height),
|
||||
new Point($x, $y + $height / 2),
|
||||
), $invert);
|
||||
}
|
||||
}
|
||||
84
vendor/jdenticon/jdenticon/src/Rendering/ColorTheme.php
vendored
Normal file
84
vendor/jdenticon/jdenticon/src/Rendering/ColorTheme.php
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Rendering;
|
||||
|
||||
use Jdenticon\Color;
|
||||
|
||||
/**
|
||||
* Specifies the colors to be used in an identicon.
|
||||
*/
|
||||
class ColorTheme
|
||||
{
|
||||
private $darkGray;
|
||||
private $midColor;
|
||||
private $lightGray;
|
||||
private $lightColor;
|
||||
private $darkColor;
|
||||
|
||||
/**
|
||||
* Creates a new ColorTheme.
|
||||
*
|
||||
* @param float $hue The hue of the colored shapes in the range [0, 1].
|
||||
* @param \Jdenticon\IdenticonStyle $style The style that specifies the
|
||||
* lightness and saturation of the icon.
|
||||
*/
|
||||
public function __construct($hue, \Jdenticon\IdenticonStyle $style)
|
||||
{
|
||||
$grayscaleLightness = $style->getGrayscaleLightness();
|
||||
$colorLightness = $style->getColorLightness();
|
||||
$hues = $style->getHues();
|
||||
|
||||
if ($hues !== null) {
|
||||
// $hue is in the range [0, 1]
|
||||
// Multiply with 0.999 to change the range to [0, 1)
|
||||
$hueIndex = (int)($hue * 0.999 * count($hues));
|
||||
$hue = (float)$hues[$hueIndex] / 360;
|
||||
}
|
||||
|
||||
$this->darkGray = Color::fromHslCompensated(
|
||||
$hue, $style->getGrayscaleSaturation(), $grayscaleLightness[0]);
|
||||
$this->midColor = Color::fromHslCompensated(
|
||||
$hue, $style->getColorSaturation(), ($colorLightness[0] + $colorLightness[1]) / 2);
|
||||
$this->lightGray = Color::fromHslCompensated(
|
||||
$hue, $style->getGrayscaleSaturation(), $grayscaleLightness[1]);
|
||||
$this->lightColor = Color::fromHslCompensated(
|
||||
$hue, $style->getColorSaturation(), $colorLightness[1]);
|
||||
$this->darkColor = Color::fromHslCompensated(
|
||||
$hue, $style->getColorSaturation(), $colorLightness[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a color from this color theme by index.
|
||||
*
|
||||
* @param int $index Color index in the range [0, getCount()).
|
||||
* @return Jdenticon\Color
|
||||
*/
|
||||
public function getByIndex($index)
|
||||
{
|
||||
if ($index === 0) return $this->darkGray;
|
||||
if ($index === 1) return $this->midColor;
|
||||
if ($index === 2) return $this->lightGray;
|
||||
if ($index === 3) return $this->lightColor;
|
||||
if ($index === 4) return $this->darkColor;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of available colors in this theme.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCount()
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
290
vendor/jdenticon/jdenticon/src/Rendering/IconGenerator.php
vendored
Normal file
290
vendor/jdenticon/jdenticon/src/Rendering/IconGenerator.php
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Rendering;
|
||||
|
||||
use Jdenticon\Shapes\Shape;
|
||||
use Jdenticon\Shapes\ShapeCategory;
|
||||
use Jdenticon\Shapes\ShapeDefinitions;
|
||||
|
||||
/**
|
||||
* Generates identicons and render them to a
|
||||
* {@link \Jdenticon\Rendering\RendererInterface}. This class dictates what
|
||||
* shapes will be used in the generated icons. If you intend to customize the
|
||||
* appearance of generated icons you probably wants to either subclass or modify
|
||||
* this class.
|
||||
*/
|
||||
class IconGenerator
|
||||
{
|
||||
private $defaultShapes;
|
||||
private static $instance;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
$this->defaultShapes = array(
|
||||
// Sides
|
||||
new ShapeCategory(
|
||||
/*$colorIndex=*/ 8,
|
||||
/*$shapes=*/ ShapeDefinitions::getOuterShapes(),
|
||||
/*$shapeIndex=*/ 2,
|
||||
/*$rotationIndex=*/ 3,
|
||||
/*$positions=*/ array(1,0, 2,0, 2,3, 1,3, 0,1, 3,1, 3,2, 0,2)
|
||||
),
|
||||
|
||||
// Corners
|
||||
new ShapeCategory(
|
||||
/*$colorIndex=*/ 9,
|
||||
/*$shapes=*/ ShapeDefinitions::getOuterShapes(),
|
||||
/*$shapeIndex=*/ 4,
|
||||
/*$rotationIndex=*/ 5,
|
||||
/*$positions=*/ array(0,0, 3,0, 3,3, 0,3)
|
||||
),
|
||||
|
||||
// Center
|
||||
new ShapeCategory(
|
||||
/*$colorIndex=*/ 10,
|
||||
/*$shapes=*/ ShapeDefinitions::getCenterShapes(),
|
||||
/*$shapeIndex=*/ 1,
|
||||
/*$rotationIndex=*/ null,
|
||||
/*$positions=*/ array(1,1, 2,1, 2,2, 1,2)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static function getDefaultGenerator()
|
||||
{
|
||||
if (self::$instance === null) {
|
||||
self::$instance = new IconGenerator();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of cells in each direction of the icons generated by
|
||||
* this IconGenerator.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCellCount()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the hue to be used in an icon for the specified hash.
|
||||
*
|
||||
* @return float Hue in the range [0, 1].
|
||||
*/
|
||||
protected static function getHue($hash)
|
||||
{
|
||||
$value = hexdec(substr($hash, -7));
|
||||
return $value / 0xfffffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether $newValue is duplicated in $source if all values
|
||||
* in $duplicateValues are determined to be equal.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function isDuplicate(
|
||||
array $source, $newValue,
|
||||
array $duplicateValues)
|
||||
{
|
||||
if (in_array($newValue, $duplicateValues, true)) {
|
||||
foreach ($duplicateValues as $value) {
|
||||
if (in_array($value, $source, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the specified octet from a byte array.
|
||||
*
|
||||
* @param string $hash The hexstring from which the octet will be retrieved.
|
||||
* @param int $index The zero-based index of the octet to be returned.
|
||||
* @return int
|
||||
*/
|
||||
protected static function getOctet($hash, $index)
|
||||
{
|
||||
return hexdec($hash[$index]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of the shape categories to be rendered in icons generated
|
||||
* by this IconGenerator.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getCategories()
|
||||
{
|
||||
return $this->defaultShapes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an enumeration of individual shapes to be rendered in an icon for a
|
||||
* specific hash.
|
||||
*
|
||||
* @param \Jdenticon\Rendering\ColorTheme $colorTheme A color theme
|
||||
* specifying the colors to be used in the icon.
|
||||
* @param string $hash The hash for which the shapes will be returned.
|
||||
* @return array(Jdenticon\Shapes\Shape)
|
||||
*/
|
||||
protected function getShapes($colorTheme, $hash)
|
||||
{
|
||||
$usedColorThemeIndexes = array();
|
||||
$categories = self::getCategories();
|
||||
$shapes = array();
|
||||
$colorCount = $colorTheme->getCount();
|
||||
|
||||
foreach ($categories as $category) {
|
||||
$colorThemeIndex =
|
||||
self::getOctet($hash, $category->colorIndex) % $colorCount;
|
||||
|
||||
if (self::isDuplicate(
|
||||
// Disallow dark gray and dark color combo
|
||||
$usedColorThemeIndexes, $colorThemeIndex, array(0, 4)) ||
|
||||
self::isDuplicate(
|
||||
// Disallow light gray and light color combo
|
||||
$usedColorThemeIndexes, $colorThemeIndex, array(2, 3))
|
||||
) {
|
||||
$colorThemeIndex = 1;
|
||||
}
|
||||
|
||||
$usedColorThemeIndexes[] = $colorThemeIndex;
|
||||
|
||||
$startRotationIndex = $category->rotationIndex === null ?
|
||||
0 : self::getOctet($hash, $category->rotationIndex);
|
||||
$shapeIndex =
|
||||
self::getOctet($hash, $category->shapeIndex) %
|
||||
count($category->shapes);
|
||||
$shape = $category->shapes[$shapeIndex];
|
||||
|
||||
$shapes[] = new Shape(
|
||||
/*$definition=*/ $shape,
|
||||
/*$color=*/ $colorTheme->getByIndex($colorThemeIndex),
|
||||
/*$positions=*/ $category->positions,
|
||||
/*$startRotationIndex=*/ $startRotationIndex
|
||||
);
|
||||
}
|
||||
|
||||
return $shapes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a quadratic copy of the specified
|
||||
* {@link \Jdenticon\Rendering\Rectangle} with a multiple of the cell count
|
||||
* as size.
|
||||
*
|
||||
* @param \Jdenticon\Rendering\Rectangle $rect The rectangle to be
|
||||
* normalized.
|
||||
*/
|
||||
protected function normalizeRectangle(\Jdenticon\Rendering\Rectangle $rect)
|
||||
{
|
||||
$size = (int)min($rect->width, $rect->height);
|
||||
|
||||
// Make size a multiple of the cell count
|
||||
$size -= $size % $this->getCellCount();
|
||||
|
||||
return new Rectangle(
|
||||
(int)($rect->x + ($rect->width - $size) / 2),
|
||||
(int)($rect->y + ($rect->height - $size) / 2),
|
||||
$size,
|
||||
$size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the background of an icon.
|
||||
*
|
||||
* @param \Jdenticon\Rendering\RendererInterface $renderer The renderer to
|
||||
* be used for rendering the icon on the target surface.
|
||||
* @param \Jdenticon\Rendering\Rectangle $rect The outer bounds of the icon.
|
||||
* @param \Jdenticon\IdenticonStyle $style The style of the icon.
|
||||
* @param \Jdenticon\Rendering\ColorTheme $colorTheme A color theme
|
||||
* specifying the colors to be used in the icon.
|
||||
* @param string $hash The hash to be used as basis for the generated icon.
|
||||
*/
|
||||
protected function renderBackground(
|
||||
\Jdenticon\Rendering\RendererInterface $renderer,
|
||||
\Jdenticon\Rendering\Rectangle $rect,
|
||||
\Jdenticon\IdenticonStyle $style,
|
||||
\Jdenticon\Rendering\ColorTheme $colorTheme,
|
||||
$hash)
|
||||
{
|
||||
$renderer->setBackgroundColor($style->getBackgroundColor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the foreground of an icon.
|
||||
*
|
||||
* @param \Jdenticon\Rendering\RendererInterface $renderer The renderer to
|
||||
* be used for rendering the icon on the target surface.
|
||||
* @param \Jdenticon\Rendering\Rectangle $rect The outer bounds of the icon.
|
||||
* @param \Jdenticon\IdenticonStyle $style The style of the icon.
|
||||
* @param \Jdenticon\Rendering\ColorTheme $colorTheme A color theme
|
||||
* specifying the colors to be used in the icon.
|
||||
* @param string $hash The hash to be used as basis for the generated icon.
|
||||
*/
|
||||
protected function renderForeground(
|
||||
\Jdenticon\Rendering\RendererInterface $renderer,
|
||||
\Jdenticon\Rendering\Rectangle $rect,
|
||||
\Jdenticon\IdenticonStyle $style,
|
||||
\Jdenticon\Rendering\ColorTheme $colorTheme,
|
||||
$hash)
|
||||
{
|
||||
// Ensure rect is quadratic and a multiple of the cell count
|
||||
$normalizedRect = $this->normalizeRectangle($rect);
|
||||
$cellSize = $normalizedRect->width / $this->getCellCount();
|
||||
|
||||
foreach ($this->getShapes($colorTheme, $hash) as $shape) {
|
||||
$rotation = $shape->startRotationIndex;
|
||||
|
||||
$renderer->beginShape($shape->color);
|
||||
|
||||
$positionCount = count($shape->positions);
|
||||
for ($i = 0; $i + 1 < $positionCount; $i += 2) {
|
||||
$renderer->setTransform(new Transform(
|
||||
$normalizedRect->x + $shape->positions[$i + 0] * $cellSize,
|
||||
$normalizedRect->y + $shape->positions[$i + 1] * $cellSize,
|
||||
$cellSize, $rotation++ % 4));
|
||||
|
||||
$shape->definition->__invoke($renderer, $cellSize, $i / 2);
|
||||
}
|
||||
|
||||
$renderer->endShape();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an identicon for the specified hash.
|
||||
*
|
||||
* @param \Jdenticon\Rendering\RendererInterface $renderer The renderer to
|
||||
* be used for rendering the icon on the target surface.
|
||||
* @param \Jdenticon\Rendering\Rectangle $rect The outer bounds of the icon.
|
||||
* @param \Jdenticon\IdenticonStyle $style The style of the icon.
|
||||
* @param string $hash The hash to be used as basis for the generated icon.
|
||||
*/
|
||||
public function generate(
|
||||
\Jdenticon\Rendering\RendererInterface $renderer,
|
||||
\Jdenticon\Rendering\Rectangle $rect,
|
||||
\Jdenticon\IdenticonStyle $style,
|
||||
$hash)
|
||||
{
|
||||
$hue = self::getHue($hash);
|
||||
$colorTheme = new ColorTheme($hue, $style);
|
||||
|
||||
$this->renderBackground($renderer, $rect, $style, $colorTheme, $hash);
|
||||
$this->renderForeground($renderer, $rect, $style, $colorTheme, $hash);
|
||||
}
|
||||
}
|
||||
296
vendor/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php
vendored
Normal file
296
vendor/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php
vendored
Normal file
@@ -0,0 +1,296 @@
|
||||
<?php
|
||||
namespace Jdenticon\Rendering;
|
||||
|
||||
class ImagickRendererLine
|
||||
{
|
||||
/**
|
||||
* Creates a new line from a vector.
|
||||
*
|
||||
* @param float $x0 Vector start x coordinate.
|
||||
* @param float $y0 Vector start y coordinate.
|
||||
* @param float $x1 Vector end x coordinate.
|
||||
* @param float $y1 Vector end y coordinate.
|
||||
*/
|
||||
public static function fromVector($x0, $y0, $x1, $y1)
|
||||
{
|
||||
$line = new ImagickRendererLine();
|
||||
|
||||
$line->Px = $x0;
|
||||
$line->Py = $y0;
|
||||
|
||||
$line->rx = $x1 - $x0;
|
||||
$line->ry = $y1 - $y0;
|
||||
|
||||
return $line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the line to the right relative the direction vector.
|
||||
*
|
||||
* @param float $distance The number of pixels to move the line.
|
||||
*/
|
||||
public function moveRight($distance)
|
||||
{
|
||||
// Ortogonal direction vector
|
||||
$rx = -$this->ry;
|
||||
$ry = $this->rx;
|
||||
|
||||
$multiplier = $distance / sqrt($rx * $rx + $ry * $ry);
|
||||
|
||||
$this->Px += $rx * $multiplier;
|
||||
$this->Py += $ry * $multiplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the point at which two lines intersect.
|
||||
*
|
||||
* @return Point|null
|
||||
*/
|
||||
public static function intersection(
|
||||
ImagickRendererLine $l1,
|
||||
ImagickRendererLine $l2
|
||||
) {
|
||||
$rs = $l1->rx * $l2->ry - $l1->ry * $l2->rx;
|
||||
|
||||
if ($rs == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$u = (($l2->Px - $l1->Px) * $l1->ry - ($l2->Py - $l1->Py) * $l1->rx) / $rs;
|
||||
|
||||
return new Point(
|
||||
$l2->Px + $u * $l2->rx,
|
||||
$l2->Py + $u * $l2->ry
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* X coordiate of a point on the line.
|
||||
* @var float
|
||||
*/
|
||||
public $Px;
|
||||
/**
|
||||
* Y coordiate of a point on the line.
|
||||
* @var float
|
||||
*/
|
||||
public $Py;
|
||||
|
||||
/**
|
||||
* X component of the direction vector.
|
||||
* @var float
|
||||
*/
|
||||
public $rx;
|
||||
/**
|
||||
* Y component of the direction vector.
|
||||
* @var float
|
||||
*/
|
||||
public $ry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders icons as PNG using ImageMagick.
|
||||
*
|
||||
* Unfortunately the ImageMagick vector renderer has a lot of quirks that
|
||||
* we need to accomodate. The most obvious is that the renderer always render
|
||||
* all polygons 1/2 pixel too large. This behavior is documented here:
|
||||
* http://www.imagemagick.org/Usage/draw/#bounds
|
||||
*
|
||||
* To prevent this we shrink all polygons with 1/2 pixels before passing them
|
||||
* to ImageMagick.
|
||||
*
|
||||
* Another quirk is that if the polygon including the 1/2 pixel invisible border
|
||||
* align perfectly to the pixel grid, white pixels will appear near edge
|
||||
* intersections. Paths containing arcs will sometimes appear with horizontal
|
||||
* lines drawn to the right side of the image.
|
||||
*
|
||||
* To prevent this (in most cases) we add 0.00013 to all coordinates.
|
||||
*
|
||||
*/
|
||||
class ImagickRenderer extends AbstractRenderer
|
||||
{
|
||||
private $draw;
|
||||
private $polygon;
|
||||
private $width;
|
||||
private $height;
|
||||
|
||||
/**
|
||||
* This constant is added to all coordinates to avoid white pixels
|
||||
* that sometimes appear near edge intersections when a polygon including
|
||||
* its 1/2 invisible border is perfectly aligned to the pixel grid.
|
||||
*/
|
||||
const PREVENT_WHITE_PIXELS_OFFSET = -0.00013;
|
||||
|
||||
/**
|
||||
* Creates an instance of the class ImagickRenderer.
|
||||
*
|
||||
* @param int $width The width of the icon in pixels.
|
||||
* @param int $height The height of the icon in pixels.
|
||||
*/
|
||||
public function __construct($width, $height)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->draw = new \ImagickDraw();
|
||||
$this->draw->setStrokeWidth(1);
|
||||
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MIME type of the renderer output.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMimeType()
|
||||
{
|
||||
return 'image/png';
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a circle without translating its coordinates.
|
||||
*
|
||||
* @param float $x The x-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $y The y-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $size The size of the bounding rectangle.
|
||||
* @param bool $counterClockwise If true the circle will be drawn
|
||||
* counter clockwise.
|
||||
*/
|
||||
protected function addCircleNoTransform($x, $y, $size, $counterClockwise)
|
||||
{
|
||||
if ($counterClockwise) {
|
||||
$x -= $size + 0.5;
|
||||
$y -= 1;
|
||||
} else {
|
||||
$size -= 1;
|
||||
$y -= 0.5;
|
||||
}
|
||||
|
||||
$radius = $size / 2;
|
||||
$this->draw->pathMoveToAbsolute(
|
||||
$x + $size + self::PREVENT_WHITE_PIXELS_OFFSET,
|
||||
$y + $radius + self::PREVENT_WHITE_PIXELS_OFFSET);
|
||||
$this->draw->pathEllipticArcRelative($radius, $radius,
|
||||
M_PI * 2, true, $counterClockwise, 0, 1);
|
||||
$this->draw->pathClose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a polygon without translating its coordinates.
|
||||
*
|
||||
* @param array $points An array of the points that the polygon consists of.
|
||||
*/
|
||||
protected function addPolygonNoTransform($points)
|
||||
{
|
||||
$firstPoint = $points[0];
|
||||
$lastPoint = end($points);
|
||||
|
||||
// Ensure polygon is closed
|
||||
if ($firstPoint->x != $lastPoint->x ||
|
||||
$firstPoint->y != $lastPoint->y
|
||||
) {
|
||||
$points[] = $firstPoint;
|
||||
}
|
||||
|
||||
// Determine if polygon is an outer ring
|
||||
// (source: https://stackoverflow.com/a/1165943)
|
||||
$sum = 0;
|
||||
$previousPoint = null;
|
||||
|
||||
foreach ($points as $point) {
|
||||
if ($previousPoint !== null) {
|
||||
$sum += ($point->x - $previousPoint->x) * ($point->y + $previousPoint->y);
|
||||
}
|
||||
$previousPoint = $point;
|
||||
}
|
||||
|
||||
$isOuterRing = $sum < 0;
|
||||
|
||||
// ImageMagick draws all polygons 1 pixel too large. To prevent this,
|
||||
// shrink polygons by 1 pixel.
|
||||
$lines = array();
|
||||
$previousPoint = null;
|
||||
|
||||
// Transform all edges to lines.
|
||||
foreach ($points as $point) {
|
||||
if ($previousPoint !== null) {
|
||||
$lines[] = $line = ImagickRendererLine::fromVector(
|
||||
$previousPoint->x, $previousPoint->y,
|
||||
$point->x, $point->y
|
||||
);
|
||||
|
||||
// ImageMagick draws a 1px border along the outer ring. To
|
||||
// prevent the border overlaps inner rings too close to the
|
||||
// outer ring, only inflate inner rings by 1/4 pixel.
|
||||
$line->moveRight($isOuterRing ? 0.5 : 0.25);
|
||||
}
|
||||
$previousPoint = $point;
|
||||
}
|
||||
|
||||
$first = true;
|
||||
$previousLine = end($lines);
|
||||
|
||||
// Reconstruct point array from line intersections and draw the polygon
|
||||
foreach ($lines as $line) {
|
||||
$points[] = $point = ImagickRendererLine::intersection($previousLine, $line);
|
||||
|
||||
// Subtract 1/2 pixel to align the shapes to the pixel grid.
|
||||
if ($first) {
|
||||
$this->draw->pathMoveToAbsolute(
|
||||
$point->x - 0.5 + self::PREVENT_WHITE_PIXELS_OFFSET,
|
||||
$point->y - 0.5 + self::PREVENT_WHITE_PIXELS_OFFSET);
|
||||
|
||||
$first = false;
|
||||
} else {
|
||||
$this->draw->pathLineToAbsolute(
|
||||
$point->x - 0.5 + self::PREVENT_WHITE_PIXELS_OFFSET,
|
||||
$point->y - 0.5 + self::PREVENT_WHITE_PIXELS_OFFSET);
|
||||
}
|
||||
|
||||
$previousLine = $line;
|
||||
}
|
||||
|
||||
$this->draw->pathClose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins a new shape. The shape should be ended with a call to endShape.
|
||||
*
|
||||
* @param \Jdenticon\Color $color The color of the shape.
|
||||
*/
|
||||
public function beginShape(\Jdenticon\Color $color)
|
||||
{
|
||||
$this->draw->setFillColor($color->__toString());
|
||||
$this->draw->pathStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the currently drawn shape.
|
||||
*/
|
||||
public function endShape()
|
||||
{
|
||||
$this->draw->pathFinish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders this image as a PNG data stream.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
$imagick = new \Imagick();
|
||||
$imagick->newImage($this->width, $this->height, $this->backgroundColor->__toString());
|
||||
$imagick->setImageFormat('png');
|
||||
|
||||
if (method_exists($imagick, 'setImageProperty')) {
|
||||
$imagick->setImageProperty('Software', 'Jdenticon');
|
||||
} else {
|
||||
$imagick->setImageAttribute('Software', 'Jdenticon');
|
||||
}
|
||||
|
||||
$imagick->drawImage($this->draw);
|
||||
return $imagick->getImageBlob();
|
||||
}
|
||||
}
|
||||
123
vendor/jdenticon/jdenticon/src/Rendering/InternalPngRenderer.php
vendored
Normal file
123
vendor/jdenticon/jdenticon/src/Rendering/InternalPngRenderer.php
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Rendering;
|
||||
|
||||
use Jdenticon\Canvas\Canvas;
|
||||
|
||||
/**
|
||||
* Renders icons as PNG using the internal vector rasterizer.
|
||||
*/
|
||||
class InternalPngRenderer extends AbstractRenderer
|
||||
{
|
||||
private $canvas;
|
||||
private $ctx;
|
||||
|
||||
/**
|
||||
* Creates an instance of the class ImagickRenderer.
|
||||
*
|
||||
* @param int $width The width of the icon in pixels.
|
||||
* @param int $height The height of the icon in pixels.
|
||||
*/
|
||||
public function __construct($width, $height)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->canvas = new Canvas($width, $height);
|
||||
$this->ctx = $this->canvas->getContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MIME type of the renderer output.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMimeType()
|
||||
{
|
||||
return 'image/png';
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a circle without translating its coordinates.
|
||||
*
|
||||
* @param float $x The x-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $y The y-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $size The size of the bounding rectangle.
|
||||
* @param bool $counterClockwise If true the circle will be drawn
|
||||
* counter clockwise.
|
||||
*/
|
||||
protected function addCircleNoTransform($x, $y, $size, $counterClockwise)
|
||||
{
|
||||
$radius = $size / 2;
|
||||
$this->ctx->moveTo($x + $size, $y + $radius);
|
||||
$this->ctx->arc(
|
||||
$x + $radius, $y + $radius,
|
||||
$radius, 0, M_PI * 2,
|
||||
$counterClockwise);
|
||||
$this->ctx->closePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a polygon without translating its coordinates.
|
||||
*
|
||||
* @param array $points An array of the points that the polygon consists of.
|
||||
*/
|
||||
protected function addPolygonNoTransform($points)
|
||||
{
|
||||
$pointCount = count($points);
|
||||
$this->ctx->moveTo($points[0]->x, $points[0]->y);
|
||||
for ($i = 1; $i < $pointCount; $i++) {
|
||||
$this->ctx->lineTo($points[$i]->x, $points[$i]->y);
|
||||
}
|
||||
$this->ctx->closePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the background color of the icon.
|
||||
*
|
||||
* @param \Jdenticon\Color $color The background color.
|
||||
*/
|
||||
public function setBackgroundColor(\Jdenticon\Color $color)
|
||||
{
|
||||
parent::setBackgroundColor($color);
|
||||
$this->canvas->backColor = $this->backgroundColor->toRgba();
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins a new shape. The shape should be ended with a call to endShape.
|
||||
*
|
||||
* @param \Jdenticon\Color $color The color of the shape.
|
||||
*/
|
||||
public function beginShape(\Jdenticon\Color $color)
|
||||
{
|
||||
$this->ctx->fillStyle = $color->toRgba();
|
||||
$this->ctx->beginPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the currently drawn shape.
|
||||
*/
|
||||
public function endShape()
|
||||
{
|
||||
$this->ctx->fill();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the output from the renderer.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->canvas->toPng(array('Software' => 'Jdenticon'));
|
||||
}
|
||||
}
|
||||
54
vendor/jdenticon/jdenticon/src/Rendering/Point.php
vendored
Normal file
54
vendor/jdenticon/jdenticon/src/Rendering/Point.php
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Rendering;
|
||||
|
||||
/**
|
||||
* A 2D coordinate.
|
||||
*/
|
||||
class Point
|
||||
{
|
||||
/**
|
||||
* Creates a new Point.
|
||||
*
|
||||
* @param float $x X coordinate.
|
||||
* @param float $y Y coordinate.
|
||||
*/
|
||||
public function __construct($x, $y)
|
||||
{
|
||||
$this->x = $x;
|
||||
$this->y = $y;
|
||||
}
|
||||
|
||||
/**
|
||||
* The X coordinate of this point.
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
public $x;
|
||||
|
||||
/**
|
||||
* The Y coordinate of this point.
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
public $y;
|
||||
|
||||
/**
|
||||
* Gets a string representation of the point.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->x + ", " + $this->y;
|
||||
}
|
||||
}
|
||||
60
vendor/jdenticon/jdenticon/src/Rendering/Rectangle.php
vendored
Normal file
60
vendor/jdenticon/jdenticon/src/Rendering/Rectangle.php
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Rendering;
|
||||
|
||||
/**
|
||||
* Specifies the bounds of a 2D rectangle.
|
||||
*/
|
||||
class Rectangle
|
||||
{
|
||||
/**
|
||||
* The X coordinate of the left side of the rectangle.
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
public $x;
|
||||
|
||||
/**
|
||||
* The Y coordinate of the top side of the rectangle.
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
public $y;
|
||||
|
||||
/**
|
||||
* The width of the rectangle.
|
||||
* @var float
|
||||
*/
|
||||
public $width;
|
||||
|
||||
/**
|
||||
* The height of the rectangle.
|
||||
* @var float
|
||||
*/
|
||||
public $height;
|
||||
|
||||
/**
|
||||
* Creates a new Rectangle.
|
||||
*
|
||||
* @param float $x The X coordinate of the left edge of the rectangle.
|
||||
* @param float $y The Y coordinate of the top edge of the rectangle.
|
||||
* @param float $width The width of the rectangle.
|
||||
* @param float $height The height of the rectangle.
|
||||
*/
|
||||
public function __construct($x, $y, $width, $height)
|
||||
{
|
||||
$this->x = $x;
|
||||
$this->y = $y;
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
}
|
||||
}
|
||||
141
vendor/jdenticon/jdenticon/src/Rendering/RendererInterface.php
vendored
Normal file
141
vendor/jdenticon/jdenticon/src/Rendering/RendererInterface.php
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Rendering;
|
||||
|
||||
use Jdenticon\Color;
|
||||
|
||||
/**
|
||||
* Interface for an identicon renderer.
|
||||
*/
|
||||
interface RendererInterface
|
||||
{
|
||||
/**
|
||||
* Sets the current transform that will be applied on all coordinates before
|
||||
* being rendered to the target image.
|
||||
*
|
||||
* @param \Jdenticon\Rendering\Transform $transform The transform to set.
|
||||
* If NULL is specified any existing transform is removed.
|
||||
*/
|
||||
public function setTransform(\Jdenticon\Rendering\Transform $transform);
|
||||
|
||||
/**
|
||||
* Gets the current transform that will be applied on all coordinates before
|
||||
* being rendered to the target image.
|
||||
*
|
||||
* @return \Jdenticon\Rendering\Transform
|
||||
*/
|
||||
public function getTransform();
|
||||
|
||||
/**
|
||||
* Sets the background color of the image.
|
||||
*
|
||||
* @param \Jdenticon\Color $color The image background color.
|
||||
*/
|
||||
public function setBackgroundColor(Color $color);
|
||||
|
||||
/**
|
||||
* Gets the background color of the image.
|
||||
*
|
||||
* @return \Jdenticon\Color
|
||||
*/
|
||||
public function getBackgroundColor();
|
||||
|
||||
/**
|
||||
* Gets the MIME type of the renderer output.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMimeType();
|
||||
|
||||
/**
|
||||
* Begins a new shape. The shape should be ended with a call to endShape.
|
||||
*
|
||||
* @param \Jdenticon\Color $color The color of the shape.
|
||||
*/
|
||||
public function beginShape(Color $color);
|
||||
|
||||
/**
|
||||
* Ends the currently drawn shape.
|
||||
*/
|
||||
public function endShape();
|
||||
|
||||
/**
|
||||
* Adds a rectangle to the image.
|
||||
*
|
||||
* @param float $x The x-coordinate of the rectangle upper-left corner.
|
||||
* @param float $y The y-coordinate of the rectangle upper-left corner.
|
||||
* @param float $width The width of the rectangle.
|
||||
* @param float $height The height of the rectangle.
|
||||
* @param bool $invert If true the area of the rectangle will be removed
|
||||
* from the filled area.
|
||||
*/
|
||||
public function addRectangle($x, $y, $width, $height, $invert = false);
|
||||
|
||||
/**
|
||||
* Adds a circle to the image.
|
||||
*
|
||||
* @param float $x The x-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $y The y-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $size The size of the bounding rectangle.
|
||||
* @param bool $invert If true the area of the circle will be removed from
|
||||
* the filled area.
|
||||
*/
|
||||
public function addCircle($x, $y, $size, $invert = false);
|
||||
|
||||
/**
|
||||
* Adds a polygon to the image.
|
||||
*
|
||||
* @param array $points Array of points that the polygon consists of.
|
||||
* @param bool $invert If true the area of the polygon will be removed from
|
||||
* the filled area.
|
||||
*/
|
||||
public function addPolygon($points, $invert = false);
|
||||
|
||||
/**
|
||||
* Adds a triangle to the image.
|
||||
*
|
||||
* @param float $x The x-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $y The y-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $width The width of the bounding rectangle.
|
||||
* @param float $height The height of the bounding rectangle.
|
||||
* @param float $direction The direction of the 90 degree corner of
|
||||
* the triangle.
|
||||
* @param bool $invert If true the area of the triangle will be removed
|
||||
* from the filled area.
|
||||
*/
|
||||
public function addTriangle($x, $y, $width, $height, $direction, $invert = false);
|
||||
|
||||
/**
|
||||
* Adds a rhombus to the image.
|
||||
*
|
||||
* @param float $x The x-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $y The y-coordinate of the bounding rectangle
|
||||
* upper-left corner.
|
||||
* @param float $width The width of the bounding rectangle.
|
||||
* @param float $height The height of the bounding rectangle.
|
||||
* @param bool $invert If true the area of the rhombus will be removed
|
||||
* from the filled area.
|
||||
*/
|
||||
public function addRhombus($x, $y, $width, $height, $invert = false);
|
||||
|
||||
/**
|
||||
* Gets the output from the renderer.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getData();
|
||||
}
|
||||
83
vendor/jdenticon/jdenticon/src/Rendering/SvgPath.php
vendored
Normal file
83
vendor/jdenticon/jdenticon/src/Rendering/SvgPath.php
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is part of Jdenticon for PHP.
|
||||
* https://github.com/dmester/jdenticon-php/
|
||||
*
|
||||
* Copyright (c) 2018 Daniel Mester Pirttijärvi
|
||||
*
|
||||
* For full license information, please see the LICENSE file that was
|
||||
* distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Jdenticon\Rendering;
|
||||
|
||||
/**
|
||||
* Represents a SVG path element.
|
||||
*/
|
||||
class SvgPath
|
||||
{
|
||||
private $dataString;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->dataString = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a circle to the SVG.
|
||||
*
|
||||
* @param float $x X coordinate of the left side of the containing rectangle.
|
||||
* @param float $y Y coordinate of the top side of the containing rectangle.
|
||||
* @param float $size The diameter of the circle.
|
||||
* @param bool $counterClockwise If true the circle will be drawn counter
|
||||
* clockwise. This affects the rendering since the evenodd filling rule
|
||||
* is used by Jdenticon.
|
||||
*/
|
||||
public function addCircle($x, $y, $size, $counterClockwise)
|
||||
{
|
||||
$sweepFlag = $counterClockwise ? '0' : '1';
|
||||
$radiusAsString = number_format($size / 2, 2, '.', '');
|
||||
|
||||
$this->dataString .=
|
||||
'M'. number_format($x, 2, '.', '') .' '.
|
||||
number_format($y + $size / 2, 2, '.', '').
|
||||
'a'. $radiusAsString .','. $radiusAsString .' 0 1,'.
|
||||
$sweepFlag .' '. number_format($size, 2, '.', '') .',0'.
|
||||
'a'. $radiusAsString .','. $radiusAsString .' 0 1,'.
|
||||
$sweepFlag .' '. number_format(-$size, 2, '.', '') .',0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a polygon to the SVG.
|
||||
*
|
||||
* @param array(\Jdenticon\Rendering\Point) $points The corners of the
|
||||
* polygon.
|
||||
*/
|
||||
public function addPolygon($points)
|
||||
{
|
||||
$pointCount = count($points);
|
||||
|
||||
$this->dataString .= 'M'.
|
||||
number_format($points[0]->x, 2, '.', '') .' '.
|
||||
number_format($points[0]->y, 2, '.', '');
|
||||
|
||||
for ($i = 1; $i < $pointCount; $i++) {
|
||||
$this->dataString .= 'L'.
|
||||
number_format($points[$i]->x, 2, '.', '') .' '.
|
||||
number_format($points[$i]->y, 2, '.', '');
|
||||
}
|
||||
|
||||
$this->dataString .= 'Z';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path as a SVG path string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->dataString;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user