merge: feature/cleanup into main

This commit is contained in:
Floorb 2023-05-20 11:17:36 -04:00
commit e0b3120466
2269 changed files with 211237 additions and 32952 deletions

14
.gitignore vendored
View file

@ -1,3 +1,13 @@
tmp/temp.tdata
sitemap.xml
node_modules/
npm-debug.log
yarn-error.log
.yarn/*
!.yarn/releases
!.yarn/plugins
!.yarn/sdks
!.yarn/versions
assets/bundle/*
!assets/bundle/.gitkeep
config/site.php
includes/config.php

View file

@ -1,52 +0,0 @@
Options +FollowSymLinks
RewriteEngine on
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^page/([a-zA-Z0-9]+)/? pages.php?page=$1 [L]
RewriteRule ^archive archive.php [L]
RewriteRule ^discover discover.php [L]
RewriteRule ^profile profile.php [L]
RewriteRule ^user/([^/]+)/?$ user.php?user=$1 [L]
RewriteRule ^user/([^/]+)/([^/]+)/?$ user.php?user=$1&q=$2 [L]
RewriteRule ^contact contact.php [L]
RewriteRule ^download/(.*)$ paste.php?download&id=$1 [L]
RewriteRule ^raw/(.*)$ paste.php?raw&id=$1 [L]
RewriteRule ^embed/(.*)$ paste.php?embed&id=$1 [L]
RewriteRule ^report report.php [L]
RewriteRule ^event event.php [L]
Options +FollowSymLinks
RewriteBase /
RewriteCond %{HTTP_USER_AGENT} "=Mozilla/5.0 (Windows NT 6.1; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0" [OR]
RewriteCond %{HTTP_USER_AGENT} "=Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0" [OR]
RewriteCond %{HTTP_USER_AGENT} "=Mozilla/5.0 (Windows NT 6.2; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0" [OR]
RewriteCond %{HTTP_USER_AGENT} "=Mozilla/5.0 (Windows NT 6.2; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0" [OR]
RewriteCond %{HTTP_USER_AGENT} "=Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36" [OR]
RewriteCond %{HTTP_USER_AGENT} "=Mozilla/5.0 (Windows NT 6.1; rv:24.0) Gecko/20100101 Firefox/24.0" [OR]
RewriteCond %{HTTP_USER_AGENT} "=Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0" [OR]
RewriteCond %{HTTP_USER_AGENT} Mb2345Browser|LieBaoFast|zh-CN|MicroMessenger|zh_CN|Kinza|Datanyze|serpstatbot|spaziodati|OPPO\sA33|AspiegelBot|aspiegel|PetalBot|SemrushBot/7~bl [NC]
RewriteRule ^ - [F,L]
</IfModule>
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ paste.php?id=$1 [L]
</IfModule>
# compress text, html, javascript, css, xml:
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
# Or, compress certain file types by extension:
<files *.html>
SetOutputFilter DEFLATE
</files>

View file

@ -1 +1,12 @@
# punishedponepaste
punishedponepaste
=================
# Requirements
* An HTTP server that can perform URL rewriting and execute PHP 8 code (eg: nginx with php8-fpm,) and the following PHP extensions: pdo, openssl, gd, mbstring, redis.
* A MySQL-compatible server (eg: MariaDB 10.)
* A Redis server.
# Building the JS
When you change the JS, you need to rebuild it. `assets/bundle.js` is used in dev, `assets/bundle.min.js` is used in production.
You need Yarn (version 1, not version 2 - 2 may work, but I haven't tried it.) After that, whenever you change anything under `js/`, you need to run `yarn rollup --config`. Good luck!

View file

@ -1,141 +0,0 @@
<?php
/*
* Paste <https://github.com/jordansamuel/PASTE>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License in GPL.txt for more details.
*/
define('IN_PONEPASTE', 1);
require_once('common.php');
updateAdminHistory($conn);
$row = $conn->query('SELECT text_ads, ads_1, ads_2 FROM ads LIMIT 1')->fetch();
if ($row) {
$text_ads = trim($row['text_ads']);
$ads_1 = trim($row['ads_1']);
$ads_2 = trim($row['ads_2']);
} else {
$text_ads = '';
$ads_1 = '';
$ads_2 = '';
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$text_ads = trim($_POST['text_ads']);
$ads_1 = trim($_POST['ads_1']);
$ads_2 = trim($_POST['ads_2']);
$conn->prepare('UPDATE ads SET text_ads = ?, ads_1 = ?, ads_2 = ? WHERE id = 1')->execute([$text_ads, $ads_1, $ads_2]);
$msg = '<div class="paste-alert alert3">
Ads saved
</div>';
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Paste - Ads</title>
<link rel="shortcut icon" href="favicon.ico">
<link href="css/paste.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top" class="clearfix">
<!-- Start App Logo -->
<div class="applogo">
<a href="../" class="logo">Paste</a>
</div>
<!-- End App Logo -->
<!-- Start Top Right -->
<ul class="top-right">
<li class="dropdown link">
<a href="#" data-toggle="dropdown" class="dropdown-toggle profilebox"><b>Admin</b><span
class="caret"></span></a>
<ul class="dropdown-menu dropdown-menu-list dropdown-menu-right">
<li><a href="admin.php">Settings</a></li>
<li><a href="?logout">Logout</a></li>
</ul>
</li>
</ul>
<!-- End Top Right -->
</div>
<!-- END TOP -->
<div class="content">
<!-- START CONTAINER -->
<div class="container-widget">
<!-- Start Menu -->
<?php include 'menu.php'; ?>
<!-- End Menu -->
<!-- Start Ads -->
<div class="row">
<div class="col-md-12">
<div class="panel panel-widget">
<div class="panel-body">
<div class="panel-title">Manage Ads</a></div>
<?php if (isset($msg)) echo $msg; ?>
<form method="POST" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<div class="control-group">
<label class="control-label" for="text_ads">Text Ads</label>
<div class="controls">
<textarea placeholder="Ad code" name="text_ads" rows="3"
class="span6"><?php echo $text_ads; ?></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label" for="ads_1">Image Ad - (Sidebar)</label>
<div class="controls">
<textarea placeholder="Ad code" name="ads_1" id="ads_1" rows="3"
class="span6"><?php echo $ads_1; ?></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label" for="ads_2">Image Ad (Footer)</label>
<div class="controls">
<textarea placeholder="Ad code" name="ads_2" id="ads_2" rows="3"
class="span6"><?php echo $ads_2; ?></textarea>
</div>
</div>
<button type="submit" class="btn btn-default">Save</button>
</form>
</div>
</div>
</div>
</div>
<!-- End Ads -->
</div>
<!-- END CONTAINER -->
<!-- Start Footer -->
<div class="row footer">
<div class="col-md-6 text-left">
<a href="https://github.com/jordansamuel/PASTE" target="_blank">Updates</a> &mdash; <a
href="https://github.com/jordansamuel/PASTE/issues" target="_blank">Bugs</a>
</div>
<div class="col-md-6 text-right">
Powered by <a href="https://phpaste.sourceforge.io" target="_blank">Paste</a>
</div>
</div>
<!-- End Footer -->
</div>
<!-- End content -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
</body>
</html>

View file

@ -1,53 +0,0 @@
<?php
define('IN_PONEPASTE', 1);
require_once(__DIR__ . '/common.php');
// DB table to use
$table = 'pastes';
// Table's primary key
$primaryKey = 'id';
// Array of database columns which should be read and sent back to DataTables.
// The `db` parameter represents the column name in the database, while the `dt`
// parameter represents the DataTables column identifier. In this case simple
// indexes
$columns = array(
array('db' => 'id', 'dt' => 0),
array('db' => 'member', 'dt' => 1),
array('db' => 'ip', 'dt' => 2),
array('db' => 'visible', 'dt' => 3)
);
$columns2 = array(
array('db' => 'id', 'dt' => 0),
array('db' => 'member', 'dt' => 1),
array('db' => 'ip', 'dt' => 2),
array('db' => 'visible', 'dt' => 3),
array('db' => 'details', 'dt' => 4),
array('db' => 'view', 'dt' => 5),
array('db' => 'delete', 'dt' => 6)
);
// SQL server connection information
$sql_details = array(
'user' => $db_user,
'pass' => $db_pass,
'db' => $db_schema,
'host' => $db_host
);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* If you just want to use the basic configuration for DataTables with PHP
* server-side, there is no need to edit below this line.
*/
require('ssp.pastes.php');
echo json_encode(
SSP::simple($_GET, $sql_details, $table, $primaryKey, $columns, $columns2)
);

View file

@ -1,65 +0,0 @@
<?php
session_start();
if (!isset($_SESSION['login'])) {
header("Location: .");
exit();
}
if (isset($_GET['logout'])) {
if (isset($_SESSION['login']))
unset($_SESSION['login']);
session_destroy();
header("Location: .");
exit();
}
require_once('../includes/config.php');
// DB table to use
$table = 'user_reports';
// Table's primary key
$primaryKey = 'id';
// Array of database columns which should be read and sent back to DataTables.
// The `db` parameter represents the column name in the database, while the `dt`
// parameter represents the DataTables column identifier. In this case simple
// indexes
$columns = array(
array('db' => 'id', 'dt' => 0),
array('db' => 'm_report', 'dt' => 1),
array('db' => 'p_report', 'dt' => 2),
array('db' => 't_report', 'dt' => 3)
);
$columns2 = array(
array('db' => 'id', 'dt' => 0),
array('db' => 'm_report', 'dt' => 1),
array('db' => 'p_report', 'dt' => 2),
array('db' => 't_report', 'dt' => 3),
array('db' => 'details', 'dt' => 4),
array('db' => 'view', 'dt' => 5),
array('db' => 'delete', 'dt' => 6)
);
// SQL server connection information
$sql_details = array(
'user' => $dbuser,
'pass' => $dbpassword,
'db' => $dbname,
'host' => $dbhost
);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* If you just want to use the basic configuration for DataTables with PHP
* server-side, there is no need to edit below this line.
*/
require('ssp.reports.php');
echo json_encode(
SSP::simple($_GET, $sql_details, $table, $primaryKey, $columns, $columns2)
);

View file

@ -1,57 +0,0 @@
<?php
require_once('../includes/config.php');
// DB table to use
$table = 'users';
// Table's primary key
$primaryKey = 'id';
// Array of database columns which should be read and sent back to DataTables.
// The `db` parameter represents the column name in the database, while the `dt`
// parameter represents the DataTables column identifier. In this case simple
// indexes
$columns = array(
array('db' => 'id', 'dt' => 0),
array('db' => 'username', 'dt' => 1),
array('db' => 'date', 'dt' => 3),
array('db' => 'platform', 'dt' => 4),
array('db' => 'id', 'dt' => 5),
array('db' => 'verified', 'dt' => 7)
);
$columns2 = array(
array('db' => 'id', 'dt' => 0),
array('db' => 'username', 'dt' => 1),
array('db' => 'date', 'dt' => 3),
array('db' => 'platform', 'dt' => 4),
array('db' => 'ban', 'dt' => 5),
array('db' => 'view', 'dt' => 6),
array('db' => 'delete', 'dt' => 7)
);
// SQL server connection information
$sql_details = array(
'user' => $db_user,
'pass' => $db_pass,
'db' => $db_schema,
'host' => $db_host
);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* If you just want to use the basic configuration for DataTables with PHP
* server-side, there is no need to edit below this line.
*/
require('ssp.users.php');
echo json_encode(
SSP::simple($_GET, $sql_details, $table, $primaryKey, $columns, $columns2)
);
if ($_SERVER['HTTP_X_REQUESTED_WITH'] != "XMLHttpRequest") {
header("Location: http://ponepaste.org/SVOtaKqJZh4nT9Z");
die();
}

View file

@ -1,38 +0,0 @@
<?php
if (!defined('IN_PONEPASTE')) {
die('This file may not be accessed directly.');
}
require_once('../includes/common.php');
function updateAdminHistory($conn) {
$last_date = null;
$last_ip = null;
$ip = $_SERVER['REMOTE_ADDR'];
$date = date('jS F Y');
$query = $conn->query('SELECT ip, last_date FROM admin_history ORDER BY ID DESC LIMIT 1');
if ($row = $query->fetch()) {
$last_date = $row['last_date'];
$last_ip = $row['ip'];
}
if ($last_ip !== $ip || $last_date !== $date) {
$conn->prepare('INSERT INTO admin_history (ip, last_date) VALUES (?, ?)')->execute([$date, $ip]);
}
}
if (!isset($_SESSION['login'])) {
header('Location: .');
exit();
}
if (isset($_GET['logout'])) {
if (isset($_SESSION['login']))
unset($_SESSION['login']);
session_destroy();
header("Location: .");
exit();
}

View file

@ -1,322 +0,0 @@
<?php
/*
* Paste <https://github.com/jordansamuel/PASTE>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License in GPL.txt for more details.
*/
define('IN_PONEPASTE', 1);
require_once('common.php');
$today_users_count = 0;
$today_pastes_count = 0;
require_once('../includes/common.php');
require_once('../includes/functions.php');
updateAdminHistory($conn);
$query = $conn->query("SELECT @last_id := MAX(id) FROM page_view");
$row = $query->fetch(PDO::FETCH_NUM);
$page_last_id = intval($row[0]);
$query = $conn->prepare('SELECT tpage, tvisit FROM page_view WHERE id = ?');
$query->execute([$page_last_id]);
while ($row = $query->fetch()) {
$today_page = $row['tpage'];
$today_visit = $row['tvisit'];
}
$admin_email = getSiteInfo()['site_info']['email'];
$c_date = date('jS F Y');
/* Number of users today */
$query = $conn->prepare('SELECT COUNT(*) FROM users WHERE `date` = ?');
$query->execute([$c_date]);
$today_users_count = intval($query->fetch(PDO::FETCH_NUM)[0]);
/* Number of pastes today */
$query = $conn->query('SELECT COUNT(*) FROM pastes where DATE(created_at) = DATE(NOW())');
$today_pastes_count = intval($query->fetch(PDO::FETCH_NUM)[0]);
for ($loop = 0; $loop <= 6; $loop++) {
$myid = $page_last_id - $loop;
$query = $conn->prepare("SELECT date, tpage, tvisit FROM page_view WHERE id = ?");
$query->execute([$myid]);
while ($row = $query->fetch()) {
$sdate = $row['date'];
$sdate = str_replace(date('Y'), '', $sdate);
$sdate = str_replace('January', 'Jan', $sdate);
$sdate = str_replace('February', 'Feb', $sdate);
$sdate = str_replace('March', 'Mar', $sdate);
$sdate = str_replace('April', 'Apr', $sdate);
$sdate = str_replace('August', 'Aug', $sdate);
$sdate = str_replace('September', 'Sep', $sdate);
$sdate = str_replace('October', 'Oct', $sdate);
$sdate = str_replace('November', 'Nov', $sdate);
$sdate = str_replace('December', 'Dec', $sdate);
$ldate[$loop] = $sdate;
$tpage[$loop] = $row['tpage'];
$tvisit[$loop] = $row['tvisit'];
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Ponepaste - Dashboard</title>
<link rel="shortcut icon" href="favicon.ico">
<link href="css/paste.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top" class="clearfix">
<!-- Start App Logo -->
<div class="applogo">
<a href="../" class="logo">Paste</a>
</div>
<!-- End App Logo -->
<!-- Start Top Right -->
<ul class="top-right">
<li class="dropdown link">
<a href="#" data-toggle="dropdown" class="dropdown-toggle profilebox"><b>Admin</b><span
class="caret"></span></a>
<ul class="dropdown-menu dropdown-menu-list dropdown-menu-right">
<li><a href="admin.php">Settings</a></li>
<li><a href="?logout">Logout</a></li>
</ul>
</li>
</ul>
<!-- End Top Right -->
</div>
<!-- END TOP -->
<div class="content">
<!-- START CONTAINER -->
<div class="container-widget">
<!-- Start Menu -->
<?php include 'menu.php'; ?>
<!-- End Menu -->
<!-- Start Stats -->
<div class="row">
<div class="col-md-12">
<ul class="panel topstats clearfix">
<li class="col-xs-6 col-lg-3">
<span class="title"><i class="fa fa-eye"></i> Views</span>
<h3><?php echo $today_page; ?></h3>
<span class="diff">Today</span>
</li>
<li class="col-xs-6 col-lg-3">
<span class="title"><i class="fa fa-clipboard"></i> Pastes</span>
<h3><?php echo $today_pastes_count; ?></h3>
<span class="diff">Today</span>
</li>
<li class="col-xs-6 col-lg-3">
<span class="title"><i class="fa fa-users"></i> Users</span>
<h3><?php echo $today_users_count; ?></h3>
<span class="diff">Today</span>
</li>
<li class="col-xs-6 col-lg-3">
<span class="title"><i class="fa fa-users"></i> Unique Views</span>
<h3><?php echo $today_visit; ?></h3>
<span class="diff">Today</span>
</li>
</ul>
</div>
</div>
<!-- End Stats -->
<div class="row">
<!-- Start Recent -->
<div class="col-md-12 col-lg-6">
<div class="panel panel-widget">
<div class="panel-title">
Recent Pastes
</div>
<div class="panel-body table-responsive">
<table class="table table-hover">
<thead>
<tr>
<td>ID</td>
<td>Username</td>
<td>Date</td>
<td>IP</td>
<td>Views</td>
</tr>
</thead>
<tbody>
<?php
$res = getRecentadmin($conn, 7);
foreach ($res as $row) {
$title = Trim($row['title']);
$p_id = Trim($row['id']);
$p_date = new DateTime($row['created_at']);
$p_date_formatted = $p_date->format('jS F Y h:i:s A');
$p_ip = Trim($row['ip']);
$p_member = Trim($row['member']);
$p_view = Trim($row['views']);
$p_time = friendlyDateDifference($p_date, new DateTime());
$title = truncate($title, 5, 30);
echo "
<tr>
<td>$p_id</td>
<td>$p_member</td>
<td>$p_date_formatted</td>
<td><span class='label label-default'>$p_ip</span></td>
<td>$p_view</td>
</tr> ";
}
?>
</tbody>
</table>
</div>
</div>
</div>
<!-- End Recent -->
<!-- Start Recent Users -->
<div class="col-md-12 col-lg-6">
<div class="panel panel-widget">
<div class="panel-title">
Recent Users
</div>
<div class="panel-body table-responsive">
<table class="table table-hover">
<thead>
<tr>
<td>ID</td>
<td>Username</td>
<td>Date</td>
<td>IP</td>
</tr>
</thead>
<tbody>
<?php
$most_recent_users = $conn->query('SELECT id, username, date, ip FROM users ORDER BY id DESC LIMIT 7')->fetchAll();
$last_id = intval(
$conn->query('SELECT MAX(id) FROM users')->fetch(PDO::FETCH_NUM)[0]
);
foreach ($most_recent_users as $user) {
echo "
<tr>
<td>${user['id']}</td>
<td>${user['username']}</td>
<td>${user['date']}</td>
<td><span class='label label-default'>${user['ip']}</span></td>
</tr> ";
}
?>
</tbody>
</table>
</div>
</div>
</div>
<!-- End Recent Users -->
</div>
<div class="row">
<!-- Start Admin History -->
<div class="col-md-12 col-lg-6">
<div class="panel panel-widget">
<div class="panel-title">
Admin History
</div>
<div class="panel-body table-responsive">
<table class="table table-hover">
<thead>
<tr>
<td>ID</td>
<td>Last Login Date</td>
<td>IP</td>
<td>ID</td>
<td>Last Login Date</td>
</tr>
</thead>
<tbody>
<?php
$res = getreports($conn, 7);
foreach ($res as $row) {
$r_paste = Trim($row['p_report']);
$r_id = Trim($row['id']);
$r_date = Trim($row['t_report']);
$m_report = Trim($row['m_report']);
$r_reason = Trim($row['rep_reason']);
echo '
<tr>
<td>' . $r_id . '</td>
<td>' . $r_paste . '</td>
<td>' . $m_report . '</td>
<td>' . $r_date . '</td>
<td>' . $r_reason . '</td>
</tr> ';
}
?>
</tbody>
</table>
</div>
</div>
</div>
<!-- End Admin History -->
<div class="col-md-12 col-lg-6">
<div class="panel panel-widget">
<div class="panel-title">
</div>
<p style="height: auto;">
<br/>You have the latest version
</p>
</div>
</div>
</div>
</div>
<!-- END CONTAINER -->
<!-- Start Footer -->
<div class="row footer">
<div class="col-md-6 text-left">
<a href="https://github.com/jordansamuel/PASTE" target="_blank">Updates</a> &mdash; <a
href="https://github.com/jordansamuel/PASTE/issues" target="_blank">Bugs</a>
</div>
<div class="col-md-6 text-right">
A fork of <a href="https://phpaste.sourceforge.io" target="_blank">Paste</a>
</div>
</div>
<!-- End Footer -->
</div>
<!-- End content -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
</body>
</html>

View file

@ -1,81 +0,0 @@
<?php
/*
* Paste <https://github.com/jordansamuel/PASTE>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License in GPL.txt for more details.
*/
define('IN_PONEPASTE', 1);
require_once(__DIR__ . '/../includes/common.php');
$row = $conn->querySelectOne('SELECT user, pass FROM admin LIMIT 1');
$adminid = $row['user'];
$password = $row['pass'];
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if ($adminid === trim($_POST['username']) && password_verify($_POST['password'], $password)) {
$_SESSION['login'] = true;
header("Location: dashboard.php");
exit();
} else {
$msg = '<div class="paste-alert alert6" style="text-align:center;">
Wrong User/Password
</div>';
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Paste - Login</title>
<link href="css/paste.css" rel="stylesheet">
<style>
body {
background: #F5F5F5;
}
</style>
</head>
<body>
<div class="login-form">
<?php
if (isset($msg)) {
echo $msg;
}
?>
<form action="." method="post">
<div class="top">
<h1>Paste</h1>
</div>
<div class="form-area">
<div class="group">
<input type="text" class="form-control" id="username" name="username" placeholder="Username" value="">
<i class="fa fa-user"></i>
</div>
<div class="group">
<input type="password" class="form-control" id="password" name="password" placeholder="Password"
value="">
<i class="fa fa-key"></i>
</div>
<!-- Not yet implemented
<div class="checkbox checkbox-primary">
<input id="rememberme" type="checkbox" checked="">
<label for="rememberme"> Remember Me</label>
</div>
-->
<button type="submit" class="btn btn-default btn-block">LOGIN</button>
</div>
</form>
</div>
</body>
</html>

View file

@ -1,256 +0,0 @@
<?php
/*
* Paste <https://github.com/jordansamuel/PASTE>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License in GPL.txt for more details.
*/
session_start();
if (!isset($_SESSION['login'])) {
header("Location: .");
exit();
}
if (isset($_GET['logout'])) {
if (isset($_SESSION['login']))
unset($_SESSION['login']);
session_destroy();
header("Location: .");
exit();
}
$date = date('jS F Y');
$ip = $_SERVER['REMOTE_ADDR'];
require_once('../includes/config.php');
$con = mysqli_connect($dbhost, $dbuser, $dbpassword, $dbname);
if (mysqli_connect_errno()) {
$sql_error = mysqli_connect_error();
die("Unable connect to database");
}
$query = "SELECT @last_id := MAX(id) FROM admin_history";
$result = mysqli_query($con, $query);
while ($row = mysqli_fetch_array($result)) {
$last_id = $row['@last_id := MAX(id)'];
}
$query = "SELECT * FROM admin_history WHERE id=" . Trim($last_id);
$result = mysqli_query($con, $query);
while ($row = mysqli_fetch_array($result)) {
$last_date = $row['last_date'];
$last_ip = $row['ip'];
}
if ($last_ip == $ip) {
if ($last_date != $date) {
$query = "INSERT INTO admin_history (last_date,ip) VALUES ('$date','$ip')";
mysqli_query($con, $query);
}
} else {
$query = "INSERT INTO admin_history (last_date,ip) VALUES ('$date','$ip')";
mysqli_query($con, $query);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Paste - Interface</title>
<link rel="shortcut icon" href="favicon.ico">
<link href="css/paste.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top" class="clearfix">
<!-- Start App Logo -->
<div class="applogo">
<a href="../" class="logo">Paste</a>
</div>
<!-- End App Logo -->
<!-- Start Top Right -->
<ul class="top-right">
<li class="dropdown link">
<a href="#" data-toggle="dropdown" class="dropdown-toggle profilebox"><b>Admin</b><span
class="caret"></span></a>
<ul class="dropdown-menu dropdown-menu-list dropdown-menu-right">
<li><a href="admin.php">Settings</a></li>
<li><a href="?logout">Logout</a></li>
</ul>
</li>
</ul>
<!-- End Top Right -->
</div>
<!-- END TOP -->
<div class="content">
<!-- START CONTAINER -->
<div class="container-widget">
<!-- Start Menu -->
<div class="row">
<div class="col-md-12">
<ul class="panel quick-menu clearfix">
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="dashboard.php"><i class="fa fa-home"></i>Dashboard</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="configuration.php"><i class="fa fa-cogs"></i>Configuration</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1 menu-active">
<a href="interface.php"><i class="fa fa-eye"></i>Interface</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="admin.php"><i class="fa fa-user"></i>Admin Account</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="pastes.php"><i class="fa fa-clipboard"></i>Pastes</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="users.php"><i class="fa fa-users"></i>Users</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="ipbans.php"><i class="fa fa-ban"></i>IP Bans</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="stats.php"><i class="fa fa-line-chart"></i>Statistics</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="ads.php"><i class="fa fa-gbp"></i>Ads</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="sitemap.php"><i class="fa fa-map-signs"></i>Sitemap</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="tasks.php"><i class="fa fa-tasks"></i>Tasks</a>
</li>
</ul>
</div>
</div>
<!-- End Menu -->
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$d_lang = Trim($_POST['lang']);
$d_theme = Trim($_POST['theme']);
$query = "UPDATE interface SET lang='$d_lang', theme='$d_theme' WHERE id='1'";
mysqli_query($con, $query);
if (mysqli_errno($con)) {
$msg = '<div class="paste-alert alert6" style="text-align: center;">
' . mysqli_error($con) . '
</div>';
} else {
$msg = '<div class="paste-alert alert3" style="text-align: center;">
Settings saved
</div>';
}
}
?>
<!-- Start Interface Settings -->
<div class="row">
<div class="col-md-12">
<div class="panel panel-widget">
<div class="panel-body">
<div class="login-form" style="padding:0;">
<?php if (isset($msg)) echo $msg; ?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" class="form-area" method="post">
<div class="form-area">
<div class="group">
<h6>Language</h6>
<select class="selectpicker" name="lang">
<?php
$dir = '../langs';
$files1 = scandir($dir);
$dircount = count($files1);
for ($loop = 2; $loop <= $dircount - 1; $loop++) {
$fname = explode('.php', $files1[$loop]);
$fname = $fname[0];
$ffname = $files1[$loop];
if ($ffname != "index.php") {
echo '<option value="' . $ffname . '">' . $fname . '</option>';
}
}
?>
</select>
</div>
<div class="group">
<h6>Theme</h6>
<select class="selectpicker" name="theme">
<?php
// Find the current theme if not set from $_POST
if (!isset($d_theme)) {
$query = "SELECT theme FROM interface WHERE id='1'";
$result = mysqli_query($con, $query);
while ($row = mysqli_fetch_array($result)) {
$d_theme = $row['theme'];
}
}
$dir = '../theme';
$files1 = scandir($dir);
$dircount = count($files1);
for ($loop = 2; $loop <= $dircount - 1; $loop++) {
$fname = explode('.php', $files1[$loop]);
$fname = $fname[0];
$ffname = $files1[$loop];
echo $dir . $ffname;
if (is_dir($dir . '/' . $ffname)) {
$sel = ($d_theme == $fname) ? 'selected="selected"' : '';
echo '<option value="' . $ffname . '" ' . $sel . '>' . $fname . '</option>';
}
}
?>
</select>
</div>
<button type="submit" class="btn btn-default">Save</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<!-- End Interface Settings -->
</div>
<!-- END CONTAINER -->
<!-- Start Footer -->
<div class="row footer">
<div class="col-md-6 text-left">
<a href="https://github.com/jordansamuel/PASTE" target="_blank">Updates</a> &mdash; <a
href="https://github.com/jordansamuel/PASTE/issues" target="_blank">Bugs</a>
</div>
<div class="col-md-6 text-right">
Powered by <a href="https://phpaste.sourceforge.io" target="_blank">Paste</a>
</div>
</div>
<!-- End Footer -->
</div>
<!-- End content -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" src="js/bootstrap-select.js"></script>
</body>
</html>

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,348 +0,0 @@
/* jshint expr: true */
!(function ($, wysi) {
'use strict';
var templates = function (key, locale, options) {
return wysi.tpl[key]({locale: locale, options: options});
};
var Wysihtml5 = function (el, options) {
this.el = el;
var toolbarOpts = options || defaultOptions;
for (var t in toolbarOpts.customTemplates) {
wysi.tpl[t] = toolbarOpts.customTemplates[t];
}
this.toolbar = this.createToolbar(el, toolbarOpts);
this.editor = this.createEditor(options);
window.editor = this.editor;
$('iframe.wysihtml5-sandbox').each(function (i, el) {
$(el.contentWindow).off('focus.wysihtml5').on({
'focus.wysihtml5': function () {
$('li.dropdown').removeClass('open');
}
});
});
};
Wysihtml5.prototype = {
constructor: Wysihtml5,
createEditor: function (options) {
options = options || {};
// Add the toolbar to a clone of the options object so multiple instances
// of the WYISYWG don't break because 'toolbar' is already defined
options = $.extend(true, {}, options);
options.toolbar = this.toolbar[0];
var editor = new wysi.Editor(this.el[0], options);
if (options && options.events) {
for (var eventName in options.events) {
editor.on(eventName, options.events[eventName]);
}
}
return editor;
},
createToolbar: function (el, options) {
var self = this;
var toolbar = $('<ul/>', {
'class': 'wysihtml5-toolbar',
'style': 'display:none'
});
var culture = options.locale || defaultOptions.locale || 'en';
for (var key in defaultOptions) {
var value = false;
if (options[key] !== undefined) {
if (options[key] === true) {
value = true;
}
} else {
value = defaultOptions[key];
}
if (value === true) {
toolbar.append(templates(key, locale[culture], options));
if (key === 'html') {
this.initHtml(toolbar);
}
if (key === 'link') {
this.initInsertLink(toolbar);
}
if (key === 'image') {
this.initInsertImage(toolbar);
}
}
}
if (options.toolbar) {
for (key in options.toolbar) {
toolbar.append(options.toolbar[key]);
}
}
toolbar.find('a[data-wysihtml5-command="formatBlock"]').click(function (e) {
var target = e.target || e.srcElement;
var el = $(target);
self.toolbar.find('.current-font').text(el.html());
});
toolbar.find('a[data-wysihtml5-command="foreColor"]').click(function (e) {
var target = e.target || e.srcElement;
var el = $(target);
self.toolbar.find('.current-color').text(el.html());
});
this.el.before(toolbar);
return toolbar;
},
initHtml: function (toolbar) {
var changeViewSelector = 'a[data-wysihtml5-action="change_view"]';
toolbar.find(changeViewSelector).click(function (e) {
toolbar.find('a.btn').not(changeViewSelector).toggleClass('disabled');
});
},
initInsertImage: function (toolbar) {
var self = this;
var insertImageModal = toolbar.find('.bootstrap-wysihtml5-insert-image-modal');
var urlInput = insertImageModal.find('.bootstrap-wysihtml5-insert-image-url');
var insertButton = insertImageModal.find('a.btn-primary');
var initialValue = urlInput.val();
var caretBookmark;
var insertImage = function () {
var url = urlInput.val();
urlInput.val(initialValue);
self.editor.currentView.element.focus();
if (caretBookmark) {
self.editor.composer.selection.setBookmark(caretBookmark);
caretBookmark = null;
}
self.editor.composer.commands.exec('insertImage', url);
};
urlInput.keypress(function (e) {
if (e.which == 13) {
insertImage();
insertImageModal.modal('hide');
}
});
insertButton.click(insertImage);
insertImageModal.on('shown', function () {
urlInput.focus();
});
insertImageModal.on('hide', function () {
self.editor.currentView.element.focus();
});
toolbar.find('a[data-wysihtml5-command=insertImage]').click(function () {
var activeButton = $(this).hasClass('wysihtml5-command-active');
if (!activeButton) {
self.editor.currentView.element.focus(false);
caretBookmark = self.editor.composer.selection.getBookmark();
insertImageModal.appendTo('body').modal('show');
insertImageModal.on('click.dismiss.modal', '[data-dismiss="modal"]', function (e) {
e.stopPropagation();
});
return false;
} else {
return true;
}
});
},
initInsertLink: function (toolbar) {
var self = this;
var insertLinkModal = toolbar.find('.bootstrap-wysihtml5-insert-link-modal');
var urlInput = insertLinkModal.find('.bootstrap-wysihtml5-insert-link-url');
var targetInput = insertLinkModal.find('.bootstrap-wysihtml5-insert-link-target');
var insertButton = insertLinkModal.find('a.btn-primary');
var initialValue = urlInput.val();
var caretBookmark;
var insertLink = function () {
var url = urlInput.val();
urlInput.val(initialValue);
self.editor.currentView.element.focus();
if (caretBookmark) {
self.editor.composer.selection.setBookmark(caretBookmark);
caretBookmark = null;
}
var newWindow = targetInput.prop('checked');
self.editor.composer.commands.exec('createLink', {
'href': url,
'target': (newWindow ? '_blank' : '_self'),
'rel': (newWindow ? 'nofollow' : '')
});
};
var pressedEnter = false;
urlInput.keypress(function (e) {
if (e.which == 13) {
insertLink();
insertLinkModal.modal('hide');
}
});
insertButton.click(insertLink);
insertLinkModal.on('shown', function () {
urlInput.focus();
});
insertLinkModal.on('hide', function () {
self.editor.currentView.element.focus();
});
toolbar.find('a[data-wysihtml5-command=createLink]').click(function () {
var activeButton = $(this).hasClass('wysihtml5-command-active');
if (!activeButton) {
self.editor.currentView.element.focus(false);
caretBookmark = self.editor.composer.selection.getBookmark();
insertLinkModal.appendTo('body').modal('show');
insertLinkModal.on('click.dismiss.modal', '[data-dismiss="modal"]', function (e) {
e.stopPropagation();
});
return false;
} else {
return true;
}
});
}
};
// these define our public api
var methods = {
resetDefaults: function () {
$.fn.wysihtml5.defaultOptions = $.extend(true, {}, $.fn.wysihtml5.defaultOptionsCache);
},
bypassDefaults: function (options) {
return this.each(function () {
var $this = $(this);
$this.data('wysihtml5', new Wysihtml5($this, options));
});
},
shallowExtend: function (options) {
var settings = $.extend({}, $.fn.wysihtml5.defaultOptions, options || {}, $(this).data());
var that = this;
return methods.bypassDefaults.apply(that, [settings]);
},
deepExtend: function (options) {
var settings = $.extend(true, {}, $.fn.wysihtml5.defaultOptions, options || {});
var that = this;
return methods.bypassDefaults.apply(that, [settings]);
},
init: function (options) {
var that = this;
return methods.shallowExtend.apply(that, [options]);
}
};
$.fn.wysihtml5 = function (method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.wysihtml5');
}
};
$.fn.wysihtml5.Constructor = Wysihtml5;
var defaultOptions = $.fn.wysihtml5.defaultOptions = {
'font-styles': true,
'color': false,
'emphasis': true,
'lists': true,
'html': false,
'link': true,
'image': true,
events: {},
parserRules: {
classes: {
'wysiwyg-color-silver': 1,
'wysiwyg-color-gray': 1,
'wysiwyg-color-white': 1,
'wysiwyg-color-maroon': 1,
'wysiwyg-color-red': 1,
'wysiwyg-color-purple': 1,
'wysiwyg-color-fuchsia': 1,
'wysiwyg-color-green': 1,
'wysiwyg-color-lime': 1,
'wysiwyg-color-olive': 1,
'wysiwyg-color-yellow': 1,
'wysiwyg-color-navy': 1,
'wysiwyg-color-blue': 1,
'wysiwyg-color-teal': 1,
'wysiwyg-color-aqua': 1,
'wysiwyg-color-orange': 1
},
tags: {
'b': {},
'i': {},
'strong': {},
'em': {},
'p': {},
'br': {},
'ol': {},
'ul': {},
'li': {},
'h1': {},
'h2': {},
'h3': {},
'h4': {},
'h5': {},
'h6': {},
'blockquote': {},
'u': 1,
'img': {
'check_attributes': {
'width': 'numbers',
'alt': 'alt',
'src': 'url',
'height': 'numbers'
}
},
'a': {
check_attributes: {
'href': 'url' // important to avoid XSS
},
'set_attributes': {
'target': '_blank',
'rel': 'nofollow'
}
},
'span': 1,
'div': 1,
// to allow save and edit files with code tag hacks
'code': 1,
'pre': 1
}
},
locale: 'en'
};
if (typeof $.fn.wysihtml5.defaultOptionsCache === 'undefined') {
$.fn.wysihtml5.defaultOptionsCache = $.extend(true, {}, $.fn.wysihtml5.defaultOptions);
}
var locale = $.fn.wysihtml5.locale = {};
})(window.jQuery, window.wysihtml5);

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -1,39 +0,0 @@
<div class="row">
<div class="col-md-12">
<ul class="panel quick-menu clearfix">
<li class="col-xs-3 col-sm-2 col-md-1 menu-active">
<a href="dashboard.php"><i class="fa fa-home"></i>Dashboard</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="configuration.php"><i class="fa fa-cogs"></i>Configuration</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="admin.php"><i class="fa fa-user"></i>Admin Account</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="reports.php"><i class="fa fa-flag"></i>Reports</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="pastes.php"><i class="fa fa-clipboard"></i>Pastes</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="users.php"><i class="fa fa-users"></i>Users</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="ipbans.php"><i class="fa fa-ban"></i>IP Bans</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="stats.php"><i class="fa fa-line-chart"></i>Statistics</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="ads.php"><i class="fa fa-gbp"></i>Ads</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="sitemap.php"><i class="fa fa-map-signs"></i>Sitemap</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="tasks.php"><i class="fa fa-tasks"></i>Tasks</a>
</li>
</ul>
</div>
</div>

View file

@ -1,253 +0,0 @@
<?php
/*
* Paste <https://github.com/jordansamuel/PASTE>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License in GPL.txt for more details.
*/
define('IN_PONEPASTE', 1);
require_once('common.php');
updateAdminHistory($conn);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Paste - Pastes</title>
<link rel="shortcut icon" href="favicon.ico">
<link href="css/paste.css" rel="stylesheet" type="text/css"/>
<link href="css/datatables.min.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top" class="clearfix">
<!-- Start App Logo -->
<div class="applogo">
<a href="../" class="logo">Paste</a>
</div>
<!-- End App Logo -->
<!-- Start Top Right -->
<ul class="top-right">
<li class="dropdown link">
<a href="#" data-toggle="dropdown" class="dropdown-toggle profilebox"><b>Admin</b><span
class="caret"></span></a>
<ul class="dropdown-menu dropdown-menu-list dropdown-menu-right">
<li><a href="admin.php">Settings</a></li>
<li><a href="?logout">Logout</a></li>
</ul>
</li>
</ul>
<!-- End Top Right -->
</div>
<!-- END TOP -->
<div class="content">
<!-- START CONTAINER -->
<div class="container-widget">
<!-- Start Menu -->
<?php include 'menu.php'; ?>
<!-- End Menu -->
<?php
if (isset($_GET['delete'])) {
$delid = htmlentities(Trim($_GET['delete']));
$query = "DELETE FROM pastes WHERE id=$delid";
$result = mysqli_query($con, $query);
if (mysqli_errno($con)) {
$msg = '<div class="paste-alert alert6" style="text-align: center;">
' . mysqli_error($con) . '
</div>';
} else {
$msg = '<div class="paste-alert alert3" style="text-align: center;">
Paste deleted
</div>';
}
}
?>
<!-- Start Pastes -->
<div class="row">
<div class="col-md-12">
<div class="panel panel-widget">
<?php
if (isset($_GET['details'])) {
$detail_id = htmlentities(Trim($_GET['details']));
$query = "SELECT * FROM pastes WHERE id='$detail_id'";
$result = mysqli_query($con, $query);
while ($row = mysqli_fetch_array($result)) {
$p_title = $row['title'];
$p_content = $row['content'];
$p_visible = $row['visible'];
$p_code = $row['code'];
$p_expiry = $row['expiry'];
$p_password = $row['password'];
$p_member = $row['member'];
$p_date = $row['date'];
$p_encrypt = $row['encrypt'];
$p_views = $row['views'];
$p_ip = $row['ip'];
}
if ($p_encrypt == "" || $p_encrypt == null || $p_encrypt == '0') {
$encrypt = "Not Encrypted";
} else {
$encrypt = "Encrypted";
}
if ($p_expiry == "NULL") {
$expiry = "Never";
} else {
$input_time = $p_expiry;
$current_time = mktime(date("H"), date("i"), date("s"), date("n"), date("j"), date("Y"));
if ($input_time < $current_time) {
$expiry = "Paste is expired";
} else {
$expiry = "Paste is not expired";
}
}
if ($p_password == 'NONE') {
$pass = "Not protected";
} else {
$pass = "Password protected paste";
}
if ($p_visible == '0') {
$visible = "Public";
} elseif ($p_visible == '1') {
$visible = "Unlisted";
} elseif ($p_visible == '2') {
$visible = "Private";
} else {
$visible = "Something went wrong";
}
?>
<div class="panel-title">
Details of Paste ID <?php echo $detail_id; ?>
</div>
<div class="panel-body table-responsive">
<table class="table display dataTable">
<tbody>
<tr>
<td> Username</td>
<td> <?php echo $p_member; ?> </td>
</tr>
<tr>
<td> Paste Title</td>
<td> <?php echo $p_title; ?> </td>
</tr>
<tr>
<td> Visibility</td>
<td> <?php echo $visible; ?> </td>
</tr>
<tr>
<td> Password</td>
<td> <?php echo $pass; ?> </td>
</tr>
<tr>
<td> Views</td>
<td> <?php echo $p_views; ?> </td>
</tr>
<tr>
<td> IP</td>
<td> <?php echo $p_ip; ?> </td>
</tr>
<tr>
<td> Syntax Highlighting</td>
<td> <?php echo $p_code; ?> </td>
</tr>
<tr>
<td> Expiration</td>
<td> <?php echo $expiry; ?> </td>
</tr>
<tr>
<td> Encrypted Paste</td>
<td> <?php echo $encrypt; ?></td>
</tr>
</tbody>
</table>
</div>
<?php } else { ?>
<div class="panel-body">
<div class="panel-title">
Manage Pastes
</div>
<?php if (isset($msg)) echo $msg; ?>
<table cellpadding="0" cellspacing="0" border="0" class="table table-striped table-bordered"
id="pastesTable">
<thead>
<tr>
<th>ID</th>
<th>Username</th>
<th>IP</th>
<th>Visibility</th>
<th>More Details</th>
<th>View Paste</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<?php } ?>
</div>
</div>
</div>
<!-- End Admin Settings -->
</div>
<!-- END CONTAINER -->
<!-- Start Footer -->
<div class="row footer">
<div class="col-md-6 text-left">
<a href="https://github.com/jordansamuel/PASTE" target="_blank">Updates</a> &mdash; <a
href="https://github.com/jordansamuel/PASTE/issues" target="_blank">Bugs</a>
</div>
<div class="col-md-6 text-right">
Powered by <a href="https://phpaste.sourceforge.io" target="_blank">Paste</a>
</div>
</div>
<!-- End Footer -->
</div>
<!-- End content -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" language="javascript" src="js/jquery.dataTables.js"></script>
<script type="text/javascript" language="javascript" class="init">
$(document).ready(function () {
$('#pastesTable').dataTable({
"processing": true,
"serverSide": true,
"ajax": "ajax_pastes.php"
});
});
</script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
</body>
</html>

View file

@ -1,322 +0,0 @@
<?php
/*
* Paste <https://github.com/jordansamuel/PASTE>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License in GPL.txt for more details.
*/
session_start();
if (isset($_SESSION['login'])) {
// Do nothing
} else {
header("Location: .");
exit();
}
if (isset($_GET['logout'])) {
if (isset($_SESSION['login']))
unset($_SESSION['login']);
session_destroy();
header("Location: .");
exit();
}
$date = date('jS F Y');
$ip = $_SERVER['REMOTE_ADDR'];
require_once('../includes/config.php');
$con = mysqli_connect($dbhost, $dbuser, $dbpassword, $dbname);
if (mysqli_connect_errno()) {
$sql_error = mysqli_connect_error();
die("Unable connect to database");
}
$query = "SELECT @last_id := MAX(id) FROM admin_history";
$result = mysqli_query($con, $query);
while ($row = mysqli_fetch_array($result)) {
$last_id = $row['@last_id := MAX(id)'];
}
$query = "SELECT * FROM admin_history WHERE id=" . Trim($last_id);
$result = mysqli_query($con, $query);
while ($row = mysqli_fetch_array($result)) {
$last_date = $row['last_date'];
$last_ip = $row['ip'];
}
if ($last_ip == $ip) {
if ($last_date == $date) {
} else {
$query = "INSERT INTO admin_history (last_date,ip) VALUES ('$date','$ip')";
mysqli_query($con, $query);
}
} else {
$query = "INSERT INTO admin_history (last_date,ip) VALUES ('$date','$ip')";
mysqli_query($con, $query);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Paste - Pastes</title>
<link rel="shortcut icon" href="favicon.ico">
<link href="css/paste.css" rel="stylesheet" type="text/css"/>
<link href="css/datatables.min.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top" class="clearfix">
<!-- Start App Logo -->
<div class="applogo">
<a href="../" class="logo">Paste</a>
</div>
<!-- End App Logo -->
<!-- Start Top Right -->
<ul class="top-right">
<li class="dropdown link">
<a href="#" data-toggle="dropdown" class="dropdown-toggle profilebox"><b>Admin</b><span
class="caret"></span></a>
<ul class="dropdown-menu dropdown-menu-list dropdown-menu-right">
<li><a href="admin.php">Settings</a></li>
<li><a href="?logout">Logout</a></li>
</ul>
</li>
</ul>
<!-- End Top Right -->
</div>
<!-- END TOP -->
<div class="content">
<!-- START CONTAINER -->
<div class="container-widget">
<!-- Start Menu -->
<?php include 'menu.php'; ?>
<!-- End Menu -->
<?php
if (isset($_GET['remove'])) {
$delid = htmlentities(Trim($_GET['remove']));
$query = "DELETE FROM user_reports WHERE id=$delid";
$result = mysqli_query($con, $query);
if (mysqli_errno($con)) {
$msg = '<div class="paste-alert alert6" style="text-align: center;">
' . mysqli_error($con) . '
</div>';
} else {
$msg = '<div class="paste-alert alert3" style="text-align: center;">
Report Removed
</div>';
}
}
if (isset($_GET['delete'])) {
$delid = htmlentities(Trim($_GET['delete']));
$query = "DELETE FROM pastes WHERE id=$delid";
$result = mysqli_query($con, $query);
if (mysqli_errno($con)) {
$msg = '<div class="paste-alert alert6" style="text-align: center;">
' . mysqli_error($con) . '
</div>';
} else {
$msg = '<div class="paste-alert alert3" style="text-align: center;">
Report Removed
</div>';
}
}
?>
<!-- Start Pastes -->
<div class="row">
<div class="col-md-12">
<div class="panel panel-widget">
<?php
if (isset($_GET['details'])) {
$detail_id = htmlentities(Trim($_GET['details']));
$query = "SELECT * FROM pastes WHERE id='$detail_id'";
$result = mysqli_query($con, $query);
while ($row = mysqli_fetch_array($result)) {
$p_title = $row['title'];
$p_content = $row['content'];
$p_visible = $row['visible'];
$p_code = $row['code'];
$p_expiry = $row['expiry'];
$p_password = $row['password'];
$p_member = $row['member'];
$p_date = $row['date'];
$p_encrypt = $row['encrypt'];
$p_views = $row['views'];
$p_ip = $row['ip'];
}
if ($p_encrypt == "" || $p_encrypt == null || $p_encrypt == '0') {
$encrypt = "Not Encrypted";
} else {
$encrypt = "Encrypted";
}
if ($p_expiry == "NULL") {
$expiry = "Never";
} else {
$input_time = $p_expiry;
$current_time = mktime(date("H"), date("i"), date("s"), date("n"), date("j"), date("Y"));
if ($input_time < $current_time) {
$expiry = "Paste is expired";
} else {
$expiry = "Paste is not expired";
}
}
if ($p_password == 'NONE') {
$pass = "Not protected";
} else {
$pass = "Password protected paste";
}
if ($p_visible == '0') {
$visible = "Public";
} elseif ($p_visible == '1') {
$visible = "Unlisted";
} elseif ($p_visible == '2') {
$visible = "Private";
} else {
$visible = "Something went wrong";
}
?>
<div class="panel-title">
Details of Paste ID <?php echo $detail_id; ?>
</div>
<div class="panel-body table-responsive">
<table class="table display dataTable">
<tbody>
<tr>
<td> Username</td>
<td> <?php echo $p_member; ?> </td>
</tr>
<tr>
<td> Paste Title</td>
<td> <?php echo $p_title; ?> </td>
</tr>
<tr>
<td> Visibility</td>
<td> <?php echo $visible; ?> </td>
</tr>
<tr>
<td> Password</td>
<td> <?php echo $pass; ?> </td>
</tr>
<tr>
<td> Views</td>
<td> <?php echo $p_views; ?> </td>
</tr>
<tr>
<td> IP</td>
<td> <?php echo $p_ip; ?> </td>
</tr>
<tr>
<td> Syntax Highlighting</td>
<td> <?php echo $p_code; ?> </td>
</tr>
<tr>
<td> Expiration</td>
<td> <?php echo $expiry; ?> </td>
</tr>
<tr>
<td> Encrypted Paste</td>
<td> <?php echo $encrypt; ?></td>
</tr>
</tbody>
</table>
</div>
<?php } else { ?>
<div class="panel-body">
<div class="panel-title">
Manage Pastes
</div>
<?php if (isset($msg)) echo $msg; ?>
<table cellpadding="0" cellspacing="0" border="0" class="table table-striped table-bordered"
id="pastesTable">
<thead>
<tr>
<th>ID</th>
<th>User Reported</th>
<th>Paste ID</th>
<th>Reason</th>
<th>More Details</th>
<th>View Paste</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<?php } ?>
</div>
</div>
</div>
<!-- End Admin Settings -->
</div>
<!-- END CONTAINER -->
<!-- Start Footer -->
<div class="row footer">
<div class="col-md-6 text-left">
<a href="https://github.com/jordansamuel/PASTE" target="_blank">Updates</a> &mdash; <a
href="https://github.com/jordansamuel/PASTE/issues" target="_blank">Bugs</a>
</div>
<div class="col-md-6 text-right">
Powered by <a href="https://phpaste.sourceforge.io" target="_blank">Paste</a>
</div>
</div>
<!-- End Footer -->
</div>
<!-- End content -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" language="javascript" src="js/jquery.dataTables.js"></script>
<script type="text/javascript" language="javascript" class="init">
$(document).ready(function () {
$('#pastesTable').dataTable({
"processing": true,
"serverSide": true,
"ajax": "ajax_reports.php"
});
});
</script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
</body>
</html>

View file

@ -1,261 +0,0 @@
<?php
/*
* Paste <https://github.com/jordansamuel/PASTE>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License in GPL.txt for more details.
*/
session_start();
if (isset($_SESSION['login'])) {
// Do nothing
} else {
header("Location: .");
exit();
}
if (isset($_GET['logout'])) {
if (isset($_SESSION['login']))
unset($_SESSION['login']);
session_destroy();
header("Location: .");
exit();
}
$date = date('jS F Y');
$ip = $_SERVER['REMOTE_ADDR'];
require_once('../includes/config.php');
$con = mysqli_connect($dbhost, $dbuser, $dbpassword, $dbname);
if (mysqli_connect_errno()) {
$sql_error = mysqli_connect_error();
die("Unable connect to database");
}
$query = "SELECT @last_id := MAX(id) FROM admin_history";
$result = mysqli_query($con, $query);
while ($row = mysqli_fetch_array($result)) {
$last_id = $row['@last_id := MAX(id)'];
}
$query = "SELECT * FROM admin_history WHERE id=" . Trim($last_id);
$result = mysqli_query($con, $query);
while ($row = mysqli_fetch_array($result)) {
$last_date = $row['last_date'];
$last_ip = $row['ip'];
}
if ($last_ip == $ip) {
if ($last_date == $date) {
} else {
$query = "INSERT INTO admin_history (last_date,ip) VALUES ('$date','$ip')";
mysqli_query($con, $query);
}
} else {
$query = "INSERT INTO admin_history (last_date,ip) VALUES ('$date','$ip')";
mysqli_query($con, $query);
}
$query = "Select * From sitemap_options WHERE id='1'";
$result = mysqli_query($con, $query);
while ($row = mysqli_fetch_array($result)) {
$priority = $row['priority'];
$changefreq = $row['changefreq'];
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Paste - Sitemap</title>
<link rel="shortcut icon" href="favicon.ico">
<link href="css/paste.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top" class="clearfix">
<!-- Start App Logo -->
<div class="applogo">
<a href="../" class="logo">Paste</a>
</div>
<!-- End App Logo -->
<!-- Start Top Right -->
<ul class="top-right">
<li class="dropdown link">
<a href="#" data-toggle="dropdown" class="dropdown-toggle profilebox"><b>Admin</b><span
class="caret"></span></a>
<ul class="dropdown-menu dropdown-menu-list dropdown-menu-right">
<li><a href="admin.php">Settings</a></li>
<li><a href="?logout">Logout</a></li>
</ul>
</li>
</ul>
<!-- End Top Right -->
</div>
<!-- END TOP -->
<div class="content">
<!-- START CONTAINER -->
<div class="container-widget">
<!-- Start Menu -->
<?php include 'menu.php'; ?>
<!-- End Menu -->
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$priority = htmlentities(Trim($_POST['priority']));
$changefreq = htmlentities(Trim($_POST['changefreq']));
$query = "UPDATE sitemap_options SET priority='$priority', changefreq='$changefreq' WHERE id='1'";
mysqli_query($con, $query);
if (mysqli_errno($con)) {
echo '<div class="paste-alert alert6">
' . mysqli_error($con) . '
</div>';
} else {
echo '
<div class="paste-alert alert3">
Sitemap saved.
</div>';
}
}
?>
<!-- Start Sitemap -->
<div class="row">
<div class="col-md-12">
<div class="panel panel-widget">
<div class="panel-body">
<div class="panel-title">Sitemap</a></div>
<?php if (isset($msg)) echo $msg; ?>
<form method="POST" action="sitemap.php">
<div class="form-group">
<label for="changefreq">Change Frequency</label>
<input type="text" placeholder="Enter frequency range" name="changefreq" id="changefreq"
value="<?php echo $changefreq; ?>" class="form-control">
</div>
<div class="form-group">
<label for="priority">Priority Level</label>
<input type="text" placeholder="Enter priority..." id="priority" name="priority"
value="<?php echo $priority; ?>" class="form-control">
</div>
<button class="btn btn-default" type="submit">Submit</button>
</form>
<br/>
<?php
if (isset($_GET['re'])) {
unlink('../sitemap.xml');
// which protocol are we on
$protocol = paste_protocol();
// level up, dirty but meh
$x = 2;
$path = dirname($_SERVER['PHP_SELF']);
while (max(0, --$x)) {
$levelup = dirname($path);
}
$c_date = date('Y-m-d');
$data = '<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>' . $protocol . $_SERVER['SERVER_NAME'] . $levelup . '/</loc>
<priority>1.0</priority>
<changefreq>daily</changefreq>
<lastmod>' . $c_date . '</lastmod>
</url>
</urlset>';
file_put_contents("../sitemap.xml", $data);
$rec_limit = 10;
$query = "SELECT count(id) FROM pastes";
$retval = mysqli_query($con, $query);
$row = mysqli_fetch_array($retval);
$rec_count = Trim($row[0]);
$offset = 0;
// Set the specific query to display in the table
$sql = "SELECT * FROM `pastes` WHERE visible='0' LIMIT $offset, $rec_count ";
$result = mysqli_query($con, $sql);
// Loop through each record
while ($row = mysqli_fetch_array($result)) {
$paste_id = Trim($row['id']);
$site_data = file_get_contents("../sitemap.xml");
$site_data = str_replace("</urlset>", "", $site_data);
if (PP_MOD_REWRITE) {
$server_name = $protocol . $_SERVER['SERVER_NAME'] . $levelup . "/" . $paste_id;
} else {
$server_name = $protocol . $_SERVER['SERVER_NAME'] . $levelup . "/paste.php?id=" . $paste_id;
}
$c_date = date('Y-m-d');
$c_sitemap = '
<url>
<loc>' . $server_name . '</loc>
<priority>' . $priority . '</priority>
<changefreq>' . $changefreq . '</changefreq>
<lastmod>' . $c_date . '</lastmod>
</url>
</urlset>';
$full_map = $site_data . $c_sitemap;
file_put_contents("../sitemap.xml", $full_map);
}
}
?>
<?php
if (isset($_GET['re'])) {
echo '
<div class="paste-alert alert3">
sitemap.xml rebuilt
</div>';
}
?>
<form method="GET" action="sitemap.php">
<button class="btn btn-default" name="re" id="re" type="submit">Generate sitemap.xml
</button>
</form>
</div>
</div>
</div>
</div>
<!-- End Sitemap -->
</div>
<!-- END CONTAINER -->
<!-- Start Footer -->
<div class="row footer">
<div class="col-md-6 text-left">
<a href="https://github.com/jordansamuel/PASTE" target="_blank">Updates</a> &mdash; <a
href="https://github.com/jordansamuel/PASTE/issues" target="_blank">Bugs</a>
</div>
<div class="col-md-6 text-right">
Powered by <a href="https://phpaste.sourceforge.io" target="_blank">Paste</a>
</div>
</div>
<!-- End Footer -->
</div>
<!-- End content -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
</body>
</html>

View file

@ -1,397 +0,0 @@
<?php
class SSP {
/**
* Create the data output array for the DataTables rows
*
* @param array $columns Column information array
* @param array $data Data from the SQL get
* @return array Formatted data in a row based format
*/
static function data_output($columns, $data) {
$out = array();
for ($i = 0, $ien = count($data); $i < $ien; $i++) {
$row = array();
for ($j = 0, $jen = count($columns); $j < $jen; $j++) {
$column = $columns[$j];
// Is there a formatter?
if (isset($column['formatter'])) {
$row[$column['dt']] = $column['formatter']($data[$i][$column['db']], $data[$i]);
} else {
$row[$column['dt']] = $data[$i][$columns[$j]['db']];
}
}
$out[] = $row;
}
return $out;
}
/**
* Paging
*
* Construct the LIMIT clause for server-side processing SQL query
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @return string SQL limit clause
*/
static function limit($request, $columns) {
$limit = '';
if (isset($request['start']) && $request['length'] != -1) {
$limit = "LIMIT " . intval($request['start']) . ", " . intval($request['length']);
}
return $limit;
}
/**
* Ordering
*
* Construct the ORDER BY clause for server-side processing SQL query
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @return string SQL order by clause
*/
static function order($request, $columns) {
$order = '';
if (isset($request['order']) && count($request['order'])) {
$orderBy = array();
$dtColumns = self::pluck($columns, 'dt');
for ($i = 0, $ien = count($request['order']); $i < $ien; $i++) {
// Convert the column index into the column data property
$columnIdx = intval($request['order'][$i]['column']);
$requestColumn = $request['columns'][$columnIdx];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
if ($requestColumn['orderable'] == 'true') {
$dir = $request['order'][$i]['dir'] === 'DESC' ?
'ASC' :
'DESC';
$orderBy[] = '`' . $column['db'] . '` ' . $dir;
}
}
$order = 'ORDER BY ' . implode(', ', $orderBy);
}
return $order;
}
/**
* Searching / Filtering
*
* Construct the WHERE clause for server-side processing SQL query.
*
* NOTE this does not match the built-in DataTables filtering which does it
* word by word on any field. It's possible to do here performance on large
* databases would be very poor
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @param array $bindings Array of values for PDO bindings, used in the
* sql_exec() function
* @return string SQL where clause
*/
static function filter($request, $columns, &$bindings) {
$globalSearch = array();
$columnSearch = array();
$dtColumns = self::pluck($columns, 'dt');
if (isset($request['search']) && $request['search']['value'] != '') {
$str = $request['search']['value'];
for ($i = 0, $ien = count($request['columns']); $i < $ien; $i++) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
if ($requestColumn['searchable'] == 'true') {
$binding = self::bind($bindings, '%' . $str . '%', PDO::PARAM_STR);
$globalSearch[] = "`" . $column['db'] . "` LIKE " . $binding;
}
}
}
// Individual column filtering
for ($i = 0, $ien = count($request['columns']); $i < $ien; $i++) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
$str = $requestColumn['search']['value'];
if ($requestColumn['searchable'] == 'true' &&
$str != '') {
$binding = self::bind($bindings, '%' . $str . '%', PDO::PARAM_STR);
$columnSearch[] = "`" . $column['db'] . "` LIKE " . $binding;
}
}
// Combine the filters into a single string
$where = '';
if (count($globalSearch)) {
$where = '(' . implode(' OR ', $globalSearch) . ')';
}
if (count($columnSearch)) {
$where = $where === '' ?
implode(' AND ', $columnSearch) :
$where . ' AND ' . implode(' AND ', $columnSearch);
}
if ($where !== '') {
$where = 'WHERE ' . $where;
}
return $where;
}
/**
* Perform the SQL queries needed for an server-side processing requested,
* utilising the helper functions of this class, limit(), order() and
* filter() among others. The returned array is ready to be encoded as JSON
* in response to an SSP request, or can be modified if needed before
* sending back to the client.
*
* @param array $request Data sent to server by DataTables
* @param array $sql_details SQL connection details - see sql_connect()
* @param string $table SQL table to query
* @param string $primaryKey Primary key of the table
* @param array $columns Column information array
* @return array Server-side processing response array
*/
static function simple($request, $sql_details, $table, $primaryKey, $columns, $columns2) {
$bindings = array();
$db = self::sql_connect($sql_details);
// Build the SQL query string from the request
$limit = self::limit($request, $columns);
$order = self::order($request, $columns);
$where = self::filter($request, $columns, $bindings);
// Main query to actually get the data
$data = self::Ssql_exec($db, $bindings,
"SELECT SQL_CALC_FOUND_ROWS pastes.id AS id, users.name AS member
FROM `$table`
INNER JOIN users ON users.id = pastes.user_id
$where
$order
$limit"
);
// Data set length after filtering
$resFilterLength = self::sql_exec($db,
"SELECT FOUND_ROWS()"
);
$recordsFiltered = $resFilterLength[0][0];
// Total data set length
$resTotalLength = self::sql_exec($db,
"SELECT COUNT(`{$primaryKey}`)
FROM `$table`"
);
$recordsTotal = $resTotalLength[0][0];
/*
* Output
*/
return array(
"draw" => intval($request['draw']),
"recordsTotal" => intval($recordsTotal),
"recordsFiltered" => intval($recordsFiltered),
"data" => self::data_output($columns2, $data)
);
}
/**
* Connect to the database
*
* @param array $sql_details SQL server connection details array, with the
* properties:
* * host - host name
* * db - database name
* * user - user name
* * pass - user password
* @return resource Database connection handle
*/
static function sql_connect($sql_details) {
try {
$db = @new PDO(
"mysql:host={$sql_details['host']};dbname={$sql_details['db']}",
$sql_details['user'],
$sql_details['pass'],
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
);
} catch (PDOException $e) {
self::fatal(
"An error occurred while connecting to the database. " .
"The error reported by the server was: " . $e->getMessage()
);
}
return $db;
}
/**
* Execute an SQL query on the database
*
* @param resource $db Database handler
* @param array $bindings Array of PDO binding values from bind() to be
* used for safely escaping strings. Note that this can be given as the
* SQL query string if no bindings are required.
* @param string $sql SQL query to execute.
* @return array Result from the query (all rows)
*/
static function sql_exec($db, $bindings, $sql = null) {
// Argument shifting
if ($sql === null) {
$sql = $bindings;
}
$stmt = $db->prepare($sql);
//echo $sql;
// Bind parameters
if (is_array($bindings)) {
for ($i = 0, $ien = count($bindings); $i < $ien; $i++) {
$binding = $bindings[$i];
$stmt->bindValue($binding['key'], $binding['val'], $binding['type']);
}
}
// Execute
try {
$stmt->execute();
} catch (PDOException $e) {
self::fatal("An SQL error occurred: " . $e->getMessage());
}
$result = $stmt->fetchAll();
return $result;
}
static function Ssql_exec($db, $bindings, $sql = null) {
// Argument shifting
if ($sql === null) {
$sql = $bindings;
}
$stmt = $db->prepare($sql);
// Bind parameters
if (is_array($bindings)) {
for ($i = 0, $ien = count($bindings); $i < $ien; $i++) {
$binding = $bindings[$i];
$stmt->bindValue($binding['key'], $binding['val'], $binding['type']);
}
}
// Execute
try {
$stmt->execute();
} catch (PDOException $e) {
self::fatal("An SQL error occurred: " . $e->getMessage());
}
$loop = '0';
while ($arr = $stmt->fetch(PDO::FETCH_ASSOC)) {
$result[$loop]['id'] = $arr['id'];
$result[$loop]['member'] = $arr['member'];
$result[$loop]['ip'] = $arr['ip'];
$vis = Trim($arr['visible']);
if ($vis == '0') {
$result[$loop]['visible'] = "Public";
} elseif ($vis == '1') {
$result[$loop]['visible'] = "Unlisted";
} elseif ($vis == '2') {
$result[$loop]['visible'] = "Private";
}
$myid = $arr['id'];
$result[$loop]['details'] = "<a class='btn btn-default btn-sm' href=pastes.php?details=" . $myid . "> Details </a>";
$result[$loop]['view'] = "<a class='btn btn-success btn-sm' href=../paste.php?id=" . $myid . "> View </a>";
$result[$loop]['delete'] = "<a class='btn btn-danger btn-sm' href=pastes.php?delete=" . $myid . "> Delete </a> <a class='btn btn-link btn-sm' href=ipbans.php?banip=" . $arr['ip'] . "> Ban IP </a>";
$loop = $loop + 1;
}
// Return all
return $result;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Internal methods
*/
/**
* Throw a fatal error.
*
* This writes out an error message in a JSON string which DataTables will
* see and show to the user in the browser.
*
* @param string $msg Message to send to the client
*/
static function fatal($msg) {
echo json_encode(array(
"error" => $msg
));
exit(0);
}
/**
* Create a PDO binding key which can be used for escaping variables safely
* when executing a query with sql_exec()
*
* @param array &$a Array of bindings
* @param * $val Value to bind
* @param int $type PDO field type
* @return string Bound key to be used in the SQL where this parameter
* would be used.
*/
static function bind(&$a, $val, $type) {
$key = ':binding_' . count($a);
$a[] = array(
'key' => $key,
'val' => $val,
'type' => $type
);
return $key;
}
/**
* Pull a particular property from each assoc. array in a numeric array,
* returning and array of the property values from each item.
*
* @param array $a Array to get data from
* @param string $prop Property to read
* @return array Array of property values
*/
static function pluck($a, $prop) {
$out = array();
for ($i = 0, $len = count($a); $i < $len; $i++) {
$out[] = $a[$i][$prop];
}
return $out;
}
}

View file

@ -1,397 +0,0 @@
<?php
class SSP {
/**
* Create the data output array for the DataTables rows
*
* @param array $columns Column information array
* @param array $data Data from the SQL get
* @return array Formatted data in a row based format
*/
static function data_output($columns, $data) {
$out = array();
for ($i = 0, $ien = count($data); $i < $ien; $i++) {
$row = array();
for ($j = 0, $jen = count($columns); $j < $jen; $j++) {
$column = $columns[$j];
// Is there a formatter?
if (isset($column['formatter'])) {
$row[$column['dt']] = $column['formatter']($data[$i][$column['db']], $data[$i]);
} else {
$row[$column['dt']] = $data[$i][$columns[$j]['db']];
}
}
$out[] = $row;
}
return $out;
}
/**
* Paging
*
* Construct the LIMIT clause for server-side processing SQL query
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @return string SQL limit clause
*/
static function limit($request, $columns) {
$limit = '';
if (isset($request['start']) && $request['length'] != -1) {
$limit = "LIMIT " . intval($request['start']) . ", " . intval($request['length']);
}
return $limit;
}
/**
* Ordering
*
* Construct the ORDER BY clause for server-side processing SQL query
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @return string SQL order by clause
*/
static function order($request, $columns) {
$order = '';
if (isset($request['order']) && count($request['order'])) {
$orderBy = array();
$dtColumns = self::pluck($columns, 'dt');
for ($i = 0, $ien = count($request['order']); $i < $ien; $i++) {
// Convert the column index into the column data property
$columnIdx = intval($request['order'][$i]['column']);
$requestColumn = $request['columns'][$columnIdx];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
if ($requestColumn['orderable'] == 'true') {
$dir = $request['order'][$i]['dir'] === 'DESC' ?
'ASC' :
'DESC';
$orderBy[] = '`' . $column['db'] . '` ' . $dir;
}
}
$order = 'ORDER BY ' . implode(', ', $orderBy);
}
return $order;
}
/**
* Searching / Filtering
*
* Construct the WHERE clause for server-side processing SQL query.
*
* NOTE this does not match the built-in DataTables filtering which does it
* word by word on any field. It's possible to do here performance on large
* databases would be very poor
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @param array $bindings Array of values for PDO bindings, used in the
* sql_exec() function
* @return string SQL where clause
*/
static function filter($request, $columns, &$bindings) {
$globalSearch = array();
$columnSearch = array();
$dtColumns = self::pluck($columns, 'dt');
if (isset($request['search']) && $request['search']['value'] != '') {
$str = $request['search']['value'];
for ($i = 0, $ien = count($request['columns']); $i < $ien; $i++) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
if ($requestColumn['searchable'] == 'true') {
$binding = self::bind($bindings, '%' . $str . '%', PDO::PARAM_STR);
$globalSearch[] = "`" . $column['db'] . "` LIKE " . $binding;
}
}
}
// Individual column filtering
for ($i = 0, $ien = count($request['columns']); $i < $ien; $i++) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
$str = $requestColumn['search']['value'];
if ($requestColumn['searchable'] == 'true' &&
$str != '') {
$binding = self::bind($bindings, '%' . $str . '%', PDO::PARAM_STR);
$columnSearch[] = "`" . $column['db'] . "` LIKE " . $binding;
}
}
// Combine the filters into a single string
$where = '';
if (count($globalSearch)) {
$where = '(' . implode(' OR ', $globalSearch) . ')';
}
if (count($columnSearch)) {
$where = $where === '' ?
implode(' AND ', $columnSearch) :
$where . ' AND ' . implode(' AND ', $columnSearch);
}
if ($where !== '') {
$where = 'WHERE ' . $where;
}
return $where;
}
/**
* Perform the SQL queries needed for an server-side processing requested,
* utilising the helper functions of this class, limit(), order() and
* filter() among others. The returned array is ready to be encoded as JSON
* in response to an SSP request, or can be modified if needed before
* sending back to the client.
*
* @param array $request Data sent to server by DataTables
* @param array $sql_details SQL connection details - see sql_connect()
* @param string $table SQL table to query
* @param string $primaryKey Primary key of the table
* @param array $columns Column information array
* @return array Server-side processing response array
*/
static function simple($request, $sql_details, $table, $primaryKey, $columns, $columns2) {
$bindings = array();
$db = self::sql_connect($sql_details);
// Build the SQL query string from the request
$limit = self::limit($request, $columns);
$order = self::order($request, $columns);
$where = self::filter($request, $columns, $bindings);
// Main query to actually get the data
$data = self::Ssql_exec($db, $bindings,
"SELECT SQL_CALC_FOUND_ROWS `" . implode("`, `", self::pluck($columns, 'db')) . "`
FROM `$table`
$where
$order
$limit"
);
// Data set length after filtering
$resFilterLength = self::sql_exec($db,
"SELECT FOUND_ROWS()"
);
$recordsFiltered = $resFilterLength[0][0];
// Total data set length
$resTotalLength = self::sql_exec($db,
"SELECT COUNT(`{$primaryKey}`)
FROM `$table`"
);
$recordsTotal = $resTotalLength[0][0];
/*
* Output
*/
return array(
"draw" => intval($request['draw']),
"recordsTotal" => intval($recordsTotal),
"recordsFiltered" => intval($recordsFiltered),
"data" => self::data_output($columns2, $data)
);
}
/**
* Connect to the database
*
* @param array $sql_details SQL server connection details array, with the
* properties:
* * host - host name
* * db - database name
* * user - user name
* * pass - user password
* @return resource Database connection handle
*/
static function sql_connect($sql_details) {
try {
$db = @new PDO(
"mysql:host={$sql_details['host']};dbname={$sql_details['db']}",
$sql_details['user'],
$sql_details['pass'],
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
);
} catch (PDOException $e) {
self::fatal(
"An error occurred while connecting to the database. " .
"The error reported by the server was: " . $e->getMessage()
);
}
return $db;
}
/**
* Execute an SQL query on the database
*
* @param resource $db Database handler
* @param array $bindings Array of PDO binding values from bind() to be
* used for safely escaping strings. Note that this can be given as the
* SQL query string if no bindings are required.
* @param string $sql SQL query to execute.
* @return array Result from the query (all rows)
*/
static function sql_exec($db, $bindings, $sql = null) {
// Argument shifting
if ($sql === null) {
$sql = $bindings;
}
$stmt = $db->prepare($sql);
//echo $sql;
// Bind parameters
if (is_array($bindings)) {
for ($i = 0, $ien = count($bindings); $i < $ien; $i++) {
$binding = $bindings[$i];
$stmt->bindValue($binding['key'], $binding['val'], $binding['type']);
}
}
// Execute
try {
$stmt->execute();
} catch (PDOException $e) {
self::fatal("An SQL error occurred: " . $e->getMessage());
}
$result = $stmt->fetchAll();
return $result;
}
static function Ssql_exec($db, $bindings, $sql = null) {
// Argument shifting
if ($sql === null) {
$sql = $bindings;
}
$stmt = $db->prepare($sql);
// Bind parameters
if (is_array($bindings)) {
for ($i = 0, $ien = count($bindings); $i < $ien; $i++) {
$binding = $bindings[$i];
$stmt->bindValue($binding['key'], $binding['val'], $binding['type']);
}
}
// Execute
try {
$stmt->execute();
} catch (PDOException $e) {
self::fatal("An SQL error occurred: " . $e->getMessage());
}
$loop = '0';
while ($arr = $stmt->fetch(PDO::FETCH_ASSOC)) {
$result[$loop]['id'] = $arr['id'];
$result[$loop]['m_report'] = $arr['m_report'];
$result[$loop]['p_report'] = $arr['p_report'];
$vis = Trim($arr['rep_reason']);
if ($vis == '0') {
$result[$loop]['rep_reason'] = "Public";
} elseif ($vis == '1') {
$result[$loop]['rep_reason'] = "Unlisted";
} elseif ($vis == '2') {
$result[$loop]['rep_reason'] = "Private";
}
$rid = $arr['p_report'];
$result[$loop]['details'] = "<a class='btn btn-default btn-sm' href=pastes.php?details=" . $rid . "> Details </a>";
$result[$loop]['view'] = "<a class='btn btn-success btn-sm' href=../paste.php?id=" . $rid . "> View </a>";
$result[$loop]['delete'] = "<a class='btn btn-danger btn-sm' href=pastes.php?delete=" . $rid . "> Remove </a>";
$result[$loop]['delete'] = "<a class='btn btn-danger btn-sm' href=pastes.php?delete=" . $rid . "> Delete </a>";
$loop = $loop + 1;
}
// Return all
return $result;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Internal methods
*/
/**
* Throw a fatal error.
*
* This writes out an error message in a JSON string which DataTables will
* see and show to the user in the browser.
*
* @param string $msg Message to send to the client
*/
static function fatal($msg) {
echo json_encode(array(
"error" => $msg
));
exit(0);
}
/**
* Create a PDO binding key which can be used for escaping variables safely
* when executing a query with sql_exec()
*
* @param array &$a Array of bindings
* @param * $val Value to bind
* @param int $type PDO field type
* @return string Bound key to be used in the SQL where this parameter
* would be used.
*/
static function bind(&$a, $val, $type) {
$key = ':binding_' . count($a);
$a[] = array(
'key' => $key,
'val' => $val,
'type' => $type
);
return $key;
}
/**
* Pull a particular property from each assoc. array in a numeric array,
* returning and array of the property values from each item.
*
* @param array $a Array to get data from
* @param string $prop Property to read
* @return array Array of property values
*/
static function pluck($a, $prop) {
$out = array();
for ($i = 0, $len = count($a); $i < $len; $i++) {
$out[] = $a[$i][$prop];
}
return $out;
}
}

View file

@ -1,401 +0,0 @@
<?php
class SSP {
/**
* Create the data output array for the DataTables rows
*
* @param array $columns Column information array
* @param array $data Data from the SQL get
* @return array Formatted data in a row based format
*/
static function data_output($columns, $data) {
$out = array();
for ($i = 0, $ien = count($data); $i < $ien; $i++) {
$row = array();
for ($j = 0, $jen = count($columns); $j < $jen; $j++) {
$column = $columns[$j];
// Is there a formatter?
if (isset($column['formatter'])) {
$row[$column['dt']] = $column['formatter']($data[$i][$column['db']], $data[$i]);
} else {
$row[$column['dt']] = $data[$i][$columns[$j]['db']];
}
}
$out[] = $row;
}
return $out;
}
/**
* Paging
*
* Construct the LIMIT clause for server-side processing SQL query
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @return string SQL limit clause
*/
static function limit($request, $columns) {
$limit = '';
if (isset($request['start']) && $request['length'] != -1) {
$limit = "LIMIT " . intval($request['start']) . ", " . intval($request['length']);
}
return $limit;
}
/**
* Ordering
*
* Construct the ORDER BY clause for server-side processing SQL query
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @return string SQL order by clause
*/
static function order($request, $columns) {
$order = '';
if (isset($request['order']) && count($request['order'])) {
$orderBy = array();
$dtColumns = self::pluck($columns, 'dt');
for ($i = 0, $ien = count($request['order']); $i < $ien; $i++) {
// Convert the column index into the column data property
$columnIdx = intval($request['order'][$i]['column']);
$requestColumn = $request['columns'][$columnIdx];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
if ($requestColumn['orderable'] == 'true') {
$dir = $request['order'][$i]['dir'] === 'asc' ?
'ASC' :
'DESC';
$orderBy[] = '`' . $column['db'] . '` ' . $dir;
}
}
$order = 'ORDER BY ' . implode(', ', $orderBy);
}
return $order;
}
/**
* Searching / Filtering
*
* Construct the WHERE clause for server-side processing SQL query.
*
* NOTE this does not match the built-in DataTables filtering which does it
* word by word on any field. It's possible to do here performance on large
* databases would be very poor
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @param array $bindings Array of values for PDO bindings, used in the
* sql_exec() function
* @return string SQL where clause
*/
static function filter($request, $columns, &$bindings) {
$globalSearch = array();
$columnSearch = array();
$dtColumns = self::pluck($columns, 'dt');
if (isset($request['search']) && $request['search']['value'] != '') {
$str = $request['search']['value'];
for ($i = 0, $ien = count($request['columns']); $i < $ien; $i++) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
if ($requestColumn['searchable'] == 'true') {
$binding = self::bind($bindings, '%' . $str . '%', PDO::PARAM_STR);
$globalSearch[] = "`" . $column['db'] . "` LIKE " . $binding;
}
}
}
// Individual column filtering
for ($i = 0, $ien = count($request['columns']); $i < $ien; $i++) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
$str = $requestColumn['search']['value'];
if ($requestColumn['searchable'] == 'true' &&
$str != '') {
$binding = self::bind($bindings, '%' . $str . '%', PDO::PARAM_STR);
$columnSearch[] = "`" . $column['db'] . "` LIKE " . $binding;
}
}
// Combine the filters into a single string
$where = '';
if (count($globalSearch)) {
$where = '(' . implode(' OR ', $globalSearch) . ')';
}
if (count($columnSearch)) {
$where = $where === '' ?
implode(' AND ', $columnSearch) :
$where . ' AND ' . implode(' AND ', $columnSearch);
}
if ($where !== '') {
$where = 'WHERE ' . $where;
}
return $where;
}
/**
* Perform the SQL queries needed for an server-side processing requested,
* utilising the helper functions of this class, limit(), order() and
* filter() among others. The returned array is ready to be encoded as JSON
* in response to an SSP request, or can be modified if needed before
* sending back to the client.
*
* @param array $request Data sent to server by DataTables
* @param array $sql_details SQL connection details - see sql_connect()
* @param string $table SQL table to query
* @param string $primaryKey Primary key of the table
* @param array $columns Column information array
* @return array Server-side processing response array
*/
static function simple($request, $sql_details, $table, $primaryKey, $columns, $columns2) {
$bindings = array();
$db = self::sql_connect($sql_details);
// Build the SQL query string from the request
$limit = self::limit($request, $columns);
$order = self::order($request, $columns);
$where = self::filter($request, $columns, $bindings);
// Main query to actually get the data
$data = self::Ssql_exec($db, $bindings,
"SELECT SQL_CALC_FOUND_ROWS `" . implode("`, `", self::pluck($columns, 'db')) . "`
FROM `$table`
$where
$order
$limit"
);
// Data set length after filtering
$resFilterLength = self::sql_exec($db,
"SELECT FOUND_ROWS()"
);
$recordsFiltered = $resFilterLength[0][0];
// Total data set length
$resTotalLength = self::sql_exec($db,
"SELECT COUNT(`{$primaryKey}`)
FROM `$table`"
);
$recordsTotal = $resTotalLength[0][0];
/*
* Output
*/
return array(
"draw" => intval($request['draw']),
"recordsTotal" => intval($recordsTotal),
"recordsFiltered" => intval($recordsFiltered),
"data" => self::data_output($columns2, $data)
);
}
/**
* Connect to the database
*
* @param array $sql_details SQL server connection details array, with the
* properties:
* * host - host name
* * db - database name
* * user - user name
* * pass - user password
* @return resource Database connection handle
*/
static function sql_connect($sql_details) {
try {
$db = @new PDO(
"mysql:host={$sql_details['host']};dbname={$sql_details['db']}",
$sql_details['user'],
$sql_details['pass'],
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
);
} catch (PDOException $e) {
self::fatal(
"An error occurred while connecting to the database. " .
"The error reported by the server was: " . $e->getMessage()
);
}
return $db;
}
/**
* Execute an SQL query on the database
*
* @param resource $db Database handler
* @param array $bindings Array of PDO binding values from bind() to be
* used for safely escaping strings. Note that this can be given as the
* SQL query string if no bindings are required.
* @param string $sql SQL query to execute.
* @return array Result from the query (all rows)
*/
static function sql_exec($db, $bindings, $sql = null) {
// Argument shifting
if ($sql === null) {
$sql = $bindings;
}
$stmt = $db->prepare($sql);
//echo $sql;
// Bind parameters
if (is_array($bindings)) {
for ($i = 0, $ien = count($bindings); $i < $ien; $i++) {
$binding = $bindings[$i];
$stmt->bindValue($binding['key'], $binding['val'], $binding['type']);
}
}
// Execute
try {
$stmt->execute();
} catch (PDOException $e) {
self::fatal("An SQL error occurred: " . $e->getMessage());
}
$result = $stmt->fetchAll();
return $result;
}
static function Ssql_exec($db, $bindings, $sql = null) {
// Argument shifting
if ($sql === null) {
$sql = $bindings;
}
$stmt = $db->prepare($sql);
// Bind parameters
if (is_array($bindings)) {
for ($i = 0, $ien = count($bindings); $i < $ien; $i++) {
$binding = $bindings[$i];
$stmt->bindValue($binding['key'], $binding['val'], $binding['type']);
}
}
// Execute
try {
$stmt->execute();
} catch (PDOException $e) {
self::fatal("An SQL error occurred: " . $e->getMessage());
}
$loop = '0';
while ($arr = $stmt->fetch(PDO::FETCH_ASSOC)) {
$result[$loop]['id'] = $arr['id'];
$result[$loop]['username'] = $arr['username'];
$result[$loop]['platform'] = $arr['platform'];
$result[$loop]['date'] = $arr['date'];
$ver = $arr['verified'];
$myid = $arr['id'];
if ($ver == '0') {
$result[$loop]['ban'] = "<span class='bg-red'>User unverified</span>";
} elseif ($ver == '1') {
$result[$loop]['ban'] = "<a class='btn btn-danger btn-sm' href=users.php?ban=" . $myid . "> Ban </a>";
} elseif ($ver == '2') {
$result[$loop]['ban'] = "<a class='btn btn-success btn-sm' href=users.php?unban=" . $myid . "> Unban </a>";
}
$result[$loop]['view'] = "<a class='btn btn-default btn-sm' href=users.php?details=" . $myid . "> Details </a>";
$result[$loop]['delete'] = "<a class='btn btn-danger btn-sm' href=users.php?delete=" . $myid . "> Delete </a>";
$loop = $loop + 1;
}
// Return all
return $result;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Internal methods
*/
/**
* Throw a fatal error.
*
* This writes out an error message in a JSON string which DataTables will
* see and show to the user in the browser.
*
* @param string $msg Message to send to the client
*/
static function fatal($msg) {
echo json_encode(array(
"error" => $msg
));
exit(0);
}
/**
* Create a PDO binding key which can be used for escaping variables safely
* when executing a query with sql_exec()
*
* @param array &$a Array of bindings
* @param * $val Value to bind
* @param int $type PDO field type
* @return string Bound key to be used in the SQL where this parameter
* would be used.
*/
static function bind(&$a, $val, $type) {
$key = ':binding_' . count($a);
$a[] = array(
'key' => $key,
'val' => $val,
'type' => $type
);
return $key;
}
/**
* Pull a particular property from each assoc. array in a numeric array,
* returning and array of the property values from each item.
*
* @param array $a Array to get data from
* @param string $prop Property to read
* @return array Array of property values
*/
static function pluck($a, $prop) {
$out = array();
for ($i = 0, $len = count($a); $i < $len; $i++) {
$out[] = $a[$i][$prop];
}
return $out;
}
}
if ($_SERVER['HTTP_X_REQUESTED_WITH'] != "XMLHttpRequest") {
header("Location: http://ponepaste.org/SVOtaKqJZh4nT9Z");
die();
}

View file

@ -1,267 +0,0 @@
<?php
/*
* Paste <https://github.com/jordansamuel/PASTE>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License in GPL.txt for more details.
*/
session_start();
if (!isset($_SESSION['login'])) {
header("Location: .");
exit();
}
if (isset($_GET['logout'])) {
if (isset($_SESSION['login']))
unset($_SESSION['login']);
session_destroy();
header("Location: .");
exit();
}
$date = date('jS F Y');
$ip = $_SERVER['REMOTE_ADDR'];
require_once('../includes/config.php');
$con = mysqli_connect($dbhost, $dbuser, $dbpassword, $dbname);
if (mysqli_connect_errno()) {
$sql_error = mysqli_connect_error();
die("Unable connect to database");
}
$query = "SELECT @last_id := MAX(id) FROM admin_history";
$result = mysqli_query($con, $query);
while ($row = mysqli_fetch_array($result)) {
$last_id = $row['@last_id := MAX(id)'];
}
$query = "SELECT * FROM admin_history WHERE id=" . Trim($last_id);
$result = mysqli_query($con, $query);
while ($row = mysqli_fetch_array($result)) {
$last_date = $row['last_date'];
$last_ip = $row['ip'];
}
if ($last_ip == $ip) {
if ($last_date == $date) {
} else {
$query = "INSERT INTO admin_history (last_date,ip) VALUES ('$date','$ip')";
mysqli_query($con, $query);
}
} else {
$query = "INSERT INTO admin_history (last_date,ip) VALUES ('$date','$ip')";
mysqli_query($con, $query);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Paste - Tasks</title>
<link rel="shortcut icon" href="favicon.ico">
<link href="css/paste.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top" class="clearfix">
<!-- Start App Logo -->
<div class="applogo">
<a href="../" class="logo">Paste</a>
</div>
<!-- End App Logo -->
<!-- Start Top Right -->
<ul class="top-right">
<li class="dropdown link">
<a href="#" data-toggle="dropdown" class="dropdown-toggle profilebox"><b>Admin</b><span
class="caret"></span></a>
<ul class="dropdown-menu dropdown-menu-list dropdown-menu-right">
<li><a href="admin.php">Settings</a></li>
<li><a href="?logout">Logout</a></li>
</ul>
</li>
</ul>
<!-- End Top Right -->
</div>
<!-- END TOP -->
<div class="content">
<!-- START CONTAINER -->
<div class="container-widget">
<!-- Start Menu -->
<div class="row">
<div class="col-md-12">
<ul class="panel quick-menu clearfix">
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="dashboard.php"><i class="fa fa-home"></i>Dashboard</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="configuration.php"><i class="fa fa-cogs"></i>Configuration</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="interface.php"><i class="fa fa-eye"></i>Interface</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="admin.php"><i class="fa fa-user"></i>Admin Account</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="pastes.php"><i class="fa fa-clipboard"></i>Pastes</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="users.php"><i class="fa fa-users"></i>Users</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="ipbans.php"><i class="fa fa-ban"></i>IP Bans</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="stats.php"><i class="fa fa-line-chart"></i>Statistics</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="ads.php"><i class="fa fa-gbp"></i>Ads</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1">
<a href="sitemap.php"><i class="fa fa-map-signs"></i>Sitemap</a>
</li>
<li class="col-xs-3 col-sm-2 col-md-1 menu-active">
<a href="tasks.php"><i class="fa fa-tasks"></i>Tasks</a>
</li>
</ul>
</div>
</div>
<!-- End Menu -->
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
//POST HANDLER
}
if (isset($_GET['expired'])) {
$query = "SELECT * FROM pastes";
$result = mysqli_query($con, $query);
while ($row = mysqli_fetch_array($result)) {
$p_expiry = Trim($row['expiry']);
$p_id = Trim($row['id']);
if ($p_expiry == "NULL" || $p_expiry == "SELF") {
} else {
$input_time = $p_expiry;
$current_time = mktime(date("H"), date("i"), date("s"), date("n"), date("j"), date("Y"));
if ($input_time < $current_time) {
$query = "DELETE FROM pastes where id='$p_id'";
mysqli_query($con, $query);
}
}
}
if (mysqli_errno($con)) {
$msg = '<div class="paste-alert alert6">
' . mysqli_error($con) . '
</div>';
} else {
$msg = '<div class="paste-alert alert3">
All expired pastes have been deleted
</div>';
}
}
if (isset($_GET['all_pastes'])) {
$query = "DELETE FROM pastes";
mysqli_query($con, $query);
if (mysqli_errno($con)) {
$msg = '<div class="paste-alert alert6">
' . mysqli_error($con) . '
</div>';
} else {
$msg = '<div class="paste-alert alert3">
All pastes have been deleted
</div>';
}
}
if (isset($_GET['not_verfied'])) {
$query = "DELETE FROM users where verified='0'";
mysqli_query($con, $query);
if (mysqli_errno($con)) {
$msg = '<div class="paste-alert alert6">
' . mysqli_error($con) . '
</div>';
} else {
$msg = '<div class="paste-alert alert3">
All unverified accounts have been deleted
</div>';
}
}
if (isset($_GET['admin_history'])) {
$query = "DELETE FROM admin_history";
mysqli_query($con, $query);
if (mysqli_errno($con)) {
$msg = '<div class="paste-alert alert6">
' . mysqli_error($con) . '
</div>';
} else {
$msg = '<div class="paste-alert alert3">
Admin history has been cleared
</div>';
}
}
?>
<!-- Start Tasks -->
<div class="row">
<div class="col-md-12">
<div class="panel panel-widget">
<div class="panel-body">
<div class="panel-title">Maintenance tasks</a></div>
<?php if (isset($msg)) echo $msg; ?>
<a href="?expired" class="btn btn-default btn-block">Delete all expired pastes</a>
<br/>
<a href="?admin_history" class="btn btn-info btn-block">Clear admin history</a>
<br/>
<a href="?not_verfied" class="btn btn-warning btn-block">Delete unverified accounts</a>
<br/>
<a href="?all_pastes" class="btn btn-danger btn-block">Delete all pastes</a>
</div>
</div>
</div>
</div>
<!-- End Tasks -->
</div>
<!-- END CONTAINER -->
<!-- Start Footer -->
<div class="row footer">
<div class="col-md-6 text-left">
<a href="https://github.com/jordansamuel/PASTE" target="_blank">Updates</a> &mdash; <a
href="https://github.com/jordansamuel/PASTE/issues" target="_blank">Bugs</a>
</div>
<div class="col-md-6 text-right">
Powered by <a href="https://phpaste.sourceforge.io" target="_blank">Paste</a>
</div>
</div>
<!-- End Footer -->
</div>
<!-- End content -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
</body>
</html>

View file

@ -1,230 +0,0 @@
<?php
/*
* Paste <https://github.com/jordansamuel/PASTE>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License in GPL.txt for more details.
*/
define('IN_PONEPASTE', 1);
require_once(__DIR__ . '/common.php');
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Paste - Users</title>
<link rel="shortcut icon" href="favicon.ico">
<link href="css/paste.css" rel="stylesheet" type="text/css"/>
<link href="css/datatables.min.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top" class="clearfix">
<!-- Start App Logo -->
<div class="applogo">
<a href="../" class="logo">Paste</a>
</div>
<!-- End App Logo -->
<!-- Start Top Right -->
<ul class="top-right">
<li class="dropdown link">
<a href="#" data-toggle="dropdown" class="dropdown-toggle profilebox"><b>Admin</b><span
class="caret"></span></a>
<ul class="dropdown-menu dropdown-menu-list dropdown-menu-right">
<li><a href="admin.php">Settings</a></li>
<li><a href="?logout">Logout</a></li>
</ul>
</li>
</ul>
<!-- End Top Right -->
</div>
<!-- END TOP -->
<div class="content">
<!-- START CONTAINER -->
<div class="container-widget">
<?php include 'menu.php'; ?>
<!-- End Menu -->
<?php
if (isset($_GET['delete'])) {
$user_id = htmlentities(Trim($_GET['delete']));
$query = "DELETE FROM users WHERE id=$user_id";
$result = mysqli_query($con, $query);
if (mysqli_errno($con)) {
$msg = '<div class="paste-alert alert6" style="text-align: center;">
' . mysqli_error($con) . '
</div>';
} else {
$msg = '<div class="paste-alert alert3" style="text-align: center;">
User deleted
</div>';
}
}
if (isset($_GET['ban'])) {
$ban_id = htmlentities(Trim($_GET['ban']));
$query = "UPDATE users SET verified='2' WHERE id='$ban_id'";
$result = mysqli_query($con, $query);
if (mysqli_errno($con)) {
$msg = '<div class="paste-alert alert6" style="text-align: center;">
' . mysqli_error($con) . '
</div>';
} else {
$msg = '<div class="paste-alert alert3" style="text-align: center;">
User banned
</div>';
}
}
if (isset($_GET['unban'])) {
$ban_id = htmlentities(Trim($_GET['unban']));
$query = "UPDATE users SET verified='1' WHERE id='$ban_id'";
$result = mysqli_query($con, $query);
if (mysqli_errno($con)) {
$msg = '<div class="paste-alert alert6" style="text-align: center;">
' . mysqli_error($con) . '
</div>';
} else {
$msg = '<div class="paste-alert alert3" style="text-align: center;">
User unbanned
</div>';
}
}
?>
<!-- Start Users -->
<div class="row">
<div class="col-md-12">
<div class="panel panel-widget">
<?php
if (isset($_GET['details'])) {
$row = $conn->querySelectOne('SELECT username, platform, verified, banned, date, ip FROM users WHERE id = ?', [$_GET['details']]);
$user_username = $row['username'];
$user_full_name = $row['full_name'];
$user_platform = Trim($row['platform']);
$user_date = $row['date'];
$user_ip = $row['ip'];
$detail_id = htmlentities(Trim($_GET['details']));
if ($row['banned']) {
$user_verified = 'Banned';
} elseif ($row['verified']) {
$user_verified = 'Verified';
} else {
$user_verified = 'Unverified';
}
?>
<div class="panel-body">
<div class="panel-title">
<?php echo $user_username . ' Details'; ?>
</div>
<table class="table table-striped table-bordered">
<tbody>
<tr>
<td> Username</td>
<td> <?php echo $user_username; ?> </td>
</tr>
<tr>
<td> Platform</td>
<td> <?php echo $user_platform; ?> </td>
</tr>
<tr>
<td> Status</td>
<td> <?php echo $user_verified; ?> </td>
</tr>
<tr>
<td> User IP</td>
<td> <?php echo $user_ip; ?> </td>
</tr>
<tr>
<td> Date Registered</td>
<td> <?php echo $user_date; ?> </td>
</tr>
<tr>
<td> Full Name</td>
<td> <?php echo $user_full_name; ?> </td>
</tr>
</tbody>
</table>
</div>
<?php } else { ?>
<div class="panel-body">
<div class="panel-title">
Manage Users
</div>
<?php if (isset($msg)) echo $msg; ?>
<table cellpadding="0" cellspacing="0" border="0" class="table table-striped table-bordered"
id="usersTable">
<thead>
<tr>
<th>ID</th>
<th>Username</th>
<th>Date Registered</th>
<th>Platform</th>
<th>Ban User</th>
<th>Profile</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<?php } ?>
</div>
</div>
</div>
<!-- End Admin Settings -->
</div>
<!-- END CONTAINER -->
<!-- Start Footer -->
<div class="row footer">
<div class="col-md-6 text-left">
<a href="https://github.com/jordansamuel/PASTE" target="_blank">Updates</a> &mdash; <a
href="https://github.com/jordansamuel/PASTE/issues" target="_blank">Bugs</a>
</div>
<div class="col-md-6 text-right">
Powered by <a href="https://phpaste.sourceforge.io" target="_blank">Paste</a>
</div>
</div>
<!-- End Footer -->
</div>
<!-- End content -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" language="javascript" src="js/jquery.dataTables.js"></script>
<script type="text/javascript" language="javascript" class="init">
$(document).ready(function () {
$('#usersTable').dataTable({
"processing": true,
"serverSide": true,
"ajax": "ajax_users.php",
"order": [[0, "desc"]]
});
});
</script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
</body>
</html>

View file

@ -1,35 +0,0 @@
<?php
header('Content-Type: application/json; charset=UTF-8');
define('IN_PONEPASTE', 1);
//require_once('../includes/config.php');
require_once('../includes/common.php');
require_once('../includes/NonRetardedSSP.class.php');
function transformDataRow($row) {
$titleHtml = '<a href="/' . urlencode($row[0]) . '">' . pp_html_escape($row[1]) . '</a>';
$authorHtml = '<a href="/user/' . urlencode($row[2]) . '">' . pp_html_escape($row[2]) . '</a>';
$tagsHtml = tagsToHtml($row[3]);
return [
$titleHtml,
$authorHtml,
$tagsHtml
];
}
$data = NonRetardedSSP::run(
$conn, $_GET,
'SELECT COUNT(*) FROM pastes WHERE pastes.visible = \'0\' AND pastes.title != \'\'',
'SELECT pastes.id AS id, title, users.username, GROUP_CONCAT(tags.name SEPARATOR \',\') AS tagsys FROM pastes
INNER JOIN users ON users.id = pastes.user_id
INNER JOIN paste_taggings on pastes.id = paste_taggings.paste_id
INNER JOIN tags ON tags.id = paste_taggings.tag_id
WHERE pastes.visible = \'0\' AND pastes.title != \'\'
GROUP BY pastes.id'
);
$data['data'] = array_map('transformDataRow', $data['data']);
echo json_encode($data);

View file

@ -1,390 +0,0 @@
<?php
class SSP {
/**
* Create the data output array for the DataTables rows
*
* @param array $columns Column information array
* @param array $data Data from the SQL get
* @return array Formatted data in a row based format
*/
static function data_output($columns, $data) {
$out = array();
for ($i = 0, $ien = count($data); $i < $ien; $i++) {
$row = array();
for ($j = 0, $jen = count($columns); $j < $jen; $j++) {
$column = $columns[$j];
// Is there a formatter?
if (isset($column['formatter'])) {
$row[$column['dt']] = $column['formatter']($data[$i][$column['db']], $data[$i]);
} else {
$row[$column['dt']] = $data[$i][$columns[$j]['db']];
}
}
$out[] = $row;
}
return $out;
}
/**
* Paging
*
* Construct the LIMIT clause for server-side processing SQL query
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @return string SQL limit clause
*/
static function limit($request, $columns) {
$limit = '';
if (isset($request['start']) && $request['length'] != -1) {
$limit = "LIMIT " . intval($request['start']) . ", " . intval($request['length']);
}
return $limit;
}
/**
* Ordering
*
* Construct the ORDER BY clause for server-side processing SQL query
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @return string SQL order by clause
*/
static function order($request, $columns) {
$order = '';
if (isset($request['order']) && count($request['order'])) {
$orderBy = array();
$dtColumns = self::pluck($columns, 'dt');
for ($i = 0, $ien = count($request['order']); $i < $ien; $i++) {
// Convert the column index into the column data property
$columnIdx = intval($request['order'][$i]['column']);
$requestColumn = $request['columns'][$columnIdx];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
if ($requestColumn['orderable'] == 'true') {
$dir = $request['order'][$i]['dir'] === 'DESC' ?
'ASC' :
'DESC';
$orderBy[] = '`' . $column['db'] . '` ' . $dir;
}
}
$order = 'ORDER BY ' . implode(', ', $orderBy);
}
return $order;
}
/**
* Searching / Filtering
*
* Construct the WHERE clause for server-side processing SQL query.
*
* NOTE this does not match the built-in DataTables filtering which does it
* word by word on any field. It's possible to do here performance on large
* databases would be very poor
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @param array $bindings Array of values for PDO bindings, used in the
* sql_exec() function
* @return string SQL where clause
*/
static function filter($request, $columns, &$bindings) {
$globalSearch = array();
$columnSearch = array();
$dtColumns = self::pluck($columns, 'dt');
if (isset($request['search']) && $request['search']['value'] != '') {
$str = $request['search']['value'];
for ($i = 0, $ien = count($request['columns']); $i < $ien; $i++) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
if ($requestColumn['searchable'] == 'true') {
$binding = self::bind($bindings, '%' . $str . '%', PDO::PARAM_STR);
$globalSearch[] = "`" . $column['db'] . "` LIKE " . $binding;
}
}
}
// Individual column filtering
for ($i = 0, $ien = count($request['columns']); $i < $ien; $i++) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
$str = $requestColumn['search']['value'];
if ($requestColumn['searchable'] == 'true' &&
$str != '') {
$binding = self::bind($bindings, '%' . $str . '%', PDO::PARAM_STR);
$columnSearch[] = "`" . $column['db'] . "` LIKE " . $binding;
}
}
// Combine the filters into a single string
$where = '';
if (count($globalSearch)) {
$where = '(' . implode(' OR ', $globalSearch) . ')';
}
if (count($columnSearch)) {
$where = $where === '' ?
implode(' AND ', $columnSearch) :
$where . ' AND ' . implode(' AND ', $columnSearch);
}
if ($where !== '') {
$where = 'WHERE ' . $where;
}
return $where;
}
/**
* Perform the SQL queries needed for an server-side processing requested,
* utilising the helper functions of this class, limit(), order() and
* filter() among others. The returned array is ready to be encoded as JSON
* in response to an SSP request, or can be modified if needed before
* sending back to the client.
*
* @param array $request Data sent to server by DataTables
* @param array $sql_details SQL connection details - see sql_connect()
* @param string $table SQL table to query
* @param string $primaryKey Primary key of the table
* @param array $columns Column information array
* @return array Server-side processing response array
*/
static function simple($request, $sql_details, $table, $primaryKey, $columns, $columns2) {
$bindings = array();
$db = self::sql_connect($sql_details);
// Build the SQL query string from the request
$limit = self::limit($request, $columns);
$order = self::order($request, $columns);
$where = self::filter($request, $columns, $bindings);
// Main query to actually get the data
$data = self::Ssql_exec($db, $bindings,
"SELECT SQL_CALC_FOUND_ROWS `" . implode("`, `", self::pluck($columns, 'db')) . "`
FROM `$table` WHERE visible='0' AND tagsys IS NOT NULL AND NOT title LIKE ''
$order
$limit"
);
// Data set length after filtering
$resFilterLength = self::sql_exec($db,
"SELECT FOUND_ROWS()"
);
$recordsFiltered = $resFilterLength[0][0];
// Total data set length
$resTotalLength = self::sql_exec($db,
"SELECT COUNT(`{$primaryKey}`)
FROM `$table`"
);
$recordsTotal = $resTotalLength[0][0];
/*
* Output
*/
return array(
"draw" => intval($request['draw']),
"recordsTotal" => intval($recordsTotal),
"recordsFiltered" => intval($recordsFiltered),
"data" => self::data_output($columns2, $data)
);
}
/**
* Connect to the database
*
* @param array $sql_details SQL server connection details array, with the
* properties:
* * host - host name
* * db - database name
* * user - user name
* * pass - user password
* @return resource Database connection handle
*/
static function sql_connect($sql_details) {
try {
$db = @new PDO(
"mysql:host={$sql_details['host']};dbname={$sql_details['db']}",
$sql_details['user'],
$sql_details['pass'],
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
);
} catch (PDOException $e) {
self::fatal(
"An error occurred while connecting to the database. " .
"The error reported by the server was: " . $e->getMessage()
);
}
return $db;
}
/**
* Execute an SQL query on the database
*
* @param resource $db Database handler
* @param array $bindings Array of PDO binding values from bind() to be
* used for safely escaping strings. Note that this can be given as the
* SQL query string if no bindings are required.
* @param string $sql SQL query to execute.
* @return array Result from the query (all rows)
*/
static function sql_exec($db, $bindings, $sql = null) {
// Argument shifting
if ($sql === null) {
$sql = $bindings;
}
$stmt = $db->prepare($sql);
//echo $sql;
// Bind parameters
if (is_array($bindings)) {
for ($i = 0, $ien = count($bindings); $i < $ien; $i++) {
$binding = $bindings[$i];
$stmt->bindValue($binding['key'], $binding['val'], $binding['type']);
}
}
// Execute
try {
$stmt->execute();
} catch (PDOException $e) {
self::fatal("An SQL error occurred: " . $e->getMessage());
}
return $stmt->fetchAll();
}
static function Ssql_exec($db, $bindings, $sql = null) {
// Argument shifting
if ($sql === null) {
$sql = $bindings;
}
$stmt = $db->prepare($sql);
// Bind parameters
if (is_array($bindings)) {
for ($i = 0, $ien = count($bindings); $i < $ien; $i++) {
$binding = $bindings[$i];
$stmt->bindValue($binding['key'], $binding['val'], $binding['type']);
}
}
// Execute
try {
$stmt->execute();
} catch (PDOException $e) {
self::fatal("An SQL error occurred: " . $e->getMessage());
}
$loop = '0';
while ($arr = $stmt->fetch(PDO::FETCH_ASSOC)) {
$result[$loop]['id'] = $arr['id'];
$result[$loop]['title'] = html_entity_decode($arr['title']);
$result[$loop]['member'] = $arr['member'];
$result[$loop]['tagsys'] = $arr['tagsys'];
$date_time = strtotime($arr['date']);
$result[$loop]['date'] = date(DATE_ISO8601, $date_time);
$myupdate = $arr['now_time'];
$result[$loop]['now_time'] = date(DATE_ISO8601, $myupdate);
$loop = $loop + 1;
}
// Return all
return $result;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Internal methods
*/
/**
* Throw a fatal error.
*
* This writes out an error message in a JSON string which DataTables will
* see and show to the user in the browser.
*
* @param string $msg Message to send to the client
*/
static function fatal($msg) {
echo json_encode(array(
"error" => $msg
));
exit(0);
}
/**
* Create a PDO binding key which can be used for escaping variables safely
* when executing a query with sql_exec()
*
* @param array &$a Array of bindings
* @param * $val Value to bind
* @param int $type PDO field type
* @return string Bound key to be used in the SQL where this parameter
* would be used.
*/
static function bind(&$a, $val, $type) {
$key = ':binding_' . count($a);
$a[] = array(
'key' => $key,
'val' => $val,
'type' => $type
);
return $key;
}
/**
* Pull a particular property from each assoc. array in a numeric array,
* returning and array of the property values from each item.
*
* @param array $a Array to get data from
* @param string $prop Property to read
* @return array Array of property values
*/
static function pluck($a, $prop) {
$out = array();
for ($i = 0, $len = count($a); $i < $len; $i++) {
$out[] = $a[$i][$prop];
}
return $out;
}
}

View file

@ -1,26 +0,0 @@
<?php
define('IN_PONEPASTE', 1);
require_once(__DIR__ . '/../includes/common.php');
require_once(__DIR__ . '/../includes/Tag.class.php');
/* get rid of unintended wildcards in a parameter to LIKE queries; not a security issue, just unexpected behaviour. */
function escapeLikeQuery(string $query) : string {
return str_replace(['\\', '_', '%'], ['\\\\', '\\_', '\\%'], $query);
}
header('Content-Type: application/json');
if (empty($_GET['tag'])) {
die(json_encode(['error' => true, 'message' => 'No tag name provided']));
}
$tag_name = Tag::cleanTagName($_GET['tag']);
$results = $conn->query('SELECT name FROM tags WHERE name LIKE ? AND name != ?', [escapeLikeQuery($tag_name) . '%', $tag_name]);
$tags = $results->fetchAll(PDO::FETCH_ASSOC);
array_push($tags, ['name' => $tag_name]);
echo json_encode($tags);

View file

@ -1,35 +0,0 @@
<?php
/*
* Paste <https://github.com/jordansamuel/PASTE>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License in GPL.txt for more details.
*/
define('IN_PONEPASTE', 1);
require_once('includes/common.php');
// UTF-8
header('Content-Type: text/html; charset=utf-8');
$date = date('jS F Y');
// Temp count for untagged pastes
$total_untagged = intval($conn->query("SELECT COUNT(*) from pastes WHERE tagsys IS NULL")->fetch(PDO::FETCH_NUM)[0]);
updatePageViews($conn);
$p_title = $lang['archive']; // "Pastes Archive";
// Theme
require_once('theme/' . $default_theme . '/header.php');
require_once('theme/' . $default_theme . '/archive.php');
require_once('theme/' . $default_theme . '/footer.php');

View file

@ -1 +0,0 @@
deny from all

View file

@ -1,66 +0,0 @@
.icon-github {
background: no-repeat url('../img/github-16px.png');
width: 16px;
height: 16px;
}
.bootstrap-tagsinput {
width: 100%;
}
.accordion {
margin-bottom: -3px;
}
.accordion-group {
border: none;
}
.twitter-typeahead .tt-query,
.twitter-typeahead .tt-hint {
margin-bottom: 0;
}
.twitter-typeahead .tt-hint {
display: none;
}
.tt-menu {
position: absolute;
top: 100%;
left: 0;
z-index: 1000;
display: none;
float: left;
min-width: 160px;
padding: 5px 0;
margin: 2px 0 0;
list-style: none;
font-size: 14px;
background-color: #ffffff;
border: 1px solid #cccccc;
border: 1px solid rgba(0, 0, 0, 0.15);
border-radius: 4px;
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
background-clip: padding-box;
cursor: pointer;
}
.tt-suggestion {
display: block;
padding: 3px 20px;
clear: both;
font-weight: normal;
line-height: 1.428571429;
color: #333333;
white-space: nowrap;
}
.tt-suggestion:hover,
.tt-suggestion:focus {
color: #ffffff;
text-decoration: none;
outline: 0;
background-color: #428bca;
}

View file

@ -1,15 +0,0 @@
$(function () {
$('input, select').on('change', function (event) {
var $element = $(event.target),
$container = $element.closest('.example');
if (!$element.data('tagsinput'))
return;
var val = $element.val();
if (val === null)
val = "null";
$('code', $('pre.val', $container)).html(($.isArray(val) ? JSON.stringify(val) : "\"" + val.replace('"', '\\"') + "\""));
$('code', $('pre.items', $container)).html(JSON.stringify($element.tagsinput('items')));
}).trigger('change');
});

View file

@ -1,84 +0,0 @@
$('.example_typeahead > > input').tagsinput({
typeahead: {
source: function (query) {
return $.getJSON('assets/citynames.json');
}
}
});
$('.example_objects_as_tags > > input').tagsinput({
itemValue: 'value',
itemText: 'text',
typeahead: {
source: function (query) {
return $.getJSON('assets/cities.json');
}
}
});
$('.example_objects_as_tags > > input').tagsinput('add', {"value": 1, "text": "Amsterdam", "continent": "Europe"});
$('.example_objects_as_tags > > input').tagsinput('add', {"value": 4, "text": "Washington", "continent": "America"});
$('.example_objects_as_tags > > input').tagsinput('add', {"value": 7, "text": "Sydney", "continent": "Australia"});
$('.example_objects_as_tags > > input').tagsinput('add', {"value": 10, "text": "Beijing", "continent": "Asia"});
$('.example_objects_as_tags > > input').tagsinput('add', {"value": 13, "text": "Cairo", "continent": "Africa"});
$('.example_tagclass > > input').tagsinput({
tagClass: function (item) {
switch (item.continent) {
case 'Europe' :
return 'label label-info';
case 'America' :
return 'label label-danger label-important';
case 'Australia':
return 'label label-success';
case 'Africa' :
return 'label';
case 'Asia' :
return 'label label-warning';
}
},
itemValue: 'value',
itemText: 'text',
typeahead: {
source: function (query) {
return $.getJSON('assets/cities.json');
}
}
});
$('.example_tagclass > > input').tagsinput('add', {"value": 1, "text": "Amsterdam", "continent": "Europe"});
$('.example_tagclass > > input').tagsinput('add', {"value": 4, "text": "Washington", "continent": "America"});
$('.example_tagclass > > input').tagsinput('add', {"value": 7, "text": "Sydney", "continent": "Australia"});
$('.example_tagclass > > input').tagsinput('add', {"value": 10, "text": "Beijing", "continent": "Asia"});
$('.example_tagclass > > input').tagsinput('add', {"value": 13, "text": "Cairo", "continent": "Africa"});
angular.module('AngularExample', ['bootstrap-tagsinput'])
.controller('CityTagsInputController',
function CityTagsInputController($scope, $http) {
// Init with some cities
$scope.cities = [
{"value": 1, "text": "Amsterdam", "continent": "Europe"},
{"value": 4, "text": "Washington", "continent": "America"},
{"value": 7, "text": "Sydney", "continent": "Australia"},
{"value": 10, "text": "Beijing", "continent": "Asia"},
{"value": 13, "text": "Cairo", "continent": "Africa"}
];
$scope.queryCities = function (query) {
return $http.get('assets/cities.json');
};
$scope.getTagClass = function (city) {
switch (city.continent) {
case 'Europe' :
return 'label label-info';
case 'America' :
return 'label label-danger label-important';
case 'Australia':
return 'label label-success';
case 'Africa' :
return 'label';
case 'Asia' :
return 'label label-warning';
}
};
}
);

View file

@ -1,101 +0,0 @@
var citynames = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: {
url: 'assets/citynames.json',
filter: function (list) {
return $.map(list, function (cityname) {
return {name: cityname};
});
}
}
});
citynames.initialize();
var cities = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('text'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: 'assets/cities.json'
});
cities.initialize();
/**
* Typeahead
*/
var elt = $('.example_typeahead > > input');
elt.tagsinput({
typeaheadjs: {
name: 'citynames',
displayKey: 'name',
valueKey: 'name',
source: citynames.ttAdapter()
}
});
/**
* Objects as tags
*/
elt = $('.example_objects_as_tags > > input');
elt.tagsinput({
itemValue: 'value',
itemText: 'text',
typeaheadjs: {
name: 'cities',
displayKey: 'text',
source: cities.ttAdapter()
}
});
elt.tagsinput('add', {"value": 1, "text": "Amsterdam", "continent": "Europe"});
elt.tagsinput('add', {"value": 4, "text": "Washington", "continent": "America"});
elt.tagsinput('add', {"value": 7, "text": "Sydney", "continent": "Australia"});
elt.tagsinput('add', {"value": 10, "text": "Beijing", "continent": "Asia"});
elt.tagsinput('add', {"value": 13, "text": "Cairo", "continent": "Africa"});
/**
* Categorizing tags
*/
elt = $('.example_tagclass > > input');
elt.tagsinput({
tagClass: function (item) {
switch (item.continent) {
case 'Europe' :
return 'label label-primary';
case 'America' :
return 'label label-danger label-important';
case 'Australia':
return 'label label-success';
case 'Africa' :
return 'label label-default';
case 'Asia' :
return 'label label-warning';
}
},
itemValue: 'value',
itemText: 'text',
// typeaheadjs: {
// name: 'cities',
// displayKey: 'text',
// source: cities.ttAdapter()
// }
typeaheadjs: [
{
hint: true,
highlight: true,
minLength: 2
},
{
name: 'cities',
displayKey: 'text',
source: cities.ttAdapter()
}
]
});
elt.tagsinput('add', {"value": 1, "text": "Amsterdam", "continent": "Europe"});
elt.tagsinput('add', {"value": 4, "text": "Washington", "continent": "America"});
elt.tagsinput('add', {"value": 7, "text": "Sydney", "continent": "Australia"});
elt.tagsinput('add', {"value": 10, "text": "Beijing", "continent": "Asia"});
elt.tagsinput('add', {"value": 13, "text": "Cairo", "continent": "Africa"});
// HACK: overrule hardcoded display inline-block of typeahead.js
$(".twitter-typeahead").css('display', 'inline');

View file

@ -1,77 +0,0 @@
[
{
"value": 1,
"text": "Amsterdam",
"continent": "Europe"
},
{
"value": 2,
"text": "London",
"continent": "Europe"
},
{
"value": 3,
"text": "Paris",
"continent": "Europe"
},
{
"value": 4,
"text": "Washington",
"continent": "America"
},
{
"value": 5,
"text": "Mexico City",
"continent": "America"
},
{
"value": 6,
"text": "Buenos Aires",
"continent": "America"
},
{
"value": 7,
"text": "Sydney",
"continent": "Australia"
},
{
"value": 8,
"text": "Wellington",
"continent": "Australia"
},
{
"value": 9,
"text": "Canberra",
"continent": "Australia"
},
{
"value": 10,
"text": "Beijing",
"continent": "Asia"
},
{
"value": 11,
"text": "New Delhi",
"continent": "Asia"
},
{
"value": 12,
"text": "Kathmandu",
"continent": "Asia"
},
{
"value": 13,
"text": "Cairo",
"continent": "Africa"
},
{
"value": 14,
"text": "Cape Town",
"continent": "Africa"
},
{
"value": 15,
"text": "Kinshasa",
"continent": "Africa"
}
]

View file

@ -1,17 +0,0 @@
[
"Amsterdam",
"London",
"Paris",
"Washington",
"New York",
"Los Angeles",
"Sydney",
"Melbourne",
"Canberra",
"Beijing",
"New Delhi",
"Kathmandu",
"Cairo",
"Cape Town",
"Kinshasa"
]

View file

@ -1,155 +0,0 @@
/* ========================================================================
* jquery.limitText.js v0.0.1
*
* ========================================================================
* Copyright 2015 Phillip Molaro
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ========================================================================
*
* Usage:
*
<textarea id="myTextArea" cols="120" rows="30" data-status-message="#status"></textarea>
<div id="status" class="text-right"></div>
<script type="text/javascript">
$(document).ready(function () {
$('#myTextArea').limitText();
});
</script>
*
* Options:
* @param limit (integer) - The cutoff character count for the field
* Default: 200
* @param warningLimit (integer) - The remaining character count to trigger class change
* Default: 10
* @param statusMessage (string) - A jQuery selector to id an existing status container DOM element
* If left empty, a default will be added after the element
* Default: ''
* @param counterClass (string) - Class to apply to the status area, and replaced on warning
* Default: 'text-primary' (Bootstrap helper class)
* @param warningClass (string) - Class applied to status area when warningLimit is reached.
* Replaces the counterClass on warning
* Default: 'text-danger' (Bootstrap helper class)
* @param containerElement (string) - DOM element to be inserted if statusMessage is undefined
* Default: '<div>'
* @param containerClass (string) - Class applied to the status container.
* Default: 'limit-text-status' (no definition)
*/
+function ($) {
'use strict';
/**
* LimitText Class Definition
*/
var LimitText = function (element, options) {
this.options = options;
this.$element = $(element);
// if an existing container is not defined, then a default will be created
this.$status = (this.options.statusMessage.length) ?
$(this.options.statusMessage) : $(this.options.containerElement);
// Add classes to the status container, and insert base text
this.$status
.addClass(this.options.containerClass + ' ' + this.options.counterClass)
.append('<small><strong>' +
this.options.limit + '</strong> characters remaining</small>');
// reference not available til we've appended the html snippet
this.$count = $('strong', this.$status);
// insert the default message container if one isn't already defined
if (!this.options.statusMessage.length) this.$element.after(this.$status);
// set our event handler and proxy it to properly set the context
this.$element.on('input.limitText.data-api propertychange.limitText.data-api', $.proxy(this.checkCount, this));
// and run initial check of current value
this.checkCount();
};
LimitText.VERSION = '0.0.1';
LimitText.NAME = 'limitText';
LimitText.DEFAULTS = {
limit: 200,
warningLimit: 10,
statusMessage: '',
// These two are Bootstrap text emphasis classes
// that you can override in the config, or roll
// your own of the same name
counterClass: 'text-primary',
warningClass: 'text-danger',
// The default container element is only used if an
// existing container (statusMessage) is not defined
containerElement: '<div>',
containerClass: 'limit-text-status'
};
LimitText.prototype.checkCount = function () {
var currVal = this.$element.val();
if (currVal.length > this.options.limit) {
// reset the currVal, so that it stays within the limit
currVal = currVal.substr(0, this.options.limit - 1);
this.$element.val(currVal);
}
var remaining = this.options.limit - currVal.length;
this.$count.html(remaining);
if (remaining <= this.options.warningLimit) {
this.$status.removeClass(this.options.counterClass).addClass(this.options.warningClass);
} else {
this.$status.removeClass(this.options.warningClass).addClass(this.options.counterClass);
}
};
LimitText.prototype.destroy = function () {
$.removeData(this.$element[0], 'limitText');
// remove the inserted status container
if (!this.options.statusMessage.length) {
this.$status.remove();
} else {
this.$status
.removeClass(
this.options.containerClass + ' ' +
this.options.counterClass + ' ' +
this.options.warningClass)
.empty();
}
this.$element.off('input.limitText.data-api propertychange.limitText.data-api');
this.$element = null;
};
// limitText Plugin Definition
function Plugin(option) {
return this.each(function () {
var $this = $(this),
data = $this.data('limitText'),
options = $.extend({}, LimitText.DEFAULTS, $this.data(), typeof option == 'object' && option);
if (!data) $this.data('limitText', (data = new LimitText(this, options)));
if (typeof option == 'string') data[option]();
});
}
var old = $.fn.limitText;
$.fn.limitText = Plugin;
$.fn.limitText.Constructor = LimitText;
// limitText No Conflict
$.fn.limitText.noConflict = function () {
$.fn.limitText = old;
return this;
};
}(jQuery);

View file

@ -1,2 +0,0 @@
/* jquery.limitText.js v0.0.1 - (c)2015 Phillip Molaro - MIT Licensed https://github.com/twbs/bootstrap/blob/master/LICENSE */
+function(t){"use strict";var s=function(s,i){this.options=i,this.$element=t(s),this.$status=t(this.options.statusMessage.length?this.options.statusMessage:this.options.containerElement),this.$status.addClass(this.options.containerClass+" "+this.options.counterClass).append("<small><strong>"+this.options.limit+"</strong> characters remaining</small>"),this.$count=t("strong",this.$status),this.options.statusMessage.length||this.$element.after(this.$status),this.$element.on("input.limitText.data-api propertychange.limitText.data-api",t.proxy(this.checkCount,this)),this.checkCount()};s.VERSION="0.0.1",s.NAME="limitText",s.DEFAULTS={limit:200,warningLimit:10,statusMessage:"",counterClass:"text-primary",warningClass:"text-danger",containerElement:"<div>",containerClass:"limit-text-status"},s.prototype.checkCount=function(){var t=this.$element.val();t.length>this.options.limit&&(t=t.substr(0,this.options.limit-1),this.$element.val(t));var s=this.options.limit-t.length;this.$count.html(s),s<=this.options.warningLimit?this.$status.removeClass(this.options.counterClass).addClass(this.options.warningClass):this.$status.removeClass(this.options.warningClass).addClass(this.options.counterClass)},s.prototype.destroy=function(){t.removeData(this.$element[0],"limitText"),this.options.statusMessage.length?this.$status.removeClass(this.options.containerClass+" "+this.options.counterClass+" "+this.options.warningClass).empty():this.$status.remove(),this.$element.off("input.limitText.data-api propertychange.limitText.data-api"),this.$element=null};var i=t.fn.limitText;t.fn.limitText=function(i){return this.each(function(){var n=t(this),e=n.data("limitText"),a=t.extend({},s.DEFAULTS,n.data(),"object"==typeof i&&i);e||n.data("limitText",e=new s(this,a)),"string"==typeof i&&e[i]()})},t.fn.limitText.Constructor=s,t.fn.limitText.noConflict=function(){return t.fn.limitText=i,this}}(jQuery);

3
babel.config.json Normal file
View file

@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env"]
}

View file

@ -12,9 +12,19 @@
}
],
"require": {
"scrivo/highlight.php": "v9.18.1.7",
"ext-pdo": "*",
"ext-openssl": "*",
"erusev/parsedown": "^1.7"
"ext-gd": "*",
"ext-mbstring": "*",
"scrivo/highlight.php": "^9.18",
"erusev/parsedown": "^1.7",
"illuminate/database": "^9.4",
"ext-redis": "*",
"erusev/parsedown-extra": "^0.8.1"
},
"autoload": {
"psr-4": {
"PonePaste\\": "includes/"
}
}
}

1829
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1 +0,0 @@
deny from all

40
config/site.example.php Normal file
View file

@ -0,0 +1,40 @@
<?php
/* This file has been machine-generated, but is human-editable if you so desire. */
return array (
'site_info' =>
array (
'title' => 'PonePaste',
'description' => 'PonePaste can store green',
'keywords' => '',
'site_name' => 'PonePaste',
'email' => ''
),
'interface' =>
array (
'language' => 'en',
'theme' => 'bulma',
),
'permissions' =>
array (
'disable_guest' => false,
'private' => false,
),
'mail' =>
array (
'verification' => false,
'smtp_host' => '',
'smtp_port' => '',
'smtp_user' => '',
'socket' => '',
'auth' => '',
'protocol' => '',
),
'captcha' =>
array (
'enabled' => true,
'multiple' => false,
'mode' => 'Normal',
'allowed' => 'ABCDEFGHIJKLMNOPQRSTUVYXYZabcdefghijklmnopqrstuvwxyz0123456789',
'colour' => '#000000',
),
);

View file

@ -1,39 +0,0 @@
<?php
return array(
'site_info' =>
array(
'title' => 'PonePaste',
'description' => 'PonePaste can store green',
'baseurl' => 'ponepaste.local/',
'keywords' => '',
'site_name' => 'PonePaste',
'email' => '',
'google_analytics' => '',
'additional_scripts' => 'PonePaste',
),
'interface' =>
array(
'language' => 'en',
'theme' => 'bulma',
),
'permissions' => [
'disable_guest' => false,
'private' => false
],
'mail' => [
'verification' => false,
'smtp_host' => '',
'smtp_port' => '',
'smtp_user' => '',
'socket' => '',
'auth' => '',
'protocol' => ''
],
'captcha' => [
'enabled' => true,
'multiple' => false,
'mode' => 'Normal',
'allowed' => 'ABCDEFGHIJKLMNOPQRSTUVYXYZabcdefghijklmnopqrstuvwxyz0123456789',
'colour' => '#000000'
]
);

View file

@ -1,104 +0,0 @@
<?php
/*
* Paste <https://github.com/jordansamuel/PASTE>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License in GPL.txt for more details.
*/
define('IN_PONEPASTE', 1);
require_once('includes/common.php');
require_once('includes/functions.php');
// UTF-8
header('Content-Type: text/html; charset=utf-8');
function getMonthPopularPastes(DatabaseHandle $conn, int $count) : array {
$query = $conn->prepare(
"SELECT pastes.id AS id, title, created_at, updated_at, users.username AS member
FROM pastes
INNER JOIN users ON users.id = pastes.user_id
WHERE MONTH(created_at) = MONTH(NOW()) AND visible = '0' ORDER BY views DESC LIMIT ?");
$query->execute([$count]);
return $query->fetchAll();
}
function getRecentUpdatesPastes(DatabaseHandle $conn, int $count) : array {
$query = $conn->prepare(
"SELECT pastes.id AS id, title, created_at, updated_at, users.username AS member
FROM pastes
INNER JOIN users ON users.id = pastes.user_id
WHERE visible = '0' ORDER BY updated_at DESC
LIMIT ?");
$query->execute([$count]);
return $query->fetchAll();
}
function getRecentCreatedPastes(DatabaseHandle $conn, int $count) : array {
$query = $conn->prepare("
SELECT pastes.id, title, created_at, updated_at, users.username AS member
FROM pastes
INNER JOIN users ON pastes.user_id = users.id
WHERE visible = '0'
ORDER BY created_at DESC
LIMIT ?");
$query->execute([$count]);
return $query->fetchAll();
}
function getMostViewedPastes(DatabaseHandle $conn, int $count) : array {
$query = $conn->prepare("
SELECT pastes.id AS id, title, created_at, updated_at, views, users.username AS member
FROM pastes INNER JOIN users ON users.id = pastes.user_id
WHERE visible = '0'
ORDER BY views DESC
LIMIT ?
");
$query->execute([$count]);
return $query->fetchAll();
}
function getRandomPastes(DatabaseHandle $conn, int $count) : array {
$query = $conn->prepare("
SELECT pastes.id, title, created_at, updated_at, views, users.username AS member
FROM pastes
INNER JOIN users ON users.id = pastes.user_id
WHERE visible = '0'
ORDER BY RAND()
LIMIT ?");
$query->execute([$count]);
return $query->fetchAll();
}
function transformPasteRow(array $row) : array {
global $conn;
return [
'id' => $row['id'],
'title' => $row['title'],
'member' => $row['member'],
'time' => $row['created_at'],
'time_update' => $row['updated_at'],
'friendly_update_time' => friendlyDateDifference(new DateTime($row['updated_at']), new DateTime()),
'friendly_time' => friendlyDateDifference(new DateTime($row['created_at']), new DateTime()),
'tags' => getPasteTags($conn, $row['id'])
];
}
$popular_pastes = array_map('transformPasteRow', getMostViewedPastes($conn, 10));
$monthly_popular_pastes = array_map('transformPasteRow', getMonthPopularPastes($conn, 10));
$recent_pastes = array_map('transformPasteRow', getRecentCreatedPastes($conn, 10));
$updated_pastes = array_map('transformPasteRow', getRecentUpdatesPastes($conn, 10));
$random_pastes = array_map('transformPasteRow', getRandomPastes($conn, 10));
// Theme
$p_title = $lang['archive']; // "Pastes Archive";
require_once('theme/' . $default_theme . '/header.php');
require_once('theme/' . $default_theme . '/discover.php');
require_once('theme/' . $default_theme . '/footer.php');

View file

@ -1,93 +0,0 @@
angular.module('bootstrap-tagsinput', [])
.directive('bootstrapTagsinput', [function () {
function getItemProperty(scope, property) {
if (!property)
return undefined;
if (angular.isFunction(scope.$parent[property]))
return scope.$parent[property];
return function (item) {
return item[property];
};
}
return {
restrict: 'EA',
scope: {
model: '=ngModel'
},
template: '<select multiple></select>',
replace: false,
link: function (scope, element, attrs) {
$(function () {
if (!angular.isArray(scope.model))
scope.model = [];
var select = $('select', element);
var typeaheadSourceArray = attrs.typeaheadSource ? attrs.typeaheadSource.split('.') : null;
var typeaheadSource = typeaheadSourceArray ?
(typeaheadSourceArray.length > 1 ?
scope.$parent[typeaheadSourceArray[0]][typeaheadSourceArray[1]]
: scope.$parent[typeaheadSourceArray[0]])
: null;
select.tagsinput(scope.$parent[attrs.options || ''] || {
typeahead: {
source: angular.isFunction(typeaheadSource) ? typeaheadSource : null
},
itemValue: getItemProperty(scope, attrs.itemvalue),
itemText: getItemProperty(scope, attrs.itemtext),
confirmKeys: getItemProperty(scope, attrs.confirmkeys) ? JSON.parse(attrs.confirmkeys) : [13],
tagClass: angular.isFunction(scope.$parent[attrs.tagclass]) ? scope.$parent[attrs.tagclass] : function (item) {
return attrs.tagclass;
}
});
for (var i = 0; i < scope.model.length; i++) {
select.tagsinput('add', scope.model[i]);
}
select.on('itemAdded', function (event) {
if (scope.model.indexOf(event.item) === -1)
scope.model.push(event.item);
});
select.on('itemRemoved', function (event) {
var idx = scope.model.indexOf(event.item);
if (idx !== -1)
scope.model.splice(idx, 1);
});
// create a shallow copy of model's current state, needed to determine
// diff when model changes
var prev = scope.model.slice();
scope.$watch("model", function () {
var added = scope.model.filter(function (i) {
return prev.indexOf(i) === -1;
}),
removed = prev.filter(function (i) {
return scope.model.indexOf(i) === -1;
}),
i;
prev = scope.model.slice();
// Remove tags no longer in binded model
for (i = 0; i < removed.length; i++) {
select.tagsinput('remove', removed[i]);
}
// Refresh remaining tags
select.tagsinput('refresh');
// Add new items in model as tags
for (i = 0; i < added.length; i++) {
select.tagsinput('add', added[i]);
}
}, true);
});
}
};
}]);

View file

@ -1,7 +0,0 @@
/*
* bootstrap-tagsinput v0.6.1 by Tim Schlechter
*
*/
angular.module("bootstrap-tagsinput",[]).directive("bootstrapTagsinput",[function(){function a(a,b){return b?angular.isFunction(a.$parent[b])?a.$parent[b]:function(a){return a[b]}:void 0}return{restrict:"EA",scope:{model:"=ngModel"},template:"<select multiple></select>",replace:!1,link:function(b,c,d){$(function(){angular.isArray(b.model)||(b.model=[]);var e=$("select",c),f=d.typeaheadSource?d.typeaheadSource.split("."):null,g=f?f.length>1?b.$parent[f[0]][f[1]]:b.$parent[f[0]]:null;e.tagsinput(b.$parent[d.options||""]||{typeahead:{source:angular.isFunction(g)?g:null},itemValue:a(b,d.itemvalue),itemText:a(b,d.itemtext),confirmKeys:a(b,d.confirmkeys)?JSON.parse(d.confirmkeys):[13],tagClass:angular.isFunction(b.$parent[d.tagclass])?b.$parent[d.tagclass]:function(a){return d.tagclass}});for(var h=0;h<b.model.length;h++)e.tagsinput("add",b.model[h]);e.on("itemAdded",function(a){-1===b.model.indexOf(a.item)&&b.model.push(a.item)}),e.on("itemRemoved",function(a){var c=b.model.indexOf(a.item);-1!==c&&b.model.splice(c,1)});var i=b.model.slice();b.$watch("model",function(){var a,c=b.model.filter(function(a){return-1===i.indexOf(a)}),d=i.filter(function(a){return-1===b.model.indexOf(a)});for(i=b.model.slice(),a=0;a<d.length;a++)e.tagsinput("remove",d[a]);for(e.tagsinput("refresh"),a=0;a<c.length;a++)e.tagsinput("add",c[a])},!0)})}}}]);
//# sourceMappingURL=bootstrap-tagsinput-angular.min.js.map

View file

@ -1,61 +0,0 @@
{
"version": 3,
"sources": [
"../src/bootstrap-tagsinput-angular.js"
],
"names": [
"angular",
"module",
"directive",
"getItemProperty",
"scope",
"property",
"isFunction",
"$parent",
"item",
"undefined",
"restrict",
"model",
"template",
"replace",
"link",
"element",
"attrs",
"$",
"isArray",
"select",
"typeaheadSourceArray",
"typeaheadSource",
"split",
"length",
"tagsinput",
"options",
"typeahead",
"source",
"itemValue",
"itemvalue",
"itemText",
"itemtext",
"confirmKeys",
"confirmkeys",
"JSON",
"parse",
"tagClass",
"tagclass",
"i",
"on",
"event",
"indexOf",
"push",
"idx",
"splice",
"prev",
"slice",
"$watch",
"added",
"filter",
"removed"
],
"mappings": ";;;;;AAAAA,QAAQC,OAAO,0BACdC,UAAU,sBAAuB,WAEhC,QAASC,GAAgBC,EAAOC,GAC9B,MAAKA,GAGDL,QAAQM,WAAWF,EAAMG,QAAQF,IAC5BD,EAAMG,QAAQF,GAEhB,SAASG,GACd,MAAOA,GAAKH,IANLI,OAUX,OACEC,SAAU,KACVN,OACEO,MAAO,YAETC,SAAU,6BACVC,SAAS,EACTC,KAAM,SAASV,EAAOW,EAASC,GAC7BC,EAAE,WACKjB,QAAQkB,QAAQd,EAAMO,SACzBP,EAAMO,SAER,IAAIQ,GAASF,EAAE,SAAUF,GACrBK,EAAuBJ,EAAMK,gBAAkBL,EAAMK,gBAAgBC,MAAM,KAAO,KAClFD,EAAkBD,EACjBA,EAAqBG,OAAS,EAC3BnB,EAAMG,QAAQa,EAAqB,IAAIA,EAAqB,IAC1DhB,EAAMG,QAAQa,EAAqB,IACvC,IAEND,GAAOK,UAAUpB,EAAMG,QAAQS,EAAMS,SAAW,MAC9CC,WACEC,OAAW3B,QAAQM,WAAWe,GAAmBA,EAAkB,MAErEO,UAAWzB,EAAgBC,EAAOY,EAAMa,WACxCC,SAAW3B,EAAgBC,EAAOY,EAAMe,UACxCC,YAAc7B,EAAgBC,EAAOY,EAAMiB,aAAeC,KAAKC,MAAMnB,EAAMiB,cAAgB,IAC3FG,SAAWpC,QAAQM,WAAWF,EAAMG,QAAQS,EAAMqB,WAAajC,EAAMG,QAAQS,EAAMqB,UAAY,SAAS7B,GAAQ,MAAOQ,GAAMqB,WAG/H,KAAK,GAAIC,GAAI,EAAGA,EAAIlC,EAAMO,MAAMY,OAAQe,IACtCnB,EAAOK,UAAU,MAAOpB,EAAMO,MAAM2B,GAGtCnB,GAAOoB,GAAG,YAAa,SAASC,GACU,KAApCpC,EAAMO,MAAM8B,QAAQD,EAAMhC,OAC5BJ,EAAMO,MAAM+B,KAAKF,EAAMhC,QAG3BW,EAAOoB,GAAG,cAAe,SAASC,GAChC,GAAIG,GAAMvC,EAAMO,MAAM8B,QAAQD,EAAMhC,KACxB,MAARmC,GACFvC,EAAMO,MAAMiC,OAAOD,EAAK,IAK5B,IAAIE,GAAOzC,EAAMO,MAAMmC,OACvB1C,GAAM2C,OAAO,QAAS,WACpB,GAEIT,GAFAU,EAAQ5C,EAAMO,MAAMsC,OAAO,SAASX,GAAI,MAA2B,KAApBO,EAAKJ,QAAQH,KAC5DY,EAAUL,EAAKI,OAAO,SAASX,GAAI,MAAkC,KAA3BlC,EAAMO,MAAM8B,QAAQH,IAMlE,KAHAO,EAAOzC,EAAMO,MAAMmC,QAGdR,EAAI,EAAGA,EAAIY,EAAQ3B,OAAQe,IAC9BnB,EAAOK,UAAU,SAAU0B,EAAQZ,GAOrC,KAHAnB,EAAOK,UAAU,WAGZc,EAAI,EAAGA,EAAIU,EAAMzB,OAAQe,IAC5BnB,EAAOK,UAAU,MAAOwB,EAAMV,MAE/B",
"file": "bootstrap-tagsinput-angular.min.js"
}

View file

@ -1,66 +0,0 @@
.bootstrap-tagsinput {
background-color: #fff;
border: 1px solid #ccc;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
display: inline-block;
padding: 4px 6px;
color: #555;
vertical-align: middle;
border-radius: 4px;
max-width: 100%;
line-height: 22px;
cursor: text;
}
.bootstrap-tagsinput input {
border: none;
box-shadow: none;
outline: none;
background-color: transparent;
padding: 0 6px;
margin: 0;
width: auto;
max-width: inherit;
}
.bootstrap-tagsinput.form-control input::-moz-placeholder {
color: #777;
opacity: 1;
}
.bootstrap-tagsinput.form-control input:-ms-input-placeholder {
color: #777;
}
.bootstrap-tagsinput.form-control input::-webkit-input-placeholder {
color: #777;
}
.bootstrap-tagsinput input:focus {
border: none;
box-shadow: none;
}
.bootstrap-tagsinput .tag {
margin-right: 2px;
color: white;
background: #3298dc;
}
.bootstrap-tagsinput .tag [data-role="remove"] {
margin-left: 8px;
cursor: pointer;
}
.bootstrap-tagsinput .tag [data-role="remove"]:after {
content: "x";
padding: 0px 2px;
}
.bootstrap-tagsinput .tag [data-role="remove"]:hover {
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
}
.bootstrap-tagsinput .tag [data-role="remove"]:hover:active {
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
}

View file

@ -1,667 +0,0 @@
(function ($) {
"use strict";
var defaultOptions = {
tagClass: function (item) {
return 'label label-info';
},
itemValue: function (item) {
return item ? item.toString() : item;
},
itemText: function (item) {
return this.itemValue(item);
},
itemTitle: function (item) {
return null;
},
freeInput: true,
addOnBlur: true,
maxTags: undefined,
maxChars: undefined,
confirmKeys: [13, 44],
delimiter: ',',
delimiterRegex: null,
cancelConfirmKeysOnEmpty: true,
onTagExists: function (item, $tag) {
$tag.hide().fadeIn();
},
trimValue: false,
allowDuplicates: false
};
/**
* Constructor function
*/
function TagsInput(element, options) {
this.itemsArray = [];
this.$element = $(element);
this.$element.hide();
this.isSelect = (element.tagName === 'SELECT');
this.multiple = (this.isSelect && element.hasAttribute('multiple'));
this.objectItems = options && options.itemValue;
this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : '';
this.inputSize = Math.max(1, this.placeholderText.length);
this.$container = $('<div class="bootstrap-tagsinput"></div>');
this.$input = $('<input type="text" placeholder="' + this.placeholderText + '"/>').appendTo(this.$container);
this.$element.before(this.$container);
this.build(options);
}
TagsInput.prototype = {
constructor: TagsInput,
/**
* Adds the given item as a new tag. Pass true to dontPushVal to prevent
* updating the elements val()
*/
add: function (item, dontPushVal, options) {
var self = this;
if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags)
return;
// Ignore falsey values, except false
if (item !== false && !item)
return;
// Trim value
if (typeof item === "string" && self.options.trimValue) {
item = $.trim(item);
}
// Throw an error when trying to add an object while the itemValue option was not set
if (typeof item === "object" && !self.objectItems)
throw("Can't add objects when itemValue option is not set");
// Ignore strings only containg whitespace
if (item.toString().match(/^\s*$/))
return;
// If SELECT but not multiple, remove current tag
if (self.isSelect && !self.multiple && self.itemsArray.length > 0)
self.remove(self.itemsArray[0]);
if (typeof item === "string" && this.$element[0].tagName === 'INPUT') {
var delimiter = (self.options.delimiterRegex) ? self.options.delimiterRegex : self.options.delimiter;
var items = item.split(delimiter);
if (items.length > 1) {
for (var i = 0; i < items.length; i++) {
this.add(items[i], true);
}
if (!dontPushVal)
self.pushVal();
return;
}
}
var itemValue = self.options.itemValue(item),
itemText = self.options.itemText(item),
tagClass = self.options.tagClass(item),
itemTitle = self.options.itemTitle(item);
// Ignore items allready added
var existing = $.grep(self.itemsArray, function (item) {
return self.options.itemValue(item) === itemValue;
})[0];
if (existing && !self.options.allowDuplicates) {
// Invoke onTagExists
if (self.options.onTagExists) {
var $existingTag = $(".tag", self.$container).filter(function () {
return $(this).data("item") === existing;
});
self.options.onTagExists(item, $existingTag);
}
return;
}
// if length greater than limit
if (self.items().toString().length + item.length + 1 > self.options.maxInputLength)
return;
// raise beforeItemAdd arg
var beforeItemAddEvent = $.Event('beforeItemAdd', {item: item, cancel: false, options: options});
self.$element.trigger(beforeItemAddEvent);
if (beforeItemAddEvent.cancel)
return;
// register item in internal array and map
self.itemsArray.push(item);
// add a tag element
var $tag = $('<span class="tag ' + htmlEncode(tagClass) + (itemTitle !== null ? ('" title="' + itemTitle) : '') + '">' + htmlEncode(itemText) + '<span data-role="remove"></span></span>');
$tag.data('item', item);
self.findInputWrapper().before($tag);
$tag.after(' ');
// add <option /> if item represents a value not present in one of the <select />'s options
if (self.isSelect && !$('option[value="' + encodeURIComponent(itemValue) + '"]', self.$element)[0]) {
var $option = $('<option selected>' + htmlEncode(itemText) + '</option>');
$option.data('item', item);
$option.attr('value', itemValue);
self.$element.append($option);
}
if (!dontPushVal)
self.pushVal();
// Add class when reached maxTags
if (self.options.maxTags === self.itemsArray.length || self.items().toString().length === self.options.maxInputLength)
self.$container.addClass('bootstrap-tagsinput-max');
self.$element.trigger($.Event('itemAdded', {item: item, options: options}));
},
/**
* Removes the given item. Pass true to dontPushVal to prevent updating the
* elements val()
*/
remove: function (item, dontPushVal, options) {
var self = this;
if (self.objectItems) {
if (typeof item === "object")
item = $.grep(self.itemsArray, function (other) {
return self.options.itemValue(other) == self.options.itemValue(item);
});
else
item = $.grep(self.itemsArray, function (other) {
return self.options.itemValue(other) == item;
});
item = item[item.length - 1];
}
if (item) {
var beforeItemRemoveEvent = $.Event('beforeItemRemove', {item: item, cancel: false, options: options});
self.$element.trigger(beforeItemRemoveEvent);
if (beforeItemRemoveEvent.cancel)
return;
$('.tag', self.$container).filter(function () {
return $(this).data('item') === item;
}).remove();
$('option', self.$element).filter(function () {
return $(this).data('item') === item;
}).remove();
if ($.inArray(item, self.itemsArray) !== -1)
self.itemsArray.splice($.inArray(item, self.itemsArray), 1);
}
if (!dontPushVal)
self.pushVal();
// Remove class when reached maxTags
if (self.options.maxTags > self.itemsArray.length)
self.$container.removeClass('bootstrap-tagsinput-max');
self.$element.trigger($.Event('itemRemoved', {item: item, options: options}));
},
/**
* Removes all items
*/
removeAll: function () {
var self = this;
$('.tag', self.$container).remove();
$('option', self.$element).remove();
while (self.itemsArray.length > 0)
self.itemsArray.pop();
self.pushVal();
},
/**
* Refreshes the tags so they match the text/value of their corresponding
* item.
*/
refresh: function () {
var self = this;
$('.tag', self.$container).each(function () {
var $tag = $(this),
item = $tag.data('item'),
itemValue = self.options.itemValue(item),
itemText = self.options.itemText(item),
tagClass = self.options.tagClass(item);
// Update tag's class and inner text
$tag.attr('class', null);
$tag.addClass('tag ' + htmlEncode(tagClass));
$tag.contents().filter(function () {
return this.nodeType == 3;
})[0].nodeValue = htmlEncode(itemText);
if (self.isSelect) {
var option = $('option', self.$element).filter(function () {
return $(this).data('item') === item;
});
option.attr('value', itemValue);
}
});
},
/**
* Returns the items added as tags
*/
items: function () {
return this.itemsArray;
},
/**
* Assembly value by retrieving the value of each item, and set it on the
* element.
*/
pushVal: function () {
var self = this,
val = $.map(self.items(), function (item) {
return self.options.itemValue(item).toString();
});
self.$element.val(val, true).trigger('change');
},
/**
* Initializes the tags input behaviour on the element
*/
build: function (options) {
var self = this;
self.options = $.extend({}, defaultOptions, options);
// When itemValue is set, freeInput should always be false
if (self.objectItems)
self.options.freeInput = false;
makeOptionItemFunction(self.options, 'itemValue');
makeOptionItemFunction(self.options, 'itemText');
makeOptionFunction(self.options, 'tagClass');
// Typeahead Bootstrap version 2.3.2
if (self.options.typeahead) {
var typeahead = self.options.typeahead || {};
makeOptionFunction(typeahead, 'source');
self.$input.typeahead($.extend({}, typeahead, {
source: function (query, process) {
function processItems(items) {
var texts = [];
for (var i = 0; i < items.length; i++) {
var text = self.options.itemText(items[i]);
map[text] = items[i];
texts.push(text);
}
process(texts);
}
this.map = {};
var map = this.map,
data = typeahead.source(query);
if ($.isFunction(data.success)) {
// support for Angular callbacks
data.success(processItems);
} else if ($.isFunction(data.then)) {
// support for Angular promises
data.then(processItems);
} else {
// support for functions and jquery promises
$.when(data)
.then(processItems);
}
},
updater: function (text) {
self.add(this.map[text]);
return this.map[text];
},
matcher: function (text) {
return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1);
},
sorter: function (texts) {
return texts.sort();
},
highlighter: function (text) {
var regex = new RegExp('(' + this.query + ')', 'gi');
return text.replace(regex, "<strong>$1</strong>");
}
}));
}
// typeahead.js
if (self.options.typeaheadjs) {
var typeaheadConfig = null;
var typeaheadDatasets = {};
// Determine if main configurations were passed or simply a dataset
var typeaheadjs = self.options.typeaheadjs;
if ($.isArray(typeaheadjs)) {
typeaheadConfig = typeaheadjs[0];
typeaheadDatasets = typeaheadjs[1];
} else {
typeaheadDatasets = typeaheadjs;
}
self.$input.typeahead(typeaheadConfig, typeaheadDatasets).on('typeahead:selected', $.proxy(function (obj, datum) {
if (typeaheadDatasets.valueKey)
self.add(datum[typeaheadDatasets.valueKey]);
else
self.add(datum);
self.$input.typeahead('val', '');
}, self));
}
self.$container.on('click', $.proxy(function (event) {
if (!self.$element.attr('disabled')) {
self.$input.removeAttr('disabled');
}
self.$input.focus();
}, self));
if (self.options.addOnBlur && self.options.freeInput) {
self.$input.on('focusout', $.proxy(function (event) {
// HACK: only process on focusout when no typeahead opened, to
// avoid adding the typeahead text as tag
if ($('.typeahead, .twitter-typeahead', self.$container).length === 0) {
self.add(self.$input.val());
self.$input.val('');
}
}, self));
}
self.$container.on('keydown', 'input', $.proxy(function (event) {
var $input = $(event.target),
$inputWrapper = self.findInputWrapper();
if (self.$element.attr('disabled')) {
self.$input.attr('disabled', 'disabled');
return;
}
switch (event.which) {
// BACKSPACE
case 8:
if (doGetCaretPosition($input[0]) === 0) {
var prev = $inputWrapper.prev();
if (prev.length) {
self.remove(prev.data('item'));
}
}
break;
// DELETE
case 46:
if (doGetCaretPosition($input[0]) === 0) {
var next = $inputWrapper.next();
if (next.length) {
self.remove(next.data('item'));
}
}
break;
// LEFT ARROW
case 37:
// Try to move the input before the previous tag
var $prevTag = $inputWrapper.prev();
if ($input.val().length === 0 && $prevTag[0]) {
$prevTag.before($inputWrapper);
$input.focus();
}
break;
// RIGHT ARROW
case 39:
// Try to move the input after the next tag
var $nextTag = $inputWrapper.next();
if ($input.val().length === 0 && $nextTag[0]) {
$nextTag.after($inputWrapper);
$input.focus();
}
break;
default:
// ignore
}
// Reset internal input's size
var textLength = $input.val().length,
wordSpace = Math.ceil(textLength / 5),
size = textLength + wordSpace + 1;
$input.attr('size', Math.max(this.inputSize, $input.val().length));
}, self));
self.$container.on('keypress', 'input', $.proxy(function (event) {
var $input = $(event.target);
if (self.$element.attr('disabled')) {
self.$input.attr('disabled', 'disabled');
return;
}
var text = $input.val(),
maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars;
if (self.options.freeInput && (keyCombinationInList(event, self.options.confirmKeys) || maxLengthReached)) {
// Only attempt to add a tag if there is data in the field
if (text.length !== 0) {
self.add(maxLengthReached ? text.substr(0, self.options.maxChars) : text);
$input.val('');
}
// If the field is empty, let the event triggered fire as usual
if (self.options.cancelConfirmKeysOnEmpty === false) {
event.preventDefault();
}
}
// Reset internal input's size
var textLength = $input.val().length,
wordSpace = Math.ceil(textLength / 5),
size = textLength + wordSpace + 1;
$input.attr('size', Math.max(this.inputSize, $input.val().length));
}, self));
// Remove icon clicked
self.$container.on('click', '[data-role=remove]', $.proxy(function (event) {
if (self.$element.attr('disabled')) {
return;
}
self.remove($(event.target).closest('.tag').data('item'));
}, self));
// Only add existing value as tags when using strings as tags
if (self.options.itemValue === defaultOptions.itemValue) {
if (self.$element[0].tagName === 'INPUT') {
self.add(self.$element.val());
} else {
$('option', self.$element).each(function () {
self.add($(this).attr('value'), true);
});
}
}
},
/**
* Removes all tagsinput behaviour and unregsiter all event handlers
*/
destroy: function () {
var self = this;
// Unbind events
self.$container.off('keypress', 'input');
self.$container.off('click', '[role=remove]');
self.$container.remove();
self.$element.removeData('tagsinput');
self.$element.show();
},
/**
* Sets focus on the tagsinput
*/
focus: function () {
this.$input.focus();
},
/**
* Returns the internal input element
*/
input: function () {
return this.$input;
},
/**
* Returns the element which is wrapped around the internal input. This
* is normally the $container, but typeahead.js moves the $input element.
*/
findInputWrapper: function () {
var elt = this.$input[0],
container = this.$container[0];
while (elt && elt.parentNode !== container)
elt = elt.parentNode;
return $(elt);
}
};
/**
* Register JQuery plugin
*/
$.fn.tagsinput = function (arg1, arg2, arg3) {
var results = [];
this.each(function () {
var tagsinput = $(this).data('tagsinput');
// Initialize a new tags input
if (!tagsinput) {
tagsinput = new TagsInput(this, arg1);
$(this).data('tagsinput', tagsinput);
results.push(tagsinput);
if (this.tagName === 'SELECT') {
$('option', $(this)).attr('selected', 'selected');
}
// Init tags from $(this).val()
$(this).val($(this).val());
} else if (!arg1 && !arg2) {
// tagsinput already exists
// no function, trying to init
results.push(tagsinput);
} else if (tagsinput[arg1] !== undefined) {
// Invoke function on existing tags input
if (tagsinput[arg1].length === 3 && arg3 !== undefined) {
var retVal = tagsinput[arg1](arg2, null, arg3);
} else {
var retVal = tagsinput[arg1](arg2);
}
if (retVal !== undefined)
results.push(retVal);
}
});
if (typeof arg1 == 'string') {
// Return the results from the invoked function calls
return results.length > 1 ? results : results[0];
} else {
return results;
}
};
$.fn.tagsinput.Constructor = TagsInput;
/**
* Most options support both a string or number as well as a function as
* option value. This function makes sure that the option with the given
* key in the given options is wrapped in a function
*/
function makeOptionItemFunction(options, key) {
if (typeof options[key] !== 'function') {
var propertyName = options[key];
options[key] = function (item) {
return item[propertyName];
};
}
}
function makeOptionFunction(options, key) {
if (typeof options[key] !== 'function') {
var value = options[key];
options[key] = function () {
return value;
};
}
}
/**
* HtmlEncodes the given value
*/
var htmlEncodeContainer = $('<div />');
function htmlEncode(value) {
if (value) {
return htmlEncodeContainer.text(value).html();
} else {
return '';
}
}
/**
* Returns the position of the caret in the given input field
* http://flightschool.acylt.com/devnotes/caret-position-woes/
*/
function doGetCaretPosition(oField) {
var iCaretPos = 0;
if (document.selection) {
oField.focus();
var oSel = document.selection.createRange();
oSel.moveStart('character', -oField.value.length);
iCaretPos = oSel.text.length;
} else if (oField.selectionStart || oField.selectionStart == '0') {
iCaretPos = oField.selectionStart;
}
return (iCaretPos);
}
/**
* Returns boolean indicates whether user has pressed an expected key combination.
* @param object keyPressEvent: JavaScript event object, refer
* http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
* @param object lookupList: expected key combinations, as in:
* [13, {which: 188, shiftKey: true}]
*/
function keyCombinationInList(keyPressEvent, lookupList) {
var found = false;
$.each(lookupList, function (index, keyCombination) {
if (typeof (keyCombination) === 'number' && keyPressEvent.which === keyCombination) {
found = true;
return false;
}
if (keyPressEvent.which === keyCombination.which) {
var alt = !keyCombination.hasOwnProperty('altKey') || keyPressEvent.altKey === keyCombination.altKey,
shift = !keyCombination.hasOwnProperty('shiftKey') || keyPressEvent.shiftKey === keyCombination.shiftKey,
ctrl = !keyCombination.hasOwnProperty('ctrlKey') || keyPressEvent.ctrlKey === keyCombination.ctrlKey;
if (alt && shift && ctrl) {
found = true;
return false;
}
}
});
return found;
}
/**
* Initialize tagsinput behaviour on inputs and selects which have
* data-role=tagsinput
*/
$(function () {
$("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput();
});
})(window.jQuery);

View file

@ -1,53 +0,0 @@
.bootstrap-tagsinput {
background-color: #fff;
border: 1px solid #ccc;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
display: inline-block;
padding: 4px 6px;
margin-bottom: 10px;
color: #555;
vertical-align: middle;
border-radius: 4px;
max-width: 100%;
line-height: 22px;
cursor: text;
input {
border: none;
box-shadow: none;
outline: none;
background-color: transparent;
padding: 0;
margin: 0;
width: auto !important;
max-width: inherit;
&:focus {
border: none;
box-shadow: none;
}
}
.tag {
margin-right: 2px;
color: white;
[data-role="remove"] {
margin-left: 8px;
cursor: pointer;
&:after {
content: "x";
padding: 0px 2px;
}
&:hover {
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
&:active {
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
}
}
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

80
doc/nginx.conf Normal file
View file

@ -0,0 +1,80 @@
# Request limit zone to help mitigate attacks
limit_req_zone $binary_remote_addr zone=ip:10m rate=5r/s;
# Cleartext listener for LetsEncrypt and HTTPS redirects.
server {
listen 80;
server_name ponepaste.org;
location ^~ /.well-known/acme-challenge/ {
root /var/www/letsencrypt/;
}
location / {
return 301 https://ponepaste.org$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/ponepaste.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ponepaste.org/privkey.pem;
add_header Strict-Transport-Security "max-age=63072000" always;
# ModSecurity config; optional, but recommended.
modsecurity on;
modsecurity_rules_file /etc/modsecurity/modsecurity.conf;
root /srv/http/ponepaste.org;
index index.html index.php;
server_name ponepaste.org;
rewrite ^/$ /index.php last;
rewrite ^/([0-9]+)$ /paste.php?id=$1 last;
rewrite ^/page/([a-zA-Z0-9]+)/?$ /pages.php?page=$1 last;
# simple routes that just map to $1.php
rewrite ^/(archive|discover|profile|contact|report|event|captcha|login|logout)/?$ /$1.php last;
# routes for users
rewrite ^/user/([^/]+)/?$ /user.php?user=$1 last;
rewrite ^/user/([^/]+)/([^/]+)/?$ /user.php?user=$1&q=$2 last;
# routes for pastes
rewrite ^/(download|raw|embed)/(.+)$ /paste.php?$1&id=$2 last;
# weird registration routes that use a URL parameter rather than a different page (FIXME)
rewrite ^/register$ /login.php last;
rewrite ^/forgot$ /login.php last;
location ~* \.(jpg|jpeg|png|gif|ico|css|js) {
add_header "Cache-Control" "public";
expires 1h;
}
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
limit_req zone=ip burst=10 delay=8;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
# Deny directories that should not be publicly accessible.
location ~ (/doc|/tmp|/includes|/config|/.git|/.ht|/js|/node_modules|/composer).* {
deny all;
}
location ~ /\.ht {
deny all;
}
}

View file

@ -1,31 +0,0 @@
<?php
/*
* Paste <https://github.com/jordansamuel/PASTE>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License in GPL.txt for more details.
*/
define('IN_PONEPASTE', 1);
require_once('includes/common.php');
require_once('includes/functions.php');
// UTF-8
header('Content-Type: text/html; charset=utf-8');
$date = date('jS F Y');
$ip = $_SERVER['REMOTE_ADDR'];
$p_title = $lang['archive']; // "Pastes Archive";
// Theme
require_once('theme/' . $default_theme . '/header.php');
require_once('theme/' . $default_theme . '/event.php');
require_once('theme/' . $default_theme . '/footer.php');

26
fav.php
View file

@ -1,26 +0,0 @@
<?php
define('IN_PONEPASTE', 1);
require_once('includes/common.php');
require_once('includes/functions.php');
// UTF-8
header('Content-Type: text/html; charset=utf-8');
if ($current_user && !empty($_POST['fid'])) {
$paste_id = intval($_POST['fid']);
$query = $conn->prepare('SELECT 1 FROM pins WHERE paste_id = ? AND user_id = ?');
$query->execute([$paste_id, $current_user->user_id]);
if ($query->fetch()) { /* Already favorited */
$query = $conn->prepare('DELETE FROM pins WHERE paste_id = ? AND user_id = ?');
} else {
$query = $conn->prepare('INSERT INTO pins (paste_id, user_id, f_time) VALUES (?, ?, NOW())');
}
$query->execute([$paste_id, $current_user->user_id]);
$error = 'Paste has been favorited.';
}
// Theme
require_once('theme/' . $default_theme . '/header.php');
require_once('theme/' . $default_theme . '/report.php');

View file

@ -1,44 +0,0 @@
<?php
class DatabaseHandle {
private PDO $conn;
public function __construct(string $conString, string $username, string $password) {
$this->conn = new PDO($conString, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
]);
}
public function prepare(string $query) : PDOStatement {
return $this->conn->prepare($query);
}
public function query(string $query, array $params = null) : PDOStatement {
if (empty($params)) {
return $this->conn->query($query);
}
$stmt = $this->conn->prepare($query);
$stmt->execute($params);
return $stmt;
}
public function querySelectOne(string $query, array $params = null, int $fetchMode = PDO::FETCH_ASSOC) : array|null {
$stmt = $this->query($query, $params);
if ($row = $stmt->fetch($fetchMode)) {
return $row;
}
return null;
}
public function queryInsert(string $query, array $params = null) : int {
$this->query($query, $params);
return (int)$this->conn->lastInsertId();
}
}

View file

@ -0,0 +1,62 @@
<?php
namespace PonePaste\Helpers;
use PonePaste\Models\User;
use PonePaste\Models\Paste;
class AbilityHelper {
private array $modelToActions = [];
private User | null $user;
public function __construct(User | null $user) {
$this->user = $user;
$this->setupAllowedActions();
}
public function can(string $action, mixed $subject) : bool {
if ($this->user !== null
&& $this->user->role == User::ROLE_ADMIN) { // Admins can do anything
return true;
}
return $this->modelToActions[$subject::class][$action]($this->user, $subject);
}
private function setupAllowedActions() : void {
$this->modelToActions['PonePaste\\Models\\Paste'] = [
'view' => function(User | null $user, Paste $paste) {
$publicly_visible = ((int) $paste->visible !== Paste::VISIBILITY_PRIVATE) && !$paste->is_hidden;
return $publicly_visible // Everyone can see public pastes
|| ($user !== null && $user->id === $paste->user_id) // Creators of pastes can see their own private pastes
|| $user->role >= User::ROLE_MODERATOR; // Moderators and above can see all pastes
},
'edit' => function(User | null $user, Paste $paste) {
return $user !== null
&& $user->id === $paste->user_id; // Creators of non-anonymous pastes can edit their own pastes
},
'hide' => function(User | null $user, Paste $paste) {
return $user !== null
&& $user->role >= User::ROLE_MODERATOR; // Moderators and above can hide pastes
},
'delete' => function(User | null $user, Paste $paste) {
return $user !== null
&& ($user->id === $paste->user_id // Creators of pastes can delete their own pastes
|| $user->role >= User::ROLE_ADMIN); // Admins can delete all pastes
}
];
$this->modelToActions['PonePaste\\Models\\User'] = [
'view' => function(User | null $user, User $subject) {
return true; // Everyone can view users
},
'edit' => function(User | null $user, User $subject) {
return $user !== null
&& $user->id === $subject->id; // Users can edit their own profiles
},
'administrate' => function(User | null $user, User $subject) {
return $user !== null
&& $user->role >= User::ROLE_ADMIN; // Admins can edit all users
}
];
}
}

View file

@ -0,0 +1,66 @@
<?php
namespace PonePaste\Helpers;
use DateTime;
use PonePaste\Models\User;
use PonePaste\Models\UserSession;
class SessionHelper {
public const REMEMBER_TOKEN_COOKIE = '_ponepaste_token';
public const CSRF_TOKEN_KEY = 'csrf_token';
public static function currentUser() {
$session_user = SessionHelper::currentUserFromPhpSession();
if ($session_user !== null) {
return $session_user;
}
if (!empty($_COOKIE[self::REMEMBER_TOKEN_COOKIE]) &&
($session = SessionHelper::currentUserFromRememberToken($_COOKIE[self::REMEMBER_TOKEN_COOKIE]))) {
$_SESSION['user_id'] = $session->user_id;
return $session;
}
return null;
}
public static function destroySession() : void {
$token = $_COOKIE[SessionHelper::REMEMBER_TOKEN_COOKIE];
UserSession::where('token', $token)->delete();
unset($_COOKIE[SessionHelper::REMEMBER_TOKEN_COOKIE]);
setcookie(SessionHelper::REMEMBER_TOKEN_COOKIE, null, time() - 3600);
}
private static function currentUserFromRememberToken(string $remember_token) {
$session = UserSession
::with('user')
->where('token', $remember_token)
->first();
if (!$session) {
return null;
}
$session_expiry = $session->expire_at;
$now = new DateTime();
/* Session is expired (diff is negative) */
if ($now->diff($session_expiry)->invert === 1) {
$session->delete();
return null;
}
return $session->user;
}
private static function currentUserFromPhpSession() {
if (empty($_SESSION['user_id'])) {
return null;
}
return User::find(intval($_SESSION['user_id']));
}
}

View file

@ -0,0 +1,25 @@
<?php
namespace PonePaste\Models;
use Illuminate\Database\Eloquent\Model;
class AdminLog extends Model {
public const ACTION_LOGIN = 0;
public const ACTION_FAIL_LOGIN = 1;
public const ACTION_EDIT_CONFIG = 2;
public const ACTION_NAMES = [
'Login',
'Failed Login',
'Edit Config'
];
protected $table = 'admin_logs';
protected $fillable = ['user_id', 'action', 'ip', 'time'];
public $timestamps = false;
public function user() {
return $this->belongsto(User::class);
}
}

13
includes/Models/Badge.php Normal file
View file

@ -0,0 +1,13 @@
<?php
namespace PonePaste\Models;
use Illuminate\Database\Eloquent\Model;
class Badge extends Model {
protected $table = 'badges';
public $timestamps = false;
protected $fillable = [
'name', 'image_url'
];
}

View file

@ -0,0 +1,8 @@
<?php
namespace PonePaste\Models;
use Illuminate\Database\Eloquent\Model;
class IPBan extends Model {
protected $table = 'ban_user';
}

8
includes/Models/Page.php Normal file
View file

@ -0,0 +1,8 @@
<?php
namespace PonePaste\Models;
use Illuminate\Database\Eloquent\Model;
class Page extends Model {
protected $table = 'pages';
}

View file

@ -0,0 +1,11 @@
<?php
namespace PonePaste\Models;
use Illuminate\Database\Eloquent\Model;
class PageView extends Model {
protected $table = 'page_view';
protected $fillable = ['date'];
public $timestamps = false;
}

134
includes/Models/Paste.php Normal file
View file

@ -0,0 +1,134 @@
<?php
namespace PonePaste\Models;
use DateTime;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
class Paste extends Model {
public const VISIBILITY_PUBLIC = 0;
public const VISIBILITY_UNLISTED = 1;
public const VISIBILITY_PRIVATE = 2;
protected $table = 'pastes';
protected $guarded = [];
protected $casts = [
'visible' => 'integer',
'encrypt' => 'boolean'
];
public $timestamps = false;
public function user() {
return $this->belongsTo(User::class);
}
public function tags() {
return $this->belongsToMany(Tag::class, 'paste_taggings');
}
public function favouriters() {
return $this->belongsToMany(User::class, 'user_favourites');
}
public function reports() {
return $this->hasMany(Report::class);
}
public function replaceTags(array $tags) : void {
$this->tags()->detach();
foreach ($tags as $tagName) {
$tag = Tag::getOrCreateByName($tagName);
$this->tags()->attach($tag);
}
$this->save();
}
public function expiryDisplay() {
$expiry = $this->expiry;
if (!$expiry || $expiry === 'NULL') { // TODO: Investigate why this is a string
return 'Never';
}
if ($expiry == 'SELF') {
return '<b>View Once</b>';
}
var_dump($expiry);
$dateTime = new DateTime($expiry);
$dateTime->setTimestamp($expiry);
$ret = $dateTime->format('Y-m-d H:i:s');
if ($dateTime->diff(new DateTime())->days < 1) {
$ret = "<b>$ret</b>";
}
return $ret;
}
public static function getRecent(int $count = 10) : Collection {
return Paste::with('user')
->orderBy('created_at', 'DESC')
->where('visible', self::VISIBILITY_PUBLIC)
->where('is_hidden', false)
->whereRaw("((expiry IS NULL) OR ((expiry != 'SELF') AND (expiry > NOW())))")
->limit($count)->get();
}
public static function getRecentlyUpdated(int $count = 10) : Collection {
return Paste::with('user')
->orderBy('updated_at', 'DESC')
->where('visible', self::VISIBILITY_PUBLIC)
->where('is_hidden', false)
->whereRaw("((expiry IS NULL) OR ((expiry != 'SELF') AND (expiry > NOW())))")
->limit($count)->get();
}
public static function getMostViewed(int $count = 10) : Collection {
return Paste::with('user')
->orderBy('views')
->where('visible', self::VISIBILITY_PUBLIC)
->where('is_hidden', false)
->whereRaw("((expiry IS NULL) OR ((expiry != 'SELF') AND (expiry > NOW())))")
->limit($count)->get();
}
public static function getMonthPopular(int $count = 10) : Collection {
return Paste::with('user')
->whereRaw('MONTH(created_at) = MONTH(NOW())')
->where('visible', self::VISIBILITY_PUBLIC)
->where('is_hidden', false)
->whereRaw("((expiry IS NULL) OR ((expiry != 'SELF') AND (expiry > NOW())))")
->orderBy('views')
->limit($count)->get();
}
public static function getRandom(int $count = 10) : array {
$total_pastes = Paste::count();
$pastes = [];
for ($i = 0; $i < $count; $i++) {
$pastes[] = self::getSingleRandom($total_pastes);
}
return $pastes;
}
private static function getSingleRandom(int $total) {
$paste = null;
do {
$paste_id = rand(1, $total);
$paste = Paste::with('user')
->where('visible', self::VISIBILITY_PUBLIC)
->where('is_hidden', false)
->whereRaw("((expiry IS NULL) OR ((expiry != 'SELF') AND (expiry > NOW())))")
->where('id', $paste_id)
->first();
} while (!$paste);
return $paste;
}
}

View file

@ -0,0 +1,22 @@
<?php
namespace PonePaste\Models;
use Illuminate\Database\Eloquent\Model;
class Report extends Model {
protected $table = 'reports';
protected $fillable = [
'paste_id',
'user_id',
'reason',
'open'
];
public function user() {
return $this->belongsTo(User::class);
}
public function paste() {
return $this->belongsTo(Paste::class);
}
}

View file

@ -1,54 +1,26 @@
<?php
namespace PonePaste\Models;
class Tag {
public int $id;
public string $name;
public string $slug;
use Illuminate\Database\Eloquent\Model;
public function __construct(array $row) {
$this->id = (int)$row['id'];
$this->name = $row['name'];
$this->slug = $row['slug'];
}
class Tag extends Model {
protected $table = 'tags';
protected $fillable = ['name', 'slug'];
public $timestamps = false;
public static function getOrCreateByName(DatabaseHandle $conn, string $name) : Tag {
public static function getOrCreateByName(string $name) : Tag {
$name = Tag::cleanTagName($name);
if ($row = $conn->querySelectOne('SELECT id, name, slug FROM tags WHERE name = ?', [$name])) {
return new Tag($row);
if ($tag = Tag::where('name', $name)->first()) {
return $tag;
}
$new_slug = Tag::encodeSlug($name);
$new_tag_id = $conn->queryInsert('INSERT INTO tags (name, slug) VALUES (?, ?)', [$name, $new_slug]);
return new Tag([
'id' => $new_tag_id,
return Tag::create([
'name' => $name,
'slug' => $new_slug
'slug' => Tag::encodeSlug($name)
]);
}
public static function findBySlug(DatabaseHandle $conn, string $slug) : Tag|null {
if ($row = $conn->querySelectOne('SELECT id, name, slug FROM tags WHERE slug = ?', [$slug])) {
return new Tag($row);
}
return null;
}
public static function replacePasteTags(DatabaseHandle $conn, int $pasteId, array $tags) {
$conn->query('DELETE FROM paste_taggings WHERE paste_id = ?', [$pasteId]);
foreach ($tags as $tagName) {
$tag = Tag::getOrCreateByName($conn, $tagName);
$conn->query('INSERT INTO paste_taggings (paste_id, tag_id) VALUES (?, ?)', [$pasteId, $tag->id]);
}
// FIXME: We need to get rid of tagsys.
$conn->query('UPDATE pastes SET tagsys = ? WHERE id = ?', [implode(',', $tags), $pasteId]);
}
/**
* Normalize a tag name, which involves downcasing it, normalizing smart quotes, trimming the string, and
* normalizing runs of whitespace to a single space.
@ -75,7 +47,7 @@ class Tag {
$cleanName = Tag::cleanTagName($tagName);
if (!empty($cleanName)) {
array_push($cleanTags, $cleanName);
$cleanTags[] = $cleanName;
}
}
@ -93,4 +65,4 @@ class Tag {
/* urlencode it. for URLs, dipshit. */
return str_replace('%20', '+', urlencode($name));
}
}
}

33
includes/Models/User.php Normal file
View file

@ -0,0 +1,33 @@
<?php
namespace PonePaste\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model {
public const ROLE_MODERATOR = 1;
public const ROLE_ADMIN = 2;
protected $table = 'users';
protected $fillable = [
'username', 'password', 'recovery_code_hash', 'ip'
];
public function session() {
return $this->hasOne(UserSession::class);
}
public function favourites() {
return $this->belongsToMany(Paste::class, 'user_favourites')->withPivot('created_at')
->whereRaw("((expiry IS NULL) OR ((expiry != 'SELF') AND (expiry > NOW())))");
}
public function pastes() {
return $this->hasMany(Paste::class)
->whereRaw("((expiry IS NULL) OR ((expiry != 'SELF') AND (expiry > NOW())))");
}
public function badges() {
return $this->hasMany(Badge::class);
}
}

View file

@ -0,0 +1,20 @@
<?php
namespace PonePaste\Models;
use Illuminate\Database\Eloquent\Model;
class UserSession extends Model {
protected $table = 'user_sessions';
protected $casts = [
'expire_at' => 'datetime'
];
protected $fillable = [
'user_id', 'token', 'expire_at'
];
public function user() {
return $this->belongsTo(User::class);
}
}

View file

@ -1,36 +0,0 @@
<?php
class NonRetardedSSP {
public static function run(DatabaseHandle $conn, array $request, string $countQuery, string $query) {
/* Some of these parameters might not be passed; zero is an OK default */
$draw = (int) @$request['draw'];
$start = (int) @$request['start'];
$length = (int) @$request['length'];
/* figure out total records */
$recordsTotal = (int) $conn->querySelectOne($countQuery, [], PDO::FETCH_NUM)[0];
/* build query */
$params = [];
if ($length != 0) {
$query .= ' LIMIT ?';
array_push($params, $length);
if ($start != 0) {
$query .= ' OFFSET ?';
array_push($params, $start);
}
}
/* fire it off */
$stmt = $conn->query($query, $params);
$data = $stmt->fetchAll(PDO::FETCH_NUM);
return [
'draw' => $draw,
'recordsTotal' => $recordsTotal,
'recordsFiltered' => ($recordsTotal - count($data)),
'data' => $data
];
}
}

69
includes/Pastedown.php Normal file
View file

@ -0,0 +1,69 @@
<?php
namespace PonePaste;
use ParsedownExtra;
class Pastedown extends ParsedownExtra {
public function __construct() {
$this->BlockTypes['>'] = ['Greentext'];
array_unshift($this->BlockTypes['<'], 'Redtext');
$this->BlockTypes['@'] = ['Purpletext'];
}
protected function blockGreentext($Line)
{
if (preg_match('/^>[ ]?(.*)/', $Line['text'], $matches))
{
$Block = array(
'element' => array(
'name' => 'span',
'attributes' => [
'class' => 'greentext'
],
'handler' => 'line',
'text' => $matches[0],
),
);
return $Block;
}
}
protected function blockRedtext($Line)
{
if (preg_match('/^<[ ]?(.*)/', $Line['text'], $matches))
{
$Block = array(
'element' => array(
'name' => 'span',
'handler' => 'line',
'attributes' => [
'class' => 'redtext'
],
'text' => $matches[0],
),
);
return $Block;
}
}
protected function blockPurpletext($Line)
{
if (preg_match('/^@[ ]?(.*)/', $Line['text'], $matches))
{
$Block = array(
'element' => array(
'name' => 'span',
'handler' => 'line',
'attributes' => [
'class' => 'purpletext'
],
'text' => $matches[0],
),
);
return $Block;
}
}
}

View file

@ -1,76 +0,0 @@
<?php
class User {
public const REMEMBER_TOKEN_COOKIE = '_ponepaste_token';
public int $user_id;
public string $username;
private function __construct(array $row) {
$this->user_id = intval($row['id']);
$this->username = $row['username'];
}
public function destroySession(DatabaseHandle $conn, string $token) {
$conn->query('DELETE FROM user_sessions WHERE user_id = ? AND token = ?', [$this->user_id, $token]);
}
public static function findByUsername(DatabaseHandle $conn, string $username) : User|null {
$query = $conn->query('SELECT id, username FROM users WHERE username = ?', [$username]);
$row = $query->fetch();
return empty($row) ? null : new User($row);
}
public static function current(DatabaseHandle $conn) : User|null {
$session_user = User::createFromPhpSession($conn);
if ($session_user !== null) {
return $session_user;
}
if (!empty($_COOKIE[self::REMEMBER_TOKEN_COOKIE]) &&
($token_user = User::createFromRememberToken($conn, $_COOKIE[self::REMEMBER_TOKEN_COOKIE]))) {
$_SESSION['user_id'] = $token_user->user_id;
return $token_user;
}
return null;
}
public static function createFromRememberToken(DatabaseHandle $conn, string $remember_token) : User|null {
$result = $conn->query(
'SELECT users.id AS id, users.username AS username, users.banned AS banned, user_sessions.id AS session_id, user_sessions.expire_at AS session_expiry
FROM user_sessions
INNER JOIN users ON users.id = user_sessions.user_id
WHERE user_sessions.token = ?', [$remember_token]
);
if ($row = $result->fetch()) {
$session_expiry = new DateTime($row['session_expiry']);
$now = new DateTime();
/* Session is expired (diff is negative) */
if ($now->diff($session_expiry)->invert === 1) {
$conn->query('DELETE FROM user_sessions WHERE id = ?', [$row['session_id']]);
return null;
}
return new User($row);
}
return null;
}
public static function createFromPhpSession(DatabaseHandle $conn) : User|null {
if (empty($_SESSION['user_id'])) {
return null;
}
$user_id = intval($_SESSION['user_id']);
$row = $conn->query('SELECT id, username, banned FROM users WHERE id = ?', [$user_id])->fetch();
return $row ? new User($row) : null;
}
}

View file

@ -1,179 +1,31 @@
<?php
function setupCaptcha($token = null) : string {
global $redis;
$allowed = "ABCDEFGHIJKLMNOPQRSTUVYXYZabcdefghijklmnopqrstuvwxyz0123456789";
use JetBrains\PhpStorm\ArrayShape;
#[ArrayShape(['code' => "mixed|string", 'image_src' => "string"])]
function captcha($color, $mode, $mul, $allowed) : array {
$bg_path = dirname(__FILE__) . '/captchabg/';
$font_path = dirname(__FILE__) . '/fonts/';
if ($mul == "on") {
$captcha_config = array(
'code' => '',
'min_length' => 5,
'max_length' => 6,
'backgrounds' => array(
$bg_path . 'text3.png',
$bg_path . 'text2.png',
$bg_path . 'text1.png'
),
'fonts' => array(
$font_path . 'LMS Pretty Pony.ttf',
$font_path . 'PonyvilleMedium0.4.ttf',
$font_path . 'PonyvilleMedium0.4.ttf'
),
'characters' => $allowed,
'min_font_size' => 20,
'max_font_size' => 28,
'color' => $color,
'angle_min' => 0,
'angle_max' => 5,
'shadow' => true,
'shadow_color' => '#fff',
'shadow_offset_x' => -2,
'shadow_offset_y' => 4
);
} else {
$captcha_config = array(
'code' => '',
'min_length' => 5,
'max_length' => 5,
'backgrounds' => array(
$bg_path . 'text2.png'
),
'fonts' => array(
$font_path . 'times_new_yorker.ttf'
),
'characters' => $allowed,
'min_font_size' => 28,
'max_font_size' => 28,
'color' => $color,
'angle_min' => 0,
'angle_max' => 10,
'shadow' => true,
'shadow_color' => '#fff',
'shadow_offset_x' => -1,
'shadow_offset_y' => 1
);
$code = '';
for ($i = 0; $i < 5; $i++) {
$code .= substr($allowed, rand() % (strlen($allowed)), 1);
}
// Overwrite defaults with custom config values
if (!empty($config) && is_array($config)) {
foreach ($config as $key => $value)
$captcha_config[$key] = $value;
if ($token === null) {
$token = pp_random_password();
}
// Restrict certain values
if ($captcha_config['min_length'] < 1)
$captcha_config['min_length'] = 1;
if ($captcha_config['angle_min'] < 0)
$captcha_config['angle_min'] = 0;
if ($captcha_config['angle_max'] > 10)
$captcha_config['angle_max'] = 10;
if ($captcha_config['angle_max'] < $captcha_config['angle_min'])
$captcha_config['angle_max'] = $captcha_config['angle_min'];
if ($captcha_config['min_font_size'] < 10)
$captcha_config['min_font_size'] = 10;
if ($captcha_config['max_font_size'] < $captcha_config['min_font_size'])
$captcha_config['max_font_size'] = $captcha_config['min_font_size'];
$redis->setex('captcha/' . md5($token), 600, $code);
// Generate CAPTCHA code if not set by user
if (empty($captcha_config['code'])) {
$captcha_config['code'] = '';
$length = rand($captcha_config['min_length'], $captcha_config['max_length']);
while (strlen($captcha_config['code']) < $length) {
$captcha_config['code'] .= substr($captcha_config['characters'], rand() % (strlen($captcha_config['characters'])), 1);
}
}
// Generate HTML for image src
$image_src = substr(__FILE__, strlen(realpath($_SERVER['DOCUMENT_ROOT']))) . '?_CAPTCHA&amp;t=' . urlencode(microtime());
$image_src = '/' . ltrim(preg_replace('/\\\\/', '/', $image_src), '/');
$_SESSION['_CAPTCHA']['config'] = serialize($captcha_config);
return [
'code' => $captcha_config['code'],
'image_src' => $image_src
];
return $token;
}
if (!function_exists('hex2rgb')) {
function hex2rgb($hex_str, $return_string = false, $separator = ',') {
$hex_str = preg_replace("/[^0-9A-Fa-f]/", '', $hex_str); // Gets a proper hex string
$rgb_array = array();
if (strlen($hex_str) == 6) {
$color_val = hexdec($hex_str);
$rgb_array['r'] = 0xFF & ($color_val >> 0x10);
$rgb_array['g'] = 0xFF & ($color_val >> 0x8);
$rgb_array['b'] = 0xFF & $color_val;
} elseif (strlen($hex_str) == 3) {
$rgb_array['r'] = hexdec(str_repeat(substr($hex_str, 0, 1), 2));
$rgb_array['g'] = hexdec(str_repeat(substr($hex_str, 1, 1), 2));
$rgb_array['b'] = hexdec(str_repeat(substr($hex_str, 2, 1), 2));
} else {
return false;
}
return $return_string ? implode($separator, $rgb_array) : $rgb_array;
function checkCaptcha(string $token, string $answer) : bool {
global $redis;
$redis_answer = $redis->get('captcha/' . md5($token));
if (!$redis_answer) {
return false;
}
$redis->del('captcha/' . $token);
return strtolower($redis_answer) === strtolower($answer);
}
// Draw the image
if (isset($_GET['_CAPTCHA'])) {
session_start();
$captcha_config = unserialize($_SESSION['_CAPTCHA']['config']);
if (!$captcha_config)
exit();
// Pick random background, get info, and start captcha
$background = $captcha_config['backgrounds'][rand(0, count($captcha_config['backgrounds']) - 1)];
list($bg_width, $bg_height, $bg_type, $bg_attr) = getimagesize($background);
$captcha = imagecreatefrompng($background);
$color = hex2rgb($captcha_config['color']);
$color = imagecolorallocate($captcha, $color['r'], $color['g'], $color['b']);
// Determine text angle
$angle = rand($captcha_config['angle_min'], $captcha_config['angle_max']) * (rand(0, 1) == 1 ? -1 : 1);
// Select font randomly
$font = $captcha_config['fonts'][rand(0, count($captcha_config['fonts']) - 1)];
// Verify font file exists
if (!file_exists($font))
throw new Exception('Font file not found: ' . $font);
// Set the font size
$font_size = rand($captcha_config['min_font_size'], $captcha_config['max_font_size']);
$text_box_size = imagettfbbox($font_size, $angle, $font, $captcha_config['code']);
// Determine text position
$box_width = abs($text_box_size[6] - $text_box_size[2]);
$box_height = abs($text_box_size[5] - $text_box_size[1]);
$text_pos_x_min = 0;
$text_pos_x_max = ($bg_width) - ($box_width);
$text_pos_x = rand($text_pos_x_min, $text_pos_x_max);
$text_pos_y_min = $box_height;
$text_pos_y_max = ($bg_height) - ($box_height / 2);
$text_pos_y = rand($text_pos_y_min, $text_pos_y_max);
// Draw shadow
if ($captcha_config['shadow']) {
$shadow_color = hex2rgb($captcha_config['shadow_color']);
$shadow_color = imagecolorallocate($captcha, $shadow_color['r'], $shadow_color['g'], $shadow_color['b']);
imagettftext($captcha, $font_size, $angle, $text_pos_x + $captcha_config['shadow_offset_x'], $text_pos_y + $captcha_config['shadow_offset_y'], $shadow_color, $font, $captcha_config['code']);
}
// Draw text
imagettftext($captcha, $font_size, $angle, $text_pos_x, $text_pos_y, $color, $font, $captcha_config['code']);
// Output image
header("Content-type: image/png");
imagepng($captcha);
}

View file

@ -5,24 +5,146 @@ if (!defined('IN_PONEPASTE')) {
require_once(__DIR__ . '/../vendor/autoload.php');
require_once(__DIR__ . '/config.php');
require_once(__DIR__ . '/functions.php');
require_once(__DIR__ . '/DatabaseHandle.class.php');
require_once(__DIR__ . '/User.class.php');
require_once(__DIR__ . '/passwords.php');
require_once(__DIR__ . '/captcha.php');
use Illuminate\Database\Capsule\Manager as Capsule;
use PonePaste\Helpers\SessionHelper;
use PonePaste\Models\IPBan;
use PonePaste\Models\PageView;
use PonePaste\Models\Paste;
use PonePaste\Models\User;
use PonePaste\Helpers\AbilityHelper;
/* View functions */
function urlForPaste($paste_id) : string {
if (PP_MOD_REWRITE) {
return "/${paste_id}";
function javascriptIncludeTag(string $name) : string {
if (PP_DEBUG) {
return "<script src=\"/assets/bundle/{$name}.js\"></script>";
}
return "/paste.php?id=${paste_id}";
return "<script src=\"/assets/bundle/{$name}.min.js\"></script>";
}
function urlForMember(string $member_name) : string {
if (PP_MOD_REWRITE) {
return '/user/' . urlencode($member_name);
function urlForPage($page = '') : string {
if (!PP_MOD_REWRITE) {
$page .= '.php';
}
return '/user.php?name=' . urlencode($member_name);
return (isset($_SERVER['HTTPS']) ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['PHP_SELF']), '/\\') . '/' . $page;
}
function urlForPaste(Paste $paste) : string {
if (PP_MOD_REWRITE) {
return "/{$paste->id}";
}
return "/paste.php?id={$paste->id}";
}
function urlForReport(Paste $paste) : string {
if (PP_MOD_REWRITE) {
return "/{$paste->id}/report";
}
return "/report.php?id={$paste->id}";
}
function urlForMember(User $user) : string {
if (PP_MOD_REWRITE) {
return '/user/' . urlencode($user->username);
}
return '/user.php?name=' . urlencode($user->username);
}
/**
* @throws Exception if the names and values aren't the same length
*/
function optionsForSelect(array $displays, array $values, string $currentSelection = null) : string {
$size = count($displays);
if (count($values) !== $size) {
throw new Exception('Option names and option values must be the same count');
}
$html = '';
for ($i = 0; $i < $size; $i++) {
$html .= '<option value="' . pp_html_escape($values[$i]) . '"';
if ($currentSelection === $values[$i]) {
$html .= ' selected="selected"';
}
$html .= '>' . pp_html_escape($displays[$i]) . '</option>';
}
return $html;
}
/**
* @throws Exception if the flash level is invalid
*/
function flash(string $level, string $message) : void {
if (!isset($_SESSION['flashes'])) {
$_SESSION['flashes'] = [
'success' => [],
'warning' => [],
'error' => []
];
}
if (!array_key_exists($level, $_SESSION['flashes'])) {
throw new Exception('Invalid flash level ' . $level);
}
$_SESSION['flashes'][$level][] = $message;
}
function flashError(string $message) : void {
flash('error', $message);
}
function flashWarning(string $message) : void {
flash('warning', $message);
}
function flashSuccess(string $message) : void {
flash('success', $message);
}
function getFlashes() {
if (!isset($_SESSION['flashes'])) {
return ['success' => [], 'warning' => [], 'error' => []];
}
$flashes = $_SESSION['flashes'];
unset($_SESSION['flashes']);
return $flashes;
}
function outputFlashes($flashes) : void {
function __outputFlash($level, $flash) : void {
echo '<div class="notification is-' . $level . ' flash">
<i class="fa fa-exclamation-circle" aria-hidden="true"></i>'
. pp_html_escape($flash) .
'</div>';
}
foreach ($flashes['success'] as $flash) {
__outputFlash('info', $flash);
}
foreach ($flashes['warning'] as $flash) {
__outputFlash('warning', $flash);
}
foreach ($flashes['error'] as $flash) {
__outputFlash('danger', $flash);
}
}
/* Database functions */
@ -30,22 +152,6 @@ function getSiteInfo() : array {
return require(__DIR__ . '/../config/site.php');
}
function getSiteAds(DatabaseHandle $conn) : array|bool {
return $conn->query('SELECT text_ads, ads_1, ads_2 FROM ads LIMIT 1')->fetch();
}
function getSiteTotalPastes(DatabaseHandle $conn) : int {
return intval($conn->query('SELECT COUNT(*) FROM pastes')->fetch(PDO::FETCH_NUM)[0]);
}
function getSiteTotalviews(DatabaseHandle $conn) : int {
return intval($conn->query('SELECT tpage FROM page_view ORDER BY id DESC LIMIT 1')->fetch(PDO::FETCH_NUM)[0]);
}
function getSiteTotal_unique_views(DatabaseHandle $conn) : int {
return intval($conn->query('SELECT tvisit FROM page_view ORDER BY id DESC LIMIT 1')->fetch(PDO::FETCH_NUM)[0]);
}
/**
* Specialization of `htmlentities()` that avoids double escaping and uses UTF-8.
*
@ -56,105 +162,134 @@ function pp_html_escape(string $unescaped) : string {
return htmlspecialchars($unescaped, ENT_QUOTES, 'UTF-8', false);
}
function updatePageViews(DatabaseHandle $conn) : void {
/* I think there is one row for each day, and in that row, tpage = non-unique, tvisit = unique page views for that day */
function updatePageViews() : void {
global $redis;
$ip = $_SERVER['REMOTE_ADDR'];
$date = date('jS F Y');
$data_ip = file_get_contents('tmp/temp.tdata');
$last_page_view = $conn->query('SELECT * FROM page_view ORDER BY id DESC LIMIT 1')->fetch();
$last_date = $last_page_view['date'];
$last_page_view = PageView::orderBy('id', 'desc')->limit(1)->first();
if ($last_date == $date) {
$last_tpage = intval($last_page_view['tpage']) + 1;
if (str_contains($data_ip, $ip)) {
// IP already exists, Update view count
$statement = $conn->prepare("UPDATE page_view SET tpage = ? WHERE id = ?");
$statement->execute([$last_tpage, $last_page_view['id']]);
} else {
$last_tvisit = intval($last_page_view['tvisit']) + 1;
// Update both tpage and tvisit.
$statement = $conn->prepare("UPDATE page_view SET tpage = ?,tvisit = ? WHERE id = ?");
$statement->execute([$last_tpage, $last_tvisit, $last_page_view['id']]);
file_put_contents('tmp/temp.tdata', $data_ip . "\r\n" . $ip);
if ($last_page_view && $last_page_view->date == $date) {
if (!$redis->sIsMember('page_view_ips', $ip)) {
$last_page_view->tvisit++;
$redis->sAdd('page_view_ips', $ip);
}
$last_page_view->tpage++;
$last_page_view->save();
} else {
// Delete the file and clear data_ip
unlink("tmp/temp.tdata");
$redis->del('page_view_ips');
// New date is created
$statement = $conn->prepare("INSERT INTO page_view (date, tpage, tvisit) VALUES (?, '1', '1')");
$statement->execute([$date]);
$new_page_view = new PageView(['date' => $date]);
$new_page_view->save();
// Update the IP
file_put_contents('tmp/temp.tdata', $ip);
$redis->sAdd('page_view_ips', $ip);
}
}
function setupCsrfToken() : string {
if (isset($_SESSION[SessionHelper::CSRF_TOKEN_KEY])) {
return $_SESSION[SessionHelper::CSRF_TOKEN_KEY];
}
$token = pp_random_token();
$_SESSION[SessionHelper::CSRF_TOKEN_KEY] = $token;
return $token;
}
function verifyCsrfToken($token = null) : bool {
if ($token === null) {
$token = $_POST[SessionHelper::CSRF_TOKEN_KEY];
}
if (empty($token) || empty($_SESSION[SessionHelper::CSRF_TOKEN_KEY])) {
return false;
}
$success = hash_equals($_SESSION[SessionHelper::CSRF_TOKEN_KEY], $token);
unset($_SESSION[SessionHelper::CSRF_TOKEN_KEY]);
return $success;
}
session_start();
$conn = new DatabaseHandle("mysql:host=$db_host;dbname=$db_schema;charset=utf8mb4", $db_user, $db_pass);
/* Set up the database and Eloquent ORM */
$capsule = new Capsule();
// Setup site info
$site_info = getSiteInfo();
$row = $site_info['site_info'];
$title = Trim($row['title']);
$des = Trim($row['description']);
$baseurl = Trim($row['baseurl']);
$keyword = Trim($row['keywords']);
$site_name = Trim($row['site_name']);
$email = Trim($row['email']);
$ga = Trim($row['google_analytics']);
$additional_scripts = Trim($row['additional_scripts']);
// Setup theme and language
$lang_and_theme = $site_info['interface'];
$default_lang = $lang_and_theme['language'];
$default_theme = $lang_and_theme['theme'];
// site permissions
$site_permissions = $site_info['permissions'];
if ($site_permissions) {
$siteprivate = $site_permissions['private'];
$disableguest = $site_permissions['disable_guest'];
} else {
$siteprivate = 'off';
$disableguest = 'off';
}
$privatesite = $siteprivate;
$noguests = $disableguest;
// CAPTCHA configuration
$captcha_config = $site_info['captcha'];
$captcha_enabled = (bool)$captcha_config['enabled'];
// Prevent a potential LFI (you never know :p)
$lang_file = "${default_lang}.php";
if (in_array($lang_file, scandir(__DIR__ . '/langs/'))) {
require_once(__DIR__ . "/langs/${lang_file}");
}
$capsule->addConnection([
'driver' => 'mysql',
'host' => $db_host,
'database' => $db_schema,
'username' => $db_user,
'password' => $db_pass ,
'charset' => 'utf8mb4',
'prefix' => ''
]);
$capsule->setAsGlobal();
$capsule->bootEloquent();
// Check if IP is banned
$ip = $_SERVER['REMOTE_ADDR'];
if ($conn->query('SELECT 1 FROM ban_user WHERE ip = ?', [$ip])->fetch()) {
die($lang['banned']); // "You have been banned from " . $site_name;
if (IPBan::where('ip', $ip)->first()) {
die('You have been banned.');
}
$site_ads = getSiteAds($conn);
$total_pastes = getSiteTotalPastes($conn);
$total_page_views = getSiteTotalviews($conn);
$total_unique_views = getSiteTotal_unique_views($conn);
/* Set up Redis */
$redis = new Redis();
$redis->pconnect(PP_REDIS_HOST);
$current_user = User::current($conn);
// Setup site info
$site_info = getSiteInfo();
$global_site_info = $site_info['site_info'];
$row = $site_info['site_info'];
$title = trim($row['title']);
$site_name = trim($row['site_name']);
$email = trim($row['email']);
if ($current_user) {
$noguests = "off";
// Setup theme
$default_theme = 'bulma';
// Site permissions
$site_permissions = $site_info['permissions'];
$site_is_private = false;
$site_disable_guests = false;
if ($site_permissions) {
$site_is_private = (bool) $site_permissions['private'];
$site_disable_guests = (bool) $site_permissions['disable_guest'];
}
// CAPTCHA configuration
$captcha_enabled = (bool) $site_info['captcha']['enabled'];
$total_pastes = Paste::count();
$total_page_views = PageView::select('tpage')->orderBy('id', 'desc')->first()->tpage;
$total_unique_views = PageView::select('tvisit')->orderBy('id', 'desc')->first()->tvisit;
$current_user = SessionHelper::currentUser();
$start = microtime(true);
function can(string $action, mixed $subject) : bool {
global $current_user;
static $current_ability = null;
if ($current_ability === null) {
$current_ability = new AbilityHelper($current_user);
}
return $current_ability->can($action, $subject);
}
$script_bundles = [];
/* Security headers */
header('X-Frame-Options: SAMEORIGIN');
header('X-Content-Type-Options: nosniff');
header("Content-Security-Policy: default-src 'self' data: 'unsafe-inline'");

View file

@ -1,65 +0,0 @@
<?php
/*
* $ID Project: Paste 2.0 - J.Samuel
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License in LIC.txt for more details.
*/
if (gethostname() === 'thunderlane') {
error_reporting(E_ALL);
ini_set('display_errors', 1);
}
/* Maximum paste size in bytes */
const PP_PASTE_LIMIT_BYTES = 1048576;
/* A long and random string used for additionally salting passwords. */
const PP_PASSWORD_PEPPER = 'd791b6c6-91f2-4e8f-ba80-74ea968e4931';
/* Whether to use friendly URLs that require mod_rewrite */
const PP_MOD_REWRITE = true;
$db_host = 'localhost';
$db_schema = 'p0nepast3s';
$db_user = 'P0nedbAcc0unt';
$db_pass = '1NWO6Tp17IFz9lbl';
// I'm sorry, I didn't want to edit this file and check it in, but I may need to make other changes to it, so I did this
if (gethostname() === 'thunderlane') {
$db_host = 'localhost';
$db_schema = 'ponepaste';
$db_user = 'ponepaste';
$db_pass = 'ponepaste';
}
// Secret key for paste encryption
//$sec_key = "8ac67343e7980b16b31e8311d4377bbb";
const PP_ENCRYPTION_ALGO = 'AES-256-CBC';
const PP_ENCRYPTION_KEY = '';
// Available GeSHi formats
$geshiformats = [
'green' => 'Green Text',
'text' => 'Plain Text',
'pastedown' => 'pastedown',
'pastedown_old' => 'pastedown old'
];
// Popular formats that are listed first.
$popular_formats = [
'green',
'text',
'pastedown',
'pastedown_old'
];
// Cookie - I want a cookie, can I have one?

View file

@ -0,0 +1,41 @@
<?php
const PP_DEBUG = false;
if (PP_DEBUG) {
error_reporting(E_ALL);
ini_set('display_errors', 1);
} else {
error_reporting(0);
ini_set('display_errors', 0);
}
/* Maximum paste size in bytes */
const PP_PASTE_LIMIT_BYTES = 1048576;
/* A long and random string used for additionally salting passwords. */
const PP_PASSWORD_PEPPER = 'a long and secure random string here';
/* Whether to use friendly URLs that require mod_rewrite */
const PP_MOD_REWRITE = true;
/* Redis credentials */
const PP_REDIS_HOST = '127.0.0.1';
const PP_REDIS_DB = 'ponepaste';
$db_host = 'localhost';
$db_schema = 'ponepaste';
$db_user = 'ponepaste';
$db_pass = 'ponepaste';
// Secret key for paste encryption
const PP_ENCRYPTION_ALGO = 'AES-256-CBC';
const PP_ENCRYPTION_KEY = 'a long and secure random string here';
const PP_HIGHLIGHT_FORMATS = [
'green' => 'Green Text',
'text' => 'Plain Text',
'pastedown' => 'pastedown',
'pastedown_old' => 'pastedown old'
];
// Cookie - I want a cookie, can I have one?

View file

@ -1,114 +1,60 @@
<?php
/*
* Paste <https://github.com/jordansamuel/PASTE>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License in GPL.txt for more details.
*/
use Illuminate\Database\Eloquent\Collection;
use PonePaste\Models\Paste;
function getPasteTags(DatabaseHandle $conn, int $paste_id) : array {
return $conn->query(
'SELECT name, slug FROM tags
INNER JOIN paste_taggings ON paste_taggings.tag_id = tags.id
WHERE paste_taggings.paste_id = ?',
[$paste_id])->fetchAll();
}
function getUserFavs(DatabaseHandle $conn, int $user_id) : array {
$query = $conn->prepare(
"SELECT pins.f_time, pastes.id, pins.paste_id, pastes.title, pastes.created_at, pastes.updated_at
FROM pins
INNER JOIN pastes ON pastes.id = pins.paste_id
WHERE pins.user_id = ?");
$query->execute([$user_id]);
return $query->fetchAll();
}
function checkFavorite(DatabaseHandle $conn, int $paste_id, int $user_id) : string {
$query = $conn->prepare("SELECT 1 FROM pins WHERE user_id = ? AND paste_id = ?");
$query->execute([$user_id, $paste_id]);
if ($query->fetch()) {
return "<a href='#' id='favorite' class='icon tool-icon' data-fid='" . $paste_id . "'><i class='fas fa-star fa-lg has-text-grey' title='Favourite'></i></a>";
} else {
return "<a href='#' id='favorite' class='icon tool-icon' data-fid='" . $paste_id . "'><i class='far fa-star fa-lg has-text-grey' title='Favourite'></i></a>";
}
}
function getreports($conn, $count = 10) {
$query = $conn->prepare('SELECT * FROM user_reports LIMIT ?');
$query->execute([$count]);
return $query->fetchAll();
}
function tagsToHtml(string | array $tags) : string {
function tagsToHtml(array | Collection $tags) : string {
$output = "";
foreach ($tags as $tagObj) {
$tag = $tagObj->name;
$tag_lower = strtolower($tag);
if ($tag_lower === 'nsfw' || $tag_lower === 'explicit') {
$tagcolor = "tag is-danger";
} elseif ($tag_lower === 'safe') {
$tagcolor = "tag is-success";
} elseif ($tag[0] === '/' && $tag[-1] === '/') {
$tagcolor = "tag is-primary";
} else {
$tagcolor = "tag is-info";
}
$output .= '<a href="/archive?q=' . urlencode($tag) . '"><span class="' . $tagcolor . '">' . pp_html_escape($tag) . '</span></a>';
}
return $output;
}
function tagsToHtmlUser(string | array | Collection $tags, $profile_username) : string {
$output = "";
if (is_a($tags, Collection::class)) {
$tags = $tags->toArray();
}
if (is_array($tags)) {
$tagsSplit = array_map(function($tag) { return $tag['name']; }, $tags);
} else {
$tagsSplit = explode(",", $tags);
}
if (count($tagsSplit) === 0) {
return '<span class="tag is-warning">No tags</span>';
}
foreach ($tagsSplit as $tag) {
if (stripos($tag, 'nsfw') !== false) {
$tag = strtoupper($tag);
$tag_lower = strtolower($tag);
if ($tag_lower === 'nsfw' || $tag_lower === 'explicit') {
$tagcolor = "tag is-danger";
} elseif (stripos($tag, 'SAFE') !== false) {
$tag = strtoupper($tag);
} elseif ($tag_lower === 'safe') {
$tagcolor = "tag is-success";
} elseif (str_contains($tag, '/')) {
} elseif ($tag[0] === '/' && $tag[-1] === '/') {
$tagcolor = "tag is-primary";
} else {
$tagcolor = "tag is-info";
}
$output .= '<a href="/archive?q=' . urlencode($tag) . '"><span class="' . $tagcolor . '">' . pp_html_escape(ucfirst($tag)) . '</span></a>';
$output .= '<a href="/user.php?user=' . $profile_username . '&q=' . urlencode($tag) . '"><span class="' . $tagcolor . '">' . pp_html_escape($tag) . '</span></a>';
}
return $output;
}
function tagsToHtmlUser(string | array $tags, $profile_username) : string {
$output = "";
if (is_array($tags)) {
$tagsSplit = array_map(function($tag) { return $tag['name']; }, $tags);
} else {
$tagsSplit = explode(",", $tags);
}
foreach ($tagsSplit as $tag) {
if (stripos($tag, 'nsfw') !== false) {
$tag = strtoupper($tag);
$tagcolor = "tag is-danger";
} elseif (stripos($tag, 'SAFE') !== false) {
$tag = strtoupper($tag);
$tagcolor = "tag is-success";
} elseif (str_contains($tag, '/')) {
$tagcolor = "tag is-primary";
} else {
$tagcolor = "tag is-info";
}
$output .= '<a href="/user.php?user=' . $profile_username . '&q=' . urlencode($tag) . '"><span class="' . $tagcolor . '">' . pp_html_escape(ucfirst($tag)) . '</span></a>';
}
return $output;
}
function getevent($conn, $event_name, $count) {
$query = $conn->prepare("SELECT id, visible, title, date, now_time, views, member FROM pastes WHERE visible='1' AND tagsys LIKE '%?%'
ORDER BY RAND () LIMIT 0, ?");
$query->execute([$event_name, $count]);
return $query->fetchAll();
}
function linkify($value, $protocols = array('http', 'mail'), array $attributes = array()) {
function linkify($value, $protocols = array('http', 'mail'), array $attributes = array()) : array|string|null {
// Link attributes
$attr = '';
foreach ($attributes as $key => $val) {
@ -123,7 +69,7 @@ function linkify($value, $protocols = array('http', 'mail'), array $attributes =
}, $value);
// Extract text links for each protocol
foreach ((array)$protocols as $protocol) {
foreach ((array) $protocols as $protocol) {
$value = match ($protocol) {
'http', 'https' => preg_replace_callback('~(?:(https?)://([^\s<]+)|(www\.[^\s<]+?\.[^\s<]+))(?<![\.,:])~i', function ($match) use ($protocol, &$links, $attr) {
if ($match[1]) $protocol = $match[1];
@ -142,52 +88,17 @@ function linkify($value, $protocols = array('http', 'mail'), array $attributes =
}, $value);
}
function getUserRecom(DatabaseHandle $conn, int $user_id) : array {
$query = $conn->prepare(
"SELECT pastes.id AS id, users.username AS member, title, visible
FROM pastes
INNER JOIN users ON pastes.user_id = users.id
WHERE pastes.visible = '0' AND users.id = ?
ORDER BY id DESC
LIMIT 0, 5");
$query->execute([$user_id]);
return $query->fetchAll();
}
function formatBytes($size, $precision = 2) {
function formatBytes($size, $precision = 2) : string {
$base = log($size, 1024);
$suffixes = array('B', 'KB', 'MB', 'GB', 'TB');
$suffixes = ['B', 'KB', 'MB', 'GB', 'TB'];
if ($size === 0) {
return '0 B';
}
return round(pow(1024, $base - floor($base)), $precision) . ' ' . $suffixes[floor($base)];
}
function getRecentadmin($conn, $count = 5) {
$query = $conn->prepare(
'SELECT pastes.id AS id, pastes.ip AS ip, title, created_at, views, users.username AS member
FROM pastes
INNER JOIN users ON users.id = pastes.user_id
ORDER BY id DESC LIMIT 0, ?');
$query->execute([$count]);
return $query->fetchAll();
}
function getUserPastes(DatabaseHandle $conn, int $user_id) : array {
return $conn->query(
"SELECT id, title, visible, code, created_at, views FROM pastes
WHERE user_id = ?
ORDER by pastes.id DESC", [$user_id])->fetchAll();
}
function getTotalPastes(DatabaseHandle $conn, int $user_id) : int {
$query = $conn->prepare("SELECT COUNT(*) AS total_pastes
FROM pastes INNER JOIN users ON users.id = pastes.user_id
WHERE users.id = ?");
$query->execute([$user_id]);
return intval($query->fetch(PDO::FETCH_NUM)[0]);
}
function friendlyDateDifference(DateTime $lesser, DateTime $greater) : string {
$delta = $greater->diff($lesser, true);
@ -205,7 +116,7 @@ function friendlyDateDifference(DateTime $lesser, DateTime $greater) : string {
foreach ($parts as $part => $value) {
if ($value !== 0) {
$pluralizer = ($value === 1 ? '' : 's');
$friendly .= "${value} ${part}${pluralizer} ";
$friendly .= "{$value} {$part}{$pluralizer} ";
}
}
@ -235,35 +146,16 @@ function truncate(string $input, int $maxWords, int $maxChars) : string {
return $result . ($input == $result ? '' : '[...]');
}
function doDownload($paste_id, $p_title, $p_member, $p_conntent, $p_code) {
$stats = false;
if ($p_code) {
// Figure out extensions.
$ext = match ($p_code) {
default => 'txt',
};
function embedView($paste_id, $p_title, $content, $title) : bool {
$baseurl = pp_site_url();
// Download
$p_title = stripslashes($p_title);
header('content-type: text/plain');
header('content-Disposition: attachment; filename="' . $paste_id . '_' . $p_title . '_' . $p_member . '.' . $ext . '"');
echo $p_conntent;
$stats = true;
} else {
// 404
header('HTTP/1.1 404 Not Found');
}
return $stats;
}
function embedView($paste_id, $p_title, $p_conntent, $p_code, $title, $baseurl, $ges_style, $lang) {
$stats = false;
if ($p_conntent) {
if ($content) {
// Build the output
$output = "<div class='paste_embed_conntainer'>";
$output = "<div class='paste_embed_container'>";
$output .= "<style>"; // Add our own styles
$output .= "
.paste_embed_conntainer {
.paste_embed_container {
font-size: 12px;
color: #333;
text-align: left;
@ -272,13 +164,13 @@ function embedView($paste_id, $p_title, $p_conntent, $p_code, $title, $baseurl,
background-color: #f7f7f7;
border-radius: 3px;
}
.paste_embed_conntainer a {
.paste_embed_container a {
font-weight: bold;
color: #666;
text-decoration: none;
border: 0;
}
.paste_embed_conntainer ol {
.paste_embed_container ol {
color: white;
background-color: #f7f7f7;
border-right: 1px solid #ccc;
@ -306,16 +198,15 @@ function embedView($paste_id, $p_title, $p_conntent, $p_code, $title, $baseurl,
line-height:20px;
}";
$output .= "</style>";
$output .= "$ges_style"; // Dynamic GeSHI Style
$output .= $p_conntent; // Paste content
$output .= $content; // Paste content
$output .= "<div class='paste_embed_footer'>";
$output .= "<a href='https://ponepaste.org/$paste_id'>$p_title</a> " . $lang['embed-hosted-by'] . " <a href='https://ponepaste.org'>$title</a> | <a href='https://ponepaste.org/raw/$paste_id'>" . strtolower($lang['view-raw']) . "</a>";
$output .= "<a href='{$baseurl}/{$paste_id}'>$p_title</a> Hosted by <a href='{$baseurl}'>$title</a> | <a href='{$baseurl}/raw/$paste_id'>view raw</a>";
$output .= "</div>";
$output .= "</div>";
// Display embed conntent using json_encode since that escapes
// characters well enough to satisfy javascript. http://stackoverflow.com/a/169035
header('conntent-type: text/javascript; charset=utf-8;');
header('Content-Type: text/javascript; charset=utf-8;');
echo 'document.write(' . json_encode($output) . ')';
$stats = true;
} else {
@ -325,22 +216,14 @@ function embedView($paste_id, $p_title, $p_conntent, $p_code, $title, $baseurl,
return $stats;
}
function addToSitemap($paste_id, $priority, $changefreq, $mod_rewrite) {
function addToSitemap(Paste $paste, $priority, $changefreq) : void {
$c_date = date('Y-m-d');
$site_data = file_get_contents("sitemap.xml");
$site_data = str_replace("</urlset>", "", $site_data);
// which protocol are we on
$protocol = paste_protocol();
if (PP_MOD_REWRITE) {
$server_name = $protocol . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']) . "/" . $paste_id;
} else {
$server_name = $protocol . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']) . "/paste.php?id=" . $paste_id;
}
$c_sitemap =
' <url>
<loc>' . $server_name . '</loc>
<loc>' . urlForPaste($paste) . '</loc>
<priority>' . $priority . '</priority>
<changefreq>' . $changefreq . '</changefreq>
<lastmod>' . $c_date . '</lastmod>
@ -352,7 +235,101 @@ function addToSitemap($paste_id, $priority, $changefreq, $mod_rewrite) {
}
function paste_protocol() : string {
return (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on") ? 'https://' : 'http://';
return !empty($_SERVER['HTTPS']) ? 'https://' : 'http://';
}
function pp_site_url() : string {
return paste_protocol() . $_SERVER['HTTP_HOST'];
}
/* get rid of unintended wildcards in a parameter to LIKE queries; not a security issue, just unexpected behaviour. */
function escapeLikeQuery(string $query) : string {
return str_replace(['\\', '_', '%'], ['\\\\', '\\_', '\\%'], $query);
}
function paginate(int $current_page, int $per_page, int $total_records) : string {
$first_page = 0;
$last_page = floor($total_records / $per_page);
$window = 2;
if ($first_page == $last_page) {
// Do something?
}
$_page_button = function(int $page, string $text, bool $disabled = false) use ($current_page) : string {
/* We need to update the 'page' parameter in the request URI, or add it if it doesn't exist. */
$request_uri = parse_url($_SERVER['REQUEST_URI']);
parse_str((string) @$request_uri['query'], $parsed_query);
$parsed_query['page'] = (string) $page;
$page_uri = ((string) @$request_uri['path']) . '?' . http_build_query($parsed_query);
$selected_class = $current_page == $page ? ' paginator__button--selected' : '';
$disabled_text = $disabled ? ' aria-disabled="true"' : '';
return sprintf("<a type=\"button\" class=\"paginator__button$selected_class\" href=\"%s\"%s>%s</a>", $page_uri, $disabled_text, $text);
};
$html = '';
/* First and last page the main paginator will show */
$first_page_show = max(($current_page - $window), $first_page);
$last_page_show = min(($current_page + $window), $last_page);
/* Whether to show the first and last pages in existence at the ends of the paginator */
$show_first_page = (abs($first_page - $current_page)) > ($window);
$show_last_page = (abs($last_page - $current_page)) > ($window);
$prev_button_disabled = $current_page == $first_page ? 'disabled' : '';
$next_button_disabled = $current_page == $last_page ? 'disabled' : '';
$html .= $_page_button($current_page - 1, 'Previous', $prev_button_disabled);
if ($show_first_page) {
$html .= $_page_button($first_page, $first_page);
$html .= '<span class="ellipsis">…</span>';
}
for ($i = $first_page_show; $i <= $last_page_show; $i++) {
$html .= $_page_button($i, $i);
}
if ($show_last_page) {
$html .= '<span class="ellipsis">…</span>';
$html .= $_page_button($last_page, $last_page);
}
$html .= $_page_button($current_page + 1, 'Next', $next_button_disabled);
return $html;
}
function pp_filename_escape(string $filename, string $extension) : string {
/* Remove NTFS invalid characters */
$filename = preg_replace('#[<>:"/|?*]#', '-', $filename);
/* Windows MAX_PATH limit */
if (strlen($filename . $extension) > 255) {
$filename = substr($filename, 0, 255 - strlen($extension));
}
return $filename . $extension;
}
function pp_setup_pagination() : array {
$per_page = 20;
$current_page = 0;
if (!empty($_GET['page'])) {
$current_page = max(0, intval($_GET['page']));
}
if (!empty($_GET['per_page'])) {
$per_page = max(1, min(100, intval($_GET['per_page'])));
}
return [$per_page, $current_page];
}
function pp_output_paginator(int $per_page, int $current_page) : void {
}

View file

@ -1,120 +0,0 @@
<?php
/*
* Language File: Bulgarian
* Translated by Plamen Vasilev <p.vasileff@gmail.com> (Oct, 2017)
*/
$lang = array();
$lang['banned'] = "Достъпа ви до " . $site_name . "е ограничен";
$lang['expired'] = "Документа, който се опитваш да достъпиш е изтекъл.";
$lang['guestwelcome'] = $site_name . " ти позволява да публикуваш текст &amp; код.";
$lang['pleaseregister'] = "<br /><br /> <a class=\"btn btn-default\" data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Влез</a> или се <a class=\"btn btn-default\" data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Регистрирай</a> за да публикуваш съдържание. Безплатно е.";
$lang['registertoedit'] = "<a class=\"btn btn-default\" data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Влез</a> или се <a class=\"btn btn-default\" data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Регистрирай</a> за да редактираш или задържиш това съдържание.";
$lang['editpaste'] = "Редактирай";
$lang['forkpaste'] = "Задръж";
$lang['guestmsgtitle'] = $site_name . " е място за публикуване на код или текст за по-лесно отстраняване на грешки.";
$lang['guestmsgbody'] = "<a data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Влез</a> или се <a data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Регистрай</a> за да редактираш, изтриваш или преглеждаш хронология на твоето публикувано съдържание";
$lang['emptypastebin'] = "Няма публикувано съдържание";
$lang['siteprivate'] = "Този документ е частен.";
$lang['image_wrong'] = "Wrong captcha.";
$lang['missing-input-response'] = "The reCAPTCHA response parameter is missing. Please verify your PASTE settings.";
$lang['missing-input-secret'] = "The reCAPTCHA secret parameter is missing. Please add it to your PASTE settings.";
$lang['missing-input-response'] = "The reCAPTCHA response parameter is invalid. Please try to complete the reCAPTCHA again.";
$lang['invalid-input-secret'] = "The reCAPTCHA secret parameter is invalid or malformed. Please double check your PASTE settings.";
$lang['empty_paste'] = "Не може да добавите публикацията без съдържание";
$lang['large_paste'] = "Вашата публикация е прекалено голяма. Максималния размер е " . $pastelimit . "MB";
$lang['paste_db_error'] = "Unable to post to database.";
$lang['error'] = "Something went wrong.";
$lang['archive'] = "Pastes Archive";
$lang['contact'] = "Contact Us";
$lang['full_name'] = "Your full name is required.";
$lang['email'] = "Your email address is required.";
$lang['email_invalid'] = "Your email address seems to be invalid.";
$lang['message'] = "Your message is required.";
$lang['login/register'] = "Вход/Регистрация";
$lang['rememberme'] = "Keep me signed in.";
$lang['mail_acc_con'] = "$site_name Account Confirmation";
$lang['mail_suc'] = "На имейла адреса ти е изпратен код за верификация.";
$lang['email_ver'] = "Имейла вече е бил потвърден.";
$lang['email_not'] = "Имейла не е намерен.";
$lang['pass_change'] = "Паролата е променена успешно и е изпратена на имейла ти.";
$lang['notverified'] = "Акаунта не е верифициран.";
$lang['incorrect'] = "Невалидни Потребител/Парола";
$lang['missingfields'] = "All fields must be filled out.";
$lang['userexists'] = "Това потребителско име вече се използва";
$lang['emailexists'] = "Този имейл адрес вече съществува в системата";
$lang['registered'] = "Акаунтът ти беше регистриран успешно";
$lang['usrinvalid'] = "Your username can only contain letters or numbers.";
$lang['mypastes'] = "My Pastes";
$lang['pastedeleted'] = "Paste deleted.";
$lang['databaseerror'] = "Unable to post to database.";
$lang['userchanged'] = "Username changed successfully.";
$lang['usernotvalid'] = "Username not vaild.";
$lang['privatepaste'] = "This is a private paste.";
$lang['wrongpassword'] = 'Грешна парола.';
$lang['pwdprotected'] = 'Съдържание с парола';
$lang['notfound'] = "Not found";
$lang['wrongpwd'] = "Въведената парола е грешна. Опитай отново.";
$lang['myprofile'] = "My Profile";
$lang['profileerror'] = "Unable to update the profile information ";
$lang['profileupdated'] = "Your profile information is updated ";
$lang['oldpasswrong'] = "Your old password is wrong.";
$lang['archives'] = "Pastes Archive";
$lang['archivestitle'] = "This page contains the most recently created 100 public pastes.";
$lang['pastetitle'] = "Paste Title";
$lang['pastetime'] = "Paste Time";
$lang['pastesyntax'] = "Paste Syntax";
$lang['pasteviews'] = "Paste Views";
$lang['wentwrong'] = "Something went wrong.";
$lang['versent'] = "A verification email has been sent to your email address.";
$lang['modpaste'] = "Modify Paste";
$lang['newpaste'] = "New Paste";
$lang['highlighting'] = "Syntax Highlighting";
$lang['expiration'] = "Paste Expiration";
$lang['visibility'] = "Paste Visibility";
$lang['pwopt'] = "Password (Optional)";
$lang['encrypt'] = "Encrypt in database";
$lang['entercode'] = "Enter Code";
$lang['almostthere'] = "Almost there. One more step to go.";
$lang['username'] = "Username";
$lang['autogen'] = "Auto generated name";
$lang['setuser'] = "Set your Username";
$lang['keepuser'] = "Keep autogenerated name";
$lang['enterpwd'] = "Enter the password";
$lang['totalpastes'] = "Total Pastes:";
$lang['membtype'] = "Membership Type:";
$lang['email'] = "Email";
$lang['fullname'] = "Full Name";
$lang['chgpwd'] = "Change Password";
$lang['curpwd'] = "Current Password";
$lang['newpwd'] = "New Password";
$lang['confpwd'] = "Confirm Password";
$lang['mypastes'] = "My Pastes";
$lang['viewpastes'] = "View all my pastes";
$lang['recentpastes'] = "Recent Pastes";
$lang['user_public_pastes'] = "'s Pastes";
$lang['yourpastes'] = "Your Pastes";
$lang['mypastestitle'] = "All of your pastes, in one place.";
$lang['delete'] = "Delete";
$lang['highlighted'] = "The text below is selected, press Ctrl+C to copy to your clipboard. (&#8984;+C on Mac)";
$lang['newpaste'] = "New Paste";
$lang['download'] = "Download";
$lang['showlineno'] = "Покажи/Скрий номерата на редовете";
$lang['copyto'] = "Копирай съдържанието в клипборда";
$lang['rawpaste'] = "Raw Paste";
$lang['membersince'] = "Joined: ";
$lang['delete_error_invalid'] = "Error: Paste not deleted because it does not exist or you do not own the paste.";
$lang['not_logged_in'] = "Грешка: Нужно е да си логнат в системата, за да направиш това.";
$lang['public'] = "Public";
$lang['unlisted'] = "Unlisted";
$lang['private'] = "Private";
$lang['hello'] = "Hello";
$lang['profile-message'] = "This is your profile page where you can manage your pastes.<br /> All of your public, private and unlisted pastes will be shown here. You can also delete your pastes from this page. If other users visit your page they will only see pastes you have set public.";
$lang['profile-stats'] = "Some of your statistics:";
$lang['profile-total-pastes'] = "Total Pastes:";
$lang['profile-total-pub'] = "Total public pastes:";
$lang['profile-total-unl'] = "Total unlisted pastes:";
$lang['profile-total-pri'] = "Total private pastes:";
$lang['profile-total-views'] = "Total views of all your pastes:";
$lang['embed-hosted-by'] = "hosted by";
$lang['view-raw'] = "Покажи в необработен текст";

View file

@ -1,121 +0,0 @@
<?php
/*
* Language File: English
*/
$lang = array();
$lang['banned'] = "Você foi banido do " . $site_name;
$lang['expired'] = "O paste que você procura não existe mais.";
$lang['guestwelcome'] = $site_name . " é um lugar para guardar e compartilhar seus pastes e codigos.";
$lang['pleaseregister'] = "<br /><br /> <a class=\"btn btn-default\" data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Entrar</a> ou <a class=\"btn btn-default\" data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Cadastre-se</a> para criar um novo paste.";
$lang['registertoedit'] = "<a class=\"btn btn-default\" data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Entrre</a> ou <a class=\"btn btn-default\" data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Cadastre-se</a> para editar ou duplicar este paste.";
$lang['editpaste'] = "Editar";
$lang['forkpaste'] = "Duplicar";
$lang['guestmsgtitle'] = $site_name . ", um lugar para salvar e compartilhar textos e codigos.";
$lang['guestmsgbody'] = "<a data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Entrar</a> ou <a data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Cadastre-se</a> para editar e acomparnhar os seus pastes.";
$lang['emptypastebin'] = "Este pastebin está vazio";
$lang['siteprivate'] = "Este é um paste privado.";
$lang['image_wrong'] = "Captha invalido.";
$lang['missing-input-response'] = "O parametro de resposta do reCapcha está faltando. Por favor verifique as configurações do seu paste.";
$lang['missing-input-secret'] = "O parametro de seguredo do reCapcha está faltando. Por favor verifique as configurações do seu paste.";
$lang['missing-input-response'] = "O parametro de resposta do reCapcha é inválido. Por favor tente novamente.";
$lang['invalid-input-secret'] = "O parametro de seguredo do reCapcha está faltando ou é inválido. Please double check your PASTE settings.";
$lang['empty_paste'] = "Você não pode publicar um paste vazio.";
$lang['large_paste'] = "O seu paste é muito grande. O tamanho maximo é: " . $pastelimit . "MB";
$lang['paste_db_error'] = "Não conseguimos eviar seu paste para o banco de dados.";
$lang['error'] = "Algo deu errado.";
$lang['archive'] = "Arquivo de pastes";
$lang['contact'] = "Entre em contato";
$lang['full_name'] = "É nescessario inserir o seu nome completo.";
$lang['email'] = "É nescessario inserir o seu email.";
$lang['email_invalid'] = "O seu endereçõ de email não parece ser válido.";
$lang['message'] = "É nescessario inserir uma mensagem válida.";
$lang['login/register'] = "Entrar/Cadastro";
$lang['rememberme'] = "Manter me logado.";
$lang['mail_acc_con'] = "Informações da conta em $site_name";
$lang['mail_suc'] = "O seu codigo de verificção foi enviado ao email preenchido.";
$lang['email_ver'] = "Email já verificado.";
$lang['email_not'] = "Email não encontrado, já fez o seu cadastro?.";
$lang['pass_change'] = "Senha alterada com sucesso, a enviamos para o seu email.";
$lang['notverified'] = "Conta não verificada.";
$lang['incorrect'] = "Senha ou usuario incorretos";
$lang['missingfields'] = "Todos os campos devem ser preenchidos.";
$lang['userexists'] = "Nome de usuario já em uso.";
$lang['emailexists'] = "Email já em uso.";
$lang['registered'] = "Conta cadastrada com sucesso.";
$lang['usrinvalid'] = "Seu nome de usuario deve conter apenas letras e numeros.";
$lang['mypastes'] = "Meus pastes";
$lang['pastedeleted'] = "Paste apagado.";
$lang['databaseerror'] = "Incapaz de enviar para o banco de dados.";
$lang['userchanged'] = "Nome de usuario alterado com sucesso.";
$lang['usernotvalid'] = "Nome de usuario inválido.";
$lang['privatepaste'] = "Este paste é privado.";
$lang['wrongpassword'] = 'Senha incorreta.';
$lang['pwdprotected'] = 'Testo protegido por senha';
$lang['notfound'] = "Não encontrado";
$lang['wrongpwd'] = "Senha inválida, tente novamente.";
$lang['myprofile'] = "Meu perfil";
$lang['profileerror'] = "Incapaz de atualizar as informações do perfil.";
$lang['profileupdated'] = "Informações do perfil atualizadas.";
$lang['oldpasswrong'] = "Senha antiga incorreta.";
$lang['archives'] = "Arquivo de pastes";
$lang['archivestitle'] = "Esta pagina contém os 100 pastes mais recentes.";
$lang['pastetitle'] = "Nome do paste";
$lang['pastetime'] = "Momento de publicação do paste";
$lang['pastesyntax'] = "Sintaxe do paste";
$lang['pasteviews'] = "Visualizações do paste";
$lang['wentwrong'] = "Algo deu errado.";
$lang['versent'] = "Um email de verificação foi enviado ao seu endereço de email.";
$lang['modpaste'] = "Modificar paste";
$lang['newpaste'] = "Novo paste";
$lang['highlighting'] = "Destaque de síntaxe";
$lang['expiration'] = "Expiraçaão do paste";
$lang['visibility'] = "Visibilidade do paste";
$lang['pwopt'] = "Senha (Opcional)";
$lang['encrypt'] = "Encriptar no banco de dados";
$lang['entercode'] = "Entre o codigo";
$lang['almostthere'] = "Quase lá, apenas mais um passo.";
$lang['username'] = "Nome de usuario";
$lang['autogen'] = "Nome Gerado automaticamente";
$lang['setuser'] = "Defina o seu nome de usuario";
$lang['keepuser'] = "Manter nome gerado automaticamente";
$lang['enterpwd'] = "Entre sua senha";
$lang['totalpastes'] = "Total de pastes:";
$lang['membtype'] = "Tipo de Membro:";
$lang['email'] = "Email";
$lang['fullname'] = "Nome completo";
$lang['chgpwd'] = "Mudar senha";
$lang['curpwd'] = "Senha atual";
$lang['newpwd'] = "Nova senha";
$lang['confpwd'] = "Confirmar senha";
$lang['mypastes'] = "Meus pastes";
$lang['viewpastes'] = "Ver todos os meus pastes";
$lang['recentpastes'] = "pastes recentes";
$lang['user_public_pastes'] = " publicou:";
$lang['yourpastes'] = "Seus pastes";
$lang['mypastestitle'] = "Todos os seus pastes, em um só lugar.";
$lang['delete'] = "Apagar";
$lang['highlighted'] = "O paste abaixo está selecionado, pressione Ctrl+C Para copiar para a area de transferencia. (&#8984;+C no mac)";
$lang['newpaste'] = "Novo paste";
$lang['download'] = "Baixar";
$lang['showlineno'] = "Mostrar/Esconder numero da linha";
$lang['copyto'] = "Copiar paste para a area de transferência";
$lang['rawpaste'] = "Novo texto bruto";
$lang['membersince'] = "Se cadastrou em: ";
$lang['delete_error_invalid'] = "Erro: paste não foi apagado por que você não é dono dele ou ele nao existe mais.";
$lang['not_logged_in'] = "Erro: Você deve estar logado para poder fazer isso.";
$lang['public'] = "Publico";
$lang['unlisted'] = "Não listado";
$lang['private'] = "Privado";
$lang['hello'] = "Olá";
$lang['profile-message'] = "Esta é a pagina do seu perfil, onde você pode ver e adminnistrar todos os seus pastes.<br /> Todos os seus pastes, publicos, privados e não listados serão mostrados aqui. Você também pode deletar os seus pastes nesta pagina. Se outros usuários acessarem esta pagina eles verão apenas seus pastes públicos.";
$lang['profile-stats'] = "Algumas de suas estatísticas:";
$lang['profile-total-pastes'] = "Numero de pastes:";
$lang['profile-total-pub'] = "Numero de pastes públicos:";
$lang['profile-total-unl'] = "Numero de pastes não listados:";
$lang['profile-total-pri'] = "Numero de pastes privados:";
$lang['profile-total-views'] = "Numero de visualizações nos seus pastes:";
$lang['embed-hosted-by'] = "hospedado por";
$lang['view-raw'] = "Ver texto bruto";

View file

@ -1,122 +0,0 @@
<?php
/*
* Language File: German
* Translated by Niranda <niranda@niranda.net> (December, 2017)
*/
$lang = array();
$lang['banned'] = "Du wurdest von " . $site_name . " gebannt.";
$lang['expired'] = "Dieser Paste ist abgelaufen.";
$lang['guestwelcome'] = $site_name . " erlaubt es dir Text &amp; Code hochzuladen.";
$lang['pleaseregister'] = "<br /><br /> <a class=\"btn btn-default\" data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Login</a> oder <a class=\"btn btn-default\" data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Registrieren</a> um einen neuen Paste hochzuladen. Es ist kostenlos.";
$lang['registertoedit'] = "<a class=\"btn btn-default\" data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Login</a> oder <a class=\"btn btn-default\" data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Registrieren</a> um diesen Paste zu bearbeiten oder zu forken. Es ist kostenlos.";
$lang['editpaste'] = "Bearbeiten";
$lang['forkpaste'] = "Fork";
$lang['guestmsgtitle'] = $site_name . " ist f$uuml;r Quelltexte und generellen Debugging Text.";
$lang['guestmsgbody'] = "<a data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Login</a> oder <a data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Registrieren</a> um zu bearbeiten, l&ouml;schen, um deine Pastes zu verfolgen und mehr.";
$lang['emptypastebin'] = "Hier sind keine Pasts zum anzeigen.";
$lang['siteprivate'] = "Dieser Pastebin ist privat.";
$lang['image_wrong'] = "Falsches Captcha.";
$lang['missing-input-response'] = "Der reCAPTCHA Response Parameter fehlt. Bitte &Uuml;berpr&uuml;fe deine PASTE Einstellungen.";
$lang['missing-input-secret'] = "Der reCAPTCHA Secret Parameter fehlt. Bitte f&uuml;ge ihn zu deinen PASTE Einstellungen hinzu.";
$lang['missing-input-response'] = "Der reCAPTCHA Response Parameter fehlt. Bitte versuche das reCAPTCHA erneut zu vollenden.";
$lang['invalid-input-secret'] = "Der reCAPTCHA Secret Parameter fehlt oder ist falsch. Bitte &uuml;berpr&uuml;fe noch mal deine PASTE Einstellungen.";
$lang['empty_paste'] = "Du kannst keinen leeren Paste hochladen.";
$lang['large_paste'] = "Dein Paste ist zu gro&szlig;. Die maximale Gr&ouml;&szlig;e betr&auml;gt " . $pastelimit . "MB";
$lang['paste_db_error'] = "Der Eintrag wurde nicht in die Datenbank geschrieben.";
$lang['error'] = "Etwas ist schief gegangen.";
$lang['archive'] = "Paste Archiv";
$lang['contact'] = "Kontaktiere uns";
$lang['full_name'] = "Es wird dein voller Name ben&ouml;tigt.";
$lang['email'] = "Deine eMail-Adresse wird ben&ouml;tigt.";
$lang['email_invalid'] = "Deine eMail-Adresse scheint ung&uuml;ltig zu sein.";
$lang['message'] = "Deine Nachricht wird ben&ouml;tigt.";
$lang['login/register'] = "Login/Registrieren";
$lang['rememberme'] = "Lass mich eingeloggt.";
$lang['mail_acc_con'] = "$site_name Konto Best&auml;tigung";
$lang['mail_suc'] = "Der Verifikationscode wurde erfolgreich an deine eMail-Adresse gesendet.";
$lang['email_ver'] = "Diese eMail-Adresse wurde bereits verifiziert.";
$lang['email_not'] = "eMail-Adresse nicht gefunden.";
$lang['pass_change'] = "Passwort erfolgreich ge&auml;ndert und per eMail versendet.";
$lang['notverified'] = "Konto nicht verifiziert.";
$lang['incorrect'] = "Falscher Benutzername/Passwort";
$lang['missingfields'] = "Alle Felder m&uuml;ssen ausgef&uuml;llt sein.";
$lang['userexists'] = "Benutzername existiert bereits.";
$lang['emailexists'] = "eMail-Adresse wurde bereits registriert.";
$lang['registered'] = "Dein Konto wurde erfolgreich registriert.";
$lang['usrinvalid'] = "Dein Benutzername kann nur Buchstaben und Zahlen enthalten.";
$lang['mypastes'] = "Meine Pastes";
$lang['pastedeleted'] = "Paste gel&ouml;scht.";
$lang['databaseerror'] = "Der Eintrag wurde nicht in die Datenbank geschrieben.";
$lang['userchanged'] = "Benutzername erfolgreich ge&auml;ndert.";
$lang['usernotvalid'] = "Benutzername ist nicht g&uuml;ltig.";
$lang['privatepaste'] = "Das ist ein privater Paste.";
$lang['wrongpassword'] = 'Falsches Passwort.';
$lang['pwdprotected'] = 'Passwortgesch&uuml;tzter Paste';
$lang['notfound'] = "Nicht gefunden";
$lang['wrongpwd'] = "Falsches Passwort. Versuche es erneut.";
$lang['myprofile'] = "Mein Profil";
$lang['profileerror'] = "Kann Profilinformationen nicht aktualisieren ";
$lang['profileupdated'] = "Profilinformationen aktualisiert ";
$lang['oldpasswrong'] = "Dein altes Passwort ist falsch.";
$lang['archives'] = "Paste Archiv";
$lang['archivestitle'] = "Diese Seite zeigt die 100 zuletzt erstellten, &ouml;ffentlichen Pastes.";
$lang['pastetitle'] = "Paste Titel";
$lang['pastetime'] = "Paste Zeit";
$lang['pastesyntax'] = "Paste Syntax";
$lang['pasteviews'] = "Paste Ansichten";
$lang['wentwrong'] = "Etwas ging schief.";
$lang['versent'] = "Eine Best&auml;tigungsmail wurde an deine eMail-Adresse gesendet.";
$lang['modpaste'] = "Paste bearbeiten ";
$lang['newpaste'] = "Neuer Paste";
$lang['highlighting'] = "Syntax Highlighting";
$lang['expiration'] = "Paste Ablaufdatum";
$lang['visibility'] = "Paste Sichtbarkeit";
$lang['pwopt'] = "Passwort (Optional)";
$lang['encrypt'] = "Verschl&uuml;sselt in Datenbank";
$lang['entercode'] = "Code eingeben";
$lang['almostthere'] = "Fast geschafft. Noch ein Schritt.";
$lang['username'] = "Benutzername";
$lang['autogen'] = "Generierter Name";
$lang['setuser'] = "Setze deinen Benutzernamen";
$lang['keepuser'] = "Behalte generierten Namen";
$lang['enterpwd'] = "Gib das Passwort ein";
$lang['totalpastes'] = "Total Pastes:";
$lang['membtype'] = "Art der Mitgliedschaft:";
$lang['email'] = "Email";
$lang['fullname'] = "Voller Name";
$lang['chgpwd'] = "Passwort &auml;ndern";
$lang['curpwd'] = "Aktuelles Passwort";
$lang['newpwd'] = "Neues Passwort";
$lang['confpwd'] = "Best&auml;#tige Passwort";
$lang['mypastes'] = "Meine Pastes";
$lang['viewpastes'] = "Zeige alle meine Pastes";
$lang['recentpastes'] = "Letzte Pastes";
$lang['user_public_pastes'] = "'s Pastes";
$lang['yourpastes'] = "Deine Pastes";
$lang['mypastestitle'] = "Alle deine Pastes, in einem Platz.";
$lang['delete'] = "L&ouml;schen";
$lang['highlighted'] = "Der unten stehende Text ist ausgew&auml;hlt, dr&uuml;cke Strg+C um ihn zu kopieren. (&#8984;+C beim Mac)";
$lang['newpaste'] = "Neuer Paste";
$lang['download'] = "Download";
$lang['showlineno'] = "Zeige/Verstecke Zeilennr.";
$lang['copyto'] = "Kopiere Text";
$lang['rawpaste'] = "Raw Paste";
$lang['membersince'] = "Beigetreten: ";
$lang['delete_error_invalid'] = "Fehler: Paste wurde nicht gel&ouml;scht, da dieser nicht existiert oder du nicht der Eigent&uuml;mer bist.";
$lang['not_logged_in'] = "Fehler: Du musst eingeloggt sein, um das zu tun.";
$lang['public'] = "&Ouml;ffentlich";
$lang['unlisted'] = "Ungelistet";
$lang['private'] = "Privat";
$lang['hello'] = "Hallo";
$lang['profile-message'] = "Dies ist deine Profilseite in der du deine Pasts verwalten kannst.<br /> All deine &ouml;ffentlichen, privaten und ungelisteten Pastes werden hier gezeigt. Du kannst sie hier auch l&ouml;schen. Falls andere Benutzer deine Seite besuchen werden sie nur deine &ouml;ffentlich gesetzten Pastes sehen k&ouml;nnen.";
$lang['profile-stats'] = "Ein paar deiner Statistiken:";
$lang['profile-total-pastes'] = "Total Pastes:";
$lang['profile-total-pub'] = "Total &ouml;ffentliche Pastes:";
$lang['profile-total-unl'] = "Total ungelistete Pastes:";
$lang['profile-total-pri'] = "Total private Pastes:";
$lang['profile-total-views'] = "Total Ansichten all deiner Pastes:";
$lang['embed-hosted-by'] = "gehostet von";
$lang['view-raw'] = "Zeige Raw";

View file

@ -1,135 +0,0 @@
<?php
/*
* Language File: English
*/
$lang = array();
$lang['pastestatus'] = "Status";
$lang['datefav'] = "Date Favorited";
$lang['loginwarning'] = "You must be logged in to do that.";
$lang['titlelen'] = "Title too long";
$lang['notags'] = "Please tag your paste";
$lang['maxnamelimit'] = "Username too long";
$lang['tags'] = "Tags";
$lang['author'] = "Paste Author";
$lang['updatedgreen'] = "Updated Pastes";
$lang['popular'] = "Popular pastes";
$lang['random'] = "Random pastes";
$lang['monthpopular'] = "This months Popular Pastes";
$lang['banned'] = "You have been banned from " . $site_name;
$lang['expired'] = "The paste you're looking for has expired.";
$lang['guestwelcome'] = $site_name . " Guest pastes temporary disabled due to spam. Please register or sign in.";
$lang['pleaseregister'] = "<br /><br /> <a class=\"btn btn-default\" data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Login</a> or <a class=\"btn btn-default\" data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Register</a> to submit a new paste. It's free.";
$lang['registertoedit'] = "<a class=\"btn btn-default\" data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Login</a> or <a class=\"btn btn-default\" data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Register</a> to edit or fork this paste. It's free.";
$lang['editpaste'] = "Edit";
$lang['forkpaste'] = "Fork";
$lang['guestmsgtitle'] = $site_name . " is for horse greens and general shitposts.";
$lang['guestmsgbody'] = "<a data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Login</a> or <a data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Register</a> to edit, delete and keep track of your pastes and more.";
$lang['emptypastebin'] = "There are no pastes to show.";
$lang['siteprivate'] = "This pastebin is private.";
$lang['image_wrong'] = "Wrong captcha.";
$lang['missing-input-response'] = "The reCAPTCHA response parameter is missing. Please verify your PASTE settings.";
$lang['missing-input-secret'] = "The reCAPTCHA secret parameter is missing. Please add it to your PASTE settings.";
$lang['missing-input-response'] = "The reCAPTCHA response parameter is invalid. Please try to complete the reCAPTCHA again.";
$lang['invalid-input-secret'] = "The reCAPTCHA secret parameter is invalid or malformed. Please double check your PASTE settings.";
$lang['empty_paste'] = "You cannot post an empty paste.";
$lang['large_paste'] = "Your paste is too large. Max size is " . PP_PASTE_LIMIT_BYTES . " bytes";
$lang['paste_db_error'] = "Unable to post to database.";
$lang['error'] = "Something went wrong.";
$lang['archive'] = "Pastes Archive";
$lang['contact'] = "Contact Us";
$lang['full_name'] = "Account name is required.";
$lang['email'] = "Your email address is required.";
$lang['email_invalid'] = "Your email address seems to be invalid.";
$lang['message'] = "Your message is required.";
$lang['login/register'] = "Login/Register";
$lang['rememberme'] = "Keep me signed in.";
$lang['mail_acc_con'] = "$site_name Account Confirmation";
$lang['mail_suc'] = "Verification code successfully sent to your email address.";
$lang['email_ver'] = "Email already verified.";
$lang['email_not'] = "Email not found.";
$lang['pass_change'] = "Password changed successfully and sent to your email.";
$lang['notverified'] = "Account not verified.";
$lang['incorrect'] = "Incorrect User/Password";
$lang['missingfields'] = "All fields must be filled out.";
$lang['userexists'] = "Username already taken.";
$lang['emailexists'] = "Email already registered.";
$lang['registered'] = "Your account was successfully registered.";
$lang['usrinvalid'] = "Your username can only contain letters or numbers.";
$lang['mypastes'] = "My Pastes";
$lang['pastedeleted'] = "Paste deleted.";
$lang['databaseerror'] = "Unable to post to database.";
$lang['userchanged'] = "Username changed successfully.";
$lang['usernotvalid'] = "Username not vaild.";
$lang['privatepaste'] = "This is a private paste.";
$lang['wrongpassword'] = 'Wrong password.';
$lang['pwdprotected'] = 'Password protected paste';
$lang['notfound'] = "Not found";
$lang['wrongpwd'] = "Wrong password. Try again.";
$lang['myprofile'] = "My Profile";
$lang['profileerror'] = "Unable to update the profile information ";
$lang['profileupdated'] = "Your profile information is updated ";
$lang['oldpasswrong'] = "Your old password is wrong.";
$lang['archives'] = "Pastes Archive";
$lang['archivestitle'] = "This page contains the most recently created 100 public pastes.";
$lang['pastetitle'] = "Paste Title";
$lang['pastetime'] = "Paste Time";
$lang['pastedate'] = "Paste Date";
$lang['pastesyntax'] = "Paste Syntax";
$lang['pasteviews'] = "Views";
$lang['wentwrong'] = "Something went wrong.";
$lang['versent'] = "A verification email has been sent to your email address.";
$lang['modpaste'] = "Modify Paste";
$lang['newpaste'] = "New Paste";
$lang['highlighting'] = "Syntax Highlighting";
$lang['expiration'] = "Paste Expiration";
$lang['visibility'] = "Paste Visibility";
$lang['pwopt'] = "Password (Optional)";
$lang['encrypt'] = "Encrypt in database";
$lang['entercode'] = "Enter Code";
$lang['almostthere'] = "Almost there. One more step to go.";
$lang['username'] = "Username";
$lang['autogen'] = "Auto generated name";
$lang['setuser'] = "Set your Username";
$lang['keepuser'] = "Keep autogenerated name";
$lang['enterpwd'] = "Enter the password";
$lang['totalpastes'] = "Total Pastes:";
$lang['membtype'] = "Membership Type:";
$lang['email'] = "Email";
$lang['fullname'] = "Full Name";
$lang['chgpwd'] = "Change Password";
$lang['curpwd'] = "Current Password";
$lang['newpwd'] = "New Password";
$lang['confpwd'] = "Confirm Password";
$lang['mypastes'] = "My Pastes";
$lang['viewpastes'] = "View all my pastes";
$lang['recentpastes'] = "Recent Pastes";
$lang['user_public_pastes'] = "'s Pastes";
$lang['yourpastes'] = "Your Pastes";
$lang['mypastestitle'] = "All of your pastes, in one place.";
$lang['delete'] = "Delete";
$lang['highlighted'] = "The text below is selected, press Ctrl+C to copy to your clipboard. (&#8984;+C on Mac)";
$lang['newpaste'] = "New Paste";
$lang['download'] = "Download";
$lang['showlineno'] = "Show/Hide line no.";
$lang['copyto'] = "Copy text to clipboard";
$lang['rawpaste'] = "Raw Paste";
$lang['membersince'] = "Joined: ";
$lang['delete_error_invalid'] = "Error: Paste not deleted because it does not exist or you do not own the paste.";
$lang['not_logged_in'] = "Error: You must be logged in to do that.";
$lang['public'] = "Public";
$lang['unlisted'] = "Unlisted";
$lang['private'] = "Private";
$lang['hello'] = "Hello";
$lang['profile-message'] = "This is your profile page where you can manage your pastes.<br /> All of your public, private and unlisted pastes will be shown here. You can also delete your pastes from this page. If other users visit your page they will only see pastes you have set public.";
$lang['profile-stats'] = "Some of your statistics:";
$lang['profile-total-pastes'] = "Total Pastes:";
$lang['profile-total-pub'] = "Total public pastes:";
$lang['profile-total-unl'] = "Total unlisted pastes:";
$lang['profile-total-pri'] = "Total private pastes:";
$lang['profile-total-views'] = "Total views of all your pastes:";
$lang['pastfavs-total'] = "Total Favorites of your pastes:";
$lang['yourfavs-total'] = "Total Favorites by you:";
$lang['embed-hosted-by'] = "hosted by";
$lang['view-raw'] = "View Raw";

View file

@ -1,120 +0,0 @@
<?php
/*
* Language File: Spanish
* Author: S. Jorge
*/
$lang = array();
$lang['banned'] = "Estas barneado en " . $site_name;
$lang['expired'] = "El pegado que estás buscando ha caducado.";
$lang['guestwelcome'] = $site_name . " te permite enviar texto &amp; código.";
$lang['pleaseregister'] = "<br /><br /> <a class=\"btn btn-default\" data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Iniciar sesión</a> o <a class=\"btn btn-default\" data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Registrarse</a> para enviar un pegado. Es gratis.";
$lang['registertoedit'] = "<a class=\"btn btn-default\" data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Iniciar sesión</a> o <a class=\"btn btn-default\" data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Registrarse</a> para editar o bifurcar este pegado. Es gratis.";
$lang['editpaste'] = "Editar";
$lang['forkpaste'] = "Bifurcar";
$lang['guestmsgtitle'] = $site_name . " es para el código fuente y el texto de depuración general.";
$lang['guestmsgbody'] = "<a data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Iniciar sesión</a> o <a data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Registrarse</a> para editar, eliminar y mantener un seguimiento de sus pegados y mucho más.";
$lang['emptypastebin'] = "No hay pegado para mostrar.";
$lang['siteprivate'] = "Este pegado es privado";
$lang['image_wrong'] = "Captcha incorrecto.";
$lang['missing-input-response'] = "Falta el parámetro de respuesta reCAPTCHA. Verifique la configuración de PASTE.";
$lang['missing-input-secret'] = "Falta el parámetro secreto reCAPTCHA. Añádala a su configuración de PASTE.";
$lang['missing-input-response'] = "El parámetro de respuesta reCAPTCHA no es válido. Por favor, intenta completar el reCAPTCHA de nuevo.";
$lang['invalid-input-secret'] = "El parámetro secreto reCAPTCHA no es válido o está mal formado. Por favor revise su configuración de PASTE.";
$lang['empty_paste'] = "No puede publicar un pegado vacío.";
$lang['large_paste'] = "El pegado es demasiado grande. El tamaño máximo es " . $pastelimit . "MB";
$lang['paste_db_error'] = "No se puede publicar en la base de datos.";
$lang['error'] = "Algo salió mal.";
$lang['archive'] = "Archivo de pegado";
$lang['contact'] = "Contactenos";
$lang['full_name'] = "Su nombre completo es obligatorio.";
$lang['email'] = "Se requiere tu dirección de correo electrónico.";
$lang['email_invalid'] = "Su dirección de correo electrónico parece no ser válida.";
$lang['message'] = "Su mensaje es obligatorio.";
$lang['login/register'] = "Iniciar sesión/Registro";
$lang['rememberme'] = "Manténgame conectado.";
$lang['mail_acc_con'] = "$site_name Cuenta confirmada";
$lang['mail_suc'] = "El código de verificación se envió correctamente a su dirección de correo electrónico.";
$lang['email_ver'] = "Correo electrónico ya verificado.";
$lang['email_not'] = "Correo electrónico no encontrado.";
$lang['pass_change'] = "La contraseña se ha cambiado correctamente y se ha enviado a tu correo electrónico.";
$lang['notverified'] = "Cuenta no verificada.";
$lang['incorrect'] = "Incorrecto usuario/contraseña";
$lang['missingfields'] = "Todos los campos deben ser llenados.";
$lang['userexists'] = "Nombre de usuario ya tomado.";
$lang['emailexists'] = "Correo electrónico ya registrado.";
$lang ['registered'] = "Tu cuenta se ha registrado correctamente.";
$lang ['usrinvalid'] = "Tu nombre de usuario solo puede contener letras o números.";
$lang ['mypastes'] = "Mis pegados";
$lang ['pastedeleted'] = "Pegado borrado.";
$lang ['databaseerror'] = "No se puede publicar en la base de datos.";
$lang ['userchanged'] = "El nombre de usuario ha cambiado correctamente.";
$lang ['usernotvalid'] = "Nombre de usuario no válido.";
$lang ['privatepaste'] = "Este es un pegado privada.";
$lang ['wrongpassword'] = "Contraseña incorrecta.";
$lang ['pwdprotected'] = "Pegar con contraseña protegida";
$lang ['notfound'] = "No encontrado";
$lang ['wrongpwd'] = "Contraseña incorrecta. Vuelva a intentarlo.";
$lang ['myprofile'] = "Mi perfil";
$lang ['profileerror'] = "No se puede actualizar la información del perfil";
$lang ['profileupdated'] = "Se ha actualizado la información de tu perfil";
$lang ['oldpasswrong'] = "Su contraseña antigua es incorrecta.";
$lang ['archives'] = "Archivos de pegado";
$lang ['archivestitle'] = "Esta página contiene los 100 pegados publicados más recientemente.";
$lang ['pastetitle'] = "Pegar título";
$lang ['pastetime'] = "Tiempo de pegado";
$lang ['pastesyntax'] = "Pegar Sintaxis";
$lang ['pasteviews'] = "Pegar vistas";
$lang ['wentwrong'] = "Algo salió mal.";
$lang ['versent'] = "Se ha enviado un correo electrónico de verificación a su dirección de correo electrónico.";
$lang ['modpaste'] = "Modificar Pegado";
$lang ['newpaste'] = "Nueva Pega";
$lang ['highlighting'] = "Resaltado de sintaxis";
$lang ['expiration'] = "Pegar Expiración";
$lang ['visibility'] = "Pegar Visibilidad";
$lang ['pwopt'] = "Contraseña (Opcional)";
$lang ['encrypt'] = "Cifrar en la base de datos";
$lang ['entercode'] = "Introducir código";
$lang ['almostthere'] = "Casi allí, un paso más.";
$lang ['username'] = "Nombre de usuario";
$lang ['autogen'] = "Nombre generado automáticamente";
$lang ['setuser'] = "Establecer su nombre de usuario";
$lang ['keepuser'] = "Mantener el nombre autogenerado";
$lang ['enterpwd'] = "Introduzca la contraseña";
$lang ['totalpastes'] = "Total pegado:";
$lang ['membtype'] = "Tipo de membresía:";
$lang ['email'] = "Correo electrónico";
$lang ['fullname'] = "Nombre completo";
$lang ['chgpwd'] = "Cambiar contraseña";
$lang ['curpwd'] = "Contraseña actual";
$lang ['newpwd'] = "Nueva contraseña";
$lang ['confpwd'] = "Confirmar contraseña";
$lang ['mypastes'] = "Mis pegados";
$lang ['viewpastes'] = "Ver todos mis pegados";
$lang ['recentpastes'] = "Pegados recientes";
$lang ['user_public_pastes'] = "'s pegados";
$lang ['yourpastes'] = "Sus pegados";
$lang ['mypastestitle'] = "Todos tus pegados, en un solo lugar.";
$lang ['delete'] = "Eliminar";
$lang['highlighted'] = "El texto siguiente está seleccionado, presione Ctrl+C para copiar en su portapapeles. (&#8984;+C en Mac)";
$lang ['newpaste'] = "Nueva Pega";
$lang ['download'] = "Descargar";
$lang ['showlineno'] = "Mostrar / Ocultar línea no";
$lang ['copyto'] = "Copiar texto al portapapeles";
$lang ['rawpaste'] = "Pasta cruda";
$lang ['membersince'] = "Registrado:";
$lang ['delete_error_invalid'] = "Error: Pegado no borrado porque no existe o no posee el pegado.";
$lang ['not_logged_in'] = "Error: Debes haber iniciado sesión para hacer eso.";
$lang ['public'] = "Público";
$lang ['unlisted'] = "No listado";
$lang ['private'] = "Privado";
$lang ['hello'] = "Hola";
$lang['profile-message'] = "Esta es su página de perfil donde puede administrar sus pegados.<br /> Todos sus pegados públicos, privados y no listados se mostrarán aquí. También puede eliminar sus pegados de esta página. Si otros usuarios visitan tu página, solo verán las pastas que hayas puesto público.";
$lang ['profile-stats'] = "Algunas de sus estadísticas:";
$lang ['profile-total-pastes'] = "Pegados totales:";
$lang ['profile-total-pub'] = "Pegados públicos totales:";
$lang ['profile-total-unl'] = "Total de pegados no listados:";
$lang ['perfil-total-pri'] = "Total de pegados privados:";
$lang ['profile-total-views'] = "Total de vistas de todos sus pegados:";
$lang ['embed-hosted-by'] = "alojado por";
$lang ['view-raw'] = "Ver crudo";

View file

@ -1,121 +0,0 @@
<?php
/*
* Language File: French
*/
$lang = array();
$lang['banned'] = "Vous avez été banni de " . $site_name;
$lang['expired'] = "Le paste que vous recherchez est expiré.";
$lang['guestwelcome'] = $site_name . " vous permet de partager du texte et du code.";
$lang['pleaseregister'] = "<br /><br /> <a class=\"btn btn-default\" data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Connectez-vous</a> ou <a class=\"btn btn-default\" data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Enregistrez-vous</a> pour soumettre un nouveau paste. C'est gratuit !";
$lang['registertoedit'] = "<a class=\"btn btn-default\" data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Connectez-vous</a> ou <a class=\"btn btn-default\" data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Enregistrez-vous</a> pour éditer ou dupliquer ce paste. C'est gratuit !";
$lang['editpaste'] = "Éditer";
$lang['forkpaste'] = "Dupliquer";
$lang['guestmsgtitle'] = $site_name . " est fait pour le code source et le texte général de débogage.";
$lang['guestmsgbody'] = "<a data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Connectez-vous</a> ou <a data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">Enregistrez-vous</a> pour éditer, supprimer et suivre vos pastes et bien plus.";
$lang['emptypastebin'] = "Pas de pastes.";
$lang['siteprivate'] = "Ce pastebin est privé.";
$lang['image_wrong'] = "Erreur de captcha.";
$lang['missing-input-response'] = "Il manque le paramètre réponse de reCAPTCHA. Vérifier la configuration de PASTE.";
$lang['missing-input-secret'] = "Il manque le paramètre secret de reCAPTCHA. Merci de l'ajouter à la configuration de PASTE.";
$lang['missing-input-response'] = "Le paramètre réponse de reCAPTCHA est invalide. Recommencez.";
$lang['invalid-input-secret'] = "Le paramètre secret de reCAPTCHA est invalide ou incorrect. Vérifiez la configuration de PASTE.";
$lang['empty_paste'] = "Vous ne pouvez pas publier un paste vide.";
$lang['large_paste'] = "Le paste est trop volumineux. La taille maximale est " . $pastelimit . "MB";
$lang['paste_db_error'] = "Impossible de publier dans la base de données.";
$lang['error'] = "Erreur fatale.";
$lang['archive'] = "Archives";
$lang['contact'] = "Nous contacter";
$lang['full_name'] = "Le champ nom doit être renseigné.";
$lang['email'] = "Le champ email doit être renseigné.";
$lang['email_invalid'] = "Adresse email invalide.";
$lang['message'] = "Le champ message doit être renseigné.";
$lang['login/register'] = "Se connecter/S'enregistrer";
$lang['rememberme'] = "Rester connecter.";
$lang['mail_acc_con'] = "Confirmation de votre compte pour $site_name";
$lang['mail_suc'] = "Le code de vérification a été transmis à votre adresse email.";
$lang['email_ver'] = "Adresse email déjà vérifiée.";
$lang['email_not'] = "Adresse email non trouvée.";
$lang['pass_change'] = "Le mot de passe a été changé et transmis à votre adresse email.";
$lang['notverified'] = "Compte non vérifié.";
$lang['incorrect'] = "Nom d'utilisateur ou mot de passe incorrect.";
$lang['missingfields'] = "Tous les champs doivent être renseignés";
$lang['userexists'] = "Le nom d'utilisateur existe déjà.";
$lang['emailexists'] = "Adresse email déjà enregistrée.";
$lang['registered'] = "Votre compte a été enregistré.";
$lang['usrinvalid'] = "Votre nom d'utilisateur ne doit contenir que des lettres ou des chiffres.";
$lang['mypastes'] = "Mes Pastes";
$lang['pastedeleted'] = "Paste supprimé.";
$lang['databaseerror'] = "Impossible d'enregistrer dans la base de données.";
$lang['userchanged'] = "Nom d'utilisateur changé.";
$lang['usernotvalid'] = "Nom d'utilisateur non valide.";
$lang['privatepaste'] = "Ce paste est privé.";
$lang['wrongpassword'] = 'Erreur mot de passe.';
$lang['pwdprotected'] = 'Ce paste est protégé par mot de passe.';
$lang['notfound'] = "Non trouvé";
$lang['wrongpwd'] = "Erreur mot de passe, re-essayez.";
$lang['myprofile'] = "Mon profil";
$lang['profileerror'] = "Impossible de mettre à jour vos informations de profil.";
$lang['profileupdated'] = "Vos informations de profil ont été mises à jour";
$lang['oldpasswrong'] = "Erreur ancien mot de passe";
$lang['archives'] = "Archives";
$lang['archivestitle'] = "Cet écran réuni les 100 derniers paste enregistrés.";
$lang['pastetitle'] = "Titre du paste";
$lang['pastetime'] = "Durée de vie du paste";
$lang['pastesyntax'] = "Syntaxe du paste";
$lang['pasteviews'] = "Nombre de vues du paste";
$lang['wentwrong'] = "Erreur fatale.";
$lang['versent'] = "Un email de vérification a été transmis à votre adresse email.";
$lang['modpaste'] = "Modifier le paste";
$lang['newpaste'] = "Nouveau paste";
$lang['highlighting'] = "Mise en évidence de la syntaxe.";
$lang['expiration'] = "Durée de vie du paste";
$lang['visibility'] = "Portée du paste";
$lang['pwopt'] = "Mot de passe (Optionnel)";
$lang['encrypt'] = "Crypter dans la base de données";
$lang['entercode'] = "Entrez le code";
$lang['almostthere'] = "Vous avez presque terminé, il ne reste qu'une étape";
$lang['username'] = "Nom d'utilisateur";
$lang['autogen'] = "Nom généré automatiquement";
$lang['setuser'] = "Saisir votre nom d'utilisateur";
$lang['keepuser'] = "Garder le nom généré automatiquement";
$lang['enterpwd'] = "Saisir le mot de passe";
$lang['totalpastes'] = "Total pastes:";
$lang['membtype'] = "Type de compte:";
$lang['email'] = "Email";
$lang['fullname'] = "Nom complet";
$lang['chgpwd'] = "Changer le mot de passe";
$lang['curpwd'] = "Mot de passe actuel";
$lang['newpwd'] = "Nouveau mot de passe";
$lang['confpwd'] = "Confirmez le nouveau mot de passe";
$lang['mypastes'] = "Mes pastes";
$lang['viewpastes'] = "Voir tous mes pastes";
$lang['recentpastes'] = "Pastes récents";
$lang['user_public_pastes'] = "'s Pastes";
$lang['yourpastes'] = "Vos pastes";
$lang['mypastestitle'] = "Tous vos pastes au même endroit.";
$lang['delete'] = "Supprimer";
$lang['highlighted'] = "Le texte ci-dessus est sélectionné, presser Ctrl+C pour le copier dans votre presse-papier. (&#8984;+C sur Mac)";
$lang['newpaste'] = "Nouveau paste";
$lang['download'] = "Télécharger";
$lang['showlineno'] = "Afficher/Cacher les numéros de ligne.";
$lang['copyto'] = "Copier le texte dans le presse-papier.";
$lang['rawpaste'] = "Paste brut";
$lang['membersince'] = "Enregistré depuis : ";
$lang['delete_error_invalid'] = "Erreur : le paste n'a pas été supprimé car il n'existe pas ou vous n'êtes pas son propriétaire.";
$lang['not_logged_in'] = "Erreur : vous devez être connecté.";
$lang['public'] = "Public";
$lang['unlisted'] = "Fantôme";
$lang['private'] = "Privé";
$lang['hello'] = "Bonjour";
$lang['profile-message'] = "Vous pouvez gérer vos pastes sur cet écran de profil.<br /> Tous vos pastes publics, privés et fantômes sont listés ici. Vous pouvez également supprimer vos pastes depuis cet écran. Si un autre utilisateur visite votre profil, il ne verra que vos pastes publics.";
$lang['profile-stats'] = "Quelques statistiques :";
$lang['profile-total-pastes'] = "Nombre total de pastes :";
$lang['profile-total-pub'] = "Nombre de pastes publics :";
$lang['profile-total-unl'] = "Nombre de pastes fantômes :";
$lang['profile-total-pri'] = "Nombre de pastes privés :";
$lang['profile-total-views'] = "Nombre total de vues :";
$lang['embed-hosted-by'] = "hébergé par";
$lang['view-raw'] = "Voir les données brutes";

View file

@ -1 +0,0 @@

View file

@ -1,122 +0,0 @@
<?php
/*
* Language File: Polish
* Translated by m4sk1n <me@m4sk.in> (June, 2017)
*/
$lang = array();
$lang['banned'] = "Zostałeś zablokowany na " . $site_name;
$lang['expired'] = "Wklejka, którą próbujesz odwiedzić, utraciła ważność.";
$lang['guestwelcome'] = $site_name . " pozwala przechowywać tekst i kod.";
$lang['pleaseregister'] = "<br /><br /> <a class=\"btn btn-default\" data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Zaloguj się</a> lub <a class=\"btn btn-default\" data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">zarejestruj</a>, aby wysłać nową wklejkę. To nic nie kosztuje.";
$lang['registertoedit'] = "<a class=\"btn btn-default\" data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Zaloguj się</a> lub <a class=\"btn btn-default\" data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">zarejestruj</a>, aby edytować lub powielić tą wklejkę. To nic nie kosztuje.";
$lang['editpaste'] = "Edytuj";
$lang['forkpaste'] = "Powiel";
$lang['guestmsgtitle'] = $site_name . " pozwala na przechowywanie kodu źródłowego i tekstu.";
$lang['guestmsgbody'] = "<a data-target=\"#signin\" data-toggle=\"modal\" href=\"#\">Zaloguj się</a> lub <a data-target=\"#signup\" data-toggle=\"modal\" href=\"#\">zarejestruj</a> aby edytować, usuwać i mieć kontrolę nad swoimi wklejkami.";
$lang['emptypastebin'] = "Brak wklejek do pokazania.";
$lang['siteprivate'] = "Ta strona jest prywatna.";
$lang['image_wrong'] = "Nieprawidłowy kod.";
$lang['missing-input-response'] = "Parametr odpowiedzi reCAPTCHA nie jest prawidłowy. Zweryfikuj ustawienia PASTE.";
$lang['missing-input-secret'] = "Brak tajnego parametru reCAPTCHA. Dodaj go do ustawień reCAPTCHA.";
$lang['missing-input-response'] = "Parametr odpowiedzi reCAPTCHA jest nieprawidłowy. Spróbuj wykonać reCAPTCHA ponownie.";
$lang['invalid-input-secret'] = "Patametr odpowiedzi reCAPTCHA jest nieprawidłowy. Sprawdź poprawność ustawień PASTE.";
$lang['empty_paste'] = "Nie możesz umieścić pustej wklejki.";
$lang['large_paste'] = "Wysłana wklejka jest zbyt duża. Maksymalny rozmiar wynosi " . $pastelimit . "MB.";
$lang['paste_db_error'] = "Nie udało się umieścić w bazie danych.";
$lang['error'] = "Coś poszło nie tak.";
$lang['archive'] = "Archiwum wklejek";
$lang['contact'] = "Kontakt";
$lang['full_name'] = "Musisz wprowadzić imię i nazwisko.";
$lang['email'] = "Musisz wprowadzić adres e-mail.";
$lang['email_invalid'] = "Wprowadzony adres e-mail jest nieprawidłowy.";
$lang['message'] = "Musisz wprowadzić wiadomość.";
$lang['login/register'] = "Zaloguj się/Zarejestruj";
$lang['rememberme'] = "Nie wylogowywuj mnie.";
$lang['mail_acc_con'] = "Potwierdzenie konta na $site_name";
$lang['mail_suc'] = "Pomyślnie przesłano kod weryfikacyjny na podany e-mail.";
$lang['email_ver'] = "Już zweryfikowano adres e-mail.";
$lang['email_not'] = "Nie znaleziono adresu e-mail.";
$lang['pass_change'] = "Pomyślnie zmieniono hasło i przesłano na adres e-mail.";
$lang['notverified'] = "Nie zweryfikowano konto.";
$lang['incorrect'] = "Nieprawidłowa nazwa użytkownika/hasło";
$lang['missingfields'] = "Wszystkie pola muszą być wypełnione.";
$lang['userexists'] = "Nazwa użytkownika jest zajęta.";
$lang['emailexists'] = "Istnieje konto przypisane do tego adresu e-mail.";
$lang['registered'] = "Pomyślnie zarejestrowano konto.";
$lang['usrinvalid'] = "Nazwa użytkownika może zawierać wyłącznie litery i cyfry.";
$lang['mypastes'] = "Moje wklejki";
$lang['pastedeleted'] = "Usunięto wklejkę.";
$lang['databaseerror'] = "Nie udało się umieścić w bazie danych.";
$lang['userchanged'] = "Pomyślnie zmieniono nazwę użytkownika.";
$lang['usernotvalid'] = "Nieprawidłowa nazwa użytkownika.";
$lang['privatepaste'] = "To jest prywatna wklejka.";
$lang['wrongpassword'] = 'Nieprawidłowe hasło.';
$lang['pwdprotected'] = 'Wklejka chroniona hasłem';
$lang['notfound'] = "Nie znaleziono";
$lang['wrongpwd'] = "Nieprawidłowe hasło. Spróbuj ponownie.";
$lang['myprofile'] = "Moje konto";
$lang['profileerror'] = "Nie udało się zaktualizować informacje o koncie ";
$lang['profileupdated'] = "Pomyślnie zaktualizowano informacje o koncie ";
$lang['oldpasswrong'] = "Nieprawidłowe aktualne hasło.";
$lang['archives'] = "Archiwum wklejek";
$lang['archivestitle'] = "Ta strona zawiera 100 najnowszych publicznych wklejek.";
$lang['pastetitle'] = "Tytuł wklejki";
$lang['pastetime'] = "Czas dodania wklejki";
$lang['pastesyntax'] = "Składnia wklejki";
$lang['pasteviews'] = "Wyświetlenia wklejki";
$lang['wentwrong'] = "Coś poszło nie tak.";
$lang['versent'] = "Link weryfikacyjny został wysłany na podany adres e-mail.";
$lang['modpaste'] = "Modyfikuj wklejkę";
$lang['newpaste'] = "Nowa wklejka";
$lang['highlighting'] = "Podświetlanie składni";
$lang['expiration'] = "Data ważności wklejki";
$lang['visibility'] = "Widoczność wklejki";
$lang['pwopt'] = "Hasło (opcjonalne)";
$lang['encrypt'] = "Zaszyfruj w bazie danych";
$lang['entercode'] = "Wprowadź kod";
$lang['almostthere'] = "Już prawie. Pozostał jeden krok.";
$lang['username'] = "Nazwa użytkownika";
$lang['autogen'] = "Wygenerowana nazwa";
$lang['setuser'] = "Ustaw swoją nazwę";
$lang['keepuser'] = "Pozostaw wygenerowaną nazwę";
$lang['enterpwd'] = "Wprowadź hasło";
$lang['totalpastes'] = "Wklejki łącznie:";
$lang['membtype'] = "Rodzaj konta:";
$lang['email'] = "E-mail";
$lang['fullname'] = "Nazwa";
$lang['chgpwd'] = "Zmień hasło";
$lang['curpwd'] = "Obecne hasło";
$lang['newpwd'] = "Nowe hasło";
$lang['confpwd'] = "Potwierdź hasło";
$lang['mypastes'] = "Moje wklejki";
$lang['viewpastes'] = "Pokaż wszystkie moje wklejki";
$lang['recentpastes'] = "Najnowsze wklejki";
$lang['user_public_pastes'] = "Wklejki użytkownika";
$lang['yourpastes'] = "Twoje wklejki";
$lang['mypastestitle'] = "Wszystkie twoje wklejki w jednym miejscu.";
$lang['delete'] = "Usuń";
$lang['highlighted'] = "Tekst jest zaznaczony, naciśnij Ctrl+C aby skopiować. (&#8984;+C na Macu)";
$lang['newpaste'] = "Nowa wklejka";
$lang['download'] = "Pobierz";
$lang['showlineno'] = "Pokaż/ukryj wiersz nr.";
$lang['copyto'] = "Kopiuj tekst do schowka";
$lang['rawpaste'] = "Surowy plik wklejki";
$lang['membersince'] = "Data dołączenia: ";
$lang['delete_error_invalid'] = "Błąd: Nie usunięto wklejki. Wklejka nie istnieje lub nie jesteś jej autorem.";
$lang['not_logged_in'] = "Błąd: Musisz zalogować się, aby to zrobić.";
$lang['public'] = "Publiczna";
$lang['unlisted'] = "Niewidoczna";
$lang['private'] = "Prywatna";
$lang['hello'] = "Witaj";
$lang['profile-message'] = "To jest strona twojego konta, na której możesz zarządzać wklejkami.<br /> Znajdują się tu twoje wszystkie prywatne, publiczne i niewidoczne wklejki. Możesz je tutaj usunąć. Inni użytkownicy mogą zobaczyć tu tylko twoje publiczne wklejki.";
$lang['profile-stats'] = "Twoje statystyki:";
$lang['profile-total-pastes'] = "Wklejki łącznie:";
$lang['profile-total-pub'] = "Publiczne wklejki:";
$lang['profile-total-unl'] = "Niewidoczne wklejki:";
$lang['profile-total-pri'] = "Prywatne wklejki:";
$lang['profile-total-views'] = "Wyświetlenia wszystkich wklejek:";
$lang['embed-hosted-by'] = "przechowywane na";
$lang['view-raw'] = "Surowy plik";

View file

@ -1,7 +0,0 @@
<?php
/*
* Language File: Russian
*/
$lang = array();

View file

@ -42,4 +42,4 @@ function pp_random_password() : string {
* can reasonably be handled by a user.
*/
return hash('MD5', pp_random_bytes(64));
}
}

198
index.php
View file

@ -1,198 +0,0 @@
<?php
/*
* Paste <https://github.com/jordansamuel/PASTE>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License in GPL.txt for more details.
*/
$directory = 'install';
if (file_exists($directory)) {
header("Location: install");
exit();
}
// Required functions
define('IN_PONEPASTE', 1);
require_once('includes/common.php');
require_once('includes/captcha.php');
require_once('includes/functions.php');
require_once('includes/Tag.class.php');
function verifyCaptcha() : string|bool {
global $captcha_config;
global $lang;
global $current_user;
if ($captcha_config['enabled'] && !$current_user) {
$scode = strtolower(htmlentities(Trim($_POST['scode'])));
$cap_code = strtolower($_SESSION['captcha']['code']);
if ($cap_code !== $scode) {
return $lang['image_wrong']; // Wrong captcha.
}
}
return true;
}
/**
* Calculate the expiry of a paste based on user input.
*
* @param string $expiry Expiry time.
* SELF means to expire upon one view. +10M, +1H, +1D, +1W, +2W, +1M all do the obvious.
* Anything unhandled means to expire never.
* @return string|null Expiry time, or NULL if expires never.
*/
function calculatePasteExpiry(string $expiry) {
// used to use mktime
if ($expiry === 'self') {
return 'SELF'; // What does this do?
}
$valid_expiries = ['10M', '1H', '1D', '1W', '2W', '1M'];
return in_array($expiry, $valid_expiries)
? (new DateTime())->add(new DateInterval("P{$expiry}"))->format('U')
: null;
}
function validatePasteFields() : string|null {
global $lang;
if (empty($_POST["paste_data"]) || trim($_POST['paste_data'] === '')) { /* Empty paste input */
return $lang['empty_paste'];
} elseif (!isset($_POST['title'])) { /* No paste title POSTed */
return $lang['error'];
} elseif (empty($_POST["tag_input"])) { /* No tags provided */
return $lang['notags'];
} elseif (strlen($_POST["title"]) > 70) { /* Paste title too long */
return $lang['titlelen'];
} elseif (mb_strlen($_POST["paste_data"], '8bit') > PP_PASTE_LIMIT_BYTES) { /* Paste size too big */
return $lang['large_paste'];
}
return null;
}
// UTF-8
header('Content-Type: text/html; charset=utf-8');
// Current date & user IP
$date = date('jS F Y');
$ip = $_SERVER['REMOTE_ADDR'];
// Sitemap
$site_sitemap_rows = $conn->query('SELECT * FROM sitemap_options LIMIT 1');
if ($row = $site_sitemap_rows->fetch()) {
$priority = $row['priority'];
$changefreq = $row['changefreq'];
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
if ($captcha_config['enabled']) {
$_SESSION['captcha'] = captcha($captcha_config['colour'], $captcha_config['mode'], $captcha_config['multiple'], $captcha_config['allowed']);
}
}
updatePageViews($conn);
// POST Handler
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$error = validatePasteFields();
if ($error !== null) {
goto OutPut;
}
$captchaResponse = verifyCaptcha();
if ($captchaResponse !== true) {
$error = $captchaResponse;
goto OutPut;
}
$editing = isset($_POST['edit']);
$p_title = trim(htmlspecialchars($_POST['title']));
if (empty($p_title)) {
$p_title = 'Untitled';
}
$p_content = htmlspecialchars($_POST['paste_data']);
$p_visible = trim(htmlspecialchars($_POST['visibility']));
$p_code = trim(htmlspecialchars($_POST['format']));
$p_expiry = trim(htmlspecialchars($_POST['paste_expire_date']));
$p_password = $_POST['pass'];
$tag_input = $_POST['tag_input'];
if (empty($p_password)) {
$p_password = null;
} else {
$p_password = password_hash($p_password, PASSWORD_DEFAULT);
}
$p_encrypt = $_POST['encrypted'];
if ($p_encrypt == "" || $p_encrypt == null) {
$p_encrypt = "0";
} else {
// Encrypt option
$p_encrypt = "1";
$p_content = openssl_encrypt($p_content, PP_ENCRYPTION_ALGO, PP_ENCRYPTION_KEY);
}
// Set expiry time
$expires = calculatePasteExpiry($p_expiry);
// Edit existing paste or create new?
if ($editing) {
if ($current_user &&
$current_user->user_id === (int)$conn->querySelectOne('SELECT user_id FROM pastes WHERE id = ?', [$_POST['paste_id']])['user_id']) {
$paste_id = intval($_POST['paste_id']);
$conn->query(
"UPDATE pastes SET title = ?, content = ?, visible = ?, code = ?, expiry = ?, password = ?, encrypt = ?, ip = ?, updated_at = NOW()
WHERE id = ?",
[$p_title, $p_content, $p_visible, $p_code, $expires, $p_password, $p_encrypt, $ip, $paste_id]
);
Tag::replacePasteTags($conn, $paste_id, Tag::parseTagInput($tag_input));
} else {
$error = $lang['loginwarning']; //"You must be logged in to do that."
}
} else {
$paste_owner = $current_user ? $current_user->user_id : 1; /* 1 is the guest user's user ID */
$paste_id = $conn->queryInsert(
"INSERT INTO pastes (title, content, visible, code, expiry, password, encrypt, user_id, created_at, ip, views) VALUES
(?, ?, ?, ?, ?, ?, ?, ?, NOW(), ?, 0)",
[$p_title, $p_content, $p_visible, $p_code, $expires, $p_password, $p_encrypt, $paste_owner, $ip]
);
Tag::replacePasteTags($conn, $paste_id, Tag::parseTagInput($tag_input));
if ($p_visible == '0') {
addToSitemap($paste_id, $priority, $changefreq, $mod_rewrite);
}
}
// Redirect to paste on successful entry, or on successful edit redirect back to edited paste
if (isset($paste_id)) {
header('Location: ' . urlForPaste($paste_id));
die();
}
}
OutPut:
// Theme
require_once('theme/' . $default_theme . '/header.php');
require_once('theme/' . $default_theme . '/main.php');
require_once('theme/' . $default_theme . '/footer.php');

30
js/archive.js Normal file
View file

@ -0,0 +1,30 @@
import { escape, whenReady } from './dom';
import { DataTable, dumbFilterCallback } from './data_tables';
import { tagsToHtml } from "./utils";
import { globalSetup } from './main';
whenReady(() => {
globalSetup();
const urlParams = new URLSearchParams(window.location.search);
const myParam = urlParams.get('q');
const apiUrl = /* myParam !== null ? '/api/ajax_pastes.php?q=' + myParam : */ '/api/ajax_pastes.php';
const table = new DataTable(document.getElementById('archive'), {
ajaxCallback: (resolve) => {
fetch(apiUrl)
.then(r => r.json())
.then(resolve);
},
rowCallback: (rowData) => {
return `<tr>
<td><a href="/${rowData.id}">${escape(rowData.title)}</a></td>
<td><a href="/user/${escape(rowData.author)}">${escape(rowData.author)}</a></td>
<td>${tagsToHtml(rowData.tags)}</td>
</tr>`;
},
filterCallback: dumbFilterCallback,
preFilter: myParam
});
table.attach();
});

256
js/data_tables.js Normal file
View file

@ -0,0 +1,256 @@
import { makeEl, clearEl } from "./dom";
class SimplePaginator {
constructor(element) {
this.element = element;
}
attach(pageCallback) {
this.element.addEventListener('click', evt => {
if (evt.target && evt.target.classList.contains('paginator__button')) {
pageCallback(+evt.target.dataset.page);
}
});
}
update(totalRecords, perPage, currentPage) {
clearEl(this.element);
/* First and last page in existence */
const firstPage = 0;
const lastPage = Math.floor(totalRecords / perPage); // ish?
const numPagesToShow = 2;
if (lastPage === firstPage) {
return;
}
/* First and last page the main paginator will show */
const firstPageShow = (currentPage - numPagesToShow) < firstPage ? firstPage : (currentPage - numPagesToShow);
const lastPageShow = (currentPage + numPagesToShow) > lastPage ? lastPage : (currentPage + numPagesToShow);
/* Whether to show the first and last pages in existence at the ends of the paginator */
const showFirstPage = (Math.abs(firstPage - currentPage)) > (numPagesToShow);
const showLastPage = (Math.abs(lastPage - currentPage)) > (numPagesToShow);
const prevButtonDisabled = currentPage === firstPage ? 'disabled' : ''
/* Previous button */
this.element.appendChild(makeEl(
`<button class="paginator__button previous" ${prevButtonDisabled} data-page="${currentPage - 1}">Previous</button>`
));
/* First page button */
if (showFirstPage) {
this.element.appendChild(makeEl(
`<button class="paginator__button" data-page="${firstPage}">${firstPage}</button>`
));
this.element.appendChild(makeEl(`<span class="ellipsis">…</span>`));
}
/* "window" buttons */
for (let i = firstPageShow; i <= lastPageShow; i++) {
const selected = (i === currentPage ? 'paginator__button--selected' : '');
this.element.appendChild(makeEl(
`<button class="paginator__button ${selected}" data-page="${i}">${i}</button>`
));
}
/* Last page button */
if (showLastPage) {
this.element.appendChild(makeEl(`<span class="ellipsis">…</span>`));
this.element.appendChild(makeEl(
`<button class="paginator__button" data-page="${lastPage}">${lastPage}</button>`
));
}
const nextButtonDisabled = currentPage === lastPage ? 'disabled' : ''
/* Next button */
this.element.appendChild(makeEl(
`<button class="paginator__button next" ${nextButtonDisabled} data-page="${currentPage + 1}">Next</button>`
));
}
}
class DataTable {
constructor(element, options) {
this.element = element;
this.container = element.parentElement;
this.options = options;
this.ajaxCallback = options.ajaxCallback;
this.data = [];
this.unfilteredData = [];
this.totalRecords = -1;
this.perPage = 20;
this.currentPage = 0;
this.paginator = new SimplePaginator(this.container.querySelector('.paginator'));
this.filterCallback = options.filterCallback;
this.sortField = null;
this.sortDir = true;
}
attach() {
this.filterField = this.container.querySelector('input.search');
if (this.filterField && this.filterCallback) {
this.filterField.addEventListener('keyup', evt => {
if (evt.target) {
this._updateFilter(evt.target.value);
}
});
if (this.options.preFilter) {
this.filterField.value = this.options.preFilter;
}
}
this.perPageField = this.container.querySelector('select[name=per_page]');
if (this.perPageField) {
this.perPageField.addEventListener('change', evt => {
this.perPage = Number(evt.target.value);
this._updatePage(0);
});
}
const header = this.element.querySelector('tr.paginator__sort');
if (header) {
header.addEventListener('click', evt => {
const target = evt.target;
if (!target.dataset.sortField) {
return;
}
if (this.sortField) {
const elem = this.element.querySelector(`th[data-sort-field=${this.sortField}]`)
elem.classList.remove('paginator__sort--down');
elem.classList.remove('paginator__sort--up');
}
this._updateSort(target.dataset.sortField, !this.sortDir);
target.classList.add(this.sortDir ? 'paginator__sort--up' : 'paginator__sort--down');
});
}
this.paginator.attach(this._updatePage.bind(this));
this._loadEntries();
}
/* Load the requested data from the server, and when done, update the DOM. */
_loadEntries() {
new Promise(this.ajaxCallback)
.then(data => {
this.element.classList.remove('hidden');
this.unfilteredData = data.data;
this._updateFilter(this.options.preFilter);
});
}
/* Update the DOM to reflect the current state of the data we have loaded */
_updateEntries(data) {
this.data = data;
this.totalRecords = this.data.length;
const bodyElement = this.element.querySelector('tbody');
clearEl(bodyElement);
const firstIndex = (this.perPage * this.currentPage);
const lastIndex = (firstIndex + this.perPage) > this.totalRecords ? this.totalRecords : (firstIndex + this.perPage);
for (let i = firstIndex; i < lastIndex; i++) {
const rowElem = makeEl(this.options.rowCallback(this.data[i]));
rowElem.classList.add(i % 2 === 0 ? 'odd' : 'even');
bodyElement.appendChild(rowElem);
}
this.paginator.update(this.totalRecords, this.perPage, this.currentPage);
}
_updatePage(n) {
this.currentPage = n;
this.paginator.update(this.totalRecords, this.perPage, this.currentPage);
this._updateEntries(this.data);
}
_updateFilter(query) {
/* clearing the query */
if (query === null || query === '') {
this._updateEntries(this.unfilteredData);
return;
}
let data = [];
for (const datum of this.unfilteredData) {
if (this.filterCallback(datum, query)) {
data.push(datum);
}
}
this._updatePage(0)
this._updateEntries(data);
}
_updateSort(field, direction) {
this.sortField = field;
this.sortDir = direction;
let newEntries = [...this.data].sort((a, b) => {
let sorter = 0;
if (a[field] > b[field]) {
sorter = 1;
} else if (a[field] < b[field]) {
sorter = -1;
}
if (!direction) {
sorter = -sorter;
}
return sorter;
});
this._updatePage(0);
this._updateEntries(newEntries);
}
}
const dumbFilterCallback = (datum, query) => {
if (!query) {
return true;
}
const queryLower = query.toLowerCase();
if (queryLower === 'untagged' && datum.tags.length === 0) {
return true;
}
if (datum.title.toLowerCase().indexOf(queryLower) !== -1) {
return true;
}
if (datum.author.toLowerCase().indexOf(queryLower) !== -1) {
return true;
}
/* this is inefficient */
for (const tag of datum.tags) {
if (tag.name.toLowerCase().indexOf(queryLower) !== -1) {
return true;
}
}
return false;
};
export { DataTable, dumbFilterCallback };

48
js/dom.js Normal file
View file

@ -0,0 +1,48 @@
const $ = function(selector) {
return document.querySelector(selector);
};
const $$ = function(selector) {
return document.querySelectorAll(selector) || [];
};
const makeEl = function(html) {
const template = document.createElement('template');
template.innerHTML = html.trim();
return template.content.firstChild;
};
const clearEl = function(el) {
while (el.firstChild) {
el.removeChild(el.firstChild);
}
};
const toggleEl = function(el) {
if (el.classList.contains('is-hidden')) {
el.classList.remove('is-hidden');
} else {
el.classList.add('is-hidden');
}
};
const escape = function(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
const whenReady = function(funcp) {
if (document.readyState !== 'loading') {
funcp();
} else {
document.addEventListener('DOMContentLoaded', funcp);
}
}
export { whenReady, $, $$, makeEl, clearEl, toggleEl, escape };

4
js/generic.js Normal file
View file

@ -0,0 +1,4 @@
import { whenReady } from "./dom";
import { globalSetup } from "./main";
whenReady(globalSetup);

115
js/main.js Normal file
View file

@ -0,0 +1,115 @@
import { $, $$, toggleEl } from './dom';
import { TagsInput } from "./tag_input";
const setupSignupModal = () => {
const signupButton = $('[data-target~="#signin"],[data-target~="#signup"]');
if (signupButton) {
signupButton.href = 'javascript:void(0)';
signupButton.addEventListener('click', () => {
$('.modal').classList.add('is-active');
});
$('.modal-button-close').addEventListener('click', () => {
$('.modal').classList.remove('is-active');
});
}
}
const globalSetup = () => {
Array.prototype.forEach.call($$('.js-tag-input'), (el) => {
new TagsInput(el).attach();
});
setupSignupModal();
const embedButton = $('.panel-tools .embed-tool');
if (embedButton){
embedButton.addEventListener('click', (evt) => {
if (evt.target && evt.target.closest('.panel-tools')) {
toggleEl(evt.target.closest('.panel-tools').querySelector('.panel-embed'));
}
});
}
const expandButton = $('.expand-tool');
if (expandButton) {
expandButton.addEventListener('click', (evt) => {
if (evt.target && evt.target.closest('.panel')) {
const panel = evt.target.closest('.panel');
if (panel.classList.contains('panel-fullsize')) {
panel.classList.remove('panel-fullsize');
} else {
panel.classList.add('panel-fullsize');
}
}
});
}
// Notifications
(document.querySelectorAll('.notification .delete') || []).forEach(($delete) => {
const $notification = $delete.parentNode;
$delete.addEventListener('click', () => {
$notification.parentNode.removeChild($notification);
});
});
// Hamburger menu
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
if ($navbarBurgers.length > 0) {
$navbarBurgers.forEach(el => {
el.addEventListener('click', () => {
const target = el.dataset.target;
const $target = document.getElementById(target);
el.classList.toggle('is-active');
$target.classList.toggle('is-active');
});
});
}
const preloader = $('.preloader');
const main = $('main');
if (preloader && main) {
preloader.remove();
main.id = '';
}
// CAPTCHA refresh
const captchaContainer = $('.captcha_container');
if (captchaContainer) {
const refreshElement = captchaContainer.querySelector('a');
const imageElement = captchaContainer.querySelector('img');
if (refreshElement && imageElement) {
refreshElement.addEventListener('click', () => {
let src = imageElement.src;
if (src.indexOf('&refresh') !== -1) {
// yeah, it's kinda cancerous. fuck off.
src = src.split('&rand=')[0];
} else {
src += '&refresh';
}
imageElement.src = src + '&rand=' + Math.random();
});
}
}
const hiddenElements = $$('.js-hidden');
if (hiddenElements) {
Array.prototype.forEach.call(hiddenElements, (elem) => {
toggleEl(elem);
});
}
}
export { globalSetup };

106
js/tag_input.js Normal file
View file

@ -0,0 +1,106 @@
import { makeEl, escape } from "./dom";
class TagsInput {
constructor(element, options = {}) {
this.element = element;
this.tags = [];
this.options = options
this.maxTags = options.maxTags || 32;
this.inputNode = null;
this.containerNode = null;
}
attach() {
this.element.style.display = 'none';
this.containerNode = makeEl('<div class="tags-input"></div>');
this.inputNode = makeEl('<input class="input" type="text" placeholder="32 tags maximum" value="" />');
this.containerNode.appendChild(this.inputNode);
this.element.parentNode.insertBefore(this.containerNode, this.element.nextSibling);
/* Load existing tags from input */
if (this.element.value) {
for (const tag of this.element.value.split(',')) {
this.addTag(tag);
}
}
/* Handle addition and removal of tags via key-presses */
this.containerNode.addEventListener('keydown', this._handleInputKeyUp.bind(this));
/* Handle deletions by clicking the delete button */
this.containerNode.addEventListener('click', this._handleContainerClick.bind(this));
}
detach() {
this.tags.clear();
this.containerNode.remove();
this.element.style.display = 'inline-block';
}
updateHiddenInputValue() {
this.element.value = this.tags.join(',');
}
deleteTagNode(node) {
this.tags.splice(this.tags.indexOf(node.dataset.value.toLowerCase()), 1);
node.remove();
/* Below the limit? Make sure the input is enabled. */
if (this.tags.length < this.maxTags) {
this.inputNode.disabled = false;
}
}
addTag(tagValue) {
tagValue = tagValue.trim();
/* Tag value is probably not empty and we don't already have the same tag. */
if (tagValue !== '' && this.tags.indexOf(tagValue.toLowerCase()) === -1) {
this.tags.push(tagValue.toLowerCase());
this.inputNode.parentNode.insertBefore(
makeEl('<span class="tag is-info" data-value="' + escape(tagValue) + '">' + escape(tagValue) + '<span class="delete is-small" /></span>'),
this.inputNode
);
/* Too many tags, disable the input for now. */
if (this.tags.length >= this.maxTags) {
this.inputNode.disabled = true;
}
}
}
_handleInputKeyUp(evt) {
let tagValue = this.inputNode.value;
if (evt.key === 'Backspace' && tagValue === '') {
// Remove the child
if (this.inputNode.previousSibling) {
this.deleteTagNode(this.inputNode.previousSibling);
this.updateHiddenInputValue();
}
} else if (evt.key === ',') {
this.addTag(tagValue);
this.inputNode.value = ''
this.updateHiddenInputValue();
evt.preventDefault();
} else if (evt.key !== 'Backspace' && tagValue.length > 255) { // This could be improved to check if it would actually result in a new char being typed...
evt.preventDefault();
}
}
_handleContainerClick(evt) {
if (evt.target && evt.target.classList.contains('delete')) {
this.deleteTagNode(evt.target.closest('.tag'));
this.updateHiddenInputValue();
}
}
}
export { TagsInput };

97
js/user_profile.js Normal file
View file

@ -0,0 +1,97 @@
import { escape, whenReady } from './dom';
import { DataTable, dumbFilterCallback } from './data_tables';
import { tagsToHtml } from "./utils";
import { globalSetup } from './main';
const getUserInfo = () => {
const elem = document.getElementById('js-data-holder');
if (!elem) {
return { userId: null, csrfToken: null };
}
return { userId: elem.dataset.userId, csrfToken: elem.dataset.csrfToken };
};
const parsePasteInfo = (elem) => {
if (!elem.dataset.pasteInfo) {
return null;
}
return JSON.parse(elem.dataset.pasteInfo);
};
whenReady(() => {
globalSetup();
const urlParams = new URLSearchParams(window.location.search);
const myParam = urlParams.get('q');
const myPastesElem = document.getElementById('archive');
const apiUrl = '/api/user_pastes.php?user_id=' + myPastesElem.dataset.userId;
console.log('myPastesElem', myPastesElem);
const table = new DataTable(myPastesElem, {
ajaxCallback: (resolve) => {
fetch(apiUrl)
.then(r => r.json())
.then(resolve);
},
rowCallback: (rowData) => {
console.log('rowData', rowData);
const userData = getUserInfo();
const ownedByUser = (parseInt(rowData.author_id) === parseInt(userData.userId));
console.log(ownedByUser);
const deleteElem = ownedByUser ? `<td class="td-center">
<form action="/${rowData.id}" method="POST">
<input type="hidden" name="delete" value="delete" />
<input type="hidden" name="csrf_token" value="${userData.csrfToken}" />
<input type="submit" value="Delete" />
</form>
</td>` : '';
const pasteCreatedAt = new Date(rowData.created_at).toLocaleString();
const pasteVisibility = ownedByUser ? `<td class="td-center">${['Public', 'Unlisted', 'Private'][rowData.visibility]}</td>` : '';
return `<tr>
<td><a href="/${rowData.id}">${escape(rowData.title)}</a></td>
<td class="td-center">${pasteCreatedAt}</td>
${pasteVisibility}
<td class="td-center">${rowData.views || 0}</td>
<td>${tagsToHtml(rowData.tags)}</td>
${deleteElem}
</tr>`;
},
filterCallback: dumbFilterCallback,
preFilter: myParam
});
table.attach();
const myFavesElem = document.getElementById('favs');
if (!myFavesElem) {
return;
}
const faveTable = new DataTable(myFavesElem, {
ajaxCallback: (resolve) => {
console.log('invoker invoked');
resolve({
data: Array.prototype.map.call(myFavesElem.querySelectorAll('tbody > tr'), parsePasteInfo)
});
},
rowCallback: (rowData) => {
const recentUpdate = rowData.recently_updated ?
`<i class='far fa-check-square fa-lg' aria-hidden='true'></i>` :
`<i class='far fa-minus-square fa-lg' aria-hidden='true'></i>`;
const pasteFavedAt = new Date(rowData.favourited_at).toLocaleString();
// <td><a href="/user/${escape(rowData.author)}">${escape(rowData.author)}</a></td>
return `<tr>
<td><a href="/${rowData.id}">${escape(rowData.title)}</a></td>
<td class="td-center">${pasteFavedAt}</td>
<td class="td-center">${recentUpdate}</td>
<td>${tagsToHtml(rowData.tags)}</td>
</tr>`;
},
filterCallback: dumbFilterCallback
});
faveTable.attach();
});

23
js/utils.js Normal file
View file

@ -0,0 +1,23 @@
import { escape } from "./dom";
const tagsToHtml = (tags) => {
return tags.map(tagData => {
let tagColorClass;
const tagLower = tagData.name.toLowerCase();
if (tagLower === 'nsfw' || tagLower === 'explicit') {
tagColorClass = 'is-danger';
} else if (tagLower === 'safe') {
tagColorClass = 'is-success';
} else if (tagLower.charAt(0) === '/' && tagLower.charAt(tagLower.length - 1) === '/') {
tagColorClass = 'is-primary';
} else {
tagColorClass = 'is-info';
}
return `<a href="/archive?q=${tagData.slug}">
<span class="tag ${tagColorClass}">${escape(tagData.name)}</span>
</a>`;
}).join('');
};
export { tagsToHtml };

145
login.php
View file

@ -1,145 +0,0 @@
<?php
/*
* Paste <https://github.com/jordansamuel/PASTE>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License in GPL.txt for more details.
*/
// Required functions
define('IN_PONEPASTE', 1);
require_once('includes/common.php');
require_once('includes/functions.php');
require_once('includes/passwords.php');
// Current Date & User IP
$date = date('jS F Y');
$ip = $_SERVER['REMOTE_ADDR'];
// Check if already logged in
if ($current_user !== null) {
header("Location: ./");
die();
}
// Page title
$p_title = $lang['login/register']; // "Login/Register";
updatePageViews($conn);
if (isset($_POST['forgot'])) {
if (!empty($_POST['username']) && !empty($_POST['recovery_code'])) {
$username = trim($_POST['username']);
$recovery_code = trim($_POST['recovery_code']);
$query = $conn->query("SELECT id, recovery_code_hash FROM users WHERE username = ?", [$username]);
$row = $query->fetch();
if ($row && pp_password_verify($_POST['recovery_code'], $row['recovery_code_hash'])) {
$new_password = pp_random_password();
$new_password_hash = pp_password_hash($new_password);
$recovery_code = pp_random_token();
$new_recovery_code_hash = pp_password_hash($recovery_code);
$conn->prepare('UPDATE users SET password = ?, recovery_code_hash = ? WHERE id = ?')
->execute([$new_password_hash, $new_recovery_code_hash, $row['id']]);
$success = 'Your password has been changed. A new recovery code has also been generated. Please note the recovery code and then sign in with the new password.';
} else {
$error = $lang['incorrect'];
}
} else {
$error = $lang['missingfields']; // "All fields must be filled out";
}
} elseif (isset($_POST['signin'])) { // Login process
if (!empty($_POST['username']) && !empty($_POST['password'])) {
$remember_me = (bool)$_POST['remember_me'];
$username = trim($_POST['username']);
$row = $conn->query("SELECT id, password, banned FROM users WHERE username = ?", [$username])
->fetch();
$needs_rehash = false;
/* This is designed to be a constant time lookup, hence the warning suppression operator so that
* we always call pp_password_verify, even if row is null.
*/
if (pp_password_verify($_POST['password'], @$row['password'], $needs_rehash)) {
$user_id = $row['id'];
if ($needs_rehash) {
$new_password_hash = pp_password_hash($_POST['password']);
$conn->query('UPDATE users SET password = ? WHERE id = ?',
[$new_password_hash, $user_id]);
}
if ($row['banned']) {
// User is banned
$error = $lang['banned'];
} else {
// Login successful
$_SESSION['user_id'] = (string)$user_id;
if ($remember_me) {
$remember_token = pp_random_token();
$expire_at = (new DateTime())->add(new DateInterval('P1Y'));
$conn->query('INSERT INTO user_sessions (user_id, token, expire_at) VALUES (?, ?, FROM_UNIXTIME(?))', [$user_id, $remember_token, $expire_at->format('U')]);
setcookie(User::REMEMBER_TOKEN_COOKIE, $remember_token, [
'expires' => (int)$expire_at->format('U'),
'secure' => !empty($_SERVER['HTTPS']), /* Local dev environment is non-HTTPS */
'httponly' => true,
'samesite' => 'Lax'
]);
}
header('Location: ' . $_SERVER['HTTP_REFERER']);
exit();
}
} else {
// Username not found or password incorrect.
$error = $lang['incorrect'];
}
} else {
$error = $lang['missingfields']; // "All fields must be filled out.";
}
} elseif (isset($_POST['signup'])) { // Registration process
$username = htmlentities(trim($_POST['username'], ENT_QUOTES));
$password = pp_password_hash($_POST['password']);
$chara_max = 25; //characters for max input
if (empty($_POST['password']) || empty($_POST['username'])) {
$error = $lang['missingfields']; // "All fields must be filled out";
} elseif (strlen($username) > $chara_max) {
$error = $lang['maxnamelimit']; // "Username already taken.";
} elseif (preg_match('/[^A-Za-z0-9._\\-$]/', $username)) {
$error = $lang['usrinvalid']; // "Username not valid. Usernames can't contain special characters.";
} else {
if ($conn->querySelectOne('SELECT 1 FROM users WHERE username = ?', [$username])) {
$error = $lang['userexists']; // "Username already taken.";
} else {
$recovery_code = pp_random_token();
$recovery_code_hash = pp_password_hash($recovery_code);
$conn->query(
"INSERT INTO users (username, password, recovery_code_hash, picture, date, ip, badge) VALUES (?, ?, ?, 'NONE', ?, ?, '0')",
[$username, $password, $recovery_code_hash, $date, $ip]
);
$success = $lang['registered']; // "Your account was successfully registered.";
}
}
}
// Theme
require_once('theme/' . $default_theme . '/header.php');
require_once('theme/' . $default_theme . '/login.php');
require_once('theme/' . $default_theme . '/footer.php');

Some files were not shown because too many files have changed in this diff Show more