commit cd37c27e97bf1b67a299a385ab1356eaaa0ef469 Author: Kieran Date: Thu May 5 16:42:50 2016 +0100 Init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..36b145e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +out/ +*.xml +config.php +google*.html diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c581fd6 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "sitemap-php"] + path = sitemap-php + url = https://github.com/o/sitemap-php diff --git a/README.md b/README.md new file mode 100644 index 0000000..b73f378 --- /dev/null +++ b/README.md @@ -0,0 +1,95 @@ +# 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? \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..f9ae287 --- /dev/null +++ b/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "php-ffmpeg/php-ffmpeg": "~0.5" + } +} \ No newline at end of file diff --git a/config.php.sample b/config.php.sample new file mode 100644 index 0000000..ed2e6d5 --- /dev/null +++ b/config.php.sample @@ -0,0 +1,12 @@ + diff --git a/db.php b/db.php new file mode 100644 index 0000000..37643a2 --- /dev/null +++ b/db.php @@ -0,0 +1,108 @@ +error = null; + $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; + } + } + + function __destruct() + { + if($this->error == null) + { + $this->mysqli->close(); + } + } + + function Exists256($hash) + { + $res = new FileUpload(); + + $stmt = $this->mysqli->prepare("select id, hash160, hash256, mime, path, filename, views, created from files where hash256 = ? 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); + $stmt->fetch(); + $stmt->close(); + } + + return $res; + } + + function GetFile($hash) + { + $res = new FileUpload(); + + $stmt = $this->mysqli->prepare("select id, hash160, hash256, mime, path, filename, views, created from files where hash160 = ? 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); + $stmt->fetch(); + $stmt->close(); + } + + return $res; + } + + function GetFiles() + { + $res = array(); + + $stmt = $this->mysqli->prepare("select id, hash160, hash256, mime, path, filename, views, created from files"); + if($stmt) + { + $stmt->execute(); + $stmt->bind_result($id, $hash160, $hash256, $mime, $path, $filename, $views, $created); + 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->views = $views; + $nf->created = $created; + + array_push($res, $nf); + } + $stmt->close(); + } + + return $res; + } + + function InsertFile($f) + { + $stmt = $this->mysqli->prepare("insert into files(hash160, hash256, mime, path, filename) values(?,?,?,?,?)"); + if($stmt) + { + $stmt->bind_param("sssss", $f->hash160, $f->hash256, $f->mime, $f->path, $f->filename); + $stmt->execute(); + $stmt->close(); + } + } + + function AddView($hash160) + { + $stmt = $this->mysqli->prepare("update files set views = views + 1 where hash160 = ?"); + if($stmt) + { + $stmt->bind_param("s", $hash160); + $stmt->execute(); + $stmt->close(); + } + } + }; +?> diff --git a/db.sql b/db.sql new file mode 100644 index 0000000..41e1f4d --- /dev/null +++ b/db.sql @@ -0,0 +1,12 @@ +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 diff --git a/download.php b/download.php new file mode 100644 index 0000000..2088169 --- /dev/null +++ b/download.php @@ -0,0 +1,82 @@ + diff --git a/file.php b/file.php new file mode 100644 index 0000000..a42cea1 --- /dev/null +++ b/file.php @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/gensitemap.php b/gensitemap.php new file mode 100644 index 0000000..4e4deaf --- /dev/null +++ b/gensitemap.php @@ -0,0 +1,16 @@ +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'); + } + +?> diff --git a/index.php b/index.php new file mode 100644 index 0000000..103756e --- /dev/null +++ b/index.php @@ -0,0 +1,131 @@ +GetFile($hash); + if($f->id != 0){ + include_once('download.php'); + smartReadFile($f->path, $f->filename, $f->mime); + } + + exit; + }else if(isset($_GET["thumb"]) && $hash != null) + { + include_once('db.php'); + + $db = new DB(); + $f = $db->GetFile($hash); + if($f->id != 0){ + include_once('download.php'); + smartReadFile($f->path . '/thumb/', $f->filename, $f->mime); + } + + exit; + } +?> + + + + GetFile($hash); + } + $title = 'void.cat'; + $maxsizeM = ini_get('post_max_size'); + $maxsize = (int)(str_replace('M', '', $maxsizeM) * 1024 * 1024); + echo ""; + ?> + <?= $title . ($f != null ? ' - ' . $f->filename : '') ?> + + + + + id != 0){ + echo "filename . "\" />"; + echo ""; + + $content_url = _SITEURL . $f->hash160; + if(strpos($f->mime, "image/") === 0) { + echo ""; + echo "mime . "\" />"; + }else if(strpos($f->mime, "audio/") === 0) { + echo ""; + echo "mime . "\" />"; + }else if(strpos($f->mime, "video/") === 0) { + echo ""; + echo "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 ""; + } + } + } + ?> + + + + + +
+ + + 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 "

File Not Found :/

"; + } + }else{ + echo "
Drop Files < " . $maxsizeM . "
"; + } + ?> + +
+ + + + diff --git a/public/main.css b/public/main.css new file mode 100644 index 0000000..079a717 --- /dev/null +++ b/public/main.css @@ -0,0 +1,185 @@ +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; +} + +#footer a { + border-right: 1px solid #B3B3B3; + padding-right: 5px; +} + +#footer a:last-child { + border-right: 0; +} + +#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; +} + +/* 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; + } +} \ No newline at end of file diff --git a/public/main.js b/public/main.js new file mode 100644 index 0000000..2fe9e1f --- /dev/null +++ b/public/main.js @@ -0,0 +1,271 @@ +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 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 + '' + rsp.hash + ''; + 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 + + '
Hash256: ' + rsp.hash + + '
Hash160: ' + rsp.publichash + '' + + '
(link)'; + 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(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); + 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); + } + } +} + +setBG(); +checkForFrag(); \ No newline at end of file diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..df147db --- /dev/null +++ b/robots.txt @@ -0,0 +1,3 @@ +User-agent: * +Disallow: /m/ +Disallow: /mobile/ diff --git a/upload.php b/upload.php new file mode 100644 index 0000000..e439d91 --- /dev/null +++ b/upload.php @@ -0,0 +1,91 @@ + 0, + "msg" => null, + "hash" => null, + "publichash" => null, + "link" => null, + "mime" => null, + "filename" => null + ); + + //check input size is large enough + $maxsizeM = ini_get('post_max_size'); + $maxsize = (int)(str_replace('M', '', $maxsizeM) * 1024 * 1024); + $fsize = (int)$_SERVER['CONTENT_LENGTH']; + $mime = strlen($_SERVER['CONTENT_TYPE']) > 0 ? $_SERVER['CONTENT_TYPE'] : _DEFAULT_TYPE; + $fname = $_GET["filename"]; + + if($fsize > $maxsize) + { + $response["msg"] = "File size larger than " . $maxsizeM; + } + else + { + $rawf = fopen('php://input', 'rb'); + $tmpf = fopen('php://temp', 'rb+'); + stream_copy_to_stream($rawf, $tmpf); + rewind($tmpf); + + //Connect to db + $db = new DB(); + + //get file hash + $hc = hash_init('sha256'); + hash_update_stream($hc, $tmpf); + $fh = hash_final($hc); + $response["hash"] = $fh; + rewind($tmpf); + + //check for dupes + $f_e = $db->Exists256($fh); + if($f_e->id != 0) + { + //file already exists + $response["publichash"] = $f_e->hash160; + $response["mime"] = $f_e->mime; + } + else + { + //file does not exist + //generate public hash + $phc = hash_init('ripemd160'); + 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); + + //update sitemap + //include("gensitemap.php"); + } + + //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); +?> diff --git a/views/audio.php b/views/audio.php new file mode 100644 index 0000000..790e865 --- /dev/null +++ b/views/audio.php @@ -0,0 +1,6 @@ +hash160; +?> + \ No newline at end of file diff --git a/views/default.php b/views/default.php new file mode 100644 index 0000000..a957dc3 --- /dev/null +++ b/views/default.php @@ -0,0 +1,6 @@ +hash160; +?> +
+ Download filename; ?> +
\ No newline at end of file diff --git a/views/image.php b/views/image.php new file mode 100644 index 0000000..307a90e --- /dev/null +++ b/views/image.php @@ -0,0 +1,4 @@ +hash160; +?> + \ No newline at end of file diff --git a/views/stats.php b/views/stats.php new file mode 100644 index 0000000..b611465 --- /dev/null +++ b/views/stats.php @@ -0,0 +1,7 @@ + +
+
Views: views; ?>
+ +
\ No newline at end of file diff --git a/views/video.php b/views/video.php new file mode 100644 index 0000000..be1005a --- /dev/null +++ b/views/video.php @@ -0,0 +1,7 @@ +hash160; +?> + \ No newline at end of file