Browsing "Older Posts"

Hide Interactive Report filter dynamically after page load

Von Tobias Arnhold → 2.28.2011
To hide IRR filters always after the page load just use this little JS code inside a dynamic action (event: "Page Load")

/* Hide IRR filter after page load*/
if( $('#apexir_CONTROLS_IMAGE').attr("src") == '/i/minus.gif') {
gReport.toggle_controls($x('apexir_CONTROL_PANEL_CONTROL'));
}

Result:

Interactive Report Header problem with multiple lines

Von Tobias Arnhold →
There is a bug/misbehavior inside the IRR column headers in APEX 4. When you create column names with linebreaks (using the <br> tag) inside then the background color changes to a grey background on the second line.
Workaround: Add this script to your IR region header:
<style>
/* IRR Header Fix */
.apexir_WORKSHEET_DATA th{background-color:#828282!important;}
</style>


Bug view:

Fixed view:


There is a forum entry as well: http://forums.oracle.com/forums/thread.jspa?threadID=1981024
APEX-AT-WORK no image

ORA-20503 im APEX Application Builder

Von Tobias Arnhold → 2.25.2011
Falls Sie auf den Fehler ORA-20503 während der Arbeit im APEX Application Builder treffen, dann wird ihnen dieser Blogeintrag hoffentlich viel Ärger ersparen.

Beispielfälle:

ORA-20503: Die aktuelle Version der Daten in der Datenbank wurde geändert, seit der Benutzer einen Updateprozess eingeleitet hat. Aktuelle Prüfsumme (Checksum) = "CE59A26EB14199C787195DCC947CFC04" Anwendungs-Prüfsumme (Checksum) = "8D8F85130213A161B73628D3D0B3F56E" Zeile der Tabelle WWV_FLOW_FEEDBACK konnte nicht verarbeitet werden.



ORA-20503: Die aktuelle Version der Daten in der Datenbank wurde geändert, seit der Benutzer einen Updateprozess eingeleitet hat. Aktuelle Prüfsumme (Checksum) = "076BC396EB2BA9DEF778E5B684CFA2B5" Anwendungs-Prüfsumme (Checksum) = "3EF59F3E445142B8A971E94C9FFABB59" Fehler beim Verarbeiten von Zeile.

Wahrscheinlich haben Sie mehrere Sprachen in ihrer APEX Umgebung installiert. Beispielsweise: Englisch, Deutsch.

Nun gibt es in APEX 4.0 das Phänomen, dass während der Laufzeit sich die Sprache im Application Builder von Englisch auf Deutsch einfach ändert,
obwohl unter "Home" Englisch als Sprache eingestellt ist.
Der Grund des Problems liegt wohl an ihrer eingestellten "Browser Language", die für gewöhnlich auf Deutsch eingestellt ist.

In diesem Zusammenhang kommt der ORA-20503 Fehler zustande. Ich denke das dies ein Bug in der aktuellen Version ist.
Es ist recht einfach diesen Fehler zu beheben:
- Melden Sie sich am APEX Application Builder an.
- Unter "Home" Startseite (1000) können Sie am rechten Seitenrand die Sprache einstellen "Language"
- Stellen Sie die Sprache auf "Deutsch" um
- Gehen Sie in das Item (bzw. in den fehlerhaften Bereich) und speichern Sie dieses erneut ab.
- Es sollte alles funktionieren!
- Alternativ können Sie auch jederzeit mit einem alternativen Browser die Daten abspeichern, der Fehler bleibt aber in ihrem Standardbrowser existent.

Bei mir trat dieser Fehler bisher nur im Firefox auf. Ich entwickle allerdings auch nur ausschließlich in diesem. :)

Ich hoffe die Sprachsteuerung wird in APEX 4.1 etwas verbessert, so dass weder der ORA-20503 auftritt noch sich einfach die Umgebungssprache ändert.

In den folgenden Forum Beiträgen finden Sie weitere Informationen zum Fehler:
http://forums.oracle.com/forums/thread.jspa?messageID=9299655
http://forums.oracle.com/forums/thread.jspa?messageID=9368275
APEX-AT-WORK no image

Clear the page cache with PL/SQL

Von Tobias Arnhold → 2.24.2011
I just stumbled into a problem where I needed to clear the page cache inside an APEX PL/SQL process.

It is quite easy if you know how:

APEX_UTIL.CLEAR_PAGE_CACHE (160);

-- APEX_UTIL.CLEAR_PAGE_CACHE (
-- p_page IN NUMBER DEFAULT NULL);
-- Description: This procedure removes session state for a given page for the current session.


There are two other similar functions:
CLEAR_APP_CACHE, CLEAR_USER_CACHE

For more information watch the documentation for APEX_UTIL:
http://download.oracle.com/docs/cd/E10513_01/doc/apirefs.310/e12855/apex_util.htm#BABCIAFJ
APEX-AT-WORK no image

Freeze panes example

Von Tobias Arnhold → 2.23.2011
Just saw the nice looking freeze panes example of Andy (ATD) in the Oracle APEX forum.
It is to good to not being mentioned.

Example:
http://apex.oracle.com/pls/otn/f?p=267:47

For more information about the implementation watch this forum post:
http://forums.oracle.com/forums/thread.jspa?threadID=2180543
APEX-AT-WORK no image

Sichere URLs mit einem Application Process erstellen

Von Tobias Arnhold → 2.15.2011
Wenn Sie eine APEX Anwendung mit Session State Protection verwenden, dann muss jeder Request entsprechend ihrer Einstellungen mit einem sicheren Hash-Schlüssel versendet werden. Wie Sie dies während der Laufzeit mit einem Application Process erstellen können, beschreibt dieser Artikel:

Was ist Session State Protection und für was brauch ich diese Funktion in APEX Anwendungen?
SSP schützt vor dem manuellen ändern der Browser URL durch den Endbenutzer, so dass dieser nicht einfach eine falsche ID abfragen oder beliebige Page-/Applikations-Variablen während der Laufzeit ändern kann.
- SSP muss explizit über Shared Components > Session State Protection aktiviert werden.
- SSP kann für jede Seite und jedes Item individuell definiert werden.
- SSP macht die Entwicklung nicht einfacher aber wesentlich sicherer.
- SSP schützt nicht automatisch vor allen feindlichen Attacken gegen eine APEX Anwendung.

Alles wichtige rund um SSP finden Sie in der APEX Dokumentation:
http://download.oracle.com/docs/cd/E17556_01/doc/user.40/e15517/sec.htm#HTMDB12002

Ein paar nützliche Links zum Thema SSP und APEX Sicherheit allgemein:
http://www.oracle.com/global/de/community/tipps/securitytipps/index.html
http://www.talkapex.com/2009/05/apex-page-access-protection-and-session.html
http://dgielis.blogspot.com/2007/03/session-state-protection-and-url.html
http://apps2fusion.com/at/64-kr/400-preventing-url-tampering-using-apex-session-state-protection

Im Normalfall generiert APEX sichere URL's automatisch, sobald SSP aktiviert wurde. Leider ist dies in Verbindung mit manuell erstelltem Code nicht der Fall. Um eigene sichere URL's zu definieren, müssen Sie die URL mit der PL/SQL Funktion apex_util.prepare_url validieren und Sie erhalten die sichere URL als Rückgabewert. Dies funktioniert exzellent bei dynamisch erstelltem PL/SQL Code. Wenn Sie dies über eine Javascript Funktion verwenden möchten, dann brauchen Sie entweder eine Dynamic Action oder einen Application Process Aufruf, der ihnen die sichere URL zurück liefert. Ein Beispielfall könnte ein dynamischer Javascript Baum sein, dieser zur Seiten-Navigation verwendet wird. Die Baum-Daten würden via AJAX dynamisch nachgeladen werden. Bsp: ExtJS in APEX
(Dieses Beispiel zeigt nur ein mögliches Szenario, es enthält kein SSP und kein AJAX.)

Die Frage ist nun: Wie bauen Sie solch einen Prozess!?

Fügen Sie diesen Code ihrem Javascript Prozess hinzu:

/* Call Application Process um eine Secure URL zu erstellen */
v_no_sec_url = 'f?p=25500:8:3521997579041922::NO::P8_E_ID:131'
/* Statt der dargestellten URL wuerden Sie eine Javascript Variable verwenden, diese die URL enthaelt. */

/* Aufruf eines Application Prozess ueber Javascript: http://www.packtpub.com/article/ajax-implementation-apex */
var v_get_sec_url = new htmldb_Get(null, $v('pFlowId'),'APPLICATION_PROCESS=AP_SECURE_URL', $v('pFlowStepId'));

/* Uebergabe Parameter 1 und 2 definieren */
v_get_sec_url.addParam('x01',v_no_sec_url);
v_get_sec_url.addParam('x02','SESSION');

v_sec_url = v_get_sec_url.get(); /* Uebergebe APEX Wert an Javascript Variable */
/* alert(v_sec_url); */

window.location.href = v_sec_url /* Seite mit neuem HREF aktualisieren */

Nun definieren Sie den Application Process - AP_SECURE_URL:

DECLARE
v_part1 varchar2(100);
v_part2 varchar2(1000);
v_url varchar2(1200);
BEGIN
/* Teile URL */
v_part1 := substr(wwv_flow.g_x01,1,instr(wwv_flow.g_x01,'f?p')-1);
v_part2 := substr(wwv_flow.g_x01,instr(wwv_flow.g_x01,'f?p'));

/* Erstelle sichere URL */
/* Hilfe: http://apex.oracle.com/i/doc/AEAPI/apex_util074.htm */
v_url := APEX_UTIL.PREPARE_URL(p_url => v_part2,
p_checksum_type => wwv_flow.g_x02);

/* Return mit Teil 1 und Secure URL */
htp.p(v_part1 || v_url);
END;

Die erstellte URL ist aber nur die halbe Miete. Für jeden AJAX Call (Bsp: Klick auf Baum Subeinträge) muss sichergestellt werden, dass der Endbenutzer die übergebenen Parameter auch wirklich verwenden darf.
Deswegen müssen Sie ein oder mehrere Validierungs-Checks in die Prozedur integrieren:

DECLARE
v_part1 varchar2(100);
v_part2 varchar2(1000);
v_sec_url varchar2(1200);

/* Parameter fuer eigene URL Validierung */
v_url_validation number;
v_url_parameter varchar2(200);
v_url_page varchar2(10);
BEGIN
/* Teile URL */
v_part1 := substr(wwv_flow.g_x01,1,instr(wwv_flow.g_x01,'f?p')-1);
v_part2 := substr(wwv_flow.g_x01,instr(wwv_flow.g_x01,'f?p'));

/* Wichtig: Individuelle URL Validierung fuer uebergebene Parameter */
/* ----------------------------------------------------------------------- */
v_url_parameter := substr(v_part2,
instr(v_part2,':',1,7)+1
);
v_url_page := substr(v_part2,
instr(v_part2,':',1,1)+1,
instr(v_part2,':',1,2)-instr(v_part2,':',1,1)-1
);

if (v_url_parameter in (10,20,30,40,50)
and v_url_page = 10)
or (v_url_parameter in (60,70,80,90,100)
and v_url_page = 10
and :APP_USER = 'TARNHOLD')
then
v_url_validation := 1;
else
v_url_validation := 0;
end if;
/* ----------------------------------------------------------------------- */

if v_url_validation = 1 then
/* Wenn OK, dann erstelle sichere URL */
/* Hilfe: http://apex.oracle.com/i/doc/AEAPI/apex_util074.htm */
v_sec_url := APEX_UTIL.PREPARE_URL(p_url => v_part2,
p_checksum_type => wwv_flow.g_x02);

/* Return mit Teil 1 und Secure URL */
htp.p(v_part1 || v_sec_url);
else
/* Bei Validierungsfehlern (falsche Parameter) auf Anmeldeseite verlinken */
htp.p(v_part1 || 'f?p=' || :APP_ID || ':101');
end if;
EXCEPTION
WHEN OTHERS THEN
/* Bei unbekannten Fehler auf Anmeldeseite verlinken */
htp.p(v_part1 || 'f?p=' || :APP_ID || ':101');
END;

Solch eine Prozedur muss alle nicht erlaubten Fremdeingaben abfangen, um die Sicherheit in ihrer Anwendung zu gewährleisten.
Deswegen zeige ich ihnen eine noch sicherere Beispiel-Prozedur, damit eine mögliche Risikominimierung für feindliche Attacken und der Aufwand dessen deutlich wird, der für eine solche Prozedur notwendig ist:

DECLARE
v_part1 varchar2(100);
v_part2 varchar2(1000);
v_sec_url varchar2(1200);

/* Parameter fuer eigene URL Validierung */
v_url_validation number;
v_url_app varchar2(100);
v_url_page varchar2(100);
v_url_request varchar2(100);
v_url_debug varchar2(3);
v_url_clearcache varchar2(100);
v_url_param_name varchar2(200);
v_url_param_val varchar2(200);
-- v_url_printer varchar2(200);
BEGIN
/* Teile URL */
v_part1 := substr(wwv_flow.g_x01,1,instr(wwv_flow.g_x01,'f?p')-1);
v_part2 := substr(wwv_flow.g_x01,instr(wwv_flow.g_x01,'f?p'));

/* Wichtig: Individuelle URL Validierung fuer uebergebene Parameter */
/* ----------------------------------------------------------------------- */
v_url_app := substr(v_part2,
instr(v_part2,'=',1,1)+1,
instr(v_part2,':',1,1)-instr(v_part2,'=',1,1)-1
);
v_url_page := substr(v_part2,
instr(v_part2,':',1,1)+1,
instr(v_part2,':',1,2)-instr(v_part2,':',1,1)-1
);
v_url_request := substr(v_part2,
instr(v_part2,':',1,3)+1,
instr(v_part2,':',1,4)-instr(v_part2,':',1,3)-1
);
v_url_debug := substr(v_part2,
instr(v_part2,':',1,4)+1,
instr(v_part2,':',1,5)-instr(v_part2,':',1,4)-1
);
v_url_clearcache := substr(v_part2,
instr(v_part2,':',1,5)+1,
instr(v_part2,':',1,6)-instr(v_part2,':',1,5)-1
);
v_url_param_name := substr(v_part2,
instr(v_part2,':',1,6)+1,
instr(v_part2,':',1,7)-instr(v_part2,':',1,6)-1
);
v_url_param_val := substr(v_part2,
instr(v_part2,':',1,7)+1
);
/* TEST
htp.p( 'v_url_app: ' || v_url_app || ' ,v_url_page: ' || v_url_page || ' ,v_url_request: ' || v_url_request
|| ' ,v_url_debug: ' || v_url_debug || ' ,v_url_clearcache: ' || v_url_clearcache
|| ' ,v_url_param_name: ' || v_url_param_name || ' ,v_url_param_val: ' || v_url_param_val
);
*/

if v_url_app IN (:APP_ID,:APP_ALIAS)
AND v_url_request is null
AND v_url_debug = 'NO'
AND (
v_url_page IN ('1','2','3','4','5')
and v_url_param_name is null
and v_url_param_val is null
OR v_url_page = '10'
and v_url_param_name IN ('P10_MFD_ID')
and v_url_param_val IN (1,14,15,16,17,19) /* Koennte auch ein Sub Select sein*/
and length(v_url_param_val)-length(replace(v_url_param_val,',','')) = 0
OR v_url_page = '20'
and v_url_clearcache = '20'
and v_url_param_name IN ('P20_KLT_ID')
and v_url_param_val IN (100,200,300,400,500,600) /* Koennte auch ein Sub Select sein*/
and length(v_url_param_val)-length(replace(v_url_param_val,',','')) = 0
OR v_url_page = '30'
and v_url_clearcache = '30'
and v_url_param_name IN ('P30_KLS_ID,P30_KLS_PAR1')
and substr(v_url_param_val,1,instr(v_url_param_val,',')-1) IN (1000,2000,3000,4000,5000,6000)
and length(v_url_param_val)-length(replace(v_url_param_val,',','')) = 1
)
then
v_url_validation := 1;
else
v_url_validation := 0;
end if;
/* ----------------------------------------------------------------------- */

if v_url_validation = 1 then
/* Wenn OK, dann erstelle sichere URL */
/* Hilfe: http://apex.oracle.com/i/doc/AEAPI/apex_util074.htm */
/* Der Parameter: p_checksum_type sollte fest über die Prozedur gesteuert werden */
v_sec_url := APEX_UTIL.PREPARE_URL(p_url => v_part2,
p_checksum_type => 'SESSION');

/* Return mit Teil 1 und Secure URL */
htp.p(v_part1 || v_sec_url);
else
/* Bei Validierungsfehlern (falsche Parameter) auf Anmeldeseite verlinken */
htp.p(v_part1 || v_part2);
-- htp.p(v_part1 || 'f?p=' || :APP_ID || ':101');
end if;
EXCEPTION
WHEN OTHERS THEN
/* Bei unbekannten Fehler auf Anmeldeseite verlinken */
htp.p(v_part1 || 'f?p=' || :APP_ID || ':101');
END;

Was schließt man daraus: Schönheit kann ganz schön teuer (aufwendig) werden. :) Wer hätte das gedacht.

Fazit: Die Verwendung von SSP mit Standard APEX Funktionalität bietet ohne großes Wissen die meiste Sicherheit. Bei der Verwendung von eigenen Erweiterungen, muss auf die oben beschriebenen Sicherheitsaspekte Wert gelegt werden. Deswegen ist es auch von Vorteil solche Erweiterungen in Plug-Ins auszulagern. Mehr Infos dazu erhalten Sie in meinem letzten APEX Community Beitrag: HowTo: APEX 4.0 Dynamic Action Plugins

Wenn Sie Unterstützung bei APEX Security Themen benötigen, dann können Sie sich natürlich immer an mich (Tobias Arnhold - tobias-arnhold@hotmail.de) wenden. Ein wahrer Kenner auf dem Gebiet "APEX Security" ist Denes Kubicek, dieser auch spezielle Schulungen zum Thema APEX anbietet.
APEX-AT-WORK no image

UILayout: Hide half loaded elements

Von Tobias Arnhold → 2.14.2011
One of the problems of an layout extension is the initialization time.
Normally the UILayout needs a couple of seconds to initialize (1-3). Depending on your server connection, your client hardware and your browser (IE6 is slow, FF 3.6 is fast).

To show a similar loading frame like the ExtJS Loading Icon http://apex.oracle.com/pls/apex/f?p=65555:1 use this trick:

Add the following code to the beginning of your Page Template Body or add a new HTML region (No template) on page 0:

<div style="width: 100%; height: 100%; position: absolute; left: 0pt; top: 0pt; background-color: rgb(255, 255, 255); z-index: 4000; opacity: 0.8; display: block;" id="loadingBackground">
<div style="height: auto;left: 50%;position: absolute;top: 50%;text-align: center; color: #555555;font-size: 18px;font-family:Arial,Helvetica,Geneva,sans-serif;padding:8px;42px;"> ... Loading ... </div>
</div>


After the initialization of the UILaoyut plug-in use the LoadingIcon plug-in with the option "Stop LoadingIcon"

The initialization feels much smoother now.

Example: http://apex.oracle.com/pls/apex/f?p=AAW_PLUGINS:UILAYOUT_PLUGIN
APEX-AT-WORK no image

Hide/Show APEX items and labels with jQuery

Von Tobias Arnhold → 2.02.2011
To hide or show items and labels with jQuery use this syntax:

$('#P1_NAME').hide();
$('#P1_NAME').parent().hide();
$('#P1_COMPANY').show();
$('#P1_COMPANY').parent().show();

Update 06.02.2011:
Peter mentioned right that this example only works when your item label is set to above!

Short way:

$('#P1_NAME').hide().parent().hide();
$('#P1_COMPANY').show().parent().show();

@Jaydip
"I want to remove those hidden item space. Is it possible by using your method?" - No
I guess you would need to move these hidden items to another place and move them back when they are not hidden. With jQuery you could use appendTo(). I don't know if it works or not? But you would need ID's for your regions.