Compare commits
112 Commits
1.3.5
...
siftleft-s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79c0ad1670 | ||
|
|
93138cbbae | ||
|
|
fc5e380ccc | ||
|
|
33587d54e4 | ||
|
|
d355bb87e3 | ||
|
|
52b9b257c3 | ||
|
|
b939b64778 | ||
|
|
342270d6dd | ||
|
|
dae093bbfa | ||
|
|
7de12d64d5 | ||
|
|
b6460616ba | ||
|
|
7a1de52e05 | ||
|
|
91c8f9f23c | ||
|
|
84771d7167 | ||
|
|
3dd01b1f70 | ||
|
|
89f6f0051d | ||
|
|
194b27e685 | ||
|
|
e32e3979a8 | ||
|
|
af5a14afc3 | ||
|
|
5812a6bb68 | ||
|
|
f339c0b1c0 | ||
|
|
502bb5fa15 | ||
|
|
89bdc92451 | ||
|
|
63d6816c7c | ||
|
|
e572e9c79c | ||
|
|
2b0ebdb6c7 | ||
|
|
3a06d5a745 | ||
|
|
12aa325494 | ||
|
|
a806a6455e | ||
|
|
4296b43832 | ||
|
|
c3ad4a4b4d | ||
|
|
805eb288d9 | ||
|
|
b21efd8336 | ||
|
|
7d82c82fd9 | ||
|
|
3f92d4c038 | ||
|
|
377d7d565b | ||
|
|
e6def62581 | ||
|
|
17c1284ccf | ||
|
|
0a9cd05453 | ||
|
|
2b8534d49e | ||
|
|
472bf520d8 | ||
|
|
4d3a2ae946 | ||
|
|
4c329be95f | ||
|
|
b47b8cf050 | ||
|
|
1b8351fef9 | ||
|
|
d0c6ab224f | ||
|
|
53e23b7422 | ||
|
|
010f9db274 | ||
|
|
c2c0980c57 | ||
|
|
fcb6422663 | ||
|
|
993abd746e | ||
|
|
30228cc33c | ||
|
|
14ff704b28 | ||
|
|
cd1b0e0a50 | ||
|
|
4a73afa057 | ||
|
|
63d20330b4 | ||
|
|
982a4f957c | ||
|
|
67fd327df4 | ||
|
|
db0db4ebff | ||
|
|
4514f1f3a4 | ||
|
|
926fab30e9 | ||
|
|
492cdc9926 | ||
|
|
6b5e7c1b49 | ||
|
|
2bc7e8e38f | ||
|
|
48916d5df7 | ||
|
|
0887f567ab | ||
|
|
3e4def2069 | ||
|
|
39867d8151 | ||
|
|
c7a86ebd5c | ||
|
|
56d993ca82 | ||
|
|
45b3ec4ac6 | ||
|
|
9bd04c55c9 | ||
|
|
dd4633ff8f | ||
|
|
c0207d00a2 | ||
|
|
bd83415c82 | ||
|
|
478f806e9c | ||
|
|
db402baa14 | ||
|
|
dac5bd1d93 | ||
|
|
4b2f2920a2 | ||
|
|
83620d7eb5 | ||
|
|
de4abad748 | ||
|
|
3ca01024fd | ||
|
|
5809a7cfa7 | ||
|
|
0e78534e48 | ||
|
|
b68ae363ec | ||
|
|
3181cfe58a | ||
|
|
bc11452259 | ||
|
|
853a4f386f | ||
|
|
9683c591bb | ||
|
|
47029fb04e | ||
|
|
735a77b783 | ||
|
|
5f4200c721 | ||
|
|
9b893f09d7 | ||
|
|
3b9b6c948f | ||
|
|
7b7a32c0a7 | ||
|
|
fd7d05e862 | ||
|
|
8232dce395 | ||
|
|
6f3bb25b09 | ||
|
|
1dc8b24665 | ||
|
|
ed66351337 | ||
|
|
9e6eb50ced | ||
|
|
d727837324 | ||
|
|
175d14224e | ||
|
|
51f1f67fe8 | ||
|
|
ab250d8686 | ||
|
|
1ff8637c23 | ||
|
|
727166e945 | ||
|
|
e50f3eb311 | ||
|
|
f5fa37b5f2 | ||
|
|
587822838a | ||
|
|
553417194c | ||
|
|
8a08a2167b |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -16,6 +16,7 @@ js/test/ export-ignore
|
|||||||
.jshintrc export-ignore
|
.jshintrc export-ignore
|
||||||
.nsprc export-ignore
|
.nsprc export-ignore
|
||||||
.php_cs export-ignore
|
.php_cs export-ignore
|
||||||
|
.scrutinizer.yml export-ignore
|
||||||
.styleci.yml export-ignore
|
.styleci.yml export-ignore
|
||||||
.travis.yml export-ignore
|
.travis.yml export-ignore
|
||||||
composer.json export-ignore
|
composer.json export-ignore
|
||||||
|
|||||||
35
.github/workflows/shiftleft-analysis.yml
vendored
Normal file
35
.github/workflows/shiftleft-analysis.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# This workflow integrates Scan with GitHub's code scanning feature
|
||||||
|
# Scan is a free open-source security tool for modern DevOps teams from ShiftLeft
|
||||||
|
# Visit https://slscan.io/en/latest/integrations/code-scan for help
|
||||||
|
name: SL Scan
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ master ]
|
||||||
|
schedule:
|
||||||
|
- cron: '16 22 * * 4'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Scan-Build:
|
||||||
|
# Scan runs on ubuntu, mac and windows
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
# potentially add composer install steo here
|
||||||
|
- name: Perform Scan
|
||||||
|
uses: ShiftLeftSecurity/scan-action@master
|
||||||
|
env:
|
||||||
|
WORKSPACE: ""
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
SCAN_AUTO_BUILD: true
|
||||||
|
with:
|
||||||
|
output: reports
|
||||||
|
# Scan auto-detects the languages.
|
||||||
|
|
||||||
|
- name: Upload report
|
||||||
|
uses: github/codeql-action/upload-sarif@v1
|
||||||
|
with:
|
||||||
|
sarif_file: reports
|
||||||
4
.github/workflows/tests.yml
vendored
4
.github/workflows/tests.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
|||||||
- name: Validate composer.json and composer.lock
|
- name: Validate composer.json and composer.lock
|
||||||
run: composer validate
|
run: composer validate
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: /usr/bin/php7.4 $(which composer) install --prefer-dist --no-suggest
|
run: composer install --prefer-dist --no-dev
|
||||||
PHPunit:
|
PHPunit:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
@@ -29,6 +29,8 @@ jobs:
|
|||||||
run: rm composer.lock
|
run: rm composer.lock
|
||||||
- name: Setup PHPunit
|
- name: Setup PHPunit
|
||||||
run: composer install -n
|
run: composer install -n
|
||||||
|
- name: Install Google Cloud Storage
|
||||||
|
run: composer require google/cloud-storage
|
||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
run: ../vendor/bin/phpunit --no-coverage
|
run: ../vendor/bin/phpunit --no-coverage
|
||||||
working-directory: tst
|
working-directory: tst
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -6,7 +6,7 @@ cfg/*
|
|||||||
!cfg/.htaccess
|
!cfg/.htaccess
|
||||||
|
|
||||||
# Ignore data/
|
# Ignore data/
|
||||||
data/
|
/data/
|
||||||
|
|
||||||
# Ignore PhpDoc
|
# Ignore PhpDoc
|
||||||
doc/*
|
doc/*
|
||||||
@@ -36,3 +36,5 @@ tst/ConfigurationCombinationsTest.php
|
|||||||
.project
|
.project
|
||||||
.externalToolBuilders
|
.externalToolBuilders
|
||||||
.c9
|
.c9
|
||||||
|
/.idea/
|
||||||
|
*.iml
|
||||||
|
|||||||
36
.scrutinizer.yml
Normal file
36
.scrutinizer.yml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
checks:
|
||||||
|
php: true
|
||||||
|
javascript: true
|
||||||
|
filter:
|
||||||
|
paths:
|
||||||
|
- "css/privatebin.css"
|
||||||
|
- "css/bootstrap/privatebin.css"
|
||||||
|
- "js/privatebin.js"
|
||||||
|
- "lib/*.php"
|
||||||
|
- "index.php"
|
||||||
|
coding_style:
|
||||||
|
php:
|
||||||
|
spaces:
|
||||||
|
around_operators:
|
||||||
|
additive: false
|
||||||
|
concatenation: true
|
||||||
|
build:
|
||||||
|
environment:
|
||||||
|
php:
|
||||||
|
version: '7.2'
|
||||||
|
tests:
|
||||||
|
override:
|
||||||
|
-
|
||||||
|
command: 'composer require google/cloud-storage && cd tst && ../vendor/bin/phpunit'
|
||||||
|
coverage:
|
||||||
|
file: 'tst/log/coverage-clover.xml'
|
||||||
|
format: 'clover'
|
||||||
|
nodes:
|
||||||
|
tests: true
|
||||||
|
analysis:
|
||||||
|
tests:
|
||||||
|
override:
|
||||||
|
-
|
||||||
|
command: phpcs-run
|
||||||
|
use_website_config: true
|
||||||
|
- php-scrutinizer-run
|
||||||
@@ -1,6 +1,14 @@
|
|||||||
# PrivateBin version history
|
# PrivateBin version history
|
||||||
|
|
||||||
* **1.4 (not yet released)**
|
* **1.4 (not yet released)**
|
||||||
|
* ADDED: Translation for Estonian
|
||||||
|
* ADDED: new HTTP headers improving security (#765)
|
||||||
|
* ADDED: Download button for paste text (#774)
|
||||||
|
* ADDED: Opt-out of federated learning of cohorts (FLoC) (#776)
|
||||||
|
* ADDED: Configuration option to exempt IPs from the rate-limiter (#787)
|
||||||
|
* ADDED: Google Cloud Storage backend support (#795)
|
||||||
|
* CHANGED: Language selection cookie only transmitted over HTTPS (#472)
|
||||||
|
* CHANGED: Upgrading libraries to: random_compat 2.0.20
|
||||||
* **1.3.5 (2021-04-05)**
|
* **1.3.5 (2021-04-05)**
|
||||||
* ADDED: Translation for Hebrew, Lithuanian, Indonesian and Catalan
|
* ADDED: Translation for Hebrew, Lithuanian, Indonesian and Catalan
|
||||||
* ADDED: Make the project info configurable (#681)
|
* ADDED: Make the project info configurable (#681)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ Sébastien Sauvage - original idea and main developer
|
|||||||
* Alexey Gladkov - syntax highlighting
|
* Alexey Gladkov - syntax highlighting
|
||||||
* Greg Knaddison - robots.txt
|
* Greg Knaddison - robots.txt
|
||||||
* MrKooky - HTML5 markup, CSS cleanup
|
* MrKooky - HTML5 markup, CSS cleanup
|
||||||
* Simon Rupf - WebCrypto, unit tests, current docker containers, MVC, configuration, i18n
|
* Simon Rupf - WebCrypto, unit tests, containers images, database backend, MVC, configuration, i18n
|
||||||
* Hexalyse - Password protection
|
* Hexalyse - Password protection
|
||||||
* Viktor Stanchev - File upload support
|
* Viktor Stanchev - File upload support
|
||||||
* azlux - Tab character input support
|
* azlux - Tab character input support
|
||||||
@@ -27,6 +27,8 @@ Sébastien Sauvage - original idea and main developer
|
|||||||
* Harald Leithner - base58 encoding of key
|
* Harald Leithner - base58 encoding of key
|
||||||
* Haocen - lots of bugfixes and UI improvements
|
* Haocen - lots of bugfixes and UI improvements
|
||||||
* Lucas Savva - configurable config file location, NixOS packaging
|
* Lucas Savva - configurable config file location, NixOS packaging
|
||||||
|
* rodehoed - option to exempt ips from the rate-limiter
|
||||||
|
* Mark van Holsteijn - Google Cloud Storage backend
|
||||||
|
|
||||||
## Translations
|
## Translations
|
||||||
* Hexalyse - French
|
* Hexalyse - French
|
||||||
@@ -50,3 +52,4 @@ Sébastien Sauvage - original idea and main developer
|
|||||||
* Moo - Lithuanian
|
* Moo - Lithuanian
|
||||||
* whenwesober - Indonesian
|
* whenwesober - Indonesian
|
||||||
* retiolus - Catalan
|
* retiolus - Catalan
|
||||||
|
* sarnane - Estonian
|
||||||
|
|||||||
19
INSTALL.md
19
INSTALL.md
@@ -190,4 +190,21 @@ CREATE TABLE prefix_config (
|
|||||||
INSERT INTO prefix_config VALUES('VERSION', '1.3.5');
|
INSERT INTO prefix_config VALUES('VERSION', '1.3.5');
|
||||||
```
|
```
|
||||||
|
|
||||||
In **PostgreSQL**, the data, attachment, nickname and vizhash columns needs to be TEXT and not BLOB or MEDIUMBLOB.
|
In **PostgreSQL**, the data, attachment, nickname and vizhash columns needs to
|
||||||
|
be TEXT and not BLOB or MEDIUMBLOB.
|
||||||
|
|
||||||
|
### Using Google Cloud Storage
|
||||||
|
If you want to deploy PrivateBin in a serverless manner in the Google Cloud, you
|
||||||
|
can choose the `GoogleCloudStorage` as backend. To use this backend, you create
|
||||||
|
a GCS bucket and specify the name as the model option `bucket`. Alternatively,
|
||||||
|
you can set the name through the environment variable PASTEBIN_GCS_BUCKET.
|
||||||
|
|
||||||
|
The default prefix for pastes stored in the bucket is `pastes`. To change the
|
||||||
|
prefix, specify the option `prefix`.
|
||||||
|
|
||||||
|
Google Cloud Storage buckets may be significantly slower than a `FileSystem` or
|
||||||
|
`Database` backend. The big advantage is that the deployment on Google Cloud
|
||||||
|
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`.
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ languageselection = false
|
|||||||
; async functions and display an error if not and for Chrome to enable
|
; async functions and display an error if not and for Chrome to enable
|
||||||
; webassembly support (used for zlib compression). You can remove it if Chrome
|
; webassembly support (used for zlib compression). You can remove it if Chrome
|
||||||
; doesn't need to be supported and old browsers don't need to be warned.
|
; doesn't need to be supported and old browsers don't need to be warned.
|
||||||
; cspheader = "default-src 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'unsafe-eval' resource:; style-src 'self'; font-src 'self'; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-downloads"
|
; cspheader = "default-src 'none'; base-uri 'self'; form-action 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'unsafe-eval' resource:; style-src 'self'; font-src 'self'; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-downloads"
|
||||||
|
|
||||||
; stay compatible with PrivateBin Alpha 0.19, less secure
|
; stay compatible with PrivateBin Alpha 0.19, less secure
|
||||||
; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of
|
; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of
|
||||||
@@ -135,6 +135,10 @@ markdown = "Markdown"
|
|||||||
; Set this to 0 to disable rate limiting.
|
; Set this to 0 to disable rate limiting.
|
||||||
limit = 10
|
limit = 10
|
||||||
|
|
||||||
|
; Set ips (v4|v6) which should be exempted for the rate-limit. CIDR also supported. Needed to be comma separated.
|
||||||
|
; Unset for enabling and invalid values will be ignored
|
||||||
|
; eg: exemptedIp = '1.2.3.4,10.10.10/24'
|
||||||
|
|
||||||
; (optional) if your website runs behind a reverse proxy or load balancer,
|
; (optional) if your website runs behind a reverse proxy or load balancer,
|
||||||
; set the HTTP header containing the visitors IP address, i.e. X_FORWARDED_FOR
|
; set the HTTP header containing the visitors IP address, i.e. X_FORWARDED_FOR
|
||||||
; header = "X_FORWARDED_FOR"
|
; header = "X_FORWARDED_FOR"
|
||||||
@@ -163,6 +167,13 @@ class = Filesystem
|
|||||||
[model_options]
|
[model_options]
|
||||||
dir = PATH "data"
|
dir = PATH "data"
|
||||||
|
|
||||||
|
[model]
|
||||||
|
; example of a Google Cloud Storage configuration
|
||||||
|
;class = GoogleCloudStorage
|
||||||
|
;[model_options]
|
||||||
|
;bucket = "my-private-bin"
|
||||||
|
;prefix = "pastes"
|
||||||
|
|
||||||
;[model]
|
;[model]
|
||||||
; example of DB configuration for MySQL
|
; example of DB configuration for MySQL
|
||||||
;class = Database
|
;class = Database
|
||||||
|
|||||||
@@ -25,8 +25,12 @@
|
|||||||
},
|
},
|
||||||
"require" : {
|
"require" : {
|
||||||
"php" : "^5.6.0 || ^7.0 || ^8.0",
|
"php" : "^5.6.0 || ^7.0 || ^8.0",
|
||||||
"paragonie/random_compat" : "2.0.19",
|
"paragonie/random_compat" : "2.0.20",
|
||||||
"yzalis/identicon" : "2.0.0"
|
"yzalis/identicon" : "2.0.0",
|
||||||
|
"mlocati/ip-lib" : "1.14.0"
|
||||||
|
},
|
||||||
|
"suggest" : {
|
||||||
|
"google/cloud-storage" : "1.23.1"
|
||||||
},
|
},
|
||||||
"require-dev" : {
|
"require-dev" : {
|
||||||
"phpunit/phpunit" : "^4.6 || ^5.0"
|
"phpunit/phpunit" : "^4.6 || ^5.0"
|
||||||
|
|||||||
106
composer.lock
generated
106
composer.lock
generated
@@ -4,20 +4,88 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "9d110873bf15a6abd66734e8a818134c",
|
"content-hash": "217f0ba9bdac1014a332a8ba390be949",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "paragonie/random_compat",
|
"name": "mlocati/ip-lib",
|
||||||
"version": "v2.0.19",
|
"version": "1.14.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/paragonie/random_compat.git",
|
"url": "https://github.com/mlocati/ip-lib.git",
|
||||||
"reference": "446fc9faa5c2a9ddf65eb7121c0af7e857295241"
|
"reference": "882bc0e115970a536b13bcfa59f312783fce08c8"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/446fc9faa5c2a9ddf65eb7121c0af7e857295241",
|
"url": "https://api.github.com/repos/mlocati/ip-lib/zipball/882bc0e115970a536b13bcfa59f312783fce08c8",
|
||||||
"reference": "446fc9faa5c2a9ddf65eb7121c0af7e857295241",
|
"reference": "882bc0e115970a536b13bcfa59f312783fce08c8",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"ext-pdo_sqlite": "*",
|
||||||
|
"phpunit/dbunit": "^1.4 || ^2 || ^3 || ^4",
|
||||||
|
"phpunit/phpunit": "^4.8 || ^5.7 || ^6.5"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"IPLib\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Michele Locati",
|
||||||
|
"email": "mlocati@gmail.com",
|
||||||
|
"homepage": "https://github.com/mlocati",
|
||||||
|
"role": "Author"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Handle IPv4, IPv6 addresses and ranges",
|
||||||
|
"homepage": "https://github.com/mlocati/ip-lib",
|
||||||
|
"keywords": [
|
||||||
|
"IP",
|
||||||
|
"address",
|
||||||
|
"addresses",
|
||||||
|
"ipv4",
|
||||||
|
"ipv6",
|
||||||
|
"manage",
|
||||||
|
"managing",
|
||||||
|
"matching",
|
||||||
|
"network",
|
||||||
|
"networking",
|
||||||
|
"range",
|
||||||
|
"subnet"
|
||||||
|
],
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/sponsors/mlocati",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://paypal.me/mlocati",
|
||||||
|
"type": "other"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2020-12-31T11:30:02+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "paragonie/random_compat",
|
||||||
|
"version": "v2.0.20",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/paragonie/random_compat.git",
|
||||||
|
"reference": "0f1f60250fccffeaf5dda91eea1c018aed1adc2a"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/0f1f60250fccffeaf5dda91eea1c018aed1adc2a",
|
||||||
|
"reference": "0f1f60250fccffeaf5dda91eea1c018aed1adc2a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -53,7 +121,7 @@
|
|||||||
"pseudorandom",
|
"pseudorandom",
|
||||||
"random"
|
"random"
|
||||||
],
|
],
|
||||||
"time": "2020-10-15T10:06:57+00:00"
|
"time": "2021-04-17T09:33:01+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "yzalis/identicon",
|
"name": "yzalis/identicon",
|
||||||
@@ -1351,16 +1419,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-ctype",
|
"name": "symfony/polyfill-ctype",
|
||||||
"version": "v1.22.1",
|
"version": "v1.23.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||||
"reference": "c6c942b1ac76c82448322025e084cadc56048b4e"
|
"reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e",
|
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce",
|
||||||
"reference": "c6c942b1ac76c82448322025e084cadc56048b4e",
|
"reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -1372,7 +1440,7 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-main": "1.22-dev"
|
"dev-main": "1.23-dev"
|
||||||
},
|
},
|
||||||
"thanks": {
|
"thanks": {
|
||||||
"name": "symfony/polyfill",
|
"name": "symfony/polyfill",
|
||||||
@@ -1423,20 +1491,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-01-07T16:49:33+00:00"
|
"time": "2021-02-19T12:13:01+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/yaml",
|
"name": "symfony/yaml",
|
||||||
"version": "v4.4.21",
|
"version": "v4.4.24",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/yaml.git",
|
"url": "https://github.com/symfony/yaml.git",
|
||||||
"reference": "3871c720871029f008928244e56cf43497da7e9d"
|
"reference": "8b6d1b97521e2f125039b3fcb4747584c6dfa0ef"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/3871c720871029f008928244e56cf43497da7e9d",
|
"url": "https://api.github.com/repos/symfony/yaml/zipball/8b6d1b97521e2f125039b3fcb4747584c6dfa0ef",
|
||||||
"reference": "3871c720871029f008928244e56cf43497da7e9d",
|
"reference": "8b6d1b97521e2f125039b3fcb4747584c6dfa0ef",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -1491,7 +1559,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-03-05T17:58:50+00:00"
|
"time": "2021-05-16T09:52:47+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "webmozart/assert",
|
"name": "webmozart/assert",
|
||||||
|
|||||||
@@ -249,6 +249,10 @@ button img {
|
|||||||
padding: 1px 0 1px 0;
|
padding: 1px 0 1px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#downloadtextbutton img {
|
||||||
|
padding: 1px 0 1px 0;
|
||||||
|
}
|
||||||
|
|
||||||
#remainingtime, #password {
|
#remainingtime, #password {
|
||||||
color: #94a3b4;
|
color: #94a3b4;
|
||||||
display: inline;
|
display: inline;
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Schliessen",
|
"Close": "Schliessen",
|
||||||
"Encrypted note on PrivateBin": "Verschlüsselte Notiz auf PrivateBin",
|
"Encrypted note on PrivateBin": "Verschlüsselte Notiz auf PrivateBin",
|
||||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Besuche diese Verknüpfung um das Dokument zu sehen. Wird die URL an eine andere Person gegeben, so kann diese Person ebenfalls auf dieses Dokument zugreifen.",
|
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Besuche diese Verknüpfung 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."
|
"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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Cerrar",
|
"Close": "Cerrar",
|
||||||
"Encrypted note on PrivateBin": "Nota cifrada en PrivateBin",
|
"Encrypted note on PrivateBin": "Nota cifrada en PrivateBin",
|
||||||
"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.",
|
"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.": "URL shortener may expose your decrypt key in URL."
|
"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\""
|
||||||
}
|
}
|
||||||
|
|||||||
189
i18n/et.json
Normal file
189
i18n/et.json
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
{
|
||||||
|
"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 on minimalistlik, avatud lähtekoodiga online pastebin, kus serveril pole kleebitud andmete kohta teadmist. Andmed krüpteeritakse/dekrüpteeritakse %sbrauseris%s kasutades 256-bitist AES-i.",
|
||||||
|
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "Lisateave <a href=\"https://privatebin.info/\">projekti lehel</a>.",
|
||||||
|
"Because ignorance is bliss": "Kuna teadmatus on õndsus",
|
||||||
|
"en": "et",
|
||||||
|
"Paste does not exist, has expired or has been deleted.": "Kleebet ei eksisteeri, on aegunud või on kustutatud.",
|
||||||
|
"%s requires php %s or above to work. Sorry.": "%s vajab, et oleks php %s või kõrgem, et töötada. Vabandame.",
|
||||||
|
"%s requires configuration section [%s] to be present in configuration file.": "%s vajab, et [%s] seadistamise jaotis oleks olemas konfiguratsioonifailis.",
|
||||||
|
"Please wait %d seconds between each post.": [
|
||||||
|
"Palun oota %d sekund iga postituse vahel.",
|
||||||
|
"Palun oota %d sekundit iga postituse vahel.",
|
||||||
|
"Palun oota %d sekundit iga postituse vahel.",
|
||||||
|
"Palun oota %d sekundit iga postituse vahel."
|
||||||
|
],
|
||||||
|
"Paste is limited to %s of encrypted data.": "Kleepe limiit on %s krüpteeritud andmeid.",
|
||||||
|
"Invalid data.": "Valed andmed.",
|
||||||
|
"You are unlucky. Try again.": "Sul ei vea. Proovi uuesti.",
|
||||||
|
"Error saving comment. Sorry.": "Viga kommentaari salvestamisel. Vabandame.",
|
||||||
|
"Error saving paste. Sorry.": "Viga kleepe salvestamisel. Vabandame.",
|
||||||
|
"Invalid paste ID.": "Vale kleepe ID.",
|
||||||
|
"Paste is not of burn-after-reading type.": "Kleebe ei ole põleta-pärast-lugemist tüüpi.",
|
||||||
|
"Wrong deletion token. Paste was not deleted.": "Vale kustutamiskood. Kleebet ei kustutatud.",
|
||||||
|
"Paste was properly deleted.": "Kleebe kustutati korralikult.",
|
||||||
|
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript on vajalik %s'i töötamiseks. Vabandame ebamugavuste pärast.",
|
||||||
|
"%s requires a modern browser to work.": "%s vajab töötamiseks kaasaegset brauserit.",
|
||||||
|
"New": "Uus",
|
||||||
|
"Send": "Saada",
|
||||||
|
"Clone": "Klooni",
|
||||||
|
"Raw text": "Lähtetekst",
|
||||||
|
"Expires": "Aegub",
|
||||||
|
"Burn after reading": "Põleta pärast lugemist",
|
||||||
|
"Open discussion": "Avatud arutelu",
|
||||||
|
"Password (recommended)": "Parool (soovitatav)",
|
||||||
|
"Discussion": "Arutelu",
|
||||||
|
"Toggle navigation": "Näita menüüd",
|
||||||
|
"%d seconds": [
|
||||||
|
"%d sekund",
|
||||||
|
"%d sekundit",
|
||||||
|
"%d sekundit",
|
||||||
|
"%d sekundit"
|
||||||
|
],
|
||||||
|
"%d minutes": [
|
||||||
|
"%d minut",
|
||||||
|
"%d minutit",
|
||||||
|
"%d minutit",
|
||||||
|
"%d minutit"
|
||||||
|
],
|
||||||
|
"%d hours": [
|
||||||
|
"%d tund",
|
||||||
|
"%d tundi",
|
||||||
|
"%d tundi",
|
||||||
|
"%d tundi"
|
||||||
|
],
|
||||||
|
"%d days": [
|
||||||
|
"%d päev",
|
||||||
|
"%d päeva",
|
||||||
|
"%d päeva",
|
||||||
|
"%d päeva"
|
||||||
|
],
|
||||||
|
"%d weeks": [
|
||||||
|
"%d nädal",
|
||||||
|
"%d nädalat",
|
||||||
|
"%d nädalat",
|
||||||
|
"%d nädalat"
|
||||||
|
],
|
||||||
|
"%d months": [
|
||||||
|
"%d kuu",
|
||||||
|
"%d kuud",
|
||||||
|
"%d kuud",
|
||||||
|
"%d kuud"
|
||||||
|
],
|
||||||
|
"%d years": [
|
||||||
|
"%d aasta",
|
||||||
|
"%d aastat",
|
||||||
|
"%d aastat",
|
||||||
|
"%d aastat"
|
||||||
|
],
|
||||||
|
"Never": "Mitte kunagi",
|
||||||
|
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Märge: See on testimisteenus: Andmeid võidakse igal ajal kustutada. Kiisupojad hukuvad, kui seda teenust kuritarvitad.",
|
||||||
|
"This document will expire in %d seconds.": [
|
||||||
|
"See dokument aegub %d sekundi pärast.",
|
||||||
|
"See dokument aegub %d sekundi pärast.",
|
||||||
|
"See dokument aegub %d sekundi pärast.",
|
||||||
|
"See dokument aegub %d sekundi pärast."
|
||||||
|
],
|
||||||
|
"This document will expire in %d minutes.": [
|
||||||
|
"See dokument aegub %d minuti pärast.",
|
||||||
|
"See dokument aegub %d minuti pärast.",
|
||||||
|
"See dokument aegub %d minuti pärast.",
|
||||||
|
"See dokument aegub %d minuti pärast."
|
||||||
|
],
|
||||||
|
"This document will expire in %d hours.": [
|
||||||
|
"See dokument aegub %d tunni pärast.",
|
||||||
|
"See dokument aegub %d tunni pärast.",
|
||||||
|
"See dokument aegub %d tunni pärast.",
|
||||||
|
"See dokument aegub %d tunni pärast."
|
||||||
|
],
|
||||||
|
"This document will expire in %d days.": [
|
||||||
|
"See dokument aegub %d päeva pärast.",
|
||||||
|
"See dokument aegub %d päeva pärast.",
|
||||||
|
"See dokument aegub %d päeva pärast.",
|
||||||
|
"See dokument aegub %d päeva pärast."
|
||||||
|
],
|
||||||
|
"This document will expire in %d months.": [
|
||||||
|
"See dokument aegub %d kuu pärast.",
|
||||||
|
"See dokument aegub %d kuu pärast.",
|
||||||
|
"See dokument aegub %d kuu pärast.",
|
||||||
|
"See dokument aegub %d kuu pärast."
|
||||||
|
],
|
||||||
|
"Please enter the password for this paste:": "Palun sisesta selle kleepe parool:",
|
||||||
|
"Could not decrypt data (Wrong key?)": "Ei suutnud andmeid dekrüpteerida (Vale võti?)",
|
||||||
|
"Could not delete the paste, it was not stored in burn after reading mode.": "Ei suutnud kleebet kustutada, seda ei salvestatud põleta pärast lugemist režiimis.",
|
||||||
|
"FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "AINULT SINU SILMADELE. Ära sulge seda akent, seda sõnumit ei saa enam kuvada.",
|
||||||
|
"Could not decrypt comment; Wrong key?": "Ei suutnud kommentaari dekrüpteerida; Vale võti?",
|
||||||
|
"Reply": "Vasta",
|
||||||
|
"Anonymous": "Anonüümne",
|
||||||
|
"Avatar generated from IP address": "Avatar genereeritud IP aadressi põhjal",
|
||||||
|
"Add comment": "Lisa kommentaar",
|
||||||
|
"Optional nickname…": "Valikuline hüüdnimi…",
|
||||||
|
"Post comment": "Postita kommentaar",
|
||||||
|
"Sending comment…": "Kommentaari saatmine…",
|
||||||
|
"Comment posted.": "Kommentaar postitatud.",
|
||||||
|
"Could not refresh display: %s": "Ei suutnud kuva värskendada: %s",
|
||||||
|
"unknown status": "tundmatu staatus",
|
||||||
|
"server error or not responding": "serveri viga või ei vasta",
|
||||||
|
"Could not post comment: %s": "Ei suutnud kommentaari postitada: %s",
|
||||||
|
"Sending paste…": "Kleepe saatmine…",
|
||||||
|
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>": "Sinu kleebe on <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Kopeerimiseks vajuta [Ctrl]+[c])</span>",
|
||||||
|
"Delete data": "Kustuta andmed",
|
||||||
|
"Could not create paste: %s": "Ei suutnud kleebet luua: %s",
|
||||||
|
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Ei suutnud kleebet dekrüpteerida: Dekrüpteerimisvõti on URL-ist puudu (Kas kasutasid ümbersuunajat või URL-i lühendajat, mis eemaldab osa URL-ist?)",
|
||||||
|
"B": "B",
|
||||||
|
"KiB": "KiB",
|
||||||
|
"MiB": "MiB",
|
||||||
|
"GiB": "GiB",
|
||||||
|
"TiB": "TiB",
|
||||||
|
"PiB": "PiB",
|
||||||
|
"EiB": "EiB",
|
||||||
|
"ZiB": "ZiB",
|
||||||
|
"YiB": "YiB",
|
||||||
|
"Format": "Formaat",
|
||||||
|
"Plain Text": "Lihttekst",
|
||||||
|
"Source Code": "Lähtekood",
|
||||||
|
"Markdown": "Markdown",
|
||||||
|
"Download attachment": "Laadi manus alla",
|
||||||
|
"Cloned: '%s'": "Kloonitud: '%s'",
|
||||||
|
"The cloned file '%s' was attached to this paste.": "Kloonitud fail '%s' manustati sellele kleepele.",
|
||||||
|
"Attach a file": "Manusta fail",
|
||||||
|
"alternatively drag & drop a file or paste an image from the clipboard": "teise võimalusena lohista fail või kleebi pilt lõikelaualt",
|
||||||
|
"File too large, to display a preview. Please download the attachment.": "Fail on eelvaate kuvamiseks liiga suur. Palun laadi manus alla.",
|
||||||
|
"Remove attachment": "Eemalda manus",
|
||||||
|
"Your browser does not support uploading encrypted files. Please use a newer browser.": "Sinu brauser ei toeta krüpteeritud failide üleslaadimist. Palun kasuta uuemat brauserit.",
|
||||||
|
"Invalid attachment.": "Sobimatu manus.",
|
||||||
|
"Options": "Valikud",
|
||||||
|
"Shorten URL": "Lühenda URL",
|
||||||
|
"Editor": "Toimetaja",
|
||||||
|
"Preview": "Eelvaade",
|
||||||
|
"%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s vajab, et PATH lõppeks järgmisega: \"%s\". Palun uuenda PATH-i oma index.php failis.",
|
||||||
|
"Decrypt": "Dekrüpteeri",
|
||||||
|
"Enter password": "Sisesta parool",
|
||||||
|
"Loading…": "Laadimine…",
|
||||||
|
"Decrypting paste…": "Kleepe dekrüpteerimine…",
|
||||||
|
"Preparing new paste…": "Uue kleepe ettevalmistamine…",
|
||||||
|
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.": "Kui see sõnum ei kao, palun vaata <a href=\"%s\">seda KKK-d, et saada tõrkeotsinguks teavet.</a>.",
|
||||||
|
"+++ no paste text +++": "+++ kleepe tekst puudub +++",
|
||||||
|
"Could not get paste data: %s": "Ei suutnud saada kleepe andmeid: %s",
|
||||||
|
"QR code": "QR kood",
|
||||||
|
"This website is using an insecure HTTP connection! Please use it only for testing.": "See veebisait kasutab ebaturvalist HTTP ühendust! Palun kasuta seda ainult katsetamiseks.",
|
||||||
|
"For more information <a href=\"%s\">see this FAQ entry</a>.": "Lisateabe saamiseks <a href=\"%s\">vaata seda KKK sissekannet</a>.",
|
||||||
|
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Sinu brauser võib vajada HTTPS ühendust, et toetada WebCrypto API-d. Proovi <a href=\"%s\">üle minna HTTPS-ile</a>.",
|
||||||
|
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Sinu brauser ei toeta WebAssembly't, mida kasutatakse zlib tihendamiseks. Sa saad luua tihendamata dokumente, kuid ei saa lugeda tihendatuid.",
|
||||||
|
"waiting on user to provide a password": "ootan parooli sisestamist kasutajalt",
|
||||||
|
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Ei suutnud andmeid dekrüpteerida. Kas sisestasid vale parooli? Proovi uuesti üleval asuva nupuga.",
|
||||||
|
"Retry": "Proovi uuesti",
|
||||||
|
"Showing raw text…": "Lähteteksti näitamine…",
|
||||||
|
"Notice:": "Teade:",
|
||||||
|
"This link will expire after %s.": "See link aegub: %s.",
|
||||||
|
"This link can only be accessed once, do not use back or refresh button in your browser.": "Sellele lingile saab vaid üks kord ligi pääseda, ära kasuta tagasi või värskenda nuppe sinu brauseris.",
|
||||||
|
"Link:": "Link:",
|
||||||
|
"Recipient may become aware of your timezone, convert time to UTC?": "Saaja võib saada teada sinu ajavööndi, kas teisendada aeg UTC-ks?",
|
||||||
|
"Use Current Timezone": "Kasuta praegust ajavööndit",
|
||||||
|
"Convert To UTC": "Teisenda UTC-ks",
|
||||||
|
"Close": "Sulge",
|
||||||
|
"Encrypted note on PrivateBin": "Krüpteeritud kiri PrivateBin-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"
|
||||||
|
}
|
||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Fermer",
|
"Close": "Fermer",
|
||||||
"Encrypted note on PrivateBin": "Message chiffré sur PrivateBin",
|
"Encrypted note on PrivateBin": "Message chiffré sur PrivateBin",
|
||||||
"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.",
|
"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."
|
"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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "סגירה",
|
"Close": "סגירה",
|
||||||
"Encrypted note on PrivateBin": "הערה מוצפנת ב־PrivateBin",
|
"Encrypted note on PrivateBin": "הערה מוצפנת ב־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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Bezárás",
|
"Close": "Bezárás",
|
||||||
"Encrypted note on PrivateBin": "Titkosított jegyzet a PrivateBinen",
|
"Encrypted note on PrivateBin": "Titkosított jegyzet a PrivateBinen",
|
||||||
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
45
i18n/id.json
45
i18n/id.json
@@ -8,10 +8,10 @@
|
|||||||
"%s requires php %s or above to work. Sorry.": "%s memerlukan php %s atau versi diatasnya untuk dapat dijalankan. Maaf.",
|
"%s requires php %s or above to work. Sorry.": "%s memerlukan php %s atau versi diatasnya untuk dapat dijalankan. Maaf.",
|
||||||
"%s requires configuration section [%s] to be present in configuration file.": "%s membutuhkan bagian konfigurasi [%s] untuk ada di file konfigurasi.",
|
"%s requires configuration section [%s] to be present in configuration file.": "%s membutuhkan bagian konfigurasi [%s] untuk ada di file konfigurasi.",
|
||||||
"Please wait %d seconds between each post.": [
|
"Please wait %d seconds between each post.": [
|
||||||
"Silahkan menunggu %d detik antara masing-masing postingan. (tunggal)",
|
"Silahkan menunggu %d detik antara masing-masing postingan.",
|
||||||
"Silahkan menunggu %d detik antara masing-masing postingan. (jamak ke-1)",
|
"Silahkan menunggu %d detik antara masing-masing postingan.",
|
||||||
"Silahkan menunggu %d detik antara masing-masing postingan. (jamak ke-2)",
|
"Silahkan menunggu %d detik antara masing-masing postingan.",
|
||||||
"Silahkan menunggu %d detik antara masing-masing postingan. (jamak ke-3)"
|
"Silahkan menunggu %d detik antara masing-masing postingan."
|
||||||
],
|
],
|
||||||
"Paste is limited to %s of encrypted data.": "Paste dibatasi sampai %s dari data yang dienskripsi.",
|
"Paste is limited to %s of encrypted data.": "Paste dibatasi sampai %s dari data yang dienskripsi.",
|
||||||
"Invalid data.": "Data tidak valid.",
|
"Invalid data.": "Data tidak valid.",
|
||||||
@@ -35,31 +35,31 @@
|
|||||||
"Discussion": "Diskusi",
|
"Discussion": "Diskusi",
|
||||||
"Toggle navigation": "Alihkan navigasi",
|
"Toggle navigation": "Alihkan navigasi",
|
||||||
"%d seconds": [
|
"%d seconds": [
|
||||||
"%d detik (tunggal)",
|
"%d detik",
|
||||||
"%d detik (jamak ke-1)",
|
"%d detik",
|
||||||
"%d detik (jamak ke-2)",
|
"%d detik",
|
||||||
"%d detik (jamak ke-3)"
|
"%d detik"
|
||||||
],
|
],
|
||||||
"%d minutes": [
|
"%d minutes": [
|
||||||
"%d menit (tunggal)",
|
"%d menit",
|
||||||
"%d menit (jamak ke-1)",
|
"%d menit",
|
||||||
"%d menit (jamak ke-2)",
|
"%d menit",
|
||||||
"%d menit (jamak ke-3)"
|
"%d menit"
|
||||||
],
|
],
|
||||||
"%d hours": [
|
"%d hours": [
|
||||||
"%d jam (tunggal)",
|
"%d jam",
|
||||||
"%d jam (jamak ke-1)",
|
"%d jam",
|
||||||
"%d jam (jamak ke-2)",
|
"%d jam",
|
||||||
"%d jam (jamak ke-3)"
|
"%d jam"
|
||||||
],
|
],
|
||||||
"%d days": [
|
"%d days": [
|
||||||
"%d hari (tunggal)",
|
"%d hari",
|
||||||
"%d hari (jamak ke-1)",
|
"%d hari",
|
||||||
"%d hari (jamak ke-2)",
|
"%d hari",
|
||||||
"%d hari (jamak ke-3)"
|
"%d hari"
|
||||||
],
|
],
|
||||||
"%d weeks": [
|
"%d weeks": [
|
||||||
"%d minggu (tunggal)",
|
"%d minggu",
|
||||||
"%d minggu",
|
"%d minggu",
|
||||||
"%d minggu",
|
"%d minggu",
|
||||||
"%d minggu"
|
"%d minggu"
|
||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Tutup",
|
"Close": "Tutup",
|
||||||
"Encrypted note on PrivateBin": "Catatan ter-ekrip di PrivateBin",
|
"Encrypted note on PrivateBin": "Catatan ter-ekrip di PrivateBin",
|
||||||
"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.",
|
"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.": "URL shortener may expose your decrypt key in URL."
|
"URL shortener may expose your decrypt key in URL.": "Pemendek URL mungkin akan menampakkan kunci dekrip Anda dalam URL.",
|
||||||
|
"Save paste": "Simpan paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Chiudi",
|
"Close": "Chiudi",
|
||||||
"Encrypted note on PrivateBin": "Nota crittografata su PrivateBin",
|
"Encrypted note on PrivateBin": "Nota crittografata su PrivateBin",
|
||||||
"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.",
|
"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 may expose your decrypt key in URL."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener può esporre la tua chiave decrittografata nell'URL.",
|
||||||
|
"Save paste": "Salva il messagio"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,10 +63,10 @@
|
|||||||
"ho": ["Hiri Motu", "Hiri Motu"],
|
"ho": ["Hiri Motu", "Hiri Motu"],
|
||||||
"hu": ["magyar", "Hungarian"],
|
"hu": ["magyar", "Hungarian"],
|
||||||
"ia": ["Interlingua", "Interlingua"],
|
"ia": ["Interlingua", "Interlingua"],
|
||||||
|
"id": ["bahasa Indonesia","Indonesian"],
|
||||||
"ie": ["Interlingue", "Interlingue"],
|
"ie": ["Interlingue", "Interlingue"],
|
||||||
"ga": ["Gaeilge", "Irish"],
|
"ga": ["Gaeilge", "Irish"],
|
||||||
"ig": ["Asụsụ Igbo", "Igbo"],
|
"ig": ["Asụsụ Igbo", "Igbo"],
|
||||||
"in": ["bahasa Indonesia","Indonesian"],
|
|
||||||
"ik": ["Iñupiaq", "Inupiaq"],
|
"ik": ["Iñupiaq", "Inupiaq"],
|
||||||
"io": ["Ido", "Ido"],
|
"io": ["Ido", "Ido"],
|
||||||
"is": ["Íslenska", "Icelandic"],
|
"is": ["Íslenska", "Icelandic"],
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"PrivateBin": "PrivateBin",
|
"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 yra minimalistinis, atvirojo kodo internetinis įdėjimų dėklas, kurį naudojant, serveris nieko nenutuokia apie įdėtus duomenis. Duomenys yra šifruojami/iššifruojami %snaršyklėje%s naudojant 256 bitų 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.": "%s yra minimalistinis, atvirojo kodo internetinis įdėjimų dėklas, kurį naudojant, serveris nieko nenutuokia apie įdėtus duomenis. Duomenys yra šifruojami/iššifruojami %snaršyklėje%s naudojant 256 bitų AES.",
|
||||||
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "Daugiau informacijos rasite <a href=\"https://privatebin.info/\">projeketo puslapyje</a>.",
|
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "Daugiau informacijos rasite <a href=\"https://privatebin.info/\">projekto puslapyje</a>.",
|
||||||
"Because ignorance is bliss": "Nes nežinojimas yra palaima",
|
"Because ignorance is bliss": "Nes nežinojimas yra palaima",
|
||||||
"en": "lt",
|
"en": "lt",
|
||||||
"Paste does not exist, has expired or has been deleted.": "Įdėjimo nėra, jis nebegalioja arba buvo ištrintas.",
|
"Paste does not exist, has expired or has been deleted.": "Įdėjimo nėra, jis nebegalioja arba buvo ištrintas.",
|
||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Užverti",
|
"Close": "Užverti",
|
||||||
"Encrypted note on PrivateBin": "Šifruoti užrašai ties PrivateBin",
|
"Encrypted note on PrivateBin": "Šifruoti užrašai ties PrivateBin",
|
||||||
"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šų.",
|
"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 shortener may expose your decrypt key in URL."
|
"URL shortener may expose your decrypt key in URL.": "URL trumpinimo įrankis gali atskleisti URL adrese jūsų iššifravimo raktą.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Steng",
|
"Close": "Steng",
|
||||||
"Encrypted note on PrivateBin": "Kryptert notat på PrivateBin",
|
"Encrypted note on PrivateBin": "Kryptert notat på PrivateBin",
|
||||||
"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.",
|
"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 shortener may expose your decrypt key in URL."
|
"URL shortener may expose your decrypt key in URL.": "URL forkorter kan avsløre dekrypteringsnøkkelen.",
|
||||||
|
"Save paste": "Lagre utklipp"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Tampar",
|
"Close": "Tampar",
|
||||||
"Encrypted note on PrivateBin": "Nòtas chifradas sus PrivateBin",
|
"Encrypted note on PrivateBin": "Nòtas chifradas sus PrivateBin",
|
||||||
"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.",
|
"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.": "URL shortener may expose your decrypt key in URL."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Fechar",
|
"Close": "Fechar",
|
||||||
"Encrypted note on PrivateBin": "Nota criptografada no PrivateBin",
|
"Encrypted note on PrivateBin": "Nota criptografada no PrivateBin",
|
||||||
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@
|
|||||||
"%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.": "Примечание: Этот сервис тестовый: Данные могут быть удалены в любое время. Котята умрут, если вы будете злоупотреблять сервисом.",
|
||||||
"This document will expire in %d seconds.": [
|
"This document will expire in %d seconds.": [
|
||||||
"Документ будет удален через %d секунду.",
|
"Документ будет удален через %d секунду.",
|
||||||
"Документ будет удален через %d секунды.",
|
"Документ будет удален через %d секунды.",
|
||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Закрыть",
|
"Close": "Закрыть",
|
||||||
"Encrypted note on PrivateBin": "Зашифрованная запись на PrivateBin",
|
"Encrypted note on PrivateBin": "Зашифрованная запись на 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."
|
"URL shortener may expose your decrypt key in URL.": "Сервис сокращения ссылок может получить ваш ключ расшифровки из ссылки.",
|
||||||
|
"Save paste": "Сохранить запись"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
19
i18n/tr.json
19
i18n/tr.json
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"PrivateBin": "PrivateBin",
|
"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.",
|
"%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>.",
|
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "Daha fazla bilgi için <a href=\"https://privatebin.info/\">proje sayfası</a>'na göz atabilirsiniz.",
|
||||||
"Because ignorance is bliss": "Because ignorance is bliss",
|
"Because ignorance is bliss": "Çünkü, cehalet mutluluktur",
|
||||||
"en": "tr",
|
"en": "tr",
|
||||||
"Paste does not exist, has expired or has been deleted.": "Paste does not exist, has expired or has been deleted.",
|
"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 php %s or above to work. Sorry.": "%s requires php %s or above to work. Sorry.",
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
"Please wait %d seconds between each post. (3rd plural)"
|
"Please wait %d seconds between each post. (3rd plural)"
|
||||||
],
|
],
|
||||||
"Paste is limited to %s of encrypted data.": "Paste is limited to %s of encrypted data.",
|
"Paste is limited to %s of encrypted data.": "Paste is limited to %s of encrypted data.",
|
||||||
"Invalid data.": "Invalid data.",
|
"Invalid data.": "Geçersiz veri.",
|
||||||
"You are unlucky. Try again.": "You are unlucky. Try again.",
|
"You are unlucky. Try again.": "Lütfen tekrar deneyiniz.",
|
||||||
"Error saving comment. Sorry.": "Error saving comment. Sorry.",
|
"Error saving comment. Sorry.": "Error saving comment. Sorry.",
|
||||||
"Error saving paste. Sorry.": "Error saving paste. Sorry.",
|
"Error saving paste. Sorry.": "Error saving paste. Sorry.",
|
||||||
"Invalid paste ID.": "Invalid paste ID.",
|
"Invalid paste ID.": "Invalid paste ID.",
|
||||||
@@ -24,8 +24,8 @@
|
|||||||
"Paste was properly deleted.": "Paste was properly 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.",
|
"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.",
|
"%s requires a modern browser to work.": "%s requires a modern browser to work.",
|
||||||
"New": "New",
|
"New": "Yeni",
|
||||||
"Send": "Send",
|
"Send": "Gönder",
|
||||||
"Clone": "Clone",
|
"Clone": "Clone",
|
||||||
"Raw text": "Raw text",
|
"Raw text": "Raw text",
|
||||||
"Expires": "Expires",
|
"Expires": "Expires",
|
||||||
@@ -59,8 +59,8 @@
|
|||||||
"%d days (3rd plural)"
|
"%d days (3rd plural)"
|
||||||
],
|
],
|
||||||
"%d weeks": [
|
"%d weeks": [
|
||||||
"%d week (singular)",
|
"%d hafta (tekil)",
|
||||||
"%d weeks (1st plural)",
|
"%d haftalar (çoğul)",
|
||||||
"%d weeks (2nd plural)",
|
"%d weeks (2nd plural)",
|
||||||
"%d weeks (3rd plural)"
|
"%d weeks (3rd plural)"
|
||||||
],
|
],
|
||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,5 +184,6 @@
|
|||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
|
"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.",
|
"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."
|
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
|
||||||
|
"Save paste": "Save paste"
|
||||||
}
|
}
|
||||||
|
|||||||
63
i18n/zh.json
63
i18n/zh.json
@@ -1,29 +1,29 @@
|
|||||||
{
|
{
|
||||||
"PrivateBin": "PrivateBin",
|
"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是一个极简、开源、对粘贴内容毫不知情的在线粘贴板,数据%s在浏览器内%s进行AES-256加密。",
|
"%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在浏览器内%s进行 AES-256 加密和解密。",
|
||||||
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "更多信息请查看<a href=\"https://privatebin.info/\">项目主页</a>。",
|
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "更多信息请查看<a href=\"https://privatebin.info/\">项目主页</a>。",
|
||||||
"Because ignorance is bliss": "因为无知是福",
|
"Because ignorance is bliss": "因为无知是福",
|
||||||
"en": "zh",
|
"en": "zh",
|
||||||
"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需要PHP %s及以上版本来工作,抱歉。",
|
"%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] 部分。",
|
"%s requires configuration section [%s] to be present in configuration file.": "%s 需要设置配置文件中的 [%s] 部分。",
|
||||||
"Please wait %d seconds between each post.": [
|
"Please wait %d seconds between each post.": [
|
||||||
"每 %d 秒只能粘贴一次。",
|
"每 %d 秒只能粘贴一次。",
|
||||||
"每 %d 秒只能粘贴一次。",
|
"每 %d 秒只能粘贴一次。",
|
||||||
"每 %d 秒只能粘贴一次。",
|
"每 %d 秒只能粘贴一次。",
|
||||||
"每 %d 秒只能粘贴一次。"
|
"每 %d 秒只能粘贴一次。"
|
||||||
],
|
],
|
||||||
"Paste is limited to %s of encrypted data.": "粘贴受限于 %s 加密数据。",
|
"Paste is limited to %s of encrypted data.": "对于加密数据,上限为 %s。",
|
||||||
"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.": "无效的ID。",
|
"Invalid paste ID.": "无效的 ID。",
|
||||||
"Paste is not of burn-after-reading type.": "粘贴内容不是阅后即焚类型。",
|
"Paste is not of burn-after-reading type.": "粘贴内容不是阅后即焚类型。",
|
||||||
"Wrong deletion token. Paste was not deleted.": "错误的删除token,粘贴内容没有被删除。",
|
"Wrong deletion token. Paste was not deleted.": "错误的删除token,粘贴内容没有被删除。",
|
||||||
"Paste was properly deleted.": "粘贴内容已被正确删除。",
|
"Paste was properly deleted.": "粘贴内容已被正确删除。",
|
||||||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "%s需要JavaScript来进行加解密。 给你带来的不便敬请谅解。",
|
"JavaScript is required for %s to work. Sorry for the inconvenience.": "%s 需要 JavaScript 来进行加解密。 给你带来的不便敬请谅解。",
|
||||||
"%s requires a modern browser to work.": "%s需要在现代浏览器上工作。",
|
"%s requires a modern browser to work.": "%s 需要在现代浏览器上工作。",
|
||||||
"New": "新建",
|
"New": "新建",
|
||||||
"Send": "送出",
|
"Send": "送出",
|
||||||
"Clone": "复制",
|
"Clone": "复制",
|
||||||
@@ -111,8 +111,8 @@
|
|||||||
"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": "由IP生成的头像",
|
"Avatar generated from IP address": "由IP生成的头像",
|
||||||
@@ -126,7 +126,7 @@
|
|||||||
"server error or not responding": "服务器错误或无回应",
|
"server error or not responding": "服务器错误或无回应",
|
||||||
"Could not post comment: %s": "无法发送评论: %s",
|
"Could not post comment: %s": "无法发送评论: %s",
|
||||||
"Sending paste…": "粘贴内容提交中…",
|
"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>",
|
"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": "删除数据",
|
"Delete data": "删除数据",
|
||||||
"Could not create paste: %s": "无法创建粘贴:%s",
|
"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?)": "无法解密粘贴:URL中缺失解密密钥(是否使用了重定向或者短链接导致密钥丢失?)",
|
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "无法解密粘贴:URL中缺失解密密钥(是否使用了重定向或者短链接导致密钥丢失?)",
|
||||||
@@ -144,45 +144,46 @@
|
|||||||
"Source Code": "源代码",
|
"Source Code": "源代码",
|
||||||
"Markdown": "Markdown",
|
"Markdown": "Markdown",
|
||||||
"Download attachment": "下载附件",
|
"Download attachment": "下载附件",
|
||||||
"Cloned: '%s'": "副本: '%s'",
|
"Cloned: '%s'": "副本:“%s”",
|
||||||
"The cloned file '%s' was attached to this paste.": "副本 '%s' 已附加到此粘贴内容。",
|
"The cloned file '%s' was attached to this paste.": "副本“%s”已附加到此粘贴内容。",
|
||||||
"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 的 PATH 变量必须结束于 \"%s\"。 请修改你的 index.php 中的 PATH 变量。",
|
"%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s 的 PATH 变量必须结束于“%s”。 请修改你的 index.php 中的 PATH 变量。",
|
||||||
"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>.": "如果这个消息一直存在,请参考 <a href=\"%s\">这里的 参考文档(英文版)</a>进行故障排除。",
|
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.": "如果此消息一直存在,请参考 <a href=\"%s\">这里的 FAQ(英文版)</a>排除故障。",
|
||||||
"+++ no paste text +++": "+++ 没有粘贴内容 +++",
|
"+++ no paste text +++": "+++ 无粘贴内容 +++",
|
||||||
"Could not get paste data: %s": "无法获取粘贴数据:%s",
|
"Could not get paste data: %s": "无法获取粘贴数据:%s",
|
||||||
"QR code": "二维码",
|
"QR code": "二维码",
|
||||||
"This website is using an insecure HTTP connection! Please use it only for testing.": "该网站使用了不安全的HTTP连接! 请仅将其用于测试。",
|
"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>。",
|
"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 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.": "您的浏览器不支持用于zlib压缩的WebAssembly。 您可以创建未压缩的文档,但不能读取压缩的文档。",
|
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "您的浏览器不支持用于 zlib 压缩的 WebAssembly。 您可以创建未压缩的文档,但不能读取压缩的文档。",
|
||||||
"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.": "这个链接将会在 %s 过期。",
|
"This link will expire after %s.": "这个链接将会在 %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?": "收件人可能会知道您的时区,将时间转换为UTC?",
|
"Recipient may become aware of your timezone, convert time to UTC?": "收件人可能会知道您的时区,将时间转换为 UTC?",
|
||||||
"Use Current Timezone": "使用当前时区",
|
"Use Current Timezone": "使用当前时区",
|
||||||
"Convert To UTC": "转换为UTC",
|
"Convert To UTC": "转换为 UTC",
|
||||||
"Close": "关闭",
|
"Close": "关闭",
|
||||||
"Encrypted note on PrivateBin": "PrivateBin上的加密笔记",
|
"Encrypted note on PrivateBin": "PrivateBin 上的加密笔记",
|
||||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "访问这个链接来查看该笔记。 将这个URL发送给任何人即可允许其访问该笔记。",
|
"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 shortener may expose your decrypt key in URL."
|
"URL shortener may expose your decrypt key in URL.": "短链接服务可能会暴露您在 URL 中的解密密钥。",
|
||||||
|
"Save paste": "保存内容"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -601,7 +601,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
* @prop {string[]}
|
* @prop {string[]}
|
||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
const supportedLanguages = ['bg', 'cs', 'de', 'es', 'fr', 'he', 'hu', 'it', 'lt', 'no', 'nl', 'pl', 'pt', 'oc', 'ru', 'sl', 'uk', 'zh'];
|
const supportedLanguages = ['bg', 'ca', 'cs', 'de', 'es', 'et', 'fr', 'he', 'hu', 'id', 'it', 'lt', 'no', 'nl', 'pl', 'pt', 'oc', 'ru', 'sl', 'uk', 'zh'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* built in language
|
* built in language
|
||||||
@@ -767,7 +767,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
/**
|
/**
|
||||||
* per language functions to use to determine the plural form
|
* per language functions to use to determine the plural form
|
||||||
*
|
*
|
||||||
* @see {@link http://localization-guide.readthedocs.org/en/latest/l10n/pluralforms.html}
|
* @see {@link https://localization-guide.readthedocs.org/en/latest/l10n/pluralforms.html}
|
||||||
* @name I18n.getPluralForm
|
* @name I18n.getPluralForm
|
||||||
* @function
|
* @function
|
||||||
* @param {int} n
|
* @param {int} n
|
||||||
@@ -795,7 +795,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
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':
|
case 'sl':
|
||||||
return n % 100 === 1 ? 1 : (n % 100 === 2 ? 2 : (n % 100 === 3 || n % 100 === 4 ? 3 : 0));
|
return n % 100 === 1 ? 1 : (n % 100 === 2 ? 2 : (n % 100 === 3 || n % 100 === 4 ? 3 : 0));
|
||||||
// bg, ca, de, en, es, hu, it, nl, no, pt
|
// bg, ca, de, en, es, et, hu, it, nl, no, pt
|
||||||
default:
|
default:
|
||||||
return n !== 1 ? 1 : 0;
|
return n !== 1 ? 1 : 0;
|
||||||
}
|
}
|
||||||
@@ -3525,6 +3525,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
$password,
|
$password,
|
||||||
$passwordInput,
|
$passwordInput,
|
||||||
$rawTextButton,
|
$rawTextButton,
|
||||||
|
$downloadTextButton,
|
||||||
$qrCodeLink,
|
$qrCodeLink,
|
||||||
$emailLink,
|
$emailLink,
|
||||||
$sendButton,
|
$sendButton,
|
||||||
@@ -3666,6 +3667,30 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
newDoc.close();
|
newDoc.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* download text
|
||||||
|
*
|
||||||
|
* @name TopNav.downloadText
|
||||||
|
* @private
|
||||||
|
* @function
|
||||||
|
*/
|
||||||
|
function downloadText()
|
||||||
|
{
|
||||||
|
var filename='paste-' + Model.getPasteId() + '.txt';
|
||||||
|
var text = PasteViewer.getText();
|
||||||
|
|
||||||
|
var element = document.createElement('a');
|
||||||
|
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
||||||
|
element.setAttribute('download', filename);
|
||||||
|
|
||||||
|
element.style.display = 'none';
|
||||||
|
document.body.appendChild(element);
|
||||||
|
|
||||||
|
element.click();
|
||||||
|
|
||||||
|
document.body.removeChild(element);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* saves the language in a cookie and reloads the page
|
* saves the language in a cookie and reloads the page
|
||||||
*
|
*
|
||||||
@@ -3676,7 +3701,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
*/
|
*/
|
||||||
function setLanguage(event)
|
function setLanguage(event)
|
||||||
{
|
{
|
||||||
document.cookie = 'lang=' + $(event.target).data('lang');
|
document.cookie = 'lang=' + $(event.target).data('lang') + ';secure';
|
||||||
UiHelper.reloadHome();
|
UiHelper.reloadHome();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3892,6 +3917,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
$newButton.removeClass('hidden');
|
$newButton.removeClass('hidden');
|
||||||
$cloneButton.removeClass('hidden');
|
$cloneButton.removeClass('hidden');
|
||||||
$rawTextButton.removeClass('hidden');
|
$rawTextButton.removeClass('hidden');
|
||||||
|
$downloadTextButton.removeClass('hidden');
|
||||||
$qrCodeLink.removeClass('hidden');
|
$qrCodeLink.removeClass('hidden');
|
||||||
|
|
||||||
viewButtonsDisplayed = true;
|
viewButtonsDisplayed = true;
|
||||||
@@ -3912,6 +3938,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
$cloneButton.addClass('hidden');
|
$cloneButton.addClass('hidden');
|
||||||
$newButton.addClass('hidden');
|
$newButton.addClass('hidden');
|
||||||
$rawTextButton.addClass('hidden');
|
$rawTextButton.addClass('hidden');
|
||||||
|
$downloadTextButton.addClass('hidden');
|
||||||
$qrCodeLink.addClass('hidden');
|
$qrCodeLink.addClass('hidden');
|
||||||
me.hideEmailButton();
|
me.hideEmailButton();
|
||||||
|
|
||||||
@@ -4073,6 +4100,17 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
$rawTextButton.addClass('hidden');
|
$rawTextButton.addClass('hidden');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* only hides the download text button
|
||||||
|
*
|
||||||
|
* @name TopNav.hideRawButton
|
||||||
|
* @function
|
||||||
|
*/
|
||||||
|
me.hideDownloadButton = function()
|
||||||
|
{
|
||||||
|
$downloadTextButton.addClass('hidden');
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* only hides the qr code button
|
* only hides the qr code button
|
||||||
*
|
*
|
||||||
@@ -4334,6 +4372,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
$password = $('#password');
|
$password = $('#password');
|
||||||
$passwordInput = $('#passwordinput');
|
$passwordInput = $('#passwordinput');
|
||||||
$rawTextButton = $('#rawtextbutton');
|
$rawTextButton = $('#rawtextbutton');
|
||||||
|
$downloadTextButton = $('#downloadtextbutton');
|
||||||
$retryButton = $('#retrybutton');
|
$retryButton = $('#retrybutton');
|
||||||
$sendButton = $('#sendbutton');
|
$sendButton = $('#sendbutton');
|
||||||
$qrCodeLink = $('#qrcodelink');
|
$qrCodeLink = $('#qrcodelink');
|
||||||
@@ -4351,6 +4390,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
$sendButton.click(PasteEncrypter.sendPaste);
|
$sendButton.click(PasteEncrypter.sendPaste);
|
||||||
$cloneButton.click(Controller.clonePaste);
|
$cloneButton.click(Controller.clonePaste);
|
||||||
$rawTextButton.click(rawText);
|
$rawTextButton.click(rawText);
|
||||||
|
$downloadTextButton.click(downloadText);
|
||||||
$retryButton.click(clickRetryButton);
|
$retryButton.click(clickRetryButton);
|
||||||
$fileRemoveButton.click(removeAttachment);
|
$fileRemoveButton.click(removeAttachment);
|
||||||
$qrCodeLink.click(displayQrCode);
|
$qrCodeLink.click(displayQrCode);
|
||||||
@@ -4689,6 +4729,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||||||
TopNav.showEmailButton();
|
TopNav.showEmailButton();
|
||||||
|
|
||||||
TopNav.hideRawButton();
|
TopNav.hideRawButton();
|
||||||
|
TopNav.hideDownloadButton();
|
||||||
Editor.hide();
|
Editor.hide();
|
||||||
|
|
||||||
// parse and show text
|
// parse and show text
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class Configuration
|
|||||||
'urlshortener' => '',
|
'urlshortener' => '',
|
||||||
'qrcode' => true,
|
'qrcode' => true,
|
||||||
'icon' => 'identicon',
|
'icon' => 'identicon',
|
||||||
'cspheader' => 'default-src \'none\'; manifest-src \'self\'; connect-src * blob:; script-src \'self\' \'unsafe-eval\' resource:; style-src \'self\'; font-src \'self\'; img-src \'self\' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-downloads',
|
'cspheader' => 'default-src \'none\'; base-uri \'self\'; form-action \'none\'; manifest-src \'self\'; connect-src * blob:; script-src \'self\' \'unsafe-eval\' resource:; style-src \'self\'; font-src \'self\'; img-src \'self\' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-downloads',
|
||||||
'zerobincompatibility' => false,
|
'zerobincompatibility' => false,
|
||||||
'httpwarning' => true,
|
'httpwarning' => true,
|
||||||
'compression' => 'zlib',
|
'compression' => 'zlib',
|
||||||
@@ -79,9 +79,10 @@ class Configuration
|
|||||||
'markdown' => 'Markdown',
|
'markdown' => 'Markdown',
|
||||||
),
|
),
|
||||||
'traffic' => array(
|
'traffic' => array(
|
||||||
'limit' => 10,
|
'limit' => 10,
|
||||||
'header' => null,
|
'header' => null,
|
||||||
'dir' => 'data',
|
'dir' => 'data',
|
||||||
|
'exemptedIp' => null,
|
||||||
),
|
),
|
||||||
'purge' => array(
|
'purge' => array(
|
||||||
'limit' => 300,
|
'limit' => 300,
|
||||||
@@ -152,6 +153,16 @@ class Configuration
|
|||||||
'pwd' => null,
|
'pwd' => null,
|
||||||
'opt' => array(PDO::ATTR_PERSISTENT => true),
|
'opt' => array(PDO::ATTR_PERSISTENT => true),
|
||||||
);
|
);
|
||||||
|
} elseif (
|
||||||
|
$section == 'model_options' && in_array(
|
||||||
|
$this->_configuration['model']['class'],
|
||||||
|
array('GoogleCloudStorage')
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$values = array(
|
||||||
|
'bucket' => getenv('PRIVATEBIN_GCS_BUCKET') ? getenv('PRIVATEBIN_GCS_BUCKET') : null,
|
||||||
|
'prefix' => 'pastes',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// "*_options" sections don't require all defaults to be set
|
// "*_options" sections don't require all defaults to be set
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ class Controller
|
|||||||
// force default language, if language selection is disabled and a default is set
|
// force default language, if language selection is disabled and a default is set
|
||||||
if (!$this->_conf->getKey('languageselection') && strlen($lang) == 2) {
|
if (!$this->_conf->getKey('languageselection') && strlen($lang) == 2) {
|
||||||
$_COOKIE['lang'] = $lang;
|
$_COOKIE['lang'] = $lang;
|
||||||
setcookie('lang', $lang);
|
setcookie('lang', $lang, 0, '', '', true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,10 +346,14 @@ class Controller
|
|||||||
header('Last-Modified: ' . $time);
|
header('Last-Modified: ' . $time);
|
||||||
header('Vary: Accept');
|
header('Vary: Accept');
|
||||||
header('Content-Security-Policy: ' . $this->_conf->getKey('cspheader'));
|
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');
|
||||||
|
header('Permissions-Policy: interest-cohort=()');
|
||||||
header('Referrer-Policy: no-referrer');
|
header('Referrer-Policy: no-referrer');
|
||||||
header('X-Xss-Protection: 1; mode=block');
|
|
||||||
header('X-Frame-Options: DENY');
|
|
||||||
header('X-Content-Type-Options: nosniff');
|
header('X-Content-Type-Options: nosniff');
|
||||||
|
header('X-Frame-Options: deny');
|
||||||
|
header('X-XSS-Protection: 1; mode=block');
|
||||||
|
|
||||||
// label all the expiration options
|
// label all the expiration options
|
||||||
$expire = array();
|
$expire = array();
|
||||||
@@ -364,7 +368,7 @@ class Controller
|
|||||||
$languageselection = '';
|
$languageselection = '';
|
||||||
if ($this->_conf->getKey('languageselection')) {
|
if ($this->_conf->getKey('languageselection')) {
|
||||||
$languageselection = I18n::getLanguage();
|
$languageselection = I18n::getLanguage();
|
||||||
setcookie('lang', $languageselection);
|
setcookie('lang', $languageselection, 0, '', '', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$page = new View;
|
$page = new View;
|
||||||
|
|||||||
251
lib/Data/GoogleCloudStorage.php
Normal file
251
lib/Data/GoogleCloudStorage.php
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PrivateBin\Data;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Google\Cloud\Core\Exception\NotFoundException;
|
||||||
|
use Google\Cloud\Storage\StorageClient;
|
||||||
|
use PrivateBin\Json;
|
||||||
|
|
||||||
|
class GoogleCloudStorage extends AbstractData
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* returns a Google Cloud Storage data backend.
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @static
|
||||||
|
* @param array $options
|
||||||
|
* @return GoogleCloudStorage
|
||||||
|
*/
|
||||||
|
public static function getInstance(array $options)
|
||||||
|
{
|
||||||
|
$client = null;
|
||||||
|
$bucket = null;
|
||||||
|
$prefix = 'pastes';
|
||||||
|
|
||||||
|
if (getenv('PRIVATEBIN_GCS_BUCKET')) {
|
||||||
|
$bucket = getenv('PRIVATEBIN_GCS_BUCKET');
|
||||||
|
}
|
||||||
|
if (is_array($options) && array_key_exists('bucket', $options)) {
|
||||||
|
$bucket = $options['bucket'];
|
||||||
|
}
|
||||||
|
if (is_array($options) && array_key_exists('prefix', $options)) {
|
||||||
|
$prefix = $options['prefix'];
|
||||||
|
}
|
||||||
|
if (is_array($options) && array_key_exists('client', $options)) {
|
||||||
|
$client = $options['client'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(self::$_instance instanceof self)) {
|
||||||
|
self::$_instance = new self($bucket, $prefix, $client);
|
||||||
|
}
|
||||||
|
return self::$_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $_client = null;
|
||||||
|
protected $_bucket = null;
|
||||||
|
protected $_prefix = 'pastes';
|
||||||
|
|
||||||
|
public function __construct($bucket, $prefix, $client = null)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
if ($client == null) {
|
||||||
|
$this->_client = new StorageClient(array('suppressKeyFileNotice' => true));
|
||||||
|
} else {
|
||||||
|
// use given client for test purposes
|
||||||
|
$this->_client = $client;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->_bucket = $this->_client->bucket($bucket);
|
||||||
|
if ($prefix != null) {
|
||||||
|
$this->_prefix = $prefix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the google storage object key for $pasteid in $this->_bucket.
|
||||||
|
* @param $pasteid string to get the key for
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function _getKey($pasteid)
|
||||||
|
{
|
||||||
|
if ($this->_prefix != '') {
|
||||||
|
return $this->_prefix . '/' . $pasteid;
|
||||||
|
}
|
||||||
|
return $pasteid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uploads the payload in the $this->_bucket under the specified key.
|
||||||
|
* The entire payload is stored as a JSON document. The metadata is replicated
|
||||||
|
* as the GCS 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 {
|
||||||
|
$this->_bucket->upload(Json::encode($payload), array(
|
||||||
|
'name' => $key,
|
||||||
|
'chunkSize' => 262144,
|
||||||
|
'predefinedAcl' => 'private',
|
||||||
|
'metadata' => array(
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'metadata' => $metadata,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('failed to upload ' . $key . ' to ' . $this->_bucket->name() . ', ' .
|
||||||
|
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 {
|
||||||
|
$o = $this->_bucket->object($this->_getKey($pasteid));
|
||||||
|
$data = $o->downloadAsString();
|
||||||
|
return Json::decode($data);
|
||||||
|
} catch (NotFoundException $e) {
|
||||||
|
return false;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log('failed to read ' . $pasteid . ' from ' . $this->_bucket->name() . ', ' .
|
||||||
|
trim(preg_replace('/\s\s+/', ' ', $e->getMessage())));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function delete($pasteid)
|
||||||
|
{
|
||||||
|
$name = $this->_getKey($pasteid);
|
||||||
|
|
||||||
|
try {
|
||||||
|
foreach ($this->_bucket->objects(array('prefix' => $name . '/discussion/')) as $comment) {
|
||||||
|
try {
|
||||||
|
$this->_bucket->object($comment->name())->delete();
|
||||||
|
} catch (NotFoundException $e) {
|
||||||
|
// ignore if already deleted.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (NotFoundException $e) {
|
||||||
|
// there are no discussions associated with the paste
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->_bucket->object($name)->delete();
|
||||||
|
} catch (NotFoundException $e) {
|
||||||
|
// ignore if already deleted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function exists($pasteid)
|
||||||
|
{
|
||||||
|
$o = $this->_bucket->object($this->_getKey($pasteid));
|
||||||
|
return $o->exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 {
|
||||||
|
foreach ($this->_bucket->objects(array('prefix' => $prefix)) as $key) {
|
||||||
|
$comment = JSON::decode($this->_bucket->object($key->name())->downloadAsString());
|
||||||
|
$comment['id'] = basename($key->name());
|
||||||
|
$slot = $this->getOpenSlot($comments, (int) $comment['meta']['created']);
|
||||||
|
$comments[$slot] = $comment;
|
||||||
|
}
|
||||||
|
} catch (NotFoundException $e) {
|
||||||
|
// no comments found
|
||||||
|
}
|
||||||
|
return $comments;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function existsComment($pasteid, $parentid, $commentid)
|
||||||
|
{
|
||||||
|
$name = $this->_getKey($pasteid) . '/discussion/' . $parentid . '/' . $commentid;
|
||||||
|
$o = $this->_bucket->object($name);
|
||||||
|
return $o->exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
protected function _getExpiredPastes($batchsize)
|
||||||
|
{
|
||||||
|
$expired = array();
|
||||||
|
|
||||||
|
$now = time();
|
||||||
|
$prefix = $this->_prefix;
|
||||||
|
if ($prefix != '') {
|
||||||
|
$prefix = $prefix . '/';
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
foreach ($this->_bucket->objects(array('prefix' => $prefix)) as $object) {
|
||||||
|
$metadata = $object->info()['metadata'];
|
||||||
|
if ($metadata != null && array_key_exists('expire_date', $metadata)) {
|
||||||
|
$expire_at = intval($metadata['expire_date']);
|
||||||
|
if ($expire_at != 0 && $expire_at < $now) {
|
||||||
|
array_push($expired, basename($object->name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($expired) > $batchsize) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (NotFoundException $e) {
|
||||||
|
// no objects in the bucket yet
|
||||||
|
}
|
||||||
|
return $expired;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -305,7 +305,7 @@ class I18n
|
|||||||
/**
|
/**
|
||||||
* determines the plural form to use based on current language and given number
|
* determines the plural form to use based on current language and given number
|
||||||
*
|
*
|
||||||
* From: http://localization-guide.readthedocs.org/en/latest/l10n/pluralforms.html
|
* From: https://localization-guide.readthedocs.org/en/latest/l10n/pluralforms.html
|
||||||
*
|
*
|
||||||
* @access protected
|
* @access protected
|
||||||
* @static
|
* @static
|
||||||
@@ -334,7 +334,7 @@ class I18n
|
|||||||
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':
|
case 'sl':
|
||||||
return $n % 100 == 1 ? 1 : ($n % 100 == 2 ? 2 : ($n % 100 == 3 || $n % 100 == 4 ? 3 : 0));
|
return $n % 100 == 1 ? 1 : ($n % 100 == 2 ? 2 : ($n % 100 == 3 || $n % 100 == 4 ? 3 : 0));
|
||||||
// bg, ca, de, en, es, hu, it, nl, no, pt
|
// bg, ca, de, en, es, et, hu, it, nl, no, pt
|
||||||
default:
|
default:
|
||||||
return $n != 1 ? 1 : 0;
|
return $n != 1 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PrivateBin
|
* PrivateBin
|
||||||
*
|
*
|
||||||
@@ -12,6 +13,8 @@
|
|||||||
|
|
||||||
namespace PrivateBin\Persistence;
|
namespace PrivateBin\Persistence;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use IPLib\Factory;
|
||||||
use PrivateBin\Configuration;
|
use PrivateBin\Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,6 +33,15 @@ class TrafficLimiter extends AbstractPersistence
|
|||||||
*/
|
*/
|
||||||
private static $_limit = 10;
|
private static $_limit = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* listed ips are exempted from limits, defaults to null
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @static
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
private static $_exemptedIp = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* key to fetch IP address
|
* key to fetch IP address
|
||||||
*
|
*
|
||||||
@@ -51,6 +63,18 @@ class TrafficLimiter extends AbstractPersistence
|
|||||||
self::$_limit = $limit;
|
self::$_limit = $limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set a list of ip(ranges) as string
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @static
|
||||||
|
* @param string $exemptedIps
|
||||||
|
*/
|
||||||
|
public static function setExemptedIp($exemptedIp)
|
||||||
|
{
|
||||||
|
self::$_exemptedIp = $exemptedIp;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set configuration options of the traffic limiter
|
* set configuration options of the traffic limiter
|
||||||
*
|
*
|
||||||
@@ -62,6 +86,8 @@ class TrafficLimiter extends AbstractPersistence
|
|||||||
{
|
{
|
||||||
self::setLimit($conf->getKey('limit', 'traffic'));
|
self::setLimit($conf->getKey('limit', 'traffic'));
|
||||||
self::setPath($conf->getKey('dir', 'traffic'));
|
self::setPath($conf->getKey('dir', 'traffic'));
|
||||||
|
self::setExemptedIp($conf->getKey('exemptedIp', 'traffic'));
|
||||||
|
|
||||||
if (($option = $conf->getKey('header', 'traffic')) !== null) {
|
if (($option = $conf->getKey('header', 'traffic')) !== null) {
|
||||||
$httpHeader = 'HTTP_' . $option;
|
$httpHeader = 'HTTP_' . $option;
|
||||||
if (array_key_exists($httpHeader, $_SERVER) && !empty($_SERVER[$httpHeader])) {
|
if (array_key_exists($httpHeader, $_SERVER) && !empty($_SERVER[$httpHeader])) {
|
||||||
@@ -83,6 +109,40 @@ class TrafficLimiter extends AbstractPersistence
|
|||||||
return hash_hmac($algo, $_SERVER[self::$_ipKey], ServerSalt::get());
|
return hash_hmac($algo, $_SERVER[self::$_ipKey], ServerSalt::get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate $_ipKey against configured ipranges. If matched we will ignore the ip
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @static
|
||||||
|
* @param string $ipRange
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private static function matchIp($ipRange = null)
|
||||||
|
{
|
||||||
|
if (is_string($ipRange)) {
|
||||||
|
$ipRange = trim($ipRange);
|
||||||
|
}
|
||||||
|
$address = Factory::addressFromString($_SERVER[self::$_ipKey]);
|
||||||
|
$range = Factory::rangeFromString($ipRange);
|
||||||
|
|
||||||
|
// address could not be parsed, we might not be in IP space and try a string comparison instead
|
||||||
|
if (is_null($address)) {
|
||||||
|
return $_SERVER[self::$_ipKey] === $ipRange;
|
||||||
|
}
|
||||||
|
// range could not be parsed, possibly an invalid ip range given in config
|
||||||
|
if (is_null($range)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ip-lib throws an exception when something goes wrong, if so we want to catch it and set contained to false
|
||||||
|
try {
|
||||||
|
return $address->matches($range);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// If something is wrong with matching the ip, we assume it doesn't match
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* traffic limiter
|
* traffic limiter
|
||||||
*
|
*
|
||||||
@@ -90,7 +150,7 @@ class TrafficLimiter extends AbstractPersistence
|
|||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @static
|
* @static
|
||||||
* @throws \Exception
|
* @throws Exception
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function canPass()
|
public static function canPass()
|
||||||
@@ -100,6 +160,16 @@ class TrafficLimiter extends AbstractPersistence
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if $_ipKey is exempted from ratelimiting
|
||||||
|
if (!is_null(self::$_exemptedIp)) {
|
||||||
|
$exIp_array = explode(',', self::$_exemptedIp);
|
||||||
|
foreach ($exIp_array as $ipRange) {
|
||||||
|
if (self::matchIp($ipRange) === true) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$file = 'traffic_limiter.php';
|
$file = 'traffic_limiter.php';
|
||||||
if (self::_exists($file)) {
|
if (self::_exists($file)) {
|
||||||
require self::getPath($file);
|
require self::getPath($file);
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ endif;
|
|||||||
?>
|
?>
|
||||||
<script type="text/javascript" data-cfasync="false" src="js/purify-2.2.7.js" integrity="sha512-7Ka1I/nJuR2CL8wzIS5PJS4HgEMd0HJ6kfAl6fFhwFBB27rhztFbe0tS+Ex+Qg+5n4nZIT4lty4k4Di3+X9T4A==" crossorigin="anonymous"></script>
|
<script type="text/javascript" data-cfasync="false" src="js/purify-2.2.7.js" integrity="sha512-7Ka1I/nJuR2CL8wzIS5PJS4HgEMd0HJ6kfAl6fFhwFBB27rhztFbe0tS+Ex+Qg+5n4nZIT4lty4k4Di3+X9T4A==" 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/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-wuKnPu9+bTYhJ0HRhUmw0UxWYP5mbQehFNspkD9N4mTlxLkjRZXPnMt/nfT2/U62rRDUw1HL3SvveKJe2v4EBw==" crossorigin="anonymous"></script>
|
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-lJwDAY69TQuYQZ7FjUFPfhgYeZ2L6y5bmGt1hR+d3kMm2sddivGr7ZDdLLSe/CBgn1JrsKMj3th9dPyXN3dLHw==" crossorigin="anonymous"></script>
|
||||||
<!-- icon -->
|
<!-- icon -->
|
||||||
<link rel="apple-touch-icon" href="<?php echo I18n::encode($BASEPATH); ?>img/apple-touch-icon.png" sizes="180x180" />
|
<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" />
|
<link rel="icon" type="image/png" href="img/favicon-32x32.png" sizes="32x32" />
|
||||||
@@ -212,6 +212,9 @@ endif;
|
|||||||
<button id="rawtextbutton" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'default'; ?> navbar-btn">
|
<button id="rawtextbutton" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'default'; ?> navbar-btn">
|
||||||
<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> <?php echo I18n::_('Raw text'), PHP_EOL; ?>
|
<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> <?php echo I18n::_('Raw text'), PHP_EOL; ?>
|
||||||
</button>
|
</button>
|
||||||
|
<button id="downloadtextbutton" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'default'; ?> navbar-btn">
|
||||||
|
<span class="glyphicon glyphicon glyphicon-download-alt" aria-hidden="true"></span> <?php echo I18n::_('Save paste'), PHP_EOL; ?>
|
||||||
|
</button>
|
||||||
<button id="emaillink" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'default'; ?> navbar-btn">
|
<button id="emaillink" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'default'; ?> navbar-btn">
|
||||||
<span class="glyphicon glyphicon-envelope" aria-hidden="true"></span> <?php echo I18n::_('Email'), PHP_EOL; ?>
|
<span class="glyphicon glyphicon-envelope" aria-hidden="true"></span> <?php echo I18n::_('Email'), PHP_EOL; ?>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ endif;
|
|||||||
?>
|
?>
|
||||||
<script type="text/javascript" data-cfasync="false" src="js/purify-2.2.7.js" integrity="sha512-7Ka1I/nJuR2CL8wzIS5PJS4HgEMd0HJ6kfAl6fFhwFBB27rhztFbe0tS+Ex+Qg+5n4nZIT4lty4k4Di3+X9T4A==" crossorigin="anonymous"></script>
|
<script type="text/javascript" data-cfasync="false" src="js/purify-2.2.7.js" integrity="sha512-7Ka1I/nJuR2CL8wzIS5PJS4HgEMd0HJ6kfAl6fFhwFBB27rhztFbe0tS+Ex+Qg+5n4nZIT4lty4k4Di3+X9T4A==" 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/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-wuKnPu9+bTYhJ0HRhUmw0UxWYP5mbQehFNspkD9N4mTlxLkjRZXPnMt/nfT2/U62rRDUw1HL3SvveKJe2v4EBw==" crossorigin="anonymous"></script>
|
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-lJwDAY69TQuYQZ7FjUFPfhgYeZ2L6y5bmGt1hR+d3kMm2sddivGr7ZDdLLSe/CBgn1JrsKMj3th9dPyXN3dLHw==" crossorigin="anonymous"></script>
|
||||||
<!-- icon -->
|
<!-- icon -->
|
||||||
<link rel="apple-touch-icon" href="img/apple-touch-icon.png?<?php echo rawurlencode($VERSION); ?>" sizes="180x180" />
|
<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" />
|
<link rel="icon" type="image/png" href="img/favicon-32x32.png?<?php echo rawurlencode($VERSION); ?>" sizes="32x32" />
|
||||||
@@ -127,6 +127,7 @@ endif;
|
|||||||
<button id="sendbutton" class="hidden"><img src="img/icon_send.png" width="18" height="15" alt="" /><?php echo I18n::_('Send'); ?></button>
|
<button id="sendbutton" class="hidden"><img src="img/icon_send.png" width="18" height="15" alt="" /><?php echo I18n::_('Send'); ?></button>
|
||||||
<button id="clonebutton" class="hidden"><img src="img/icon_clone.png" width="15" height="17" alt="" /><?php echo I18n::_('Clone'); ?></button>
|
<button id="clonebutton" class="hidden"><img src="img/icon_clone.png" width="15" height="17" alt="" /><?php echo I18n::_('Clone'); ?></button>
|
||||||
<button id="rawtextbutton" class="hidden"><img src="img/icon_raw.png" width="15" height="15" alt="" /><?php echo I18n::_('Raw text'); ?></button>
|
<button id="rawtextbutton" class="hidden"><img src="img/icon_raw.png" width="15" height="15" alt="" /><?php echo I18n::_('Raw text'); ?></button>
|
||||||
|
<button id="downloadtextbutton" class="hidden"><?php echo I18n::_('Save paste'), PHP_EOL; ?></button>
|
||||||
<button id="emaillink" class="hidden"><img src="img/icon_email.png" width="15" height="15" alt="" /><?php echo I18n::_('Email'); ?></button>
|
<button id="emaillink" class="hidden"><img src="img/icon_email.png" width="15" height="15" alt="" /><?php echo I18n::_('Email'); ?></button>
|
||||||
<?php
|
<?php
|
||||||
if ($QRCODE):
|
if ($QRCODE):
|
||||||
|
|||||||
715
tst/Data/GoogleCloudStorageTest.php
Normal file
715
tst/Data/GoogleCloudStorageTest.php
Normal file
@@ -0,0 +1,715 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Google\Auth\HttpHandler\HttpHandlerFactory;
|
||||||
|
use Google\Cloud\Core\Exception\BadRequestException;
|
||||||
|
use Google\Cloud\Core\Exception\NotFoundException;
|
||||||
|
use Google\Cloud\Storage\Bucket;
|
||||||
|
use Google\Cloud\Storage\Connection\ConnectionInterface;
|
||||||
|
use Google\Cloud\Storage\StorageClient;
|
||||||
|
use Google\Cloud\Storage\StorageObject;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use PrivateBin\Data\GoogleCloudStorage;
|
||||||
|
|
||||||
|
class GoogleCloudStorageTest extends PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
private static $_client;
|
||||||
|
private static $_bucket;
|
||||||
|
|
||||||
|
public static function setUpBeforeClass()
|
||||||
|
{
|
||||||
|
$httpClient = new Client(array('debug'=>false));
|
||||||
|
$handler = HttpHandlerFactory::build($httpClient);
|
||||||
|
|
||||||
|
$name = 'pb-';
|
||||||
|
$alphabet = 'abcdefghijklmnopqrstuvwxyz';
|
||||||
|
for ($i = 0; $i < 29; ++$i) {
|
||||||
|
$name .= $alphabet[rand(0, strlen($alphabet) - 1)];
|
||||||
|
}
|
||||||
|
self::$_client = new StorageClientStub(array());
|
||||||
|
self::$_bucket = self::$_client->createBucket($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
// do not report E_NOTICE as fsouza/fake-gcs-server does not return a `generation` value in the response
|
||||||
|
// which the Google Cloud Storage PHP library expects.
|
||||||
|
error_reporting(E_ERROR | E_WARNING | E_PARSE);
|
||||||
|
$this->_model = GoogleCloudStorage::getInstance(array(
|
||||||
|
'bucket' => self::$_bucket->name(),
|
||||||
|
'prefix' => 'pastes',
|
||||||
|
'client' => self::$_client, ));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tearDown()
|
||||||
|
{
|
||||||
|
foreach (self::$_bucket->objects() as $object) {
|
||||||
|
$object->delete();
|
||||||
|
}
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function tearDownAfterClass()
|
||||||
|
{
|
||||||
|
self::$_bucket->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFileBasedDataStoreWorks()
|
||||||
|
{
|
||||||
|
$this->_model->delete(Helper::getPasteId());
|
||||||
|
|
||||||
|
// storing pastes
|
||||||
|
$paste = Helper::getPaste(2, array('expire_date' => 1344803344));
|
||||||
|
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
|
||||||
|
$this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
|
||||||
|
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
|
||||||
|
$this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store the same paste twice');
|
||||||
|
$this->assertEquals($paste, $this->_model->read(Helper::getPasteId()));
|
||||||
|
|
||||||
|
// storing comments
|
||||||
|
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist');
|
||||||
|
$this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment()), 'store comment');
|
||||||
|
$this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment exists after storing it');
|
||||||
|
$this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment()), 'unable to store the same comment twice');
|
||||||
|
$comment = Helper::getComment();
|
||||||
|
$comment['id'] = Helper::getCommentId();
|
||||||
|
$comment['parentid'] = Helper::getPasteId();
|
||||||
|
$this->assertEquals(
|
||||||
|
array($comment['meta']['created'] => $comment),
|
||||||
|
$this->_model->readComments(Helper::getPasteId())
|
||||||
|
);
|
||||||
|
|
||||||
|
// deleting pastes
|
||||||
|
$this->_model->delete(Helper::getPasteId());
|
||||||
|
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste successfully deleted');
|
||||||
|
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment was deleted with paste');
|
||||||
|
$this->assertFalse($this->_model->read(Helper::getPasteId()), 'paste can no longer be found');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pastes a-g are expired and should get deleted, x never expires and y-z expire in an hour
|
||||||
|
*/
|
||||||
|
public function testPurge()
|
||||||
|
{
|
||||||
|
$expired = Helper::getPaste(2, array('expire_date' => 1344803344));
|
||||||
|
$paste = Helper::getPaste(2, array('expire_date' => time() + 3600));
|
||||||
|
$keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z');
|
||||||
|
$ids = array();
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
$ids[$key] = hash('fnv164', $key);
|
||||||
|
$this->assertFalse($this->_model->exists($ids[$key]), "paste $key does not yet exist");
|
||||||
|
if (in_array($key, array('x', 'y', 'z'))) {
|
||||||
|
$this->assertTrue($this->_model->create($ids[$key], $paste), "store $key paste");
|
||||||
|
} elseif ($key === 'x') {
|
||||||
|
$this->assertTrue($this->_model->create($ids[$key], Helper::getPaste()), "store $key paste");
|
||||||
|
} else {
|
||||||
|
$this->assertTrue($this->_model->create($ids[$key], $expired), "store $key paste");
|
||||||
|
}
|
||||||
|
$this->assertTrue($this->_model->exists($ids[$key]), "paste $key exists after storing it");
|
||||||
|
}
|
||||||
|
$this->_model->purge(10);
|
||||||
|
foreach ($ids as $key => $id) {
|
||||||
|
if (in_array($key, array('x', 'y', 'z'))) {
|
||||||
|
$this->assertTrue($this->_model->exists($id), "paste $key exists after purge");
|
||||||
|
$this->_model->delete($id);
|
||||||
|
} else {
|
||||||
|
$this->assertFalse($this->_model->exists($id), "paste $key was purged");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testErrorDetection()
|
||||||
|
{
|
||||||
|
$this->_model->delete(Helper::getPasteId());
|
||||||
|
$paste = Helper::getPaste(2, array('expire' => "Invalid UTF-8 sequence: \xB1\x31"));
|
||||||
|
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
|
||||||
|
$this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
|
||||||
|
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCommentErrorDetection()
|
||||||
|
{
|
||||||
|
$this->_model->delete(Helper::getPasteId());
|
||||||
|
$comment = Helper::getComment(1, array('nickname' => "Invalid UTF-8 sequence: \xB1\x31"));
|
||||||
|
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
|
||||||
|
$this->assertTrue($this->_model->create(Helper::getPasteId(), Helper::getPaste()), 'store new paste');
|
||||||
|
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
|
||||||
|
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist');
|
||||||
|
$this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment), 'unable to store broken comment');
|
||||||
|
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does still not exist');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class StorageClientStub provides a limited stub for performing the unit test
|
||||||
|
*/
|
||||||
|
class StorageClientStub extends StorageClient
|
||||||
|
{
|
||||||
|
private $_config = null;
|
||||||
|
private $_connection = null;
|
||||||
|
private $_buckets = array();
|
||||||
|
|
||||||
|
public function __construct(array $config = array())
|
||||||
|
{
|
||||||
|
$this->_config = $config;
|
||||||
|
$this->_connection = new ConnectionInterfaceStub();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bucket($name, $userProject = false)
|
||||||
|
{
|
||||||
|
if (!key_exists($name, $this->_buckets)) {
|
||||||
|
$b = new BucketStub($this->_connection, $name, array(), $this);
|
||||||
|
$this->_buckets[$name] = $b;
|
||||||
|
}
|
||||||
|
return $this->_buckets[$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Google\Cloud\Core\Exception\NotFoundException
|
||||||
|
*/
|
||||||
|
public function deleteBucket($name)
|
||||||
|
{
|
||||||
|
if (key_exists($name, $this->_buckets)) {
|
||||||
|
unset($this->_buckets[$name]);
|
||||||
|
} else {
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buckets(array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function registerStreamWrapper($protocol = null)
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unregisterStreamWrapper($protocol = null)
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function signedUrlUploader($uri, $data, array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function timestamp(\DateTimeInterface $timestamp, $nanoSeconds = null)
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getServiceAccount(array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hmacKeys(array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hmacKey($accessId, $projectId = null, array $metadata = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createHmacKey($serviceAccountEmail, array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createBucket($name, array $options = array())
|
||||||
|
{
|
||||||
|
if (key_exists($name, $this->_buckets)) {
|
||||||
|
throw new BadRequestException('already exists');
|
||||||
|
}
|
||||||
|
$b = new BucketStub($this->_connection, $name, array(), $this);
|
||||||
|
$this->_buckets[$name] = $b;
|
||||||
|
return $b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BucketStub stubs a GCS bucket.
|
||||||
|
*/
|
||||||
|
class BucketStub extends Bucket
|
||||||
|
{
|
||||||
|
public $_objects;
|
||||||
|
private $_name;
|
||||||
|
private $_info;
|
||||||
|
private $_connection;
|
||||||
|
private $_client;
|
||||||
|
|
||||||
|
public function __construct(ConnectionInterface $connection, $name, array $info = array(), $client = null)
|
||||||
|
{
|
||||||
|
$this->_name = $name;
|
||||||
|
$this->_info = $info;
|
||||||
|
$this->_connection = $connection;
|
||||||
|
$this->_objects = array();
|
||||||
|
$this->_client = $client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function acl()
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defaultAcl()
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exists()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function upload($data, array $options = array())
|
||||||
|
{
|
||||||
|
if (!is_string($data) || !key_exists('name', $options)) {
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = $options['name'];
|
||||||
|
$generation = '1';
|
||||||
|
$o = new StorageObjectStub($this->_connection, $name, $this, $generation, $options);
|
||||||
|
$this->_objects[$options['name']] = $o;
|
||||||
|
$o->setData($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uploadAsync($data, array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResumableUploader($data, array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStreamableUploader($data, array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function object($name, array $options = array())
|
||||||
|
{
|
||||||
|
if (key_exists($name, $this->_objects)) {
|
||||||
|
return $this->_objects[$name];
|
||||||
|
} else {
|
||||||
|
return new StorageObjectStub($this->_connection, $name, $this, null, $options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function objects(array $options = array())
|
||||||
|
{
|
||||||
|
$prefix = key_exists('prefix', $options) ? $options['prefix'] : '';
|
||||||
|
|
||||||
|
return new CallbackFilterIterator(
|
||||||
|
new ArrayIterator($this->_objects),
|
||||||
|
function ($current, $key, $iterator) use ($prefix) {
|
||||||
|
return substr($key, 0, strlen($prefix)) == $prefix;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createNotification($topic, array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function notification($id)
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function notifications(array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(array $options = array())
|
||||||
|
{
|
||||||
|
$this->_client->deleteBucket($this->_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function compose(array $sourceObjects, $name, array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function info(array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reload(array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function name()
|
||||||
|
{
|
||||||
|
return $this->_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function lifecycle(array $lifecycle = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function currentLifecycle(array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isWritable($file = null)
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function iam()
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function lockRetentionPolicy(array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function signedUrl($expires, array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generateSignedPostPolicyV4($objectName, $expires, array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class StorageObjectStub stubs a GCS storage object.
|
||||||
|
*/
|
||||||
|
class StorageObjectStub extends StorageObject
|
||||||
|
{
|
||||||
|
private $_name;
|
||||||
|
private $_data;
|
||||||
|
private $_info;
|
||||||
|
private $_bucket;
|
||||||
|
private $_generation;
|
||||||
|
private $_exists = false;
|
||||||
|
private $_connection;
|
||||||
|
|
||||||
|
public function __construct(ConnectionInterface $connection, $name, $bucket, $generation = null, array $info = array(), $encryptionKey = null, $encryptionKeySHA256 = null)
|
||||||
|
{
|
||||||
|
$this->_name = $name;
|
||||||
|
$this->_bucket = $bucket;
|
||||||
|
$this->_generation = $generation;
|
||||||
|
$this->_info = $info;
|
||||||
|
$this->_connection = $connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function acl()
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exists(array $options = array())
|
||||||
|
{
|
||||||
|
return key_exists($this->_name, $this->_bucket->_objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NotFoundException
|
||||||
|
*/
|
||||||
|
public function delete(array $options = array())
|
||||||
|
{
|
||||||
|
if (key_exists($this->_name, $this->_bucket->_objects)) {
|
||||||
|
unset($this->_bucket->_objects[$this->_name]);
|
||||||
|
} else {
|
||||||
|
throw new NotFoundException('key ' . $this->_name . ' not found.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NotFoundException
|
||||||
|
*/
|
||||||
|
public function update(array $metadata, array $options = array())
|
||||||
|
{
|
||||||
|
if (!$this->_exists) {
|
||||||
|
throw new NotFoundException('key ' . $this->_name . ' not found.');
|
||||||
|
}
|
||||||
|
$this->_info = $metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function copy($destination, array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rewrite($destination, array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rename($name, array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NotFoundException
|
||||||
|
*/
|
||||||
|
public function downloadAsString(array $options = array())
|
||||||
|
{
|
||||||
|
if (!$this->_exists) {
|
||||||
|
throw new NotFoundException('key ' . $this->_name . ' not found.');
|
||||||
|
}
|
||||||
|
return $this->_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadToFile($path, array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadAsStream(array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadAsStreamAsync(array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function signedUrl($expires, array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function signedUploadUrl($expires, array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function beginSignedUploadSession(array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function info(array $options = array())
|
||||||
|
{
|
||||||
|
return key_exists('metadata',$this->_info) ? $this->_info['metadata'] : array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reload(array $options = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function name()
|
||||||
|
{
|
||||||
|
return $this->_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function identity()
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function gcsUri()
|
||||||
|
{
|
||||||
|
return sprintf(
|
||||||
|
'gs://%s/%s',
|
||||||
|
$this->_bucket->name(),
|
||||||
|
$this->_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setData($data)
|
||||||
|
{
|
||||||
|
$this->_data = $data;
|
||||||
|
$this->_exists = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ConnectionInterfaceStub required for the stubs.
|
||||||
|
*/
|
||||||
|
class ConnectionInterfaceStub implements ConnectionInterface
|
||||||
|
{
|
||||||
|
public function deleteAcl(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAcl(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listAcl(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function insertAcl(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function patchAcl(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteBucket(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBucket(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listBuckets(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function insertBucket(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBucketIamPolicy(array $args)
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBucketIamPolicy(array $args)
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBucketIamPermissions(array $args)
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function patchBucket(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteObject(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function copyObject(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rewriteObject(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function composeObject(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getObject(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listObjects(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function patchObject(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadObject(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function insertObject(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNotification(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteNotification(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function insertNotification(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listNotifications(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getServiceAccount(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function lockRetentionPolicy(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createHmacKey(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteHmacKey(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHmacKey(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateHmacKey(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listHmacKeys(array $args = array())
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('not supported by this stub');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,5 +35,20 @@ class TrafficLimiterTest extends PHPUnit_Framework_TestCase
|
|||||||
$this->assertTrue(TrafficLimiter::canPass(), 'fourth request has different ip and may pass');
|
$this->assertTrue(TrafficLimiter::canPass(), 'fourth request has different ip and may pass');
|
||||||
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
||||||
$this->assertFalse(TrafficLimiter::canPass(), 'fifth request is to fast, may not pass');
|
$this->assertFalse(TrafficLimiter::canPass(), 'fifth request is to fast, may not pass');
|
||||||
|
|
||||||
|
// exempted IPs configuration
|
||||||
|
TrafficLimiter::setExemptedIp('1.2.3.4,10.10.10.0/24,2001:1620:2057::/48');
|
||||||
|
$this->assertFalse(TrafficLimiter::canPass(), 'still too fast and not exempted');
|
||||||
|
$_SERVER['REMOTE_ADDR'] = '10.10.10.10';
|
||||||
|
$this->assertTrue(TrafficLimiter::canPass(), 'IPv4 in exempted range');
|
||||||
|
$this->assertTrue(TrafficLimiter::canPass(), 'request is to fast, but IPv4 in exempted range');
|
||||||
|
$_SERVER['REMOTE_ADDR'] = '2001:1620:2057:dead:beef::cafe:babe';
|
||||||
|
$this->assertTrue(TrafficLimiter::canPass(), 'IPv6 in exempted range');
|
||||||
|
$this->assertTrue(TrafficLimiter::canPass(), 'request is to fast, but IPv6 in exempted range');
|
||||||
|
TrafficLimiter::setExemptedIp('127.*,foobar');
|
||||||
|
$this->assertFalse(TrafficLimiter::canPass(), 'request is to fast, invalid range');
|
||||||
|
$_SERVER['REMOTE_ADDR'] = 'foobar';
|
||||||
|
$this->assertTrue(TrafficLimiter::canPass(), 'non-IP address');
|
||||||
|
$this->assertTrue(TrafficLimiter::canPass(), 'request is to fast, but non-IP address matches exempted range');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
15
vendor/composer/autoload_classmap.php
vendored
15
vendor/composer/autoload_classmap.php
vendored
@@ -6,6 +6,20 @@ $vendorDir = dirname(dirname(__FILE__));
|
|||||||
$baseDir = dirname($vendorDir);
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
|
'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',
|
||||||
|
'IPLib\\Address\\IPv6' => $vendorDir . '/mlocati/ip-lib/src/Address/IPv6.php',
|
||||||
|
'IPLib\\Address\\Type' => $vendorDir . '/mlocati/ip-lib/src/Address/Type.php',
|
||||||
|
'IPLib\\Factory' => $vendorDir . '/mlocati/ip-lib/src/Factory.php',
|
||||||
|
'IPLib\\Range\\AbstractRange' => $vendorDir . '/mlocati/ip-lib/src/Range/AbstractRange.php',
|
||||||
|
'IPLib\\Range\\Pattern' => $vendorDir . '/mlocati/ip-lib/src/Range/Pattern.php',
|
||||||
|
'IPLib\\Range\\RangeInterface' => $vendorDir . '/mlocati/ip-lib/src/Range/RangeInterface.php',
|
||||||
|
'IPLib\\Range\\Single' => $vendorDir . '/mlocati/ip-lib/src/Range/Single.php',
|
||||||
|
'IPLib\\Range\\Subnet' => $vendorDir . '/mlocati/ip-lib/src/Range/Subnet.php',
|
||||||
|
'IPLib\\Range\\Type' => $vendorDir . '/mlocati/ip-lib/src/Range/Type.php',
|
||||||
|
'IPLib\\Service\\BinaryMath' => $vendorDir . '/mlocati/ip-lib/src/Service/BinaryMath.php',
|
||||||
|
'IPLib\\Service\\RangesFromBounradyCalculator' => $vendorDir . '/mlocati/ip-lib/src/Service/RangesFromBounradyCalculator.php',
|
||||||
'Identicon\\Generator\\BaseGenerator' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/BaseGenerator.php',
|
'Identicon\\Generator\\BaseGenerator' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/BaseGenerator.php',
|
||||||
'Identicon\\Generator\\GdGenerator' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/GdGenerator.php',
|
'Identicon\\Generator\\GdGenerator' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/GdGenerator.php',
|
||||||
'Identicon\\Generator\\GeneratorInterface' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/GeneratorInterface.php',
|
'Identicon\\Generator\\GeneratorInterface' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/GeneratorInterface.php',
|
||||||
@@ -17,6 +31,7 @@ return array(
|
|||||||
'PrivateBin\\Data\\AbstractData' => $baseDir . '/lib/Data/AbstractData.php',
|
'PrivateBin\\Data\\AbstractData' => $baseDir . '/lib/Data/AbstractData.php',
|
||||||
'PrivateBin\\Data\\Database' => $baseDir . '/lib/Data/Database.php',
|
'PrivateBin\\Data\\Database' => $baseDir . '/lib/Data/Database.php',
|
||||||
'PrivateBin\\Data\\Filesystem' => $baseDir . '/lib/Data/Filesystem.php',
|
'PrivateBin\\Data\\Filesystem' => $baseDir . '/lib/Data/Filesystem.php',
|
||||||
|
'PrivateBin\\Data\\GoogleCloudStorage' => $baseDir . '/lib/Data/GoogleCloudStorage.php',
|
||||||
'PrivateBin\\Filter' => $baseDir . '/lib/Filter.php',
|
'PrivateBin\\Filter' => $baseDir . '/lib/Filter.php',
|
||||||
'PrivateBin\\FormatV2' => $baseDir . '/lib/FormatV2.php',
|
'PrivateBin\\FormatV2' => $baseDir . '/lib/FormatV2.php',
|
||||||
'PrivateBin\\I18n' => $baseDir . '/lib/I18n.php',
|
'PrivateBin\\I18n' => $baseDir . '/lib/I18n.php',
|
||||||
|
|||||||
1
vendor/composer/autoload_psr4.php
vendored
1
vendor/composer/autoload_psr4.php
vendored
@@ -8,4 +8,5 @@ $baseDir = dirname($vendorDir);
|
|||||||
return array(
|
return array(
|
||||||
'PrivateBin\\' => array($baseDir . '/lib'),
|
'PrivateBin\\' => array($baseDir . '/lib'),
|
||||||
'Identicon\\' => array($vendorDir . '/yzalis/identicon/src/Identicon'),
|
'Identicon\\' => array($vendorDir . '/yzalis/identicon/src/Identicon'),
|
||||||
|
'IPLib\\' => array($vendorDir . '/mlocati/ip-lib/src'),
|
||||||
);
|
);
|
||||||
|
|||||||
20
vendor/composer/autoload_static.php
vendored
20
vendor/composer/autoload_static.php
vendored
@@ -18,6 +18,7 @@ class ComposerStaticInitDontChange
|
|||||||
'I' =>
|
'I' =>
|
||||||
array (
|
array (
|
||||||
'Identicon\\' => 10,
|
'Identicon\\' => 10,
|
||||||
|
'IPLib\\' => 6,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -30,9 +31,27 @@ class ComposerStaticInitDontChange
|
|||||||
array (
|
array (
|
||||||
0 => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon',
|
0 => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon',
|
||||||
),
|
),
|
||||||
|
'IPLib\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/mlocati/ip-lib/src',
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
public static $classMap = array (
|
public static $classMap = array (
|
||||||
|
'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',
|
||||||
|
'IPLib\\Address\\IPv6' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/IPv6.php',
|
||||||
|
'IPLib\\Address\\Type' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/Type.php',
|
||||||
|
'IPLib\\Factory' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Factory.php',
|
||||||
|
'IPLib\\Range\\AbstractRange' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Range/AbstractRange.php',
|
||||||
|
'IPLib\\Range\\Pattern' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Range/Pattern.php',
|
||||||
|
'IPLib\\Range\\RangeInterface' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Range/RangeInterface.php',
|
||||||
|
'IPLib\\Range\\Single' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Range/Single.php',
|
||||||
|
'IPLib\\Range\\Subnet' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Range/Subnet.php',
|
||||||
|
'IPLib\\Range\\Type' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Range/Type.php',
|
||||||
|
'IPLib\\Service\\BinaryMath' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Service/BinaryMath.php',
|
||||||
|
'IPLib\\Service\\RangesFromBounradyCalculator' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Service/RangesFromBounradyCalculator.php',
|
||||||
'Identicon\\Generator\\BaseGenerator' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/BaseGenerator.php',
|
'Identicon\\Generator\\BaseGenerator' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/BaseGenerator.php',
|
||||||
'Identicon\\Generator\\GdGenerator' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/GdGenerator.php',
|
'Identicon\\Generator\\GdGenerator' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/GdGenerator.php',
|
||||||
'Identicon\\Generator\\GeneratorInterface' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/GeneratorInterface.php',
|
'Identicon\\Generator\\GeneratorInterface' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/GeneratorInterface.php',
|
||||||
@@ -44,6 +63,7 @@ class ComposerStaticInitDontChange
|
|||||||
'PrivateBin\\Data\\AbstractData' => __DIR__ . '/../..' . '/lib/Data/AbstractData.php',
|
'PrivateBin\\Data\\AbstractData' => __DIR__ . '/../..' . '/lib/Data/AbstractData.php',
|
||||||
'PrivateBin\\Data\\Database' => __DIR__ . '/../..' . '/lib/Data/Database.php',
|
'PrivateBin\\Data\\Database' => __DIR__ . '/../..' . '/lib/Data/Database.php',
|
||||||
'PrivateBin\\Data\\Filesystem' => __DIR__ . '/../..' . '/lib/Data/Filesystem.php',
|
'PrivateBin\\Data\\Filesystem' => __DIR__ . '/../..' . '/lib/Data/Filesystem.php',
|
||||||
|
'PrivateBin\\Data\\GoogleCloudStorage' => __DIR__ . '/../..' . '/lib/Data/GoogleCloudStorage.php',
|
||||||
'PrivateBin\\Filter' => __DIR__ . '/../..' . '/lib/Filter.php',
|
'PrivateBin\\Filter' => __DIR__ . '/../..' . '/lib/Filter.php',
|
||||||
'PrivateBin\\FormatV2' => __DIR__ . '/../..' . '/lib/FormatV2.php',
|
'PrivateBin\\FormatV2' => __DIR__ . '/../..' . '/lib/FormatV2.php',
|
||||||
'PrivateBin\\I18n' => __DIR__ . '/../..' . '/lib/I18n.php',
|
'PrivateBin\\I18n' => __DIR__ . '/../..' . '/lib/I18n.php',
|
||||||
|
|||||||
13
vendor/mlocati/ip-lib/ip-lib.php
vendored
Normal file
13
vendor/mlocati/ip-lib/ip-lib.php
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
spl_autoload_register(
|
||||||
|
function ($class) {
|
||||||
|
if (strpos($class, 'IPLib\\') !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$file = __DIR__ . DIRECTORY_SEPARATOR . 'src' . str_replace('\\', DIRECTORY_SEPARATOR, substr($class, strlen('IPLib'))) . '.php';
|
||||||
|
if (is_file($file)) {
|
||||||
|
require_once $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
125
vendor/mlocati/ip-lib/src/Address/AddressInterface.php
vendored
Normal file
125
vendor/mlocati/ip-lib/src/Address/AddressInterface.php
vendored
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace IPLib\Address;
|
||||||
|
|
||||||
|
use IPLib\Range\RangeInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface of all the IP address types.
|
||||||
|
*/
|
||||||
|
interface AddressInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the short string representation of this address.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of bits representing this address type.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*
|
||||||
|
* @example 32 for IPv4
|
||||||
|
* @example 128 for IPv6
|
||||||
|
*/
|
||||||
|
public static function getNumberOfBits();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the string representation of this address.
|
||||||
|
*
|
||||||
|
* @param bool $long set to true to have a long/full representation, false otherwise
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @example If $long is true, you'll get '0000:0000:0000:0000:0000:0000:0000:0001', '::1' otherwise.
|
||||||
|
*/
|
||||||
|
public function toString($long = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the byte list of the IP address.
|
||||||
|
*
|
||||||
|
* @return int[]
|
||||||
|
*
|
||||||
|
* @example For localhost: for IPv4 you'll get array(127, 0, 0, 1), for IPv6 array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)
|
||||||
|
*/
|
||||||
|
public function getBytes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the full bit list the IP address.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @example For localhost: For IPv4 you'll get '01111111000000000000000000000001' (32 digits), for IPv6 '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001' (128 digits)
|
||||||
|
*/
|
||||||
|
public function getBits();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the type of the IP address.
|
||||||
|
*
|
||||||
|
* @return int One of the \IPLib\Address\Type::T_... constants
|
||||||
|
*/
|
||||||
|
public function getAddressType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default RFC reserved range type.
|
||||||
|
*
|
||||||
|
* @return int One of the \IPLib\Range\Type::T_... constants
|
||||||
|
*/
|
||||||
|
public static function getDefaultReservedRangeType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the RFC reserved ranges (except the ones of type getDefaultReservedRangeType).
|
||||||
|
*
|
||||||
|
* @return \IPLib\Address\AssignedRange[] ranges are sorted
|
||||||
|
*/
|
||||||
|
public static function getReservedRanges();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the type of range of the IP address.
|
||||||
|
*
|
||||||
|
* @return int One of the \IPLib\Range\Type::T_... constants
|
||||||
|
*/
|
||||||
|
public function getRangeType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a string representation of this address than can be used when comparing addresses and ranges.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getComparableString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this address is contained in an range.
|
||||||
|
*
|
||||||
|
* @param \IPLib\Range\RangeInterface $range
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function matches(RangeInterface $range);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the address right after this IP address (if available).
|
||||||
|
*
|
||||||
|
* @return \IPLib\Address\AddressInterface|null
|
||||||
|
*/
|
||||||
|
public function getNextAddress();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the address right before this IP address (if available).
|
||||||
|
*
|
||||||
|
* @return \IPLib\Address\AddressInterface|null
|
||||||
|
*/
|
||||||
|
public function getPreviousAddress();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Reverse DNS Lookup Address of this IP address.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @example for IPv4 it returns something like x.x.x.x.in-addr.arpa
|
||||||
|
* @example for IPv6 it returns something like x.x.x.x..x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa
|
||||||
|
*/
|
||||||
|
public function getReverseDNSLookupName();
|
||||||
|
}
|
||||||
138
vendor/mlocati/ip-lib/src/Address/AssignedRange.php
vendored
Normal file
138
vendor/mlocati/ip-lib/src/Address/AssignedRange.php
vendored
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace IPLib\Address;
|
||||||
|
|
||||||
|
use IPLib\Range\RangeInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an IP address range with an assigned range type.
|
||||||
|
*/
|
||||||
|
class AssignedRange
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The range definition.
|
||||||
|
*
|
||||||
|
* @var \IPLib\Range\RangeInterface
|
||||||
|
*/
|
||||||
|
protected $range;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The range type.
|
||||||
|
*
|
||||||
|
* @var int one of the \IPLib\Range\Type::T_ constants
|
||||||
|
*/
|
||||||
|
protected $type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of exceptions for this range type.
|
||||||
|
*
|
||||||
|
* @var \IPLib\Address\AssignedRange[]
|
||||||
|
*/
|
||||||
|
protected $exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the instance.
|
||||||
|
*
|
||||||
|
* @param \IPLib\Range\RangeInterface $range the range definition
|
||||||
|
* @param int $type The range type (one of the \IPLib\Range\Type::T_ constants)
|
||||||
|
* @param \IPLib\Address\AssignedRange[] $exceptions the list of exceptions for this range type
|
||||||
|
*/
|
||||||
|
public function __construct(RangeInterface $range, $type, array $exceptions = array())
|
||||||
|
{
|
||||||
|
$this->range = $range;
|
||||||
|
$this->type = $type;
|
||||||
|
$this->exceptions = $exceptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the range definition.
|
||||||
|
*
|
||||||
|
* @return \IPLib\Range\RangeInterface
|
||||||
|
*/
|
||||||
|
public function getRange()
|
||||||
|
{
|
||||||
|
return $this->range;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the range type.
|
||||||
|
*
|
||||||
|
* @return int one of the \IPLib\Range\Type::T_ constants
|
||||||
|
*/
|
||||||
|
public function getType()
|
||||||
|
{
|
||||||
|
return $this->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of exceptions for this range type.
|
||||||
|
*
|
||||||
|
* @return \IPLib\Address\AssignedRange[]
|
||||||
|
*/
|
||||||
|
public function getExceptions()
|
||||||
|
{
|
||||||
|
return $this->exceptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the assigned type for a specific address.
|
||||||
|
*
|
||||||
|
* @param \IPLib\Address\AddressInterface $address
|
||||||
|
*
|
||||||
|
* @return int|null return NULL of the address is outside this address; a \IPLib\Range\Type::T_ constant otherwise
|
||||||
|
*/
|
||||||
|
public function getAddressType(AddressInterface $address)
|
||||||
|
{
|
||||||
|
$result = null;
|
||||||
|
if ($this->range->contains($address)) {
|
||||||
|
foreach ($this->exceptions as $exception) {
|
||||||
|
$result = $exception->getAddressType($address);
|
||||||
|
if ($result !== null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($result === null) {
|
||||||
|
$result = $this->type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the assigned type for a specific address range.
|
||||||
|
*
|
||||||
|
* @param \IPLib\Range\RangeInterface $range
|
||||||
|
*
|
||||||
|
* @return int|false|null return NULL of the range is fully outside this range; false if it's partly crosses this range (or it contains mixed types); a \IPLib\Range\Type::T_ constant otherwise
|
||||||
|
*/
|
||||||
|
public function getRangeType(RangeInterface $range)
|
||||||
|
{
|
||||||
|
$myStart = $this->range->getComparableStartString();
|
||||||
|
$rangeEnd = $range->getComparableEndString();
|
||||||
|
if ($myStart > $rangeEnd) {
|
||||||
|
$result = null;
|
||||||
|
} else {
|
||||||
|
$myEnd = $this->range->getComparableEndString();
|
||||||
|
$rangeStart = $range->getComparableStartString();
|
||||||
|
if ($myEnd < $rangeStart) {
|
||||||
|
$result = null;
|
||||||
|
} elseif ($rangeStart < $myStart || $rangeEnd > $myEnd) {
|
||||||
|
$result = false;
|
||||||
|
} else {
|
||||||
|
$result = null;
|
||||||
|
foreach ($this->exceptions as $exception) {
|
||||||
|
$result = $exception->getRangeType($range);
|
||||||
|
if ($result !== null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($result === null) {
|
||||||
|
$result = $this->getType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
465
vendor/mlocati/ip-lib/src/Address/IPv4.php
vendored
Normal file
465
vendor/mlocati/ip-lib/src/Address/IPv4.php
vendored
Normal file
@@ -0,0 +1,465 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace IPLib\Address;
|
||||||
|
|
||||||
|
use IPLib\Range\RangeInterface;
|
||||||
|
use IPLib\Range\Subnet;
|
||||||
|
use IPLib\Range\Type as RangeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An IPv4 address.
|
||||||
|
*/
|
||||||
|
class IPv4 implements AddressInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The string representation of the address.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*
|
||||||
|
* @example '127.0.0.1'
|
||||||
|
*/
|
||||||
|
protected $address;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The byte list of the IP address.
|
||||||
|
*
|
||||||
|
* @var int[]|null
|
||||||
|
*/
|
||||||
|
protected $bytes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the range of this IP address.
|
||||||
|
*
|
||||||
|
* @var int|null
|
||||||
|
*/
|
||||||
|
protected $rangeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string representation of this address than can be used when comparing addresses and ranges.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $comparableString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array containing RFC designated address ranges.
|
||||||
|
*
|
||||||
|
* @var array|null
|
||||||
|
*/
|
||||||
|
private static $reservedRanges = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the instance.
|
||||||
|
*
|
||||||
|
* @param string $address
|
||||||
|
*/
|
||||||
|
protected function __construct($address)
|
||||||
|
{
|
||||||
|
$this->address = $address;
|
||||||
|
$this->bytes = null;
|
||||||
|
$this->rangeType = null;
|
||||||
|
$this->comparableString = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::__toString()
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return $this->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getNumberOfBits()
|
||||||
|
*/
|
||||||
|
public static function getNumberOfBits()
|
||||||
|
{
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a string and returns an IPv4 instance if the string is valid, or null otherwise.
|
||||||
|
*
|
||||||
|
* @param string|mixed $address the address to parse
|
||||||
|
* @param bool $mayIncludePort set to false to avoid parsing addresses with ports
|
||||||
|
* @param bool $supportNonDecimalIPv4 set to true to support parsing non decimal (that is, octal and hexadecimal) IPv4 addresses
|
||||||
|
*
|
||||||
|
* @return static|null
|
||||||
|
*/
|
||||||
|
public static function fromString($address, $mayIncludePort = true, $supportNonDecimalIPv4 = false)
|
||||||
|
{
|
||||||
|
if (!is_string($address) || !strpos($address, '.')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$rxChunk = '0?[0-9]{1,3}';
|
||||||
|
if ($supportNonDecimalIPv4) {
|
||||||
|
$rxChunk = "(?:0[Xx]0*[0-9A-Fa-f]{1,2})|(?:{$rxChunk})";
|
||||||
|
}
|
||||||
|
$rx = "0*?({$rxChunk})\.0*?({$rxChunk})\.0*?({$rxChunk})\.0*?({$rxChunk})";
|
||||||
|
if ($mayIncludePort) {
|
||||||
|
$rx .= '(?::\d+)?';
|
||||||
|
}
|
||||||
|
$matches = null;
|
||||||
|
if (!preg_match('/^' . $rx . '$/', $address, $matches)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$nums = array();
|
||||||
|
for ($i = 1; $i <= 4; $i++) {
|
||||||
|
$s = $matches[$i];
|
||||||
|
if ($supportNonDecimalIPv4) {
|
||||||
|
if (stripos($s, '0x') === 0) {
|
||||||
|
$n = hexdec(substr($s, 2));
|
||||||
|
} elseif ($s[0] === '0') {
|
||||||
|
if (!preg_match('/^[0-7]+$/', $s)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$n = octdec(substr($s, 1));
|
||||||
|
} else {
|
||||||
|
$n = (int) $s;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$n = (int) $s;
|
||||||
|
}
|
||||||
|
if ($n < 0 || $n > 255) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$nums[] = (string) $n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new static(implode('.', $nums));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse an array of bytes and returns an IPv4 instance if the array is valid, or null otherwise.
|
||||||
|
*
|
||||||
|
* @param int[]|array $bytes
|
||||||
|
*
|
||||||
|
* @return static|null
|
||||||
|
*/
|
||||||
|
public static function fromBytes(array $bytes)
|
||||||
|
{
|
||||||
|
$result = null;
|
||||||
|
if (count($bytes) === 4) {
|
||||||
|
$chunks = array_map(
|
||||||
|
function ($byte) {
|
||||||
|
return (is_int($byte) && $byte >= 0 && $byte <= 255) ? (string) $byte : false;
|
||||||
|
},
|
||||||
|
$bytes
|
||||||
|
);
|
||||||
|
if (in_array(false, $chunks, true) === false) {
|
||||||
|
$result = new static(implode('.', $chunks));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::toString()
|
||||||
|
*/
|
||||||
|
public function toString($long = false)
|
||||||
|
{
|
||||||
|
if ($long) {
|
||||||
|
return $this->getComparableString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the octal representation of this IP address.
|
||||||
|
*
|
||||||
|
* @param bool $long
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @example if $long == false: if the decimal representation is '0.7.8.255': '0.7.010.0377'
|
||||||
|
* @example if $long == true: if the decimal representation is '0.7.8.255': '0000.0007.0010.0377'
|
||||||
|
*/
|
||||||
|
public function toOctal($long = false)
|
||||||
|
{
|
||||||
|
$chunks = array();
|
||||||
|
foreach ($this->getBytes() as $byte) {
|
||||||
|
if ($long) {
|
||||||
|
$chunks[] = sprintf('%04o', $byte);
|
||||||
|
} else {
|
||||||
|
$chunks[] = '0' . decoct($byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode('.', $chunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the hexadecimal representation of this IP address.
|
||||||
|
*
|
||||||
|
* @param bool $long
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @example if $long == false: if the decimal representation is '0.9.10.255': '0.9.0xa.0xff'
|
||||||
|
* @example if $long == true: if the decimal representation is '0.9.10.255': '0x00.0x09.0x0a.0xff'
|
||||||
|
*/
|
||||||
|
public function toHexadecimal($long = false)
|
||||||
|
{
|
||||||
|
$chunks = array();
|
||||||
|
foreach ($this->getBytes() as $byte) {
|
||||||
|
if ($long) {
|
||||||
|
$chunks[] = sprintf('0x%02x', $byte);
|
||||||
|
} else {
|
||||||
|
$chunks[] = '0x' . dechex($byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode('.', $chunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getBytes()
|
||||||
|
*/
|
||||||
|
public function getBytes()
|
||||||
|
{
|
||||||
|
if ($this->bytes === null) {
|
||||||
|
$this->bytes = array_map(
|
||||||
|
function ($chunk) {
|
||||||
|
return (int) $chunk;
|
||||||
|
},
|
||||||
|
explode('.', $this->address)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getBits()
|
||||||
|
*/
|
||||||
|
public function getBits()
|
||||||
|
{
|
||||||
|
$parts = array();
|
||||||
|
foreach ($this->getBytes() as $byte) {
|
||||||
|
$parts[] = sprintf('%08b', $byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode('', $parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getAddressType()
|
||||||
|
*/
|
||||||
|
public function getAddressType()
|
||||||
|
{
|
||||||
|
return Type::T_IPv4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getDefaultReservedRangeType()
|
||||||
|
*/
|
||||||
|
public static function getDefaultReservedRangeType()
|
||||||
|
{
|
||||||
|
return RangeType::T_PUBLIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getReservedRanges()
|
||||||
|
*/
|
||||||
|
public static function getReservedRanges()
|
||||||
|
{
|
||||||
|
if (self::$reservedRanges === null) {
|
||||||
|
$reservedRanges = array();
|
||||||
|
foreach (array(
|
||||||
|
// RFC 5735
|
||||||
|
'0.0.0.0/8' => array(RangeType::T_THISNETWORK, array('0.0.0.0/32' => RangeType::T_UNSPECIFIED)),
|
||||||
|
// RFC 5735
|
||||||
|
'10.0.0.0/8' => array(RangeType::T_PRIVATENETWORK),
|
||||||
|
// RFC 6598
|
||||||
|
'100.64.0.0/10' => array(RangeType::T_CGNAT),
|
||||||
|
// RFC 5735
|
||||||
|
'127.0.0.0/8' => array(RangeType::T_LOOPBACK),
|
||||||
|
// RFC 5735
|
||||||
|
'169.254.0.0/16' => array(RangeType::T_LINKLOCAL),
|
||||||
|
// RFC 5735
|
||||||
|
'172.16.0.0/12' => array(RangeType::T_PRIVATENETWORK),
|
||||||
|
// RFC 5735
|
||||||
|
'192.0.0.0/24' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 5735
|
||||||
|
'192.0.2.0/24' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 5735
|
||||||
|
'192.88.99.0/24' => array(RangeType::T_ANYCASTRELAY),
|
||||||
|
// RFC 5735
|
||||||
|
'192.168.0.0/16' => array(RangeType::T_PRIVATENETWORK),
|
||||||
|
// RFC 5735
|
||||||
|
'198.18.0.0/15' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 5735
|
||||||
|
'198.51.100.0/24' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 5735
|
||||||
|
'203.0.113.0/24' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 5735
|
||||||
|
'224.0.0.0/4' => array(RangeType::T_MULTICAST),
|
||||||
|
// RFC 5735
|
||||||
|
'240.0.0.0/4' => array(RangeType::T_RESERVED, array('255.255.255.255/32' => RangeType::T_LIMITEDBROADCAST)),
|
||||||
|
) as $range => $data) {
|
||||||
|
$exceptions = array();
|
||||||
|
if (isset($data[1])) {
|
||||||
|
foreach ($data[1] as $exceptionRange => $exceptionType) {
|
||||||
|
$exceptions[] = new AssignedRange(Subnet::fromString($exceptionRange), $exceptionType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$reservedRanges[] = new AssignedRange(Subnet::fromString($range), $data[0], $exceptions);
|
||||||
|
}
|
||||||
|
self::$reservedRanges = $reservedRanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$reservedRanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getRangeType()
|
||||||
|
*/
|
||||||
|
public function getRangeType()
|
||||||
|
{
|
||||||
|
if ($this->rangeType === null) {
|
||||||
|
$rangeType = null;
|
||||||
|
foreach (static::getReservedRanges() as $reservedRange) {
|
||||||
|
$rangeType = $reservedRange->getAddressType($this);
|
||||||
|
if ($rangeType !== null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->rangeType = $rangeType === null ? static::getDefaultReservedRangeType() : $rangeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->rangeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an IPv6 representation of this address (in 6to4 notation).
|
||||||
|
*
|
||||||
|
* @return \IPLib\Address\IPv6
|
||||||
|
*/
|
||||||
|
public function toIPv6()
|
||||||
|
{
|
||||||
|
$myBytes = $this->getBytes();
|
||||||
|
|
||||||
|
return IPv6::fromString('2002:' . sprintf('%02x', $myBytes[0]) . sprintf('%02x', $myBytes[1]) . ':' . sprintf('%02x', $myBytes[2]) . sprintf('%02x', $myBytes[3]) . '::');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an IPv6 representation of this address (in IPv6 IPv4-mapped notation).
|
||||||
|
*
|
||||||
|
* @return \IPLib\Address\IPv6
|
||||||
|
*/
|
||||||
|
public function toIPv6IPv4Mapped()
|
||||||
|
{
|
||||||
|
return IPv6::fromBytes(array_merge(array(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff), $this->getBytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getComparableString()
|
||||||
|
*/
|
||||||
|
public function getComparableString()
|
||||||
|
{
|
||||||
|
if ($this->comparableString === null) {
|
||||||
|
$chunks = array();
|
||||||
|
foreach ($this->getBytes() as $byte) {
|
||||||
|
$chunks[] = sprintf('%03d', $byte);
|
||||||
|
}
|
||||||
|
$this->comparableString = implode('.', $chunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->comparableString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::matches()
|
||||||
|
*/
|
||||||
|
public function matches(RangeInterface $range)
|
||||||
|
{
|
||||||
|
return $range->contains($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getNextAddress()
|
||||||
|
*/
|
||||||
|
public function getNextAddress()
|
||||||
|
{
|
||||||
|
$overflow = false;
|
||||||
|
$bytes = $this->getBytes();
|
||||||
|
for ($i = count($bytes) - 1; $i >= 0; $i--) {
|
||||||
|
if ($bytes[$i] === 255) {
|
||||||
|
if ($i === 0) {
|
||||||
|
$overflow = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$bytes[$i] = 0;
|
||||||
|
} else {
|
||||||
|
$bytes[$i]++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $overflow ? null : static::fromBytes($bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getPreviousAddress()
|
||||||
|
*/
|
||||||
|
public function getPreviousAddress()
|
||||||
|
{
|
||||||
|
$overflow = false;
|
||||||
|
$bytes = $this->getBytes();
|
||||||
|
for ($i = count($bytes) - 1; $i >= 0; $i--) {
|
||||||
|
if ($bytes[$i] === 0) {
|
||||||
|
if ($i === 0) {
|
||||||
|
$overflow = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$bytes[$i] = 255;
|
||||||
|
} else {
|
||||||
|
$bytes[$i]--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $overflow ? null : static::fromBytes($bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getReverseDNSLookupName()
|
||||||
|
*/
|
||||||
|
public function getReverseDNSLookupName()
|
||||||
|
{
|
||||||
|
return implode(
|
||||||
|
'.',
|
||||||
|
array_reverse($this->getBytes())
|
||||||
|
) . '.in-addr.arpa';
|
||||||
|
}
|
||||||
|
}
|
||||||
568
vendor/mlocati/ip-lib/src/Address/IPv6.php
vendored
Normal file
568
vendor/mlocati/ip-lib/src/Address/IPv6.php
vendored
Normal file
@@ -0,0 +1,568 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace IPLib\Address;
|
||||||
|
|
||||||
|
use IPLib\Range\RangeInterface;
|
||||||
|
use IPLib\Range\Subnet;
|
||||||
|
use IPLib\Range\Type as RangeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An IPv6 address.
|
||||||
|
*/
|
||||||
|
class IPv6 implements AddressInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The long string representation of the address.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*
|
||||||
|
* @example '0000:0000:0000:0000:0000:0000:0000:0001'
|
||||||
|
*/
|
||||||
|
protected $longAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The long string representation of the address.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*
|
||||||
|
* @example '::1'
|
||||||
|
*/
|
||||||
|
protected $shortAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The byte list of the IP address.
|
||||||
|
*
|
||||||
|
* @var int[]|null
|
||||||
|
*/
|
||||||
|
protected $bytes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The word list of the IP address.
|
||||||
|
*
|
||||||
|
* @var int[]|null
|
||||||
|
*/
|
||||||
|
protected $words;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the range of this IP address.
|
||||||
|
*
|
||||||
|
* @var int|null
|
||||||
|
*/
|
||||||
|
protected $rangeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array containing RFC designated address ranges.
|
||||||
|
*
|
||||||
|
* @var array|null
|
||||||
|
*/
|
||||||
|
private static $reservedRanges = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the instance.
|
||||||
|
*
|
||||||
|
* @param string $longAddress
|
||||||
|
*/
|
||||||
|
public function __construct($longAddress)
|
||||||
|
{
|
||||||
|
$this->longAddress = $longAddress;
|
||||||
|
$this->shortAddress = null;
|
||||||
|
$this->bytes = null;
|
||||||
|
$this->words = null;
|
||||||
|
$this->rangeType = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::__toString()
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return $this->toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getNumberOfBits()
|
||||||
|
*/
|
||||||
|
public static function getNumberOfBits()
|
||||||
|
{
|
||||||
|
return 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a string and returns an IPv6 instance if the string is valid, or null otherwise.
|
||||||
|
*
|
||||||
|
* @param string|mixed $address the address to parse
|
||||||
|
* @param bool $mayIncludePort set to false to avoid parsing addresses with ports
|
||||||
|
* @param bool $mayIncludeZoneID set to false to avoid parsing addresses with zone IDs (see RFC 4007)
|
||||||
|
*
|
||||||
|
* @return static|null
|
||||||
|
*/
|
||||||
|
public static function fromString($address, $mayIncludePort = true, $mayIncludeZoneID = true)
|
||||||
|
{
|
||||||
|
$result = null;
|
||||||
|
if (is_string($address) && strpos($address, ':') !== false && strpos($address, ':::') === false) {
|
||||||
|
$matches = null;
|
||||||
|
if ($mayIncludePort && $address[0] === '[' && preg_match('/^\[(.+)]:\d+$/', $address, $matches)) {
|
||||||
|
$address = $matches[1];
|
||||||
|
}
|
||||||
|
if ($mayIncludeZoneID) {
|
||||||
|
$percentagePos = strpos($address, '%');
|
||||||
|
if ($percentagePos > 0) {
|
||||||
|
$address = substr($address, 0, $percentagePos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (preg_match('/^((?:[0-9a-f]*:+)+)(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i', $address, $matches)) {
|
||||||
|
$address6 = static::fromString($matches[1] . '0:0', false);
|
||||||
|
if ($address6 !== null) {
|
||||||
|
$address4 = IPv4::fromString($matches[2], false);
|
||||||
|
if ($address4 !== null) {
|
||||||
|
$bytes4 = $address4->getBytes();
|
||||||
|
$address6->longAddress = substr($address6->longAddress, 0, -9) . sprintf('%02x%02x:%02x%02x', $bytes4[0], $bytes4[1], $bytes4[2], $bytes4[3]);
|
||||||
|
$result = $address6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (strpos($address, '::') === false) {
|
||||||
|
$chunks = explode(':', $address);
|
||||||
|
} else {
|
||||||
|
$chunks = array();
|
||||||
|
$parts = explode('::', $address);
|
||||||
|
if (count($parts) === 2) {
|
||||||
|
$before = ($parts[0] === '') ? array() : explode(':', $parts[0]);
|
||||||
|
$after = ($parts[1] === '') ? array() : explode(':', $parts[1]);
|
||||||
|
$missing = 8 - count($before) - count($after);
|
||||||
|
if ($missing >= 0) {
|
||||||
|
$chunks = $before;
|
||||||
|
if ($missing !== 0) {
|
||||||
|
$chunks = array_merge($chunks, array_fill(0, $missing, '0'));
|
||||||
|
}
|
||||||
|
$chunks = array_merge($chunks, $after);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count($chunks) === 8) {
|
||||||
|
$nums = array_map(
|
||||||
|
function ($chunk) {
|
||||||
|
return preg_match('/^[0-9A-Fa-f]{1,4}$/', $chunk) ? hexdec($chunk) : false;
|
||||||
|
},
|
||||||
|
$chunks
|
||||||
|
);
|
||||||
|
if (!in_array(false, $nums, true)) {
|
||||||
|
$longAddress = implode(
|
||||||
|
':',
|
||||||
|
array_map(
|
||||||
|
function ($num) {
|
||||||
|
return sprintf('%04x', $num);
|
||||||
|
},
|
||||||
|
$nums
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$result = new static($longAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse an array of bytes and returns an IPv6 instance if the array is valid, or null otherwise.
|
||||||
|
*
|
||||||
|
* @param int[]|array $bytes
|
||||||
|
*
|
||||||
|
* @return static|null
|
||||||
|
*/
|
||||||
|
public static function fromBytes(array $bytes)
|
||||||
|
{
|
||||||
|
$result = null;
|
||||||
|
if (count($bytes) === 16) {
|
||||||
|
$address = '';
|
||||||
|
for ($i = 0; $i < 16; $i++) {
|
||||||
|
if ($i !== 0 && $i % 2 === 0) {
|
||||||
|
$address .= ':';
|
||||||
|
}
|
||||||
|
$byte = $bytes[$i];
|
||||||
|
if (is_int($byte) && $byte >= 0 && $byte <= 255) {
|
||||||
|
$address .= sprintf('%02x', $byte);
|
||||||
|
} else {
|
||||||
|
$address = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($address !== null) {
|
||||||
|
$result = new static($address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse an array of words and returns an IPv6 instance if the array is valid, or null otherwise.
|
||||||
|
*
|
||||||
|
* @param int[]|array $words
|
||||||
|
*
|
||||||
|
* @return static|null
|
||||||
|
*/
|
||||||
|
public static function fromWords(array $words)
|
||||||
|
{
|
||||||
|
$result = null;
|
||||||
|
if (count($words) === 8) {
|
||||||
|
$chunks = array();
|
||||||
|
for ($i = 0; $i < 8; $i++) {
|
||||||
|
$word = $words[$i];
|
||||||
|
if (is_int($word) && $word >= 0 && $word <= 0xffff) {
|
||||||
|
$chunks[] = sprintf('%04x', $word);
|
||||||
|
} else {
|
||||||
|
$chunks = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($chunks !== null) {
|
||||||
|
$result = new static(implode(':', $chunks));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::toString()
|
||||||
|
*/
|
||||||
|
public function toString($long = false)
|
||||||
|
{
|
||||||
|
if ($long) {
|
||||||
|
$result = $this->longAddress;
|
||||||
|
} else {
|
||||||
|
if ($this->shortAddress === null) {
|
||||||
|
if (strpos($this->longAddress, '0000:0000:0000:0000:0000:ffff:') === 0) {
|
||||||
|
$lastBytes = array_slice($this->getBytes(), -4);
|
||||||
|
$this->shortAddress = '::ffff:' . implode('.', $lastBytes);
|
||||||
|
} else {
|
||||||
|
$chunks = array_map(
|
||||||
|
function ($word) {
|
||||||
|
return dechex($word);
|
||||||
|
},
|
||||||
|
$this->getWords()
|
||||||
|
);
|
||||||
|
$shortAddress = implode(':', $chunks);
|
||||||
|
$matches = null;
|
||||||
|
for ($i = 8; $i > 1; $i--) {
|
||||||
|
$search = '(?:^|:)' . rtrim(str_repeat('0:', $i), ':') . '(?:$|:)';
|
||||||
|
if (preg_match('/^(.*?)' . $search . '(.*)$/', $shortAddress, $matches)) {
|
||||||
|
$shortAddress = $matches[1] . '::' . $matches[2];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->shortAddress = $shortAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$result = $this->shortAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getBytes()
|
||||||
|
*/
|
||||||
|
public function getBytes()
|
||||||
|
{
|
||||||
|
if ($this->bytes === null) {
|
||||||
|
$bytes = array();
|
||||||
|
foreach ($this->getWords() as $word) {
|
||||||
|
$bytes[] = $word >> 8;
|
||||||
|
$bytes[] = $word & 0xff;
|
||||||
|
}
|
||||||
|
$this->bytes = $bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getBits()
|
||||||
|
*/
|
||||||
|
public function getBits()
|
||||||
|
{
|
||||||
|
$parts = array();
|
||||||
|
foreach ($this->getBytes() as $byte) {
|
||||||
|
$parts[] = sprintf('%08b', $byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode('', $parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the word list of the IP address.
|
||||||
|
*
|
||||||
|
* @return int[]
|
||||||
|
*/
|
||||||
|
public function getWords()
|
||||||
|
{
|
||||||
|
if ($this->words === null) {
|
||||||
|
$this->words = array_map(
|
||||||
|
function ($chunk) {
|
||||||
|
return hexdec($chunk);
|
||||||
|
},
|
||||||
|
explode(':', $this->longAddress)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->words;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getAddressType()
|
||||||
|
*/
|
||||||
|
public function getAddressType()
|
||||||
|
{
|
||||||
|
return Type::T_IPv6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getDefaultReservedRangeType()
|
||||||
|
*/
|
||||||
|
public static function getDefaultReservedRangeType()
|
||||||
|
{
|
||||||
|
return RangeType::T_RESERVED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getReservedRanges()
|
||||||
|
*/
|
||||||
|
public static function getReservedRanges()
|
||||||
|
{
|
||||||
|
if (self::$reservedRanges === null) {
|
||||||
|
$reservedRanges = array();
|
||||||
|
foreach (array(
|
||||||
|
// RFC 4291
|
||||||
|
'::/128' => array(RangeType::T_UNSPECIFIED),
|
||||||
|
// RFC 4291
|
||||||
|
'::1/128' => array(RangeType::T_LOOPBACK),
|
||||||
|
// RFC 4291
|
||||||
|
'100::/8' => array(RangeType::T_DISCARD, array('100::/64' => RangeType::T_DISCARDONLY)),
|
||||||
|
//'2002::/16' => array(RangeType::),
|
||||||
|
// RFC 4291
|
||||||
|
'2000::/3' => array(RangeType::T_PUBLIC),
|
||||||
|
// RFC 4193
|
||||||
|
'fc00::/7' => array(RangeType::T_PRIVATENETWORK),
|
||||||
|
// RFC 4291
|
||||||
|
'fe80::/10' => array(RangeType::T_LINKLOCAL_UNICAST),
|
||||||
|
// RFC 4291
|
||||||
|
'ff00::/8' => array(RangeType::T_MULTICAST),
|
||||||
|
// RFC 4291
|
||||||
|
//'::/8' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 4048
|
||||||
|
//'200::/7' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 4291
|
||||||
|
//'400::/6' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 4291
|
||||||
|
//'800::/5' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 4291
|
||||||
|
//'1000::/4' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 4291
|
||||||
|
//'4000::/3' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 4291
|
||||||
|
//'6000::/3' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 4291
|
||||||
|
//'8000::/3' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 4291
|
||||||
|
//'a000::/3' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 4291
|
||||||
|
//'c000::/3' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 4291
|
||||||
|
//'e000::/4' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 4291
|
||||||
|
//'f000::/5' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 4291
|
||||||
|
//'f800::/6' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 4291
|
||||||
|
//'fe00::/9' => array(RangeType::T_RESERVED),
|
||||||
|
// RFC 3879
|
||||||
|
//'fec0::/10' => array(RangeType::T_RESERVED),
|
||||||
|
) as $range => $data) {
|
||||||
|
$exceptions = array();
|
||||||
|
if (isset($data[1])) {
|
||||||
|
foreach ($data[1] as $exceptionRange => $exceptionType) {
|
||||||
|
$exceptions[] = new AssignedRange(Subnet::fromString($exceptionRange), $exceptionType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$reservedRanges[] = new AssignedRange(Subnet::fromString($range), $data[0], $exceptions);
|
||||||
|
}
|
||||||
|
self::$reservedRanges = $reservedRanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$reservedRanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getRangeType()
|
||||||
|
*/
|
||||||
|
public function getRangeType()
|
||||||
|
{
|
||||||
|
if ($this->rangeType === null) {
|
||||||
|
$ipv4 = $this->toIPv4();
|
||||||
|
if ($ipv4 !== null) {
|
||||||
|
$this->rangeType = $ipv4->getRangeType();
|
||||||
|
} else {
|
||||||
|
$rangeType = null;
|
||||||
|
foreach (static::getReservedRanges() as $reservedRange) {
|
||||||
|
$rangeType = $reservedRange->getAddressType($this);
|
||||||
|
if ($rangeType !== null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->rangeType = $rangeType === null ? static::getDefaultReservedRangeType() : $rangeType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->rangeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an IPv4 representation of this address (if possible, otherwise returns null).
|
||||||
|
*
|
||||||
|
* @return \IPLib\Address\IPv4|null
|
||||||
|
*/
|
||||||
|
public function toIPv4()
|
||||||
|
{
|
||||||
|
if (strpos($this->longAddress, '2002:') === 0) {
|
||||||
|
// 6to4
|
||||||
|
return IPv4::fromBytes(array_slice($this->getBytes(), 2, 4));
|
||||||
|
}
|
||||||
|
if (strpos($this->longAddress, '0000:0000:0000:0000:0000:ffff:') === 0) {
|
||||||
|
// IPv4-mapped IPv6 addresses
|
||||||
|
return IPv4::fromBytes(array_slice($this->getBytes(), -4));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render this IPv6 address in the "mixed" IPv6 (first 12 bytes) + IPv4 (last 4 bytes) mixed syntax.
|
||||||
|
*
|
||||||
|
* @param bool $ipV6Long render the IPv6 part in "long" format?
|
||||||
|
* @param bool $ipV4Long render the IPv4 part in "long" format?
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @example '::13.1.68.3'
|
||||||
|
* @example '0000:0000:0000:0000:0000:0000:13.1.68.3' when $ipV6Long is true
|
||||||
|
* @example '::013.001.068.003' when $ipV4Long is true
|
||||||
|
* @example '0000:0000:0000:0000:0000:0000:013.001.068.003' when $ipV6Long and $ipV4Long are true
|
||||||
|
*
|
||||||
|
* @see https://tools.ietf.org/html/rfc4291#section-2.2 point 3.
|
||||||
|
*/
|
||||||
|
public function toMixedIPv6IPv4String($ipV6Long = false, $ipV4Long = false)
|
||||||
|
{
|
||||||
|
$myBytes = $this->getBytes();
|
||||||
|
$ipv6Bytes = array_merge(array_slice($myBytes, 0, 12), array(0xff, 0xff, 0xff, 0xff));
|
||||||
|
$ipv6String = static::fromBytes($ipv6Bytes)->toString($ipV6Long);
|
||||||
|
$ipv4Bytes = array_slice($myBytes, 12, 4);
|
||||||
|
$ipv4String = IPv4::fromBytes($ipv4Bytes)->toString($ipV4Long);
|
||||||
|
|
||||||
|
return preg_replace('/((ffff:ffff)|(\d+(\.\d+){3}))$/i', $ipv4String, $ipv6String);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getComparableString()
|
||||||
|
*/
|
||||||
|
public function getComparableString()
|
||||||
|
{
|
||||||
|
return $this->longAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::matches()
|
||||||
|
*/
|
||||||
|
public function matches(RangeInterface $range)
|
||||||
|
{
|
||||||
|
return $range->contains($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getNextAddress()
|
||||||
|
*/
|
||||||
|
public function getNextAddress()
|
||||||
|
{
|
||||||
|
$overflow = false;
|
||||||
|
$words = $this->getWords();
|
||||||
|
for ($i = count($words) - 1; $i >= 0; $i--) {
|
||||||
|
if ($words[$i] === 0xffff) {
|
||||||
|
if ($i === 0) {
|
||||||
|
$overflow = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$words[$i] = 0;
|
||||||
|
} else {
|
||||||
|
$words[$i]++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $overflow ? null : static::fromWords($words);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getPreviousAddress()
|
||||||
|
*/
|
||||||
|
public function getPreviousAddress()
|
||||||
|
{
|
||||||
|
$overflow = false;
|
||||||
|
$words = $this->getWords();
|
||||||
|
for ($i = count($words) - 1; $i >= 0; $i--) {
|
||||||
|
if ($words[$i] === 0) {
|
||||||
|
if ($i === 0) {
|
||||||
|
$overflow = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$words[$i] = 0xffff;
|
||||||
|
} else {
|
||||||
|
$words[$i]--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $overflow ? null : static::fromWords($words);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Address\AddressInterface::getReverseDNSLookupName()
|
||||||
|
*/
|
||||||
|
public function getReverseDNSLookupName()
|
||||||
|
{
|
||||||
|
return implode(
|
||||||
|
'.',
|
||||||
|
array_reverse(str_split(str_replace(':', '', $this->toString(true)), 1))
|
||||||
|
) . '.ip6.arpa';
|
||||||
|
}
|
||||||
|
}
|
||||||
42
vendor/mlocati/ip-lib/src/Address/Type.php
vendored
Normal file
42
vendor/mlocati/ip-lib/src/Address/Type.php
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace IPLib\Address;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types of IP addresses.
|
||||||
|
*/
|
||||||
|
class Type
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* IPv4 address.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const T_IPv4 = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IPv6 address.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const T_IPv6 = 6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of a type.
|
||||||
|
*
|
||||||
|
* @param int $type
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getName($type)
|
||||||
|
{
|
||||||
|
switch ($type) {
|
||||||
|
case static::T_IPv4:
|
||||||
|
return 'IP v4';
|
||||||
|
case static::T_IPv6:
|
||||||
|
return 'IP v6';
|
||||||
|
default:
|
||||||
|
return sprintf('Unknown type (%s)', $type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
205
vendor/mlocati/ip-lib/src/Factory.php
vendored
Normal file
205
vendor/mlocati/ip-lib/src/Factory.php
vendored
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace IPLib;
|
||||||
|
|
||||||
|
use IPLib\Address\AddressInterface;
|
||||||
|
use IPLib\Range\Subnet;
|
||||||
|
use IPLib\Service\RangesFromBounradyCalculator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory methods to build class instances.
|
||||||
|
*/
|
||||||
|
class Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Parse an IP address string.
|
||||||
|
*
|
||||||
|
* @param string $address the address to parse
|
||||||
|
* @param bool $mayIncludePort set to false to avoid parsing addresses with ports
|
||||||
|
* @param bool $mayIncludeZoneID set to false to avoid parsing IPv6 addresses with zone IDs (see RFC 4007)
|
||||||
|
* @param bool $supportNonDecimalIPv4 set to true to support parsing non decimal (that is, octal and hexadecimal) IPv4 addresses
|
||||||
|
*
|
||||||
|
* @return \IPLib\Address\AddressInterface|null
|
||||||
|
*/
|
||||||
|
public static function addressFromString($address, $mayIncludePort = true, $mayIncludeZoneID = true, $supportNonDecimalIPv4 = false)
|
||||||
|
{
|
||||||
|
$result = null;
|
||||||
|
if ($result === null) {
|
||||||
|
$result = Address\IPv4::fromString($address, $mayIncludePort, $supportNonDecimalIPv4);
|
||||||
|
}
|
||||||
|
if ($result === null) {
|
||||||
|
$result = Address\IPv6::fromString($address, $mayIncludePort, $mayIncludeZoneID);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a byte array to an address instance.
|
||||||
|
*
|
||||||
|
* @param int[]|array $bytes
|
||||||
|
*
|
||||||
|
* @return \IPLib\Address\AddressInterface|null
|
||||||
|
*/
|
||||||
|
public static function addressFromBytes(array $bytes)
|
||||||
|
{
|
||||||
|
$result = null;
|
||||||
|
if ($result === null) {
|
||||||
|
$result = Address\IPv4::fromBytes($bytes);
|
||||||
|
}
|
||||||
|
if ($result === null) {
|
||||||
|
$result = Address\IPv6::fromBytes($bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse an IP range string.
|
||||||
|
*
|
||||||
|
* @param string $range
|
||||||
|
* @param bool $supportNonDecimalIPv4 set to true to support parsing non decimal (that is, octal and hexadecimal) IPv4 addresses
|
||||||
|
*
|
||||||
|
* @return \IPLib\Range\RangeInterface|null
|
||||||
|
*/
|
||||||
|
public static function rangeFromString($range, $supportNonDecimalIPv4 = false)
|
||||||
|
{
|
||||||
|
$result = null;
|
||||||
|
if ($result === null) {
|
||||||
|
$result = Range\Subnet::fromString($range, $supportNonDecimalIPv4);
|
||||||
|
}
|
||||||
|
if ($result === null) {
|
||||||
|
$result = Range\Pattern::fromString($range, $supportNonDecimalIPv4);
|
||||||
|
}
|
||||||
|
if ($result === null) {
|
||||||
|
$result = Range\Single::fromString($range, $supportNonDecimalIPv4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the smallest address range that comprises two addresses.
|
||||||
|
*
|
||||||
|
* @param string|\IPLib\Address\AddressInterface $from
|
||||||
|
* @param string|\IPLib\Address\AddressInterface $to
|
||||||
|
* @param bool $supportNonDecimalIPv4 set to true to support parsing non decimal (that is, octal and hexadecimal) IPv4 addresses
|
||||||
|
*
|
||||||
|
* @return \IPLib\Range\RangeInterface|null return NULL if $from and/or $to are invalid addresses, or if both are NULL or empty strings, or if they are addresses of different types
|
||||||
|
*/
|
||||||
|
public static function rangeFromBoundaries($from, $to, $supportNonDecimalIPv4 = false)
|
||||||
|
{
|
||||||
|
list($from, $to) = self::parseBoundaries($from, $to, $supportNonDecimalIPv4);
|
||||||
|
|
||||||
|
return $from === false || $to === false ? null : static::rangeFromBoundaryAddresses($from, $to);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a list of Range instances that exactly describes all the addresses between the two provided addresses.
|
||||||
|
*
|
||||||
|
* @param string|\IPLib\Address\AddressInterface $from
|
||||||
|
* @param string|\IPLib\Address\AddressInterface $to
|
||||||
|
* @param bool $supportNonDecimalIPv4 set to true to support parsing non decimal (that is, octal and hexadecimal) IPv4 addresses
|
||||||
|
*
|
||||||
|
* @return \IPLib\Range\Subnet[]|null return NULL if $from and/or $to are invalid addresses, or if both are NULL or empty strings, or if they are addresses of different types
|
||||||
|
*/
|
||||||
|
public static function rangesFromBoundaries($from, $to, $supportNonDecimalIPv4 = false)
|
||||||
|
{
|
||||||
|
list($from, $to) = self::parseBoundaries($from, $to, $supportNonDecimalIPv4);
|
||||||
|
if (($from === false || $to === false) || ($from === null && $to === null)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if ($from === null || $to === null) {
|
||||||
|
$address = $from ? $from : $to;
|
||||||
|
|
||||||
|
return array(new Subnet($address, $address, $address->getNumberOfBits()));
|
||||||
|
}
|
||||||
|
$numberOfBits = $from->getNumberOfBits();
|
||||||
|
if ($to->getNumberOfBits() !== $numberOfBits) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$calculator = new RangesFromBounradyCalculator($numberOfBits);
|
||||||
|
|
||||||
|
return $calculator->getRanges($from, $to);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \IPLib\Address\AddressInterface $from
|
||||||
|
* @param \IPLib\Address\AddressInterface $to
|
||||||
|
*
|
||||||
|
* @return \IPLib\Range\RangeInterface|null
|
||||||
|
*/
|
||||||
|
protected static function rangeFromBoundaryAddresses(AddressInterface $from = null, AddressInterface $to = null)
|
||||||
|
{
|
||||||
|
if ($from === null && $to === null) {
|
||||||
|
$result = null;
|
||||||
|
} elseif ($to === null) {
|
||||||
|
$result = Range\Single::fromAddress($from);
|
||||||
|
} elseif ($from === null) {
|
||||||
|
$result = Range\Single::fromAddress($to);
|
||||||
|
} else {
|
||||||
|
$result = null;
|
||||||
|
$addressType = $from->getAddressType();
|
||||||
|
if ($addressType === $to->getAddressType()) {
|
||||||
|
$cmp = strcmp($from->getComparableString(), $to->getComparableString());
|
||||||
|
if ($cmp === 0) {
|
||||||
|
$result = Range\Single::fromAddress($from);
|
||||||
|
} else {
|
||||||
|
if ($cmp > 0) {
|
||||||
|
list($from, $to) = array($to, $from);
|
||||||
|
}
|
||||||
|
$fromBytes = $from->getBytes();
|
||||||
|
$toBytes = $to->getBytes();
|
||||||
|
$numBytes = count($fromBytes);
|
||||||
|
$sameBits = 0;
|
||||||
|
for ($byteIndex = 0; $byteIndex < $numBytes; $byteIndex++) {
|
||||||
|
$fromByte = $fromBytes[$byteIndex];
|
||||||
|
$toByte = $toBytes[$byteIndex];
|
||||||
|
if ($fromByte === $toByte) {
|
||||||
|
$sameBits += 8;
|
||||||
|
} else {
|
||||||
|
$differentBitsInByte = decbin($fromByte ^ $toByte);
|
||||||
|
$sameBits += 8 - strlen($differentBitsInByte);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$result = static::rangeFromString($from->toString(true) . '/' . (string) $sameBits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|\IPLib\Address\AddressInterface $from
|
||||||
|
* @param string|\IPLib\Address\AddressInterface $to
|
||||||
|
* @param bool $supportNonDecimalIPv4
|
||||||
|
*
|
||||||
|
* @return \IPLib\Address\AddressInterface[]|null[]|false[]
|
||||||
|
*/
|
||||||
|
private static function parseBoundaries($from, $to, $supportNonDecimalIPv4 = false)
|
||||||
|
{
|
||||||
|
$result = array();
|
||||||
|
foreach (array('from', 'to') as $param) {
|
||||||
|
$value = $$param;
|
||||||
|
if (!($value instanceof AddressInterface)) {
|
||||||
|
$value = (string) $value;
|
||||||
|
if ($value === '') {
|
||||||
|
$value = null;
|
||||||
|
} else {
|
||||||
|
$value = static::addressFromString($value, true, true, $supportNonDecimalIPv4);
|
||||||
|
if ($value === null) {
|
||||||
|
$value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$result[] = $value;
|
||||||
|
}
|
||||||
|
if ($result[0] && $result[1] && strcmp($result[0]->getComparableString(), $result[1]->getComparableString()) > 0) {
|
||||||
|
$result = array($result[1], $result[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
95
vendor/mlocati/ip-lib/src/Range/AbstractRange.php
vendored
Normal file
95
vendor/mlocati/ip-lib/src/Range/AbstractRange.php
vendored
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace IPLib\Range;
|
||||||
|
|
||||||
|
use IPLib\Address\AddressInterface;
|
||||||
|
use IPLib\Address\IPv4;
|
||||||
|
use IPLib\Address\IPv6;
|
||||||
|
use IPLib\Address\Type as AddressType;
|
||||||
|
use IPLib\Factory;
|
||||||
|
|
||||||
|
abstract class AbstractRange implements RangeInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getRangeType()
|
||||||
|
*/
|
||||||
|
public function getRangeType()
|
||||||
|
{
|
||||||
|
if ($this->rangeType === null) {
|
||||||
|
$addressType = $this->getAddressType();
|
||||||
|
if ($addressType === AddressType::T_IPv6 && Subnet::get6to4()->containsRange($this)) {
|
||||||
|
$this->rangeType = Factory::rangeFromBoundaries($this->fromAddress->toIPv4(), $this->toAddress->toIPv4())->getRangeType();
|
||||||
|
} else {
|
||||||
|
switch ($addressType) {
|
||||||
|
case AddressType::T_IPv4:
|
||||||
|
$defaultType = IPv4::getDefaultReservedRangeType();
|
||||||
|
$reservedRanges = IPv4::getReservedRanges();
|
||||||
|
break;
|
||||||
|
case AddressType::T_IPv6:
|
||||||
|
$defaultType = IPv6::getDefaultReservedRangeType();
|
||||||
|
$reservedRanges = IPv6::getReservedRanges();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new \Exception('@todo'); // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
$rangeType = null;
|
||||||
|
foreach ($reservedRanges as $reservedRange) {
|
||||||
|
$rangeType = $reservedRange->getRangeType($this);
|
||||||
|
if ($rangeType !== null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->rangeType = $rangeType === null ? $defaultType : $rangeType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->rangeType === false ? null : $this->rangeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::contains()
|
||||||
|
*/
|
||||||
|
public function contains(AddressInterface $address)
|
||||||
|
{
|
||||||
|
$result = false;
|
||||||
|
if ($address->getAddressType() === $this->getAddressType()) {
|
||||||
|
$cmp = $address->getComparableString();
|
||||||
|
$from = $this->getComparableStartString();
|
||||||
|
if ($cmp >= $from) {
|
||||||
|
$to = $this->getComparableEndString();
|
||||||
|
if ($cmp <= $to) {
|
||||||
|
$result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::containsRange()
|
||||||
|
*/
|
||||||
|
public function containsRange(RangeInterface $range)
|
||||||
|
{
|
||||||
|
$result = false;
|
||||||
|
if ($range->getAddressType() === $this->getAddressType()) {
|
||||||
|
$myStart = $this->getComparableStartString();
|
||||||
|
$itsStart = $range->getComparableStartString();
|
||||||
|
if ($itsStart >= $myStart) {
|
||||||
|
$myEnd = $this->getComparableEndString();
|
||||||
|
$itsEnd = $range->getComparableEndString();
|
||||||
|
if ($itsEnd <= $myEnd) {
|
||||||
|
$result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
275
vendor/mlocati/ip-lib/src/Range/Pattern.php
vendored
Normal file
275
vendor/mlocati/ip-lib/src/Range/Pattern.php
vendored
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace IPLib\Range;
|
||||||
|
|
||||||
|
use IPLib\Address\AddressInterface;
|
||||||
|
use IPLib\Address\IPv4;
|
||||||
|
use IPLib\Address\IPv6;
|
||||||
|
use IPLib\Address\Type as AddressType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an address range in pattern format (only ending asterisks are supported).
|
||||||
|
*
|
||||||
|
* @example 127.0.*.*
|
||||||
|
* @example ::/8
|
||||||
|
*/
|
||||||
|
class Pattern extends AbstractRange
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Starting address of the range.
|
||||||
|
*
|
||||||
|
* @var \IPLib\Address\AddressInterface
|
||||||
|
*/
|
||||||
|
protected $fromAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Final address of the range.
|
||||||
|
*
|
||||||
|
* @var \IPLib\Address\AddressInterface
|
||||||
|
*/
|
||||||
|
protected $toAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of ending asterisks.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $asterisksCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the range of this IP range.
|
||||||
|
*
|
||||||
|
* @var int|false|null false if this range crosses multiple range types, null if yet to be determined
|
||||||
|
*/
|
||||||
|
protected $rangeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the instance.
|
||||||
|
*
|
||||||
|
* @param \IPLib\Address\AddressInterface $fromAddress
|
||||||
|
* @param \IPLib\Address\AddressInterface $toAddress
|
||||||
|
* @param int $asterisksCount
|
||||||
|
*/
|
||||||
|
public function __construct(AddressInterface $fromAddress, AddressInterface $toAddress, $asterisksCount)
|
||||||
|
{
|
||||||
|
$this->fromAddress = $fromAddress;
|
||||||
|
$this->toAddress = $toAddress;
|
||||||
|
$this->asterisksCount = $asterisksCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::__toString()
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return $this->toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try get the range instance starting from its string representation.
|
||||||
|
*
|
||||||
|
* @param string|mixed $range
|
||||||
|
* @param bool $supportNonDecimalIPv4 set to true to support parsing non decimal (that is, octal and hexadecimal) IPv4 addresses
|
||||||
|
*
|
||||||
|
* @return static|null
|
||||||
|
*/
|
||||||
|
public static function fromString($range, $supportNonDecimalIPv4 = false)
|
||||||
|
{
|
||||||
|
if (!is_string($range) || strpos($range, '*') === false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if ($range === '*.*.*.*') {
|
||||||
|
return new static(IPv4::fromString('0.0.0.0'), IPv4::fromString('255.255.255.255'), 4);
|
||||||
|
}
|
||||||
|
if ($range === '*:*:*:*:*:*:*:*') {
|
||||||
|
return new static(IPv6::fromString('::'), IPv6::fromString('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'), 8);
|
||||||
|
}
|
||||||
|
$matches = null;
|
||||||
|
if (strpos($range, '.') !== false && preg_match('/^[^*]+((?:\.\*)+)$/', $range, $matches)) {
|
||||||
|
$asterisksCount = strlen($matches[1]) >> 1;
|
||||||
|
if ($asterisksCount > 0) {
|
||||||
|
$missingDots = 3 - substr_count($range, '.');
|
||||||
|
if ($missingDots > 0) {
|
||||||
|
$range .= str_repeat('.*', $missingDots);
|
||||||
|
$asterisksCount += $missingDots;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$fromAddress = IPv4::fromString(str_replace('*', '0', $range), true, $supportNonDecimalIPv4);
|
||||||
|
if ($fromAddress === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$fixedBytes = array_slice($fromAddress->getBytes(), 0, -$asterisksCount);
|
||||||
|
$otherBytes = array_fill(0, $asterisksCount, 255);
|
||||||
|
$toAddress = IPv4::fromBytes(array_merge($fixedBytes, $otherBytes));
|
||||||
|
|
||||||
|
return new static($fromAddress, $toAddress, $asterisksCount);
|
||||||
|
}
|
||||||
|
if (strpos($range, ':') !== false && preg_match('/^[^*]+((?::\*)+)$/', $range, $matches)) {
|
||||||
|
$asterisksCount = strlen($matches[1]) >> 1;
|
||||||
|
$fromAddress = IPv6::fromString(str_replace('*', '0', $range));
|
||||||
|
if ($fromAddress === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$fixedWords = array_slice($fromAddress->getWords(), 0, -$asterisksCount);
|
||||||
|
$otherWords = array_fill(0, $asterisksCount, 0xffff);
|
||||||
|
$toAddress = IPv6::fromWords(array_merge($fixedWords, $otherWords));
|
||||||
|
|
||||||
|
return new static($fromAddress, $toAddress, $asterisksCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::toString()
|
||||||
|
*/
|
||||||
|
public function toString($long = false)
|
||||||
|
{
|
||||||
|
if ($this->asterisksCount === 0) {
|
||||||
|
return $this->fromAddress->toString($long);
|
||||||
|
}
|
||||||
|
switch (true) {
|
||||||
|
case $this->fromAddress instanceof \IPLib\Address\IPv4:
|
||||||
|
$chunks = explode('.', $this->fromAddress->toString());
|
||||||
|
$chunks = array_slice($chunks, 0, -$this->asterisksCount);
|
||||||
|
$chunks = array_pad($chunks, 4, '*');
|
||||||
|
$result = implode('.', $chunks);
|
||||||
|
break;
|
||||||
|
case $this->fromAddress instanceof \IPLib\Address\IPv6:
|
||||||
|
if ($long) {
|
||||||
|
$chunks = explode(':', $this->fromAddress->toString(true));
|
||||||
|
$chunks = array_slice($chunks, 0, -$this->asterisksCount);
|
||||||
|
$chunks = array_pad($chunks, 8, '*');
|
||||||
|
$result = implode(':', $chunks);
|
||||||
|
} elseif ($this->asterisksCount === 8) {
|
||||||
|
$result = '*:*:*:*:*:*:*:*';
|
||||||
|
} else {
|
||||||
|
$bytes = $this->toAddress->getBytes();
|
||||||
|
$bytes = array_slice($bytes, 0, -$this->asterisksCount * 2);
|
||||||
|
$bytes = array_pad($bytes, 16, 1);
|
||||||
|
$address = IPv6::fromBytes($bytes);
|
||||||
|
$before = substr($address->toString(false), 0, -strlen(':101') * $this->asterisksCount);
|
||||||
|
$result = $before . str_repeat(':*', $this->asterisksCount);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new \Exception('@todo'); // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getAddressType()
|
||||||
|
*/
|
||||||
|
public function getAddressType()
|
||||||
|
{
|
||||||
|
return $this->fromAddress->getAddressType();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getStartAddress()
|
||||||
|
*/
|
||||||
|
public function getStartAddress()
|
||||||
|
{
|
||||||
|
return $this->fromAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getEndAddress()
|
||||||
|
*/
|
||||||
|
public function getEndAddress()
|
||||||
|
{
|
||||||
|
return $this->toAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getComparableStartString()
|
||||||
|
*/
|
||||||
|
public function getComparableStartString()
|
||||||
|
{
|
||||||
|
return $this->fromAddress->getComparableString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getComparableEndString()
|
||||||
|
*/
|
||||||
|
public function getComparableEndString()
|
||||||
|
{
|
||||||
|
return $this->toAddress->getComparableString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::asSubnet()
|
||||||
|
*/
|
||||||
|
public function asSubnet()
|
||||||
|
{
|
||||||
|
switch ($this->getAddressType()) {
|
||||||
|
case AddressType::T_IPv4:
|
||||||
|
return new Subnet($this->getStartAddress(), $this->getEndAddress(), 8 * (4 - $this->asterisksCount));
|
||||||
|
case AddressType::T_IPv6:
|
||||||
|
return new Subnet($this->getStartAddress(), $this->getEndAddress(), 16 * (8 - $this->asterisksCount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::asPattern()
|
||||||
|
*/
|
||||||
|
public function asPattern()
|
||||||
|
{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getSubnetMask()
|
||||||
|
*/
|
||||||
|
public function getSubnetMask()
|
||||||
|
{
|
||||||
|
if ($this->getAddressType() !== AddressType::T_IPv4) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
switch ($this->asterisksCount) {
|
||||||
|
case 0:
|
||||||
|
$bytes = array(255, 255, 255, 255);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
$bytes = array(0, 0, 0, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$bytes = array_pad(array_fill(0, 4 - $this->asterisksCount, 255), 4, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return IPv4::fromBytes($bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getReverseDNSLookupName()
|
||||||
|
*/
|
||||||
|
public function getReverseDNSLookupName()
|
||||||
|
{
|
||||||
|
return $this->asterisksCount === 0 ? array($this->getStartAddress()->getReverseDNSLookupName()) : $this->asSubnet()->getReverseDNSLookupName();
|
||||||
|
}
|
||||||
|
}
|
||||||
120
vendor/mlocati/ip-lib/src/Range/RangeInterface.php
vendored
Normal file
120
vendor/mlocati/ip-lib/src/Range/RangeInterface.php
vendored
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace IPLib\Range;
|
||||||
|
|
||||||
|
use IPLib\Address\AddressInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface of all the range types.
|
||||||
|
*/
|
||||||
|
interface RangeInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the short string representation of this address.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the string representation of this address.
|
||||||
|
*
|
||||||
|
* @param bool $long set to true to have a long/full representation, false otherwise
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @example If $long is true, you'll get '0000:0000:0000:0000:0000:0000:0000:0001/128', '::1/128' otherwise.
|
||||||
|
*/
|
||||||
|
public function toString($long = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the type of the IP addresses contained in this range.
|
||||||
|
*
|
||||||
|
* @return int One of the \IPLib\Address\Type::T_... constants
|
||||||
|
*/
|
||||||
|
public function getAddressType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the type of range of the IP address.
|
||||||
|
*
|
||||||
|
* @return int One of the \IPLib\Range\Type::T_... constants
|
||||||
|
*/
|
||||||
|
public function getRangeType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this range contains an IP address.
|
||||||
|
*
|
||||||
|
* @param \IPLib\Address\AddressInterface $address
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function contains(AddressInterface $address);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this range contains another range.
|
||||||
|
*
|
||||||
|
* @param \IPLib\Range\RangeInterface $range
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function containsRange(RangeInterface $range);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the initial address contained in this range.
|
||||||
|
*
|
||||||
|
* @return \IPLib\Address\AddressInterface
|
||||||
|
*/
|
||||||
|
public function getStartAddress();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the final address contained in this range.
|
||||||
|
*
|
||||||
|
* @return \IPLib\Address\AddressInterface
|
||||||
|
*/
|
||||||
|
public function getEndAddress();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a string representation of the starting address of this range than can be used when comparing addresses and ranges.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getComparableStartString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a string representation of the final address of this range than can be used when comparing addresses and ranges.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getComparableEndString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the subnet mask representing this range (only for IPv4 ranges).
|
||||||
|
*
|
||||||
|
* @return \IPLib\Address\IPv4|null return NULL if the range is an IPv6 range, the subnet mask otherwise
|
||||||
|
*/
|
||||||
|
public function getSubnetMask();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the subnet/CIDR representation of this range.
|
||||||
|
*
|
||||||
|
* @return \IPLib\Range\Subnet
|
||||||
|
*/
|
||||||
|
public function asSubnet();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the pattern/asterisk representation (if applicable) of this range.
|
||||||
|
*
|
||||||
|
* @return \IPLib\Range\Pattern|null return NULL if this range can't be represented by a pattern notation
|
||||||
|
*/
|
||||||
|
public function asPattern();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Reverse DNS Lookup Addresses of this IP range.
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
*
|
||||||
|
* @example for IPv4 it returns something like array('x.x.x.x.in-addr.arpa', 'x.x.x.x.in-addr.arpa') (where the number of 'x.' ranges from 1 to 4)
|
||||||
|
* @example for IPv6 it returns something like array('x.x.x.x..x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa', 'x.x.x.x..x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa') (where the number of 'x.' ranges from 1 to 32)
|
||||||
|
*/
|
||||||
|
public function getReverseDNSLookupName();
|
||||||
|
}
|
||||||
226
vendor/mlocati/ip-lib/src/Range/Single.php
vendored
Normal file
226
vendor/mlocati/ip-lib/src/Range/Single.php
vendored
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace IPLib\Range;
|
||||||
|
|
||||||
|
use IPLib\Address\AddressInterface;
|
||||||
|
use IPLib\Address\IPv4;
|
||||||
|
use IPLib\Address\Type as AddressType;
|
||||||
|
use IPLib\Factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a single address (eg a range that contains just one address).
|
||||||
|
*
|
||||||
|
* @example 127.0.0.1
|
||||||
|
* @example ::1
|
||||||
|
*/
|
||||||
|
class Single extends AbstractRange
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \IPLib\Address\AddressInterface
|
||||||
|
*/
|
||||||
|
protected $address;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the instance.
|
||||||
|
*
|
||||||
|
* @param \IPLib\Address\AddressInterface $address
|
||||||
|
*/
|
||||||
|
protected function __construct(AddressInterface $address)
|
||||||
|
{
|
||||||
|
$this->address = $address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::__toString()
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return $this->address->__toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try get the range instance starting from its string representation.
|
||||||
|
*
|
||||||
|
* @param string|mixed $range
|
||||||
|
* @param bool $supportNonDecimalIPv4 set to true to support parsing non decimal (that is, octal and hexadecimal) IPv4 addresses
|
||||||
|
*
|
||||||
|
* @return static|null
|
||||||
|
*/
|
||||||
|
public static function fromString($range, $supportNonDecimalIPv4 = false)
|
||||||
|
{
|
||||||
|
$result = null;
|
||||||
|
$address = Factory::addressFromString($range, true, true, $supportNonDecimalIPv4);
|
||||||
|
if ($address !== null) {
|
||||||
|
$result = new static($address);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the range instance starting from an address instance.
|
||||||
|
*
|
||||||
|
* @param \IPLib\Address\AddressInterface $address
|
||||||
|
*
|
||||||
|
* @return static
|
||||||
|
*/
|
||||||
|
public static function fromAddress(AddressInterface $address)
|
||||||
|
{
|
||||||
|
return new static($address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::toString()
|
||||||
|
*/
|
||||||
|
public function toString($long = false)
|
||||||
|
{
|
||||||
|
return $this->address->toString($long);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getAddressType()
|
||||||
|
*/
|
||||||
|
public function getAddressType()
|
||||||
|
{
|
||||||
|
return $this->address->getAddressType();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getRangeType()
|
||||||
|
*/
|
||||||
|
public function getRangeType()
|
||||||
|
{
|
||||||
|
return $this->address->getRangeType();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::contains()
|
||||||
|
*/
|
||||||
|
public function contains(AddressInterface $address)
|
||||||
|
{
|
||||||
|
$result = false;
|
||||||
|
if ($address->getAddressType() === $this->getAddressType()) {
|
||||||
|
if ($address->toString(false) === $this->address->toString(false)) {
|
||||||
|
$result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::containsRange()
|
||||||
|
*/
|
||||||
|
public function containsRange(RangeInterface $range)
|
||||||
|
{
|
||||||
|
$result = false;
|
||||||
|
if ($range->getAddressType() === $this->getAddressType()) {
|
||||||
|
if ($range->toString(false) === $this->toString(false)) {
|
||||||
|
$result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getStartAddress()
|
||||||
|
*/
|
||||||
|
public function getStartAddress()
|
||||||
|
{
|
||||||
|
return $this->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getEndAddress()
|
||||||
|
*/
|
||||||
|
public function getEndAddress()
|
||||||
|
{
|
||||||
|
return $this->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getComparableStartString()
|
||||||
|
*/
|
||||||
|
public function getComparableStartString()
|
||||||
|
{
|
||||||
|
return $this->address->getComparableString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getComparableEndString()
|
||||||
|
*/
|
||||||
|
public function getComparableEndString()
|
||||||
|
{
|
||||||
|
return $this->address->getComparableString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::asSubnet()
|
||||||
|
*/
|
||||||
|
public function asSubnet()
|
||||||
|
{
|
||||||
|
$networkPrefixes = array(
|
||||||
|
AddressType::T_IPv4 => 32,
|
||||||
|
AddressType::T_IPv6 => 128,
|
||||||
|
);
|
||||||
|
|
||||||
|
return new Subnet($this->address, $this->address, $networkPrefixes[$this->address->getAddressType()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::asPattern()
|
||||||
|
*/
|
||||||
|
public function asPattern()
|
||||||
|
{
|
||||||
|
return new Pattern($this->address, $this->address, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getSubnetMask()
|
||||||
|
*/
|
||||||
|
public function getSubnetMask()
|
||||||
|
{
|
||||||
|
if ($this->getAddressType() !== AddressType::T_IPv4) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return IPv4::fromBytes(array(255, 255, 255, 255));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getReverseDNSLookupName()
|
||||||
|
*/
|
||||||
|
public function getReverseDNSLookupName()
|
||||||
|
{
|
||||||
|
return array($this->getStartAddress()->getReverseDNSLookupName());
|
||||||
|
}
|
||||||
|
}
|
||||||
305
vendor/mlocati/ip-lib/src/Range/Subnet.php
vendored
Normal file
305
vendor/mlocati/ip-lib/src/Range/Subnet.php
vendored
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace IPLib\Range;
|
||||||
|
|
||||||
|
use IPLib\Address\AddressInterface;
|
||||||
|
use IPLib\Address\IPv4;
|
||||||
|
use IPLib\Address\IPv6;
|
||||||
|
use IPLib\Address\Type as AddressType;
|
||||||
|
use IPLib\Factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an address range in subnet format (eg CIDR).
|
||||||
|
*
|
||||||
|
* @example 127.0.0.1/32
|
||||||
|
* @example ::/8
|
||||||
|
*/
|
||||||
|
class Subnet extends AbstractRange
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Starting address of the range.
|
||||||
|
*
|
||||||
|
* @var \IPLib\Address\AddressInterface
|
||||||
|
*/
|
||||||
|
protected $fromAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Final address of the range.
|
||||||
|
*
|
||||||
|
* @var \IPLib\Address\AddressInterface
|
||||||
|
*/
|
||||||
|
protected $toAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of the same bits of the range.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $networkPrefix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the range of this IP range.
|
||||||
|
*
|
||||||
|
* @var int|null
|
||||||
|
*/
|
||||||
|
protected $rangeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The 6to4 address IPv6 address range.
|
||||||
|
*
|
||||||
|
* @var self|null
|
||||||
|
*/
|
||||||
|
private static $sixToFour;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the instance.
|
||||||
|
*
|
||||||
|
* @param \IPLib\Address\AddressInterface $fromAddress
|
||||||
|
* @param \IPLib\Address\AddressInterface $toAddress
|
||||||
|
* @param int $networkPrefix
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
public function __construct(AddressInterface $fromAddress, AddressInterface $toAddress, $networkPrefix)
|
||||||
|
{
|
||||||
|
$this->fromAddress = $fromAddress;
|
||||||
|
$this->toAddress = $toAddress;
|
||||||
|
$this->networkPrefix = $networkPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::__toString()
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return $this->toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try get the range instance starting from its string representation.
|
||||||
|
*
|
||||||
|
* @param string|mixed $range
|
||||||
|
* @param bool $supportNonDecimalIPv4 set to true to support parsing non decimal (that is, octal and hexadecimal) IPv4 addresses
|
||||||
|
*
|
||||||
|
* @return static|null
|
||||||
|
*/
|
||||||
|
public static function fromString($range, $supportNonDecimalIPv4 = false)
|
||||||
|
{
|
||||||
|
if (!is_string($range)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$parts = explode('/', $range);
|
||||||
|
if (count($parts) !== 2) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$address = Factory::addressFromString($parts[0], true, true, $supportNonDecimalIPv4);
|
||||||
|
if ($address === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!preg_match('/^[0-9]{1,9}$/', $parts[1])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$networkPrefix = (int) $parts[1];
|
||||||
|
$addressBytes = $address->getBytes();
|
||||||
|
$totalBytes = count($addressBytes);
|
||||||
|
$numDifferentBits = $totalBytes * 8 - $networkPrefix;
|
||||||
|
if ($numDifferentBits < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$numSameBytes = $networkPrefix >> 3;
|
||||||
|
$sameBytes = array_slice($addressBytes, 0, $numSameBytes);
|
||||||
|
$differentBytesStart = ($totalBytes === $numSameBytes) ? array() : array_fill(0, $totalBytes - $numSameBytes, 0);
|
||||||
|
$differentBytesEnd = ($totalBytes === $numSameBytes) ? array() : array_fill(0, $totalBytes - $numSameBytes, 255);
|
||||||
|
$startSameBits = $networkPrefix % 8;
|
||||||
|
if ($startSameBits !== 0) {
|
||||||
|
$varyingByte = $addressBytes[$numSameBytes];
|
||||||
|
$differentBytesStart[0] = $varyingByte & bindec(str_pad(str_repeat('1', $startSameBits), 8, '0', STR_PAD_RIGHT));
|
||||||
|
$differentBytesEnd[0] = $differentBytesStart[0] + bindec(str_repeat('1', 8 - $startSameBits));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new static(
|
||||||
|
Factory::addressFromBytes(array_merge($sameBytes, $differentBytesStart)),
|
||||||
|
Factory::addressFromBytes(array_merge($sameBytes, $differentBytesEnd)),
|
||||||
|
$networkPrefix
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::toString()
|
||||||
|
*/
|
||||||
|
public function toString($long = false)
|
||||||
|
{
|
||||||
|
return $this->fromAddress->toString($long) . '/' . $this->networkPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getAddressType()
|
||||||
|
*/
|
||||||
|
public function getAddressType()
|
||||||
|
{
|
||||||
|
return $this->fromAddress->getAddressType();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getStartAddress()
|
||||||
|
*/
|
||||||
|
public function getStartAddress()
|
||||||
|
{
|
||||||
|
return $this->fromAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getEndAddress()
|
||||||
|
*/
|
||||||
|
public function getEndAddress()
|
||||||
|
{
|
||||||
|
return $this->toAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getComparableStartString()
|
||||||
|
*/
|
||||||
|
public function getComparableStartString()
|
||||||
|
{
|
||||||
|
return $this->fromAddress->getComparableString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getComparableEndString()
|
||||||
|
*/
|
||||||
|
public function getComparableEndString()
|
||||||
|
{
|
||||||
|
return $this->toAddress->getComparableString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::asSubnet()
|
||||||
|
*/
|
||||||
|
public function asSubnet()
|
||||||
|
{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the pattern (asterisk) representation (if applicable) of this range.
|
||||||
|
*
|
||||||
|
* @return \IPLib\Range\Pattern|null return NULL if this range can't be represented by a pattern notation
|
||||||
|
*/
|
||||||
|
public function asPattern()
|
||||||
|
{
|
||||||
|
$address = $this->getStartAddress();
|
||||||
|
$networkPrefix = $this->getNetworkPrefix();
|
||||||
|
switch ($address->getAddressType()) {
|
||||||
|
case AddressType::T_IPv4:
|
||||||
|
return $networkPrefix % 8 === 0 ? new Pattern($address, $address, 4 - $networkPrefix / 8) : null;
|
||||||
|
case AddressType::T_IPv6:
|
||||||
|
return $networkPrefix % 16 === 0 ? new Pattern($address, $address, 8 - $networkPrefix / 16) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the 6to4 address IPv6 address range.
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public static function get6to4()
|
||||||
|
{
|
||||||
|
if (self::$sixToFour === null) {
|
||||||
|
self::$sixToFour = self::fromString('2002::/16');
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$sixToFour;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get subnet prefix.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getNetworkPrefix()
|
||||||
|
{
|
||||||
|
return $this->networkPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getSubnetMask()
|
||||||
|
*/
|
||||||
|
public function getSubnetMask()
|
||||||
|
{
|
||||||
|
if ($this->getAddressType() !== AddressType::T_IPv4) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$bytes = array();
|
||||||
|
$prefix = $this->getNetworkPrefix();
|
||||||
|
while ($prefix >= 8) {
|
||||||
|
$bytes[] = 255;
|
||||||
|
$prefix -= 8;
|
||||||
|
}
|
||||||
|
if ($prefix !== 0) {
|
||||||
|
$bytes[] = bindec(str_pad(str_repeat('1', $prefix), 8, '0'));
|
||||||
|
}
|
||||||
|
$bytes = array_pad($bytes, 4, 0);
|
||||||
|
|
||||||
|
return IPv4::fromBytes($bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see \IPLib\Range\RangeInterface::getReverseDNSLookupName()
|
||||||
|
*/
|
||||||
|
public function getReverseDNSLookupName()
|
||||||
|
{
|
||||||
|
switch ($this->getAddressType()) {
|
||||||
|
case AddressType::T_IPv4:
|
||||||
|
$unitSize = 8; // bytes
|
||||||
|
$maxUnits = 4;
|
||||||
|
$isHex = false;
|
||||||
|
$rxUnit = '\d+';
|
||||||
|
break;
|
||||||
|
case AddressType::T_IPv6:
|
||||||
|
$unitSize = 4; // nibbles
|
||||||
|
$maxUnits = 32;
|
||||||
|
$isHex = true;
|
||||||
|
$rxUnit = '[0-9A-Fa-f]';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$totBits = $unitSize * $maxUnits;
|
||||||
|
$prefixUnits = (int) ($this->networkPrefix / $unitSize);
|
||||||
|
$extraBits = ($totBits - $this->networkPrefix) % $unitSize;
|
||||||
|
if ($extraBits !== 0) {
|
||||||
|
$prefixUnits += 1;
|
||||||
|
}
|
||||||
|
$numVariants = 1 << $extraBits;
|
||||||
|
$result = array();
|
||||||
|
$unitsToRemove = $maxUnits - $prefixUnits;
|
||||||
|
$initialPointer = preg_replace("/^(({$rxUnit})\.){{$unitsToRemove}}/", '', $this->getStartAddress()->getReverseDNSLookupName());
|
||||||
|
$chunks = explode('.', $initialPointer, 2);
|
||||||
|
for ($index = 0; $index < $numVariants; $index++) {
|
||||||
|
if ($index !== 0) {
|
||||||
|
$chunks[0] = $isHex ? dechex(1 + hexdec($chunks[0])) : (string) (1 + (int) $chunks[0]);
|
||||||
|
}
|
||||||
|
$result[] = implode('.', $chunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
150
vendor/mlocati/ip-lib/src/Range/Type.php
vendored
Normal file
150
vendor/mlocati/ip-lib/src/Range/Type.php
vendored
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace IPLib\Range;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types of IP address classes.
|
||||||
|
*/
|
||||||
|
class Type
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Unspecified/unknown address.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const T_UNSPECIFIED = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reserved/internal use only.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const T_RESERVED = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refer to source hosts on "this" network.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const T_THISNETWORK = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internet host loopback address.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const T_LOOPBACK = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Relay anycast address.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const T_ANYCASTRELAY = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Limited broadcast" destination address.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const T_LIMITEDBROADCAST = 6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multicast address assignments - Indentify a group of interfaces.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const T_MULTICAST = 7;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Link local" address, allocated for communication between hosts on a single link.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const T_LINKLOCAL = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link local unicast / Linked-scoped unicast.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const T_LINKLOCAL_UNICAST = 9;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discard-Only address.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const T_DISCARDONLY = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discard address.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const T_DISCARD = 11;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For use in private networks.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const T_PRIVATENETWORK = 12;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public address.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const T_PUBLIC = 13;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Carrier-grade NAT address.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const T_CGNAT = 14;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of a type.
|
||||||
|
*
|
||||||
|
* @param int $type
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getName($type)
|
||||||
|
{
|
||||||
|
switch ($type) {
|
||||||
|
case static::T_UNSPECIFIED:
|
||||||
|
return 'Unspecified/unknown address';
|
||||||
|
case static::T_RESERVED:
|
||||||
|
return 'Reserved/internal use only';
|
||||||
|
case static::T_THISNETWORK:
|
||||||
|
return 'Refer to source hosts on "this" network';
|
||||||
|
case static::T_LOOPBACK:
|
||||||
|
return 'Internet host loopback address';
|
||||||
|
case static::T_ANYCASTRELAY:
|
||||||
|
return 'Relay anycast address';
|
||||||
|
case static::T_LIMITEDBROADCAST:
|
||||||
|
return '"Limited broadcast" destination address';
|
||||||
|
case static::T_MULTICAST:
|
||||||
|
return 'Multicast address assignments - Indentify a group of interfaces';
|
||||||
|
case static::T_LINKLOCAL:
|
||||||
|
return '"Link local" address, allocated for communication between hosts on a single link';
|
||||||
|
case static::T_LINKLOCAL_UNICAST:
|
||||||
|
return 'Link local unicast / Linked-scoped unicast';
|
||||||
|
case static::T_DISCARDONLY:
|
||||||
|
return 'Discard only';
|
||||||
|
case static::T_DISCARD:
|
||||||
|
return 'Discard';
|
||||||
|
case static::T_PRIVATENETWORK:
|
||||||
|
return 'For use in private networks';
|
||||||
|
case static::T_PUBLIC:
|
||||||
|
return 'Public address';
|
||||||
|
case static::T_CGNAT:
|
||||||
|
return 'Carrier-grade NAT';
|
||||||
|
default:
|
||||||
|
return $type === null ? 'Unknown type' : sprintf('Unknown type (%s)', $type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
118
vendor/mlocati/ip-lib/src/Service/BinaryMath.php
vendored
Normal file
118
vendor/mlocati/ip-lib/src/Service/BinaryMath.php
vendored
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace IPLib\Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to work with unsigned binary integers.
|
||||||
|
*/
|
||||||
|
class BinaryMath
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Trim the leading zeroes from a non-negative integer represented in binary form.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function reduce($value)
|
||||||
|
{
|
||||||
|
$value = ltrim($value, '0');
|
||||||
|
|
||||||
|
return $value === '' ? '0' : $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare two non-negative integers represented in binary form.
|
||||||
|
*
|
||||||
|
* @param string $a
|
||||||
|
* @param string $b
|
||||||
|
*
|
||||||
|
* @return int 1 if $a is greater than $b, -1 if $b is greater than $b, 0 if they are the same
|
||||||
|
*/
|
||||||
|
public function compare($a, $b)
|
||||||
|
{
|
||||||
|
list($a, $b) = $this->toSameLength($a, $b);
|
||||||
|
|
||||||
|
return $a < $b ? -1 : ($a > $b ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add 1 to a non-negative integer represented in binary form.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function increment($value)
|
||||||
|
{
|
||||||
|
$lastZeroIndex = strrpos($value, '0');
|
||||||
|
if ($lastZeroIndex === false) {
|
||||||
|
return '1' . str_repeat('0', strlen($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ltrim(substr($value, 0, $lastZeroIndex), '0') . '1' . str_repeat('0', strlen($value) - $lastZeroIndex - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the bitwise AND of two non-negative integers represented in binary form.
|
||||||
|
*
|
||||||
|
* @param string $operand1
|
||||||
|
* @param string $operand2
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function andX($operand1, $operand2)
|
||||||
|
{
|
||||||
|
$operand1 = $this->reduce($operand1);
|
||||||
|
$operand2 = $this->reduce($operand2);
|
||||||
|
$numBits = min(strlen($operand1), strlen($operand2));
|
||||||
|
$operand1 = substr(str_pad($operand1, $numBits, '0', STR_PAD_LEFT), -$numBits);
|
||||||
|
$operand2 = substr(str_pad($operand2, $numBits, '0', STR_PAD_LEFT), -$numBits);
|
||||||
|
$result = '';
|
||||||
|
for ($index = 0; $index < $numBits; $index++) {
|
||||||
|
$result .= $operand1[$index] === '1' && $operand2[$index] === '1' ? '1' : '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->reduce($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the bitwise OR of two non-negative integers represented in binary form.
|
||||||
|
*
|
||||||
|
* @param string $operand1
|
||||||
|
* @param string $operand2
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function orX($operand1, $operand2)
|
||||||
|
{
|
||||||
|
list($operand1, $operand2, $numBits) = $this->toSameLength($operand1, $operand2);
|
||||||
|
$result = '';
|
||||||
|
for ($index = 0; $index < $numBits; $index++) {
|
||||||
|
$result .= $operand1[$index] === '1' || $operand2[$index] === '1' ? '1' : '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zero-padding of two non-negative integers represented in binary form, so that they have the same length.
|
||||||
|
*
|
||||||
|
* @param string $num1
|
||||||
|
* @param string $num2
|
||||||
|
*
|
||||||
|
* @return string[],int[] The first array element is $num1 (padded), the first array element is $num2 (padded), the third array element is the number of bits
|
||||||
|
*/
|
||||||
|
private function toSameLength($num1, $num2)
|
||||||
|
{
|
||||||
|
$num1 = $this->reduce($num1);
|
||||||
|
$num2 = $this->reduce($num2);
|
||||||
|
$numBits = max(strlen($num1), strlen($num2));
|
||||||
|
|
||||||
|
return array(
|
||||||
|
str_pad($num1, $numBits, '0', STR_PAD_LEFT),
|
||||||
|
str_pad($num2, $numBits, '0', STR_PAD_LEFT),
|
||||||
|
$numBits,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
161
vendor/mlocati/ip-lib/src/Service/RangesFromBounradyCalculator.php
vendored
Normal file
161
vendor/mlocati/ip-lib/src/Service/RangesFromBounradyCalculator.php
vendored
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace IPLib\Service;
|
||||||
|
|
||||||
|
use IPLib\Address\AddressInterface;
|
||||||
|
use IPLib\Factory;
|
||||||
|
use IPLib\Range\Subnet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to calculate the subnets describing all (and only all) the addresses between two bouundaries.
|
||||||
|
*/
|
||||||
|
class RangesFromBounradyCalculator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The BinaryMath instance to be used to perform bitwise poerations.
|
||||||
|
*
|
||||||
|
* @var \IPLib\Service\BinaryMath
|
||||||
|
*/
|
||||||
|
private $math;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of bits used to represent addresses.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*
|
||||||
|
* @example 32 for IPv4, 128 for IPv6
|
||||||
|
*/
|
||||||
|
private $numBits;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bit masks for every bit index.
|
||||||
|
*
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $masks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bit unmasks for every bit index.
|
||||||
|
*
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $unmasks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the instance.
|
||||||
|
*
|
||||||
|
* @param int $numBits the number of bits used to represent addresses (32 for IPv4, 128 for IPv6)
|
||||||
|
*/
|
||||||
|
public function __construct($numBits)
|
||||||
|
{
|
||||||
|
$this->math = new BinaryMath();
|
||||||
|
$this->setNumBits($numBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the subnets describing all (and only all) the addresses between two bouundaries.
|
||||||
|
*
|
||||||
|
* @param \IPLib\Address\AddressInterface $from
|
||||||
|
* @param \IPLib\Address\AddressInterface $to
|
||||||
|
*
|
||||||
|
* @return \IPLib\Range\Subnet[]|null return NULL if the two addresses have an invalid number of bits (that is, different from the one passed to the constructor of this class)
|
||||||
|
*/
|
||||||
|
public function getRanges(AddressInterface $from, AddressInterface $to)
|
||||||
|
{
|
||||||
|
if ($from->getNumberOfBits() !== $this->numBits || $to->getNumberOfBits() !== $this->numBits) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if ($from->getComparableString() > $to->getComparableString()) {
|
||||||
|
list($from, $to) = array($to, $from);
|
||||||
|
}
|
||||||
|
$result = array();
|
||||||
|
$this->calculate($this->math->reduce($from->getBits()), $this->math->reduce($to->getBits()), $this->numBits, $result);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the number of bits used to represent addresses (32 for IPv4, 128 for IPv6).
|
||||||
|
*
|
||||||
|
* @param int $numBits
|
||||||
|
*/
|
||||||
|
private function setNumBits($numBits)
|
||||||
|
{
|
||||||
|
$numBits = (int) $numBits;
|
||||||
|
$masks = array();
|
||||||
|
$unmasks = array();
|
||||||
|
for ($bit = 0; $bit < $numBits; $bit++) {
|
||||||
|
$masks[$bit] = str_repeat('1', $numBits - $bit) . str_repeat('0', $bit);
|
||||||
|
$unmasks[$bit] = $bit === 0 ? '0' : str_repeat('1', $bit);
|
||||||
|
}
|
||||||
|
$this->numBits = $numBits;
|
||||||
|
$this->masks = $masks;
|
||||||
|
$this->unmasks = $unmasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the subnets.
|
||||||
|
*
|
||||||
|
* @param string $start the start address (represented in reduced bit form)
|
||||||
|
* @param string $end the end address (represented in reduced bit form)
|
||||||
|
* @param int $position the number of bits in the mask we are comparing at this cycle
|
||||||
|
* @param \IPLib\Range\Subnet[] $result found ranges will be added to this variable
|
||||||
|
*/
|
||||||
|
private function calculate($start, $end, $position, array &$result)
|
||||||
|
{
|
||||||
|
if ($start === $end) {
|
||||||
|
$result[] = $this->subnetFromBits($start, $this->numBits);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for ($index = $position - 1; $index >= 0; $index--) {
|
||||||
|
$startMasked = $this->math->andX($start, $this->masks[$index]);
|
||||||
|
$endMasked = $this->math->andX($end, $this->masks[$index]);
|
||||||
|
if ($startMasked !== $endMasked) {
|
||||||
|
$position = $index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($startMasked === $start && $this->math->andX($this->math->increment($end), $this->unmasks[$position]) === '0') {
|
||||||
|
$result[] = $this->subnetFromBits($start, $this->numBits - 1 - $position);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$middleAddress = $this->math->orX($start, $this->unmasks[$position]);
|
||||||
|
$this->calculate($start, $middleAddress, $position, $result);
|
||||||
|
$this->calculate($this->math->increment($middleAddress), $end, $position, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an address instance starting from its bits.
|
||||||
|
*
|
||||||
|
* @param string $bits the bits of the address (represented in reduced bit form)
|
||||||
|
*
|
||||||
|
* @return \IPLib\Address\AddressInterface
|
||||||
|
*/
|
||||||
|
private function addressFromBits($bits)
|
||||||
|
{
|
||||||
|
$bits = str_pad($bits, $this->numBits, '0', STR_PAD_LEFT);
|
||||||
|
$bytes = array();
|
||||||
|
foreach (explode("\n", trim(chunk_split($bits, 8, "\n"))) as $byteBits) {
|
||||||
|
$bytes[] = bindec($byteBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Factory::addressFromBytes($bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an range instance starting from the bits if the address and the length of the network prefix.
|
||||||
|
*
|
||||||
|
* @param string $bits the bits of the address (represented in reduced bit form)
|
||||||
|
* @param int $networkPrefix the length of the network prefix
|
||||||
|
*
|
||||||
|
* @return \IPLib\Range\Subnet
|
||||||
|
*/
|
||||||
|
private function subnetFromBits($bits, $networkPrefix)
|
||||||
|
{
|
||||||
|
$address = $this->addressFromBits($bits);
|
||||||
|
|
||||||
|
return new Subnet($address, $address, $networkPrefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
vendor/paragonie/random_compat/lib/random.php
vendored
19
vendor/paragonie/random_compat/lib/random.php
vendored
@@ -54,9 +54,9 @@ if (!defined('RANDOM_COMPAT_READ_BUFFER')) {
|
|||||||
|
|
||||||
$RandomCompatDIR = dirname(__FILE__);
|
$RandomCompatDIR = dirname(__FILE__);
|
||||||
|
|
||||||
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'byte_safe_strings.php';
|
require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'byte_safe_strings.php';
|
||||||
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'cast_to_int.php';
|
require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'cast_to_int.php';
|
||||||
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'error_polyfill.php';
|
require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'error_polyfill.php';
|
||||||
|
|
||||||
if (!is_callable('random_bytes')) {
|
if (!is_callable('random_bytes')) {
|
||||||
/**
|
/**
|
||||||
@@ -76,9 +76,9 @@ if (!is_callable('random_bytes')) {
|
|||||||
if (extension_loaded('libsodium')) {
|
if (extension_loaded('libsodium')) {
|
||||||
// See random_bytes_libsodium.php
|
// See random_bytes_libsodium.php
|
||||||
if (PHP_VERSION_ID >= 50300 && is_callable('\\Sodium\\randombytes_buf')) {
|
if (PHP_VERSION_ID >= 50300 && is_callable('\\Sodium\\randombytes_buf')) {
|
||||||
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium.php';
|
require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'random_bytes_libsodium.php';
|
||||||
} elseif (method_exists('Sodium', 'randombytes_buf')) {
|
} elseif (method_exists('Sodium', 'randombytes_buf')) {
|
||||||
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_libsodium_legacy.php';
|
require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'random_bytes_libsodium_legacy.php';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ if (!is_callable('random_bytes')) {
|
|||||||
// place, that is not helpful to us here.
|
// place, that is not helpful to us here.
|
||||||
|
|
||||||
// See random_bytes_dev_urandom.php
|
// See random_bytes_dev_urandom.php
|
||||||
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_dev_urandom.php';
|
require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'random_bytes_dev_urandom.php';
|
||||||
}
|
}
|
||||||
// Unset variables after use
|
// Unset variables after use
|
||||||
$RandomCompat_basedir = null;
|
$RandomCompat_basedir = null;
|
||||||
@@ -159,7 +159,7 @@ if (!is_callable('random_bytes')) {
|
|||||||
extension_loaded('mcrypt')
|
extension_loaded('mcrypt')
|
||||||
) {
|
) {
|
||||||
// See random_bytes_mcrypt.php
|
// See random_bytes_mcrypt.php
|
||||||
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_mcrypt.php';
|
require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'random_bytes_mcrypt.php';
|
||||||
}
|
}
|
||||||
$RandomCompatUrandom = null;
|
$RandomCompatUrandom = null;
|
||||||
|
|
||||||
@@ -182,9 +182,10 @@ if (!is_callable('random_bytes')) {
|
|||||||
if (!in_array('com', $RandomCompat_disabled_classes)) {
|
if (!in_array('com', $RandomCompat_disabled_classes)) {
|
||||||
try {
|
try {
|
||||||
$RandomCompatCOMtest = new COM('CAPICOM.Utilities.1');
|
$RandomCompatCOMtest = new COM('CAPICOM.Utilities.1');
|
||||||
|
/** @psalm-suppress TypeDoesNotContainType */
|
||||||
if (method_exists($RandomCompatCOMtest, 'GetRandom')) {
|
if (method_exists($RandomCompatCOMtest, 'GetRandom')) {
|
||||||
// See random_bytes_com_dotnet.php
|
// See random_bytes_com_dotnet.php
|
||||||
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_bytes_com_dotnet.php';
|
require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'random_bytes_com_dotnet.php';
|
||||||
}
|
}
|
||||||
} catch (com_exception $e) {
|
} catch (com_exception $e) {
|
||||||
// Don't try to use it.
|
// Don't try to use it.
|
||||||
@@ -219,7 +220,7 @@ if (!is_callable('random_bytes')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!is_callable('random_int')) {
|
if (!is_callable('random_int')) {
|
||||||
require_once $RandomCompatDIR . DIRECTORY_SEPARATOR . 'random_int.php';
|
require_once $RandomCompatDIR.DIRECTORY_SEPARATOR.'random_int.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
$RandomCompatDIR = null;
|
$RandomCompatDIR = null;
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require_once __DIR__ . '/psalm-autoload.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is necessary for PHPUnit on PHP >= 5.3
|
|
||||||
*
|
|
||||||
* Class PHPUnit_Framework_TestCase
|
|
||||||
*/
|
|
||||||
if (PHP_VERSION_ID >= 50300) {
|
|
||||||
if (!class_exists('PHPUnit_Framework_TestCase')) {
|
|
||||||
require_once __DIR__ . '/other/phpunit-shim.php';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user