Not downloading correctly files from APEX - sql

I have a little problem. I'm trying to download files from APEX application. The file downloads correctly but the browser doesn't recognize the file as a PDF. The code below works perfectly but lacks the recognition of the filetype.
create or replace PROCEDURE DOWNLOAD_LIST
(p_id_list in VARCHAR2) AS
v_mime VARCHAR2(2000);
v_length NUMBER;
v_file_name VARCHAR2(2000);
Lob_loc BLOB;
BEGIN
SELECT MIME_TYPE, BLOB_CONTENT, CODI ,DBMS_LOB.GETLENGTH(blob_content)
INTO v_mime,lob_loc,v_file_name,v_length
FROM table
WHERE ID_LIST = p_id_list;
-- set up HTTP header
-- use an NVL around the mime type and
-- if it is a null set it to application/octect
-- application/octect may launch a download window from windows
-- I've tried to put either pdf or octet. The database file has 'application/pdf' as mime_type
owa_util.mime_header( nvl(v_mime,'application/pdf'), FALSE );
-- set the size so the browser knows how much to download
htp.p('Content-length: ' || v_length);
-- the filename will be used by the browser if the users does a save as
--htp.p('Content-Disposition: attatchment; filename="'||replace(replace(substr(v_file_name,instr(v_file_name,'/')+1),chr(10),null),chr(13),null)|| '"');
htp.p('Content-Disposition: attatchment; filename="'||v_file_name||'.pdf'||'"');
-- close the headers
owa_util.http_header_close;
-- download the BLOB
wpg_docload.download_file( Lob_loc );
end DOWNLOAD_LIST;
Any help?

I think there is a slight issue with your content-length:
This is code I have in production and it does show a .pdf file properly using the browser built-in viewer:
PROCEDURE PR_SHOW_REPORT(io_blReport IN OUT BLOB,
i_vcContentDisposition IN VARCHAR2 DEFAULT 'inline',
i_vcFilename IN VARCHAR2 DEFAULT 'reportresult.pdf') IS
l_mime VARCHAR2 (255);
l_length NUMBER;
l_file_name VARCHAR2 (2000);
lob_loc BLOB;
BEGIN
OWA_UTIL.mime_header ('application/pdf', FALSE);
HTP.p ('Content-Length: ' || DBMS_LOB.GETLENGTH(io_blReport));
HTP.p ('Content-Disposition: ' || i_vcContentDisposition ||'; filename="' || i_vcFilename || '"');
OWA_UTIL.http_header_close;
WPG_DOCLOAD.download_file(io_blReport);
END;

It is not that simple; requires you to take some additional steps, as described in Creating PDF Reports with Oracle Application Express 5.0 and Oracle REST Data Services. Have a look, that tutorial takes 20 minutes to complete.

Related

Oracle APEX - An unexpected error with the following message occurred: application/pdf

I have a pl/sql procedure that that downloads a blob file in pdf format from Jasper Server. In this procedure I have the following code which prompts the browser to download the file to my local drive.
begin
v_param_val (1) := 1;
owa.init_cgi_env (v_param_val);
htp.flush;
-- clear the output buffer and reset response state
htp.init;
owa_util.mime_header ('application/pdf', false);--,'UTF-8'
htp.p('Content-length: ' || v_lob_length);
htp.p('Content-Disposition: attachement; filename="'||v_file||'"' );
owa_util.http_header_close;
htp.showpage ();
wpg_docload.download_file(v_blobref);
exception
when timeout_on_resource then
raise_application_error (-00051,'No response from the server.');
when others then
htp.p('other error : ' || sqlerrm);
end;
The problem is, I have an oracle apex page that I use to call my procedure. The page passes through the values to be used as parameters in the call of the procedure. I have a an apex process that makes this happen...
declare
v_report_name reports_data.report_name%type;
begin
v_report_name := s_reports_data.get_report_name(:P31_AVAILABLE_REPORTS);
s_reports_data.generate_jasper_report(v_report_name, :P31_DATE_TO,
:P31_RESEARCH_STATION, :P31_DATE_FROM);
end;
No the following error comes up when I try to call the procedure.
An unexpected error with the following message occurred: application/pdf
It seems like the following line is the cause of the error.
owa_util.mime_header ('application/pdf', false);--,'UTF-8'
Or the following line.
wpg_docload.download_file(v_blobref);
Looking in the docs, the function seems to need 3 parameters. Have you tried
owa_util.mime_header('application/pdf', false, 'UTF-8')
I finally got rid of the problem I had. This is how my code looks like now and it works perfectly fine.
begin
sys.htp.init;
sys.owa_util.mime_header (nvl(v_mime,'application/octet'), false, 'UTF-8');
sys.htp.p('Content-length: ' || v_lob_length);
sys.htp.p('Content-Disposition: attachement; filename="'||v_file||'"' );
sys.owa_util.http_header_close;
sys.wpg_docload.download_file(v_blobref);
apex_application.stop_apex_engine;
exception when others then
sys.htp.prn('error: '||sqlerrm);
apex_application.stop_apex_engine;
end;

Oracle Apex 4.2 custom file download error 404 Not Found or 403 Forbidden

I'am using Oracle Apex and I have a form to upload and store a file in a table via wwv_flow_files
In order to download the file I am using the procedure download_my_file
When I try to click the link and download the error 404 is raised
My environment is
Application Express 4.2.6.00.03
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
Oracle Rest Data Service 3.0.9.348.07.16
Thanks to any suggestion or advice
EDIT:
I check the stored procedure in Apex going Home->SQL Workshop->SQL Commands
If I copy and paste the code and instead of the parameter I use a known ID the execution is successful.
With the syntax download_my_file?p_file=#ID# url is
http://myhost:8080/ords/download_my_file?p_file=24255
the error 404 Not found is raised.
With the syntax #OWNER#.download_my_file?p_file=#ID# url is
http://myhost:8080/ords/mypdb.download_my_file?p_file=24255
the error 403 Forbidden is raised.
EDIT 2 : as requested here is the procedure
PROCEDURE download_my_file(p_file in number) AS
v_mime VARCHAR2(48);
v_length NUMBER;
v_file_name VARCHAR2(2000);
Lob_loc BLOB;
BEGIN
SELECT files_mime_type, files_content, files_name, dbms_lob.getlength(files_content)
INTO v_mime,lob_loc,v_file_name,v_length
FROM pub_db0files
WHERE files_id = p_file;
--
-- set up HTTP header
--
-- use an NVL around the mime type and
-- if it is a null set it to application/octect
-- application/octect may launch a download window from windows
owa_util.mime_header( nvl(v_mime,'application/octet'), FALSE );
-- set the size so the browser knows how much to download
htp.p('Content-length: ' || v_length);
-- the filename will be used by the browser if the users does a save as
htp.p('Content-Disposition: attachment; filename="'||replace(replace(substr(v_file_name,instr(v_file_name,'/')+1),chr(10),null),chr(13),null)|| '"');
-- close the headers
owa_util.http_header_close;
-- download the BLOB
wpg_docload.download_file( Lob_loc );
end download_my_file;
According to documentation «Fusion Middleware User's Guide for mod_plsql» regarding to wpg_docload.download_file we have to «add the line WindowsFileConversion Off to DAD entry.
Open the file ORACLE_INSTANCE\config\OHS\ohs1\mod_plsql\dads.conf.
Locate the DAD used to access the application.
Add the line WindowsFileConversion Off to this DAD entry.
Save the file.
Restart Oracle HTTP Server.
If you do not update the DAD configuration, you will experience failures while downloading documents which contain 0x5c in the filename. For example:
In Oracle Portal, you will see the download error:
Error: Document not found (WWC-46000)
When using mod_plsql against your own PL/SQL application, file downloads will result in the error:
HTTP-404 Not Found
https://docs.oracle.com/cd/E28280_01/portal.1111/e12041/concept.htm#YPMOD001

PL/SQL Oracle Directory

I am using util_file.fopen to import a .txt file into a database. However, I do not want hardcode the directory. Is there a way save the current directory to a variable or log the path? That way I can create an oracle directory that is the current directory, and util_file.fopen will always open the .txt file that is in the directory that I am running my pl/sql from
I know that "HOST CD" will show me my current directory, but I have not been able to save it to a variable or log it
Thanks
Create multiple directory objects:
CREATE DIRECTORY DIRECTORY_1 AS '/some/path';
CREATE DIRECTORY DIRECTORY_2 AS '/some/other/path';
CREATE DIRECTORY DIRECTORY_3 AS '/yet/another/path';
Assign the name of the directory to a variable:
strDirectory_to_use := 'DIRECTORY_1';
Use the variable when opening a file:
-- References /some/path/filename.txt
aFile := UTL_FILE.FOPEN(strDirectory_to_use, 'filename.txt', 'r');
Change the variable to contain the name of a different directory object:
strDirectory_to_use := 'DIRECTORY_2';
Now when you use the variable in a call to UTL_FILE.FOPEN it will look at the directory pointed to by directory object DIRECTORY_2:
-- References /some/other/path/filename.txt
aFile := UTL_FILE.FOPEN(strDirectory_to_use, 'filename.txt', 'r');
Best of luck.
If you want to use current working directory you can create that directory dinamically. Problem is when multiple processes try to access your procedure.
If you can ensure that only one process is using procedure at same time you can do:
create or replace procedure (mypath varchar2) as
begin
execute immediate 'CREATE OR REPLACE DIRECTORY DIRECTORY_1 AS ' || mypath;
aFile := UTL_FILE.FOPEN(DIRECTORY_1, 'filename.txt', 'r');
end;
/
If you can't ensure that only one thread will call procedure at same time it gets tricky. You can try to lookup directory.
create or replace procedure (mypath varchar2) as
dirname varchar2;
begin
select DIRECTORY_NAME into dirname from dba_directories where DIRECTORY_PATH = mypath;
if (dirname is null) then
dirname := substr(replace(replace(replace(replace(dirname,'\',''),':',''),'/',''),'.',''),1,30);
execute immediate 'CREATE OR REPLACE ' || dirname || ' AS ' || mypath;
end if;
aFile := UTL_FILE.FOPEN(dirname, 'filename.txt', 'r');
end;
/

Wrapping a Stored Procedure

I have created a Stored Procedure in Oracle (Via TOAD).
I need to deliver this procedure to some other developers. All is need to do is Wrap the procedure so that at basic level he/she should not be able to view the code.
At the same time, the developer should be able to create the procedure and execute/test it.
my procedure is saved in say FileName.sql whose content are like:
Create or Replace Procedure
IS
Declaration
Begin
Code
End;
Now i want this FileName.sql to be wrapped. So that the encrypted file can be send to other to check in different environment.
Please help me in how to wrap, and then how the other guy will be able to create the procedure, and execute the same.
Thanks in advance.
The Oracle WRAP utility does exactly that - allows you to encode a stored procedure in a form suitable for shipping.
The wrapped code is as portable as source code, but cannot be examined as plain text.
You will need access to the command line using a suitable system user (i.e. one that has access to the Oracle binary commands e.g. sqlplus etc.) and the basic syntax is:
wrap iname=input_file [ oname=output_file ]
If you do not specify any extensions, the default for input is .sql and output is .plb
Once you have generated a .plb file, you can execute it against the database to create your stored procedure.
See:
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/wrap.htm#LNPLS016
http://docs.oracle.com/cd/B10500_01/appdev.920/a96624/c_wrap.htm
WARNING
WRAPencoded procedures are not completely secure - it is possible to "unwrap" them.
A better way of using WRAP is to put the procedure(s) you wish to protect in a package and WRAP the package definition.
Let's say your procedure is:
CREATE OR REPLACE PROCEDURE PR_OUTPUT_TEXT(
P_TYPE IN CHAR,
P_TEXT IN VARCHAR2
) IS
V_TYPE CHAR(3) := UPPER(P_TYPE);
BEGIN
IF V_TYPE = 'LOG' THEN
APPS.FND_FILE.PUT_LINE(APPS.FND_FILE.LOG, TO_CHAR(SYSDATE,'HH24:MI:SS')||' - '||P_TEXT);
ELSE
APPS.FND_FILE.PUT_LINE(APPS.FND_FILE.OUTPUT, P_TEXT);
END IF;
END PR_OUTPUT_TEXT;
you would normally call it using:
EXECUTE PR_OUTPUT_TEXT('LOG', 'Kittehz!!!')
In a package you would define the package body and the procedure thus:
CREATE OR REPLACE PACKAGE BODY USER.MYPACKAGE AS
PROCEDURE PR_OUTPUT_TEXT(
P_TYPE IN CHAR,
P_TEXT IN VARCHAR2
) IS
BEGIN
IF V_TYPE = 'LOG' THEN
APPS.FND_FILE.PUT_LINE(APPS.FND_FILE.LOG, TO_CHAR(SYSDATE,'HH24:MI:SS')||' - '||P_TEXT);
ELSE
APPS.FND_FILE.PUT_LINE(APPS.FND_FILE.OUTPUT, P_TEXT);
END IF;
END PR_OUTPUT_TEXT;
END MYPACKAGE;
and you would call the package using:
EXECUTE USER.MYPACKAGE.PR_OUTPUT_TEXT('LOG', 'ERMAHGERD KERTERNS!!!')
From documentation, to be precise, this is what you need to do :
Running the wrap Utility
For example, assume that the wrap_test.sql file contains the following:
CREATE PROCEDURE wraptest IS
TYPE emp_tab IS TABLE OF employees%ROWTYPE INDEX BY PLS_INTEGER;
all_emps emp_tab;
BEGIN
SELECT * BULK COLLECT INTO all_emps FROM employees;
FOR i IN 1..10 LOOP
DBMS_OUTPUT.PUT_LINE('Emp Id: ' || all_emps(i).employee_id);
END LOOP;
END;
/
To wrap the file, run the following from the operating system prompt:
wrap iname=wrap_test.sql
The output of the wrap utility is similar to the following:
PL/SQL Wrapper: Release 10.2.0.0.0 on Tue Apr 26 16:47:39 2005
Copyright (c) 1993, 2005, Oracle. All rights reserved.
Processing wrap_test.sql to wrap_test.plb
If you view the contents of the wrap_test.plb text file, the first line is CREATE PROCEDURE wraptest wrapped and the rest of the file contents is hidden.
You can run wrap_test.plb in SQL*Plus to execute the SQL statements in the file:
SQL> #wrap_test.plb
After the wrap_test.plb is run, you can execute the procedure that was created:
SQL> CALL wraptest();
More information in docs

Understanding Utl_file

So I am changing the procedure of this parse_file 'clean_files_up procedure'. I have coded the changes but after testing I realized
I am actually having a hard time understanding what is going on. I have never worked with parsing a file or utl_file so I don't entirely
undrestand the concept.
So in summary, we need it to look for a file called Files20130807.xxx with the current sysdate from a directory called NEWFILE_DIRECTORY.
IF there is no file meaning that it can not find a file matching the current sysdate it needs to run the orignial file which is located
in a different directory called ORIGINALFILE_DIRECTORY and then go the the end of the procedure. If there is a file that matches the
current sysdate then it needs to continue through the procedure. When it gets to actually opening up the file it will open the file that
matches the current sysdate from NEWFILE_DIRECTORY and then will parse the file, otherwise if the current file from NEWFILE_DIRECTORY
is open then it will need to open the original file located in ORIGNIALFILE_DIRECTORY and then will parse that file instead.
PROCEDURE clean_files_up IS
v_fileName VARCHAR2(20) := Files || to_char(sysdate, 'YYYYMMDD') || '.xxx';
v_inFile utl_file.file_type;
v_outFile utl_file.file_type;
v_line VARCHAR2(2000);
v_newLine VARCHAR2(2000);
v_count NUMBER := 1;
BEGIN
--No Files found for current date
IF (substr(v_fileName, 6, 8)) <> to_char(sysdate, 'YYYYMMDD') THEN
v_inFile := utl_file.fopen('ORIGINALFILE_DIRECTORY', 'OriginalFile.xxx', 'r');
RETURN; --go to end of procedure
END IF;
v_inFile := utl_file.fopen ('NEWFILE_DIRECTORY', 'v_fileName', 'r');
IF utl_file.is_open(v_inFile) THEN
v_outFile := utl_file.fopen('ORIGINALFILE_DIRECTORY',
'OriginalFile.xxx',
'W');
LOOP
BEGIN
utl_file.get_line(v_inFile, v_line);
IF v_line IS NULL THEN
EXIT;
END IF;
IF v_count > 1 THEN
get_new_csv_line(v_line, v_newLine);
utl_file.put_line(v_outFile, v_newLine);
utl_file.fflush(v_outFile);
END IF;
v_count := v_count + 1;
EXCEPTION
WHEN no_data_found THEN
EXIT;
END;
END LOOP;
utl_file.fclose(v_outFile);
END IF;
EXCEPTION
WHEN OTHERS THEN
Condition;
END clean_files_up;
Questions:
So I need to create a new directory called NEWFILE_DIRECTORY located in some file path /xxx/xxx/xxx that has the list of files
like ; Files20130804.xxx, Files20130805.xxx, Files20130806.xxx, Files20130807 locted in it. I don't know
where inside of this procedure I would have the new directory being created or even if I can create it within the procedure
CREATE OR REPLACE DIRECTORY newfile_directory in as '/xxx/xxx/xxx'
2.. I need to read in these files to make sure that it matches the sysdate otherwise it needs to run the original file and
then go to the end of the proceudre. This part is the IF statement right after the BEGIN. I am just confussed in how it knows
to look in the NEWFILE_DIRECTORY to find the matching file name Files20130807.xxx to see if it is a match or not.
3.. This is a similiar question to #2 but how does (after the first End IF;) it know where the file path for NEWFILE_DIRECOTRY
and ORIGINALFILE_DIRECTORY is located without giving or defining a path ?
4.. Lastly when testing the code I noticed that after it reads in the v_inFile := utl_file.fopen ('NEWFILE_DIRECTORY', 'v_fileName', 'r');
(right after the first End IF;) it goes down to the exception without continuing through the if and to the loop.
I would really appreciate it someone could answer theses questions are at least help to understand what is going on. Also
if I need to clearfiy and of the questions (1-4) I can do that.
Answers on your questions:
1) Following code creates link from Oracle internally defined directory (can see them by selecting data from DBA_DIRECTORIES) to file system directory.
CREATE OR REPLACE DIRECTORY NEWFILE_DIRECTORY AS '/xxx/xxx/xxx'
If path '/xxx/xxx/xxx' already exists in file system, then this will be correct way.
2) If I understand you correctly, then you must check that in NEWFILE_DIRECTORY exists file with current date in it's name. It can be done with following function:
FUNCTION check_if_file_exists
(p_file_name IN VARCHAR2
,p_file_dir IN VARCHAR2)
RETURN BOOLEAN
IS
v_file utl_file.file_type;
BEGIN
v_file := utl_file.fopen(p_file_dir, p_file_name, 'R');
IF utl_file.is_open(v_file) THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
EXCEPTION
WHEN UTL_FILE.invalid_path THEN
RETURN FALSE;
WHEN utl_file.invalid_operation THEN
RETURN FALSE;
END check_if_file_exists;
And your first if will be:
IF check_if_file_exists(v_fileName, 'NEWFILE_DIRECTORY') THEN
3) You can create DB directories (mapping for DB to find file system path) by "CREATE OR REPLACE DIRECTORY" (see #1)
4) You pass parameter as string value 'v_fileName' not variable v_fileName. Correct code would be:
v_inFile := utl_file.fopen ('NEWFILE_DIRECTORY', v_fileName, 'r');
Janis Baiza thank you for the answer it really helped me to understand what was going on.
I actually found that this will check to see if the file exists in the current directory as well and if it does then outputs that it exists and if it doesn't then out put it doesn't exist and run the original file then return to end of procedure.
utl_file.fgetattr ('NEWFILE_DIRECTORY', v_fileName, v_check_fileEX, v_fLength, v_Bsize );
IF v_check_fileEX THEN
dbms_output.put_line('file exists');
END IF;
IF NOT v_check_fileEX THEN
dbms_output.put_line('file does not exist');
v_inFile := utl_file.fopen('ORIGINALFILE_DIRECTORY', 'OriginalFile.xxx', 'r');
RETURN;
END IF;