Created
September 13, 2022 10:00
-
-
Save jakubboucek/5ce3868f1eb8e20871edf597c44f0403 to your computer and use it in GitHub Desktop.
Shottr upload server-side script
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 | |
// CONFIGURATION | |
$uploadPath = 'upload'; // <-- directory to save images | |
$wwwPath = ''; // <-- url to uplaod directory (optional - will be filled) | |
$secretKey = ''; // <-- secret key - optional, fill to protect endpoint | |
// SECURITY CONFIG - do not modify when you not understand consequences | |
$allowedExts = ['png', 'jpg']; | |
$allowedChars = '-a-z0-9.'; | |
function sendResponse($data, $code = 200) | |
{ | |
header('Content-Type: application/json;charset=utf-8', true, $code); | |
echo json_encode($data, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); | |
die(); | |
} | |
function sendError($message, $code = 400) | |
{ | |
$data = ['error' => ['code' => $code, 'message' => $message]]; | |
sendResponse($data, $code); | |
} | |
$validKey = true; | |
if (empty($secretKey) === false) { | |
$requestKey = $_SERVER['HTTP_X_SHOTTR_KEY'] ?? ''; | |
$validKey = hash_equals($secretKey, $requestKey); | |
} | |
//Detect URLs | |
$authority = (($_SERVER['HTTPS'] ?? '') === 'on' ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST']; | |
$scriptFile = $_SERVER['SCRIPT_NAME'] ?? '/'; | |
$scriptPath = dirname($scriptFile); | |
if (strpos($uploadPath, '/') !== 0) { // rewrite relative path to absolute | |
$uploadSuffix = $uploadPath; | |
$uploadPath = __DIR__ . '/' . $uploadSuffix; | |
$wwwPath = $authority . trim($scriptPath, '/') . '/' . $uploadSuffix; | |
} | |
if (!is_dir($uploadPath) && !mkdir($uploadPath, 0777, true) && !is_dir($uploadPath)) { | |
sendError("File upload failed because error on server", 500); | |
} | |
// Send doc | |
if (strcasecmp($_SERVER['REQUEST_METHOD'], 'get') === 0) { | |
sendResponse([ | |
'name' => 'Shottr uploader', | |
'uploadUrlPrefix' => $wwwPath, | |
'validKey' => $validKey | |
]); | |
} elseif (strcasecmp($_SERVER['REQUEST_METHOD'], 'post') !== 0) { | |
sendError("Method '{$_SERVER['REQUEST_METHOD']}' not allowed", 405); | |
} | |
if (empty($secretKey) === false && $validKey === false) { | |
sendError('Unauthorized, X-Shottr-Key key missing or invalid', 401); | |
} | |
if (isset($_FILES['file']) === false || is_string($_FILES['file']['name']) === false) { | |
sendError('Missing uploaded file in POST request', 400); | |
} | |
$file = $_FILES['file']; | |
if ($file['error'] !== UPLOAD_ERR_OK) { | |
sendError("File upload failed because error on server (upload error: {$file['error']})", 500); | |
} | |
$filename = mb_strtolower(basename($file['name'])); | |
// SECURITY: Prevent attack with vulnerable file type | |
$exp = pathinfo($filename, PATHINFO_EXTENSION); | |
if (in_array($exp, $allowedExts, true) === false) { | |
sendError("File '$filename' is unacceptable to upload", 403); | |
} | |
// SECURITY: Remove unsafe chars from filename | |
$filename = preg_replace("~[^{$allowedChars}]+~", '-', $filename); | |
if (move_uploaded_file($file['tmp_name'], $uploadPath . '/' . $filename) === false) { | |
sendError("File upload failed because error on server (save error)", 500); | |
} | |
sendResponse(['url' => $wwwPath . '/' . rawurlencode($filename)]); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment