Einfacher FTP-Client für Application Express

FTP wird in vielen IT-Landschaften und -Systemen als Dateiübertragungs-Protokoll eingesetzt; insofern kommt es hin und wieder vor, dass man aus einer Application Express-Anwendung oder aus einer PL/SQL-Prozedur heraus etwas auf einen FTP-Server hoch- bzw. von einem solchen herunterladen muss.

Ein PL/SQL-Paket für FTP-Zugriffe gibt es nicht; allerdings können einfache FTP-Zugriffe recht einfach mit ein wenig Java-Code realisiert werden (Achtung: Da Java in der Datenbank verwendet wird, läuft dieser Tipp nicht in einer OracleXE-Datenbank).

Lassen Sie das folgende Skript in SQL*Plus, dem SQL Developer oder dem SQL Workshop laufen - es installiert den für die FTP-Kommunikation nötigen Java-Code und das PL/SQL-Paket SIMPLE_FTP, mit welchem Sie den FTP Client ansprechen können.

create or replace java source named ftp as 
import java.sql.*;
import oracle.sql.*;
import oracle.jdbc.*;
import java.net.*;
import java.io.*;

public class SimpleFtp {
  public static BLOB download(String psUrl) throws Exception {
    URL url = new URL(psUrl + ";type=i");
    URLConnection ucon = url.openConnection();
    BufferedInputStream in = new BufferedInputStream(ucon.getInputStream());

    Connection con = DriverManager.getConnection("jdbc:default:connection:");
    BLOB blob = BLOB.createTemporary(con, true, BLOB.DURATION_SESSION); 
    OutputStream out = blob.getBinaryOutputStream();
    int i = 0;
    byte[] bytesIn = new byte[blob.getChunkSize()];
    while ((i = in.read(bytesIn)) >= 0) {
      out.write(bytesIn, 0, i);
    }
    out.close();
    in.close();
    con.close();
    return blob;
  }

  public static void upload(String psUrl, BLOB blob) throws Exception {
    URL url = new URL(psUrl + ";type=i");
    URLConnection ucon = url.openConnection();
    BufferedInputStream in = new BufferedInputStream(blob.getBinaryStream(0L));

    OutputStream out = ucon.getOutputStream();
    int i = 0;
    byte[] bytesIn = new byte[blob.getChunkSize()];
    while ((i = in.read(bytesIn)) >= 0) {
      out.write(bytesIn, 0, i);
    }
    out.close();
    in.close();
  }
}
/
sho err

alter java source ftp compile
/
sho err

create or replace package simple_ftp is
 function ftp_download(p_url in varchar2) return blob;
 procedure ftp_upload(p_url in varchar2, p_blob in blob);
end simple_ftp;
/ 
sho err

create or replace package body simple_ftp is
 function ftp_download(p_url in varchar2) return blob
 as language java name 'SimpleFtp.download(java.lang.String) return oracle.sql.BLOB';
 procedure ftp_upload(p_url in varchar2, p_blob in blob)
 as language java name 'SimpleFtp.upload(java.lang.String, oracle.sql.BLOB)';
end simple_ftp;
/ 
sho err

Die Implementierung ist sehr einfach; der Code kann Dateien per FTP oder HTTP hoch- und herunterladen. "Erweiterte" Funktionen wie das Wechseln des Verzeichnisses sind hiermit nicht möglich.

Bevor Sie das PL/SQL-Paket SIMPLE_FTP nun nutzen können, müssen Sie dem Parsing Schema Ihrer Anwendung noch entsprechende Netzwerkprivilegien vergeben. Dazu muss der DBA folgende SQL-Kommandos laufen lassen:

call  dbms_java.grant_permission( '[Parsing Schema]', 'SYS:java.net.SocketPermission', '[Hostname]', 'resolve' );
call  dbms_java.grant_permission( '[Parsing Schema]', 'SYS:java.net.SocketPermission', '[IP-Addresse]', 'connect, resolve' );

Nun können Sie den Client testen. Wir möchten eine Benutzereingabe auf einen FTP-Server hochladen. Erzeugen Sie also eine APEX-Applikation mit einer Textarea für den Dateiinhalt (P2_CONTENT) sowie mit Eingabefeldern für den Dateipfad (P2_PATH), Benutzername (P2_USERNAME) und Passwort (P2_PASSWORT) für den FTP-Server.

Formular für den FTP-Upload

Abbildung 1: Formular für den FTP-Upload

Erstellen Sie nun den PL/SQL-Prozeß, welcher mit Hilfe des neuen Pakets SIMPLE_FTP die Datei hochlädt: Erzeugen Sie einen Prozeß, der beim Weiterleiten der Seite (onSubmit) ausgeführt wird, nennen Sie ihn Datei hochladen und hinterlegen Sie folgenden PL/SQL-Code:

declare
  v_content blob;
  v_doffset number := 1;
  v_soffset number := 1; 
  v_langctx number := 1;
  v_warning number;
begin
  -- Den Text in einen BLOB umwandeln
  dbms_lob.createTemporary(v_content, true, DBMS_LOB.CALL);
  dbms_lob.converttoblob(
    dest_lob => v_content, 
    SRC_CLOB => to_clob(:P2_CONTENT),
    amount   => length(:P2_CONTENT),
    dest_offset => v_doffset,
    src_offset => v_doffset,
    blob_csid => nls_charset_id('AL32UTF8'),
    lang_context => v_langctx,
    warning => v_warning
  );
  if :P2_USERNAME is not null then 
  -- Wenn ein Username angegeben wird: Username und Passwort in URL einbauen
    simple_ftp.ftp_upload(
      p_url => 'ftp://'||:P2_USERNAME ||  ':'||:P2_PASSWORT||'@'||:P2_PATH,
      p_blob => v_content
    );
  else 
  -- ... sonst anonyme Verbindung
    simple_ftp.ftp_upload(
      p_url => 'ftp://'||:P2_PATH,
      p_blob => v_content
    );
  end if;
end;

Testen Sie die Seite nun - tragen Sie ein ...

  • In den Textbereich (P2_CONTENT) einen beliebigen Text
  • Als Username (P2_USERNAME) tragen Sie den Usernamen für die Verbindung zum FTP-Server ein - wenn Sie sich anonym mit dem FTP-Server verbinden möchten, tragen Sie nichts ein.
  • Als Passwort ( P2_PASSWORT) tragen Sie das Passwort für die Verbindung zum FTP-Server ein - wenn Sie sich anonym mit dem FTP-Server verbinden möchten, tragen Sie nichts ein.
  • Als Pfad ( P2_PATH) tragen Sie den Hostnamen des FTP-Servers und den Dateipfad ein. Wenn die Datei also den Namen test.txt erhalten und ins Verzeichnis /upload/myfiles auf dem Server ftpserv.mydomain.com gelegt werden soll, tragen Sie ftpserv.mydomain.com/upload/myfiles/text.txt ein.
Das Hochladen war erfolgreich

Abbildung 2: Das Hochladen war erfolgreich

Nun können Sie prüfen, ob die Datei auch wirklich auf dem FTP-Server liegt. Das Verzeichnis, in welches die Datei platziert werden soll, muss bereits existieren. Herunterladen von einem FTP-Server funktioniert analog mit der Funktion SIMPLE_FTP.FTP_DOWNLOAD; mit diesem einfachen Paket ist die Kommunikation mit einem FTP-Server im Unternehmen nun kein Problem mehr.

Dieser Tipp wurde aus dem Blog sql-plsql-de.blogspot.com entnommen.

Zurück zur Community-Seite