This commit is contained in:
Kieran 2017-11-09 15:49:18 +08:00
parent ce7b4120a9
commit 7e4002dc00
36 changed files with 1077 additions and 1017 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
out/
*.xml
config.php
src/php/config.php
google*.html

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "sitemap-php"]
path = sitemap-php
url = https://github.com/o/sitemap-php

View File

@ -1,95 +0,0 @@
# baba
Simple file upload with statistics
## Features
* Async uploads
* View counter
* Copy/Paste uploads
* Drag&Drop uploads
* File browser uploads
* Eye pain while reading logo text
* Random background colors
## Screenshots
![screenshot1](http://shit.host/d37c6bcb25b42d8493d43634a12ee6e2b6241f8aa33eb3b5b55c7552f90c1b65/baba0.PNG)
![screenshot2](http://shit.host/4e6e7c4598533d2e29b1b10d14600333c9fae901ff477b5f05ad8fcfadc080c2/baba1.PNG)
![screenshot3](http://shit.host/bf544fd2b1cc9f32b4556062c7bb77bd64647211c134e7d3811fbd8b43707ca6/baba2.PNG)
## Roadmap
See issues.
##Install
### Requirements
* nginx (or other)
* php5
* php5-mysql
* mysql-server
### Setup
Start by configuring your ```config.php``` with details for you mysql server.
Next import the sql script to create the table
```
cat db.sql | mysql -p -D baba
```
Next you need to add a rule to you webserver to use index.php for 404 errors, below is an example for nginx
```
location / {
try_files $uri index.php?hash=$uri;
}
```
If this is not setup correctly your file links will not work.
Another thing you will need to do is adjust the max post size in PHP and nginx, for nginx you add the following:
```
client_max_body_size 512M;
```
Or whatever you want to the max file size to be.
In ```php.ini``` change the following:
```
memory_limit = 512M
post_max_size = 512M
```
You will need to set the memory limit to the same size as your desired max file size since the file is stored in memory while reading from the client.
```post_max_size``` is the size you will see on the home page.
Finally make sure the PHP process has access to the directory where files will be saved.
The default directory is ```out``` in the root of the site. To set this up do the following.
```
mkdir out
mkdir out/thumbs
chown www-data:www-data out -R
chmod 770 out -R
```
Make sure to reset php5 and your webserver so settings apply
Run composer
```
php composer.phar install
```
## License
Whats that?

22
bower.json Normal file
View File

@ -0,0 +1,22 @@
{
"name": "void.cat",
"description": "void.cat",
"main": "index.html",
"authors": [
"v0l"
],
"license": "MIT",
"homepage": "https://github.com/v0l/void.cat",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"polymer": "polymer/polymer#^2.0.0",
"webcomponentsjs": "webcomponents/webcomponentsjs#^1.0.17"
}
}

View File

@ -1,15 +0,0 @@
<?php
/* DB SETTINGS */
define('_DB_HOST', '127.0.0.1');
define('_DB_DATABASE', 'baba');
define('_DB_USER', 'root');
define('_DB_PASS', 'root');
/* GENERAL SETTINGS */
define('_DEFAULT_TYPE', 'application/octet-stream');
define('_SITEURL', 'http://example.com/');
define('_UPLOADDIR', '/out/');
define('_FILEPATH', dirname ( __FILE__ ) . _UPLOADDIR);
define('_DISCORD_WEBHOOK', 'DISCORD_HOOK_URL');
define('_FILE_EXPIRE_TIME', 30);
?>

12
db.sql
View File

@ -1,12 +0,0 @@
CREATE TABLE `files` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`hash160` varchar(40) DEFAULT NULL,
`hash256` varchar(64) DEFAULT NULL,
`mime` varchar(64) DEFAULT NULL,
`path` varchar(512) DEFAULT NULL,
`filename` varchar(255) DEFAULT NULL,
`views` int(11) DEFAULT 0 NULL,
`created` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `hs160` (`hash160`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=54 DEFAULT CHARSET=latin1

View File

@ -1,82 +0,0 @@
<?php
/**
* Reads the requested portion of a file and sends its contents to the client with the appropriate headers.
*
* This HTTP_RANGE compatible read file function is necessary for allowing streaming media to be skipped around in.
*
* @param string $location
* @param string $filename
* @param string $mimeType
* @return void
*
* @link https://groups.google.com/d/msg/jplayer/nSM2UmnSKKA/Hu76jDZS4xcJ
* @link http://php.net/manual/en/function.readfile.php#86244
*/
function smartReadFile($location, $filename, $mimeType = 'application/octet-stream')
{
if (!file_exists($location))
{
header ("HTTP/1.1 404 Not Found");
return;
}
$size = filesize($location);
$ftime = filemtime($location);
$time = date('r', $ftime);
$fm = @fopen($location, 'rb');
if (!$fm)
{
header ("HTTP/1.1 505 Internal server error");
return;
}
$begin = 0;
$end = $size - 1;
if (isset($_SERVER['HTTP_RANGE']))
{
if (preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches))
{
$begin = intval($matches[1]);
if (!empty($matches[2]))
{
$end = intval($matches[2]);
}
}
}
if (isset($_SERVER['HTTP_RANGE']))
{
header('HTTP/1.1 206 Partial Content');
}
else
{
header('HTTP/1.1 200 OK');
}
$expire = 604800;
header("Content-Type: $mimeType");
header("Cache-Control: public, max-age=$expire");
header("Accept-Ranges: bytes");
header("Content-Length: " . (($end - $begin) + 1));
if (isset($_SERVER['HTTP_RANGE']))
{
header("Content-Range: bytes $begin-$end/$size");
}
header("Content-Disposition: inline; filename=$filename");
header("Content-Transfer-Encoding: binary");
header("Last-Modified: $time");
header("Expires: " . date('r', strtotime("+$expire seconds")));
$cur = $begin;
fseek($fm, $begin, 0);
while(!feof($fm) && $cur <= $end && (connection_status() == 0))
{
print fread($fm, min(1024 * 16, ($end - $cur) + 1));
$cur += 1024 * 16;
}
}
?>

View File

@ -1,28 +0,0 @@
<?php
function XFastDownload($location, $filename, $mimeType = 'application/octet-stream')
{
if(!isset($_SERVER["HTTP_RANGE"]))
{
$url = "https://www.google-analytics.com/collect";
$payload = "v=1&tid=UA-73200448-1&cid=" . session_id() . "&t=pageview&dh=" . $_SERVER['HTTP_HOST'] . "&dp=" . urlencode($_SERVER['REQUEST_URI']) . "&uip=" . $_SERVER['REMOTE_ADDR'] . "&ua=" . urlencode($_SERVER["HTTP_USER_AGENT"]) . "&dr=" . urlencode(isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : "");
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close ($ch);
}
$expire = 604800;
header("X-Accel-Redirect: $location");
header("Cache-Control: public, max-age=$expire");
header("Content-type: $mimeType");
header('Content-Disposition: inline; filename="' . $filename . '"');
}
?>

View File

@ -1,17 +0,0 @@
<?php
class FileUpload {
public $id;
public $hash160;
public $hash256;
public $mime;
public $path;
public $filename;
public $views;
public $created;
public $expire;
}
class FileUploadStats {
}
?>

View File

@ -1,18 +0,0 @@
<?php
require_once('sitemap-php/Sitemap.php');
require_once('db.php');
$sitemap = new Sitemap('https://example.com');
$sitemap->setPath('sitemap/');
$sitemap->addItem('/', '1.0');
$db = new DB();
$links = $db->GetFiles();
foreach($links as $f){
$url = '/' . $f->hash160 . '&v';
$sitemap->addItem($url, '0.8', 'daily');
}
$sitemap->createSitemapIndex('https://example.com/sitemap/', 'Today');
?>

26
index.html Normal file
View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
<title>void.cat</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="src/css/style.css" rel="stylesheet">
<script src="src/js/util.js"></script>
<script src="bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="src/modules/main.html">
</head>
<body>
<div class="page">
<div class="header">
void.cat
</div>
<div class="content">
<void-main></void-main>
</div>
</div>
</body>
</html>

138
index.php
View File

@ -1,138 +0,0 @@
<?php
session_start();
//check for view param otherwise return file
$hash = isset($_GET["hash"]) ? substr($_GET["hash"], strrpos($_GET["hash"], '/') + 1) : null;
if(!isset($_GET["v"]) && $hash != null)
{
include_once('db.php');
$db = new DB();
$f = $db->GetFile($hash);
if($f->id != 0){
include_once('download2.php');
XFastDownload(_UPLOADDIR . $f->hash160, $f->filename, $f->mime);
if(!isset($_SERVER['HTTP_RANGE'])){
$db->AddView($f->hash160);
}
}
exit;
}
?>
<!DOCTYPE html>
<html prefix="og: http://ogp.me/ns#">
<head>
<?php
$f = null;
if($hash != null){
include_once('db.php');
$db = new DB();
$f = $db->GetFile($hash);
}
$title = 'void.cat';
$maxsizeM = ini_get('post_max_size');
$maxsize = (int)(str_replace('M', '', $maxsizeM) * 1024 * 1024);
echo "<script>var max_upload_size = " . $maxsize . ";</script>";
?>
<title><?= $title . ($f != null ? ' - ' . $f->filename : '') ?></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="keywords" content="baba,file,host,upload,free">
<meta name="description" content="Free file host">
<?php
if($hash != null){
if($f->id != 0){
echo "<meta property=\"og:title\" content=\"" . $f->filename . "\" />";
echo "<meta property=\"og:site_name\" content=\"" . $title . "\" />";
$content_url = _SITEURL . $f->hash160;
if(strpos($f->mime, "image/") === 0) {
echo "<meta property=\"og:image:url\" content=\"" . $content_url . "\" />";
echo "<meta property=\"og:image:type\" content=\"" . $f->mime . "\" />";
}else if(strpos($f->mime, "audio/") === 0) {
echo "<meta property=\"og:audio\" content=\"" . $content_url . "\" />";
echo "<meta property=\"og:audio:type\" content=\"" . $f->mime . "\" />";
}else if(strpos($f->mime, "video/") === 0) {
echo "<meta property=\"og:video\" content=\"" . $content_url . "\" />";
echo "<meta property=\"og:video:type\" content=\"" . $f->mime . "\" />";
$ld = array(
"@context" => "http://schema.org",
"@type" => "VideoObject",
"name" => $f->filename,
"description" => $f->filename . " Video",
"thumbnailUrl" => $content_url . "&thumb",
"uploadDate" => $f->created,
"contentUrl" => $content_url . "&v",
"embedUrl" => $content_url,
"interactionCount" => $f->views
);
echo "<script type=\"application/ld+json\">" . json_encode($ld) . "</script>";
}
}
}
?>
<link rel="stylesheet" href="public/main.css" />
</head>
<body>
<div id="main">
<?php include_once('config.php'); ?>
<div id="header" onclick="window.location.href = '<?php echo _SITEURL; ?>';"><?= $title ?></div>
<?php
if($hash != null){
if($f->id != 0){
$db->AddView($f->hash160);
if(strpos($f->mime, "image/") === 0) {
require_once('views/image.php');
}else if(strpos($f->mime, "audio/") === 0) {
require_once('views/audio.php');
}else if(strpos($f->mime, "video/") === 0) {
require_once('views/video.php');
}else {
require_once('views/default.php');
}
require_once('views/stats.php');
}else{
echo "<h1>File Not Found :/</h1>";
}
}else{
echo "<div id=\"uploads\" style=\"display: none\"></div><div id=\"upload\">Drop Files < " . $maxsizeM . "</div>";
}
?>
<div id="history">
<h3>Your Uploads</h3>
<small>History is saved in <a style="display: initial; padding: initial; margin: initial;" href="https://www.w3schools.com/html/html5_webstorage.asp">localStorage</a> <b style="cursor: pointer; user-select: none;" onclick="localStorage.setItem('history', ''); window.location.reload();">(clear)</b></small>
</div>
<div id="footer">
<a href="https://github.com/v0l/void.cat">Github</a>
| <a href="https://twitter.com/chkn10deez">Twitter</a>
| <a href="http://discord.gg/8BkxTGs">Discord</a>
| Hosting: <?php echo explode("\t", exec("du -sh " . _FILEPATH))[0]; ?>
<br/><small>Files expire in <?php echo _FILE_EXPIRE_TIME; ?> days if not viewed</small>
<br/><img src="https://void.cat/graph"/>
</div>
</div>
<script src="public/main.js"></script>
<script>
var h = loadHistory();
var hl = document.querySelector('#history');
for(var x = h.length - 1; x >= 0; x--) {
var hx = h[x];
var nh = document.createElement('a');
nh.href = hx.link + '&v';
nh.target = '_blank'
nh.text = (hx.filename === null ? 'clipboard' : hx.filename);
hl.appendChild(nh);
}
</script>
</body>
</html>

22
polymer.json Normal file
View File

@ -0,0 +1,22 @@
{
"entrypoint": "index.html",
"fragments": [
"src/modules/main.html",
"src/modules/dropzone.html",
"src/modules/upload.html",
"src/modules/view.html"
],
"sources": [
"src/php/*.php",
"src/js/*.js",
"src/css/*.css"
],
"builds": [
{
"bundle": true,
"js": { "compile": true, "minify": true },
"css": { "minify": true },
"html": { "minify": true }
}
]
}

View File

@ -1,188 +0,0 @@
html, body {
margin: 0;
padding: 0;
font-family: Arial;
}
a { text-decoration: underline; color: inherit; }
a:link { text-decoration: underline; color: inherit; }
a:visited { text-decoration: underline; color: inherit; }
a:hover { text-decoration: underline; color: inherit; }
audio {
margin-top: 10px;
margin-bottom:10px;
}
video {
max-height: 500px;
width: 100%;
}
#main {
width: 700px;
border: 1px solid #555;
background-color: #4B898C;
margin-left: auto;
margin-right: auto;
margin-top: 20px;
border-radius: 3px;
box-shadow: 0px 0px 20px 2px #000;
overflow: hidden;
}
#main #header
{
text-align: center;
text-shadow: rgba(7, 255, 255, 0.78) 3px 0px 0px, rgba(255, 75, 75, 0.73) -3px 0px 0px;
color: #555555;
font-size: 50px;
padding: 10px;
border-bottom: 1px solid #aaa;
background-color: #E4E4E4;
}
#main #header:hover {
cursor: pointer;
}
#main .imglink
{
text-align: center;
display: block;
}
#main .imgview
{
max-width: 100%;
margin-top: 10px;
margin-bottom: 10px;
}
#uploads {
margin: 10px;
border: 2px solid #eee;
}
#uploads .uploadItem{
height: 50px;
line-height: 45px;
border-bottom: 1px solid #efefef;
}
#uploads .uploadItem .previewImage {
float: left;
height: 45px;
margin-right: 10px;
}
#uploads .uploadItem .uploadTitle {
float: left;
}
#uploads .uploadItem .uploadTitle small{
color: #bbb;
}
#uploads .uploadItem .progress {
height: 5px;
display: block;
background-color: #ccc;
float: left;
width: 100%;
}
#uploads .uploadItem .progress .progressCurrent {
width: 1px;
background-color: green;
height: 5px;
display: block;
}
#upload {
margin: 10px;
height: 350px;
border: 2px dashed #eee;
background-color: rgba(238, 238, 238, 0.18);
text-align: center;
line-height: 320px;
font-size: 40px;
color: rgba(238, 238, 238, 0.5);
}
#upload:hover {
cursor: pointer;
}
#footer {
text-align: center;
line-height: 38px;
}
#stats
{
width: 500px;
margin-left: auto;
margin-right: auto;
background-color: #565656;
color: #eee;
padding: 10px;
}
#download {
text-align: center;
padding: 20px;
margin: 10px;
background-color: #565656;
border: 1px solid #333;
border-radius: 5px;
font-size: 25px;
font-weight: bold;
}
#history {
margin: 10px;
padding: 10px;
border: 2px solid #eee;
background-color: rgba(238, 238, 238, 0.18);
}
#history a {
display: block;
margin: 5px;
}
/* MEDIA OVERWRITE QUERIES */
@media (max-width: 720px) {
#main {
width: auto;
box-shadow: none;
margin: 0;
}
}
@media (min-width: 1044px) {
#main {
width: 1024px;
}
#upload {
height: 500px;
line-height: 470px;
}
video {
max-height: 576px;
}
}
@media (min-width: 2048px) {
#main {
width: 1280px;
}
#upload {
height: 700px;
line-height: 670px;
}
video {
max-height: 720px;
}
}

View File

@ -1,308 +0,0 @@
function $(str) { if (str[0] === '.') { return document.getElementsByClassName(str.substring(1)); } else if (str[0] === '#') { return document.getElementById(str.substring(1)); } else { return document.getElementsByTagName(str.substring(1)); } }
function co(b){var a={r:1,g:1,b:1};.25>b?(a.r=0,a.g=4*b):.5>b?(a.r=0,a.b=1+4*(.25-b)):(.75>b?a.r=4*(b-.5):a.g=1+4*(.75-b),a.b=0);return a};
//http://stackoverflow.com/questions/18638900/javascript-crc32
var makeCRCTable = function(){
var c;
var crcTable = [];
for(var n =0; n < 256; n++){
c = n;
for(var k =0; k < 8; k++){
c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
}
crcTable[n] = c;
}
return crcTable;
}
var crc32 = function(str) {
var crcTable = window.crcTable || (window.crcTable = makeCRCTable());
var crc = 0 ^ (-1);
for (var i = 0; i < str.length; i++ ) {
crc = (crc >>> 8) ^ crcTable[(crc ^ str.charCodeAt(i)) & 0xFF];
}
return (crc ^ (-1)) >>> 0;
};
function setBG()
{
var x = Math.random();
var c = co(x);
document.documentElement.style.backgroundColor = 'rgb(' + parseInt(255*c.r, 10) + ',' + parseInt(255*c.g, 10) + ',' + parseInt(255*c.b, 10) + ')';
}
function addDropZoneFunctions()
{
var dz = document.getElementById('upload');
dz.addEventListener('dragover', handleDragOver, false);
dz.addEventListener('drop', handleFileSelect, false);
dz.addEventListener('click', handleDropClick, false);
}
function checkForFrag()
{
if($('#upload') !== null)
{
addDropZoneFunctions();
addPasteFunctions();
}
}
function addPasteFunctions()
{
document.addEventListener('paste', handleFilePaste, false);
}
function loadHistory(){
var hist = localStorage.getItem("history");
if(hist !== null && hist.length > 0) {
hist = JSON.parse(hist);
} else {
hist = [];
}
return hist;
}
function saveToHistory(r){
var hist = loadHistory();
hist[hist.length] = r;
localStorage.setItem("history", JSON.stringify(hist));
}
function uploadComplete(rsp, id, s)
{
var upl = $('#' + id);
var upl_p = $('#' + id + '_imagePreview');
//remove progress bar
var pb = $('#' + id + '_progress');
pb.parentElement.parentElement.removeChild(pb.parentElement);
//resize box
upl.style.height = '100px';
upl.style.lineHeight = '20px';
if(upl_p !== null)
{
upl_p.style.height = '100px';
upl_p.style.maxWidth = '100px';
}
//update links etc
if(rsp !== null)
{
switch(rsp.status)
{
case 0: {
//generic error
break;
}
case 1: {
//udupe
break;
}
case 2: {
//save failed
break;
}
case 200:{
//ok
//upl.innerText = upl.innerText + '<small>' + rsp.hash + '</small>';
var lk = window.location.host + ((window.location.port !== '80' || window.location.port !== '443') && window.location.port !== '' ? ':' + window.location.port : '') + window.location.pathname + (window.location.pathname.indexOf('/') >= 0 ? '' : '/') + rsp.publichash;
var upl_t = $('#' + id + '_title');
upl_t.innerHTML = upl_t.innerHTML
+ '<br/><small><b>Hash256:</b> ' + rsp.hash
+ '</small><br/><small><b>Hash160:</b> ' + rsp.publichash + '</small>'
+ '<br/><small><a target=\"_blank\" href=\"//' + lk + '&v\">(link)</a></small>';
//save to history
saveToHistory(rsp);
break;
}
}
}
}
function uploadProgress(evt, id)
{
switch(evt.type){
case 'readystatechange':{
if(evt.target.readyState == 4)
{
uploadComplete(JSON.parse(evt.target.response), id, 0);
}
break;
}
case 'progress':{
var p = parseFloat(evt.loaded) / parseFloat(evt.total);
var pb = $('#' + id + '_progress');
pb.style.width = (pb.parentElement.offsetWidth * p) + 'px';
break;
}
case 'error':{
break;
}
}
}
function changeUI()
{
if($('#uploads').style.display === 'none')
{
//minimize dz
$('#upload').style.lineHeight = "150px";
$('#upload').style.height = "167px";
$('#uploads').style.minHeight = "167px";
$('#uploads').style.display = "block";
}
}
/*
* Accepts File/Blob type ONLY
*/
function uploadFile(f, id)
{
if(typeof f === "string"){
var fx = new File([], 'remote');
fx.type = "text/plain";
fx.size = 0;
fx.url = f;
f = fx;
}
if(f instanceof Blob || f instanceof File)
{
if($('#' + id) === null){
var nf = document.createElement('div');
nf.id = id;
nf.className = "uploadItem";
//check is image type, add preview pane
if(f.type.indexOf('image') >= 0)
{
var pid = id + '_imagePreview';
var pi = document.createElement('img');
pi.id = pid;
pi.className = "previewImage";
nf.appendChild(pi);
var fr = new FileReader();
fr.onload = function (res) {
$('#' + pid).src = res.target.result;
};
fr.readAsDataURL(f);
}
//title
var nf_t = document.createElement('div');
nf_t.id = id + '_title';
nf_t.className = 'uploadTitle';
nf_t.innerHTML = f.name;
nf.appendChild(nf_t);
//progress bar
var nfp = document.createElement('span');
nfp.className = "progress";
nf.appendChild(nfp);
//progress bar inner
var nfp_c = document.createElement('span');
nfp_c.id = id + '_progress';
nfp_c.className = "progressCurrent";
nfp.appendChild(nfp_c);
$('#uploads').appendChild(nf);
changeUI();
if(f.size > max_upload_size)
{
uploadComplete(null, id, 1);
}
else
{
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', function(evt) { uploadProgress(evt, id); });
xhr.upload.addEventListener('load', function(evt) { uploadProgress(evt, id); });
xhr.upload.addEventListener('error', function(evt) { uploadProgress(evt, id); });
xhr.upload.addEventListener('abort', function(evt) { uploadProgress(evt, id); });
xhr.addEventListener('readystatechange', function(evt) { uploadProgress(evt, id); });
xhr.open("POST", "upload.php?filename=" + f.name + (f.url !== undefined ? "&remote=" + encodeURIComponent(f.url) : ""));
xhr.send(f);
}
}
}
}
function handleDropClick(evt){
var i = document.createElement('input');
i.setAttribute('type', 'file');
i.addEventListener('change', function(evt){
var fl = evt.path[0].files;
for(var i = 0; i < fl.length; i++)
{
var file = fl[i];
var fid = crc32(file.name);
uploadFile(file, fid);
}
});
i.click();
}
function handleDragOver(evt)
{
evt.stopPropagation();
evt.preventDefault();
evt.dataTransfer.dropEffect = 'copy';
}
function handleFileSelect(evt)
{
evt.stopPropagation();
evt.preventDefault();
var files = evt.dataTransfer.files;
console.log(files);
for(var i = 0; i < files.length; i++){
var file = files[i];
var fid = crc32(file.name);
if(file.type === ''){
file.type = 'application/octet-stream';
}
uploadFile(file, fid);
}
}
function handleFilePaste(evt)
{
for(var i = 0; i < evt.clipboardData.items.length; i++)
{
var fid = crc32('' + new Date().getTime());
var file = evt.clipboardData.items[i];
if(file.kind === 'file')
{
var file_t = file.getAsFile();
file_t.name = "clipboard.png";
uploadFile(file_t, fid);
}else if(file.kind === 'string' && file.type === 'text/plain'){
var file_t = file.getAsString(function(url){
if(url.indexOf('http://') === 0 || url.indexOf('https://') === 0) {
uploadFile(url);
}
});
}
}
}
setBG();
checkForFrag();

View File

@ -1,3 +0,0 @@
User-agent: *
Disallow: /m/
Disallow: /mobile/

41
src/css/style.css Normal file
View File

@ -0,0 +1,41 @@
html, body {
background-color: #dbedf5;
font-family: 'Roboto', sans-serif;
font-size: 12px;
padding: 0;
margin: 0;
}
.page {
width:1024px;
margin-left:auto;
margin-right:auto;
margin-top:20px;
background-color: #a5d4ea;
border-radius: 5px;
border: 1px solid #aaa;
}
.content {
padding:20px;
}
.header{
text-align: center;
color: #555555;
font-size: 50px;
padding: 10px;
border-bottom: 1px solid #aaa;
background-color: #E4E4E4;
border-radius: 5px 5px 0px 0px;
}
@media(max-width: 1024px){
.page {
width: auto;
margin: 10px 0 0 0;
}
.content {
padding: 5px;
}
}

13
src/db.sql Normal file
View File

@ -0,0 +1,13 @@
CREATE TABLE `files` (
`hash160` varchar(40) NOT NULL,
`hash256` varchar(64) NOT NULL,
`filename` varchar(255) NOT NULL,
`mime` varchar(64) NOT NULL,
`size` int(11) NOT NULL,
`path` varchar(512) NOT NULL,
`views` int(11) DEFAULT 0 NULL,
`isAdminFile` bit(1) DEFAULT 0 NULL,
`uploaded` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`lastview` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`hash160`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

86
src/js/util.js Normal file
View File

@ -0,0 +1,86 @@
const API = {
xhr: function (method, url, data, cb) {
let x = new XMLHttpRequest();
x.onreadystatechange = function () {
if (x.readyState === 4 && cb !== undefined && cb !== null && typeof cb === 'function') {
cb(this);
}
}
x.open(method, url, true);
if (data !== null) {
x.setRequestHeader('Content-Type', 'application/json');
x.send(JSON.stringify(data));
} else {
x.send();
}
},
sendAPICommand: function (data, cb) {
API.xhr('POST', '/src/php/api.php', data, function (xhr) {
if(xhr.status == 200) {
cb(JSON.parse(xhr.response));
}
});
},
getServerConfig: function (cb) {
API.sendAPICommand({ cmd: 'config' }, function (data) {
cb(data);
});
},
getFileInfo: function(hash, cb) {
API.sendAPICommand({ cmd: 'file', hash: hash }, function (data) {
cb(data);
});
}
};
const Util = {
formatBytes: function (b, f) {
f = f === undefined ? 2 : f;
if (b >= 1073741824) {
return (b / 1073741824.0).toFixed(f) + ' GiB';
} else if (b >= 1048576) {
return (b / 1048576.0).toFixed(f) + ' MiB';
} else if (b >= 1024) {
return (b / 1024.0).toFixed(f) + ' KiB';
}
return b.toFixed(f | 2) + ' B'
}
};
const doCaptcha = function(view){
API.sendAPICommand({ cmd: 'captcha_config' }, function(data){
this.view.captchaKey = data.cap_key;
this.view.captchaDL = data.cap_dl;
window['capLoad'] = function(){
window["capCb"] = function(rsp){
API.sendAPICommand({ cmd: 'captcha_verify', hash: this.view.fileInfo.hash160, token: rsp }, function(data){
if(window.location.search.indexOf('?dl') === 0){
window.location = window.location.href.replace('?dl#', '');
}else{
window.location.reload();
}
}.bind({ view: this.view }));
}.bind({ view: this.view });
grecaptcha.render(document.querySelector('#g-recaptcha'),
{
sitekey: this.view.captchaKey,
callback: 'capCb'
}
);
}.bind({ view: this.view });
let cb = document.createElement('div');
cb.id = 'g-recaptcha';
let par = document.querySelector('.content');
par.insertBefore(cb, par.firstChild);
let ct = document.createElement('script');
ct.src = 'https://www.google.com/recaptcha/api.js?onload=capLoad&render=explicit';
document.head.appendChild(ct);
}.bind({ view: view }));
};

157
src/modules/dropzone.html Normal file
View File

@ -0,0 +1,157 @@
<link rel="import" href="/bower_components/polymer/polymer-element.html">
<dom-module id="void-drop-zone">
<template>
<style>
.drop-zone {
height: 400px;
border: 2px dashed #aaa;
line-height: 400px;
text-align: center;
font-size: 50px;
}
.drop-zone:hover {
cursor: pointer;
}
.note {
font-size: 12px;
text-align: center;
}
.uploads {
margin-top: 10px;
}
.stats {
background-color: #0071a7;
color: #eee;
margin-left: auto;
margin-right: auto;
line-height: 25px;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
border-left: 1px solid #777;
border-bottom: 1px solid #777;
border-right: 1px solid #777;
text-align: center;
overflow: hidden;
}
.stats div {
width: 33.333%;
float: left;
}
.stats b {
overflow: hidden;
}
@media(max-width: 1024px) {
.drop-zone {
font-size: 30px;
height: 200px;
line-height: 200px;
}
}
</style>
<div class="drop-zone">
Max size [[formatBytes(maxSize, 0)]]
</div>
<div class="stats">
<div><b>Files:</b> [[stats.files]]</div>
<div><b>Total Size:</b> [[formatBytes(stats.size, 1)]]</div>
<div><b>Avg Size:</b> [[formatBytes(stats.avgSize, 1)]]</div>
</div>
<template is="dom-if" if="[[expire]]">
<br/><i class="note">**Expires after [[expire]] days since last view</i>
</template>
<div class="uploads">
</div>
</template>
</dom-module>
<script>
class VoidDropZone extends Polymer.Element {
static get is() { return "void-drop-zone"; }
constructor() {
super();
this.formatBytes = Util.formatBytes;
}
ready() {
super.ready();
this.uploads = this.root.querySelector('.uploads');
API.getServerConfig(function(cfg){
this.self.maxSize = cfg.maxsize;
this.self.expire = cfg.expire;
this.self.stats = cfg.stats;
}.bind({ self: this }));
this.dz = this.root.querySelector('.drop-zone');
this.dz.addEventListener('dragover', this.handleDragOver.bind({ self: this }), false);
this.dz.addEventListener('drop', this.handleFileDropped.bind({ self: this }), false);
this.dz.addEventListener('click', this.handleFileSelect.bind({ self: this }), false);
document.addEventListener('paste', this.handleFilePaste.bind({ self: this }), false);
}
addFileUpload(file) {
var nf = new VoidUpload(this, file);
this.uploads.appendChild(nf);
if (this.dz.style.height.length === 0) {
this.dz.style.height = this.dz.style.lineHeight = this.dz.offsetHeight / 2 + 'px';
}
}
handleFileSelect(evt) {
var i = document.createElement('input');
i.setAttribute('type', 'file');
i.addEventListener('change', function (evt) {
var fl = evt.target.files;
for (let i = 0; i < fl.length; i++) {
let file = fl[i];
this.self.addFileUpload(file);
}
}.bind({ self: this.self }));
i.click();
}
handleDragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.dataTransfer.dropEffect = 'copy';
}
handleFileDropped(evt) {
evt.stopPropagation();
evt.preventDefault();
let files = evt.dataTransfer.files;
for (let i = 0; i < files.length; i++) {
this.self.addFileUpload(files[i]);
}
}
handleFilePaste(evt) {
for (var i = 0; i < evt.clipboardData.items.length; i++) {
var file = evt.clipboardData.items[i];
if (file.kind === 'file') {
this.self.addFileUpload(file.getAsFile());
} else if (file.kind === 'string' && file.type === 'text/plain') {
var file_t = file.getAsString(function (url) {
if (url.indexOf('http://') === 0 || url.indexOf('https://') === 0) {
this.self.addFileUpload(file);
}
});
}
}
}
}
customElements.define(VoidDropZone.is, VoidDropZone)
</script>

54
src/modules/main.html Normal file
View File

@ -0,0 +1,54 @@
<link rel="import" href="/bower_components/polymer/polymer-element.html">
<link rel="import" href="/src/modules/dropzone.html">
<link rel="import" href="/src/modules/upload.html">
<link rel="import" href="/src/modules/view.html">
<dom-module id="void-main">
<template>
<style>
.footer {
text-align:center;
margin-top: 20px;
}
@media(max-width: 470px) {
img {
width: 100%;
}
}
</style>
<template is="dom-if" if="{{view}}">
<void-view hash="{{hash}}"></void-view>
</template>
<template is="dom-if" if="{{!view}}">
<void-drop-zone></void-drop-zone>
</template>
<div class="footer">
<img src="/graph"/>
</div>
</template>
</dom-module>
<script>
class VoidMain extends Polymer.Element {
static get is() { return "void-main"; }
constructor() {
super();
}
ready() {
super.ready();
this.hash = window.location.hash;
if(this.hash.length === 41){
this.view = true;
}else{
this.view = false;
}
}
}
customElements.define(VoidMain.is, VoidMain)
</script>

249
src/modules/upload.html Normal file
View File

@ -0,0 +1,249 @@
<link rel="import" href="/bower_components/polymer/polymer-element.html">
<dom-module id="void-upload">
<template>
<style>
.upload {
margin-bottom: 2px;
}
.upload-header {
overflow: hidden;
height: 40px;
line-height: 20px;
background-color: #94aeec;
color: #000;
}
.upload-header-content {
padding: 10px;
float: left;
}
.upload-header-content-filename {
float: left;
height: 20px;
width: 120px;
text-overflow: ellipsis;
overflow:hidden;
}
.upload-content {
background-color: #638aa0;
}
.upload-header-tag {
float: right;
background-color: #6d6d6d;
padding: 10px;
width: 80px;
text-align: center;
font-size: 12px;
color: #eee;
}
.abort-tag {
background-color: #ff4d4d;
width: auto;
min-width: 25px;
}
.cap {
text-transform: uppercase;
font-weight: bold;
}
.cap:hover {
cursor: pointer;
}
.upload-progress-bar {
background-color: #35b300;
height: 10px;
border-right: 1px solid #3F51B5;
}
@keyframes uploadAnimated {
0% {
background-color: #6c8bff;
}
50% {
background-color: #95acff;
}
100% {
background-color: #6c8bff;
}
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px;
letter-spacing: normal;
text-transform: none;
display: block;
float: left;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased;
}
</style>
<div class="upload">
<div class="upload-header">
<div class="upload-header-content">
<i class="material-icons" style="margin-right: 10px">file_upload</i>
<div class="upload-header-content-filename">{{file.name}}</div>
</div>
<template is="dom-if" if="{{!complete}}">
<div class="upload-header-tag abort-tag">
<i class="material-icons" on-click="abortUpload">cancel</i>
</div>
<div class="upload-header-tag">
{{formatBytes(transferRate)}}/s
</div>
</template>
<template is="dom-if" if="{{complete}}">
<template is="dom-if" if="{{!error}}">
<div class="upload-header-tag" style="border-left: 1px solid #888;">
<div class="cap" on-click="openLink">link</div>
</div>
<div class="upload-header-tag">
<div class="cap" on-click="openViewLink">view</div>
</div>
</template>
<template is="dom-if" if="{{error}}">
<div class="upload-header-tag abort-tag"><i class="material-icons" style="margin-right: 10px">error_outline</i> {{response.msg}}</div>
</template>
</template>
</div>
<div class="upload-content">
<template is="dom-if" if="{{!complete}}">
<div class="upload-progress-bar" style="width: calc(100 * {{progress}}%)"></div>
</template>
</div>
</div>
</template>
</dom-module>
<script>
class VoidUpload extends Polymer.Element {
static get is() { return "void-upload"; }
static get properties() {
return {
file: Object
};
}
truncatedName() {
return this.file !== undefined ? this.file.name.substring(0, 10) : '';
}
abortUpload() {
if (this.xhr) {
this.xhr.abort();
this.response = { msg: "Aborted by user" };
}
}
openLink() {
if (this.response !== undefined && this.response !== null && this.response.link !== undefined && this.response.link !== null && this.response.link.length > 0) {
window.open(this.response.link, '_blank');
}
}
openViewLink() {
if (this.response !== undefined && this.response !== null && this.response.link !== undefined && this.response.link !== null && this.response.link.length > 0) {
window.open(this.response.link.replace(this.response.publichash, '#' + this.response.publichash), '_blank');
}
}
uploadBlob() {
if (!this.xhr) {
this.xhr = new XMLHttpRequest();
this.xhr.upload.addEventListener('progress', this.uploadProgress.bind({ self: this }));
this.xhr.upload.addEventListener('load', this.uploadProgress.bind({ self: this }));
this.xhr.upload.addEventListener('error', this.uploadProgress.bind({ self: this }));
this.xhr.upload.addEventListener('abort', this.uploadProgress.bind({ self: this }));
this.xhr.addEventListener('readystatechange', this.uploadProgress.bind({ self: this }));
this.xhr.open("POST", "/src/php/upload.php?filename=" + this.file.name + (this.file.url ? "&remote=" + encodeURIComponent(this.file.url) : ""));
this.xhr.send(this.file);
}
}
uploadProgress(evt) {
switch (evt.type) {
case 'readystatechange': {
if (evt.target.readyState == 4) {
this.self.complete = true;
if (evt.target.status == 200) {
this.self.response = JSON.parse(evt.target.response);
if (this.self.response.status !== 200) {
this.self.error = true;
}
this.self.notifyPath('error');
} else {
this.self.error = true;
}
}
break;
}
case 'progress': {
this.self.progress = parseFloat(evt.loaded) / parseFloat(evt.total);
let txnow = Date.now()
let txdif = evt.loaded - this.self.lastProgressLoaded;
let txt = txnow - this.self.lastProgress;
let txrate = txdif / (txt / 1000.0);
this.self.transferRate = txrate;
this.self.lastProgressLoaded = evt.loaded;
this.self.lastProgress = txnow;
break;
}
case 'error': {
this.self.error = true;
this.self.complete = true;
break;
}
}
}
constructor(dz, file) {
super();
this.dropZone = dz;
this.formatBytes = Util.formatBytes;
this.file = file;
this.progress = 0;
this.lastProgressLoaded = 0;
this.lastProgress = Date.now();
this.transferRate = 0;
this.response = {}
this.complete = false;
this.error = false;
if (file.size > this.dropZone.maxSize) {
this.complete = true;
this.error = true;
this.response = { msg: "File too big" };
}
}
ready() {
super.ready()
if (!this.error) {
this.uploadBlob();
}
}
}
customElements.define(VoidUpload.is, VoidUpload);
</script>

126
src/modules/view.html Normal file
View File

@ -0,0 +1,126 @@
<link rel="import" href="/bower_components/polymer/polymer-element.html">
<dom-module id="void-view">
<template>
<style>
img {
max-width: 100%;
display: block;
margin-left: auto;
margin-right: auto;
}
.file-info {
margin-top: 10px;
background-color: #1fa4ab;
line-height: 30px;
width: 300px;
margin-left: auto;
margin-right: auto;
border-radius: 3px;
padding: 5px 10px 5px 10px;
overflow: hidden;
}
.file-info-views {
float: left;
}
.file-info-size {
float: right;
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 25px;
float:left;
margin-right: 5px;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale;
font-feature-settings: 'liga';
}
audio, video {
width: 100%;
}
.captcha { text-align: center; }
</style>
<template is="dom-if" if="[[isCaptcha]]">
<div class="captcha">
<h3>Oh no :( you downloaded this file [[captchaDL]] times, please verify you are human</h3>
</div>
</template>
<template is="dom-if" if="[[isImage]]">
<img src="[[fileInfo.url]]"/>
</template>
<template is="dom-if" if="[[isVideo]]">
<video controls>
<source src="[[fileInfo.url]]" type="[[fileInfo.mime]]">
</video>
</template>
<template is="dom-if" if="[[isSound]]">
<audio controls>
<source src="[[fileInfo.url]]" type="[[fileInfo.mime]]">
</audio>
</template>
<template is="dom-if" if="[[isDefault]]">
<a href="[[fileInfo.url]]">Download [[fileInfo.filename]]</a>
</template>
<template is="dom-if" if="[[!isCaptcha]]">
<div class="file-info">
<div class="file-info-views">
<div class="material-icons">cloud_download</div>Downloads: [[fileInfo.views]]
</div>
<div class="file-info-size">Size: [[formatBytes(fileInfo.size)]]</div>
</div>
</template>
</template>
</dom-module>
<script>
class VoidView extends Polymer.Element {
static get is() { return "void-view"; }
get properties() {
return {
"hash": String
}
}
constructor() {
super();
this.formatBytes = Util.formatBytes;
}
ready() {
super.ready();
if(location.search.indexOf('?captcha') === 0){
doCaptcha(this);
this.isCaptcha = true;
} else {
API.getFileInfo(this.hash.substring(1), function(data) {
this.self.fileInfo = data.file;
if(data.captcha) {
doCaptcha(this.self);
this.self.isCaptcha = true;
}else{
this.self.isCaptcha = false;
this.self.isImage = (this.self.fileInfo.mime.match(/^image\/(png|jpg|jpeg|gif|bmp)$/gi) !== null);
this.self.isVideo = (this.self.fileInfo.mime.match(/^video\/(mp4|mkv|avi|m4v)$/gi) !== null);
this.self.isSound = (this.self.fileInfo.mime.match(/^audio\/(mp3|ogg|flac|wav|alac)$/gi) !== null);
this.self.isDefault = !this.self.isImage && !this.self.isVideo && !this.self.isSound;
}
}.bind({ self: this }));
}
}
}
customElements.define(VoidView.is, VoidView)
</script>

95
src/php/api.php Normal file
View File

@ -0,0 +1,95 @@
<?php
session_start();
require_once('config.php');
$body = file_get_contents('php://input');
$c = json_decode($body);
$rsp = array(
"input" => $c
);
switch($c->cmd){
case "config":
{
require_once("db.php");
$db = new DB();
$rsp["stats"] = $db->GetStats();
$maxsizeM = ini_get('post_max_size');
$maxsize = (int)(str_replace('M', '', $maxsizeM) * 1000 * 1000);
$rsp["maxsize"] = $maxsize;
$rsp["expire"] = _FILE_EXPIRE_TIME;
break;
}
case "file":
{
require_once("db.php");
$db = new DB();
$fi = $db->GetFile($c->hash);
if($fi->hash160 != NULL)
{
unset($fi->path); //block internal path value
$fi->url = _SITEURL . $fi->hash160;
$rsp["file"] = $fi;
$hashKey = $_SERVER['REMOTE_ADDR'] . ':' . $fi->hash160;
$redis = new Redis();
$redis->connect(_REDIS_SERVER);
$dlCounter = $redis->get($hashKey);
if($dlCounter != False && $dlCounter >= _DL_CAPTCHA) {
$rsp["captcha"] = True;
}
$redis->close();
}
break;
}
case "captcha_config":
{
$rsp["cap_key"] = _CAPTCHA_KEY;
$rsp["cap_dl"] = _DL_CAPTCHA;
break;
}
case "captcha_verify":
{
$redis = new Redis();
$redis->connect(_REDIS_SERVER);
$hashKey = $_SERVER['REMOTE_ADDR'] . ':' . $c->hash;
$dlCounter = $redis->get($hashKey);
if($dlCounter != FALSE) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://www.google.com/recaptcha/api/siteverify');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'secret=' . _CAPTCHA_SECRET . '&response=' . $c->token . '&remoteip=' . $_SERVER['REMOTE_ADDR']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$crsp = json_decode(curl_exec($ch));
curl_close ($ch);
if($crsp->success == True){
$dlCounter = 0;
$redis->setEx($hashKey, _CAPTCHA_DL_EXPIRE, 0);
$rsp["ok"] = True;
}else{
$rsp["ok"] = False;
}
}else{
$rsp["ok"] = True;
}
$redis->close();
break;
}
}
header('Content-Type: application/json');
echo json_encode($rsp);
?>

25
src/php/config.php.sample Normal file
View File

@ -0,0 +1,25 @@
<?php
/* DB SETTINGS */
define('_DB_HOST', '127.0.0.1');
define('_DB_DATABASE', 'void');
define('_DB_USER', 'root');
define('_DB_PASS', 'mysql');
/* REDIS CONFIG */
define('_REDIS_SERVER', '127.0.0.1');
/* GENERAL SETTINGS */
define('_DEFAULT_TYPE', 'application/octet-stream');
define('_SITEURL', 'https://void.cat/');
define('_UPLOADDIR', '/files/');
define('_FILEPATH', '/var/www/void.cat' . _UPLOADDIR);
define('_DISCORD_WEBHOOK', 'DISCORD_HOOK_URL');
define('_FILE_EXPIRE_TIME', 30);
define('_GA_CODE', 'UA-73200448-1');
/* CAPTCHA SETTINGS */
define('_DL_CAPTCHA', 10);
define('_CAPTCHA_DL_EXPIRE', 86400);
define('_CAPTCHA_KEY', 'CAP_KEY');
define('_CAPTCHA_SECRET', 'CAP_SECRET');
?>

View File

@ -19,4 +19,4 @@
$discord_data = array("content" => 'Deleted ' . count($fl) . ' expired files.');
include('discord.php');
}
?>
?>

View File

@ -9,7 +9,7 @@
$this->mysqli = new mysqli(_DB_HOST, _DB_USER, _DB_PASS, _DB_DATABASE);
if ($this->mysqli->connect_errno) {
$this->error = "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
$this->error = "Failed to connect to MySQL: (" . $this->mysqli->connect_errno . ") " . $this->mysqli->connect_error;
}
}
@ -23,14 +23,18 @@
function Exists256($hash)
{
$res = new FileUpload();
return $this->GetFile($hash, "hash256");
}
function GetStats()
{
$res = new FileStats();
$stmt = $this->mysqli->prepare("select id, hash160, hash256, mime, path, filename, views, created, expire from files where hash256 = ? limit 1");
$stmt = $this->mysqli->prepare("select count(hash160), sum(size), avg(size) from files");
if($stmt)
{
$stmt->bind_param("s", $hash);
$stmt->execute();
$stmt->bind_result($res->id, $res->hash160, $res->hash256, $res->mime, $res->path, $res->filename, $res->views, $res->created, $res->expire);
$stmt->bind_result($res->files, $res->size, $res->avgSize);
$stmt->fetch();
$stmt->close();
}
@ -38,16 +42,16 @@
return $res;
}
function GetFile($hash)
function GetFile($hash, $hc = "hash160")
{
$res = new FileUpload();
$stmt = $this->mysqli->prepare("select id, hash160, hash256, mime, path, filename, views, created, expire from files where hash160 = ? limit 1");
$stmt = $this->mysqli->prepare("select hash160, hash256, filename, mime, size, path, views, isAdminFile, uploaded, lastview from files where " . $hc . " = ? limit 1");
if($stmt)
{
$stmt->bind_param("s", $hash);
$stmt->execute();
$stmt->bind_result($res->id, $res->hash160, $res->hash256, $res->mime, $res->path, $res->filename, $res->views, $res->created, $res->expire);
$stmt->bind_result($res->hash160, $res->hash256, $res->filename, $res->mime, $res->size, $res->path, $res->views, $res->isAdminFile, $res->uploaded, $res->lastview);
$stmt->fetch();
$stmt->close();
}
@ -59,22 +63,23 @@
{
$res = array();
$stmt = $this->mysqli->prepare("select id, hash160, hash256, mime, path, filename, views, created, expire from files");
$stmt = $this->mysqli->prepare("select hash160, hash256, filename, mime, size, path, views, isAdminFile, uploaded, lastview from files");
if($stmt)
{
$stmt->execute();
$stmt->bind_result($id, $hash160, $hash256, $mime, $path, $filename, $views, $created, $expire);
$stmt->bind_result($hash160, $hash256, $filename, $mime, $size, $path, $views, $isAdminFile, $uploaded, $lastview);
while($stmt->fetch()){
$nf = new FileUpload();
$nf->id = $id;
$nf->hash160 = $hash160;
$nf->hash256 = $hash256;
$nf->mime = $mime;
$nf->path = $path;
$nf->filename = $filename;
$nf->mime = $mime;
$nf->size = $size;
$nf->path = $path;
$nf->views = $views;
$nf->created = $created;
$nf->expire = $expire;
$nf->isAdminFile = $isAdminFile;
$nf->uploaded = uploaded;
$nf->lastview = $lastview;
array_push($res, $nf);
}
@ -86,27 +91,29 @@
function InsertFile($f)
{
$stmt = $this->mysqli->prepare("insert into files(hash160, hash256, mime, path, filename, expire) values(?,?,?,?,?, DATE_ADD(NOW(), INTERVAL " . _FILE_EXPIRE_TIME . " DAY))");
$stmt = $this->mysqli->prepare("insert into files(hash160, hash256, filename, mime, size, path) values(?,?,?,?,?,?)");
if($stmt)
{
$stmt->bind_param("sssss", $f->hash160, $f->hash256, $f->mime, $f->path, $f->filename);
$stmt->bind_param("ssssss", $f->hash160, $f->hash256, $f->filename, $f->mime, $f->size, $f->path);
$stmt->execute();
$stmt->close();
}
}
function DeleteFile($f)
{
$stmt = $this->mysqli->prepare("delete from files where id = ?");
$stmt = $this->mysqli->prepare("delete from files where hash160 = ?");
if($stmt)
{
$stmt->bind_param("d", $f->id);
$stmt->bind_param("s", $f->id);
$stmt->execute();
$stmt->close();
}
}
function AddView($hash160)
{
$stmt = $this->mysqli->prepare("update files set views = views + 1, expire = DATE_ADD(NOW(), INTERVAL " . _FILE_EXPIRE_TIME . " DAY) where hash160 = ?");
$stmt = $this->mysqli->prepare("update files set views = views + 1, lastview = NOW() where hash160 = ?");
if($stmt)
{
$stmt->bind_param("s", $hash160);
@ -114,11 +121,12 @@
$stmt->close();
}
}
function GetExpiredFiles()
{
$res = array();
$stmt = $this->mysqli->prepare("select id, hash160, hash256, mime, path, filename, views, created, expire from files where expire < CURRENT_TIMESTAMP");
$stmt = $this->mysqli->prepare("select hash160 from files where date_add(lastview, INTERVAL " . _FILE_EXPIRE_TIME . " DAY) >= CURRENT_TIMESTAMP");
if($stmt)
{
$stmt->execute();
@ -143,4 +151,4 @@
return $res;
}
};
?>
?>

View File

@ -7,4 +7,4 @@
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_exec($curl);
}
?>
?>

77
src/php/download.php Normal file
View File

@ -0,0 +1,77 @@
<?php
session_start();
include_once('config.php');
function XFastDownload($location, $filename, $mimeType = 'application/octet-stream')
{
global $validRequest;
if($validRequest)
{
$url = "https://www.google-analytics.com/collect";
$payload = "v=1&tid=" . _GA_CODE . "&cid=" . session_id() . "&t=pageview&dh=" . $_SERVER['HTTP_HOST'] . "&dp=" . urlencode($_SERVER['REQUEST_URI']) . "&uip=" . $_SERVER['REMOTE_ADDR'] . "&ua=" . urlencode($_SERVER["HTTP_USER_AGENT"]) . "&dr=" . urlencode(isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : "");
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close ($ch);
}
$expire = 604800;
header("X-Accel-Redirect: $location");
header("Cache-Control: public, max-age=$expire");
header("Content-type: $mimeType");
header('Content-Disposition: inline; filename="' . $filename . '"');
}
$hash = substr($_SERVER["REQUEST_URI"], 1);
$hashKey = $_SERVER['REMOTE_ADDR'] . ':' . $hash;
$range_start = 0;
$range_end = 999;
if(isset($_SERVER['HTTP_RANGE'])){
$rby = explode('=', $_SERVER['HTTP_RANGE']);
$rbv = explode('-', $rby[1]);
if($rbv[0] != ''){
$range_start = $rbv[0];
}
if($rbv[1] != ''){
$range_end = $rbv[1];
}
}
$validRequest = ($range_start == 0);
$redis = new Redis();
$redis->connect(_REDIS_SERVER);
$dlCounter = $redis->get($hashKey);
if($dlCounter != FALSE) {
if($dlCounter >= _DL_CAPTCHA){
//redirect for captcha check
$redis->close();
header('location: ' . _SITEURL . '?dl#' . $hash);
exit();
}
}else{
$redis->setEx($hashKey, _CAPTCHA_DL_EXPIRE, 0);
}
include_once('db.php');
$db = new DB();
$f = $db->GetFile($hash);
if($f->hash160 != NULL){
XFastDownload(_UPLOADDIR . $f->hash160, $f->filename, $f->mime);
if($validRequest){
$db->AddView($f->hash160);
$redis->incr($hashKey);
}
}
$redis->close();
?>

20
src/php/file.php Normal file
View File

@ -0,0 +1,20 @@
<?php
class FileUpload {
public $hash160;
public $hash256;
public $filename;
public $mime;
public $size;
public $path;
public $views;
public $isAdminFile;
public $uploaded;
public $lastview;
}
class FileStats {
public $files;
public $size;
public $avgSize;
}
?>

View File

@ -1,6 +1,6 @@
<?php
include('db.php');
require_once('db.php');
$response = array(
"status" => 0,
"msg" => null,
@ -20,7 +20,7 @@
if($fsize > $maxsize)
{
$response["msg"] = "File size larger than " . $maxsizeM;
$response["msg"] = "File too big";
}
else
{
@ -71,10 +71,12 @@
//check for dupes
$f_e = $db->Exists256($fh);
if($f_e->id != 0)
if($f_e->hash160 != NULL)
{
//file already exists
$response["status"] = 200;
$response["publichash"] = $f_e->hash160;
$response["link"] = _SITEURL . $f_e->hash160;
$response["mime"] = $f_e->mime;
}
else
@ -85,37 +87,40 @@
hash_update($phc, $fh);
$ph = hash_final($phc);
$response["publichash"] = $ph;
//save to disk
$op = _FILEPATH . $ph;
$fo = fopen($op, 'wb+');
stream_copy_to_stream($tmpf, $fo);
fclose($fo);
//save to db
$f_e = new FileUpload();
$f_e->hash160 = $ph;
$f_e->hash256 = $fh;
$f_e->mime = $mime;
$f_e->path = $op;
$f_e->filename = $fname;
$db->InsertFile($f_e);
$discord_data = array("content" => _SITEURL . $f_e->hash160 . '&v');
include("discord.php");
if($fo !== False){
stream_copy_to_stream($tmpf, $fo);
fclose($fo);
//save to db
$f_e = new FileUpload();
$f_e->hash160 = $ph;
$f_e->hash256 = $fh;
$f_e->mime = $mime;
$f_e->size = filesize($op);
$f_e->path = $op;
$f_e->filename = $fname;
$db->InsertFile($f_e);
$discord_data = array("content" => _SITEURL . $f_e->hash160 . '&v');
include_once("discord.php");
$response["status"] = 200;
$response["link"] = _SITEURL . $f_e->hash160;
$response["mime"] = $mime;
}else{
$response["status"] = 500;
$response["msg"] = "Server error!";
}
}
//close streams
fclose($rawf);
fclose($tmpf);
$response["status"] = 200;
$response["link"] = _SITEURL . $f_e->hash160;
$response["mime"] = $mime;
}
//return response
header('Content-Type: application/json');
echo json_encode($response);
?>
?>

View File

@ -1,6 +0,0 @@
<?php
$audio_url = _SITEURL . $f->hash160;
?>
<audio controls style="width: 100%">
<source src="<?php echo $audio_url; ?>" type="<?php echo $f->mime; ?>">
</audio>

View File

@ -1,6 +0,0 @@
<?php
$u = _SITEURL . $f->hash160;
?>
<div id="download">
<a href="<?php echo $u; ?>">Download <?php echo $f->filename; ?></a>
</div>

View File

@ -1,4 +0,0 @@
<?php
$img_url = _SITEURL . $f->hash160;
?>
<a href="<?php echo $img_url; ?>" class="imglink"><img class="imgview" src="<?php echo $img_url; ?>"/></a>

View File

@ -1,36 +0,0 @@
<?php
function formatSizeUnits($bytes)
{
if ($bytes >= 1073741824)
{
$bytes = number_format($bytes / 1073741824, 2) . ' GB';
}
elseif ($bytes >= 1048576)
{
$bytes = number_format($bytes / 1048576, 2) . ' MB';
}
elseif ($bytes >= 1024)
{
$bytes = number_format($bytes / 1024, 2) . ' kB';
}
elseif ($bytes > 1)
{
$bytes = $bytes . ' bytes';
}
elseif ($bytes == 1)
{
$bytes = $bytes . ' byte';
}
else
{
$bytes = '0 bytes';
}
return $bytes;
}
$size = filesize($f->path);
?>
<div id="stats">
<div class="header">Views: <?php echo $f->views; ?> <font style="float: right">Size: <?php echo formatSizeUnits($size); ?></font></div>
</div>

View File

@ -1,7 +0,0 @@
<?php
$audio_url = _SITEURL . $f->hash160;
?>
<video controls>
<source src="<?php echo $audio_url; ?>" type="<?php echo $f->mime; ?>">
Your browser does not support the video tag.
</video>