$files]; 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(getMandatoryPost('filename')); $filesize = getMandatoryPost('size'); $mimeType = getOptionalPostParameter('content_type'); $recipientJid = getOptionalPostParameter('recipient_jid', 'Unknown'); // Optional for backwards compatibility (xep-0363 v0.1) // 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 $uploadedContentType = mime_content_type($uploadFilePath); if (!is_null($slotParameters['content_type']) && !empty($slotParameters['content_type']) && $uploadedContentType != $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); $xmppServerKey = $_SERVER["HTTP_X_XMPP_SERVER_KEY"]; $userJid = $_SERVER["HTTP_X_USER_JID"]; // Check if xmppServerKey is allowed to request slots if (false === checkXmppServerKey($config['valid_xmpp_server_keys'], $xmppServerKey)) { sendHttpReturnCodeAndJson(403, 'Server is not allowed to delete a file'); } $slotParameters = loadSlotParameters($slotUUID, $config); if ($config['delete_only_by_creator']) { if (getBareJid($slotParameters['user_jid']) != getBareJid($userJid)) { sendHttpReturnCodeAndJson(403, "Deletion of that file is only allowed by the user created it."); } } if (!slotExists($slotUUID, $config)) { sendHttpReturnCodeAndJson(403, "The slot does not exist."); } 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; case 'GET': $actionParameter = getMandatoryGet('action'); switch ($actionParameter) { case 'version': echo json_encode(require_once(__DIR__.'/lib/version.inc.php')); break; default: sendHttpReturnCodeAndJson(403, "Access not allowed."); } 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 getMandatoryPost($parameterName) { return getMandatoryPostParameter($parameterName, ['msg' => 'Missing parameter.', 'err_code' => 4, 'parameters' => ['missing_parameter' => $parameterName]], true); } function getMandatoryGet($parameterName) { return getMandatoryGetParameter($parameterName, ['msg' => 'Missing parameter.', 'err_code' => 4, 'parameters' => ['missing_parameter' => $parameterName]], true); } 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, $recipientJid, $config) { $contents = " \''.$filename.'\', \'filesize\' => \''.$filesize.'\', '; $contents .= '\'content_type\' => \''.$contentType.'\', \'user_jid\' => \''.$userJid.'\', \'recipient_jid\' => \''.$recipientJid.'\'];'; $contents .= "\n?>"; if (!file_put_contents(getSlotFilePath($slotUUID, $config), $contents)) { sendHttpReturnCodeAndMessage(500, "Could not create slot registry entry."); } } function slotExists($slotUUID, $config) { return file_exists(getSlotFilePath($slotUUID, $config)); } ?>