scratch – Rev 96
?pathlinks?
<?php
###########################################################################
## Copyright (C) Wizardry and Steamworks 2017 - License: GNU GPLv3 ##
###########################################################################
require_once('php/pseudocrypt.php');
require_once('php/functions.php');
require_once('vendor/autoload.php');
### Load configuration.
$config = spyc_load_file('config.yaml');
#### POST -> upload / GET -> download
switch ($_SERVER['REQUEST_METHOD']) {
case 'POST':
#### Script restrictions.
session_start();
if (empty($_POST['token']) || !hash_equals($_SESSION['token'], $_POST['token'])) {
http_response_code(403);
die('Forbidden.');
}
#### Retrieve uploaded file.
if (!empty($_FILES['file']) and
is_uploaded_file($_FILES['file']['tmp_name'])) {
if($_FILES['file']['size'] > $config['ALLOWED_ASSET_SIZE'] * 1048576) {
http_response_code(403);
die('File size exceeds '.$config['ALLOWED_ASSET_SIZE'].'MiB.');
}
# Regular multipart/form-data upload.
$name = $_FILES['file']['name'];
$data = atomized_get_contents($_FILES['file']['tmp_name']);
} else {
if((int)get_file_size("php://input") > $config['ALLOWED_ASSET_SIZE'] * 1048576) {
http_response_code(403);
die('File size exceeds '.$config['ALLOWED_ASSET_SIZE'].'MiB.');
}
# Raw POST data.
$name = urldecode(@$_SERVER['HTTP_X_FILE_NAME']);
$data = atomized_get_contents("php://input");
}
#### Grab the file extension.
$fileExtension = pathinfo($name, PATHINFO_EXTENSION);
#### If the extension is not allowed then change it to a text extension.
if (!isset($fileExtension) ||
!in_array(strtoupper($fileExtension),
array_map('strtoupper', $config['ALLOWED_FILE_EXTENSIONS']))) {
http_response_code(403);
die('File extension not allowed.');
}
#### Hash filename.
$file = strtolower(
PseudoCrypt::hash(
preg_replace(
'/\D/',
'',
hash(
'sha512',
$data
)
),
$config['ASSET_HASH_SIZE']
)
);
#### Build the user path.
$userPath = join(
DIRECTORY_SEPARATOR,
array(
$config['STORE_FOLDER'],
$file
)
);
#### Check for path traversals
$pathPart = pathinfo($userPath.'.'.$fileExtension);
if (strcasecmp(
realpath($pathPart['dirname']), realpath($config['STORE_FOLDER'])) != 0) {
http_response_code(500);
die('Internal server error.');
}
#### Store the file.
$timestamp = atomized_put_contents($userPath.'.'.$fileExtension, $data);
### Hook for various file extensions.
$opengraph = FALSE;
switch(strtoupper($fileExtension)) {
case 'GIF':
$opengraph = TRUE;
break;
}
### Return the URL to the file.
header('Content-Type: text/plain; charset=utf-8');
echo json_encode(
array(
"hash" => $file,
"timestamp" => $timestamp,
"opengraph" => $opengraph
)
);
break;
case 'GET':
### Tell browser not to cache files.
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
### If no file has been specified for download then return.
if (!isset($_GET['hash']) or empty($_GET['hash'])) {
http_response_code(404);
die('File not found.');
}
### Find the requested file.
$file = array_shift(
preg_grep(
'/'.$_GET['hash'].'/',
scandir($config['STORE_FOLDER'])
)
);
if (!isset($file) or empty($file)) {
http_response_code(404);
die('File not found.');
}
### Check the path for path traversals.
$fileExtension = pathinfo($file, PATHINFO_EXTENSION);
#### If the extension is not allowed then return.
if (!isset($fileExtension) ||
!in_array(strtoupper($fileExtension),
array_map('strtoupper', $config['ALLOWED_FILE_EXTENSIONS']))) {
http_response_code(403);
die('File extension not allowed.');
}
#### Build the user path.
$userPath = join(
DIRECTORY_SEPARATOR,
array(
$config['STORE_FOLDER'],
$file
)
);
#### Check for path traversals
$pathPart = pathinfo($userPath);
if (strcasecmp(
realpath($pathPart['dirname']), realpath($config['STORE_FOLDER'])) != 0) {
http_response_code(500);
die('Internal server error.');
}
### Hook for various file extensions.
switch(strtoupper($fileExtension)) {
case "HTML":
case "HTM":
header('Content-type: text/html');
break;
break;
case "URL":
if(preg_match(
"/URL=(https?:\/\/[\-_\.\+!\*'\(\),a-zA-Z0-9]+:?[0-9]{0,5}\/.*?)\n/",
file_get_contents($userPath), $matches)) {
header('Location: '.$matches[1]);
return;
}
break;
default:
### Open MIME info database and send the content type.
$finfo = finfo_open(FILEINFO_MIME_TYPE);
if (!$finfo) {
http_response_code(500);
die('Internal server error.');
}
header('Content-type: '.finfo_file($finfo, $userPath));
finfo_close($finfo);
break;
}
### Send the file along with the inline content disposition.
header('Content-length: '.(int)get_file_size($userPath));
header('Content-Disposition: inline; filename="' . basename($userPath) . '"');
header('Content-Transfer-Encoding: binary');
header('X-Sendfile: '.$userPath);
break;
}