#if (!defined $PApp::_compiled) { eval do { local $/; }; die if $@ } 1; #__DATA__ ##line 4 "(PApp.pm)" ########################################################################## ## All portions of this code are copyright (c) 2003,2004 nethype GmbH ## ########################################################################## ## Using, reading, modifying or copying this code requires a LICENSE ## ## from nethype GmbH, Franz-Werfel-Str. 11, 74078 Heilbronn, ## ## Germany. If you happen to have questions, feel free to contact us at ## ## license@nethype.de. ## ########################################################################## =head1 NAME PApp - multi-page-state-preserving web applications =head1 SYNOPSIS I =head1 DESCRIPTION PApp is a complete solution for developing multi-page web applications that preserve state I page views. It also tracks user id's, supports a user access system and provides many utility functions (html, sql...). You do not need (and should not use) the CGI module. Advantages: =over 4 =item * Speed. PApp isn't much slower than a hand-coded mod_perl handler, and this is only due to the extra database request to fetch and restore state, which typically you would do anyway. To the contrary: a non-trivial Apache::Registry page is slower than the equivalent PApp application (or much, much more complicated). =item * Embedded Perl. You can freely embed perl into your documents. In fact, You can do things like these:

Names and amounts

<: my $st = sql_exec \my($name, $amount), "select name, amount from ...", while ($st->fetch) {?> Name: $name, Amount: $amount

<:} :>


That is, mixing html and perl at statement boundaries. =item * State-preserving: The global hash C<%S> is automaticaly preserved during the session. Everything you save there will be available in any subsequent pages that the user accesses. =item * XML. PApp-applications are written in XML. While this is no advantage in itself, it means that it uses a standardized file format that can easily be extended. PApp comes with a DTD and a vim syntax file, even ;) =item * Easy internationalisation. I18n has never been that easy: just mark you strings with __C<>"string", either in html or in the perl source. The "poedit"-demo-application enables editing of the strings on-line, so translaters need not touch any text files and can work diretcly via the web. =item * Feature-Rich. PApp comes with a I of small-but-nice-to-have functionality. =back To get a quick start, read the F module, the F module, the F module and the F description of the papp file format. Also, have a look at the F subdirectory of the distribution, which will have some tutorials in sdf and html format. =cut package PApp; use 5.006; use utf8; no bytes; no warnings; # imports use Carp; use FileHandle (); use File::Basename qw(dirname); use PApp::Storable; use Compress::LZF qw(:compress :freeze); use Crypt::Twofish2; use PApp::Config qw(DBH $DBH); DBH; use PApp::FormBuffer; use PApp::Exception; use PApp::I18n; use PApp::HTML qw(escape_uri escape_html tag alink unixtime2http); use PApp::SQL; use PApp::Callback; use PApp::Application; use PApp::Package; use PApp::Util; use PApp::Recode (); use PApp::Prefs (); use PApp::Session (); use PApp::Event (); <<' */'=~m>>; /* * the DataRef (and Callback) modules must be included just in case * no application has been loaded and we need to deserialize state, * since overloaded packages must already exist before an object becomes * overloaded. Ugly. */ use PApp::DataRef (); use Convert::Scalar qw(:utf8 weaken); BEGIN { $VERSION = 1.43; use base Exporter; @EXPORT = qw( debugbox surl slink sform cform suburl sublink retlink_p returl retlink current_locals reference_url multipart_form parse_multipart_form endform redirect internal_redirect abort_to content_type abort_with setlocale fixup_marker insert_fixup SURL_PUSH SURL_UNSHIFT SURL_POP SURL_SHIFT SURL_EXEC SURL_SAVE_PREFS SURL_SET_LOCALE SURL_SUFFIX SURL_EXEC_IMMED SURL_START_SESSION surl_style postpone SURL_STYLE_URL SURL_STYLE_GET SURL_STYLE_STATIC $request $NOW *ppkg $papp *state %P *A *S $userid $sessionid reload_p switch_userid getuid dprintf dprint echo capture $request N_ language_selector preferences_url preferences_link $prefs $curprefs getpref setpref save_prefs ); @EXPORT_OK = qw(config_eval abort_with_file); # might also get loaded in PApp::Util require XSLoader; XSLoader::load PApp, $VERSION unless defined &PApp::bootstrap; unshift @ISA, PApp::Base; } sub getuid(); # prototype needed # globals # due to what I call bugs in mod_perl, my variables do not survive # configuration time unless global $translator; $configured; $key = $PApp::Config{CIPHERKEY}; our $cipher_e; $cipher_d; $libdir = $PApp::Config{LIBDIR}; $i18ndir = $PApp::Config{I18NDIR}; our $stateid; # uncrypted state-id $sessionid; $prevstateid; $alternative; our $userid; # uncrypted user-id our %state; our %arguments; our %temporary; our %S; # points into %state our %A; # points into %arguments our %P; our %papp; # toplevel ("mounted") applications our $NOW; # the current time (so you only need to call "time" once) # other globals. must be globals since they should be accessible outside our $output; # the collected output (must be global) our $routput = \$output; # the real output, even inside capture {} our $doutput; # debugging output our @fixup; our $location; # the current location (a.k.a. application, pathname) our $pathinfo; # the "CGI"-pathinfo our $papp; # the current location (a.k.a. application) our $modules; # the module state our $module; # the current module name (single component) our $curprfx; # the current state prefix our $curpath; # the current application/package path our $curmod; # the current module (ref into $modules)#d##FIXME# our $ppkg; # the current package (a.k.a. package) our $curconf; # the current configuration hash our $request; # the apache request object our %module; # module path => current module our @pmod; # the current stack of pmod's NYI our $langs; # contains the current requested languages (e.g. "de, en-GB") $cookie_reset = 86400; # reset the cookie at most every ... seconds $cookie_expires = 86400 * 365; # cookie expiry time (one year, whooo..) $checkdeps; # check dependencies (relatively slow) $delayed; # delay loading of apps until needed our %preferences; # keys that are preferences are marked here $content_type; $output_charset; our $output_p = 0;# flush called already? $surlstyle = scalar SURL_STYLE_URL; $in_cleanup = 0; # are we in a clean-up phase? $onerr = 'sha'; our $warn_log; # all warnings will be logged here our $url_prefix_nossl = undef; our $url_prefix_ssl = undef; our $url_prefix_sslauth = undef; our $logfile = undef; our $prefs = new PApp::Prefs \""; # the global preferences our $curprefs = new PApp::Prefs *curprfx; # the current application preferences %preferences = ( # system default preferences '' => [qw( papp_locale papp_cookie )], ); # flush translation table caches when they are re-written PApp::Event::on papp_i18n_flush => sub { PApp::I18n::flush_cache; }; our $papp_main; our $restart_flag; if ($restart_flag) { die "FATAL ERROR: PerlFreshRestart is buggy\n"; PApp::Util::_exit(0); } else { $restart_flag = 1; } our $save_prefs_cb = create_callback { &save_prefs if $userid; } name => "papp_save_prefs"; our $start_session_cb = create_callback { &start_session; } name => "papp_start_session"; sub SURL_PUSH ($$){ ( "\x00\x01", undef, @_ ) } sub SURL_UNSHIFT ($$){ ( "\x00\x02", undef, @_ ) } sub SURL_POP ($) { ( "\x00\x81", @_ ) } sub SURL_SHIFT ($) { ( "\x00\x82", @_ ) } #sub SURL_EXEC ($) { SURL_PUSH("/papp_execonce" => $_[0]) } sub SURL_EXEC_IMMED ($) { "\x00\x91", \$_[0] } sub SURL_EXEC ($) { $_[0] } sub SURL_SAVE_PREFS () { $save_prefs_cb } sub SURL_SET_LOCALE ($) { ( SURL_SAVE_PREFS, "/papp_locale" => $_[0] ) } sub SURL_START_SESSION() { SURL_EXEC_IMMED ($start_session_cb) } sub SURL_SUFFIX ($) { ("\x00\x41", @_) } sub SURL_STYLE ($) { ("\x00\x42", @_) } sub _SURL_STYLE_URL () { 1 } sub _SURL_STYLE_GET () { 2 } sub _SURL_STYLE_STATIC() { 3 } sub SURL_STYLE_URL () { SURL_STYLE(_SURL_STYLE_URL ) } sub SURL_STYLE_GET () { SURL_STYLE(_SURL_STYLE_GET ) } sub SURL_STYLE_STATIC () { SURL_STYLE(_SURL_STYLE_STATIC ) } sub CHARSET (){ "utf-8" } # the charset used internally by PApp # we might be slow, but we are rarely being called ;) sub __($) { $translator ? $translator->get_table($langs)->gettext($_[0]) : $_[0] } sub N_($) { $_[0] } # constant our $xmlnspapp = "http://www.plan9.de/xmlns/papp"; =head1 Global Variables Some global variables are free to use and even free to change (yes, we still are about speed, not abstraction). In addition to these variables, the globs C<*state>, C<*S> and C<*A> (and in future versions C<*L>) are reserved. This means that you cannot define a scalar, sub, hash, filehandle or whatsoever with these names. =over 4 =item $request [read-only] The Apache request object (L), the same as returned by Crequest>. =item %state [read-write, persistent] A system-global hash that can be used for almost any purpose, such as saving (global) preferences values. All keys with prefix C are reserved for use by this module. Everything else is yours. =item %S [read-write, persistent] Similar to C<%state>, but is local to the current application. Input arguments prefixed with a dash end up here. =item %A [read-write, input only] A global hash that contains the arguments to the current module. Arguments to the module can be given to surl or any other function that calls it, by prefixing parameter names with a minus sign (i.e. "-switch"). =item %P [read-write, input only] Similar to C<%A>, but it instead contains the parameters from forms submitted via GET or POST (C, however). Everything in this hash is insecure by nature and must be used carefully. Normally, the values stored in C<%P> are plain strings (in utf-8, though). However, it is possible to submit the same field multiple times, in which case the value stored in C<$P{field}> is a reference to an array with all strings, i.e. if you want to evaluate a form field that might be submitted multiple times (e.g. checkboxes or multi-select elements) you must use something like this: my @values = ref $P{field} ? @{$P{field}} : $P{field}; =item %temporary [not exported] Is empty at the beginning of a request and will be cleared at request end. =item $userid [read-only] The current userid. User-Id's are automatically assigned, you are encouraged to use them for your own user-databases, but you must not trust them. C<$userid> is zero in case no userid has been assigned yet. In this case you can force a userid by calling the function C, which allocated one if necessary, =item $sessionid [read-only] A unique number identifying the current session (not page). You could use this for transactions or similar purposes. This variable might or might not be zero indicating that no session has been allocated yet (similar to C<$userid> == 0). =item $curprefs, $prefs [L] The current application's (C<$curprefs>) and the global (C<$prefs>) preferences object. $curprefs->get("bg_color"); ef_string $curprefs->ref("bg_color"), 15; =item $PApp::papp (a hash-ref) [read-only] [not exported] [might get replaced by a function call] The current PApp::Application object (see L). The following keys are user-readable: config the argument to the Coption given to C. =item $ppkg [read-only] [might get replaced by a function call] This variable contains the current C object (see L). This variable might be replaced by something else, so watch out. This might or might not be the same as $PApp::ppkg, so best use $ppkg when using it. Ah, actually it's best to not use it at all. =item $PApp::location [read-only] [not exported] [might get replaced by a function call] The location value from C. =item $PApp::module [read-only] [not exported] [might get replaced by a function call] The current module I the application (full path). =item $NOW [read-only] Contains the time (as returned by C