Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Multiple Pages with CGI

by Trihedralguy (Pilgrim)
on Mar 24, 2007 at 14:34 UTC ( [id://606414]=perlquestion: print w/replies, xml ) Need Help??

Trihedralguy has asked for the wisdom of the Perl Monks concerning the following question:

I have a quick question, I bet its fairly easy, but within my books, and all the online searches - I've been unable to find a direct answer. Basically, how does one go about making Multiple Pages within a perl/cgi application. (Maybe something like if I navigate to index.cgi?p=10 it will some how goto a page with an id of 10. Also - If I have an application that uses this convention, if someone click an "internal" link - can the varibles i declare else where in the "index.cgi?p=xx" be used throughout? Sorry if this question is confusing/stupid, but I'm still very much a perl noob.

Replies are listed 'Best First'.
Re: Multiple Pages with CGI
by gloryhack (Deacon) on Mar 24, 2007 at 17:32 UTC
    Yep, it's fairly easy -- depending upon the tools you choose.

    Suppose you have an online catalog and you have some way to configure what will appear on page 10 (which is left as an exercise to the coder). Maybe there's a sub generate_page() that takes in a number and just does the right thing. So, assuming you're using CGI or CGI::Simple, you'd just extract the number of the requested page via:

    my $page_number = $q -> param('p'); if ($page_number =~ /^\d+$/) { generate_page($page_number); } else { generate_error_page('One of us is confused.'); }

    The second question, well... it's not clear to me what you mean by "variables I declare elsewhere" so I can't speak to that. I'll try again, though, if you'll clarify that.

Re: Multiple Pages with CGI
by f00li5h (Chaplain) on Mar 24, 2007 at 18:30 UTC

    I'd like to suggest that $ENV{PATH_INFO} may be a good way to pass a unique page name to your script, and end you up with a more friendly set of URIs as a bonus.

    For example, In the url http://example.com/index.cgi/foo/bar the PATH_INFO is the /foo/bar part, the part that appears after the script that your server chooses.

    This makes for lovely bookmarkable pages, because it's just a string at the end of the filename, and that you can use form variables for ther things, because /index.cgi/foo/bar?user_action=update_cart has the 2 parts still, the first being PATH_INFO, the second being the GET (QUERY_INFO) variables that are accessible via CGI.pm's param method.

    Also, if your script is set up as the directory index, you don't need to list it there at all, and my uri of http://example.com/index.cgi/foo/bar becomes http://example.com/foo/bar because the '' after the domain name is expanded to index.cgi by the webserver.

    It's so sneaky that nobody will ever suspect that you're using dynamic content.

    keep in mind that with any of these approaches, you have to make sure that you send sensible modification headers, expire dates and content types otherwise you risk confusing proxy/cache servers...

    @_=qw; ask f00li5h to appear and remain for a moment of pretend better than a lifetime;;s;;@_[map hex,split'',B204316D8C2A4516DE];;y/05/os/&print;
Re: Multiple Pages with CGI
by un-chomp (Scribe) on Mar 24, 2007 at 20:56 UTC
Re: Multiple Pages with CGI
by TGI (Parson) on Mar 25, 2007 at 05:37 UTC

    You might want to check out Ovid's CGI course. It's chock full of good advice and is very well written.


    TGI says moo

Re: Multiple Pages with CGI
by Popcorn Dave (Abbot) on Mar 25, 2007 at 04:42 UTC
    Other monks have offered you some good advice, so here's my two cents.

    I actually did something like you're describing with 4 pages for a shopping cart app, and I used a hash dispatch table combined with a hidden field to decide which page I wanted to display. That might be an avenue for you to consider.

    Good luck!

    Revolution. Today, 3 O'Clock. Meet behind the monkey bars.

    I would love to change the world, but they won't give me the source code

Re: Multiple Pages with CGI
by Trihedralguy (Pilgrim) on Mar 24, 2007 at 17:46 UTC
    Basically I already have a script created that uses param and such, and it vaildates information from a database after the user imputs the data. Then if everything checks out (passes all my if else statements for making sure the user is ready to move on...It creates a list of "Policies" they must fill out. Now, the program already has their "personal information" stored in $name $id and $birthyear. So I need to contiune to keep those around, so once they click on one of the policy links, (a page with a form) once they click submit *enter vailidation here* it will update the database with their selections. If that makes sense. So basically I have it up to the point where I have a page with links, but I need to either securely pass the varibles to another cgi script to process the new form, or make it a way when they click on the link, it keeps using say index.cgi - thus the variables like $name $id and $birthyear are still able to be used without them having to be passed anywhere.
    I hope that helps understand what I'm trying to do.
Re: Multiple Pages with CGI
by Trihedralguy (Pilgrim) on Mar 24, 2007 at 19:11 UTC
    I dont really need to make the URL's easy or bookmarkable, as they are they result from a login page, which if you were to goto these pages directly, you would get a "An error is occured, your not logged in, or your not allowed to navigate to this page directly."

    Thats a good thought though I guess.
    Thanks for everyones comments thus far, if you have anymore ideas, please keep them coming!
      Don't forget to change the error text to "An error has occured. You are not logged in, or you are not allowed to navigate to this page directly." before putting it on the web...
Re: Multiple Pages with CGI
by dragonchild (Archbishop) on Mar 24, 2007 at 14:35 UTC
    Why are you wanting to shove all your pages through index.cgi? The standard way of handling this is to have a page1.cgi and a page2.cgi, etc.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
      When handcoding, yes. But when using a framework like CGI::Application, all pages do indeed tend to go through a single master script.

        Through a single instance script, yes. But using some inheritance and dispatch tricks, each run mode (page) can be delegated to a separate Perl module.


        --
        Rohan

Re: Multiple Pages with CGI
by Trihedralguy (Pilgrim) on Mar 24, 2007 at 23:23 UTC
    Is there a way for a basic href url to call a fuction within perl that will write a new page like I want it to do? Is there a way to have a user select a page from a list, then change to that page? Thats I guess the simplest way I can put it.
      Is there a way for a basic href url to call a fuction within perl that will write a new page like I want it to do? Is there a way to have a user select a page from a list, then change to that page?

      URL's don't call functions, they just establish the host from which the request will be made and perhaps the parameters of the request itself (if you're using, say, "/cgi-bin/mycgi.cgi?p=5"). After that, it's all up to you to ensure that the right thing happens, and more importantly, that no wrong thing happens. Yes, there is a way to get from the information available to the correct solution -- all dynamically generated web content you've ever seen, and every application you've ever launched on your own computer has done exactly that, after all.

      Maybe it's not sinking in just yet, but you've been given several viable options to think about. Maybe you're a bit too new to programming to have the mental habits and breadth of information that will easily guide you through to a solution? If that's the case, you're going to have to expend some brain sweat to get there. Don't worry, it won't hurt. At least not too much. It will be worth the effort, even if your first go at it fails miserably.

      Please forgive me if I'm assuming wrongly about your experience level in what follows. It's difficult to gauge another's knowledge and skill without a good bit of discussion, and I'm just doing the best I can to help you along with what little I know right now. Some suggestions to get you on track:

      Sit down with a pencil and paper and write out what you expect your application to do, case by case and step by step. Don't even think of tapping the keyboard until you've got the whole darn thing reduced to scribble. You want at least a very good outline to start with: in this case it will do this, in this other case it will do this other thing, et cetera. Then fill in between each "in this case" and its corresponding "it will do this" with the logical steps that define what "do this" means and how it will be accomplished. By the time you're done, a possibly doable solution will probably suggest itself to you. If not, think on it some more, expend that brain sweat. Then take just one case and code it up. Make it work, at least mostly. Then work a second case into the code and provide the logic that will allow the thing to decide which response is appropriate. By that point you've got a skeleton of some hopefully reasonable logic that at least mostly works. And at that point you can set that bit of code aside and start over with your now hopefully more refined idea of what should happen. Always always always write one to throw away.

      Above all else, have fun with it. Every application solves a problem ranging from "I want the string 'Hello World' to appear on my display" to "I want to solve all of the world's problems with a computer". How to get from the basic idea to the implementation of a fully working solution is a puzzle, hopefully an intriguing puzzle that will simultaneously exercise and entertain your mind.

      You've been given several viable options to get you started. So get started!

        Some of the perl web-application frameworks do use a mapping from apache handlers to perl subs... or with some other sort of callback magic. I think maypole does that, CGI::Application also does.

        If you want a request to call a sub, you just need a dispatch table keyed by page name, or id

        #use strict unless untested_code; use Template; use CGI qw/header/; print header; # hash of subs that return 2 element list of page title and page conte +nt. my %title_and_content_for = ( # about_us => \&MyModule::get_about_us_html, '/quick_hack' => sub { return ( 'this is a quick, nasty hack', 'some junk to go in the page' ) }, # ... ); my %template_variables = ( # the default is to complain, this will be replaced below title => 'Oh noes!', content => q[ I couldn't find the page you asked for ], # add other stuff to keys in %template_variables ); my $html_layout = q{ <html> <head><title>[% title %]</title></head> <body> [% content %] </body> </html> }; # call the sub for this page, if there is one. # assign the results of the sub to the keys "title" and "content" @template_variables{title,content} = $title_and_content_for{ $ENV{ PATH_INFO } }->() if defined $title_and_content_for{ $ENV{ PATH_INFO } }; # and feed the whole lot to Template toolkit my $TT = Template->new() or die $TT->error(); $TT->process(\$html_layout,\%template_variables) or die $TT->error();

        Now we view http://mysite.com/cgi-bin/sub-madness.cgi/quick_hack and if all goes according to plan (and my untested-make-it-up-on-the-spottery is as good as I think it is) you'll get a nice little html page that reads "some junk to go in the page".

        I've cheated a little, and stuffed most of the HTML generation into places you can't see, the subs on one hand, and Template::Toolkit on the other

        Other interesting this to do:

        • Perhaps want to have some kind of http/404 headers too?
        • Generating a navigation bar from the keys of the hash could be a fun exercise ...
        • Passing in a CGI instance to the subs could make for user-activated stuff, allowing foo.com/sub-madness.cgi/about_us?action=contact&from_email=f00li5h@example.com&question=....
        • It may also be good to add a default page, for when no page is requested... but you're getting mighty close to the page dispatching that your web server should be doing tat that point.

        Update

        • use Template; use CGI; print header all added post creation
        @_=qw; ask f00li5h to appear and remain for a moment of pretend better than a lifetime;;s;;@_[map hex,split'',B204316D8C2A4516DE];;y/05/os/&print;
Re: Multiple Pages with CGI
by Trihedralguy (Pilgrim) on Mar 24, 2007 at 14:45 UTC
    How do i send stored varibles from one page to another without using cookies / putting them into the url bar like index.cgi?=yourssn=2222222222

      CGI::Session or a database are the conventional ways of storing information pertaining to a session or a user. Using a cookie (which CGI::Session manages for you) or some get data embodied in the URL is generally the way you track a session.

      The trick is to use a key (in the URL) that provides access to the server side stored information for the session. Often an MD5 hash of something like a user ID and login time is used to provide the key.


      DWIM is Perl's answer to Gödel
      The only ways to get information to your script from a client are cookies, forms, and the URL. You can use cookies to create sessions, where you store the information on the Web server and just pass enough information to find the session data. You can use forms with hidden elements to pass information to your script that is not entered by the user. Forms which use the GET method will have the parameters show up in the URL; with the POST method the parameters will not be visible in the URL.

      From your example, it looks like the user may be entering private information you don't want to show up in the URL. In that case, a good solution is to have the user enter the information into a form which uses the POST method, and make sure the server is using SSL so the data is encrypted, and so the browser is more careful with the information in its history.

      Hopefully that will be enough to get you started.

        Can you please explain the method in which user enters the information into a form...thanks !!

      if u want to transport data to several pages u can use input hidden fields, so u don't need to mess up ure url or store everything in cookies

      kd ultibuzz

Re: Multiple Pages with CGI
by Trihedralguy (Pilgrim) on Mar 25, 2007 at 19:18 UTC
    My background in programing anything more than a few personal websites was all I was doing until about 6 months ago, when I landed a job to make a simple website for a company, now they think since I'm just a $10 an hour intern they can hand me anything and I can get it done. Until 6 months ago, I didnt know what perl was or what it could do. I heard about it before, but now that I'm slowly learning, I love it so much.
    I do thank you all for your tips and hints, I'm close to finishing this project (Only 3 webpages, but really its like 10 because it has the ability to "adapt to data". I hope I'm not making any of your angry by asking all these newbie questions :)

    Sooner or later I will actually be able to do a whole perl program without asking a handful of questions here first. Cause this crash course thing is really working well. :)
    Thanks again for your help perlmonks!!
Re: Multiple Pages with CGI
by dwhite20899 (Friar) on Mar 25, 2007 at 18:34 UTC
    I've written Perl CGI scripts that progress through 2 or 3 pages; I've also had to maintain other peoples' script that implement 10 pages.

    While 2 pages is manageable, 10 is pandemonium. For the sake of future maintainence, don't try to cram that much into one CGI.

Re: Multiple Pages with CGI
by lokiloki (Beadle) on Mar 25, 2007 at 22:59 UTC
    Possibly you could so something as inelegant as writing out the variables to a local file whose filename is the IP address of the visiting user. Then, on access of additional pages, you simply check for the existence of a file with the IP address.

      Ick.

      CGI::Session would be somewhat better. It may do just that, but atleast you don't see the file handles.

      @_=qw; ask f00li5h to appear and remain for a moment of pretend better than a lifetime;;s;;@_[map hex,split'',B204316D8C2A4516DE];;y/05/os/&print;

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://606414]
Approved by Corion
Front-paged by neversaint
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (8)
As of 2024-04-25 11:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found