mirror of
https://git.v0l.io/Kieran/void.cat.git
synced 2025-03-18 05:43:00 +01:00
v2
This commit is contained in:
parent
ce7b4120a9
commit
7e4002dc00
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
out/
|
||||
*.xml
|
||||
config.php
|
||||
src/php/config.php
|
||||
google*.html
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
||||
[submodule "sitemap-php"]
|
||||
path = sitemap-php
|
||||
url = https://github.com/o/sitemap-php
|
95
README.md
95
README.md
@ -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
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
## 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
22
bower.json
Normal 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"
|
||||
}
|
||||
}
|
@ -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
12
db.sql
@ -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
|
82
download.php
82
download.php
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -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 . '"');
|
||||
}
|
||||
?>
|
17
file.php
17
file.php
@ -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 {
|
||||
|
||||
}
|
||||
?>
|
@ -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
26
index.html
Normal 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
138
index.php
@ -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
22
polymer.json
Normal 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 }
|
||||
}
|
||||
]
|
||||
}
|
188
public/main.css
188
public/main.css
@ -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;
|
||||
}
|
||||
}
|
308
public/main.js
308
public/main.js
@ -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();
|
@ -1,3 +0,0 @@
|
||||
User-agent: *
|
||||
Disallow: /m/
|
||||
Disallow: /mobile/
|
41
src/css/style.css
Normal file
41
src/css/style.css
Normal 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
13
src/db.sql
Normal 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
86
src/js/util.js
Normal 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
157
src/modules/dropzone.html
Normal 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
54
src/modules/main.html
Normal 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
249
src/modules/upload.html
Normal 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
126
src/modules/view.html
Normal 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
95
src/php/api.php
Normal 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
25
src/php/config.php.sample
Normal 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');
|
||||
?>
|
@ -19,4 +19,4 @@
|
||||
$discord_data = array("content" => 'Deleted ' . count($fl) . ' expired files.');
|
||||
include('discord.php');
|
||||
}
|
||||
?>
|
||||
?>
|
@ -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;
|
||||
}
|
||||
};
|
||||
?>
|
||||
?>
|
@ -7,4 +7,4 @@
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_exec($curl);
|
||||
}
|
||||
?>
|
||||
?>
|
77
src/php/download.php
Normal file
77
src/php/download.php
Normal 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
20
src/php/file.php
Normal 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;
|
||||
}
|
||||
?>
|
@ -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);
|
||||
?>
|
||||
?>
|
@ -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>
|
@ -1,6 +0,0 @@
|
||||
<?php
|
||||
$u = _SITEURL . $f->hash160;
|
||||
?>
|
||||
<div id="download">
|
||||
<a href="<?php echo $u; ?>">Download <?php echo $f->filename; ?></a>
|
||||
</div>
|
@ -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>
|
@ -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>
|
@ -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>
|
Loading…
x
Reference in New Issue
Block a user