Performing FTP Commands From ABAP
The use of FTP from ABAP seems to have been a hot topic on the ABAP Forums of late. I thought I might sit down and document whatever I could find on this subject and share it as a weblog.
Over the years I have seen lots of different solutions for moving files on and off of a SAP system. I have seen external FTP scripts written in OS shell languages. I have seen full blown custom applications that are made to interface to the SAP system. However I think you will find that most of the technology you need to perform a simple FTP from ABAP is already contained in the standard system. All of my examples and screen shots will be coming from a 46C system.
If you have ever taken a look at the kernel directory of your SAP system, you might have noticed an interesting little executable: sapftp.exe (the name of the file on Windows SAP Kernels). It is this part of the Kernel that exposes FTP functionality to the ABAP Programming language.
So you have a suspicion that there is FTP functionality in ABAP, but youre not quite sure how to use it. Where do you start? I always turn to the Service Marketplace first. A quick search on SAPFTP reveals there is an entire component (BC-SRV-COM-FTP) on the subject. The most general note and our starting place is OSS Note 93042. This note starts off with a nice description of what SAPFTP is: A client RFC application that is accessed via RFC from ABAP. But we also find out that in addition to SAPFTP being part of the kernel, it is also part of the SAPGui. That means that we can perform FTP commands originating from our R/3 Server or from a Client Workstation.
Well if this solution is accessed via RFC, then we must have to setup some RFC destinations. In fact we have two that we need; SAPFTP for Front-end FTP and SAPFTPA for access on the application server. Luckily we don’t even have to mess with setting these RFC destinations up in SM59. SAP has supplied a program, RSFTP005, to generate the destinations for us.
Now before we go off and start written code on our own to hit these FTP functions, why don’t we make sure everything is setup and working. Once again SAP has helped us out by providing us with a test program, RSFTP002. (In case you are wondering the FTP functionality and many other test programs are all contained in SAP Development Class SFTP). When we run this test, we get a set input parameters for the server, username password, etc. We want to start out simple and just make sure we are getting a connection. Therefore we will just execute the pwd command (Print Working Directory).
Your answer back should look something like this:
If you are wanting to see a list of FTP commands, try using the command HELP in place of PWD:
If something did go wrong during the test, I suggest that you active the trace option in SM59 for the FTP Destination. You can then use program RSFTP001 to display the current trace file.
Programming the FTP
Not only does the RSFTP002 program give us a test environment, but it also provides us with a programming example. We can see that the FTP functionality is really provided by a set of function modules all within the SFTP Function Group. We have the basic commands such as FTP_CONNECT, FTP_COMMAND, and FTP_DISCONNECT that can be strung together to create a complete file operation action. The FTP_COMMAND Function allows you to issue arbitrary FTP commands as long as the SAPFTP function, the Host, and the Destination server all support the command. Then you have the specialized functions such as FTP_R3_TO_SERVER, FTP_R3_TO_CLIENT, and FTP_CLIENT_TO_R3. This lets you take some data in memory and transfer it someplace else. This has the advantage of not having to write the data to the file system first and not to have to issue any FTP commands. However these functions are also limited to the scope described.
If you are already familiar with FTP in general, working with these function modules should not seem to difficult. The Connect, Command, Disconnect actions would seem somewhat self explanatory. So instead of looking at the entire program in detail let’s focus on two things that may be unfamiliar. First the program starts off with an ABAP Kernel System call to AB_RFC_X_SCRAMBLE_STRING. Well we don’t want to pass a potentially sensitive password openly. Therefore the FTP_CONNECT function module requires that the password be encrypted before it receives it. It is this System call that performs that one-way encryption. Now I checked a 620 SP42 system and in this example, SAP has replace the AB_RFC_X_SCRAMBLE_STRING with a function call to HTTP_SCRAMBLE. Unfortunately HTTP_SCRAMBLE doesn’t even exist in my 46C system. The only other thing that I wanted to point out about these function calls is the exporting parameter on the FTP_CONNECT. It passes back a parameter called handle. This handle then becomes an importing parameter to all subsequent calls: FTP_COMMAND and FTP_CLOSE. This handle is the pointer to the instance of FTP that we started with the FTP_CONNECT. This assures that we get reconnected to the same FTP session with each command we issue.
I thought I would share a few of the things that can be built using this FTP functionality. First off I didn’t want a bunch of ABAP programs directly working with the SAP FTP Function modules. As you can see there is already a difference in the examples for encrypting the password between 46C and 620. Therefore I thought it would be best to encapsulate all the FTP function in one custom ABAP OO Class. Not only did I get the opportunity to hid the inner SAP functionality and make it easy to switch out during upgrades, but I also get consistent error handling as well. I accept the User Name, Password, Host, and RFC Destination in during the Constructor of the class. I then store these values away in Protected Attributes. Each function module is then implemented as a Instance Method. The Password encryption functionality is then all tucked away nicely in the class. Also the calling program doesn’t have to worry about keeping track of the FTP handle either since it is an instance attribute as well.
Next I got really carried away. I wanted a way to record entire FTP scripts that could be filled with values at runtime and ran as a step in a background job. My company used to have many interfaces that ran frequently sending files all over the place. We needed a mechanism to monitor and support these file moves. This was really the root of this tool, but it also gives you an idea of how powerful these functions can be.
I hope that anyone interested in FTP from ABAP will find this resource useful. If anyone has any other resources that should be included here, feel free to post them.
CLASS zcl_ftp_base DEFINITION.
* Output file type
TYPES: BEGIN OF t_scratch,
data(1024) TYPE c,
END OF t_scratch,
t_str_tab TYPE STANDARD TABLE OF t_scratch.
CONSTANTS: co_crlf(2) TYPE x VALUE '0D0A'.
DATA: status TYPE c VALUE space.
METHODS: constructor IMPORTING im_user TYPE string im_pwd TYPE string
im_server TYPE string,
send_table_data IMPORTING im_file TYPE string
im_table TYPE t_str_tab,
get_table_data IMPORTING im_file TYPE string
EXPORTING ex_table TYPE t_str_tab,
send_string_data IMPORTING im_file TYPE string
im_string TYPE string,
get_string_data IMPORTING im_file TYPE string
EXPORTING ex_string TYPE string,
DATA: v_user(64) TYPE c,
v_pwd_clear(30) TYPE c,
v_pwd(64) TYPE c,
v_server(30) TYPE c,
v_filename TYPE rlgrap-filename,
v_handle TYPE i.
METHODS: pwd_scramble IMPORTING im_pwd TYPE c.
ENDCLASS. "ZCL_FTP_BASE DEFINITION
Any help using the HTTP* functions in the ZFTP function group will be greatly appreciated. Any one?
My first task is to develop a generalized ftp application to send data to the mainframe and then on to financial institutions. I have created an ABAP/4 test program with literals for the dest/host etc. And it works fine. I need more detail/guidance in creating the Class/Method/Function you have described to make this parameter driven and callable by other programs. I know this is a lot to ask, any help in pointing me in the right direction would be greatly appreciated. When I mention class creation to the existing staff they all say "Oh, we don't use or know anything about that object oriented stuff, we just right programs."
However it is true that you have to learn to walk before you run. There are some fundamentals to ABAP that are usefull to have down before you start in with ABAP OO. But I wouldn't let that hold you back for long.
I'm afraid that I wouldn't be able to teach you everything you would need to know to create a function module or a class in this posting. There was a nice weblog that was just posted the other day that had the steps to create your first simple class. I suggest you start there.
As far as my FTP class goes, I don't mind sending you the code for the class. My email address is already all over SDN (and spammers' lists) so just send me the address that you want the details sent to. My email is firstname.lastname@example.org.
Do you have any experience about this problem?
is it possible to pass it in parameter text, without length. This will help if you only have text in your table.
Do you know if the SAPFTP programs support secure FTP (over SSH or SSL) ?
According to note 795131, it is recommended to create an SSH port forward to secure the FTP.
If you haven't already worked out a solution good luck, I will be trying this soon as well.
did you try to send a string table in text mode with sapftp.. It doesn't give any error.. even creates a file on the ftp server but cannot transfer the contents of the table..
data: gt_file type standard table of string.
You should report this behavior through normal support channels (OSS) and see what they have to say.
Thanks 4 a Gr8 Blog helped me a lot.I am using FTP_CONNECT to ftp data from external server, to get data into internal table directly i used FTP_SERVER_TO_R3. when i am passing file path of external server to FNAME parameter i am getting error. Can u pls help with the flow of how to fetch data into internal table after ftp_connect.
Thanks in anticipation.
You will want to loop through your internal table and concatenate the fields together into string separated by CL_ABAP_CHAR_UTILITIES=>HORIZONTAL_TAB and CL_ABAP_CHAR_UTILITIES=>CR_LF. The process is really the same as when you are preparing an internal table for download as an HTTP response object attachment:
BSP Download to Excel in Unicode Format
That example works fine if you know you fields at design time, but if you want a generic solution that also handles conversion exits have a look at this Blog in the section PROCESS_XLS_DOWNLOAD:
Creating a BSP Extension for Downloading a Table
Hello, Please let me know if you have any solution for this.
You mean to say...
if a ftp command works in SM49/SM69 then it would work with FTP_CONNECT too !!
We are testing program RSFTP002 to send files from a specific directory in our R/3 appl. server to a FTP server. We are interesting in defining this process in a job. We are using the program with RFC destination SAPFTPA (in order to be executed in the appl. server) but don't know where we can define the server path we want to use (the directory in our appl. server where the files are placed).
Thanks in advance.
But to pieces of advice. First I don't believe that the RSFTP* programs are intended for productive usage. They don't really have enough error trapping in them and their list of commands (lenght and number of commands) is restrictive. You should probably only consider them as code samples for building your own FTP application.
Second - try building the FTP "script" from the command line of the application server first. Work out any problems with permissions, FTP command syntax, etc there before moving the commands into ABAP. The smaller number of possible places that could be a problem, the better.
I am using the FM FTP_SERVER_TO_R3 to get the data from external application server to internal table in text mode. But the text line is greater than 255 characters and it gets truncated from 256 characters.
Please do let me know if you have any solution for this.
I have coded a program to connect and FTP a file.
The programs works without any problems when run in foreground. Howvere, when run in backgound, the job fails with on FTP_CONNECT.
Have you come across this issue before ?
Well if this solution is accessed via RFC, then we must have to setup some RFC destinations. In fact we have two that we need; SAPFTP for Front-end FTP and SAPFTPA for access on the application server. Luckily we don't even have to mess with setting these RFC destinations up in SM59. SAP has supplied a program, RSFTP005, to generate the destinations for us.
If you are using SAPFTP that needs a connection to the SAPGUI. That seems the mostly likely cause of your problem. When running in the background you would have no connection to a client/SAPGUI.
I'm connecting to other system via FTP_connect ... and moving files from this system to SAP, but files are passed with incorrect format "DOS text" instead "UNIX text". Do you know if there is some command for that(command 'binary' is not working)? Or how can I solve it?
Thanks in advanced and regards!
I'm using the gateway parameters to connect to the proxy, but the function always returns an error saying that the user doesn't have access to the external FTP-server. I know the users and passwords are correct. Is it the correct way to use the gateway parameters? What is the account parameter for?
Everytime they are executing there arise masses of logfiles in root directory from SAP Central Instance host(SXF193). Their name is a number (2,3,4,...) and the content is constantly:
local directory now \\SXF193\Daten\SAP_PROBIS
What could be the cause of it and how we can prevent from it?
Please be kind enough to help me get this right. Thanks in advance.
What about password storage and handling?
I am going to set up a new program that will ftp files to several servers. Specification said to create a table to put all server information (the pgm will determine server based on functional information - a partner of sorts). This table is to include passwords to the servers.
I pointed out this is not a good way to do it since anybody can see the passwords this way.
What is the alternative?
- store pwd encrypted; when I read the record, I have to decrypt it to use it. Not good. Anybody with access to function modules can decrypt it.
- SAP's secure store cannot be used by custom applications
I have looked around SDN, but have not found a good solution.
It happened to me.. You are rigth... And DECRYPT FM doesn't work...
Hello everybody. Regarding to FM FTP_R3_TO_SAP . I'm facing a problem with XML files, the FM is working fine. But when I open the file migrated from FTP SERVER with CHROME, it throw me one error.
Extra content at the end of the document
If I open XML with the note pad, I could correct the error manually, it is due blank spaces at the end of XML, but I don´t know how the blank spaces arrive there!!! The original XML doesn´t have any error neither blank spaces. If manually delete blank spaces and save file is possible to open XML file with any internet explorer.
Do you have any ideas how to solve this??
This is my implementation for the FM with some personal comments.
*& FTP R3 TO SERVER
* Transferring the data from internal table to FTP Server
FORM ftp_r3_to_server TABLES it_table TYPE table USING p_file.
CLEAR: gv_code, gv_message.
DATA: lv_char TYPE i,
lv_len TYPE i,
lv_table TYPE string.
DESCRIBE TABLE it_table LINES lv_char.
lv_len = lv_char * 255.
PERFORM ftp_command USING 'set passive on' CHANGING it_result.
CALL FUNCTION 'FTP_R3_TO_SERVER'
handle = gv_dhdl
fname = p_file
blob_length = lv_len
* character_mode = space " Add blank spaces at end of file using TABLE BLOB
* character_mode = 'X' "Split with newline some XML nodes using TABLE TEXT
* text = it_table " works only with CHARACTER MODE = X otherwise create empty files
blob = it_table
tcpip_error = 1
command_error = 2
data_error = 3
others = 4.
gv_code = sy-subrc.
IF gv_code NE 0.
WHEN 1. gv_message = 'tcpip_error'.
WHEN 2. gv_message = 'command_error'.
WHEN 3. gv_message = 'data_error'.
WHEN OTHERS. gv_message = 'others'.
CLEAR: gv_code, gv_command.
CONCATENATE 'put' p_file INTO gv_command SEPARATED BY space.
PERFORM ftp_command USING gv_command CHANGING it_result.
Edgar, you'll have better luck opening a discussion to ask this instead of waiting for answers in the comments on a blog that is 12 years old. Wild guess though - could this be a problem?
Maybe your file length is inaccurate. Just simple logic...