LoginRegisterCommercial SupportContact Us


POD documentation > Web Protocols > Input.pm

Input.pm

Handling of POST, GET, and PATH input data
posted on 3:14 PM, July 12, 2009


ExSite::Input -- tools for reading http inputs

Input from the client typically comes in 3 ways:

  • POST data (forms)

  • Forms typically send their data as POST data, which is a set of parameter names and values. We convert this to a hash of names => values.

  • GET data (query string)
  • Query strings are treated similarly to forms by default; that is, they are presumed to contain parameterized values such as
        /cgi/page.cgi?parameter=value&less=more

    Note that the separator character ``&'' can be changed to ``;'' or any other charcter in your configuration file. For example, if you use a CSV format such as

        /cgi/page.cgi?value,more

    then you can set your separator character to ``,'' and the values will come through as parameter names. More on this is given below. If you use an entirely different format, then you can always fetch the raw GET data and parse it yourself.

  • PATH_INFO
  • Path info data is a list of values separated by the ``/'' character. This list can be broken down into named sub-lists. The sub-list names are treated as parameter values, and the sub-list data are treated as simple arrays. Any remaining trailing part of the path info is kept in an unnamed sub-list. For example, a PATH_INFO like
        /exsite/index.html/blog/my_article

    might break down into two sub-lists:

        CMS -> exsite, index.html
        Zine -> blog, my_article

    Unlike POST and GET data, these parameter names are not provided by the input data; they are defined after the fact by code that reads from the path.

To begin working with inputs of any of these types, declare an Input object to work with:

    my $in = new ExSite::Input;

Reading POST and GET data

Input is returned as a hash reference of parameters names => values.

query()

    my $querydata = $in->query();

Reads input passed via GET method (ie. QUERY_STRING)

post()

    my $postdata = $in->post();

Reads input passed via POST method.

query_or_post()

    my $data = $in->query_or_post();

Reads from query preferentially, but if the query contains no data, it will read from post data as a backup.

post_or_query()

    my $data = $in->post_or_query();

Reads from post data preferentially, but if the post contains no data, it will read from the query string as a backup.

combine()

Usage: my $data = $in->combine()

Combines the post data and query data into a single hash. Post data is taken preferentially.

Other QUERY_STRING formats

If your query string is not formatted as a sequence of parameter=value settings, you can try one of these:

# fetch a list of the parameter names my @parameter_list = $in->fetch("get","keys");

    # fetch the raw QUERY_STRING to be parsed by another program
    my $raw_input = $in->fetch("get","raw");

Path Info

path_info()

    my $data = $in->path_info();

Returns the complete PATH_INFO, as a string.

The path info can be comprised of a number of different sub-paths that are concantenated together. For example:

    /exsite/page.html/blog/my_article

The first two elements of this path might refer to a path in the CMS (eg. /SECTION/PAGE), while the last two refer to a path in the Zine subsystem. The complete path info is a concatenation of these two subpaths, but we will often want to deal with the subpaths individually.

path()

    my $data = $in->path($id);
    my @data = $in->path($id);

Returns a sub-path as a string, or as an array of path elements. The complete path can be divided into any number of sub-paths, each with an ID. Any remaining path with no ID is called the remainder. If no ID is given, the remainder is returned.

    $in->path($id,$data);
    $in->path($id,@data);

Sets a sub-path to a string, or as an array of path elements. With the string form, the $data must begin with ``/''. To delete a sub-path, use:

    $in->path($id,"");

To set the remainder, use:

$in->path("",$data);

new_path()

This method defines a new sub-path. It is called automatically from path() if the id passed to path has not yet been defined.

    $in->new_path($id,$data);
    $in->new_path($id,@data);

Defines a new sub-path, which follows all other sub-paths that have already been defined. The path data can be passed as a simple string (starting with ``/''), or as an array of path elements. If the path data matches the start of the remainder, the subpath will be removed from the remainder. For example, if the remainder is ``/foo/bar/baz'', and you define a new subpath as ``/foo/bar'', then the remainder will change to ``/baz''. If, however, you define a new subpath like ``/bar/foo'' which does not match the remainder, then the new subpath will be inserted into the path, and the remainder will be left unchanged, resulting in ``/bar/foo/foo/bar/baz'' as the complete path.

Raw Input Data

The raw input is also saved, and can be retrieved using:

    my $raw = $in->fetch("post","raw");   # or, use "get" instead of "post"

Input Order

If the order of the inputs is important, you can fetch the raw key order using:

    my $keylist_ref = $in->fetch("post","keylist");  # or "get"...


Notes

The Input class is a replacement for the generic input parsing routines in ExSite::Misc::, which are deprecated for processing inputs to page.cgi.

The main purpose in having an Input class is so that POST input can be shared by multiple modules working independently. Without an Input class, the first module to get its mitts on STDIN gobbles all the input, and the remaining modules see nothing.

Multipart-encoded Forms

Multipart-encoding is handled automatically using the CGI:: class. Multipart-encoding is normally only enabled by ExSite when the form accepts file uploads.

To fetch the decoded file data directly, use:

    my $raw_file = $in->fetch_file("input_name","raw"); # binary file data
    $my $encoded_file = $in->fetch_file("input_name");  # encoded file data

ExSite encoded file data looks like this:

    filename.jpg#MIMEDATA....

To convert this back to a regular file, split on the separator character ('#' by default) to get the file name, and the mime-encoded data. Then use

    use Mime::Base64;
    decode_base64($mimedata);

If you request the raw input data from a multipart-encoded form, you will receive a CGI:: object.

Input Storage

ExSite::Input stores all input data in %share, where other modules will find it if they also play nice and use ExSite::Input. The input is parsed and cached automatically, and ExSite::Input is smart enough not to redo this work once it has been done.

Input is saved in the following structure:

$share{input}{get|post|combine|path}{raw|data|keylist}

where get/post/combine/path selects the input stream, and raw/data/keylist selects the format you would like to view the data in.

Get and post data are the parameter/value pairs found in the get and post input streams, respectively. Combined data is the merged get and post data, where post data is taken preferentially if the same parameter appears in both.

Path data are stored as a hash of subpath IDs mapped to path element arrays. The raw data is the scalar version of the subpath; the data is the array version of the subpath, and the keylist is the order of the subpaths.

Hacking Input

Typical usage involves passively reading the input data that has been passed from the web server. In some cases, however, you want to modify the input data, or define your own input data.

To modify a single input parameter:

    $in->set("parameter","newvalue","post");  # changes the parameter in the POST data
    $in->set("parameter","newvalue","get");   # changes the parameter in the GET data

To remove a form parameter from the input cache, use:

    $in->delete("parameter");

To change part of the path, see the section on path(), above.

To define the entire set of input data, you can pass the raw data in when defining your Input object:

    my $preset_input = new ExSite::Input( { post=>"foo=bar&bat=baz",
                                            get=>"x=1&y=2",
                                            path=>"/some/path" } );