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

I am building my web applications with CGI, CGI::Application, CGI::Application::Session, CGI::Application::ValidateRM, HTML::Template, Data::Page, Mysql modules and I have a couple of questions reagading design and choice of modules:

1) Is it possible to change the name of CGISESSID variable when using the CGI::Application::Session or do I have to use CGI::Session to be able to change that? If my users don't accept cookies I need to add the sessionID to the querystring and I don't want to use the variablename: CGISESSID In the CGI::Session module I can easily change the name of the CGISESSID variable by:

CGI::Session->name("sid");
but I can't figure out how to do this with the CGI::Application::Session module. CGI::Application::Session is using the CGI::Session module so there should be a way of calling the name() sub routine, but how?

2) Are there any major drawbacks in using CGI::Application::Session instead of CGI::Session?

3) In my old shopping site scripts I always used a Shopping Cart DB table to keep info on my customers temporary shopping carts. However with sessions this approach feels unneccesary when I can store all shopping cart info. in a session variable instead. What is the most common way of doing this, how is the biggest shopping sites (amazon etc.) doing this? Pros and Cons?

4) Any information on what to do to make parts of my sites secure (https)? No clue about this! Where should I start, this might not even be a programming questions. I probably need some kind of certificate but do I have to buy a commericial one?

5) I am currently using the Mysql module because...well I don't really know why. Is there a reason to switch to the DBI module?

6) Is there any other modules that I should pay attention to when building my framework, such as: using the Template Toolkit (Apache::Template) instead of HTML::Template? any other tips?

Replies are listed 'Best First'.
Re: Code Design Issues
by perrin (Chancellor) on Feb 06, 2005 at 16:50 UTC
    Some tips:
    1. Sessions are not a good place to store any significant data. They are inefficient, can't be queried through SQL, and don't support concurrency safety methods like transactions. Store an ID for a shopping cart in the session, but store the actual cart data in a database.
    2. If you use MySQL, use InnoDB tables. A shopping cart system is not a silly little forum app -- you need transactional safety for this.
    3. Apache::Template is just a mod_perl handler for running files through Template Toolkit. If you are using CGI::Application, you have no use for it. You can use TT directly from CGI::Application. There's even a plugin module for it.
Re: Code Design Issues
by Zaxo (Archbishop) on Feb 06, 2005 at 08:40 UTC

    On question 5: DBI is the standard way of talking to databases in Perl. It is a unified (more-or-less) interface which will permit you to port your code to other databases with ease. That may not seem important now, but there will be other projects where you will want to build on what you've done.

    After Compline,
    Zaxo

Re: Code Design Issues
by bradcathey (Prior) on Feb 06, 2005 at 13:47 UTC

    Question 4: having experience with secure certificates, if you really want to lock down parts of your site, I would suggest a name brand certificate, like GeoTrust, Verisign, etc. I have discovered that some browers (Netscape and Safari) have problems recognizing the cheap ones (goDaddy) or newer ones. This will be a turn-off to your visitor/shopper. Of course there are hosting plans with shared SSL, but be prepared to pay a bit more for the service overall.

    Installation will require a few hoops to be jumped through, depending your host and the certificate, but really isn't a big deal.


    —Brad
    "The important work of moving the world forward does not wait to be done by perfect men." George Eliot
Re: Code Design Issues
by Tanktalus (Canon) on Feb 06, 2005 at 16:13 UTC

    1) From a quick perusal of the CGI::Application::Plugin::Session code (which is the newer version of CGI::Application::Session, so I'd recommend an upgrade to this version), I'd say that calling CGI::Session->name("sid") before your first call to $self->session would be effective at this since C::A::P::S uses C::S under the covers anyway.

    2) There aren't supposed to be - C::A::P::S should hide many of the details of C::S to make it easier, but there is still a C::S object under it all.

    3) I would think of storing it in the session unless you need to do some sort of data mining on unfinished shopping carts.

    4) If no one else has any idea, you may want to look this up on google or something - I'm sure this question has been answered by many other sites already.

    5) Because more people will be able to help you with it? ;-)

    6) Templating systems are almost as religious as editors. In that vein, I would suggest familiarising yourself (and your web design people, if that isn't you ;-}) with one of the templating systems, and using it. I may use HTML::Template for websites, but it's inadequate for other templating jobs, which means to me that it may also be inadequate for other websites which may be more convoluted than mine. You'll need to come up with a list of requirements that you need in a templating system and figure out which templating system meets those requirements. You may also want to run it by the monks - some monks may be able to help you come up with more requirements, or may explain how to design code differently so that some of your requirements can go away.

      do you know how I can make the call? if you look below I show code that doesn't work. Basically how can I call a function from a module that is being used by the module I use?
Re: Code Design Issues
by johnnywang (Priest) on Feb 07, 2005 at 07:49 UTC
    I happen to have just started doing something similar for my application (although I do other webapps in java, which has more standard answers):

    1 & 2. I'm directly using CGI::Session inside CGI::Application, of course then I can use any name I want, but that's not my motivation: it was just the first thing I did:-)

    3. I would store that in the session, but if you are using the MySql for storing sessions in CGI::Session, it amounts to the same thing: it's safely inside the database, but you don't have to explictily do it.

    4. Get a digital certificate, from places like verisign. Unfortunately you do have to pay for them (and year after year, just like passports, only shorter and more expensive, but it does work worldwide.)

    5. Not understanding your question, we all use DBI to access Mysql

    6. I use Template Toolkit with CGI::Application, I'm pretty happy with it, but again it's the first perl template I learnt after reading people's post here.

    Hope that helps.

      I concur with using TT with CGI::Application and with other folks who pointed out that TT is useful beyond HTML (for stuff like export files). If you're only gonna learn on template engine, TT should probably be the one.

      I've hacked together my own mini application server based on TT, CGI::Application, DBI, and some home brew authentication stuff. With this sitting on the shelf, cranking out new applications is very straightforward.

Re: Code Design Issues
by boboson (Monk) on Feb 07, 2005 at 10:26 UTC
    Thanks for all your replies. Here are my reply for all of your answers:

    1)
    CGI::Application::Session is using CGI::Session, but how do I call functions from CGI::Session? for example the name() function?

    I've tried to following code but it gives me an error

    use CGI::Application::Session; CGI::Session->name("sid"); # init session object my $session = $self->session; # if user doesn't accept cookies if ($q->cookie('sid') ne $self->session->id()) { # get sessionid for querystring $self->param('start')->param(sid => "&sid=".$self->session->id()); }

    the code below works but it does not change the CGISESSID variable name

    use CGI::Application::Session; # init session object my $session = $self->session; # if user doesn't accept cookies if ($q->cookie('CGISESSID') ne $self->session->id()) { # get sessionid for querystring $self->param('start')->param(CGISESSID => "&CGISESSID=".$self->sessi +on->id()); }

    by the way, maybe anyone have a better way of appending the sessionid to the querystring if the user doesn't accept cookies?

    2)
    As long as I can call the functions from the original module I can't see any direct drawbacks in using plugins to the original modules. On the contrary, maybe it's better to hide away the basic functionality as much as possible.

    3)
    My plan before asking this question was to:
    Use a database for my product, order and customer data etc. Use sessions to store the productID, name and price (price will be doublechecked towards the products table at checkout)
    1) I wanted to use sessions instead of the database to minimize unneccesary database calls, is this really an issue?
    2) I don't want a growing shoppingcart table, Tanktalus had a good point considering if this data could be of any intrest?

    perrin had some excellent points which are pretty hard to neglect.

    4)
    As I guessed. Thanks bradcathey

    5)
    I guess I will get rid of that Mysql module that was introduced to me at my first job. I must have overlooked this sentence at the top of its documentation:
    "You are strongly encouraged to implement new code with DBI directly."

    6)
    Good tips on templating.

      A session should be used to store session information. What is session information? It's anything that has to do with the current session. If your session is a shopping cart, it's whatever you want to do with the shopping cart, like productID, name, and price.

      Now, the security of this session is as good as the security of your database, because it's stored in the database. None of it is exposed to the user beyond the exposure your database has to the user. Which, in most cases, is good enough.

      I wanted to use sessions instead of the database to minimize unneccesary database calls, is this really an issue?

      I don't know - have you seen an issue? In 99.999% of all situations, rearranging code to minimize X is a bad plan, because X isn't a problem. For example, let's say that by having the maximum number of database calls, your pages return, on average, in 3 seconds. Is 3 seconds a problem? I don't think so ...

      Now, let's say that you can rearrange your code, making it harder to work with, and shave 50% off of your database usage. You end up taking twice as long to make a change, but your database time is down by 50%. Since database calls, in my experience, usually account for either 20% or 80% of the total time most applications spend on a request, you either saved 10% or 40%. This brings your 3s response time to 2.7s or 1.8s. Even in the best case, I don't think most users will even notice you did anything.

      Now, database call optimization can be important, but only when you start receiving above 3-5 requests per second. Anything below that is easily handled by most modern databases, including MySQL, when running on most modern machines.

      I don't want a growing shoppingcart table, Tanktalus had a good point considering if this data could be of any intrest?

      Do you want to know what people are buying? Do you want to know when they're buying it? Do you want to know who bought what? Most retailers would kill for this information, but you're not sure. Riiiight.

      For example, let's say you have a product ABC. ABC seems to be purchased almost exclusively between 10pm and 3am. So, maybe you want to start targeting users that login during those times and mentioning "You might want to look at product ABC." Or, you might want to do something like Amazon does - "People who bought ABC also bought these items".

      This is the heart of your store, man! You lust for this information. Plus, you might be legally required to gather this information, depending on where you are and what you're selling. For example, if you sell some items that are age-restricted and some that aren't, you may have to prove that all the age-restricted items were purchased by users that had verified their age in some fashion. The only way you can do that is if you have a complete history of all purchases.

      And, if you have that complete history, you can do neat things like provide copies of receipts for a dollar. :-)

      Being right, does not endow the right to be rude; politeness costs nothing.
      Being unknowing, is not the same as being stupid.
      Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
      Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

        To answer and clarify some things:

        I am saving my sessionid's on File at the moment. Thanks for good input on database calls.

        However, I think you missunderstood what I meant with a shopping cart

        A shopping cart is a TEMPORARY storage place where my customers put information on objects they are planning to buy.
        When they are done shopping they will checkout their objects, they will receive an orderreceipt.
        Relations between customer and shopping cart will be deleted.
        They also have a choise of not going to the checkout, in that case relations between customer and shopping cart will be deleted.

        So what information am I intrested in at the moment or will be in the future.

        I already have information on my products, I store that in my PRODUCTS table
        I want information on my customer, I store that in my CUSTOMER table when the customer checkout
        I want information on what my customer bought, I store that in my ORDER table

        Do I really want information on what products my customers put in their temporary shopping carts, products that at the end, won't be bought?