$slots]; break; case 'delete': // Check if all parameters needed for an delete are present - return 400 (bad request) if a parameter is missing / empty $fileURL = getMandatoryPostParameter('file_url'); $slotUUID = getUUIDFromUri($fileURL); $filename = getFilenameFromUri($fileURL); if (!slotExists($slotUUID, $config)) { sendHttpReturnCodeAndJson(403, "The slot does not exist."); } if ($config['delete_only_by_creator']) { $slotParameters = loadSlotParameters($slotUUID, $config); if ($slotParameters['user_jid'] != $userJid) { sendHttpReturnCodeAndJson(403, "Deletion of that file is only allowed by the user created it."); } } // generate delete token, register delete token $deleteToken = generate_uuid(); registerDeleteToken($slotUUID, $filename, $deleteToken, $config); // return 200 for success and delete url Json formatted ( ['delete'=>url] ) $result = ['deletetoken' => $deleteToken]; break; case 'upload': default: // Check if all parameters needed for an upload are present - return 400 (bad request) if a parameter is missing / empty $filename = rawurlencode(getMandatoryPostParameter('filename')); $filesize = getMandatoryPostParameter('size'); $mimeType = getOptionalPostParameter('content_type'); $recipientJid = getMandatoryPostParameter('recipient_jid'); // check file name - return 406 (not acceptable) if file contains invalid characters foreach ($config['invalid_characters_in_filename'] as $invalidCharacter) { if (stripos($filename, $invalidCharacter) !== false) { sendHttpReturnCodeAndJson(406, ['msg' => 'Invalid character found in filename.', 'err_code' => 3, 'parameters' => ['invalid_character' => $invalidCharacter]]); } } // check file size - return 406 (not acceptable) if file too small if ($filesize <= 0) { sendHttpReturnCodeAndJson(406, ['msg' => 'File is empty.', 'err_code' => 1]); } // check file size - return 406 (not acceptable) if file too large if ($filesize > $config['max_upload_file_size']) { sendHttpReturnCodeAndJson(406, ['msg' => 'File too large.', 'err_code' => 2, 'parameters' => ['max_file_size' => $config['max_upload_file_size']]]); } // generate slot uuid, register slot uuid and expected file size and expected mime type $slotUUID = generate_uuid(); registerSlot($slotUUID, $filename, $filesize, $mimeType, $userJid, $recipientJid, $config); if (!mkdir(getUploadFilePath($slotUUID, $config))) { sendHttpReturnCodeAndJson(500, "Could not create directory for upload."); } // return 200 for success and get / put url Json formatted ( ['get'=>url, 'put'=>url] ) $result = ['put' => $config['base_url_put'].$slotUUID.'/'.$filename, 'get' => $config['base_url_get'].$slotUUID.'/'.$filename]; } echo json_encode($result); break; case 'PUT': // check slot uuid - return 403 if not existing $uri = $_SERVER["REQUEST_URI"]; $slotUUID = getUUIDFromUri($uri); $filename = getFilenameFromUri($uri); if (!slotExists($slotUUID, $config)) { sendHttpReturnCodeAndJson(403, "The slot does not exist."); } $slotParameters = loadSlotParameters($slotUUID, $config); if (!checkFilenameParameter($filename, $slotParameters)) { sendHttpReturnCodeAndJson(403, "Uploaded filename differs from requested slot filename."); } $uploadFilePath = rawurldecode(getUploadFilePath($slotUUID, $config, $slotParameters['filename'])); if (file_exists($uploadFilePath)) { sendHttpReturnCodeAndJson(403, "The slot was already used."); } // save file $incomingFileStream = fopen("php://input", "r"); $targetFileStream = fopen($uploadFilePath, "w"); $uploadedFilesize = stream_copy_to_stream($incomingFileStream, $targetFileStream, $slotParameters['filesize'] + 1); // max. 1 byte more than expected to avoid spamming fclose($targetFileStream); // check actual file size with registered file size - return 413 if ($uploadedFilesize != $slotParameters['filesize']) { unlink($uploadFilePath); sendHttpReturnCodeAndJson(403, "Uploaded file size differs from requested slot size."); } // check actual mime type with registered mime type if (!is_null($slotParameters['content_type']) && !empty($slotParameters['content_type']) && mime_content_type($uploadFilePath) != $slotParameters['content_type']) { unlink($uploadFilePath); sendHttpReturnCodeAndJson(403, "Uploaded file content type differs from requested slot content type."); } // return 500 in case of any error // return 201 for success sendHttpReturnCodeAndMessage(201); break; case 'DELETE': // check slot uuid - return 403 if not existing $uri = $_SERVER["REQUEST_URI"]; $slotUUID = getUUIDFromUri($uri); $filename = getFilenameFromUri($uri); $deleteToken = $_SERVER["HTTP_X_FILETRANSFER_HTTP_DELETE_TOKEN"]; if (!slotExists($slotUUID, $config)) { sendHttpReturnCodeAndJson(403, "The slot does not exist."); } $slotParameters = loadSlotParameters($slotUUID, $config); if ($deleteToken != $slotParameters['delete_token']) { sendHttpReturnCodeAndJson(403, "The delete token is not valid."); } if (time() > $slotParameters['delete_token_valid_till']) { sendHttpReturnCodeAndJson(403, "The delete token is not valid anymore."); } if (!checkFilenameParameter($filename, $slotParameters)) { sendHttpReturnCodeAndJson(403, "Filename to delete differs from requested slot filename."); } $uploadFilePath = rawurldecode(getUploadFilePath($slotUUID, $config, $slotParameters['filename'])); if (!file_exists($uploadFilePath)) { sendHttpReturnCodeAndJson(404, "The file does not exist."); } // Delete file if (unlink($uploadFilePath)) { // Clean up the server - ignore errors @rmdir(getUploadFilePath($slotUUID, $config)); // return 204 for success sendHttpReturnCodeAndMessage(204); } else { sendHttpReturnCodeAndJson(500, "Could not delete file."); } break; default: sendHttpReturnCodeAndJson(403, "Access not allowed."); break; } function checkXmppServerKey($validXmppServerKeys, $xmppServerKey) { foreach ($validXmppServerKeys as $validXmppServerKey) { if ($validXmppServerKey == $xmppServerKey) { return true; } } return false; } function checkFilenameParameter($filename, $slotParameters) { $filename = $filename; // the filename is a http get parameter and therefore encoded return $slotParameters['filename'] == $filename; } function getMandatoryPostParameter($parameterName) { $parameter = $_POST[$parameterName]; if (!isset($parameter) || is_null($parameter) || empty($parameter)) { sendHttpReturnCodeAndJson(400, ['msg' => 'Missing parameter.', 'err_code' => 4, 'parameters' => ['missing_parameter' => $parameterName]]); } return $parameter; } function getUUIDFromUri($uri) { $pattern = "/[a-f0-9]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/"; preg_match($pattern, $uri, $matches); return $matches[0]; } function getFilenameFromUri($uri) { $lastSlash = strrpos($uri, '/') + 1; return substr($uri, $lastSlash); } function registerSlot($slotUUID, $filename, $filesize, $contentType, $userJid, $receipientJid, $config) { $contents = " \''.$filename.'\', \'filesize\' => \''.$filesize.'\', '; $contents .= '\'content_type\' => \''.$contentType.'\', \'user_jid\' => \''.$userJid.'\', \'receipient_jid\' => \''.$receipientJid.'\'];'; $contents .= "\n?>"; if (!file_put_contents(getSlotFilePath($slotUUID, $config), $contents)) { sendHttpReturnCodeAndMessage(500, "Could not create slot registry entry."); } } function registerDeleteToken($slotUUID, $filename, $deleteToken, $config) { $slotFilePath = getSlotFilePath($slotUUID, $config); $contents = file_get_contents($slotFilePath); $validTo = time() + $config['delete_token_validity']; $newContents = str_replace("]", ", 'delete_token' => '".$deleteToken."', 'delete_token_valid_till' => '".$validTo."']", $contents); if (!file_put_contents($slotFilePath, $newContents)) { sendHttpReturnCodeAndMessage(500, "Could not update slot registry entry."); } } function slotExists($slotUUID, $config) { return file_exists(getSlotFilePath($slotUUID, $config)); } ?>