4 Commits

39 changed files with 1087 additions and 1036 deletions

2
.gitattributes vendored
View File

@@ -1,5 +1,3 @@
bin/configuration-test-generator export-ignore
bin/icon-test export-ignore
doc/ export-ignore
tst/ export-ignore
img/browserstack.svg export-ignore

View File

@@ -1,10 +1,9 @@
# PrivateBin version history
* **1.4.1 (not yet released)**
* ADDED: script for data storage backend migrations (#1012)
* ADDED: Translations for Turkish, Slovak and Greek
* ADDED: S3 Storage backend (#994)
* CHANGED: Switched to Jdenticons as the default for comment icons (#793)
* ADDED: Jdenticons as an option for comment icons (#793)
* CHANGED: Avoid `SUPER` privilege for setting the `sql_mode` for MariaDB/MySQL (#919)
* CHANGED: Upgrading libraries to: zlib 1.2.13
* FIXED: Revert to CREATE INDEX without IF NOT EXISTS clauses, to support MySQL (#943)

View File

@@ -31,7 +31,6 @@
* Austin Huang - Oracle database support
* Felix J. Ogris - S3 Storage backend
* Mounir Idrassi & J. Mozdzen - secure YOURLS integration
* Felix J. Ogris - script for data backend migrations, dropped singleton behaviour of data backends
## Translations
* Hexalyse - French

View File

@@ -26,7 +26,7 @@ install and configure PrivateBin on your server. It's available on
- `open_basedir` access to `/dev/urandom`
- mcrypt extension AND `open_basedir` access to `/dev/urandom`
- com_dotnet extension
- GD extension
- GD extension (when using identicon or vizhash icons, jdenticon works without it)
- zlib extension
- some disk space or a database supported by [PDO](https://php.net/manual/book.pdo.php)
- ability to create files and folders in the installation directory and the PATH
@@ -38,10 +38,10 @@ install and configure PrivateBin on your server. It's available on
### Changing the Path
In the index.php you can define a different `PATH`. This is useful to secure
your installation. You can move the utilities, configuration, data files,
templates and PHP libraries (directories bin, cfg, doc, data, lib, tpl, tst and
vendor) outside of your document root. This new location must still be
accessible to your webserver and PHP process (see also
your installation. You can move the configuration, data files, templates and PHP
libraries (directories cfg, doc, data, lib, tpl, tst and vendor) outside of your
document root. This new location must still be accessible to your webserver and
PHP process (see also
[open_basedir setting](https://secure.php.net/manual/en/ini.core.php#ini.open-basedir)).
> #### PATH Example

View File

@@ -1,199 +0,0 @@
#!/usr/bin/env php
<?php
// change this, if your php files and data is outside of your webservers document root
define('PATH', dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR);
define('PUBLIC_PATH', __DIR__ . DIRECTORY_SEPARATOR);
require PATH . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
use PrivateBin\Configuration;
use PrivateBin\Model;
// third argument in getopt requires PHP >= 7.1
if (version_compare(PHP_VERSION, '7.1.0') < 0) {
dieerr('migrate requires php 7.1 or above to work. Sorry.');
}
$longopts = array(
"delete-after",
"delete-during"
);
$opts_arr = getopt("fhnv", $longopts, $rest);
if ($opts_arr === false) {
dieerr("Erroneous command line options. Please use -h");
}
if (array_key_exists("h", $opts_arr)) {
helpexit();
}
$delete_after = array_key_exists("delete-after", $opts_arr);
$delete_during = array_key_exists("delete-during", $opts_arr);
$force_overwrite = array_key_exists("f", $opts_arr);
$dryrun = array_key_exists("n", $opts_arr);
$verbose = array_key_exists("v", $opts_arr);
if ($rest >= $argc) {
dieerr("Missing source configuration directory");
}
if ($delete_after && $delete_during) {
dieerr("--delete-after and --delete-during are mutually exclusive");
}
$srcconf = getConfig("source", $argv[$rest]);
$rest++;
$dstconf = getConfig("destination", ($rest < $argc ? $argv[$rest] : ""));
if (($srcconf->getSection("model") == $dstconf->getSection("model")) &&
($srcconf->getSection("model_options") == $dstconf->getSection("model_options"))) {
dieerr("Source and destination storage configurations are identical");
}
$srcmodel = new Model($srcconf);
$srcstore = $srcmodel->getStore();
$dstmodel = new Model($dstconf);
$dststore = $dstmodel->getStore();
$ids = $srcstore->getAllPastes();
foreach ($ids as $id) {
debug("Reading paste id " . $id);
$paste = $srcstore->read($id);
$comments = $srcstore->readComments($id);
savePaste($force_overwrite, $dryrun, $id, $paste, $dststore);
foreach ($comments as $comment) {
saveComment($force_overwrite, $dryrun, $id, $comment, $dststore);
}
if ($delete_during) {
deletePaste($dryrun, $id, $srcstore);
}
}
if ($delete_after) {
foreach ($ids as $id) {
deletePaste($dryrun, $id, $srcstore);
}
}
debug("Done.");
function deletePaste($dryrun, $pasteid, $srcstore)
{
if (!$dryrun) {
debug("Deleting paste id " . $pasteid);
$srcstore->delete($pasteid);
} else {
debug("Would delete paste id " . $pasteid);
}
}
function saveComment ($force_overwrite, $dryrun, $pasteid, $comment, $dststore)
{
$parentid = $comment["parentid"];
$commentid = $comment["id"];
if (!$dststore->existsComment($pasteid, $parentid, $commentid)) {
if (!$dryrun) {
debug("Saving paste id " . $pasteid . ", parent id " .
$parentid . ", comment id " . $commentid);
$dststore->createComment($pasteid, $parentid, $commentid, $comment);
} else {
debug("Would save paste id " . $pasteid . ", parent id " .
$parentid . ", comment id " . $commentid);
}
} else if ($force_overwrite) {
if (!$dryrun) {
debug("Overwriting paste id " . $pasteid . ", parent id " .
$parentid . ", comment id " . $commentid);
$dststore->createComment($pasteid, $parentid, $commentid, $comment);
} else {
debug("Would overwrite paste id " . $pasteid . ", parent id " .
$parentid . ", comment id " . $commentid);
}
} else {
if (!$dryrun) {
dieerr("Not overwriting paste id " . $pasteid . ", parent id " .
$parentid . ", comment id " . $commentid);
} else {
dieerr("Would not overwrite paste id " . $pasteid . ", parent id " .
$parentid . ", comment id " . $commentid);
}
}
}
function savePaste ($force_overwrite, $dryrun, $pasteid, $paste, $dststore)
{
if (!$dststore->exists($pasteid)) {
if (!$dryrun) {
debug("Saving paste id " . $pasteid);
$dststore->create($pasteid, $paste);
} else {
debug("Would save paste id " . $pasteid);
}
} else if ($force_overwrite) {
if (!$dryrun) {
debug("Overwriting paste id " . $pasteid);
$dststore->create($pasteid, $paste);
} else {
debug("Would overwrite paste id " . $pasteid);
}
} else {
if (!$dryrun) {
dieerr("Not overwriting paste id " . $pasteid);
} else {
dieerr("Would not overwrite paste id " . $pasteid);
}
}
}
function getConfig ($target, $confdir)
{
debug("Trying to load " . $target . " conf.php" .
($confdir === "" ? "" : " from " . $confdir));
putenv("CONFIG_PATH=" . $confdir);
$conf = new Configuration;
putenv("CONFIG_PATH=");
return $conf;
}
function dieerr ($text)
{
fprintf(STDERR, "ERROR: %s" . PHP_EOL, $text);
die(1);
}
function debug ($text) {
if ($GLOBALS["verbose"]) {
printf("DEBUG: %s" . PHP_EOL, $text);
}
}
function helpexit ()
{
print("migrate.php - Copy data between PrivateBin backends
Usage:
migrate [--delete-after] [--delete-during] [-f] [-n] [-v] srcconfdir
[<dstconfdir>]
migrate [-h]
Options:
--delete-after delete data from source after all pastes and comments have
successfully been copied to the destination
--delete-during delete data from source after the current paste and its
comments have successfully been copied to the destination
-f forcefully overwrite data which already exists at the
destination
-n dry run, do not copy data
-v be verbose
<srcconfdir> use storage backend configration from conf.php found in
this directory as source
<dstconfdir> optionally, use storage backend configration from conf.php
found in this directory as destination; defaults to:
" . PATH . "cfg" . DIRECTORY_SEPARATOR . "conf.php
");
exit();
}

View File

@@ -7,10 +7,9 @@
; (optional) set a project name to be displayed on the website
; name = "PrivateBin"
; The full URL, with the domain name and directories that point to the
; PrivateBin files, including an ending slash (/). This URL is essential to
; allow Opengraph images to be displayed on social networks.
; basepath = "https://privatebin.example.com/"
; The full URL, with the domain name and directories that point to the PrivateBin files
; This URL is essential to allow Opengraph images to be displayed on social networks
; basepath = ""
; enable or disable the discussion feature, defaults to true
discussion = true
@@ -56,9 +55,9 @@ languageselection = false
; if this is set and language selection is disabled, this will be the only language
; languagedefault = "en"
; (optional) URL shortener address to offer after a new paste is created.
; It is suggested to only use this with self-hosted shorteners as this will leak
; the pastes encryption key.
; (optional) URL shortener address to offer after a new paste is created
; it is suggested to only use this with self-hosted shorteners as this will leak
; the pastes encryption key
; urlshortener = "https://shortener.example.com/api?link="
; (optional) Let users create a QR code for sharing the paste URL with one click.
@@ -70,7 +69,7 @@ languageselection = false
; used to get the IP of a comment poster if the server salt is leaked and a
; SHA512 HMAC rainbow table is generated for all (relevant) IPs.
; Can be set to one these values:
; "none" / "vizhash" / "identicon" / "jdenticon" (default).
; "none" / "identicon" (default) / "jdenticon" / "vizhash".
; icon = "none"
; Content Security Policy headers allow a website to restrict what sources are
@@ -231,18 +230,18 @@ dir = PATH "data"
;secretkey = "secret access key"
[yourls]
; When using YOURLS as a "urlshortener" config item:
; - By default, "urlshortener" will point to the YOURLS API URL, with or without
; credentials, and will be visible in public on the PrivateBin web page.
; Only use this if you allow short URL creation without credentials.
; - Alternatively, using the parameters in this section ("signature" and
; "apiurl"), "urlshortener" needs to point to the base URL of your PrivateBin
; instance with "shortenviayourls?link=" appended. For example:
; urlshortener = "${basepath}shortenviayourls?link="
; This URL will in turn call YOURLS on the server side, using the URL from
; "apiurl" and the "access signature" from the "signature" parameters below.
; don't mix this up with "urlshortener" config item:
; - when using a standard configuration, "urlshortener" will point to the YOURLS
; API, including access credentials, and will be part of the PrivateBin public
; web page (insecure!)
; - when using the parameters in this section ("signature" and "apiurl"),
; "urlshortener" will point to a fixed PrivateBin page
; ("$basepath/shortenviayourls?link=") and that URL will in turn call YOURLS
; server-side, using the URL from "apiurl" and the "access signature" from the
; "signature" parameters below.
; (optional) the "signature" (access key) issued by YOURLS for the using account
; signature = ""
; (optional) the URL of the YOURLS API, called to shorten a PrivateBin URL
; apiurl = "https://yourls.example.com/yourls-api.php"
; apiurl = ""

484
composer.lock generated
View File

@@ -8,16 +8,16 @@
"packages": [
{
"name": "jdenticon/jdenticon",
"version": "1.0.2",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/dmester/jdenticon-php.git",
"reference": "cabb7a44c413c318392a341c5d3ca30fcdd57a6f"
"reference": "994ee07293fb978f983393ffcb2c0250592a6ac4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dmester/jdenticon-php/zipball/cabb7a44c413c318392a341c5d3ca30fcdd57a6f",
"reference": "cabb7a44c413c318392a341c5d3ca30fcdd57a6f",
"url": "https://api.github.com/repos/dmester/jdenticon-php/zipball/994ee07293fb978f983393ffcb2c0250592a6ac4",
"reference": "994ee07293fb978f983393ffcb2c0250592a6ac4",
"shasum": ""
},
"require": {
@@ -48,7 +48,12 @@
"identicon",
"jdenticon"
],
"time": "2022-10-30T17:15:02+00:00"
"support": {
"docs": "https://jdenticon.com/php-api.html",
"issues": "https://github.com/dmester/jdenticon-php/issues",
"source": "https://github.com/dmester/jdenticon-php"
},
"time": "2022-07-02T11:03:15+00:00"
},
{
"name": "mlocati/ip-lib",
@@ -105,6 +110,20 @@
"range",
"subnet"
],
"support": {
"issues": "https://github.com/mlocati/ip-lib/issues",
"source": "https://github.com/mlocati/ip-lib/tree/1.18.0"
},
"funding": [
{
"url": "https://github.com/sponsors/mlocati",
"type": "github"
},
{
"url": "https://paypal.me/mlocati",
"type": "other"
}
],
"time": "2022-01-13T18:05:33+00:00"
},
{
@@ -154,6 +173,11 @@
"pseudorandom",
"random"
],
"support": {
"email": "info@paragonie.com",
"issues": "https://github.com/paragonie/random_compat/issues",
"source": "https://github.com/paragonie/random_compat"
},
"time": "2022-02-16T17:07:03+00:00"
},
{
@@ -206,6 +230,10 @@
"identicon",
"image"
],
"support": {
"issues": "https://github.com/yzalis/Identicon/issues",
"source": "https://github.com/yzalis/Identicon/tree/master"
},
"abandoned": true,
"time": "2019-10-14T09:30:57+00:00"
}
@@ -213,32 +241,34 @@
"packages-dev": [
{
"name": "doctrine/instantiator",
"version": "1.4.1",
"version": "1.0.5",
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
"reference": "10dcfce151b967d20fde1b34ae6640712c3891bc"
"reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc",
"reference": "10dcfce151b967d20fde1b34ae6640712c3891bc",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
"reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
"php": ">=5.3,<8.0-DEV"
},
"require-dev": {
"doctrine/coding-standard": "^9",
"athletic/athletic": "~0.1.8",
"ext-pdo": "*",
"ext-phar": "*",
"phpbench/phpbench": "^0.16 || ^1",
"phpstan/phpstan": "^1.4",
"phpstan/phpstan-phpunit": "^1",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"vimeo/psalm": "^4.22"
"phpunit/phpunit": "~4.0",
"squizlabs/php_codesniffer": "~2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
@@ -252,42 +282,42 @@
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com",
"homepage": "https://ocramius.github.io/"
"homepage": "http://ocramius.github.com/"
}
],
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
"homepage": "https://www.doctrine-project.org/projects/instantiator.html",
"homepage": "https://github.com/doctrine/instantiator",
"keywords": [
"constructor",
"instantiate"
],
"time": "2022-03-03T08:28:38+00:00"
"support": {
"issues": "https://github.com/doctrine/instantiator/issues",
"source": "https://github.com/doctrine/instantiator/tree/master"
},
"time": "2015-06-14T21:17:01+00:00"
},
{
"name": "myclabs/deep-copy",
"version": "1.11.0",
"version": "1.7.0",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614"
"reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614",
"reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e",
"reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"conflict": {
"doctrine/collections": "<1.6.8",
"doctrine/common": "<2.13.3 || >=3,<3.2.2"
"php": "^5.6 || ^7.0"
},
"require-dev": {
"doctrine/collections": "^1.6.8",
"doctrine/common": "^2.13.3 || ^3.2.2",
"phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
"doctrine/collections": "^1.0",
"doctrine/common": "^2.6",
"phpunit/phpunit": "^4.1"
},
"type": "library",
"autoload": {
@@ -310,34 +340,43 @@
"object",
"object graph"
],
"time": "2022-03-03T13:19:32+00:00"
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.x"
},
"time": "2017-10-19T19:58:43+00:00"
},
{
"name": "phpdocumentor/reflection-common",
"version": "2.2.0",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
"reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
"reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
"reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
"reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
"php": ">=5.5"
},
"require-dev": {
"phpunit/phpunit": "^4.6"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-2.x": "2.x-dev"
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": "src/"
"phpDocumentor\\Reflection\\": [
"src"
]
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -359,42 +398,42 @@
"reflection",
"static analysis"
],
"time": "2020-06-27T09:03:43+00:00"
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
"source": "https://github.com/phpDocumentor/ReflectionCommon/tree/master"
},
"time": "2017-09-11T18:02:19+00:00"
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "5.3.0",
"version": "3.3.2",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "622548b623e81ca6d78b721c5e029f4ce664f170"
"reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170",
"reference": "622548b623e81ca6d78b721c5e029f4ce664f170",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bf329f6c1aadea3299f08ee804682b7c45b326a2",
"reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2",
"shasum": ""
},
"require": {
"ext-filter": "*",
"php": "^7.2 || ^8.0",
"phpdocumentor/reflection-common": "^2.2",
"phpdocumentor/type-resolver": "^1.3",
"webmozart/assert": "^1.9.1"
"php": "^5.6 || ^7.0",
"phpdocumentor/reflection-common": "^1.0.0",
"phpdocumentor/type-resolver": "^0.4.0",
"webmozart/assert": "^1.0"
},
"require-dev": {
"mockery/mockery": "~1.3.2",
"psalm/phar": "^4.8"
"mockery/mockery": "^0.9.4",
"phpunit/phpunit": "^4.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.x-dev"
}
},
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": "src"
"phpDocumentor\\Reflection\\": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -405,46 +444,48 @@
{
"name": "Mike van Riel",
"email": "me@mikevanriel.com"
},
{
"name": "Jaap van Otterdijk",
"email": "account@ijaap.nl"
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"time": "2021-10-19T17:43:47+00:00"
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/release/3.x"
},
"time": "2017-11-10T14:09:06+00:00"
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.6.1",
"version": "0.4.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "77a32518733312af16a44300404e945338981de3"
"reference": "9c977708995954784726e25d0cd1dddf4e65b0f7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3",
"reference": "77a32518733312af16a44300404e945338981de3",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7",
"reference": "9c977708995954784726e25d0cd1dddf4e65b0f7",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0",
"phpdocumentor/reflection-common": "^2.0"
"php": "^5.5 || ^7.0",
"phpdocumentor/reflection-common": "^1.0"
},
"require-dev": {
"ext-tokenizer": "*",
"psalm/phar": "^4.8"
"mockery/mockery": "^0.9.4",
"phpunit/phpunit": "^5.2||^4.8.24"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-1.x": "1.x-dev"
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": "src"
"phpDocumentor\\Reflection\\": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -457,8 +498,11 @@
"email": "me@mikevanriel.com"
}
],
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"time": "2022-03-15T21:29:03+00:00"
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/master"
},
"time": "2017-07-14T14:27:02+00:00"
},
{
"name": "phpspec/prophecy",
@@ -521,39 +565,43 @@
"spy",
"stub"
],
"support": {
"issues": "https://github.com/phpspec/prophecy/issues",
"source": "https://github.com/phpspec/prophecy/tree/v1.10.3"
},
"time": "2020-03-05T15:02:03+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "4.0.6",
"version": "4.0.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "ca060f645beeddebedb1885c97bf163e93264c35"
"reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca060f645beeddebedb1885c97bf163e93264c35",
"reference": "ca060f645beeddebedb1885c97bf163e93264c35",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d",
"reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-xmlwriter": "*",
"php": "^5.6 || ^7.0",
"phpunit/php-file-iterator": "~1.3",
"phpunit/php-text-template": "~1.2",
"phpunit/php-file-iterator": "^1.3",
"phpunit/php-text-template": "^1.2",
"phpunit/php-token-stream": "^1.4.2 || ^2.0",
"sebastian/code-unit-reverse-lookup": "~1.0",
"sebastian/code-unit-reverse-lookup": "^1.0",
"sebastian/environment": "^1.3.2 || ^2.0",
"sebastian/version": "~1.0|~2.0"
"sebastian/version": "^1.0 || ^2.0"
},
"require-dev": {
"ext-xdebug": ">=2.1.4",
"phpunit/phpunit": "^5.4"
"ext-xdebug": "^2.1.4",
"phpunit/phpunit": "^5.7"
},
"suggest": {
"ext-dom": "*",
"ext-xdebug": ">=2.4.0",
"ext-xmlwriter": "*"
"ext-xdebug": "^2.5.1"
},
"type": "library",
"extra": {
@@ -584,7 +632,12 @@
"testing",
"xunit"
],
"time": "2017-02-23T07:38:02+00:00"
"support": {
"irc": "irc://irc.freenode.net/phpunit",
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/4.0"
},
"time": "2017-04-02T07:44:40+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -631,6 +684,11 @@
"filesystem",
"iterator"
],
"support": {
"irc": "irc://irc.freenode.net/phpunit",
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/1.4.5"
},
"time": "2017-11-27T13:52:08+00:00"
},
{
@@ -672,6 +730,10 @@
"keywords": [
"template"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-text-template/issues",
"source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1"
},
"time": "2015-06-21T13:50:34+00:00"
},
{
@@ -721,33 +783,37 @@
"keywords": [
"timer"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-timer/issues",
"source": "https://github.com/sebastianbergmann/php-timer/tree/master"
},
"time": "2017-02-26T11:10:40+00:00"
},
{
"name": "phpunit/php-token-stream",
"version": "2.0.2",
"version": "1.4.12",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "791198a2c6254db10131eecfe8c06670700904db"
"reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db",
"reference": "791198a2c6254db10131eecfe8c06670700904db",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16",
"reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": "^7.0"
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "^6.2.4"
"phpunit/phpunit": "~4.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
"dev-master": "1.4-dev"
}
},
"autoload": {
@@ -770,21 +836,25 @@
"keywords": [
"tokenizer"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-token-stream/issues",
"source": "https://github.com/sebastianbergmann/php-token-stream/tree/1.4"
},
"abandoned": true,
"time": "2017-11-27T05:48:46+00:00"
"time": "2017-12-04T08:55:13+00:00"
},
{
"name": "phpunit/phpunit",
"version": "5.7.27",
"version": "5.6.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c"
"reference": "a9de0dbafeb6b1391b391fbb034734cb0af9f67c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c",
"reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a9de0dbafeb6b1391b391fbb034734cb0af9f67c",
"reference": "a9de0dbafeb6b1391b391fbb034734cb0af9f67c",
"shasum": ""
},
"require": {
@@ -795,21 +865,21 @@
"ext-xml": "*",
"myclabs/deep-copy": "~1.3",
"php": "^5.6 || ^7.0",
"phpspec/prophecy": "^1.6.2",
"phpunit/php-code-coverage": "^4.0.4",
"phpspec/prophecy": "^1.3.1",
"phpunit/php-code-coverage": "^4.0.1",
"phpunit/php-file-iterator": "~1.4",
"phpunit/php-text-template": "~1.2",
"phpunit/php-timer": "^1.0.6",
"phpunit/phpunit-mock-objects": "^3.2",
"sebastian/comparator": "^1.2.4",
"sebastian/diff": "^1.4.3",
"sebastian/environment": "^1.3.4 || ^2.0",
"sebastian/exporter": "~2.0",
"sebastian/global-state": "^1.1",
"sebastian/object-enumerator": "~2.0",
"sebastian/comparator": "~1.1",
"sebastian/diff": "~1.2",
"sebastian/environment": "^1.3 || ^2.0",
"sebastian/exporter": "~1.2",
"sebastian/global-state": "~1.0",
"sebastian/object-enumerator": "~1.0",
"sebastian/resource-operations": "~1.0",
"sebastian/version": "^1.0.6|^2.0.1",
"symfony/yaml": "~2.1|~3.0|~4.0"
"sebastian/version": "~1.0|~2.0",
"symfony/yaml": "~2.1|~3.0"
},
"conflict": {
"phpdocumentor/reflection-docblock": "3.0.2"
@@ -827,7 +897,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.7.x-dev"
"dev-master": "5.6.x-dev"
}
},
"autoload": {
@@ -853,7 +923,11 @@
"testing",
"xunit"
],
"time": "2018-02-01T05:50:59+00:00"
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/5.6.3"
},
"time": "2016-11-14T06:39:40+00:00"
},
{
"name": "phpunit/phpunit-mock-objects",
@@ -912,6 +986,11 @@
"mock",
"xunit"
],
"support": {
"irc": "irc://irc.freenode.net/phpunit",
"issues": "https://github.com/sebastianbergmann/phpunit-mock-objects/issues",
"source": "https://github.com/sebastianbergmann/phpunit-mock-objects/tree/3.4"
},
"abandoned": true,
"time": "2017-06-30T09:13:00+00:00"
},
@@ -958,6 +1037,16 @@
],
"description": "Looks up which function or method a line of code belongs to",
"homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
"support": {
"issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
"source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
}
],
"time": "2020-11-30T08:15:22+00:00"
},
{
@@ -1022,6 +1111,10 @@
"compare",
"equality"
],
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
"source": "https://github.com/sebastianbergmann/comparator/tree/1.2"
},
"time": "2017-01-29T09:50:25+00:00"
},
{
@@ -1074,6 +1167,10 @@
"keywords": [
"diff"
],
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
"source": "https://github.com/sebastianbergmann/diff/tree/1.4"
},
"time": "2017-05-22T07:24:03+00:00"
},
{
@@ -1124,25 +1221,29 @@
"environment",
"hhvm"
],
"support": {
"issues": "https://github.com/sebastianbergmann/environment/issues",
"source": "https://github.com/sebastianbergmann/environment/tree/master"
},
"time": "2016-11-26T07:53:53+00:00"
},
{
"name": "sebastian/exporter",
"version": "2.0.0",
"version": "1.2.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4"
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
"reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"sebastian/recursion-context": "~2.0"
"sebastian/recursion-context": "~1.0"
},
"require-dev": {
"ext-mbstring": "*",
@@ -1151,7 +1252,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
"dev-master": "1.3.x-dev"
}
},
"autoload": {
@@ -1191,7 +1292,11 @@
"export",
"exporter"
],
"time": "2016-11-19T08:54:04+00:00"
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
"source": "https://github.com/sebastianbergmann/exporter/tree/master"
},
"time": "2016-06-17T09:04:28+00:00"
},
{
"name": "sebastian/global-state",
@@ -1242,25 +1347,29 @@
"keywords": [
"global state"
],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
"source": "https://github.com/sebastianbergmann/global-state/tree/1.1.1"
},
"time": "2015-10-12T03:26:01+00:00"
},
{
"name": "sebastian/object-enumerator",
"version": "2.0.1",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/object-enumerator.git",
"reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7"
"reference": "d4ca2fb70344987502567bc50081c03e6192fb26"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7",
"reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7",
"url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/d4ca2fb70344987502567bc50081c03e6192fb26",
"reference": "d4ca2fb70344987502567bc50081c03e6192fb26",
"shasum": ""
},
"require": {
"php": ">=5.6",
"sebastian/recursion-context": "~2.0"
"sebastian/recursion-context": "~1.0"
},
"require-dev": {
"phpunit/phpunit": "~5"
@@ -1268,7 +1377,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
"dev-master": "1.0.x-dev"
}
},
"autoload": {
@@ -1288,20 +1397,24 @@
],
"description": "Traverses array structures and object graphs to enumerate all referenced objects",
"homepage": "https://github.com/sebastianbergmann/object-enumerator/",
"time": "2017-02-18T15:18:39+00:00"
"support": {
"issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
"source": "https://github.com/sebastianbergmann/object-enumerator/tree/master"
},
"time": "2016-01-28T13:25:10+00:00"
},
{
"name": "sebastian/recursion-context",
"version": "2.0.0",
"version": "1.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
"reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a"
"reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a",
"reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
"reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
"shasum": ""
},
"require": {
@@ -1313,7 +1426,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
"dev-master": "1.0.x-dev"
}
},
"autoload": {
@@ -1341,7 +1454,11 @@
],
"description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
"time": "2016-11-19T07:33:16+00:00"
"support": {
"issues": "https://github.com/sebastianbergmann/recursion-context/issues",
"source": "https://github.com/sebastianbergmann/recursion-context/tree/master"
},
"time": "2016-10-03T07:41:43+00:00"
},
{
"name": "sebastian/resource-operations",
@@ -1383,6 +1500,10 @@
],
"description": "Provides a list of PHP built-in functions that operate on resources",
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
"support": {
"issues": "https://github.com/sebastianbergmann/resource-operations/issues",
"source": "https://github.com/sebastianbergmann/resource-operations/tree/master"
},
"time": "2015-07-28T20:34:47+00:00"
},
{
@@ -1426,27 +1547,28 @@
],
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version",
"support": {
"issues": "https://github.com/sebastianbergmann/version/issues",
"source": "https://github.com/sebastianbergmann/version/tree/master"
},
"time": "2016-10-03T07:35:21+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.26.0",
"version": "v1.19.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4"
"reference": "aed596913b70fae57be53d86faa2e9ef85a2297b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
"reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/aed596913b70fae57be53d86faa2e9ef85a2297b",
"reference": "aed596913b70fae57be53d86faa2e9ef85a2297b",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-ctype": "*"
"php": ">=5.3.3"
},
"suggest": {
"ext-ctype": "For best performance"
@@ -1454,7 +1576,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.19-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -1491,31 +1613,48 @@
"polyfill",
"portable"
],
"time": "2022-05-24T11:49:31+00:00"
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.19.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-10-23T09:01:57+00:00"
},
{
"name": "symfony/yaml",
"version": "v4.4.45",
"version": "v3.4.47",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d"
"reference": "88289caa3c166321883f67fe5130188ebbb47094"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d",
"reference": "aeccc4dc52a9e634f1d1eebeb21eacfdcff1053d",
"url": "https://api.github.com/repos/symfony/yaml/zipball/88289caa3c166321883f67fe5130188ebbb47094",
"reference": "88289caa3c166321883f67fe5130188ebbb47094",
"shasum": ""
},
"require": {
"php": ">=7.1.3",
"php": "^5.5.9|>=7.0.8",
"symfony/polyfill-ctype": "~1.8"
},
"conflict": {
"symfony/console": "<3.4"
},
"require-dev": {
"symfony/console": "^3.4|^4.0|^5.0"
"symfony/console": "~3.4|~4.0"
},
"suggest": {
"symfony/console": "For validating YAML files using the lint command"
@@ -1543,41 +1682,53 @@
"homepage": "https://symfony.com/contributors"
}
],
"description": "Loads and dumps YAML files",
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2022-08-02T15:47:23+00:00"
"support": {
"source": "https://github.com/symfony/yaml/tree/v3.4.47"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-10-24T10:57:07+00:00"
},
{
"name": "webmozart/assert",
"version": "1.10.0",
"version": "1.9.1",
"source": {
"type": "git",
"url": "https://github.com/webmozarts/assert.git",
"reference": "6964c76c7804814a842473e0c8fd15bab0f18e25"
"reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25",
"reference": "6964c76c7804814a842473e0c8fd15bab0f18e25",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389",
"reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0",
"php": "^5.3.3 || ^7.0 || ^8.0",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
"phpstan/phpstan": "<0.12.20",
"vimeo/psalm": "<4.6.1 || 4.6.2"
"vimeo/psalm": "<3.9.1"
},
"require-dev": {
"phpunit/phpunit": "^8.5.13"
"phpunit/phpunit": "^4.8.36 || ^7.5.13"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.10-dev"
}
},
"autoload": {
"psr-4": {
"Webmozart\\Assert\\": "src/"
@@ -1599,7 +1750,11 @@
"check",
"validate"
],
"time": "2021-03-09T10:59:23+00:00"
"support": {
"issues": "https://github.com/webmozarts/assert/issues",
"source": "https://github.com/webmozarts/assert/tree/1.9.1"
},
"time": "2020-07-08T17:02:28+00:00"
}
],
"aliases": [],
@@ -1610,5 +1765,6 @@
"platform": {
"php": "^5.6.0 || ^7.0 || ^8.0"
},
"platform-dev": []
"platform-dev": [],
"plugin-api-version": "2.3.0"
}

View File

@@ -53,7 +53,7 @@ class Configuration
'languagedefault' => '',
'urlshortener' => '',
'qrcode' => true,
'icon' => 'jdenticon',
'icon' => 'identicon',
'cspheader' => 'default-src \'none\'; base-uri \'self\'; form-action \'none\'; manifest-src \'self\'; connect-src * blob:; script-src \'self\' \'unsafe-eval\'; style-src \'self\'; font-src \'self\'; frame-ancestors \'none\'; 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,
'httpwarning' => true,
@@ -236,14 +236,6 @@ class Configuration
if (!array_key_exists($this->_configuration['expire']['default'], $this->_configuration['expire_options'])) {
$this->_configuration['expire']['default'] = key($this->_configuration['expire_options']);
}
// ensure the basepath ends in a slash, if one is set
if (
strlen($this->_configuration['main']['basepath']) &&
substr_compare($this->_configuration['main']['basepath'], '/', -1) !== 0
) {
$this->_configuration['main']['basepath'] .= '/';
}
}
/**

View File

@@ -15,17 +15,61 @@ namespace PrivateBin\Data;
/**
* AbstractData
*
* Abstract model for data access
* Abstract model for data access, implemented as a singleton.
*/
abstract class AbstractData
{
/**
* cache for the traffic limiter
* Singleton instance
*
* @access protected
* @static
* @var AbstractData
*/
protected static $_instance = null;
/**
* cache for the traffic limiter
*
* @access private
* @static
* @var array
*/
protected $_last_cache = array();
protected static $_last_cache = array();
/**
* Enforce singleton, disable constructor
*
* Instantiate using {@link getInstance()}, this object implements the singleton pattern.
*
* @access protected
*/
protected function __construct()
{
}
/**
* Enforce singleton, disable cloning
*
* Instantiate using {@link getInstance()}, this object implements the singleton pattern.
*
* @access private
*/
private function __clone()
{
}
/**
* Get instance of singleton
*
* @access public
* @static
* @param array $options
* @return AbstractData
*/
public static function getInstance(array $options)
{
}
/**
* Create a paste.
@@ -106,9 +150,9 @@ abstract class AbstractData
public function purgeValues($namespace, $time)
{
if ($namespace === 'traffic_limiter') {
foreach ($this->_last_cache as $key => $last_submission) {
foreach (self::$_last_cache as $key => $last_submission) {
if ($last_submission <= $time) {
unset($this->_last_cache[$key]);
unset(self::$_last_cache[$key]);
}
}
}
@@ -163,14 +207,6 @@ abstract class AbstractData
}
}
/**
* Returns all paste ids
*
* @access public
* @return array
*/
abstract public function getAllPastes();
/**
* Get next free slot for comment from postdate.
*

View File

@@ -25,43 +25,59 @@ use PrivateBin\Json;
*/
class Database extends AbstractData
{
/**
* cache for select queries
*
* @var array
*/
private static $_cache = array();
/**
* instance of database connection
*
* @access private
* @static
* @var PDO
*/
private $_db;
private static $_db;
/**
* table prefix
*
* @access private
* @static
* @var string
*/
private $_prefix = '';
private static $_prefix = '';
/**
* database type
*
* @access private
* @static
* @var string
*/
private $_type = '';
private static $_type = '';
/**
* instantiates a new Database data backend
* get instance of singleton
*
* @access public
* @static
* @param array $options
* @throws Exception
* @return
* @return Database
*/
public function __construct(array $options)
public static function getInstance(array $options)
{
// if needed initialize the singleton
if (!(self::$_instance instanceof self)) {
self::$_instance = new self;
}
// set table prefix if given
if (array_key_exists('tbl', $options)) {
$this->_prefix = $options['tbl'];
self::$_prefix = $options['tbl'];
}
// initialize the db connection with new options
@@ -78,16 +94,16 @@ class Database extends AbstractData
$db_tables_exist = true;
// setup type and dabase connection
$this->_type = strtolower(
self::$_type = strtolower(
substr($options['dsn'], 0, strpos($options['dsn'], ':'))
);
// MySQL uses backticks to quote identifiers by default,
// tell it to expect ANSI SQL double quotes
if ($this->_type === 'mysql' && defined('PDO::MYSQL_ATTR_INIT_COMMAND')) {
if (self::$_type === 'mysql' && defined('PDO::MYSQL_ATTR_INIT_COMMAND')) {
$options['opt'][PDO::MYSQL_ATTR_INIT_COMMAND] = "SET SESSION sql_mode='ANSI_QUOTES'";
}
$tableQuery = $this->_getTableQuery($this->_type);
$this->_db = new PDO(
$tableQuery = self::_getTableQuery(self::$_type);
self::$_db = new PDO(
$options['dsn'],
$options['usr'],
$options['pwd'],
@@ -95,41 +111,43 @@ class Database extends AbstractData
);
// check if the database contains the required tables
$tables = $this->_db->query($tableQuery)->fetchAll(PDO::FETCH_COLUMN, 0);
$tables = self::$_db->query($tableQuery)->fetchAll(PDO::FETCH_COLUMN, 0);
// create paste table if necessary
if (!in_array($this->_sanitizeIdentifier('paste'), $tables)) {
$this->_createPasteTable();
if (!in_array(self::_sanitizeIdentifier('paste'), $tables)) {
self::_createPasteTable();
$db_tables_exist = false;
}
// create comment table if necessary
if (!in_array($this->_sanitizeIdentifier('comment'), $tables)) {
$this->_createCommentTable();
if (!in_array(self::_sanitizeIdentifier('comment'), $tables)) {
self::_createCommentTable();
$db_tables_exist = false;
}
// create config table if necessary
$db_version = Controller::VERSION;
if (!in_array($this->_sanitizeIdentifier('config'), $tables)) {
$this->_createConfigTable();
if (!in_array(self::_sanitizeIdentifier('config'), $tables)) {
self::_createConfigTable();
// if we only needed to create the config table, the DB is older then 0.22
if ($db_tables_exist) {
$db_version = '0.21';
}
} else {
$db_version = $this->_getConfig('VERSION');
$db_version = self::_getConfig('VERSION');
}
// update database structure if necessary
if (version_compare($db_version, Controller::VERSION, '<')) {
$this->_upgradeDatabase($db_version);
self::_upgradeDatabase($db_version);
}
} else {
throw new Exception(
'Missing configuration for key dsn, usr, pwd or opt in the section model_options, please check your configuration file', 6
);
}
return self::$_instance;
}
/**
@@ -142,12 +160,22 @@ class Database extends AbstractData
*/
public function create($pasteid, array $paste)
{
if (
array_key_exists($pasteid, self::$_cache)
) {
if (false !== self::$_cache[$pasteid]) {
return false;
} else {
unset(self::$_cache[$pasteid]);
}
}
$expire_date = 0;
$opendiscussion = $burnafterreading = false;
$attachment = $attachmentname = null;
$meta = $paste['meta'];
$isVersion1 = array_key_exists('data', $paste);
list($createdKey) = $this->_getVersionedKeys($isVersion1 ? 1 : 2);
list($createdKey) = self::_getVersionedKeys($isVersion1 ? 1 : 2);
$created = (int) $meta[$createdKey];
unset($meta[$createdKey], $paste['meta']);
if (array_key_exists('expire_date', $meta)) {
@@ -176,8 +204,8 @@ class Database extends AbstractData
$burnafterreading = $paste['adata'][3];
}
try {
return $this->_exec(
'INSERT INTO "' . $this->_sanitizeIdentifier('paste') .
return self::_exec(
'INSERT INTO "' . self::_sanitizeIdentifier('paste') .
'" VALUES(?,?,?,?,?,?,?,?,?)',
array(
$pasteid,
@@ -205,59 +233,64 @@ class Database extends AbstractData
*/
public function read($pasteid)
{
if (array_key_exists($pasteid, self::$_cache)) {
return self::$_cache[$pasteid];
}
self::$_cache[$pasteid] = false;
try {
$row = $this->_select(
'SELECT * FROM "' . $this->_sanitizeIdentifier('paste') .
$paste = self::_select(
'SELECT * FROM "' . self::_sanitizeIdentifier('paste') .
'" WHERE "dataid" = ?', array($pasteid), true
);
} catch (Exception $e) {
$row = false;
$paste = false;
}
if ($row === false) {
if ($paste === false) {
return false;
}
// create array
$data = Json::decode($row['data']);
$data = Json::decode($paste['data']);
$isVersion2 = array_key_exists('v', $data) && $data['v'] >= 2;
if ($isVersion2) {
$paste = $data;
list($createdKey) = $this->_getVersionedKeys(2);
self::$_cache[$pasteid] = $data;
list($createdKey) = self::_getVersionedKeys(2);
} else {
$paste = array('data' => $row['data']);
list($createdKey) = $this->_getVersionedKeys(1);
self::$_cache[$pasteid] = array('data' => $paste['data']);
list($createdKey) = self::_getVersionedKeys(1);
}
try {
$row['meta'] = Json::decode($row['meta']);
$paste['meta'] = Json::decode($paste['meta']);
} catch (Exception $e) {
$row['meta'] = array();
$paste['meta'] = array();
}
$row = self::upgradePreV1Format($row);
$paste['meta'] = $row['meta'];
$paste['meta'][$createdKey] = (int) $row['postdate'];
$expire_date = (int) $row['expiredate'];
$paste = self::upgradePreV1Format($paste);
self::$_cache[$pasteid]['meta'] = $paste['meta'];
self::$_cache[$pasteid]['meta'][$createdKey] = (int) $paste['postdate'];
$expire_date = (int) $paste['expiredate'];
if ($expire_date > 0) {
$paste['meta']['expire_date'] = $expire_date;
self::$_cache[$pasteid]['meta']['expire_date'] = $expire_date;
}
if ($isVersion2) {
return $paste;
return self::$_cache[$pasteid];
}
// support v1 attachments
if (array_key_exists('attachment', $row) && !empty($row['attachment'])) {
$paste['attachment'] = $row['attachment'];
if (array_key_exists('attachmentname', $row) && !empty($row['attachmentname'])) {
$paste['attachmentname'] = $row['attachmentname'];
if (array_key_exists('attachment', $paste) && !empty($paste['attachment'])) {
self::$_cache[$pasteid]['attachment'] = $paste['attachment'];
if (array_key_exists('attachmentname', $paste) && !empty($paste['attachmentname'])) {
self::$_cache[$pasteid]['attachmentname'] = $paste['attachmentname'];
}
}
if ($row['opendiscussion']) {
$paste['meta']['opendiscussion'] = true;
if ($paste['opendiscussion']) {
self::$_cache[$pasteid]['meta']['opendiscussion'] = true;
}
if ($row['burnafterreading']) {
$paste['meta']['burnafterreading'] = true;
if ($paste['burnafterreading']) {
self::$_cache[$pasteid]['meta']['burnafterreading'] = true;
}
return $paste;
return self::$_cache[$pasteid];
}
/**
@@ -268,14 +301,19 @@ class Database extends AbstractData
*/
public function delete($pasteid)
{
$this->_exec(
'DELETE FROM "' . $this->_sanitizeIdentifier('paste') .
self::_exec(
'DELETE FROM "' . self::_sanitizeIdentifier('paste') .
'" WHERE "dataid" = ?', array($pasteid)
);
$this->_exec(
'DELETE FROM "' . $this->_sanitizeIdentifier('comment') .
self::_exec(
'DELETE FROM "' . self::_sanitizeIdentifier('comment') .
'" WHERE "pasteid" = ?', array($pasteid)
);
if (
array_key_exists($pasteid, self::$_cache)
) {
unset(self::$_cache[$pasteid]);
}
}
/**
@@ -287,15 +325,12 @@ class Database extends AbstractData
*/
public function exists($pasteid)
{
try {
$row = $this->_select(
'SELECT "dataid" FROM "' . $this->_sanitizeIdentifier('paste') .
'" WHERE "dataid" = ?', array($pasteid), true
);
} catch (Exception $e) {
return false;
if (
!array_key_exists($pasteid, self::$_cache)
) {
self::$_cache[$pasteid] = $this->read($pasteid);
}
return (bool) $row;
return (bool) self::$_cache[$pasteid];
}
/**
@@ -317,7 +352,7 @@ class Database extends AbstractData
$version = 2;
$data = Json::encode($comment);
}
list($createdKey, $iconKey) = $this->_getVersionedKeys($version);
list($createdKey, $iconKey) = self::_getVersionedKeys($version);
$meta = $comment['meta'];
unset($comment['meta']);
foreach (array('nickname', $iconKey) as $key) {
@@ -326,8 +361,8 @@ class Database extends AbstractData
}
}
try {
return $this->_exec(
'INSERT INTO "' . $this->_sanitizeIdentifier('comment') .
return self::_exec(
'INSERT INTO "' . self::_sanitizeIdentifier('comment') .
'" VALUES(?,?,?,?,?,?,?)',
array(
$commentid,
@@ -353,8 +388,8 @@ class Database extends AbstractData
*/
public function readComments($pasteid)
{
$rows = $this->_select(
'SELECT * FROM "' . $this->_sanitizeIdentifier('comment') .
$rows = self::_select(
'SELECT * FROM "' . self::_sanitizeIdentifier('comment') .
'" WHERE "pasteid" = ?', array($pasteid)
);
@@ -371,7 +406,7 @@ class Database extends AbstractData
$version = 1;
$comments[$i] = array('data' => $row['data']);
}
list($createdKey, $iconKey) = $this->_getVersionedKeys($version);
list($createdKey, $iconKey) = self::_getVersionedKeys($version);
$comments[$i]['id'] = $row['dataid'];
$comments[$i]['parentid'] = $row['parentid'];
$comments[$i]['meta'] = array($createdKey => (int) $row['postdate']);
@@ -398,8 +433,8 @@ class Database extends AbstractData
public function existsComment($pasteid, $parentid, $commentid)
{
try {
return (bool) $this->_select(
'SELECT "dataid" FROM "' . $this->_sanitizeIdentifier('comment') .
return (bool) self::_select(
'SELECT "dataid" FROM "' . self::_sanitizeIdentifier('comment') .
'" WHERE "pasteid" = ? AND "parentid" = ? AND "dataid" = ?',
array($pasteid, $parentid, $commentid), true
);
@@ -420,15 +455,15 @@ class Database extends AbstractData
public function setValue($value, $namespace, $key = '')
{
if ($namespace === 'traffic_limiter') {
$this->_last_cache[$key] = $value;
self::$_last_cache[$key] = $value;
try {
$value = Json::encode($this->_last_cache);
$value = Json::encode(self::$_last_cache);
} catch (Exception $e) {
return false;
}
}
return $this->_exec(
'UPDATE "' . $this->_sanitizeIdentifier('config') .
return self::_exec(
'UPDATE "' . self::_sanitizeIdentifier('config') .
'" SET "value" = ? WHERE "id" = ?',
array($value, strtoupper($namespace))
);
@@ -448,8 +483,8 @@ class Database extends AbstractData
$value = $this->_getConfig($configKey);
if ($value === '') {
// initialize the row, so that setValue can rely on UPDATE queries
$this->_exec(
'INSERT INTO "' . $this->_sanitizeIdentifier('config') .
self::_exec(
'INSERT INTO "' . self::_sanitizeIdentifier('config') .
'" VALUES(?,?)',
array($configKey, '')
);
@@ -457,8 +492,7 @@ class Database extends AbstractData
// migrate filesystem based salt into database
$file = 'data' . DIRECTORY_SEPARATOR . 'salt.php';
if ($namespace === 'salt' && is_readable($file)) {
$fs = new Filesystem(array('dir' => 'data'));
$value = $fs->getValue('salt');
$value = Filesystem::getInstance(array('dir' => 'data'))->getValue('salt');
$this->setValue($value, 'salt');
@unlink($file);
return $value;
@@ -466,12 +500,12 @@ class Database extends AbstractData
}
if ($value && $namespace === 'traffic_limiter') {
try {
$this->_last_cache = Json::decode($value);
self::$_last_cache = Json::decode($value);
} catch (Exception $e) {
$this->_last_cache = array();
self::$_last_cache = array();
}
if (array_key_exists($key, $this->_last_cache)) {
return $this->_last_cache[$key];
if (array_key_exists($key, self::$_last_cache)) {
return self::$_last_cache[$key];
}
}
return (string) $value;
@@ -486,37 +520,34 @@ class Database extends AbstractData
*/
protected function _getExpiredPastes($batchsize)
{
$statement = $this->_db->prepare(
'SELECT "dataid" FROM "' . $this->_sanitizeIdentifier('paste') .
$pastes = array();
$rows = self::_select(
'SELECT "dataid" FROM "' . self::_sanitizeIdentifier('paste') .
'" WHERE "expiredate" < ? AND "expiredate" != ? ' .
($this->_type === 'oci' ? 'FETCH NEXT ? ROWS ONLY' : 'LIMIT ?')
(self::$_type === 'oci' ? 'FETCH NEXT ? ROWS ONLY' : 'LIMIT ?'),
array(time(), 0, $batchsize)
);
$statement->execute(array(time(), 0, $batchsize));
return $statement->fetchAll(PDO::FETCH_COLUMN, 0);
}
/**
* @inheritDoc
*/
public function getAllPastes()
{
return $this->_db->query(
'SELECT "dataid" FROM "' . $this->_sanitizeIdentifier('paste') . '"'
)->fetchAll(PDO::FETCH_COLUMN, 0);
if (is_array($rows) && count($rows)) {
foreach ($rows as $row) {
$pastes[] = $row['dataid'];
}
}
return $pastes;
}
/**
* execute a statement
*
* @access private
* @static
* @param string $sql
* @param array $params
* @throws PDOException
* @return bool
*/
private function _exec($sql, array $params)
private static function _exec($sql, array $params)
{
$statement = $this->_db->prepare($sql);
$statement = self::$_db->prepare($sql);
foreach ($params as $key => &$parameter) {
$position = $key + 1;
if (is_int($parameter)) {
@@ -536,19 +567,20 @@ class Database extends AbstractData
* run a select statement
*
* @access private
* @static
* @param string $sql
* @param array $params
* @param bool $firstOnly if only the first row should be returned
* @throws PDOException
* @return array|false
*/
private function _select($sql, array $params, $firstOnly = false)
private static function _select($sql, array $params, $firstOnly = false)
{
$statement = $this->_db->prepare($sql);
$statement = self::$_db->prepare($sql);
$statement->execute($params);
if ($firstOnly) {
$result = $statement->fetch(PDO::FETCH_ASSOC);
} elseif ($this->_type === 'oci') {
} elseif (self::$_type === 'oci') {
// workaround for https://bugs.php.net/bug.php?id=46728
$result = array();
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
@@ -558,7 +590,7 @@ class Database extends AbstractData
$result = $statement->fetchAll(PDO::FETCH_ASSOC);
}
$statement->closeCursor();
if ($this->_type === 'oci' && is_array($result)) {
if (self::$_type === 'oci' && is_array($result)) {
// returned CLOB values are streams, convert these into strings
$result = $firstOnly ?
array_map('PrivateBin\Data\Database::_sanitizeClob', $result) :
@@ -571,10 +603,11 @@ class Database extends AbstractData
* get version dependent key names
*
* @access private
* @static
* @param int $version
* @return array
*/
private function _getVersionedKeys($version)
private static function _getVersionedKeys($version)
{
if ($version === 1) {
return array('postdate', 'vizhash');
@@ -586,11 +619,12 @@ class Database extends AbstractData
* get table list query, depending on the database type
*
* @access private
* @static
* @param string $type
* @throws Exception
* @return string
*/
private function _getTableQuery($type)
private static function _getTableQuery($type)
{
switch ($type) {
case 'ibm':
@@ -641,14 +675,15 @@ class Database extends AbstractData
* get a value by key from the config table
*
* @access private
* @static
* @param string $key
* @return string
*/
private function _getConfig($key)
private static function _getConfig($key)
{
try {
$row = $this->_select(
'SELECT "value" FROM "' . $this->_sanitizeIdentifier('config') .
$row = self::_select(
'SELECT "value" FROM "' . self::_sanitizeIdentifier('config') .
'" WHERE "id" = ?', array($key), true
);
} catch (PDOException $e) {
@@ -661,13 +696,14 @@ class Database extends AbstractData
* get the primary key clauses, depending on the database driver
*
* @access private
* @static
* @param string $key
* @return array
*/
private function _getPrimaryKeyClauses($key = 'dataid')
private static function _getPrimaryKeyClauses($key = 'dataid')
{
$main_key = $after_key = '';
switch ($this->_type) {
switch (self::$_type) {
case 'mysql':
case 'oci':
$after_key = ", PRIMARY KEY (\"$key\")";
@@ -685,11 +721,12 @@ class Database extends AbstractData
* PostgreSQL and OCI uses a different API for BLOBs then SQL, hence we use TEXT and CLOB
*
* @access private
* @static
* @return string
*/
private function _getDataType()
private static function _getDataType()
{
switch ($this->_type) {
switch (self::$_type) {
case 'oci':
return 'CLOB';
case 'pgsql':
@@ -705,11 +742,12 @@ class Database extends AbstractData
* PostgreSQL and OCI use different APIs for BLOBs then SQL, hence we use TEXT and CLOB
*
* @access private
* @static
* @return string
*/
private function _getAttachmentType()
private static function _getAttachmentType()
{
switch ($this->_type) {
switch (self::$_type) {
case 'oci':
return 'CLOB';
case 'pgsql':
@@ -725,11 +763,12 @@ class Database extends AbstractData
* OCI doesn't accept TEXT so it has to be VARCHAR2(4000)
*
* @access private
* @static
* @return string
*/
private function _getMetaType()
private static function _getMetaType()
{
switch ($this->_type) {
switch (self::$_type) {
case 'oci':
return 'VARCHAR2(4000)';
default:
@@ -741,15 +780,16 @@ class Database extends AbstractData
* create the paste table
*
* @access private
* @static
*/
private function _createPasteTable()
private static function _createPasteTable()
{
list($main_key, $after_key) = $this->_getPrimaryKeyClauses();
$dataType = $this->_getDataType();
$attachmentType = $this->_getAttachmentType();
$metaType = $this->_getMetaType();
$this->_db->exec(
'CREATE TABLE "' . $this->_sanitizeIdentifier('paste') . '" ( ' .
list($main_key, $after_key) = self::_getPrimaryKeyClauses();
$dataType = self::_getDataType();
$attachmentType = self::_getAttachmentType();
$metaType = self::_getMetaType();
self::$_db->exec(
'CREATE TABLE "' . self::_sanitizeIdentifier('paste') . '" ( ' .
"\"dataid\" CHAR(16) NOT NULL$main_key, " .
"\"data\" $attachmentType, " .
'"postdate" INT, ' .
@@ -766,13 +806,14 @@ class Database extends AbstractData
* create the paste table
*
* @access private
* @static
*/
private function _createCommentTable()
private static function _createCommentTable()
{
list($main_key, $after_key) = $this->_getPrimaryKeyClauses();
$dataType = $this->_getDataType();
$this->_db->exec(
'CREATE TABLE "' . $this->_sanitizeIdentifier('comment') . '" ( ' .
list($main_key, $after_key) = self::_getPrimaryKeyClauses();
$dataType = self::_getDataType();
self::$_db->exec(
'CREATE TABLE "' . self::_sanitizeIdentifier('comment') . '" ( ' .
"\"dataid\" CHAR(16) NOT NULL$main_key, " .
'"pasteid" CHAR(16), ' .
'"parentid" CHAR(16), ' .
@@ -781,15 +822,15 @@ class Database extends AbstractData
"\"vizhash\" $dataType, " .
"\"postdate\" INT$after_key )"
);
if ($this->_type === 'oci') {
$this->_db->exec(
if (self::$_type === 'oci') {
self::$_db->exec(
'declare
already_exists exception;
columns_indexed exception;
pragma exception_init( already_exists, -955 );
pragma exception_init(columns_indexed, -1408);
begin
execute immediate \'create index "comment_parent" on "' . $this->_sanitizeIdentifier('comment') . '" ("pasteid")\';
execute immediate \'create index "comment_parent" on "' . self::_sanitizeIdentifier('comment') . '" ("pasteid")\';
exception
when already_exists or columns_indexed then
NULL;
@@ -797,10 +838,10 @@ class Database extends AbstractData
);
} else {
// CREATE INDEX IF NOT EXISTS not supported as of Oracle MySQL <= 8.0
$this->_db->exec(
self::$_db->exec(
'CREATE INDEX "' .
$this->_sanitizeIdentifier('comment_parent') . '" ON "' .
$this->_sanitizeIdentifier('comment') . '" ("pasteid")'
self::_sanitizeIdentifier('comment_parent') . '" ON "' .
self::_sanitizeIdentifier('comment') . '" ("pasteid")'
);
}
}
@@ -809,18 +850,19 @@ class Database extends AbstractData
* create the paste table
*
* @access private
* @static
*/
private function _createConfigTable()
private static function _createConfigTable()
{
list($main_key, $after_key) = $this->_getPrimaryKeyClauses('id');
$charType = $this->_type === 'oci' ? 'VARCHAR2(16)' : 'CHAR(16)';
$textType = $this->_getMetaType();
$this->_db->exec(
'CREATE TABLE "' . $this->_sanitizeIdentifier('config') .
list($main_key, $after_key) = self::_getPrimaryKeyClauses('id');
$charType = self::$_type === 'oci' ? 'VARCHAR2(16)' : 'CHAR(16)';
$textType = self::_getMetaType();
self::$_db->exec(
'CREATE TABLE "' . self::_sanitizeIdentifier('config') .
"\" ( \"id\" $charType NOT NULL$main_key, \"value\" $textType$after_key )"
);
$this->_exec(
'INSERT INTO "' . $this->_sanitizeIdentifier('config') .
self::_exec(
'INSERT INTO "' . self::_sanitizeIdentifier('config') .
'" VALUES(?,?)',
array('VERSION', Controller::VERSION)
);
@@ -848,88 +890,90 @@ class Database extends AbstractData
* sanitizes identifiers
*
* @access private
* @static
* @param string $identifier
* @return string
*/
private function _sanitizeIdentifier($identifier)
private static function _sanitizeIdentifier($identifier)
{
return preg_replace('/[^A-Za-z0-9_]+/', '', $this->_prefix . $identifier);
return preg_replace('/[^A-Za-z0-9_]+/', '', self::$_prefix . $identifier);
}
/**
* upgrade the database schema from an old version
*
* @access private
* @static
* @param string $oldversion
*/
private function _upgradeDatabase($oldversion)
private static function _upgradeDatabase($oldversion)
{
$dataType = $this->_getDataType();
$attachmentType = $this->_getAttachmentType();
$dataType = self::_getDataType();
$attachmentType = self::_getAttachmentType();
switch ($oldversion) {
case '0.21':
// create the meta column if necessary (pre 0.21 change)
try {
$this->_db->exec(
'SELECT "meta" FROM "' . $this->_sanitizeIdentifier('paste') . '" ' .
($this->_type === 'oci' ? 'FETCH NEXT 1 ROWS ONLY' : 'LIMIT 1')
self::$_db->exec(
'SELECT "meta" FROM "' . self::_sanitizeIdentifier('paste') . '" ' .
(self::$_type === 'oci' ? 'FETCH NEXT 1 ROWS ONLY' : 'LIMIT 1')
);
} catch (PDOException $e) {
$this->_db->exec('ALTER TABLE "' . $this->_sanitizeIdentifier('paste') . '" ADD COLUMN "meta" TEXT');
self::$_db->exec('ALTER TABLE "' . self::_sanitizeIdentifier('paste') . '" ADD COLUMN "meta" TEXT');
}
// SQLite only allows one ALTER statement at a time...
$this->_db->exec(
'ALTER TABLE "' . $this->_sanitizeIdentifier('paste') .
self::$_db->exec(
'ALTER TABLE "' . self::_sanitizeIdentifier('paste') .
"\" ADD COLUMN \"attachment\" $attachmentType"
);
$this->_db->exec(
'ALTER TABLE "' . $this->_sanitizeIdentifier('paste') . "\" ADD COLUMN \"attachmentname\" $dataType"
self::$_db->exec(
'ALTER TABLE "' . self::_sanitizeIdentifier('paste') . "\" ADD COLUMN \"attachmentname\" $dataType"
);
// SQLite doesn't support MODIFY, but it allows TEXT of similar
// size as BLOB, so there is no need to change it there
if ($this->_type !== 'sqlite') {
$this->_db->exec(
'ALTER TABLE "' . $this->_sanitizeIdentifier('paste') .
if (self::$_type !== 'sqlite') {
self::$_db->exec(
'ALTER TABLE "' . self::_sanitizeIdentifier('paste') .
"\" ADD PRIMARY KEY (\"dataid\"), MODIFY COLUMN \"data\" $dataType"
);
$this->_db->exec(
'ALTER TABLE "' . $this->_sanitizeIdentifier('comment') .
self::$_db->exec(
'ALTER TABLE "' . self::_sanitizeIdentifier('comment') .
"\" ADD PRIMARY KEY (\"dataid\"), MODIFY COLUMN \"data\" $dataType, " .
"MODIFY COLUMN \"nickname\" $dataType, MODIFY COLUMN \"vizhash\" $dataType"
);
} else {
$this->_db->exec(
self::$_db->exec(
'CREATE UNIQUE INDEX IF NOT EXISTS "' .
$this->_sanitizeIdentifier('paste_dataid') . '" ON "' .
$this->_sanitizeIdentifier('paste') . '" ("dataid")'
self::_sanitizeIdentifier('paste_dataid') . '" ON "' .
self::_sanitizeIdentifier('paste') . '" ("dataid")'
);
$this->_db->exec(
self::$_db->exec(
'CREATE UNIQUE INDEX IF NOT EXISTS "' .
$this->_sanitizeIdentifier('comment_dataid') . '" ON "' .
$this->_sanitizeIdentifier('comment') . '" ("dataid")'
self::_sanitizeIdentifier('comment_dataid') . '" ON "' .
self::_sanitizeIdentifier('comment') . '" ("dataid")'
);
}
// CREATE INDEX IF NOT EXISTS not supported as of Oracle MySQL <= 8.0
$this->_db->exec(
self::$_db->exec(
'CREATE INDEX "' .
$this->_sanitizeIdentifier('comment_parent') . '" ON "' .
$this->_sanitizeIdentifier('comment') . '" ("pasteid")'
self::_sanitizeIdentifier('comment_parent') . '" ON "' .
self::_sanitizeIdentifier('comment') . '" ("pasteid")'
);
// no break, continue with updates for 0.22 and later
case '1.3':
// SQLite doesn't support MODIFY, but it allows TEXT of similar
// size as BLOB and PostgreSQL uses TEXT, so there is no need
// to change it there
if ($this->_type !== 'sqlite' && $this->_type !== 'pgsql') {
$this->_db->exec(
'ALTER TABLE "' . $this->_sanitizeIdentifier('paste') .
if (self::$_type !== 'sqlite' && self::$_type !== 'pgsql') {
self::$_db->exec(
'ALTER TABLE "' . self::_sanitizeIdentifier('paste') .
"\" MODIFY COLUMN \"data\" $attachmentType"
);
}
// no break, continue with updates for all newer versions
default:
$this->_exec(
'UPDATE "' . $this->_sanitizeIdentifier('config') .
self::_exec(
'UPDATE "' . self::_sanitizeIdentifier('config') .
'" SET "value" = ? WHERE "id" = ?',
array(Controller::VERSION, 'VERSION')
);

View File

@@ -40,26 +40,33 @@ class Filesystem extends AbstractData
* path in which to persist something
*
* @access private
* @static
* @var string
*/
private $_path = 'data';
private static $_path = 'data';
/**
* instantiates a new Filesystem data backend
* get instance of singleton
*
* @access public
* @static
* @param array $options
* @return
* @return Filesystem
*/
public function __construct(array $options)
public static function getInstance(array $options)
{
// if needed initialize the singleton
if (!(self::$_instance instanceof self)) {
self::$_instance = new self;
}
// if given update the data directory
if (
is_array($options) &&
array_key_exists('dir', $options)
) {
$this->_path = $options['dir'];
self::$_path = $options['dir'];
}
return self::$_instance;
}
/**
@@ -72,7 +79,7 @@ class Filesystem extends AbstractData
*/
public function create($pasteid, array $paste)
{
$storagedir = $this->_dataid2path($pasteid);
$storagedir = self::_dataid2path($pasteid);
$file = $storagedir . $pasteid . '.php';
if (is_file($file)) {
return false;
@@ -80,7 +87,7 @@ class Filesystem extends AbstractData
if (!is_dir($storagedir)) {
mkdir($storagedir, 0700, true);
}
return $this->_store($file, $paste);
return self::_store($file, $paste);
}
/**
@@ -94,7 +101,7 @@ class Filesystem extends AbstractData
{
if (
!$this->exists($pasteid) ||
!$paste = $this->_get($this->_dataid2path($pasteid) . $pasteid . '.php')
!$paste = self::_get(self::_dataid2path($pasteid) . $pasteid . '.php')
) {
return false;
}
@@ -109,7 +116,7 @@ class Filesystem extends AbstractData
*/
public function delete($pasteid)
{
$pastedir = $this->_dataid2path($pasteid);
$pastedir = self::_dataid2path($pasteid);
if (is_dir($pastedir)) {
// Delete the paste itself.
if (is_file($pastedir . $pasteid . '.php')) {
@@ -117,7 +124,7 @@ class Filesystem extends AbstractData
}
// Delete discussion if it exists.
$discdir = $this->_dataid2discussionpath($pasteid);
$discdir = self::_dataid2discussionpath($pasteid);
if (is_dir($discdir)) {
// Delete all files in discussion directory
$dir = dir($discdir);
@@ -141,20 +148,20 @@ class Filesystem extends AbstractData
*/
public function exists($pasteid)
{
$basePath = $this->_dataid2path($pasteid) . $pasteid;
$basePath = self::_dataid2path($pasteid) . $pasteid;
$pastePath = $basePath . '.php';
// convert to PHP protected files if needed
if (is_readable($basePath)) {
$this->_prependRename($basePath, $pastePath);
self::_prependRename($basePath, $pastePath);
// convert comments, too
$discdir = $this->_dataid2discussionpath($pasteid);
$discdir = self::_dataid2discussionpath($pasteid);
if (is_dir($discdir)) {
$dir = dir($discdir);
while (false !== ($filename = $dir->read())) {
if (substr($filename, -4) !== '.php' && strlen($filename) >= 16) {
$commentFilename = $discdir . $filename . '.php';
$this->_prependRename($discdir . $filename, $commentFilename);
self::_prependRename($discdir . $filename, $commentFilename);
}
}
$dir->close();
@@ -175,7 +182,7 @@ class Filesystem extends AbstractData
*/
public function createComment($pasteid, $parentid, $commentid, array $comment)
{
$storagedir = $this->_dataid2discussionpath($pasteid);
$storagedir = self::_dataid2discussionpath($pasteid);
$file = $storagedir . $pasteid . '.' . $commentid . '.' . $parentid . '.php';
if (is_file($file)) {
return false;
@@ -183,7 +190,7 @@ class Filesystem extends AbstractData
if (!is_dir($storagedir)) {
mkdir($storagedir, 0700, true);
}
return $this->_store($file, $comment);
return self::_store($file, $comment);
}
/**
@@ -196,7 +203,7 @@ class Filesystem extends AbstractData
public function readComments($pasteid)
{
$comments = array();
$discdir = $this->_dataid2discussionpath($pasteid);
$discdir = self::_dataid2discussionpath($pasteid);
if (is_dir($discdir)) {
$dir = dir($discdir);
while (false !== ($filename = $dir->read())) {
@@ -205,7 +212,7 @@ class Filesystem extends AbstractData
// - commentid is the comment identifier itself.
// - parentid is the comment this comment replies to (It can be pasteid)
if (is_file($discdir . $filename)) {
$comment = $this->_get($discdir . $filename);
$comment = self::_get($discdir . $filename);
$items = explode('.', $filename);
// Add some meta information not contained in file.
$comment['id'] = $items[1];
@@ -236,7 +243,7 @@ class Filesystem extends AbstractData
public function existsComment($pasteid, $parentid, $commentid)
{
return is_file(
$this->_dataid2discussionpath($pasteid) .
self::_dataid2discussionpath($pasteid) .
$pasteid . '.' . $commentid . '.' . $parentid . '.php'
);
}
@@ -254,20 +261,20 @@ class Filesystem extends AbstractData
{
switch ($namespace) {
case 'purge_limiter':
return $this->_storeString(
$this->_path . DIRECTORY_SEPARATOR . 'purge_limiter.php',
return self::_storeString(
self::$_path . DIRECTORY_SEPARATOR . 'purge_limiter.php',
'<?php' . PHP_EOL . '$GLOBALS[\'purge_limiter\'] = ' . $value . ';'
);
case 'salt':
return $this->_storeString(
$this->_path . DIRECTORY_SEPARATOR . 'salt.php',
return self::_storeString(
self::$_path . DIRECTORY_SEPARATOR . 'salt.php',
'<?php # |' . $value . '|'
);
case 'traffic_limiter':
$this->_last_cache[$key] = $value;
return $this->_storeString(
$this->_path . DIRECTORY_SEPARATOR . 'traffic_limiter.php',
'<?php' . PHP_EOL . '$GLOBALS[\'traffic_limiter\'] = ' . var_export($this->_last_cache, true) . ';'
self::$_last_cache[$key] = $value;
return self::_storeString(
self::$_path . DIRECTORY_SEPARATOR . 'traffic_limiter.php',
'<?php' . PHP_EOL . '$GLOBALS[\'traffic_limiter\'] = ' . var_export(self::$_last_cache, true) . ';'
);
}
return false;
@@ -285,14 +292,14 @@ class Filesystem extends AbstractData
{
switch ($namespace) {
case 'purge_limiter':
$file = $this->_path . DIRECTORY_SEPARATOR . 'purge_limiter.php';
$file = self::$_path . DIRECTORY_SEPARATOR . 'purge_limiter.php';
if (is_readable($file)) {
require $file;
return $GLOBALS['purge_limiter'];
}
break;
case 'salt':
$file = $this->_path . DIRECTORY_SEPARATOR . 'salt.php';
$file = self::$_path . DIRECTORY_SEPARATOR . 'salt.php';
if (is_readable($file)) {
$items = explode('|', file_get_contents($file));
if (is_array($items) && count($items) == 3) {
@@ -301,12 +308,12 @@ class Filesystem extends AbstractData
}
break;
case 'traffic_limiter':
$file = $this->_path . DIRECTORY_SEPARATOR . 'traffic_limiter.php';
$file = self::$_path . DIRECTORY_SEPARATOR . 'traffic_limiter.php';
if (is_readable($file)) {
require $file;
$this->_last_cache = $GLOBALS['traffic_limiter'];
if (array_key_exists($key, $this->_last_cache)) {
return $this->_last_cache[$key];
self::$_last_cache = $GLOBALS['traffic_limiter'];
if (array_key_exists($key, self::$_last_cache)) {
return self::$_last_cache[$key];
}
}
break;
@@ -318,10 +325,11 @@ class Filesystem extends AbstractData
* get the data
*
* @access public
* @static
* @param string $filename
* @return array|false $data
*/
private function _get($filename)
private static function _get($filename)
{
return Json::decode(
substr(
@@ -342,7 +350,7 @@ class Filesystem extends AbstractData
{
$pastes = array();
$firstLevel = array_filter(
scandir($this->_path),
scandir(self::$_path),
'PrivateBin\Data\Filesystem::_isFirstLevelDir'
);
if (count($firstLevel) > 0) {
@@ -350,7 +358,7 @@ class Filesystem extends AbstractData
for ($i = 0, $max = $batchsize * 10; $i < $max; ++$i) {
$firstKey = array_rand($firstLevel);
$secondLevel = array_filter(
scandir($this->_path . DIRECTORY_SEPARATOR . $firstLevel[$firstKey]),
scandir(self::$_path . DIRECTORY_SEPARATOR . $firstLevel[$firstKey]),
'PrivateBin\Data\Filesystem::_isSecondLevelDir'
);
@@ -361,7 +369,7 @@ class Filesystem extends AbstractData
}
$secondKey = array_rand($secondLevel);
$path = $this->_path . DIRECTORY_SEPARATOR .
$path = self::$_path . DIRECTORY_SEPARATOR .
$firstLevel[$firstKey] . DIRECTORY_SEPARATOR .
$secondLevel[$secondKey];
if (!is_dir($path)) {
@@ -404,55 +412,6 @@ class Filesystem extends AbstractData
return $pastes;
}
/**
* @inheritDoc
*/
public function getAllPastes()
{
$pastes = array();
$firstLevel = array_filter(
scandir($this->_path),
'PrivateBin\Data\Filesystem::_isFirstLevelDir'
);
if (count($firstLevel) > 0) {
foreach ($firstLevel as $firstKey) {
$secondLevel = array_filter(
scandir($this->_path . DIRECTORY_SEPARATOR . $firstKey),
'PrivateBin\Data\Filesystem::_isSecondLevelDir'
);
// skip this folder
if (count($secondLevel) == 0) {
continue;
}
foreach ($secondLevel as $secondKey) {
$path = $this->_path . DIRECTORY_SEPARATOR . $firstKey .
DIRECTORY_SEPARATOR . $secondKey;
if (!is_dir($path)) {
continue;
}
$thirdLevel = array_filter(
array_map(
function ($filename) {
return strlen($filename) >= 20 ?
substr($filename, 0, -4) :
$filename;
},
scandir($path)
),
'PrivateBin\\Model\\Paste::isValidId'
);
if (count($thirdLevel) == 0) {
continue;
}
$pastes += $thirdLevel;
}
}
}
return $pastes;
}
/**
* Convert paste id to storage path.
*
@@ -464,12 +423,13 @@ class Filesystem extends AbstractData
* eg. input 'e3570978f9e4aa90' --> output 'data/e3/57/'
*
* @access private
* @static
* @param string $dataid
* @return string
*/
private function _dataid2path($dataid)
private static function _dataid2path($dataid)
{
return $this->_path . DIRECTORY_SEPARATOR .
return self::$_path . DIRECTORY_SEPARATOR .
substr($dataid, 0, 2) . DIRECTORY_SEPARATOR .
substr($dataid, 2, 2) . DIRECTORY_SEPARATOR;
}
@@ -480,12 +440,13 @@ class Filesystem extends AbstractData
* eg. input 'e3570978f9e4aa90' --> output 'data/e3/57/e3570978f9e4aa90.discussion/'
*
* @access private
* @static
* @param string $dataid
* @return string
*/
private function _dataid2discussionpath($dataid)
private static function _dataid2discussionpath($dataid)
{
return $this->_dataid2path($dataid) . $dataid .
return self::_dataid2path($dataid) . $dataid .
'.discussion' . DIRECTORY_SEPARATOR;
}
@@ -493,23 +454,25 @@ class Filesystem extends AbstractData
* Check that the given element is a valid first level directory.
*
* @access private
* @static
* @param string $element
* @return bool
*/
private function _isFirstLevelDir($element)
private static function _isFirstLevelDir($element)
{
return $this->_isSecondLevelDir($element) &&
is_dir($this->_path . DIRECTORY_SEPARATOR . $element);
return self::_isSecondLevelDir($element) &&
is_dir(self::$_path . DIRECTORY_SEPARATOR . $element);
}
/**
* Check that the given element is a valid second level directory.
*
* @access private
* @static
* @param string $element
* @return bool
*/
private function _isSecondLevelDir($element)
private static function _isSecondLevelDir($element)
{
return (bool) preg_match('/^[a-f0-9]{2}$/', $element);
}
@@ -518,14 +481,15 @@ class Filesystem extends AbstractData
* store the data
*
* @access public
* @static
* @param string $filename
* @param array $data
* @return bool
*/
private function _store($filename, array $data)
private static function _store($filename, array $data)
{
try {
return $this->_storeString(
return self::_storeString(
$filename,
self::PROTECTION_LINE . PHP_EOL . Json::encode($data)
);
@@ -538,19 +502,20 @@ class Filesystem extends AbstractData
* store a string
*
* @access public
* @static
* @param string $filename
* @param string $data
* @return bool
*/
private function _storeString($filename, $data)
private static function _storeString($filename, $data)
{
// Create storage directory if it does not exist.
if (!is_dir($this->_path)) {
if (!@mkdir($this->_path, 0700)) {
if (!is_dir(self::$_path)) {
if (!@mkdir(self::$_path, 0700)) {
return false;
}
}
$file = $this->_path . DIRECTORY_SEPARATOR . '.htaccess';
$file = self::$_path . DIRECTORY_SEPARATOR . '.htaccess';
if (!is_file($file)) {
$writtenBytes = 0;
if ($fileCreated = @touch($file)) {
@@ -588,11 +553,12 @@ class Filesystem extends AbstractData
* rename a file, prepending the protection line at the beginning
*
* @access public
* @static
* @param string $srcFile
* @param string $destFile
* @return void
*/
private function _prependRename($srcFile, $destFile)
private static function _prependRename($srcFile, $destFile)
{
// don't overwrite already converted file
if (!is_readable($destFile)) {

View File

@@ -14,43 +14,54 @@ class GoogleCloudStorage extends AbstractData
* GCS client
*
* @access private
* @static
* @var StorageClient
*/
private $_client = null;
private static $_client = null;
/**
* GCS bucket
*
* @access private
* @static
* @var Bucket
*/
private $_bucket = null;
private static $_bucket = null;
/**
* object prefix
*
* @access private
* @static
* @var string
*/
private $_prefix = 'pastes';
private static $_prefix = 'pastes';
/**
* bucket acl type
*
* @access private
* @static
* @var bool
*/
private $_uniformacl = false;
private static $_uniformacl = false;
/**
* instantiantes a new Google Cloud Storage data backend.
* returns a Google Cloud Storage data backend.
*
* @access public
* @static
* @param array $options
* @return
* @return GoogleCloudStorage
*/
public function __construct(array $options)
public static function getInstance(array $options)
{
// if needed initialize the singleton
if (!(self::$_instance instanceof self)) {
self::$_instance = new self;
}
$bucket = null;
if (getenv('PRIVATEBIN_GCS_BUCKET')) {
$bucket = getenv('PRIVATEBIN_GCS_BUCKET');
}
@@ -58,22 +69,24 @@ class GoogleCloudStorage extends AbstractData
$bucket = $options['bucket'];
}
if (is_array($options) && array_key_exists('prefix', $options)) {
$this->_prefix = $options['prefix'];
self::$_prefix = $options['prefix'];
}
if (is_array($options) && array_key_exists('uniformacl', $options)) {
$this->_uniformacl = $options['uniformacl'];
self::$_uniformacl = $options['uniformacl'];
}
$this->_client = class_exists('StorageClientStub', false) ?
new \StorageClientStub(array()) :
new StorageClient(array('suppressKeyFileNotice' => true));
if (isset($bucket)) {
$this->_bucket = $this->_client->bucket($bucket);
if (empty(self::$_client)) {
self::$_client = class_exists('StorageClientStub', false) ?
new \StorageClientStub(array()) :
new StorageClient(array('suppressKeyFileNotice' => true));
}
self::$_bucket = self::$_client->bucket($bucket);
return self::$_instance;
}
/**
* returns the google storage object key for $pasteid in $this->_bucket.
* returns the google storage object key for $pasteid in self::$_bucket.
*
* @access private
* @param $pasteid string to get the key for
@@ -81,14 +94,14 @@ class GoogleCloudStorage extends AbstractData
*/
private function _getKey($pasteid)
{
if ($this->_prefix != '') {
return $this->_prefix . '/' . $pasteid;
if (self::$_prefix != '') {
return self::$_prefix . '/' . $pasteid;
}
return $pasteid;
}
/**
* Uploads the payload in the $this->_bucket under the specified key.
* Uploads the payload in the self::$_bucket under the specified key.
* The entire payload is stored as a JSON document. The metadata is replicated
* as the GCS object's metadata except for the fields attachment, attachmentname
* and salt.
@@ -113,12 +126,12 @@ class GoogleCloudStorage extends AbstractData
'metadata' => $metadata,
),
);
if (!$this->_uniformacl) {
if (!self::$_uniformacl) {
$data['predefinedAcl'] = 'private';
}
$this->_bucket->upload(Json::encode($payload), $data);
self::$_bucket->upload(Json::encode($payload), $data);
} catch (Exception $e) {
error_log('failed to upload ' . $key . ' to ' . $this->_bucket->name() . ', ' .
error_log('failed to upload ' . $key . ' to ' . self::$_bucket->name() . ', ' .
trim(preg_replace('/\s\s+/', ' ', $e->getMessage())));
return false;
}
@@ -143,13 +156,13 @@ class GoogleCloudStorage extends AbstractData
public function read($pasteid)
{
try {
$o = $this->_bucket->object($this->_getKey($pasteid));
$o = self::$_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() . ', ' .
error_log('failed to read ' . $pasteid . ' from ' . self::$_bucket->name() . ', ' .
trim(preg_replace('/\s\s+/', ' ', $e->getMessage())));
return false;
}
@@ -163,9 +176,9 @@ class GoogleCloudStorage extends AbstractData
$name = $this->_getKey($pasteid);
try {
foreach ($this->_bucket->objects(array('prefix' => $name . '/discussion/')) as $comment) {
foreach (self::$_bucket->objects(array('prefix' => $name . '/discussion/')) as $comment) {
try {
$this->_bucket->object($comment->name())->delete();
self::$_bucket->object($comment->name())->delete();
} catch (NotFoundException $e) {
// ignore if already deleted.
}
@@ -175,7 +188,7 @@ class GoogleCloudStorage extends AbstractData
}
try {
$this->_bucket->object($name)->delete();
self::$_bucket->object($name)->delete();
} catch (NotFoundException $e) {
// ignore if already deleted
}
@@ -186,7 +199,7 @@ class GoogleCloudStorage extends AbstractData
*/
public function exists($pasteid)
{
$o = $this->_bucket->object($this->_getKey($pasteid));
$o = self::$_bucket->object($this->_getKey($pasteid));
return $o->exists();
}
@@ -210,8 +223,8 @@ class GoogleCloudStorage extends AbstractData
$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());
foreach (self::$_bucket->objects(array('prefix' => $prefix)) as $key) {
$comment = JSON::decode(self::$_bucket->object($key->name())->downloadAsString());
$comment['id'] = basename($key->name());
$slot = $this->getOpenSlot($comments, (int) $comment['meta']['created']);
$comments[$slot] = $comment;
@@ -228,7 +241,7 @@ class GoogleCloudStorage extends AbstractData
public function existsComment($pasteid, $parentid, $commentid)
{
$name = $this->_getKey($pasteid) . '/discussion/' . $parentid . '/' . $commentid;
$o = $this->_bucket->object($name);
$o = self::$_bucket->object($name);
return $o->exists();
}
@@ -239,7 +252,7 @@ class GoogleCloudStorage extends AbstractData
{
$path = 'config/' . $namespace;
try {
foreach ($this->_bucket->objects(array('prefix' => $path)) as $object) {
foreach (self::$_bucket->objects(array('prefix' => $path)) as $object) {
$name = $object->name();
if (strlen($name) > strlen($path) && substr($name, strlen($path), 1) !== '/') {
continue;
@@ -287,12 +300,12 @@ class GoogleCloudStorage extends AbstractData
'metadata' => $metadata,
),
);
if (!$this->_uniformacl) {
if (!self::$_uniformacl) {
$data['predefinedAcl'] = 'private';
}
$this->_bucket->upload($value, $data);
self::$_bucket->upload($value, $data);
} catch (Exception $e) {
error_log('failed to set key ' . $key . ' to ' . $this->_bucket->name() . ', ' .
error_log('failed to set key ' . $key . ' to ' . self::$_bucket->name() . ', ' .
trim(preg_replace('/\s\s+/', ' ', $e->getMessage())));
return false;
}
@@ -310,7 +323,7 @@ class GoogleCloudStorage extends AbstractData
$key = 'config/' . $namespace . '/' . $key;
}
try {
$o = $this->_bucket->object($key);
$o = self::$_bucket->object($key);
return $o->downloadAsString();
} catch (NotFoundException $e) {
return '';
@@ -325,12 +338,12 @@ class GoogleCloudStorage extends AbstractData
$expired = array();
$now = time();
$prefix = $this->_prefix;
$prefix = self::$_prefix;
if ($prefix != '') {
$prefix .= '/';
}
try {
foreach ($this->_bucket->objects(array('prefix' => $prefix)) as $object) {
foreach (self::$_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']);
@@ -348,28 +361,4 @@ class GoogleCloudStorage extends AbstractData
}
return $expired;
}
/**
* @inheritDoc
*/
public function getAllPastes()
{
$pastes = array();
$prefix = $this->_prefix;
if ($prefix != '') {
$prefix .= '/';
}
try {
foreach ($this->_bucket->objects(array('prefix' => $prefix)) as $object) {
$candidate = substr($object->name(), strlen($prefix));
if (strpos($candidate, '/') === false) {
$pastes[] = $candidate;
}
}
} catch (NotFoundException $e) {
// no objects in the bucket yet
}
return $pastes;
}
}

View File

@@ -45,71 +45,86 @@ class S3Storage extends AbstractData
* S3 client
*
* @access private
* @static
* @var S3Client
*/
private $_client = null;
private static $_client = null;
/**
* S3 client options
*
* @access private
* @static
* @var array
*/
private $_options = array();
private static $_options = array();
/**
* S3 bucket
*
* @access private
* @static
* @var string
*/
private $_bucket = null;
private static $_bucket = null;
/**
* S3 prefix for all PrivateBin data in this bucket
*
* @access private
* @static
* @var string
*/
private $_prefix = '';
private static $_prefix = '';
/**
* instantiates a new S3 data backend.
* returns an S3 data backend.
*
* @access public
* @static
* @param array $options
* @return
* @return S3Storage
*/
public function __construct(array $options)
public static function getInstance(array $options)
{
$this->_options['credentials'] = array();
// if needed initialize the singleton
if (!(self::$_instance instanceof self)) {
self::$_instance = new self;
}
self::$_options = array();
self::$_options['credentials'] = array();
if (is_array($options) && array_key_exists('region', $options)) {
$this->_options['region'] = $options['region'];
self::$_options['region'] = $options['region'];
}
if (is_array($options) && array_key_exists('version', $options)) {
$this->_options['version'] = $options['version'];
self::$_options['version'] = $options['version'];
}
if (is_array($options) && array_key_exists('endpoint', $options)) {
$this->_options['endpoint'] = $options['endpoint'];
self::$_options['endpoint'] = $options['endpoint'];
}
if (is_array($options) && array_key_exists('accesskey', $options)) {
$this->_options['credentials']['key'] = $options['accesskey'];
self::$_options['credentials']['key'] = $options['accesskey'];
}
if (is_array($options) && array_key_exists('secretkey', $options)) {
$this->_options['credentials']['secret'] = $options['secretkey'];
self::$_options['credentials']['secret'] = $options['secretkey'];
}
if (is_array($options) && array_key_exists('use_path_style_endpoint', $options)) {
$this->_options['use_path_style_endpoint'] = filter_var($options['use_path_style_endpoint'], FILTER_VALIDATE_BOOLEAN);
self::$_options['use_path_style_endpoint'] = filter_var($options['use_path_style_endpoint'], FILTER_VALIDATE_BOOLEAN);
}
if (is_array($options) && array_key_exists('bucket', $options)) {
$this->_bucket = $options['bucket'];
self::$_bucket = $options['bucket'];
}
if (is_array($options) && array_key_exists('prefix', $options)) {
$this->_prefix = $options['prefix'];
self::$_prefix = $options['prefix'];
}
$this->_client = new S3Client($this->_options);
if (empty(self::$_client)) {
self::$_client = new S3Client(self::$_options);
}
return self::$_instance;
}
/**
@@ -123,12 +138,12 @@ class S3Storage extends AbstractData
{
$allObjects = array();
$options = array(
'Bucket' => $this->_bucket,
'Bucket' => self::$_bucket,
'Prefix' => $prefix,
);
do {
$objectsListResponse = $this->_client->listObjects($options);
$objectsListResponse = self::$_client->listObjects($options);
$objects = $objectsListResponse['Contents'] ?? array();
foreach ($objects as $object) {
$allObjects[] = $object;
@@ -140,7 +155,7 @@ class S3Storage extends AbstractData
}
/**
* returns the S3 storage object key for $pasteid in $this->_bucket.
* returns the S3 storage object key for $pasteid in self::$_bucket.
*
* @access private
* @param $pasteid string to get the key for
@@ -148,14 +163,14 @@ class S3Storage extends AbstractData
*/
private function _getKey($pasteid)
{
if ($this->_prefix != '') {
return $this->_prefix . '/' . $pasteid;
if (self::$_prefix != '') {
return self::$_prefix . '/' . $pasteid;
}
return $pasteid;
}
/**
* Uploads the payload in the $this->_bucket under the specified key.
* Uploads the payload in the self::$_bucket under the specified key.
* The entire payload is stored as a JSON document. The metadata is replicated
* as the S3 object's metadata except for the fields attachment, attachmentname
* and salt.
@@ -172,15 +187,15 @@ class S3Storage extends AbstractData
$metadata[$k] = strval($v);
}
try {
$this->_client->putObject(array(
'Bucket' => $this->_bucket,
self::$_client->putObject(array(
'Bucket' => self::$_bucket,
'Key' => $key,
'Body' => Json::encode($payload),
'ContentType' => 'application/json',
'Metadata' => $metadata,
));
} catch (S3Exception $e) {
error_log('failed to upload ' . $key . ' to ' . $this->_bucket . ', ' .
error_log('failed to upload ' . $key . ' to ' . self::$_bucket . ', ' .
trim(preg_replace('/\s\s+/', ' ', $e->getMessage())));
return false;
}
@@ -205,14 +220,14 @@ class S3Storage extends AbstractData
public function read($pasteid)
{
try {
$object = $this->_client->getObject(array(
'Bucket' => $this->_bucket,
$object = self::$_client->getObject(array(
'Bucket' => self::$_bucket,
'Key' => $this->_getKey($pasteid),
));
$data = $object['Body']->getContents();
return Json::decode($data);
} catch (S3Exception $e) {
error_log('failed to read ' . $pasteid . ' from ' . $this->_bucket . ', ' .
error_log('failed to read ' . $pasteid . ' from ' . self::$_bucket . ', ' .
trim(preg_replace('/\s\s+/', ' ', $e->getMessage())));
return false;
}
@@ -229,8 +244,8 @@ class S3Storage extends AbstractData
$comments = $this->_listAllObjects($name . '/discussion/');
foreach ($comments as $comment) {
try {
$this->_client->deleteObject(array(
'Bucket' => $this->_bucket,
self::$_client->deleteObject(array(
'Bucket' => self::$_bucket,
'Key' => $comment['Key'],
));
} catch (S3Exception $e) {
@@ -242,8 +257,8 @@ class S3Storage extends AbstractData
}
try {
$this->_client->deleteObject(array(
'Bucket' => $this->_bucket,
self::$_client->deleteObject(array(
'Bucket' => self::$_bucket,
'Key' => $name,
));
} catch (S3Exception $e) {
@@ -256,7 +271,7 @@ class S3Storage extends AbstractData
*/
public function exists($pasteid)
{
return $this->_client->doesObjectExistV2($this->_bucket, $this->_getKey($pasteid));
return self::$_client->doesObjectExistV2(self::$_bucket, $this->_getKey($pasteid));
}
/**
@@ -281,8 +296,8 @@ class S3Storage extends AbstractData
try {
$entries = $this->_listAllObjects($prefix);
foreach ($entries as $entry) {
$object = $this->_client->getObject(array(
'Bucket' => $this->_bucket,
$object = self::$_client->getObject(array(
'Bucket' => self::$_bucket,
'Key' => $entry['Key'],
));
$body = JSON::decode($object['Body']->getContents());
@@ -304,7 +319,7 @@ class S3Storage extends AbstractData
public function existsComment($pasteid, $parentid, $commentid)
{
$name = $this->_getKey($pasteid) . '/discussion/' . $parentid . '/' . $commentid;
return $this->_client->doesObjectExistV2($this->_bucket, $name);
return self::$_client->doesObjectExistV2(self::$_bucket, $name);
}
/**
@@ -312,7 +327,7 @@ class S3Storage extends AbstractData
*/
public function purgeValues($namespace, $time)
{
$path = $this->_prefix;
$path = self::$_prefix;
if ($path != '') {
$path .= '/';
}
@@ -324,16 +339,16 @@ class S3Storage extends AbstractData
if (strlen($name) > strlen($path) && substr($name, strlen($path), 1) !== '/') {
continue;
}
$head = $this->_client->headObject(array(
'Bucket' => $this->_bucket,
$head = self::$_client->headObject(array(
'Bucket' => self::$_bucket,
'Key' => $name,
));
if ($head->get('Metadata') != null && array_key_exists('value', $head->get('Metadata'))) {
$value = $head->get('Metadata')['value'];
if (array_key_exists('Metadata', $head) && array_key_exists('value', $head['Metadata'])) {
$value = $head['Metadata']['value'];
if (is_numeric($value) && intval($value) < $time) {
try {
$this->_client->deleteObject(array(
'Bucket' => $this->_bucket,
self::$_client->deleteObject(array(
'Bucket' => self::$_bucket,
'Key' => $name,
));
} catch (S3Exception $e) {
@@ -354,7 +369,7 @@ class S3Storage extends AbstractData
*/
public function setValue($value, $namespace, $key = '')
{
$prefix = $this->_prefix;
$prefix = self::$_prefix;
if ($prefix != '') {
$prefix .= '/';
}
@@ -370,15 +385,15 @@ class S3Storage extends AbstractData
$metadata['value'] = strval($value);
}
try {
$this->_client->putObject(array(
'Bucket' => $this->_bucket,
self::$_client->putObject(array(
'Bucket' => self::$_bucket,
'Key' => $key,
'Body' => $value,
'ContentType' => 'application/json',
'Metadata' => $metadata,
));
} catch (S3Exception $e) {
error_log('failed to set key ' . $key . ' to ' . $this->_bucket . ', ' .
error_log('failed to set key ' . $key . ' to ' . self::$_bucket . ', ' .
trim(preg_replace('/\s\s+/', ' ', $e->getMessage())));
return false;
}
@@ -390,7 +405,7 @@ class S3Storage extends AbstractData
*/
public function getValue($namespace, $key = '')
{
$prefix = $this->_prefix;
$prefix = self::$_prefix;
if ($prefix != '') {
$prefix .= '/';
}
@@ -402,8 +417,8 @@ class S3Storage extends AbstractData
}
try {
$object = $this->_client->getObject(array(
'Bucket' => $this->_bucket,
$object = self::$_client->getObject(array(
'Bucket' => self::$_bucket,
'Key' => $key,
));
return $object['Body']->getContents();
@@ -419,19 +434,19 @@ class S3Storage extends AbstractData
{
$expired = array();
$now = time();
$prefix = $this->_prefix;
$prefix = self::$_prefix;
if ($prefix != '') {
$prefix .= '/';
}
try {
foreach ($this->_listAllObjects($prefix) as $object) {
$head = $this->_client->headObject(array(
'Bucket' => $this->_bucket,
$head = self::$_client->headObject(array(
'Bucket' => self::$_bucket,
'Key' => $object['Key'],
));
if ($head->get('Metadata') != null && array_key_exists('expire_date', $head->get('Metadata'))) {
$expire_at = intval($head->get('Metadata')['expire_date']);
if (array_key_exists('Metadata', $head) && array_key_exists('expire_date', $head['Metadata'])) {
$expire_at = intval($head['Metadata']['expire_date']);
if ($expire_at != 0 && $expire_at < $now) {
array_push($expired, $object['Key']);
}
@@ -446,28 +461,4 @@ class S3Storage extends AbstractData
}
return $expired;
}
/**
* @inheritDoc
*/
public function getAllPastes()
{
$pastes = array();
$prefix = $this->_prefix;
if ($prefix != '') {
$prefix .= '/';
}
try {
foreach ($this->_listAllObjects($prefix) as $object) {
$candidate = substr($object['Key'], strlen($prefix));
if (strpos($candidate, '/') === false) {
$pastes[] = $candidate;
}
}
} catch (S3Exception $e) {
// no objects in the bucket yet
}
return $pastes;
}
}

View File

@@ -81,8 +81,10 @@ class Model
public function getStore()
{
if ($this->_store === null) {
$class = 'PrivateBin\\Data\\' . $this->_conf->getKey('class', 'model');
$this->_store = new $class($this->_conf->getSection('model_options'));
$this->_store = forward_static_call(
'PrivateBin\\Data\\' . $this->_conf->getKey('class', 'model') . '::getInstance',
$this->_conf->getSection('model_options')
);
}
return $this->_store;
}

View File

@@ -165,7 +165,10 @@ class Comment extends AbstractModel
if ($icon != 'none') {
$pngdata = '';
$hmac = TrafficLimiter::getHash();
if ($icon == 'jdenticon') {
if ($icon == 'identicon') {
$identicon = new Identicon();
$pngdata = $identicon->getImageDataUri($hmac, 16);
} elseif ($icon == 'jdenticon') {
$jdenticon = new Jdenticon(array(
'hash' => $hmac,
'size' => 16,
@@ -175,9 +178,6 @@ class Comment extends AbstractModel
),
));
$pngdata = $jdenticon->getImageDataUri('png');
} elseif ($icon == 'identicon') {
$identicon = new Identicon();
$pngdata = $identicon->getImageDataUri($hmac, 16);
} elseif ($icon == 'vizhash') {
$vh = new Vizhash16x16();
$pngdata = 'data:image/png;base64,' . base64_encode(

View File

@@ -48,7 +48,7 @@ class YourlsProxy
*/
public function __construct(Configuration $conf, $link)
{
if (strpos($link, $conf->getKey('basepath') . '?') === false) {
if (strpos($link, $conf->getKey('basepath') . '/?') === false) {
$this->_error = 'Trying to shorten a URL that isn\'t pointing at our instance.';
return;
}

View File

@@ -32,9 +32,9 @@ Helper::updateSubresourceIntegrity();
*/
class StorageClientStub extends StorageClient
{
private $_config = null;
private $_connection = null;
private static $_buckets = array();
private $_config = null;
private $_connection = null;
private $_buckets = array();
public function __construct(array $config = array())
{
@@ -44,11 +44,11 @@ class StorageClientStub extends StorageClient
public function bucket($name, $userProject = false)
{
if (!key_exists($name, self::$_buckets)) {
if (!key_exists($name, $this->_buckets)) {
$b = new BucketStub($this->_connection, $name, array(), $this);
self::$_buckets[$name] = $b;
$this->_buckets[$name] = $b;
}
return self::$_buckets[$name];
return $this->_buckets[$name];
}
/**
@@ -56,8 +56,8 @@ class StorageClientStub extends StorageClient
*/
public function deleteBucket($name)
{
if (key_exists($name, self::$_buckets)) {
unset(self::$_buckets[$name]);
if (key_exists($name, $this->_buckets)) {
unset($this->_buckets[$name]);
} else {
throw new NotFoundException();
}
@@ -110,11 +110,11 @@ class StorageClientStub extends StorageClient
public function createBucket($name, array $options = array())
{
if (key_exists($name, self::$_buckets)) {
if (key_exists($name, $this->_buckets)) {
throw new BadRequestException('already exists');
}
$b = new BucketStub($this->_connection, $name, array(), $this);
self::$_buckets[$name] = $b;
$this->_buckets[$name] = $b;
return $b;
}
}

View File

@@ -9,9 +9,7 @@
* DANGER: Too many options/settings and too high max iteration setting may trigger
* a fork bomb. Please save your work before executing this script.
*/
define('PATH', dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR);
include PATH . 'tst' . DIRECTORY_SEPARATOR . 'Bootstrap.php';
include 'Bootstrap.php';
$vd = array('view', 'delete');
$vcd = array('view', 'create', 'delete');
@@ -394,7 +392,7 @@ class ConfigurationTestGenerator
}
}
$code .= '}' . PHP_EOL;
file_put_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'tst' . DIRECTORY_SEPARATOR . 'ConfigurationCombinationsTest.php', $code);
file_put_contents('ConfigurationCombinationsTest.php', $code);
}
/**
@@ -429,9 +427,7 @@ class ConfigurationCombinationsTest extends PHPUnit_Framework_TestCase
/* Setup Routine */
Helper::confBackup();
$this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
$this->_model = new Filesystem(array('dir' => $this->_path));
ServerSalt::setStore($this->_model);
TrafficLimiter::setStore($this->_model);
$this->_model = Filesystem::getInstance(array('dir' => $this->_path));
$this->reset();
}

View File

@@ -16,7 +16,7 @@ class ControllerTest extends PHPUnit_Framework_TestCase
{
/* Setup Routine */
$this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
$this->_data = new Filesystem(array('dir' => $this->_path));
$this->_data = Filesystem::getInstance(array('dir' => $this->_path));
ServerSalt::setStore($this->_data);
TrafficLimiter::setStore($this->_data);
$this->reset();

View File

@@ -25,7 +25,7 @@ class ControllerWithDbTest extends ControllerTest
mkdir($this->_path);
}
$this->_options['dsn'] = 'sqlite:' . $this->_path . DIRECTORY_SEPARATOR . 'tst.sq3';
$this->_data = new Database($this->_options);
$this->_data = Database::getInstance($this->_options);
ServerSalt::setStore($this->_data);
TrafficLimiter::setStore($this->_data);
$this->reset();

View File

@@ -39,7 +39,7 @@ class ControllerWithGcsTest extends ControllerTest
'bucket' => self::$_bucket->name(),
'prefix' => 'pastes',
);
$this->_data = new GoogleCloudStorage($this->_options);
$this->_data = GoogleCloudStorage::getInstance($this->_options);
ServerSalt::setStore($this->_data);
TrafficLimiter::setStore($this->_data);
$this->reset();

View File

@@ -22,7 +22,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
{
/* Setup Routine */
$this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
$this->_model = new Database($this->_options);
$this->_model = Database::getInstance($this->_options);
}
public function tearDown()
@@ -35,7 +35,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
public function testSaltMigration()
{
ServerSalt::setStore(new Filesystem(array('dir' => 'data')));
ServerSalt::setStore(Filesystem::getInstance(array('dir' => 'data')));
$salt = ServerSalt::get();
$file = 'data' . DIRECTORY_SEPARATOR . 'salt.php';
$this->assertFileExists($file, 'ServerSalt got initialized and stored on disk');
@@ -141,7 +141,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
*/
public function testGetIbmInstance()
{
new Database(array(
Database::getInstance(array(
'dsn' => 'ibm:', 'usr' => null, 'pwd' => null,
'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
));
@@ -152,7 +152,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
*/
public function testGetInformixInstance()
{
new Database(array(
Database::getInstance(array(
'dsn' => 'informix:', 'usr' => null, 'pwd' => null,
'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
));
@@ -163,7 +163,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
*/
public function testGetMssqlInstance()
{
new Database(array(
Database::getInstance(array(
'dsn' => 'mssql:', 'usr' => null, 'pwd' => null,
'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
));
@@ -174,7 +174,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
*/
public function testGetMysqlInstance()
{
new Database(array(
Database::getInstance(array(
'dsn' => 'mysql:', 'usr' => null, 'pwd' => null,
'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
));
@@ -185,7 +185,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
*/
public function testGetOciInstance()
{
new Database(array(
Database::getInstance(array(
'dsn' => 'oci:', 'usr' => null, 'pwd' => null,
'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
));
@@ -196,7 +196,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
*/
public function testGetPgsqlInstance()
{
new Database(array(
Database::getInstance(array(
'dsn' => 'pgsql:', 'usr' => null, 'pwd' => null,
'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
));
@@ -208,7 +208,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
*/
public function testGetFooInstance()
{
new Database(array(
Database::getInstance(array(
'dsn' => 'foo:', 'usr' => null, 'pwd' => null, 'opt' => null,
));
}
@@ -221,7 +221,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
{
$options = $this->_options;
unset($options['dsn']);
new Database($options);
Database::getInstance($options);
}
/**
@@ -232,7 +232,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
{
$options = $this->_options;
unset($options['usr']);
new Database($options);
Database::getInstance($options);
}
/**
@@ -243,7 +243,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
{
$options = $this->_options;
unset($options['pwd']);
new Database($options);
Database::getInstance($options);
}
/**
@@ -254,7 +254,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
{
$options = $this->_options;
unset($options['opt']);
new Database($options);
Database::getInstance($options);
}
public function testOldAttachments()
@@ -266,7 +266,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
}
$this->_options['dsn'] = 'sqlite:' . $path;
$this->_options['tbl'] = 'bar_';
$model = new Database($this->_options);
$model = Database::getInstance($this->_options);
$original = $paste = Helper::getPasteWithAttachment(1, array('expire_date' => 1344803344));
$meta = $paste['meta'];
@@ -311,7 +311,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
}
$this->_options['dsn'] = 'sqlite:' . $path;
$this->_options['tbl'] = 'baz_';
$model = new Database($this->_options);
$model = Database::getInstance($this->_options);
$paste = Helper::getPaste(1, array('expire_date' => 1344803344));
unset($paste['meta']['formatter'], $paste['meta']['opendiscussion'], $paste['meta']['salt']);
$model->delete(Helper::getPasteId());
@@ -378,7 +378,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
'vizhash BLOB, ' .
'postdate INT );'
);
$this->assertInstanceOf('PrivateBin\\Data\\Database', new Database($this->_options));
$this->assertInstanceOf('PrivateBin\\Data\\Database', Database::getInstance($this->_options));
// check if version number was upgraded in created configuration table
$statement = $db->prepare('SELECT value FROM foo_config WHERE id LIKE ?');

View File

@@ -15,7 +15,7 @@ class FilesystemTest extends PHPUnit_Framework_TestCase
/* Setup Routine */
$this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
$this->_invalidPath = $this->_path . DIRECTORY_SEPARATOR . 'bar';
$this->_model = new Filesystem(array('dir' => $this->_path));
$this->_model = Filesystem::getInstance(array('dir' => $this->_path));
if (!is_dir($this->_path)) {
mkdir($this->_path);
}

View File

@@ -26,7 +26,7 @@ class GoogleCloudStorageTest extends PHPUnit_Framework_TestCase
public function setUp()
{
ini_set('error_log', stream_get_meta_data(tmpfile())['uri']);
$this->_model = new GoogleCloudStorage(array(
$this->_model = GoogleCloudStorage::getInstance(array(
'bucket' => self::$_bucket->name(),
'prefix' => 'pastes',
));

View File

@@ -9,6 +9,7 @@ use Identicon\Generator\GdGenerator;
use Identicon\Generator\ImageMagickGenerator;
use Identicon\Generator\SvgGenerator;
use Identicon\Identicon;
use Jdenticon\Identicon as Jdenticon;
use PrivateBin\Vizhash16x16;
@@ -17,7 +18,19 @@ $vizhash = new Vizhash16x16();
$identiconGenerators = array(
'identicon GD' => new Identicon(new GdGenerator()),
'identicon ImageMagick' => new Identicon(new ImageMagickGenerator()),
'identicon SVG' => new Identicon(new SvgGenerator())
'identicon SVG' => new Identicon(new SvgGenerator()),
);
$jdenticon = new Jdenticon(array(
'size' => 16,
'style' => array(
'backgroundColor' => '#fff0', // fully transparent, for dark mode
'padding' => 0,
),
));
$jdenticonGenerators = array(
'jdenticon' => 'png',
'jdenticon ImageMagick' => 'png',
'jdenticon SVG' => 'svg',
);
$results = array(
'vizhash' => array(
@@ -35,21 +48,30 @@ $results = array(
'identicon SVG' => array(
'lengths' => array(),
'time' => 0
)
),
'jdenticon' => array(
'lengths' => array(),
'time' => 0
),
'jdenticon ImageMagick' => array(
'lengths' => array(),
'time' => 0
),
'jdenticon SVG' => array(
'lengths' => array(),
'time' => 0
),
);
$hmacs = array();
echo 'generate ', ITERATIONS, ' hmacs and pre-populate the result array, so tests wont be slowed down', PHP_EOL;
for ($i = 0; $i < ITERATIONS; ++$i) {
$hmacs[$i] = hash_hmac('sha512', '127.0.0.1', bin2hex(random_bytes(256)));
$results['vizhash']['lengths'][$i] = 0;
$results['identicon GD']['lengths'][$i] = 0;
$results['identicon ImageMagick']['lengths'][$i] = 0;
$results['identicon SVG']['lengths'][$i] = 0;
foreach (array_keys($results) as $test) {
$results[$test]['lengths'][$i] = 0;
}
}
echo 'run vizhash tests', PHP_EOL;
$start = microtime(true);
foreach ($hmacs as $i => $hmac) {
@@ -60,7 +82,6 @@ foreach ($hmacs as $i => $hmac) {
}
$results['vizhash']['time'] = microtime(true) - $start;
foreach ($identiconGenerators as $key => $identicon) {
echo 'run ', $key,' tests', PHP_EOL;
$start = microtime(true);
@@ -71,9 +92,35 @@ foreach ($identiconGenerators as $key => $identicon) {
$results[$key]['time'] = microtime(true) - $start;
}
foreach ($jdenticonGenerators as $key => $format) {
echo 'run ', $key,' tests', PHP_EOL;
if ($key === 'jdenticon ImageMagick') {
$jdenticon->enableImageMagick = true;
} else {
$jdenticon->enableImageMagick = false;
}
$start = microtime(true);
foreach ($hmacs as $i => $hmac) {
$jdenticon->setHash($hmac);
$data = $jdenticon->getImageDataUri($format);
$results[$key]['lengths'][$i] = strlen($data);
}
$results[$key]['time'] = microtime(true) - $start;
}
define('PADDING_LENGTH', max(array_map(function ($key) { return strlen($key); }, array_keys($results))) + 1);
define(
'PADDING_LENGTH',
max(
array_map(
function ($key) {
return strlen($key);
},
array_keys($results)
)
) + 1
);
function format_result_line($generator, $min, $max, $avg, $sec) {
echo str_pad($generator, PADDING_LENGTH, ' '), "\t",
str_pad($min, 4, ' ', STR_PAD_LEFT), "\t",
@@ -84,7 +131,10 @@ function format_result_line($generator, $min, $max, $avg, $sec) {
echo PHP_EOL;
format_result_line('Generator:', 'min', 'max', 'avg', 'seconds');
format_result_line(str_repeat('─', PADDING_LENGTH), str_repeat('─', 4), str_repeat('─', 4), str_repeat('─', 4), str_repeat('─', 7));
format_result_line(
str_repeat('─', PADDING_LENGTH), str_repeat('─', 4), str_repeat('─', 4),
str_repeat('─', 4), str_repeat('─', 7)
);
foreach ($results as $generator => $result) {
sort($result['lengths']);
format_result_line(

View File

@@ -18,7 +18,7 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
if (!is_dir($this->_path)) {
mkdir($this->_path);
}
$this->_model = new Filesystem(array('dir' => $this->_path));
$this->_model = Filesystem::getInstance(array('dir' => $this->_path));
ServerSalt::setStore($this->_model);
$_POST = array();
@@ -272,7 +272,7 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
{
$mock_yourls_service = $this->_path . DIRECTORY_SEPARATOR . 'yourls.json';
$options = parse_ini_file(CONF, true);
$options['main']['basepath'] = 'https://example.com/path'; // missing slash gets added by Configuration constructor
$options['main']['basepath'] = 'https://example.com/path';
$options['main']['urlshortener'] = 'https://example.com/path/shortenviayourls?link=';
$options['yourls']['apiurl'] = $mock_yourls_service;
Helper::createIniFile(CONF, $options);

View File

@@ -1,85 +0,0 @@
<?php
use PrivateBin\Data\Database;
use PrivateBin\Data\Filesystem;
class MigrateTest extends PHPUnit_Framework_TestCase
{
protected $_model_1;
protected $_model_2;
protected $_path;
protected $_path_instance_1;
protected $_path_instance_2;
public function setUp()
{
/* Setup Routine */
$this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
$this->_path_instance_1 = $this->_path . DIRECTORY_SEPARATOR . 'instance_1';
$this->_path_instance_2 = $this->_path . DIRECTORY_SEPARATOR . 'instance_2';
if (!is_dir($this->_path)) {
mkdir($this->_path);
}
mkdir($this->_path_instance_1);
mkdir($this->_path_instance_1 . DIRECTORY_SEPARATOR . 'cfg');
mkdir($this->_path_instance_2);
mkdir($this->_path_instance_2 . DIRECTORY_SEPARATOR . 'cfg');
$options = parse_ini_file(CONF_SAMPLE, true);
$options['purge']['limit'] = 0;
$options['model_options']['dir'] = $this->_path_instance_1 . DIRECTORY_SEPARATOR . 'data';
$this->_model_1 = new Filesystem($options['model_options']);
Helper::createIniFile($this->_path_instance_1 . DIRECTORY_SEPARATOR . 'cfg' . DIRECTORY_SEPARATOR . 'conf.php', $options);
$options['model'] = array(
'class' => 'Database',
);
$options['model_options'] = array(
'dsn' => 'sqlite:' . $this->_path_instance_2 . DIRECTORY_SEPARATOR . 'test.sq3',
'usr' => null,
'pwd' => null,
'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
);
$this->_model_2 = new Database($options['model_options']);
Helper::createIniFile($this->_path_instance_2 . DIRECTORY_SEPARATOR . 'cfg' . DIRECTORY_SEPARATOR . 'conf.php', $options);
}
public function tearDown()
{
/* Tear Down Routine */
Helper::rmDir($this->_path);
}
public function testMigrate()
{
if (version_compare(PHP_VERSION, '7.1.0') < 0) {
return; // skip test on unsupported PHP versions
}
$this->_model_1->delete(Helper::getPasteId());
$this->_model_2->delete(Helper::getPasteId());
// storing paste & comment
$this->_model_1->create(Helper::getPasteId(), Helper::getPaste());
$this->_model_1->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment());
// migrate files to database
$output = null;
$exit_code = 255;
exec('php ' . PATH . 'bin' . DIRECTORY_SEPARATOR . 'migrate --delete-after ' . $this->_path_instance_1 . DIRECTORY_SEPARATOR . 'cfg ' . $this->_path_instance_2 . DIRECTORY_SEPARATOR . 'cfg', $output, $exit_code);
$this->assertEquals(0, $exit_code, 'migrate script exits 0');
$this->assertFalse($this->_model_1->exists(Helper::getPasteId()), 'paste removed after migrating it');
$this->assertFalse($this->_model_1->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment removed after migrating it');
$this->assertTrue($this->_model_2->exists(Helper::getPasteId()), 'paste migrated');
$this->assertTrue($this->_model_2->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment migrated');
// migrate back to files
$exit_code = 255;
exec('php ' . PATH . 'bin' . DIRECTORY_SEPARATOR . 'migrate ' . $this->_path_instance_2 . DIRECTORY_SEPARATOR . 'cfg ' . $this->_path_instance_1 . DIRECTORY_SEPARATOR . 'cfg', $output, $exit_code);
$this->assertEquals(0, $exit_code, 'migrate script exits 0');
$this->assertTrue($this->_model_1->exists(Helper::getPasteId()), 'paste migrated back');
$this->assertTrue($this->_model_1->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment migrated back');
}
}

View File

@@ -1,6 +1,6 @@
<?php
use Jdenticon\Identicon;
use Identicon\Identicon;
use PrivateBin\Configuration;
use PrivateBin\Data\Database;
use PrivateBin\Model;
@@ -38,7 +38,7 @@ class ModelTest extends PHPUnit_Framework_TestCase
);
Helper::confBackup();
Helper::createIniFile(CONF, $options);
ServerSalt::setStore(new Database($options['model_options']));
ServerSalt::setStore(Database::getInstance($options['model_options']));
$this->_conf = new Configuration;
$this->_model = new Model($this->_conf);
$_SERVER['REMOTE_ADDR'] = '::1';
@@ -156,10 +156,10 @@ class ModelTest extends PHPUnit_Framework_TestCase
public function testCommentDefaults()
{
$class = 'PrivateBin\\Data\\' . $this->_conf->getKey('class', 'model');
$comment = new Comment(
$this->_conf,
new $class(
forward_static_call(
'PrivateBin\\Data\\' . $this->_conf->getKey('class', 'model') . '::getInstance',
$this->_conf->getSection('model_options')
)
);
@@ -259,10 +259,7 @@ class ModelTest extends PHPUnit_Framework_TestCase
$paste = $model->getPaste();
$paste->setData($pasteData);
$paste->store();
$this->assertTrue($paste->exists(), 'paste exists before creating comment');
$comment = $paste->getComment(Helper::getPasteId());
$comment->setData($commentData);
$paste->exists();
$db = new PDO(
$options['model_options']['dsn'],
@@ -274,9 +271,8 @@ class ModelTest extends PHPUnit_Framework_TestCase
$statement->execute();
$statement->closeCursor();
if (version_compare(PHP_VERSION, '7.2.0') < 0) {
throw new Exception('For some reason, this test stopped working in PHP < 7.2', 70);
}
$comment = $paste->getComment(Helper::getPasteId());
$comment->setData($commentData);
$comment->store();
}
@@ -318,15 +314,8 @@ class ModelTest extends PHPUnit_Framework_TestCase
$comment->get();
$comment->store();
$identicon = new Identicon(array(
'hash' => TrafficLimiter::getHash(),
'size' => 16,
'style' => array(
'backgroundColor' => '#fff0', // fully transparent, for dark mode
'padding' => 0,
),
));
$pngdata = $identicon->getImageDataUri('png');
$identicon = new Identicon();
$pngdata = $identicon->getImageDataUri(TrafficLimiter::getHash(), 16);
$comment = current($this->_model->getPaste(Helper::getPasteId())->get()['comments']);
$this->assertEquals($pngdata, $comment['meta']['icon'], 'icon gets set');
}
@@ -456,7 +445,7 @@ class ModelTest extends PHPUnit_Framework_TestCase
public function testPurge()
{
$conf = new Configuration;
$store = new Database($conf->getSection('model_options'));
$store = Database::getInstance($conf->getSection('model_options'));
$store->delete(Helper::getPasteId());
$expired = Helper::getPaste(2, array('expire_date' => 1344803344));
$paste = Helper::getPaste(2, array('expire_date' => time() + 3600));

View File

@@ -15,7 +15,7 @@ class PurgeLimiterTest extends PHPUnit_Framework_TestCase
mkdir($this->_path);
}
PurgeLimiter::setStore(
new Filesystem(array('dir' => $this->_path))
Filesystem::getInstance(array('dir' => $this->_path))
);
}

View File

@@ -21,7 +21,7 @@ class ServerSaltTest extends PHPUnit_Framework_TestCase
mkdir($this->_path);
}
ServerSalt::setStore(
new Filesystem(array('dir' => $this->_path))
Filesystem::getInstance(array('dir' => $this->_path))
);
$this->_otherPath = $this->_path . DIRECTORY_SEPARATOR . 'foo';
@@ -44,17 +44,17 @@ class ServerSaltTest extends PHPUnit_Framework_TestCase
{
// generating new salt
ServerSalt::setStore(
new Filesystem(array('dir' => $this->_path))
Filesystem::getInstance(array('dir' => $this->_path))
);
$salt = ServerSalt::get();
// try setting a different path and resetting it
ServerSalt::setStore(
new Filesystem(array('dir' => $this->_otherPath))
Filesystem::getInstance(array('dir' => $this->_otherPath))
);
$this->assertNotEquals($salt, ServerSalt::get());
ServerSalt::setStore(
new Filesystem(array('dir' => $this->_path))
Filesystem::getInstance(array('dir' => $this->_path))
);
$this->assertEquals($salt, ServerSalt::get());
}
@@ -63,7 +63,7 @@ class ServerSaltTest extends PHPUnit_Framework_TestCase
{
// try setting an invalid path
chmod($this->_invalidPath, 0000);
$store = new Filesystem(array('dir' => $this->_invalidPath));
$store = Filesystem::getInstance(array('dir' => $this->_invalidPath));
ServerSalt::setStore($store);
$salt = ServerSalt::get();
ServerSalt::setStore($store);
@@ -76,7 +76,7 @@ class ServerSaltTest extends PHPUnit_Framework_TestCase
chmod($this->_invalidPath, 0700);
file_put_contents($this->_invalidFile, '');
chmod($this->_invalidFile, 0000);
$store = new Filesystem(array('dir' => $this->_invalidPath));
$store = Filesystem::getInstance(array('dir' => $this->_invalidPath));
ServerSalt::setStore($store);
$salt = ServerSalt::get();
ServerSalt::setStore($store);
@@ -93,7 +93,7 @@ class ServerSaltTest extends PHPUnit_Framework_TestCase
}
file_put_contents($this->_invalidPath . DIRECTORY_SEPARATOR . '.htaccess', '');
chmod($this->_invalidPath, 0500);
$store = new Filesystem(array('dir' => $this->_invalidPath));
$store = Filesystem::getInstance(array('dir' => $this->_invalidPath));
ServerSalt::setStore($store);
$salt = ServerSalt::get();
ServerSalt::setStore($store);
@@ -105,9 +105,9 @@ class ServerSaltTest extends PHPUnit_Framework_TestCase
// try creating an invalid path
chmod($this->_invalidPath, 0000);
ServerSalt::setStore(
new Filesystem(array('dir' => $this->_invalidPath . DIRECTORY_SEPARATOR . 'baz'))
Filesystem::getInstance(array('dir' => $this->_invalidPath . DIRECTORY_SEPARATOR . 'baz'))
);
$store = new Filesystem(array('dir' => $this->_invalidPath));
$store = Filesystem::getInstance(array('dir' => $this->_invalidPath));
ServerSalt::setStore($store);
$salt = ServerSalt::get();
ServerSalt::setStore($store);

View File

@@ -12,7 +12,7 @@ class TrafficLimiterTest extends PHPUnit_Framework_TestCase
{
/* Setup Routine */
$this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'trafficlimit';
$store = new Filesystem(array('dir' => $this->_path));
$store = Filesystem::getInstance(array('dir' => $this->_path));
ServerSalt::setStore($store);
TrafficLimiter::setStore($store);
}

View File

@@ -18,7 +18,7 @@ class Vizhash16x16Test extends PHPUnit_Framework_TestCase
mkdir($this->_path);
}
$this->_file = $this->_path . DIRECTORY_SEPARATOR . 'vizhash.png';
ServerSalt::setStore(new Filesystem(array('dir' => $this->_path)));
ServerSalt::setStore(Filesystem::getInstance(array('dir' => $this->_path)));
}
public function tearDown()

View File

@@ -20,7 +20,7 @@ class YourlsProxyTest extends PHPUnit_Framework_TestCase
}
$this->_mock_yourls_service = $this->_path . DIRECTORY_SEPARATOR . 'yourls.json';
$options = parse_ini_file(CONF_SAMPLE, true);
$options['main']['basepath'] = 'https://example.com/';
$options['main']['basepath'] = 'https://example.com';
$options['main']['urlshortener'] = 'https://example.com/shortenviayourls?link=';
$options['yourls']['apiurl'] = $this->_mock_yourls_service;
Helper::confBackup();

View File

@@ -1,6 +1,7 @@
<phpunit bootstrap="Bootstrap.php" colors="true">
<testsuite name="PrivateBin Test Suite">
<directory suffix=".php">./</directory>
<exclude>ConfigurationTestGenerator.php</exclude>
</testsuite>
<filter>
<whitelist>

View File

@@ -37,57 +37,130 @@ namespace Composer\Autoload;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
/** @var ?string */
private $vendorDir;
// PSR-4
/**
* @var array[]
* @psalm-var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, array<int, string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* @var array[]
* @psalm-var array<string, array<string, string[]>>
*/
private $prefixesPsr0 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr0 = array();
/** @var bool */
private $useIncludePath = false;
/**
* @var string[]
* @psalm-var array<string, string>
*/
private $classMap = array();
/** @var bool */
private $classMapAuthoritative = false;
/**
* @var bool[]
* @psalm-var array<string, bool>
*/
private $missingClasses = array();
/** @var ?string */
private $apcuPrefix;
/**
* @var self[]
*/
private static $registeredLoaders = array();
/**
* @param ?string $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
}
/**
* @return string[]
*/
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $this->prefixesPsr0);
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
}
/**
* @return array[]
* @psalm-return array<string, array<int, string>>
*/
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
/**
* @return string[] Array of classname => path
* @psalm-return array<string, string>
*/
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
* @param string[] $classMap Class to filename map
* @psalm-param array<string, string> $classMap
*
* @return void
*/
public function addClassMap(array $classMap)
{
@@ -102,9 +175,11 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
@@ -147,11 +222,13 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
@@ -195,8 +272,10 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 base directories
*
* @return void
*/
public function set($prefix, $paths)
{
@@ -211,10 +290,12 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function setPsr4($prefix, $paths)
{
@@ -234,6 +315,8 @@ class ClassLoader
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*
* @return void
*/
public function setUseIncludePath($useIncludePath)
{
@@ -256,6 +339,8 @@ class ClassLoader
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*
* @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
@@ -276,6 +361,8 @@ class ClassLoader
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*
* @return void
*/
public function setApcuPrefix($apcuPrefix)
{
@@ -296,25 +383,44 @@ class ClassLoader
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
}
/**
* Unregisters this instance as an autoloader.
*
* @return void
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
@@ -323,6 +429,8 @@ class ClassLoader
return true;
}
return null;
}
/**
@@ -367,6 +475,21 @@ class ClassLoader
return $file;
}
/**
* Returns the currently registered loaders indexed by their corresponding vendor directories.
*
* @return self[]
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
@@ -438,6 +561,10 @@ class ClassLoader
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
* @private
*/
function includeFile($file)
{

View File

@@ -6,6 +6,7 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'IPLib\\Address\\AddressInterface' => $vendorDir . '/mlocati/ip-lib/src/Address/AddressInterface.php',
'IPLib\\Address\\AssignedRange' => $vendorDir . '/mlocati/ip-lib/src/Address/AssignedRange.php',
'IPLib\\Address\\IPv4' => $vendorDir . '/mlocati/ip-lib/src/Address/IPv4.php',
@@ -52,7 +53,6 @@ return array(
'Jdenticon\\Rendering\\ColorTheme' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/ColorTheme.php',
'Jdenticon\\Rendering\\IconGenerator' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/IconGenerator.php',
'Jdenticon\\Rendering\\ImagickRenderer' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php',
'Jdenticon\\Rendering\\ImagickRendererLine' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php',
'Jdenticon\\Rendering\\InternalPngRenderer' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/InternalPngRenderer.php',
'Jdenticon\\Rendering\\Point' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/Point.php',
'Jdenticon\\Rendering\\Rectangle' => $vendorDir . '/jdenticon/jdenticon/src/Rendering/Rectangle.php',

View File

@@ -13,19 +13,24 @@ class ComposerAutoloaderInitDontChange
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInitDontChange', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInitDontChange', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitDontChange::getInitializer($loader));
} else {
@@ -60,11 +65,16 @@ class ComposerAutoloaderInitDontChange
}
}
/**
* @param string $fileIdentifier
* @param string $file
* @return void
*/
function composerRequireDontChange($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
require $file;
}
}

View File

@@ -46,6 +46,7 @@ class ComposerStaticInitDontChange
);
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'IPLib\\Address\\AddressInterface' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/AddressInterface.php',
'IPLib\\Address\\AssignedRange' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/AssignedRange.php',
'IPLib\\Address\\IPv4' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Address/IPv4.php',
@@ -92,7 +93,6 @@ class ComposerStaticInitDontChange
'Jdenticon\\Rendering\\ColorTheme' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/ColorTheme.php',
'Jdenticon\\Rendering\\IconGenerator' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/IconGenerator.php',
'Jdenticon\\Rendering\\ImagickRenderer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php',
'Jdenticon\\Rendering\\ImagickRendererLine' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/ImagickRenderer.php',
'Jdenticon\\Rendering\\InternalPngRenderer' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/InternalPngRenderer.php',
'Jdenticon\\Rendering\\Point' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/Point.php',
'Jdenticon\\Rendering\\Rectangle' => __DIR__ . '/..' . '/jdenticon/jdenticon/src/Rendering/Rectangle.php',

View File

@@ -21,15 +21,6 @@ class SuperSampleBuffer
const IDX_G = 3;
const IDX_B = 4;
private $samples;
private $samplesPerPixel;
private $pixelOffset;
private $subPixelOffset;
private $width;
private $used;
/**
* Creates a color buffer keeping an average color out of several
* color samples per pixel.