Skip to content
Snippets Groups Projects
Unverified Commit 5c43ab6e authored by El RIDO's avatar El RIDO
Browse files

refactor administrative script into OOP style and to our code guidelines

parent c00b9501
No related branches found
No related tags found
No related merge requests found
# PrivateBin version history # PrivateBin version history
* **1.5.1 (not yet released)** * **1.5.1 (not yet released)**
* ADDED: script for administrative tasks: deleting pastes (#274), removing empty directories (#277), purging expired pastes (#276) & statistics (#319)
* FIXED: Revert Filesystem purge to limited and randomized lookup (#1030) * FIXED: Revert Filesystem purge to limited and randomized lookup (#1030)
* FIXED: Catch JSON decode errors when invalid data gets sent to the API (#1030) * FIXED: Catch JSON decode errors when invalid data gets sent to the API (#1030)
* FIXED: Support sorting v1 format in mixed version comments in Filesystem backend (#1030) * FIXED: Support sorting v1 format in mixed version comments in Filesystem backend (#1030)
* **1.5 (2022-12-11)** * **1.5 (2022-12-11)**
* ADDED: script for data storage backend migrations (#1012) * ADDED: script for data storage backend migrations (#1012)
* ADDED: script for administrative tasks: deleting pastes (#274), removing empty directories (#277), purging expired pastes (#276) & statistics (#319)
* ADDED: Translations for Turkish, Slovak, Greek and Thai * ADDED: Translations for Turkish, Slovak, Greek and Thai
* ADDED: S3 Storage backend (#994) * ADDED: S3 Storage backend (#994)
* ADDED: Jdenticons as an option for comment icons (#793) * ADDED: Jdenticons as an option for comment icons (#793)
......
#!/usr/bin/env php #!/usr/bin/env php
<?php <?php
define('PATH', dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR); /**
require PATH . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php'; * PrivateBin
*
* a zero-knowledge paste bin
*
* @link https://github.com/PrivateBin/PrivateBin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 1.5.0
*/
namespace PrivateBin;
use PrivateBin\Configuration; use PrivateBin\Configuration;
use PrivateBin\Data\AbstractData;
use PrivateBin\Model\Paste; use PrivateBin\Model\Paste;
$options = array(); define('PATH', dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR);
require PATH . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
function error($message, $code = 1) {
error_echo($message);
exit($code);
}
function error_echo($message) { /**
fwrite(STDERR, 'Error: ' . $message . PHP_EOL); * Administration
} *
* Command line utility for administrative tasks.
*/
class Administration
{
/**
* configuration
*
* @access private
* @var Configuration
*/
private $_conf;
function help($code = 0) { /**
echo <<<'EOT' * options, parsed from the command line arguments
Usage: *
privatebin-admin [--delete <paste id> | --empty-dirs | --help | --statistics] * @access private
* @var array
*/
private $_opts = array();
Options: /**
-d, --delete deletes the requested paste ID * data storage model
-e, --empty-dirs removes empty directories (only if Filesystem storage is *
configured) * @access private
-h, --help displays this help message * @var AbstractData
-s, --statistics reads all stored pastes and comments and reports statistics */
EOT, PHP_EOL; private $_store;
exit($code);
}
function option($short, $long) { /**
global $options; * deletes the requested paste ID, if a valid ID and it exists
$option = null; *
foreach (array($short, $long) as $key) { * @access private
if (array_key_exists($key, $options)) { * @param string $pasteId
$option = $options[$key]; */
private function _delete($pasteId)
{
if (!Paste::isValidId($pasteId)) {
self::_error('given ID is not a valid paste ID (16 hexadecimal digits)', 5);
} }
} if (!$this->_store->exists($pasteId)) {
return $option; self::_error('given ID does not exist, has expired or was already deleted', 6);
} }
$this->_store->delete($pasteId);
function main() { if ($this->_store->exists($pasteId)) {
if ($_SERVER['argc'] > 3) { self::_error('paste ID exists after deletion, permission problem?', 7);
error_echo('too many arguments given'); }
fwrite(STDERR, PHP_EOL); exit("paste $pasteId successfully deleted" . PHP_EOL);
help(1);
} }
if ($_SERVER['argc'] < 2) { /**
error_echo('missing arguments'); * removes empty directories, if current storage model uses Filesystem
fwrite(STDERR, PHP_EOL); *
help(2); * @access private
*/
private function _empty_dirs()
{
if ($this->_conf->getKey('class', 'model') !== 'Filesystem') {
self::_error('instance not using Filesystem storage, no directories to empty', 4);
}
$dir = $this->_conf->getKey('dir', 'model_options');
passthru("find $dir -type d -empty -delete", $code);
exit($code);
} }
global $options; /**
$options = getopt('hd:eps', array('help', 'delete:', 'empty-dirs', 'purge', 'statistics')); * display a message on STDERR and exits
if (!$options) { *
error_echo('unsupported arguments given'); * @access private
fwrite(STDERR, PHP_EOL); * @static
help(3); * @param string $message
* @param int $code optional, defaults to 1
*/
private static function _error($message, $code = 1)
{
self::_error_echo($message);
exit($code);
} }
if (option('h', 'help') !== null) { /**
help(); * display a message on STDERR
*
* @access private
* @static
* @param string $message
*/
private static function _error_echo($message)
{
fwrite(STDERR, 'Error: ' . $message . PHP_EOL);
} }
$conf = new Configuration; /**
* display usage help on STDOUT and exits
*
* @access private
* @static
* @param int $code optional, defaults to 0
*/
private static function _help($code = 0)
{
echo <<<'EOT'
Usage:
administration [--delete <paste id> | --empty-dirs | --help | --statistics]
if (option('e', 'empty-dirs') !== null) { Options:
if ($conf->getKey('class', 'model') !== 'Filesystem') { -d, --delete deletes the requested paste ID
error('instance not using Filesystem storage, no directories to empty', 4); -e, --empty-dirs removes empty directories (only if Filesystem storage is
} configured)
$dir = $conf->getKey('dir', 'model_options'); -h, --help displays this help message
passthru("find $dir -type d -empty -delete", $code); -s, --statistics reads all stored pastes and comments and reports statistics
EOT, PHP_EOL;
exit($code); exit($code);
} }
$class = 'PrivateBin\\Data\\' . $conf->getKey('class', 'model'); /**
$store = new $class($conf->getSection('model_options')); * return option for given short or long keyname, if it got set
*
if (($pasteid = option('d', 'delete')) !== null) { * @access private
if (!Paste::isValidId($pasteid)) { * @static
error('given ID is not a valid paste ID (16 hexadecimal digits)', 5); * @param string $short
* @param string $long
* @return string|null
*/
private function _option($short, $long)
{
foreach (array($short, $long) as $key) {
if (array_key_exists($key, $this->_opts)) {
return $this->_opts[$key];
}
} }
if (!$store->exists($pasteid)) { return null;
error('given ID does not exist, has expired or was already deleted', 6); }
/**
* initialize options from given argument array
*
* @access private
* @static
* @param array $arguments
*/
private function _options_initialize($arguments)
{
if ($arguments > 3) {
self::_error_echo('too many arguments given');
echo PHP_EOL;
self::_help(1);
} }
$store->delete($pasteid);
if ($store->exists($pasteid)) { if ($arguments < 2) {
error('paste ID exists after deletion, permission problem?', 7); self::_error_echo('missing arguments');
echo PHP_EOL;
self::_help(2);
} }
exit("paste $pasteid successfully deleted" . PHP_EOL);
}
if (option('p', 'purge') !== null) { $this->_opts = getopt('hd:eps', array('help', 'delete:', 'empty-dirs', 'purge', 'statistics'));
$store->purge(PHP_INT_MAX); if (!$this->_opts) {
exit('purging of expired pastes concluded' . PHP_EOL); self::_error_echo('unsupported arguments given');
echo PHP_EOL;
self::_help(3);
}
} }
if (option('s', 'statistics') !== null) { /**
* reads all stored pastes and comments and reports statistics
*
* @access public
*/
private function _statistics()
{
$counters = array( $counters = array(
'burn' => 0, 'burn' => 0,
'discussion' => 0, 'discussion' => 0,
...@@ -116,7 +205,7 @@ function main() { ...@@ -116,7 +205,7 @@ function main() {
'unknown' => 0, 'unknown' => 0,
); );
$time = time(); $time = time();
$ids = $store->getAllPastes(); $ids = $this->_store->getAllPastes();
$counters['total'] = count($ids); $counters['total'] = count($ids);
$dots = $counters['total'] < 100 ? 10 : ( $dots = $counters['total'] < 100 ? 10 : (
$counters['total'] < 1000 ? 50 : 100 $counters['total'] < 1000 ? 50 : 100
...@@ -124,16 +213,19 @@ function main() { ...@@ -124,16 +213,19 @@ function main() {
$percentages = $counters['total'] < 100 ? 0 : ( $percentages = $counters['total'] < 100 ? 0 : (
$counters['total'] < 1000 ? 4 : 10 $counters['total'] < 1000 ? 4 : 10
); );
echo "Total:\t\t\t${counters['total']}", PHP_EOL; echo "Total:\t\t\t${counters['total']}", PHP_EOL;
foreach ($ids as $pasteid) { foreach ($ids as $pasteid) {
$paste = $store->read($pasteid); $paste = $this->_store->read($pasteid);
++$counters['progress']; ++$counters['progress'];
if ( if (
array_key_exists('expire_date', $paste['meta']) && array_key_exists('expire_date', $paste['meta']) &&
$paste['meta']['expire_date'] < $time $paste['meta']['expire_date'] < $time
) { ) {
++$counters['expired']; ++$counters['expired'];
} }
if (array_key_exists('adata', $paste)) { if (array_key_exists('adata', $paste)) {
$format = $paste['adata'][1]; $format = $paste['adata'][1];
$discussion = $paste['adata'][2]; $discussion = $paste['adata'][2];
...@@ -143,6 +235,7 @@ function main() { ...@@ -143,6 +235,7 @@ function main() {
$discussion = array_key_exists('opendiscussion', $paste['meta']) ? $paste['meta']['opendiscussion'] : false; $discussion = array_key_exists('opendiscussion', $paste['meta']) ? $paste['meta']['opendiscussion'] : false;
$burn = array_key_exists('burnafterreading', $paste['meta']) ? $paste['meta']['burnafterreading'] : false; $burn = array_key_exists('burnafterreading', $paste['meta']) ? $paste['meta']['burnafterreading'] : false;
} }
if ($format === 'plaintext') { if ($format === 'plaintext') {
++$counters['plain']; ++$counters['plain'];
} elseif ($format === 'syntaxhighlighting') { } elseif ($format === 'syntaxhighlighting') {
...@@ -152,6 +245,7 @@ function main() { ...@@ -152,6 +245,7 @@ function main() {
} else { } else {
++$counters['unknown']; ++$counters['unknown'];
} }
$counters['discussion'] += (int) $discussion; $counters['discussion'] += (int) $discussion;
$counters['burn'] += (int) $burn; $counters['burn'] += (int) $burn;
...@@ -167,6 +261,7 @@ function main() { ...@@ -167,6 +261,7 @@ function main() {
} }
} }
} }
echo PHP_EOL, <<<EOT echo PHP_EOL, <<<EOT
Expired:\t\t${counters['expired']} Expired:\t\t${counters['expired']}
Burn after reading:\t${counters['burn']} Burn after reading:\t${counters['burn']}
...@@ -179,6 +274,44 @@ EOT, PHP_EOL; ...@@ -179,6 +274,44 @@ EOT, PHP_EOL;
echo "Unknown format:\t\t${counters['unknown']}", PHP_EOL; echo "Unknown format:\t\t${counters['unknown']}", PHP_EOL;
} }
} }
/**
* constructor
*
* initializes and runs administrative tasks
*
* @access public
*/
public function __construct()
{
$this->_options_initialize($_SERVER['argc']);
if ($this->_option('h', 'help') !== null) {
self::_help();
}
$this->_conf = new Configuration;
if ($this->_option('e', 'empty-dirs') !== null) {
$this->_empty_dirs();
}
$class = 'PrivateBin\\Data\\' . $this->_conf->getKey('class', 'model');
$this->_store = new $class($this->_conf->getSection('model_options'));
if (($pasteId = $this->_option('d', 'delete')) !== null) {
$this->_delete($pasteId);
}
if ($this->_option('p', 'purge') !== null) {
$this->_store->purge(PHP_INT_MAX);
exit('purging of expired pastes concluded' . PHP_EOL);
}
if ($this->_option('s', 'statistics') !== null) {
$this->_statistics();
}
}
} }
main(); new Administration();
\ No newline at end of file \ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment