implemented zerobin_db model, added more options for paste expiration, made comments and max data size configurable
This commit is contained in:
parent
7cee995cd7
commit
421e6cba97
7 changed files with 432 additions and 49 deletions
96
DOCUMENTATION.md
Normal file
96
DOCUMENTATION.md
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
Documentation
|
||||||
|
=============
|
||||||
|
|
||||||
|
For Administrators
|
||||||
|
------------------
|
||||||
|
|
||||||
|
In the index.php in the main folder you can define a different PATH. This is
|
||||||
|
useful if you want to secure your installation and want to move the
|
||||||
|
configuration, data files, templates and PHP libraries (directories cfg, lib
|
||||||
|
and tpl) outside of your document root. This new location must still be
|
||||||
|
accessible to your webserver / PHP process.
|
||||||
|
|
||||||
|
> ### PATH Example ###
|
||||||
|
> Your zerobin installation lives in a subfolder called "paste" inside of your
|
||||||
|
> document root. The URL looks like this:
|
||||||
|
> http://example.com/paste/
|
||||||
|
> The ZeroBin folder on your webserver is really:
|
||||||
|
> /home/example.com/htdocs/paste
|
||||||
|
>
|
||||||
|
> When setting the path like this:
|
||||||
|
> define('PATH', '../../secret/zerobin/');
|
||||||
|
> ZeroBin will look for your includes here:
|
||||||
|
> /home/example.com/secret/zerobin
|
||||||
|
|
||||||
|
In the file "cfg/conf.ini" you can configure ZeroBin. The config file is
|
||||||
|
divided into multiple sections, which are enclosed in square brackets. In the
|
||||||
|
"[main]" section you can enable or disable the discussion feature, set the
|
||||||
|
limit of stored pastes and comments in bytes. The "[traffic]" section lets you
|
||||||
|
set a time limit in seconds. Users may not post more often the this limit to
|
||||||
|
your ZeroBin.
|
||||||
|
|
||||||
|
Finally the "[model]" and "[model_options]" sections let you configure your
|
||||||
|
favourite way of storing the pastes and discussions on your server.
|
||||||
|
"zerobin_data" is the default model, which stores everything in files in the
|
||||||
|
data folder. This is the recommended setup for low traffic sites. Under high
|
||||||
|
load, in distributed setups or if you are not allowed to store files locally,
|
||||||
|
you might want to switch to the "zerobin_db" model. This lets you store your
|
||||||
|
data in a database. Basically all databases, that are supported by PDO (PHP
|
||||||
|
data objects) may be used. Automatic table creation is provided for pdo_ibm,
|
||||||
|
pdo_informix, pdo_mssql, pdo_mysql, pdo_oci, pdo_pgsql and pdo_sqlite. You may
|
||||||
|
want to provide a table prefix, if you have to share the zerobin database with
|
||||||
|
another application. The table prefix option is called "tbl".
|
||||||
|
|
||||||
|
> ### Note ###
|
||||||
|
> The "zerobin_db" model has only been tested with sqlite and MySQL, although
|
||||||
|
> it would not be recommended to use sqlite in a production environment. If you
|
||||||
|
> gain any experience running ZeroBin on other RDBMS, let us know.
|
||||||
|
|
||||||
|
For reference or if you want to create the table schema for yourself:
|
||||||
|
|
||||||
|
CREATE TABLE prefix_paste (
|
||||||
|
dataid CHAR(16),
|
||||||
|
data TEXT,
|
||||||
|
postdate INT,
|
||||||
|
expiredate INT,
|
||||||
|
opendiscussion INT,
|
||||||
|
burnafterreading INT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE prefix_comment (
|
||||||
|
dataid CHAR(16),
|
||||||
|
pasteid CHAR(16),
|
||||||
|
parentid CHAR(16),
|
||||||
|
data TEXT,
|
||||||
|
nickname VARCHAR(255),
|
||||||
|
vizhash TEXT,
|
||||||
|
postdate INT
|
||||||
|
);
|
||||||
|
|
||||||
|
For Developers
|
||||||
|
--------------
|
||||||
|
If you want to create your own data models, you might want to know how the arrays, that you have to store, look like:
|
||||||
|
|
||||||
|
public function create($pasteid, $paste)
|
||||||
|
{
|
||||||
|
$pasteid = substr(hash('md5', $paste['data']), 0, 16);
|
||||||
|
|
||||||
|
$paste['data'] // text
|
||||||
|
$paste['meta']['postdate'] // int UNIX timestamp
|
||||||
|
$paste['meta']['expire_date'] // int UNIX timestamp
|
||||||
|
$paste['meta']['opendiscussion'] // true (if false it is unset)
|
||||||
|
$paste['meta']['burnafterreading'] // true (if false it is unset; if true, then opendiscussion is unset)
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createComment($pasteid, $parentid, $commentid, $comment)
|
||||||
|
{
|
||||||
|
$pasteid // the id of the paste this comment belongs to
|
||||||
|
$parentid // the id of the parent of this comment, may be the paste id itself
|
||||||
|
$commentid = substr(hash('md5', $paste['data']), 0, 16);
|
||||||
|
|
||||||
|
$paste['data'] // text
|
||||||
|
$paste['meta']['nickname'] // text or null (if anonymous)
|
||||||
|
$paste['meta']['vizhash'] // text or null (if anonymous)
|
||||||
|
$paste['meta']['postdate'] // int UNIX timestamp
|
||||||
|
}
|
||||||
|
|
45
cfg/conf.ini
45
cfg/conf.ini
|
@ -7,28 +7,41 @@
|
||||||
; @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
|
; @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
|
||||||
; @version 0.15
|
; @version 0.15
|
||||||
|
|
||||||
; time limit between calls from the same IP address in seconds
|
[main]
|
||||||
traffic_limit = 10
|
; enable or disable discussions
|
||||||
traffic_dir = PATH "data"
|
opendiscussion = true
|
||||||
|
|
||||||
; size limit per paste or comment in bytes
|
; size limit per paste or comment in bytes
|
||||||
size_limit = 2000000
|
sizelimit = 2097152
|
||||||
|
|
||||||
|
[traffic]
|
||||||
|
; time limit between calls from the same IP address in seconds
|
||||||
|
limit = 10
|
||||||
|
dir = PATH "data"
|
||||||
|
|
||||||
|
[model]
|
||||||
; name of data model class to load and directory for storage
|
; name of data model class to load and directory for storage
|
||||||
; the default model "zerobin_data" stores everything in the filesystem
|
; the default model "zerobin_data" stores everything in the filesystem
|
||||||
model = zerobin_data
|
class = zerobin_data
|
||||||
model_options["dir"] = PATH "data"
|
[model_options]
|
||||||
|
dir = PATH "data"
|
||||||
|
|
||||||
|
;[model]
|
||||||
; example of DB configuration for MySQL
|
; example of DB configuration for MySQL
|
||||||
;model = zerobin_db
|
;class = zerobin_db
|
||||||
;model_options["dsn"] = "mysql:host=localhost;dbname=zerobin"
|
;[model_options]
|
||||||
;model_options["usr"] = "zerobin"
|
;dsn = "mysql:host=localhost;dbname=zerobin;charset=UTF8"
|
||||||
;model_options["pwd"] = "Z3r0P4ss"
|
;tbl = "zerobin_" ; table prefix
|
||||||
;model_options["opt"][PDO::ATTR_PERSISTENT] = true
|
;usr = "zerobin"
|
||||||
|
;pwd = "Z3r0P4ss"
|
||||||
|
;opt[12] = true ; PDO::ATTR_PERSISTENT
|
||||||
|
|
||||||
|
;[model]
|
||||||
; example of DB configuration for SQLite
|
; example of DB configuration for SQLite
|
||||||
;model = zerobin_db
|
;[model_options]
|
||||||
;model_options["dsn"] = "sqlite:" PATH "data"/db.sq3"
|
;class = zerobin_db
|
||||||
;model_options["usr"] = null
|
;dsn = "sqlite:" PATH "data/db.sq3"
|
||||||
;model_options["pwd"] = null
|
;usr = null
|
||||||
;model_options["opt"] = null
|
;pwd = null
|
||||||
|
;opt[12] = true ; PDO::ATTR_PERSISTENT
|
||||||
|
|
||||||
|
|
|
@ -103,8 +103,8 @@ class zerobin
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->_conf = parse_ini_file(PATH . 'cfg/conf.ini');
|
$this->_conf = parse_ini_file(PATH . 'cfg/conf.ini', true);
|
||||||
$this->_model = $this->_conf['model'];
|
$this->_model = $this->_conf['model']['class'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -117,7 +117,10 @@ class zerobin
|
||||||
{
|
{
|
||||||
// if needed, initialize the model
|
// if needed, initialize the model
|
||||||
if(is_string($this->_model)) {
|
if(is_string($this->_model)) {
|
||||||
$this->_model = forward_static_call(array($this->_model, 'getInstance'), $this->_conf['model_options']);
|
$this->_model = forward_static_call(
|
||||||
|
array($this->_model, 'getInstance'),
|
||||||
|
$this->_conf['model_options']
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return $this->_model;
|
return $this->_model;
|
||||||
}
|
}
|
||||||
|
@ -129,7 +132,7 @@ class zerobin
|
||||||
* data (mandatory) = json encoded SJCL encrypted text (containing keys: iv,salt,ct)
|
* data (mandatory) = json encoded SJCL encrypted text (containing keys: iv,salt,ct)
|
||||||
*
|
*
|
||||||
* All optional data will go to meta information:
|
* All optional data will go to meta information:
|
||||||
* expire (optional) = expiration delay (never,10min,1hour,1day,1month,1year,burn) (default:never)
|
* expire (optional) = expiration delay (never,5min,10min,1hour,1day,1week,1month,1year,burn) (default:never)
|
||||||
* opendiscusssion (optional) = is the discussion allowed on this paste ? (0/1) (default:0)
|
* opendiscusssion (optional) = is the discussion allowed on this paste ? (0/1) (default:0)
|
||||||
* nickname (optional) = in discussion, encoded SJCL encrypted text nickname of author of comment (containing keys: iv,salt,ct)
|
* nickname (optional) = in discussion, encoded SJCL encrypted text nickname of author of comment (containing keys: iv,salt,ct)
|
||||||
* parentid (optional) = in discussion, which comment this comment replies to.
|
* parentid (optional) = in discussion, which comment this comment replies to.
|
||||||
|
@ -143,18 +146,30 @@ class zerobin
|
||||||
header('Content-type: application/json');
|
header('Content-type: application/json');
|
||||||
$error = false;
|
$error = false;
|
||||||
|
|
||||||
// Make sure last paste from the IP address was more than 10 seconds ago.
|
// Make sure last paste from the IP address was more than X seconds ago.
|
||||||
trafficlimiter::setLimit($this->_conf['traffic_limit']);
|
trafficlimiter::setLimit($this->_conf['traffic']['limit']);
|
||||||
trafficlimiter::setPath($this->_conf['traffic_dir']);
|
trafficlimiter::setPath($this->_conf['traffic']['dir']);
|
||||||
if (
|
if (
|
||||||
!trafficlimiter::canPass($_SERVER['REMOTE_ADDR'])
|
!trafficlimiter::canPass($_SERVER['REMOTE_ADDR'])
|
||||||
) $this->_return_message(1, 'Please wait 10 seconds between each post.');
|
) $this->_return_message(
|
||||||
|
1,
|
||||||
|
'Please wait ' .
|
||||||
|
$this->_conf['traffic']['limit'] .
|
||||||
|
' seconds between each post.'
|
||||||
|
);
|
||||||
|
|
||||||
// Make sure content is not too big.
|
// Make sure content is not too big.
|
||||||
$data = $_POST['data'];
|
$data = $_POST['data'];
|
||||||
if (
|
if (
|
||||||
strlen($data) > 2000000
|
strlen($data) > $this->_conf['main']['sizelimit']
|
||||||
) $this->_return_message(1, 'Paste is limited to 2 MB of encrypted data.');
|
) $this->_return_message(
|
||||||
|
1,
|
||||||
|
'Paste is limited to ' .
|
||||||
|
$this->_conf['main']['sizelimit'] .
|
||||||
|
' ' .
|
||||||
|
filter::size_humanreadable($this->_conf['main']['sizelimit']) .
|
||||||
|
' of encrypted data.'
|
||||||
|
);
|
||||||
|
|
||||||
// Make sure format is correct.
|
// Make sure format is correct.
|
||||||
if (!sjcl::isValid($data)) $this->_return_message(1, 'Invalid data.');
|
if (!sjcl::isValid($data)) $this->_return_message(1, 'Invalid data.');
|
||||||
|
@ -167,6 +182,12 @@ class zerobin
|
||||||
{
|
{
|
||||||
switch ($_POST['expire'])
|
switch ($_POST['expire'])
|
||||||
{
|
{
|
||||||
|
case 'burn':
|
||||||
|
$meta['burnafterreading'] = true;
|
||||||
|
break;
|
||||||
|
case '5min':
|
||||||
|
$meta['expire_date'] = time()+5*60;
|
||||||
|
break;
|
||||||
case '10min':
|
case '10min':
|
||||||
$meta['expire_date'] = time()+10*60;
|
$meta['expire_date'] = time()+10*60;
|
||||||
break;
|
break;
|
||||||
|
@ -176,19 +197,19 @@ class zerobin
|
||||||
case '1day':
|
case '1day':
|
||||||
$meta['expire_date'] = time()+24*60*60;
|
$meta['expire_date'] = time()+24*60*60;
|
||||||
break;
|
break;
|
||||||
|
case '1week':
|
||||||
|
$meta['expire_date'] = time()+7*24*60*60;
|
||||||
|
break;
|
||||||
case '1month':
|
case '1month':
|
||||||
$meta['expire_date'] = strtotime('+1 month');
|
$meta['expire_date'] = strtotime('+1 month');
|
||||||
break;
|
break;
|
||||||
case '1year':
|
case '1year':
|
||||||
$meta['expire_date'] = strtotime('+1 year');
|
$meta['expire_date'] = strtotime('+1 year');
|
||||||
break;
|
|
||||||
case 'burn':
|
|
||||||
$meta['burnafterreading'] = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read open discussion flag.
|
// Read open discussion flag.
|
||||||
if (!empty($_POST['opendiscussion']))
|
if ($this->_conf['main']['opendiscussion'] && !empty($_POST['opendiscussion']))
|
||||||
{
|
{
|
||||||
$opendiscussion = $_POST['opendiscussion'];
|
$opendiscussion = $_POST['opendiscussion'];
|
||||||
if ($opendiscussion != 0)
|
if ($opendiscussion != 0)
|
||||||
|
@ -381,6 +402,7 @@ class zerobin
|
||||||
// We escape it here because ENT_NOQUOTES can't be used in RainTPL templates.
|
// We escape it here because ENT_NOQUOTES can't be used in RainTPL templates.
|
||||||
$page->assign('CIPHERDATA', htmlspecialchars($this->_data, ENT_NOQUOTES));
|
$page->assign('CIPHERDATA', htmlspecialchars($this->_data, ENT_NOQUOTES));
|
||||||
$page->assign('ERRORMESSAGE', $this->_error);
|
$page->assign('ERRORMESSAGE', $this->_error);
|
||||||
|
$page->assign('OPENDISCUSSION', $this->_conf['main']['opendiscussion']);
|
||||||
$page->assign('VERSION', self::VERSION);
|
$page->assign('VERSION', self::VERSION);
|
||||||
$page->draw('page');
|
$page->draw('page');
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ abstract class zerobin_abstract
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @static
|
* @static
|
||||||
* @return zerobin
|
* @return zerobin_abstract
|
||||||
*/
|
*/
|
||||||
abstract public static function getInstance($options);
|
abstract public static function getInstance($options);
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,9 @@ class zerobin_data extends zerobin_abstract
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @static
|
* @static
|
||||||
* @return zerobin
|
* @return zerobin_data
|
||||||
*/
|
*/
|
||||||
public static function getInstance($options)
|
public static function getInstance($options = null)
|
||||||
{
|
{
|
||||||
// if given update the data directory
|
// if given update the data directory
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -17,6 +17,13 @@
|
||||||
*/
|
*/
|
||||||
class zerobin_db extends zerobin_abstract
|
class zerobin_db extends zerobin_abstract
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* @access private
|
||||||
|
* @static
|
||||||
|
* @var array to cache select queries
|
||||||
|
*/
|
||||||
|
private static $_cache = array();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @access private
|
* @access private
|
||||||
* @static
|
* @static
|
||||||
|
@ -24,31 +31,137 @@ class zerobin_db extends zerobin_abstract
|
||||||
*/
|
*/
|
||||||
private static $_db;
|
private static $_db;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @access private
|
||||||
|
* @static
|
||||||
|
* @var string table prefix
|
||||||
|
*/
|
||||||
|
private static $_prefix = '';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @access private
|
||||||
|
* @static
|
||||||
|
* @var string database type
|
||||||
|
*/
|
||||||
|
private static $_type = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get instance of singleton
|
* get instance of singleton
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @static
|
* @static
|
||||||
* @return zerobin
|
* @throws Exception
|
||||||
|
* @return zerobin_db
|
||||||
*/
|
*/
|
||||||
public static function getInstance($options)
|
public static function getInstance($options = null)
|
||||||
{
|
{
|
||||||
// if needed initialize the singleton
|
// if needed initialize the singleton
|
||||||
if(null === self::$_instance) {
|
if(null === self::$_instance) {
|
||||||
parent::$_instance = new self;
|
parent::$_instance = new self;
|
||||||
}
|
}
|
||||||
if (
|
|
||||||
is_array($options) &&
|
if (is_array($options))
|
||||||
array_key_exists('dsn', $options) &&
|
{
|
||||||
array_key_exists('usr', $options) &&
|
// set table prefix if given
|
||||||
array_key_exists('pwd', $options) &&
|
if (array_key_exists('tbl', $options)) self::$_prefix = $options['tbl'];
|
||||||
array_key_exists('opt', $options)
|
|
||||||
) self::$_db = new PDO(
|
// initialize the db connection with new options
|
||||||
$options['dsn'],
|
if (
|
||||||
$options['usr'],
|
array_key_exists('dsn', $options) &&
|
||||||
$options['pwd'],
|
array_key_exists('usr', $options) &&
|
||||||
$options['opt']
|
array_key_exists('pwd', $options) &&
|
||||||
);
|
array_key_exists('opt', $options)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
self::$_db = new PDO(
|
||||||
|
$options['dsn'],
|
||||||
|
$options['usr'],
|
||||||
|
$options['pwd'],
|
||||||
|
$options['opt']
|
||||||
|
);
|
||||||
|
|
||||||
|
// check if the database contains the required tables
|
||||||
|
self::$_type = strtolower(
|
||||||
|
substr($options['dsn'], 0, strpos($options['dsn'], ':'))
|
||||||
|
);
|
||||||
|
switch(self::$_type)
|
||||||
|
{
|
||||||
|
case 'ibm':
|
||||||
|
$sql = 'SELECT tabname FROM SYSCAT.TABLES ';
|
||||||
|
break;
|
||||||
|
case 'informix':
|
||||||
|
$sql = 'SELECT tabname FROM systables ';
|
||||||
|
break;
|
||||||
|
case 'mssql':
|
||||||
|
$sql = "SELECT name FROM sysobjects "
|
||||||
|
. "WHERE type = 'U' ORDER BY name";
|
||||||
|
break;
|
||||||
|
case 'mysql':
|
||||||
|
$sql = 'SHOW TABLES';
|
||||||
|
break;
|
||||||
|
case 'oci':
|
||||||
|
$sql = 'SELECT table_name FROM all_tables';
|
||||||
|
break;
|
||||||
|
case 'pgsql':
|
||||||
|
$sql = "SELECT c.relname AS table_name "
|
||||||
|
. "FROM pg_class c, pg_user u "
|
||||||
|
. "WHERE c.relowner = u.usesysid AND c.relkind = 'r' "
|
||||||
|
. "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) "
|
||||||
|
. "AND c.relname !~ '^(pg_|sql_)' "
|
||||||
|
. "UNION "
|
||||||
|
. "SELECT c.relname AS table_name "
|
||||||
|
. "FROM pg_class c "
|
||||||
|
. "WHERE c.relkind = 'r' "
|
||||||
|
. "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) "
|
||||||
|
. "AND NOT EXISTS (SELECT 1 FROM pg_user WHERE usesysid = c.relowner) "
|
||||||
|
. "AND c.relname !~ '^pg_'";
|
||||||
|
break;
|
||||||
|
case 'sqlite':
|
||||||
|
$sql = "SELECT name FROM sqlite_master WHERE type='table' "
|
||||||
|
. "UNION ALL SELECT name FROM sqlite_temp_master "
|
||||||
|
. "WHERE type='table' ORDER BY name";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception(
|
||||||
|
'PDO type ' .
|
||||||
|
self::$_type .
|
||||||
|
' is currently not supported.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$statement = self::$_db->query($sql);
|
||||||
|
$tables = $statement->fetchAll(PDO::FETCH_COLUMN, 0);
|
||||||
|
|
||||||
|
// create paste table if needed
|
||||||
|
if (!array_key_exists(self::$_prefix . 'paste', $tables))
|
||||||
|
{
|
||||||
|
self::$_db->exec(
|
||||||
|
'CREATE TABLE ' . self::$_prefix . 'paste ( ' .
|
||||||
|
'dataid CHAR(16), ' .
|
||||||
|
'data TEXT, ' .
|
||||||
|
'postdate INT, ' .
|
||||||
|
'expiredate INT, ' .
|
||||||
|
'opendiscussion INT, ' .
|
||||||
|
'burnafterreading INT );'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create comment table if needed
|
||||||
|
if (!array_key_exists(self::$_prefix . 'comment', $tables))
|
||||||
|
{
|
||||||
|
self::$_db->exec(
|
||||||
|
'CREATE TABLE ' . self::$_prefix . 'comment ( ' .
|
||||||
|
'dataid CHAR(16), ' .
|
||||||
|
'pasteid CHAR(16), ' .
|
||||||
|
'parentid CHAR(16), ' .
|
||||||
|
'data TEXT, ' .
|
||||||
|
'nickname VARCHAR(255), ' .
|
||||||
|
'vizhash TEXT, ' .
|
||||||
|
'postdate INT );'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return parent::$_instance;
|
return parent::$_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,10 +171,27 @@ class zerobin_db extends zerobin_abstract
|
||||||
* @access public
|
* @access public
|
||||||
* @param string $pasteid
|
* @param string $pasteid
|
||||||
* @param array $paste
|
* @param array $paste
|
||||||
* @return int|false
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function create($pasteid, $paste)
|
public function create($pasteid, $paste)
|
||||||
{
|
{
|
||||||
|
if (
|
||||||
|
!array_key_exists('opendiscussion', $paste['meta'])
|
||||||
|
) $paste['meta']['opendiscussion'] = false;
|
||||||
|
if (
|
||||||
|
!array_key_exists('burnafterreading', $paste['meta'])
|
||||||
|
) $paste['meta']['burnafterreading'] = false;
|
||||||
|
return self::_exec(
|
||||||
|
'INSERT INTO ' . self::$_prefix . 'paste VALUES(?,?,?,?,?,?)',
|
||||||
|
array(
|
||||||
|
$pasteid,
|
||||||
|
$paste['data'],
|
||||||
|
$paste['meta']['postdate'],
|
||||||
|
$paste['meta']['expire_date'],
|
||||||
|
(int) $paste['meta']['opendiscussion'],
|
||||||
|
(int) $paste['meta']['burnafterreading'],
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,6 +203,27 @@ class zerobin_db extends zerobin_abstract
|
||||||
*/
|
*/
|
||||||
public function read($pasteid)
|
public function read($pasteid)
|
||||||
{
|
{
|
||||||
|
if (
|
||||||
|
!array_key_exists($pasteid, self::$_cache)
|
||||||
|
) self::$_cache[$pasteid] = self::_select(
|
||||||
|
'SELECT * FROM ' . self::$_prefix . 'paste WHERE dataid = ?',
|
||||||
|
array($pasteid), true
|
||||||
|
);
|
||||||
|
|
||||||
|
// create object
|
||||||
|
$paste = new stdClass;
|
||||||
|
$paste->data = self::$_cache[$pasteid]['data'];
|
||||||
|
$paste->meta = new stdClass;
|
||||||
|
$paste->meta->postdate = (int) self::$_cache[$pasteid]['postdate'];
|
||||||
|
$paste->meta->expire_date = (int) self::$_cache[$pasteid]['expiredate'];
|
||||||
|
if (
|
||||||
|
self::$_cache[$pasteid]['opendiscussion']
|
||||||
|
) $paste->meta->opendiscussion = true;
|
||||||
|
if (
|
||||||
|
self::$_cache[$pasteid]['burnafterreading']
|
||||||
|
) $paste->meta->burnafterreading = true;
|
||||||
|
|
||||||
|
return $paste;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -84,6 +235,14 @@ class zerobin_db extends zerobin_abstract
|
||||||
*/
|
*/
|
||||||
public function delete($pasteid)
|
public function delete($pasteid)
|
||||||
{
|
{
|
||||||
|
self::_exec(
|
||||||
|
'DELETE FROM ' . self::$_prefix . 'paste WHERE dataid = ?',
|
||||||
|
array($pasteid)
|
||||||
|
);
|
||||||
|
self::_exec(
|
||||||
|
'DELETE FROM ' . self::$_prefix . 'comment WHERE pasteid = ?',
|
||||||
|
array($pasteid)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -95,6 +254,13 @@ class zerobin_db extends zerobin_abstract
|
||||||
*/
|
*/
|
||||||
public function exists($pasteid)
|
public function exists($pasteid)
|
||||||
{
|
{
|
||||||
|
if (
|
||||||
|
!array_key_exists($pasteid, self::$_cache)
|
||||||
|
) self::$_cache[$pasteid] = self::_select(
|
||||||
|
'SELECT * FROM ' . self::$_prefix . 'paste WHERE dataid = ?',
|
||||||
|
array($pasteid), true
|
||||||
|
);
|
||||||
|
return (bool) self::$_cache[$pasteid];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -109,6 +275,18 @@ class zerobin_db extends zerobin_abstract
|
||||||
*/
|
*/
|
||||||
public function createComment($pasteid, $parentid, $commentid, $comment)
|
public function createComment($pasteid, $parentid, $commentid, $comment)
|
||||||
{
|
{
|
||||||
|
return self::_exec(
|
||||||
|
'INSERT INTO ' . self::$_prefix . 'comment VALUES(?,?,?,?,?,?,?)',
|
||||||
|
array(
|
||||||
|
$pasteid,
|
||||||
|
$parentid,
|
||||||
|
$commentid,
|
||||||
|
$comment['data'],
|
||||||
|
$comment['meta']['nickname'],
|
||||||
|
$comment['meta']['vizhash'],
|
||||||
|
$comment['meta']['postdate'],
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -120,6 +298,33 @@ class zerobin_db extends zerobin_abstract
|
||||||
*/
|
*/
|
||||||
public function readComments($pasteid)
|
public function readComments($pasteid)
|
||||||
{
|
{
|
||||||
|
$rows = self::_select(
|
||||||
|
'SELECT * FROM ' . self::$_prefix . 'comment WHERE pasteid = ?',
|
||||||
|
array($pasteid)
|
||||||
|
);
|
||||||
|
|
||||||
|
// create object
|
||||||
|
$commentTemplate = new stdClass;
|
||||||
|
$commentTemplate->meta = new stdClass;
|
||||||
|
|
||||||
|
// create comment list
|
||||||
|
$comments = array();
|
||||||
|
if (count($rows))
|
||||||
|
{
|
||||||
|
foreach ($rows as $row)
|
||||||
|
{
|
||||||
|
$i = (int) $row['postdate'];
|
||||||
|
$comments[$i] = clone $commentTemplate;
|
||||||
|
$comments[$i]->data = $row['data'];
|
||||||
|
$comments[$i]->meta->nickname = $row['nickname'];
|
||||||
|
$comments[$i]->meta->vizhash = $row['vizhash'];
|
||||||
|
$comments[$i]->meta->postdate = $i;
|
||||||
|
$comments[$i]->meta->commentid = $row['dataid'];
|
||||||
|
$comments[$i]->meta->parentid = $row['parentid'];
|
||||||
|
}
|
||||||
|
ksort($comments);
|
||||||
|
}
|
||||||
|
return $comments;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,5 +338,50 @@ class zerobin_db extends zerobin_abstract
|
||||||
*/
|
*/
|
||||||
public function existsComment($pasteid, $parentid, $commentid)
|
public function existsComment($pasteid, $parentid, $commentid)
|
||||||
{
|
{
|
||||||
|
return (bool) self::_select(
|
||||||
|
'SELECT dataid FROM ' . self::$_prefix . 'comment ' .
|
||||||
|
'WHERE pasteid = ? AND parentid = ? AND dataid = ?',
|
||||||
|
array($pasteid, $parentid, $commentid), true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* execute a statement
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @static
|
||||||
|
* @param string $sql
|
||||||
|
* @param array $params
|
||||||
|
* @throws PDOException
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private static function _exec($sql, array $params)
|
||||||
|
{
|
||||||
|
$statement = self::$_db->prepare($sql);
|
||||||
|
$result = $statement->execute($params);
|
||||||
|
$statement->closeCursor();
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
private static function _select($sql, array $params, $firstOnly = false)
|
||||||
|
{
|
||||||
|
$statement = self::$_db->prepare($sql);
|
||||||
|
$statement->execute($params);
|
||||||
|
$result = $firstOnly ?
|
||||||
|
$statement->fetch(PDO::FETCH_ASSOC) :
|
||||||
|
$statement->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
$statement->closeCursor();
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,9 +48,11 @@
|
||||||
<div id="expiration" style="display:none;">Expire:
|
<div id="expiration" style="display:none;">Expire:
|
||||||
<select id="pasteExpiration" name="pasteExpiration">
|
<select id="pasteExpiration" name="pasteExpiration">
|
||||||
<option value="burn">Burn after reading</option>
|
<option value="burn">Burn after reading</option>
|
||||||
|
<option value="5min">5 minutes</option>
|
||||||
<option value="10min">10 minutes</option>
|
<option value="10min">10 minutes</option>
|
||||||
<option value="1hour">1 hour</option>
|
<option value="1hour">1 hour</option>
|
||||||
<option value="1day">1 day</option>
|
<option value="1day">1 day</option>
|
||||||
|
<option value="1week">1 week</option>
|
||||||
<option value="1month" selected="selected">1 month</option>
|
<option value="1month" selected="selected">1 month</option>
|
||||||
<option value="1year">1 year</option>
|
<option value="1year">1 year</option>
|
||||||
<option value="never">Never</option>
|
<option value="never">Never</option>
|
||||||
|
@ -67,7 +69,7 @@
|
||||||
</div>
|
</div>
|
||||||
<input id="password" value="Optional password..." style="display:none;" />
|
<input id="password" value="Optional password..." style="display:none;" />
|
||||||
<div id="opendisc" class="button" style="display:none;">
|
<div id="opendisc" class="button" style="display:none;">
|
||||||
<input type="checkbox" id="opendiscussion" name="opendiscussion" />
|
<input type="checkbox" id="opendiscussion" name="opendiscussion" {if="!$OPENDISCUSSION"} disabled="disabled"{/if} />
|
||||||
<label for="opendiscussion">Open discussion</label>
|
<label for="opendiscussion">Open discussion</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue