mirror of
https://github.com/HaschekSolutions/pictshare.git
synced 2025-11-16 04:58:00 +00:00
added logging, updated theme and included info on the landing page
This commit is contained in:
2
TODO.md
2
TODO.md
@@ -1,5 +1,7 @@
|
|||||||
# Todos
|
# Todos
|
||||||
|
|
||||||
|
- [ ] Caching in Redis for already handled URLs so it doesn't need to go through the whole algorithm again
|
||||||
|
- [ ] View stats in redis
|
||||||
- [ ] Keep track of deleted (and therefore forbidden) hashes
|
- [ ] Keep track of deleted (and therefore forbidden) hashes
|
||||||
- [ ] Store list in Storage Controllers as well
|
- [ ] Store list in Storage Controllers as well
|
||||||
- [ ] Add a way for users to report content
|
- [ ] Add a way for users to report content
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ services:
|
|||||||
- FTP_BASEDIR=
|
- FTP_BASEDIR=
|
||||||
- ENCRYPTION_KEY=
|
- ENCRYPTION_KEY=
|
||||||
- ALWAYS_WEBP=
|
- ALWAYS_WEBP=
|
||||||
|
- LOG_VIEWS=false
|
||||||
ports:
|
ports:
|
||||||
- 8080:80
|
- 8080:80
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ services:
|
|||||||
- FTP_BASEDIR=
|
- FTP_BASEDIR=
|
||||||
- ENCRYPTION_KEY=
|
- ENCRYPTION_KEY=
|
||||||
- ALWAYS_WEBP=
|
- ALWAYS_WEBP=
|
||||||
|
- LOG_VIEWS=false
|
||||||
ports:
|
ports:
|
||||||
- 8080:80
|
- 8080:80
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ _buildConfig() {
|
|||||||
echo "define('ALWAYS_WEBP', ${ALWAYS_WEBP:-false});"
|
echo "define('ALWAYS_WEBP', ${ALWAYS_WEBP:-false});"
|
||||||
echo "define('ALLOWED_DOMAINS', '${ALLOWED_DOMAINS:-}');"
|
echo "define('ALLOWED_DOMAINS', '${ALLOWED_DOMAINS:-}');"
|
||||||
echo "define('SPLIT_DATA_DIR', ${SPLIT_DATA_DIR:-false});"
|
echo "define('SPLIT_DATA_DIR', ${SPLIT_DATA_DIR:-false});"
|
||||||
|
echo "define('LOG_VIEWS', ${LOG_VIEWS:-false});"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ In this file you can set the following options. For a simple working example con
|
|||||||
| UPLOAD_CODE | string | If set, all uploads require this code via GET or POST variable "uploadcode" to succeed |
|
| UPLOAD_CODE | string | If set, all uploads require this code via GET or POST variable "uploadcode" to succeed |
|
||||||
| REDIS_SERVER (NOT IMPLEMENTED) | IP | If you define a REDIS server IP here, it will enable you to use the FFMPEG Worker |
|
| REDIS_SERVER (NOT IMPLEMENTED) | IP | If you define a REDIS server IP here, it will enable you to use the FFMPEG Worker |
|
||||||
| UPLOAD_QUOTA (NOT IMPLEMENTED) | int | Size in MB. If set, will only allow uploads if combined size of uploads on Server is smaller than this value. Does not account for ALT_FOLDER data and resized versions of original uploads won't be added to calculation |
|
| UPLOAD_QUOTA (NOT IMPLEMENTED) | int | Size in MB. If set, will only allow uploads if combined size of uploads on Server is smaller than this value. Does not account for ALT_FOLDER data and resized versions of original uploads won't be added to calculation |
|
||||||
| MAX_RESIZED_IMAGES (NOT IMPLEMENTED | string | If set, limits count of resized images/videos per file on server |
|
| MAX_RESIZED_IMAGES (NOT IMPLEMENTED ) | string | If set, limits count of resized images/videos per file on server |
|
||||||
|
| LOG_VIEWS | bool | If set, will log all views into the ./logs/app.log. Pretty resource heavy, only use for debugging purposes |
|
||||||
|
|
||||||
|
|
||||||
# Content controllers
|
# Content controllers
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class API
|
|||||||
|
|
||||||
//check if we should get a file from a remote URL
|
//check if we should get a file from a remote URL
|
||||||
if ($_REQUEST['url']) {
|
if ($_REQUEST['url']) {
|
||||||
$url = trim($_REQUEST['url']);
|
$url = trim(rawurldecode($_REQUEST['url']));
|
||||||
if (checkURLForPrivateIPRange($url)) {
|
if (checkURLForPrivateIPRange($url)) {
|
||||||
addToLog(getUserIP() . " tried to get us to download a file from: " . $url . " but it is in a private IP range");
|
addToLog(getUserIP() . " tried to get us to download a file from: " . $url . " but it is in a private IP range");
|
||||||
return ['status' => 'err', 'reason' => 'Private IP range'];
|
return ['status' => 'err', 'reason' => 'Private IP range'];
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ function architect($u)
|
|||||||
if(isExistingHash($el))
|
if(isExistingHash($el))
|
||||||
{
|
{
|
||||||
$hash = $el;
|
$hash = $el;
|
||||||
|
if(defined('LOG_VIEWS') && LOG_VIEWS===true)
|
||||||
|
addToLog(getUserIP()." viewed $hash (".$_SERVER['HTTP_USER_AGENT'].")\tIt was locally found", ROOT.DS.'logs/views.log');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// if we don't have a hash yet but the element looks like it could be a hash
|
// if we don't have a hash yet but the element looks like it could be a hash
|
||||||
@@ -58,6 +60,9 @@ function architect($u)
|
|||||||
$c->pullFile($hash,ROOT.DS.'tmp'.DS.$hash);
|
$c->pullFile($hash,ROOT.DS.'tmp'.DS.$hash);
|
||||||
if(!file_exists(ROOT.DS.'tmp'.DS.$hash)) continue;
|
if(!file_exists(ROOT.DS.'tmp'.DS.$hash)) continue;
|
||||||
storeFile(ROOT.DS.'tmp'.DS.$hash,$hash,true);
|
storeFile(ROOT.DS.'tmp'.DS.$hash,$hash,true);
|
||||||
|
|
||||||
|
if(defined('LOG_VIEWS') && LOG_VIEWS===true)
|
||||||
|
addToLog(getUserIP()." viewed $hash (".$_SERVER['HTTP_USER_AGENT'].")\tIt was found in Storage Controller $contr", ROOT.DS.'logs/views.log');
|
||||||
|
|
||||||
break; // we break here because we already have the file. no need to check other storage controllers
|
break; // we break here because we already have the file. no need to check other storage controllers
|
||||||
}
|
}
|
||||||
@@ -73,6 +78,9 @@ function architect($u)
|
|||||||
storeFile(ROOT.DS.'tmp'.DS.$hash,$hash,true);
|
storeFile(ROOT.DS.'tmp'.DS.$hash,$hash,true);
|
||||||
unlink(ROOT.DS.'tmp'.DS.$el.'.enc');
|
unlink(ROOT.DS.'tmp'.DS.$el.'.enc');
|
||||||
|
|
||||||
|
if(defined('LOG_VIEWS') && LOG_VIEWS===true)
|
||||||
|
addToLog(getUserIP()." viewed $hash (".$_SERVER['HTTP_USER_AGENT'].")\tIt was found encrypted in Storage Controller $contr", ROOT.DS.'logs/views.log');
|
||||||
|
|
||||||
break; // we break here because we already have the file. no need to check other storage controllers
|
break; // we break here because we already have the file. no need to check other storage controllers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,6 +93,8 @@ function architect($u)
|
|||||||
{
|
{
|
||||||
if((new $cc)::ctype=='dynamic' && in_array((new $cc)->getRegisteredExtensions()[0],$u) )
|
if((new $cc)::ctype=='dynamic' && in_array((new $cc)->getRegisteredExtensions()[0],$u) )
|
||||||
{
|
{
|
||||||
|
if(defined('LOG_VIEWS') && LOG_VIEWS===true)
|
||||||
|
addToLog(getUserIP()." (".$_SERVER['HTTP_USER_AGENT'].") requested ".implode("/",$u)."\tIt's a dynamic image handled by $cc", ROOT.DS.'logs/views.log');
|
||||||
$hash = true;
|
$hash = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -112,6 +122,7 @@ function architect($u)
|
|||||||
//@todo: allow MASTER_DELETE_IP to be CIDR range or coma separated
|
//@todo: allow MASTER_DELETE_IP to be CIDR range or coma separated
|
||||||
if(getDeleteCodeOfHash($hash)==$code || (defined('MASTER_DELETE_CODE') && MASTER_DELETE_CODE==$code ) || (defined('MASTER_DELETE_IP') && MASTER_DELETE_IP==getUserIP()) )
|
if(getDeleteCodeOfHash($hash)==$code || (defined('MASTER_DELETE_CODE') && MASTER_DELETE_CODE==$code ) || (defined('MASTER_DELETE_IP') && MASTER_DELETE_IP==getUserIP()) )
|
||||||
{
|
{
|
||||||
|
addToLog(getUserIP()." (".$_SERVER['HTTP_USER_AGENT'].") deleted $hash");
|
||||||
deleteHash($hash);
|
deleteHash($hash);
|
||||||
exit($hash.' deleted successfully');
|
exit($hash.' deleted successfully');
|
||||||
}
|
}
|
||||||
@@ -1045,9 +1056,9 @@ function updateMetaData($hash, $meta)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addToLog($data)
|
function addToLog($data,$logfile=ROOT.DS.'logs/app.log')
|
||||||
{
|
{
|
||||||
$fp = fopen(ROOT.DS.'logs/app.log','a');
|
$fp = fopen($logfile,'a');
|
||||||
fwrite($fp,date("d.m.y H:i")."\t[".getURL()."] | ".$data."\n");
|
fwrite($fp,date("d.m.y H:i")."\t[".getURL()."] | ".$data."\n");
|
||||||
fclose($fp);
|
fclose($fp);
|
||||||
}
|
}
|
||||||
@@ -1,90 +1,269 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<!--[if IEMobile 7 ]> <html class="no-js iem7"> <![endif]-->
|
<!--[if IEMobile 7 ]> <html class="no-js iem7"> <![endif]-->
|
||||||
<!--[if (gt IEMobile 7)|!(IEMobile)]><!--> <html class="no-js"> <!--<![endif]-->
|
<!--[if (gt IEMobile 7)|!(IEMobile)]><!-->
|
||||||
<head>
|
<html class="no-js"> <!--<![endif]-->
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<title><?php echo (defined('TITLE')?TITLE:'PictShare image hosting'); ?></title>
|
|
||||||
|
|
||||||
<!-- Bootstrap -->
|
|
||||||
<link href="/css/bootstrap.min.css" rel="stylesheet">
|
|
||||||
|
|
||||||
<!-- PictShare overwrites -->
|
<head>
|
||||||
<link href="/css/pictshare.css" rel="stylesheet">
|
<meta charset="utf-8">
|
||||||
<link href="/css/dropzone.css" rel="stylesheet">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title><?php echo (defined('TITLE') ? TITLE : 'PictShare image hosting'); ?></title>
|
||||||
|
|
||||||
<!-- github-fork-ribbon-css
|
<!-- Bootstrap -->
|
||||||
|
<link href="/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- PictShare overwrites -->
|
||||||
|
<link href="/css/pictshare.css" rel="stylesheet">
|
||||||
|
<link href="/css/dropzone.css" rel="stylesheet">
|
||||||
|
<link href="/css/hljs-dracula.css" rel="stylesheet">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- github-fork-ribbon-css
|
||||||
https://simonwhitaker.github.io/github-fork-ribbon-css/ -->
|
https://simonwhitaker.github.io/github-fork-ribbon-css/ -->
|
||||||
<link href="/css/gh-fork-ribbon.min.css" rel="stylesheet">
|
<link href="/css/gh-fork-ribbon.min.css" rel="stylesheet">
|
||||||
|
|
||||||
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
||||||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
|
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var maxUploadFileSize=<?php echo (int)(ini_get('upload_max_filesize'));?>
|
var maxUploadFileSize = <?php echo (int)(ini_get('upload_max_filesize')); ?>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<meta name="description" content="Free image sharing, linking and tracking">
|
<meta name="description" content="Free image sharing, linking and tracking">
|
||||||
<meta name="keywords" content="image, share, hosting, free">
|
<meta name="keywords" content="image, share, hosting, free">
|
||||||
<meta name="robots" content="index, follow">
|
<meta name="robots" content="index, follow">
|
||||||
<meta name="copyright" content="Haschek Solutions">
|
<meta name="copyright" content="Haschek Solutions">
|
||||||
<meta name="language" content="EN,DE">
|
<meta name="language" content="EN,DE">
|
||||||
<meta name="author" content="Haschek Solutions">
|
<meta name="author" content="Haschek Solutions">
|
||||||
<meta name="distribution" content="global">
|
<meta name="distribution" content="global">
|
||||||
<meta name="rating" content="general">
|
<meta name="rating" content="general">
|
||||||
|
|
||||||
</HEAD>
|
</HEAD>
|
||||||
<BODY>
|
|
||||||
<a class="github-fork-ribbon left-top" href="https://github.com/HaschekSolutions/pictshare" data-ribbon="Fork me on GitHub" title="Fork me on GitHub">Fork me on GitHub</a>
|
|
||||||
|
|
||||||
<div class="container" id="headcontainer">
|
<BODY>
|
||||||
<div class="row">
|
<a class="github-fork-ribbon left-top" href="https://github.com/HaschekSolutions/pictshare" data-ribbon="Fork me on GitHub" title="Fork me on GitHub">Fork me on GitHub</a>
|
||||||
<div class="col-md-8">
|
|
||||||
<a href="/"><img src="/css/imgs/logo/horizontalv3.png" /></a>
|
|
||||||
<?php
|
|
||||||
if(file_exists(ROOT.DS.'notice.txt'))
|
|
||||||
echo '<div class="alert alert-warning" role="alert">'.file_get_contents(ROOT.DS.'notice.txt').'</div>';
|
|
||||||
?>
|
|
||||||
<div class="well">
|
|
||||||
<?php if($forbidden===true) { ?>
|
|
||||||
|
|
||||||
<h2>Upload forbidden</h2>
|
<div class="container" id="headcontainer">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<a href="/"><img src="/css/imgs/logo/horizontalv3.png" /></a>
|
||||||
|
<?php
|
||||||
|
if (file_exists(ROOT . DS . 'notice.txt'))
|
||||||
|
echo '<div class="alert alert-warning" role="alert">' . file_get_contents(ROOT . DS . 'notice.txt') . '</div>';
|
||||||
|
?>
|
||||||
|
<div class="well">
|
||||||
|
<?php if ($forbidden === true) { ?>
|
||||||
|
|
||||||
<p>Due to configured restrictions, you are not allowed to upload files at this time</p>
|
<h2>Upload forbidden</h2>
|
||||||
|
|
||||||
<?php } else { ?>
|
<p>Due to configured restrictions, you are not allowed to upload files at this time</p>
|
||||||
|
|
||||||
|
<?php } else { ?>
|
||||||
<div id="uploadinfo"></div>
|
<div id="uploadinfo"></div>
|
||||||
<p>
|
<p>
|
||||||
<?php
|
Max Upload size: <?=(int)(ini_get('upload_max_filesize'))?>MB / File<br/>
|
||||||
echo "Max Upload size: ". (int)(ini_get('upload_max_filesize'))."MB / File<br/>";
|
Allowed file types: <?= implode(', ', getAllContentFiletypes()) ?>
|
||||||
echo "Allowed file types: ". implode(', ',getAllContentFiletypes());
|
<?php
|
||||||
|
if (defined('UPLOAD_CODE') && UPLOAD_CODE != ''):?>
|
||||||
if(defined('UPLOAD_CODE') && UPLOAD_CODE!='')
|
<br>Upload Code: <input type="password" id="uploadcode" />
|
||||||
echo '<br>Upload Code: <input type="password" id="uploadcode" />';
|
<?php endif; ?>
|
||||||
?>
|
|
||||||
</p>
|
</p>
|
||||||
<form class="dropzone well" id="dropzone" method="post" action="/api/upload" enctype="multipart/form-data">
|
<form class="dropzone well" id="dropzone" method="post" action="/api/upload" enctype="multipart/form-data">
|
||||||
<div class="fallback">
|
<div class="fallback">
|
||||||
<input name="file" type="file" multiple />
|
<input name="file" type="file" multiple />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<footer>(c)<?php echo date("y");?> by<br/><a href="https://haschek.solutions" target="_blank"><img height="30" src="/css/imgs/hs_logo.png" /></a></footer>
|
|
||||||
</div>
|
|
||||||
|
</div>
|
||||||
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
|
<div class="container">
|
||||||
<script src="/js/bootstrap.min.js"></script>
|
<h2 id="api" class="section-heading">Using PictShare</h2>
|
||||||
<script src="/js/dropzone.js"></script>
|
|
||||||
<script src="/js/pictshare.js"></script>
|
<div class="row">
|
||||||
</BODY>
|
<div class="col-6">
|
||||||
</HTML>
|
<h3>Basics</h3>
|
||||||
|
<p>
|
||||||
|
When you upload an image you'll get a link like this:<pre><code class="url"><?= getURL() ?>abcef123.jpg</code></pre>
|
||||||
|
You can modify the size of the image by adding a size parameter to the URL. For example this will render the image in 800x600:
|
||||||
|
<pre><code class="url"><?= getURL() ?>800x600/abcef123.jpg</code></pre>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If you want to force the size to really be 800x600, you can use the "forcesize" parameter. It will still keep the aspect ratio but zoom in as needed to fit the dimensions
|
||||||
|
<pre><code class="url"><?= getURL() ?>800x600/forcesize/abcef123.jpg</code></pre>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>There are many more of these <a target="_blank" href="https://github.com/HaschekSolutions/pictshare/blob/master/rtfm/MODIFIERS.md">modifiers</a> and even <a target="_blank" href="https://github.com/HaschekSolutions/pictshare/blob/master/rtfm/IMAGEFILTERS.md">filters</a> available</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="no-print border border-primary border-2 opacity-50">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<h2 id="api" class="section-heading">Using the API</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6">
|
||||||
|
<h2>Basics</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
All API calls are done via GET or POST requests. The API will return JSON encoded data.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Base URL
|
||||||
|
<pre><code class="url"><?= getURL() ?>api</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-6">
|
||||||
|
<h2>Error handling</h2>
|
||||||
|
When the status is err there will always be a field "reason" that explains what went wrong.
|
||||||
|
<pre><code class="json">
|
||||||
|
{
|
||||||
|
"status": "err",
|
||||||
|
"reason": "File not a valid image"
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-100">
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-6">
|
||||||
|
<h2>Uploading an image</h2>
|
||||||
|
|
||||||
|
API call
|
||||||
|
<pre><code class="url">/upload</code></pre>
|
||||||
|
|
||||||
|
<p>You can post a file using the POST variable <span class="badge text-bg-secondary">image</span></p>
|
||||||
|
|
||||||
|
CURL example
|
||||||
|
<pre><code class="bash">curl -s -F "file=@myphoto.jpg" "<?= getURL() ?>upload"</code></pre>
|
||||||
|
|
||||||
|
Output
|
||||||
|
<pre><code class="json">
|
||||||
|
{
|
||||||
|
"status": "ok",
|
||||||
|
"hash": "7eli4d.jpg",
|
||||||
|
"filetype": "image/jpeg",
|
||||||
|
"url": "http://localhost:8080/7eli4d.jpg",
|
||||||
|
"delete_code": "jxgat3wze8lmn9sqwxy4x32p2xm7211g",
|
||||||
|
"delete_url": "http://localhost:8080/delete_jxgat3wze8lmn9sqwxy4x32p2xm7211g/7eli4d.jpg"
|
||||||
|
}</code></pre>
|
||||||
|
</div>
|
||||||
|
<div class="col-6">
|
||||||
|
<h2>Grabbing a URL</h2>
|
||||||
|
|
||||||
|
API call
|
||||||
|
<pre><code class="url">/upload?url=<span class="badge text-bg-secondary">url of image</span></code></pre>
|
||||||
|
|
||||||
|
<p>You can specify a URL in the POST or GET variable <span class="badge text-bg-secondary">url</span>
|
||||||
|
that the call will try to download and process.</p>
|
||||||
|
|
||||||
|
CURL example
|
||||||
|
<pre><code class="bash">curl -s "<?= getURL() ?>api/upload?url=https://pictshare.net/d2j1e1.png</code></pre>
|
||||||
|
|
||||||
|
Output
|
||||||
|
<pre><code class="json">
|
||||||
|
{
|
||||||
|
"status": "ok",
|
||||||
|
"hash": "ysj455.webp",
|
||||||
|
"filetype": "image/webp",
|
||||||
|
"url": "http://localhost:8080/ysj455.webp",
|
||||||
|
"delete_code": "4l0w04l4s42xddt2s5mrj1wikxz11l5z",
|
||||||
|
"delete_url": "http://localhost:8080/delete_4l0w04l4s42xddt2s5mrj1wikxz11l5z/ysj455.webp"
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-100">
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-6">
|
||||||
|
<h2>Uploading Base64 encoded content</h2>
|
||||||
|
<p>It's also possible to upload supported files via Base64 strings by providing the <span class="badge text-bg-secondary">base64</span> http parameter</p>
|
||||||
|
|
||||||
|
API call
|
||||||
|
<pre><code class="url">/hash/<span class="badge badge-success">sha1 hash of file</span></code></pre>
|
||||||
|
|
||||||
|
CURL example
|
||||||
|
<pre><code class="bash">(echo -n "base64="; echo -n "data:image/jpeg;base64,$(base64 -w 0 Screenshot3.jpg)") | curl --data @- <?= getURL() ?>api/upload</code></pre>
|
||||||
|
|
||||||
|
Output
|
||||||
|
<pre><code class="json">
|
||||||
|
{
|
||||||
|
"status": "ok",
|
||||||
|
"hash": "5e6alk.jpg",
|
||||||
|
"filetype": "image/jpeg",
|
||||||
|
"url": "http://localhost:8080/5e6alk.jpg",
|
||||||
|
"delete_code": "7ha2b5ccvsuvdd3qdnegzb2zqa9zxb5t",
|
||||||
|
"delete_url": "http://localhost:8080/delete_7ha2b5ccvsuvdd3qdnegzb2zqa9zxb5t/5e6alk.jpg"
|
||||||
|
}</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col-6">
|
||||||
|
<h2>Free vs Key</h2>
|
||||||
|
|
||||||
|
<p>If no valid key is sent to the API, the free quota of 10 calls per IP and day will be used. The
|
||||||
|
daily free quota will reset 24 hours after the last API call (with a quota cost of 1) was
|
||||||
|
received.</p>
|
||||||
|
|
||||||
|
Quota costs
|
||||||
|
<table class="table table-dark">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col"></th>
|
||||||
|
<th scope="col">No key</th>
|
||||||
|
<th scope="col">With key</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Uploading a new image</th>
|
||||||
|
<td>1</td>
|
||||||
|
<td>1</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Uploading an existing image</th>
|
||||||
|
<td>1</td>
|
||||||
|
<td>0</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Checking a hash</th>
|
||||||
|
<td>0</td>
|
||||||
|
<td>0</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<footer>(c)<?php echo date("y"); ?> by<br /><a href="https://haschek.solutions" target="_blank"><img height="30" src="/css/imgs/hs_logo.png" /></a></footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="/js/dropzone.js"></script>
|
||||||
|
<script src="/js/highlight.pack.js"></script>
|
||||||
|
<script src="/js/pictshare.js"></script>
|
||||||
|
</BODY>
|
||||||
|
|
||||||
|
</HTML>
|
||||||
1
web/css/bootstrap.css.map
Normal file
1
web/css/bootstrap.css.map
Normal file
File diff suppressed because one or more lines are too long
10
web/css/bootstrap.min.css
vendored
10
web/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
76
web/css/hljs-dracula.css
Normal file
76
web/css/hljs-dracula.css
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Dracula Theme v1.2.0
|
||||||
|
|
||||||
|
https://github.com/zenorocha/dracula-theme
|
||||||
|
|
||||||
|
Copyright 2015, All rights reserved
|
||||||
|
|
||||||
|
Code licensed under the MIT license
|
||||||
|
http://zenorocha.mit-license.org
|
||||||
|
|
||||||
|
@author Éverton Ribeiro <nuxlli@gmail.com>
|
||||||
|
@author Zeno Rocha <hi@zenorocha.com>
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding: 0.5em;
|
||||||
|
background: #282a36;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-keyword,
|
||||||
|
.hljs-selector-tag,
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-section,
|
||||||
|
.hljs-link {
|
||||||
|
color: #8be9fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-function .hljs-keyword {
|
||||||
|
color: #ff79c6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs,
|
||||||
|
.hljs-subst {
|
||||||
|
color: #f8f8f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-title,
|
||||||
|
.hljs-name,
|
||||||
|
.hljs-type,
|
||||||
|
.hljs-attribute,
|
||||||
|
.hljs-symbol,
|
||||||
|
.hljs-bullet,
|
||||||
|
.hljs-addition,
|
||||||
|
.hljs-variable,
|
||||||
|
.hljs-template-tag,
|
||||||
|
.hljs-template-variable {
|
||||||
|
color: #f1fa8c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-comment,
|
||||||
|
.hljs-quote,
|
||||||
|
.hljs-deletion,
|
||||||
|
.hljs-meta {
|
||||||
|
color: #6272a4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-keyword,
|
||||||
|
.hljs-selector-tag,
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-title,
|
||||||
|
.hljs-section,
|
||||||
|
.hljs-doctag,
|
||||||
|
.hljs-type,
|
||||||
|
.hljs-name,
|
||||||
|
.hljs-strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-emphasis {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
2377
web/js/bootstrap.js
vendored
2377
web/js/bootstrap.js
vendored
File diff suppressed because it is too large
Load Diff
7
web/js/bootstrap.min.js
vendored
7
web/js/bootstrap.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,40 +1,91 @@
|
|||||||
Dropzone.autoDiscover = false;
|
Dropzone.autoDiscover = false;
|
||||||
|
hljs.initHighlightingOnLoad();
|
||||||
|
|
||||||
$(function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
var myDropzone = new Dropzone("#dropzone");
|
var myDropzone = new Dropzone("#dropzone");
|
||||||
//console.log(myDropzone.options);
|
if (typeof maxUploadFileSize !== "undefined")
|
||||||
if (maxUploadFileSize !== undefined)
|
|
||||||
myDropzone.options.maxFilesize = maxUploadFileSize;
|
myDropzone.options.maxFilesize = maxUploadFileSize;
|
||||||
myDropzone.options.timeout = 0,
|
|
||||||
myDropzone.on("sending", function(file, xhr, formData) {
|
myDropzone.options.timeout = 0;
|
||||||
if(document.getElementById("uploadcode"))
|
|
||||||
formData.append("uploadcode", document.getElementById("uploadcode").value);
|
myDropzone.on("sending", function(file, xhr, formData) {
|
||||||
});
|
var uploadCodeElem = document.getElementById("uploadcode");
|
||||||
myDropzone.on('error', function(file, response) {
|
if (uploadCodeElem)
|
||||||
alert("Error: "+response.reason);
|
formData.append("uploadcode", uploadCodeElem.value);
|
||||||
});
|
});
|
||||||
myDropzone.on("success", function (file, response) {
|
|
||||||
console.log("raw response: " + response);
|
myDropzone.on('error', function(file, response) {
|
||||||
if (response == null || response == "null")
|
var uploadInfo = document.getElementById("uploadinfo");
|
||||||
$("#uploadinfo").append("<div class='alert alert-danger' role='alert'><strong>Error uploading " + file.name + "</strong><br/>Reason is unknown :(</div>")
|
if (response == null || response == "null") {
|
||||||
else {
|
uploadInfo.insertAdjacentHTML("beforeend",
|
||||||
var o = response;
|
renderMessage(
|
||||||
if (o.status == 'ok')
|
"Error uploading " + file.name,
|
||||||
$("#uploadinfo").append("<div class='alert alert-success' role='alert'><strong>" + file.name + "</strong> uploaded as <a target='_blank' href='/" + o.hash + "'>" + o.hash + "</a><br/>URL: <a target='_blank' href='" + o.url + "'>" + o.url + "</a> <button class='btn btn-xs' onClick='navigator.clipboard.writeText(\"" + o.url + "\");'>Copy URL</button></div>")
|
"Reason is unknown :(",
|
||||||
else if (o.status == 'err')
|
"danger"
|
||||||
$("#uploadinfo").append("<div class='alert alert-danger' role='alert'><strong>Error uploading " + file.name + "</strong><br/>Reason: " + o.reason + "</div>")
|
)
|
||||||
console.log(o)
|
);
|
||||||
|
} else {
|
||||||
|
if (response.status == 'err') {
|
||||||
|
uploadInfo.insertAdjacentHTML("beforeend",
|
||||||
|
renderMessage(
|
||||||
|
"Error uploading " + file.name,
|
||||||
|
"Reason: " + response.reason,
|
||||||
|
"danger"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
uploadInfo.insertAdjacentHTML("beforeend",
|
||||||
|
renderMessage(
|
||||||
|
"Error uploading " + file.name,
|
||||||
|
"Reason: " + response,
|
||||||
|
"danger"
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
myDropzone.on("success", function (file, response) {
|
||||||
|
console.log("raw response: " + response);
|
||||||
|
var uploadInfo = document.getElementById("uploadinfo");
|
||||||
|
if (response == null || response == "null") {
|
||||||
|
uploadInfo.insertAdjacentHTML("beforeend",
|
||||||
|
renderMessage(
|
||||||
|
"Error uploading " + file.name,
|
||||||
|
"Reason is unknown :(",
|
||||||
|
"danger"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (response.status == 'ok') {
|
||||||
|
uploadInfo.insertAdjacentHTML("beforeend",
|
||||||
|
renderMessage(file.name+" uploaded as <a target='_blank' href='/" + response.hash + "'>" + response.hash + "</a>","URL: <a target='_blank' href='" + response.url + "'>" + response.url + "</a> <button class='btn btn-primary btn-sm' onClick='navigator.clipboard.writeText(\"" + response.url + "\");'>Copy URL</button>","success")
|
||||||
|
);
|
||||||
|
} else if (response.status == 'err') {
|
||||||
|
uploadInfo.insertAdjacentHTML("beforeend",
|
||||||
|
renderMessage(
|
||||||
|
"Error uploading " + file.name,
|
||||||
|
response.reason,
|
||||||
|
"danger"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
document.onpaste = function (event) {
|
document.onpaste = function (event) {
|
||||||
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
|
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
|
||||||
for (index in items) {
|
for (var index in items) {
|
||||||
var item = items[index];
|
var item = items[index];
|
||||||
if (item.kind === 'file') {
|
if (item.kind === 'file') {
|
||||||
// adds the file to your dropzone instance
|
myDropzone.addFile(item.getAsFile());
|
||||||
myDropzone.addFile(item.getAsFile())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
|
|
||||||
|
function renderMessage(title,message,type){
|
||||||
|
if(!type)
|
||||||
|
type = "danger";
|
||||||
|
return `<div class='alert alert-${type}' role='alert'><strong>${title}</strong><br/>${message}</div>`;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user