Some of our Customers use Webdav (nextcloud) Fileserver to store theire Files.
So we need a integration in Oracle Apex:
First we need a Upload File Item
Then we need to Load it into the nextcloud Webdav API Service: Calling our Function
DECLARE
l_files apex_t_varchar2;
v_result number;
BEGIN
--- P210_CONTENTS is the Item for Upload
l_files := apex_string.split(:P210_CONTENTS, ':');
FOR i IN 1..l_files.COUNT LOOP
p_log.log_debug('file upload start for ' || l_files(i));
v_result := p_fil_webdav.upload_file('', l_files(i));
p_log.log_debug('result upload_file: ' || v_result );
END LOOP;
EXCEPTION
WHEN OTHERS THEN
-- Exception handling
p_log.log_error('An error occurred: ' || SQLERRM);
RAISE;
END;
The main doing is in our Procedure p_fil_webdav.upload_file
We tried it first with APEX_WEB_SERVICE but we got a Cookie not set error so we decided to use UTL_HTTP to handle this correctly.
The following function uploads a file from Oracle APEX's
apex_application_temp_files
table to a Nextcloud server using theUTL_HTTP
package.
Function Overview
FYI: Basic APIs — Nextcloud latest Developer Manual latest documentation
The upload_file
function:
Retrieves file metadata and content from APEX's temporary file storage.
Ensures the target directory exists on Nextcloud.
Authenticates and sends the file to Nextcloud using HTTP PUT requests.
Handles errors gracefully and logs important steps for debugging.
Code Walkthrough
Below, we break the function into meaningful sections and describe their purpose.
1. Function Declaration and Initialization
FUNCTION upload_file(p_dir VARCHAR2, p_filename VARCHAR2) RETURN VARCHAR2
AS
-- HTTP request/response objects
v_http_request UTL_HTTP.req;
v_http_response UTL_HTTP.resp;
v_url VARCHAR2(1000);
-- Authentication and wallet details
v_username VARCHAR2(1000);
v_password VARCHAR2(1000);
v_wallet_path VARCHAR2(200);
v_wallet_password VARCHAR2(200);
-- File handling variables
v_blob BLOB;
v_content_length NUMBER := 0;
v_offset INTEGER;
v_buffer RAW(32767);
v_chunk_size PLS_INTEGER := 32767;
-- Miscellaneous
v_filename VARCHAR2(500);
v_start DATE;
v_end DATE;
nextcloud_dir_create_error EXCEPTION;
upload_multiple_loops_error EXCEPTION;
BEGIN
p_log.log_debug('upload_file ' || p_dir || ':' || p_filename);
Parameters:
p_dir
: Target directory on Nextcloud.p_filename
: File to be uploaded.
Purpose: Initializes variables and logs the function call.
2. Retrieve File from APEX Temporary Table
FOR c1 IN (
SELECT application_id, name, filename, mime_type, blob_content
FROM apex_application_temp_files
WHERE name = p_filename
) LOOP
IF (v_cycle > 0) THEN
RAISE upload_multiple_loops_error;
END IF;
v_cycle := 1;
v_blob := c1.blob_content;
v_content_length := DBMS_LOB.getlength(v_blob);
Purpose: Queries the file content and metadata from the temporary files table.
Error Handling: Ensures only one file matches
p_filename
by using a cycle counter.
3. Directory Validation
v_result := create_directory(p_dir);
IF v_result = 0 THEN
RAISE nextcloud_dir_create_error;
END IF;
v_filename := determine_filename(p_dir, c1.filename);
Directory Check: Calls
create_directory
to verify or create the target directory.Error Handling: Raises an exception if directory creation fails.
4. Authentication Setup
--- In our Case important!
UTL_HTTP.SET_COOKIE_SUPPORT(TRUE);
v_wallet_path := p_adm.get_param('wallet_path','');
v_wallet_password := p_adm.get_param_base64('wallet_password','');
UTL_HTTP.SET_WALLET(v_wallet_path, v_wallet_password);
v_username := p_adm.get_param('nextcloud_username','');
v_password := p_adm.get_param_base64('nextcloud_password','');
v_url := p_adm.get_param('nextcloud_basic_url','') ||
UPPER(v_username) || '/' ||
CASE WHEN p_dir IS NULL THEN '' ELSE p_dir || '/' END ||
UTL_URL.escape(v_filename);
Wallet Configuration: Configures the Oracle Wallet for secure HTTPS communication.
Authentication: Uses basic authentication for Nextcloud.
Dynamic URL: Constructs the target URL using parameters.
5. Send File Using HTTP PUT Request
v_http_request := UTL_HTTP.begin_request(v_url, 'PUT', 'HTTP/1.1');
UTL_HTTP.set_authentication(v_http_request, v_username, v_password, 'Basic');
-- Nextcloud specific
UTL_HTTP.set_header(v_http_request, 'OCS-APIREQUEST', 'true');
UTL_HTTP.set_header(v_http_request, 'Content-Type', c1.mime_type);
UTL_HTTP.set_header(v_http_request, 'Content-Length', v_content_length);
v_offset := 1;
WHILE v_offset <= v_content_length LOOP
v_amount := LEAST(32767, v_content_length - v_offset + 1);
DBMS_LOB.read(v_blob, v_amount, v_offset, v_buffer);
UTL_HTTP.write_raw(v_http_request, v_buffer);
v_offset := v_offset + v_amount;
END LOOP;
v_http_response := UTL_HTTP.get_response(v_http_request);
Request Initialization: Creates an HTTP
PUT
request and sets necessary headers.File Streaming: Reads the BLOB in chunks and writes it to the HTTP request body.
Response Handling: Captures the server's response after file upload.
6. Response Handling and Logging
BEGIN
LOOP
UTL_HTTP.READ_TEXT(r => v_http_response, data => v_data);
p_log.log_debug('Response data: ' || v_data);
END LOOP;
EXCEPTION
WHEN UTL_HTTP.END_OF_BODY THEN
NULL; -- End of response body reached
END;
UTL_HTTP.end_response(v_http_response);
IF v_http_response.status_code = 201 THEN
RETURN v_filename;
ELSE
RETURN 'NOK';
END IF;
Purpose: Processes the server's response.
Success Check: Confirms the status code (
201 Created
) for successful upload.Return Value: Returns the uploaded filename or 'NOK' for failure.
7. Exception Handling
EXCEPTION
WHEN OTHERS THEN
p_log.log_error('An error occurred: ' || SQLERRM);
RAISE;
END upload_file;
Error Logging: Logs unexpected errors for debugging.
Re-Raises Errors: Ensures unhandled exceptions propagate.
Key Features of the Function
Secure Communication: Leverages Oracle Wallet for HTTPS.
Chunked Uploads: Handles large files efficiently by reading in chunks.
Robust Logging: Uses a custom
p_log
package for debugging and monitoring.Dynamic Configuration: Retrieves parameters (e.g., usernames, passwords) at runtime.
Example Usage
DECLARE
v_result VARCHAR2(500);
BEGIN
v_result := upload_file('Documents', 'example.pdf');
DBMS_OUTPUT.PUT_LINE('Upload result: ' || v_result);
END;