mirror of
https://github.com/HaschekSolutions/pictshare.git
synced 2025-11-12 03:06:22 +00:00
implemented alt_folder and reorganized interface class code
This commit is contained in:
17
README.md
17
README.md
@@ -1,7 +1,4 @@
|
||||
# PictShare
|
||||
**[Live Demo](https://www.pictshare.net)**
|
||||
PictShare is a selfhostable, open source image, video and text hosting as well as URL shortening service with a simple API.
|
||||
|
||||
# PictShare version 2
|
||||
---
|
||||
[](https://github.com/HaschekSolutions/pictshare/blob/master/LICENSE)
|
||||
|
||||
@@ -20,6 +17,18 @@ Test site: https://dev.pictshare.net/ (only sometimes on)
|
||||
- [x] Duplicate detection
|
||||
- [x] Write permission detection
|
||||
|
||||
### Config options
|
||||
|
||||
- [x] ALT_FOLDER
|
||||
- [x] URL
|
||||
- [x] LOG_UPLOADER
|
||||
- [x] FFMPEG_BINARY
|
||||
- [ ] PNG_COMPRESSION
|
||||
- [ ] JPEG_COMPRESSION
|
||||
- [ ] MASTER_DELETE_CODE
|
||||
- [ ] MASTER_DELETE_IP
|
||||
- [ ] UPLOAD_CODE
|
||||
|
||||
### Image hosting
|
||||
- [ ] Resizing
|
||||
- [ ] Filters
|
||||
|
||||
@@ -10,7 +10,7 @@ include_once(ROOT.DS.'inc'.DS.'config.inc.php');
|
||||
|
||||
//loading core and controllers
|
||||
include_once(ROOT . DS . 'inc' . DS. 'core.php');
|
||||
require_once(ROOT . DS . 'controllers' . DS. 'text'. DS . 'text.controller.php');
|
||||
require_once(ROOT . DS . 'content-controllers' . DS. 'text'. DS . 'text.controller.php');
|
||||
|
||||
// check write permissions first
|
||||
if(!isFolderWritable(ROOT.DS.'data'))
|
||||
|
||||
@@ -10,10 +10,10 @@ include_once(ROOT.DS.'inc'.DS.'config.inc.php');
|
||||
|
||||
//loading core and controllers
|
||||
include_once(ROOT . DS . 'inc' . DS. 'core.php');
|
||||
require_once(ROOT . DS . 'controllers' . DS. 'image'. DS . 'image.controller.php');
|
||||
require_once(ROOT . DS . 'controllers' . DS. 'text'. DS . 'text.controller.php');
|
||||
require_once(ROOT . DS . 'controllers' . DS. 'url'. DS . 'url.controller.php');
|
||||
require_once(ROOT . DS . 'controllers' . DS. 'video'. DS . 'video.controller.php');
|
||||
require_once(ROOT . DS . 'content-controllers' . DS. 'image'. DS . 'image.controller.php');
|
||||
require_once(ROOT . DS . 'content-controllers' . DS. 'text'. DS . 'text.controller.php');
|
||||
require_once(ROOT . DS . 'content-controllers' . DS. 'url'. DS . 'url.controller.php');
|
||||
require_once(ROOT . DS . 'content-controllers' . DS. 'video'. DS . 'video.controller.php');
|
||||
|
||||
// check write permissions first
|
||||
if(!isFolderWritable(ROOT.DS.'data'))
|
||||
@@ -57,8 +57,19 @@ if ($_FILES['file']["error"] == UPLOAD_ERR_OK)
|
||||
$answer = array('status'=>'err','reason'=>'Unsupported filetype');
|
||||
|
||||
if($answer['hash'])
|
||||
{
|
||||
//add this sha1 to the list
|
||||
addSha1($answer['hash'],$sha1);
|
||||
|
||||
// Lets' check all storage controllers and tell them that a new file was uploaded
|
||||
$sc = getStorageControllers();
|
||||
foreach($sc as $contr)
|
||||
{
|
||||
if((new $contr())->isEnabled()===true)
|
||||
(new $contr())->pushFile($answer['hash']);
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($answer);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* - Conversion jpg,png to webp
|
||||
*/
|
||||
|
||||
class ImageController
|
||||
class ImageController implements ContentController
|
||||
{
|
||||
//returns all extensions registered by this type of content
|
||||
public function getRegisteredExtensions(){return array('png','bmp','gif','jpg','jpeg','x-png','ico','webp');}
|
||||
@@ -56,15 +56,6 @@ class ImageController
|
||||
copy($tmpfile, $file);
|
||||
unlink($tmpfile);
|
||||
|
||||
if(defined('ALT_FOLDER') && ALT_FOLDER)
|
||||
{
|
||||
$altname=ALT_FOLDER.DS.$hash;
|
||||
if(!file_exists($altname) && is_dir(ALT_FOLDER))
|
||||
{
|
||||
copy($file,$altname);
|
||||
}
|
||||
}
|
||||
|
||||
if(defined('LOG_UPLOADER') && LOG_UPLOADER)
|
||||
{
|
||||
$fh = fopen(ROOT.DS.'data'.DS.'uploads.txt', 'a');
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
class TextController
|
||||
class TextController implements ContentController
|
||||
{
|
||||
//returns all extensions registered by this type of content
|
||||
public function getRegisteredExtensions(){return array('txt');}
|
||||
@@ -52,15 +52,6 @@ class TextController
|
||||
copy($tmpfile, $file);
|
||||
unlink($tmpfile);
|
||||
|
||||
if(defined('ALT_FOLDER') && ALT_FOLDER)
|
||||
{
|
||||
$altname=ALT_FOLDER.DS.$hash;
|
||||
if(!file_exists($altname) && is_dir(ALT_FOLDER))
|
||||
{
|
||||
copy($file,$altname);
|
||||
}
|
||||
}
|
||||
|
||||
if(defined('LOG_UPLOADER') && LOG_UPLOADER)
|
||||
{
|
||||
$fh = fopen(ROOT.DS.'data'.DS.'uploads.txt', 'a');
|
||||
9
content-controllers/url/url.controller.php
Normal file
9
content-controllers/url/url.controller.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
class UrlController implements ContentController
|
||||
{
|
||||
//returns all extensions registered by this type of content
|
||||
public function getRegisteredExtensions(){return array('url');}
|
||||
public function handleHash($hash,$url){}
|
||||
public function handleUpload($tmpfile,$hash=false){}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
class VideoController
|
||||
class VideoController implements ContentController
|
||||
{
|
||||
//returns all extensions registered by this type of content
|
||||
public function getRegisteredExtensions(){return array('mp4','ogg','webm');}
|
||||
@@ -81,15 +81,6 @@ class VideoController
|
||||
if(!$this->rightEncodedMP4($file))
|
||||
system("nohup php ".ROOT.DS.'tools'.DS.'re-encode_mp4.php force '.$hash." > /dev/null 2> /dev/null &");
|
||||
|
||||
if(defined('ALT_FOLDER') && ALT_FOLDER)
|
||||
{
|
||||
$altname=ALT_FOLDER.DS.$hash;
|
||||
if(!file_exists($altname) && is_dir(ALT_FOLDER))
|
||||
{
|
||||
copy($file,$altname);
|
||||
}
|
||||
}
|
||||
|
||||
if(defined('LOG_UPLOADER') && LOG_UPLOADER)
|
||||
{
|
||||
$fh = fopen(ROOT.DS.'data'.DS.'uploads.txt', 'a');
|
||||
@@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
class UrlController
|
||||
{
|
||||
//returns all extensions registered by this type of content
|
||||
public function getRegisteredExtensions(){return array('url');}
|
||||
}
|
||||
59
inc/core.php
59
inc/core.php
@@ -31,7 +31,25 @@ function architect($url)
|
||||
foreach($u as $el)
|
||||
{
|
||||
if(isExistingHash($el))
|
||||
{
|
||||
$hash = $el;
|
||||
break;
|
||||
}
|
||||
if($hash === false && mightBeAHash($el))
|
||||
{
|
||||
if(!$sc)
|
||||
$sc = getStorageControllers();
|
||||
foreach($sc as $contr)
|
||||
{
|
||||
$c = new $contr();
|
||||
if($c->isEnabled()===true && $c->hashExists($el))
|
||||
{
|
||||
$c->pullFile($el);
|
||||
$hash = $el;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//we didn't find a hash. Well let's just display the webpage instead
|
||||
@@ -67,7 +85,7 @@ function architect($url)
|
||||
(new VideoController())->handleHash($hash,$u);
|
||||
}
|
||||
//very odd. We know it's a valid hash but no controller says it's one of their kids
|
||||
//oh well, just show the main website
|
||||
//oh well
|
||||
else
|
||||
{
|
||||
var_dump("odd err");
|
||||
@@ -93,11 +111,24 @@ function isExistingHash($hash)
|
||||
return is_dir(ROOT.DS.'data'.DS.$hash);
|
||||
}
|
||||
|
||||
function mightBeAHash($string)
|
||||
{
|
||||
$len = strlen($string);
|
||||
$dot = strpos($string,'.');
|
||||
if(substr_count($string,'.')!=1) return false;
|
||||
if(!$dot) return false;
|
||||
$afterdot = substr($string,$dot+1);
|
||||
|
||||
//@todo: maybe pull all allowed types and compare to afterdot
|
||||
return ($afterdot && strlen($afterdot)>=2 && strlen($afterdot)<=5 );
|
||||
}
|
||||
|
||||
function autoload($className)
|
||||
{
|
||||
if (file_exists(ROOT . DS . 'controllers' . DS . strtolower($className) . '.php'))
|
||||
require_once(ROOT . DS . 'controllers' . DS . strtolower($className) . '.php');
|
||||
if (file_exists(ROOT . DS . 'content-controllers' . DS . strtolower($className) . '.php'))
|
||||
require_once(ROOT . DS . 'content-controllers' . DS . strtolower($className) . '.php');
|
||||
if (file_exists(ROOT . DS . 'interfaces' . DS . strtolower($className) . '.interface.php'))
|
||||
require_once(ROOT . DS . 'interfaces' . DS . strtolower($className) . '.interface.php');
|
||||
}
|
||||
|
||||
function renderTemplate($template,$vars=false)
|
||||
@@ -225,8 +256,7 @@ function getTypeOfFile($url)
|
||||
$fi = new finfo(FILEINFO_MIME);
|
||||
$type = $fi->buffer(file_get_contents($url, false, null, -1, 1024));
|
||||
|
||||
//to catch a strange error for PHP7 and Alpine Linux
|
||||
//if the file seems to be a stream, use unix file command
|
||||
// on linux use the "file" command or it will handle everything as octet-stream
|
||||
if(strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN' && startsWith($type,'application/octet-stream'))
|
||||
{
|
||||
$content_type = exec("file -bi " . escapeshellarg($url));
|
||||
@@ -334,3 +364,22 @@ function isSize($var)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getStorageControllers()
|
||||
{
|
||||
$controllers = array();
|
||||
if ($handle = opendir(ROOT.DS.'storage-controllers')) {
|
||||
while (false !== ($entry = readdir($handle))) {
|
||||
if ($entry != "." && $entry != "..") {
|
||||
if(endswith($entry,'.controller.php'))
|
||||
{
|
||||
$controllers[] = ucfirst(substr($entry,0,-15)).'Storage';
|
||||
include_once(ROOT.DS.'storage-controllers'.DS.$entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($handle);
|
||||
}
|
||||
|
||||
return $controllers;
|
||||
}
|
||||
14
inc/example.config.inc.php
Normal file
14
inc/example.config.inc.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* All settings that are uncommented are mandatory
|
||||
* Others optional
|
||||
*/
|
||||
|
||||
//Use a specific domain for links presented to the user
|
||||
//Format: https://your.domain.name/
|
||||
// MUST HAVE TAILING /
|
||||
define('URL','https://dev.pictshare.net/');
|
||||
|
||||
//define('JPEG_COMPRESSION', 90);
|
||||
//define('FFMPEG_BINARY','');
|
||||
//define('ALT_FOLDER','/ftp/pictshare');
|
||||
@@ -10,10 +10,10 @@ include_once(ROOT.DS.'inc'.DS.'config.inc.php');
|
||||
|
||||
//loading core and controllers
|
||||
include_once(ROOT.DS.'inc'.DS.'core.php');
|
||||
require_once(ROOT . DS . 'controllers' . DS. 'image'. DS . 'image.controller.php');
|
||||
require_once(ROOT . DS . 'controllers' . DS. 'text'. DS . 'text.controller.php');
|
||||
require_once(ROOT . DS . 'controllers' . DS. 'url'. DS . 'url.controller.php');
|
||||
require_once(ROOT . DS . 'controllers' . DS. 'video'. DS . 'video.controller.php');
|
||||
require_once(ROOT . DS . 'content-controllers' . DS. 'image'. DS . 'image.controller.php');
|
||||
require_once(ROOT . DS . 'content-controllers' . DS. 'text'. DS . 'text.controller.php');
|
||||
require_once(ROOT . DS . 'content-controllers' . DS. 'url'. DS . 'url.controller.php');
|
||||
require_once(ROOT . DS . 'content-controllers' . DS. 'video'. DS . 'video.controller.php');
|
||||
|
||||
|
||||
//send the URL to the architect. It'll know what to do
|
||||
|
||||
37
interfaces/contentcontroller.interface.php
Normal file
37
interfaces/contentcontroller.interface.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Content controller interface for new content types
|
||||
*/
|
||||
|
||||
interface ContentController
|
||||
{
|
||||
/** This method will return all file extensions that will be associated with this content type
|
||||
* for example 'pdf' but it could be anything really. You just need a way later to confirm that a type is what it says it is
|
||||
*
|
||||
*
|
||||
* @return array the extensions of files associated with this controller. eg. return array('pdf');
|
||||
*/
|
||||
public function getRegisteredExtensions();
|
||||
|
||||
/** This method will be called whenever the system has to find out if a user requested (existing) hash
|
||||
* belongs to this controller.
|
||||
* In here the content should be rendered or processed like resized or something.
|
||||
* You can decide what it does by working with the $url array which gives you every element in the URL
|
||||
* Does not need to return anything for example you can just set the header and print your data right away
|
||||
*
|
||||
* @param string $hash the hash (with extension eg '5saB2.pdf') of the file this controller will work with
|
||||
* @param array $url contains all URL elements exploded with '/' so you can do your magic.
|
||||
*/
|
||||
public function handleHash($hash,$url);
|
||||
|
||||
/** This method will be called if the upload script detects the content of a newly uploaded file as one of the
|
||||
* extensions registered at "getRegisteredExtensions".
|
||||
* For Example if someone uploads a PDF and getRegisteredExtensions has registered "pdf", then this method of this
|
||||
* controller will be called
|
||||
*
|
||||
* @param string $tmpfile is the location on disk of the temp file that was uploaded. It is your job to put it somewhere, your handleHash method will find it again
|
||||
* @param array $hash (optional) if you want your upload to have a certain hash then add it here. This allows for user chosen hashes
|
||||
*/
|
||||
public function handleUpload($tmpfile,$hash=false);
|
||||
}
|
||||
60
interfaces/storagecontroller.interface.php
Normal file
60
interfaces/storagecontroller.interface.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* StorageController interface
|
||||
*
|
||||
* Must be implemented by all storage systems
|
||||
*/
|
||||
|
||||
interface StorageController
|
||||
{
|
||||
/**
|
||||
* Checks if this storage system is enabled.
|
||||
* For example check if all depenencies are met
|
||||
* or config vars are set
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function isEnabled();
|
||||
|
||||
/**
|
||||
* Is fired whenever a hash is not found locally
|
||||
* Use this to look in your storage system for the file
|
||||
*
|
||||
* @param string $hash is the hash of the file requested
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function hashExists($hash);
|
||||
|
||||
/**
|
||||
* If a file does exist in this storage system, then this method should
|
||||
* get the file and put it in the default data directory
|
||||
*
|
||||
* The file should be placed in /data/$hash/$hash where the first $hash is obviously
|
||||
* a folder that you might have to create first before putting the file in
|
||||
*
|
||||
* @param string $hash is the hash of the file that should be pulled from this storage system
|
||||
*
|
||||
* @return bool true if successful
|
||||
*/
|
||||
function pullFile($hash);
|
||||
|
||||
/**
|
||||
* Whenever a new file is uploaded this method will be called
|
||||
* You should then upload it or do whatever your storage system is meant to do with new files
|
||||
*
|
||||
* @param string $hash is the hash of the new file. The file path of this file is always ROOT.DS.'data'.DS.$hash.DS.$hash
|
||||
*
|
||||
* @return bool true if successful
|
||||
*/
|
||||
function pushFile($hash);
|
||||
|
||||
/**
|
||||
* If deletion of a file is requested, this method is called
|
||||
*
|
||||
* @param string $hash is the hash of the file. Delete this hash from your storage system
|
||||
*
|
||||
* @return bool true if successful
|
||||
*/
|
||||
function deleteFile($hash);
|
||||
}
|
||||
47
storage-controllers/altfolder.controller.php
Normal file
47
storage-controllers/altfolder.controller.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
class AltfolderStorage implements StorageController
|
||||
{
|
||||
function isEnabled()
|
||||
{
|
||||
return (defined('ALT_FOLDER') && ALT_FOLDER && is_dir(ALT_FOLDER));
|
||||
}
|
||||
|
||||
function hashExists($hash)
|
||||
{
|
||||
$altname=ALT_FOLDER.DS.$hash;
|
||||
return file_exists($altname);
|
||||
}
|
||||
|
||||
function pullFile($hash)
|
||||
{
|
||||
$altname=ALT_FOLDER.DS.$hash;
|
||||
if(file_exists($altname))
|
||||
{
|
||||
mkdir(ROOT.DS.'data'.DS.$hash);
|
||||
copy($altname,ROOT.DS.'data'.DS.$hash.DS.$hash);
|
||||
|
||||
//and don't forget to add it to the duplicate detection system
|
||||
addSha1($hash,sha1_file($altname));
|
||||
}
|
||||
}
|
||||
|
||||
function pushFile($hash)
|
||||
{
|
||||
$altname=ALT_FOLDER.DS.$hash;
|
||||
$orig = ROOT.DS.'data'.DS.$hash.DS.$hash;
|
||||
if(file_exists($orig) && !$this->hashExists($hash))
|
||||
{
|
||||
copy($orig,$altname);
|
||||
}
|
||||
}
|
||||
|
||||
function deleteFile($hash)
|
||||
{
|
||||
$altname=ALT_FOLDER.DS.$hash;
|
||||
if(file_exists($altname))
|
||||
{
|
||||
unlink($altname);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ include_once(ROOT.DS.'inc'.DS.'config.inc.php');
|
||||
|
||||
//loading core and controllers
|
||||
include_once(ROOT.DS.'inc'.DS.'core.php');
|
||||
require_once(ROOT . DS . 'controllers' . DS. 'video'. DS . 'video.controller.php');
|
||||
require_once(ROOT . DS . 'content-controllers' . DS. 'video'. DS . 'video.controller.php');
|
||||
|
||||
if(!defined('FFMPEG_BINARY')||FFMPEG_BINARY=='' || !FFMPEG_BINARY) exit('Error: FFMPEG_BINARY not defined, no clue where to look');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user