Last active
March 1, 2020 18:33
-
-
Save mikitsu/3a4f19f27a2c54c3cfb7eabd3dea9dff to your computer and use it in GitHub Desktop.
Simple PHP uploader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// the location of the configuration/state data in JSON format | |
$CONFIG_FILE = '/path/to/config.json'; | |
/* Config file format: | |
* The configuration file is a JSON object with the following (sub-keys): | |
* - 'users': an object mapping user names to objects with the following keys: | |
* - 'password': the user's password, in the format accepted by password_verify | |
* - 'upload interval': the time limit between successive uploads by the user, in seconds | |
* - 'upload directory': the directory to place the user's uploads in; this should end in the path separator. | |
* - 'max file size': the maximum uploadable file size, in bytes | |
* - 'max saved files': the maximum number of files to be kept. Old files will be deleted if neccessary. null to keep all files. | |
* - 'defaults': default values for user settings 'upload interval', 'max file size', 'max saved files' and 'upload directory' | |
* - '_internal': internal data structure (don't touch) | |
*/ | |
function send_status($number){ | |
$stati = [500 => "Internal Server Error", 400 => "Bad Request", 401 => "Unauthorized", 413 => "Payload too large", 429 => "Too many requests"]; | |
header($_SERVER['SERVER_PROTOCOL']." $number ".$stati[$number]); | |
} | |
$config = json_decode(file_get_contents($CONFIG_FILE), TRUE); | |
if ($config == NULL){ | |
send_status(500); | |
} else { | |
if (!array_key_exists('_internal', $config)){ | |
$config['_internal'] = ['last upload' => []]; | |
} | |
if (isset($_SERVER['PHP_AUTH_USER'])){ | |
$user = $_SERVER['PHP_AUTH_USER']; | |
$password = $_SERVER['PHP_AUTH_PW']; | |
} else { | |
$user = $_POST['username']; | |
$password = $_POST['password']; | |
} | |
if (array_key_exists($user, $config['users'])){ | |
$uconfig = array_merge($config['defaults'], $config['users'][$user]); | |
if (password_verify($password, $uconfig['password'])){ | |
$dir = $uconfig['upload directory']; | |
if (substr($dir, -1) != '/'){ | |
$dir .= '/'; | |
} | |
if (!($file_name = array_keys($_FILES)[0])){ | |
send_status(400); | |
}else if (array_key_exists($user, $config['_internal']['last upload']) | |
&& time() < $config['_internal']['last upload'][$user] + $uconfig['upload interval']){ | |
send_status(429); | |
}else if ($_FILES[$file_name]['size'] > $uconfig['max file size']){ | |
send_status(413); | |
}else if (move_uploaded_file($_FILES[$file_name]['tmp_name'], | |
$dir.$user.'-'.date('c'))){ | |
$config['_internal']['last upload'][$user] = time(); | |
if ($uconfig['max saved files'] !== NULL){ | |
$files = []; | |
foreach(scandir($dir, TRUE) as $potential_file){ | |
if (is_file($dir.$potential_file) | |
&& substr($potential_file, 0, strlen($user)) === $user){ | |
array_push($files, $potential_file); | |
} | |
} | |
foreach(array_slice($files, $uconfig['max saved files']) as $old_file){ | |
$old_file = $dir . $old_file; | |
unlink($old_file); | |
} | |
} | |
} else { | |
send_status(500); | |
} | |
} else { | |
send_status(401); | |
echo 'Wrong password'; | |
} | |
} else { | |
send_status(401); | |
echo 'user unknown'; | |
} | |
file_put_contents($CONFIG_FILE, json_encode($config)); | |
} | |
?> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"users": { | |
"test": { | |
"password": "$2y$10$2cTYPE3RUzZltUE86cp31O0Xy2KZn0wApF1xko.WxQrlxIte.UtDC", | |
"upload directory": "/path/to/uploads/", | |
"upload interval": 5 | |
}, | |
"user-2": { | |
"password": "$2y$10$.4LGqtDExkTFc62lz9vLm.r3xXHzuzPf81xP8pNbpAzOdkixZuoAy", | |
"upload directory": "/path/to/other/uploads/", | |
"max file size": 1000000 | |
} | |
}, | |
"defaults": { | |
"max file size": 1000, | |
"max saved files": 5, | |
"upload interval": 3600 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment