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

CGI::Tiny versus undefined parameter/form field

by Polyglot (Chaplain)
on Dec 11, 2022 at 16:33 UTC ( [id://11148743]=perlquestion: print w/replies, xml ) Need Help??

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

Monks,

I've been trying to "upgrade" one of my scripts from the now-outdated (so I am told) CGI.pm to a more modern implementation that I had hoped would be mostly a "drop-in" replacement for it: CGI::Tiny. However, my script needs to function on several sets of pages, not all of them having the same form parameters. CGI.pm did not have any trouble with something like:

my $bookparam = $cgi->param('book') || '';

But CGI::Tiny is throwing a hissy fit over this if the form on that particular page does not happen to include the 'book' field, i.e. code execution is totally halted. Surely there is a way to avoid this, but I cannot find it. I tried this:

defined(my $bookparam = $cgi->param("book")) or my $bookparam = "";

...and I tried this:

my $bookparam; if (defined $cgi->param("book")) {$bookparam = $cgi->param("book")};


...but both of these generate show-stopper errors, like this one (in the logfile):

[Sun Dec 11 22:03:35 2022] [error] [client ::1] Can't call method "param" on an undefined value at /Users/me/PERL/ScriptDir/dev.pl line 1026.

...and to the browser:

Status: 500 Internal Server Error Date: Sun, 11 Dec 2022 15:03:35 GMT Content-Type: text/plain Content-Length: 25 500 Internal Server Error

Obviously, that's not going to work. Must I return to CGI.pm? If a total code rewrite is required in order to switch, it's too big of an ask. I have tens of thousands of lines of code in this project, and hundreds of form fields.

Aside from a defined(%hash) is deprecated error in the log, no other errors are produced--and that "defined(%hash)" issue is part of debugging code that only runs in debug mode anyhow. And yes, "strict" is in use.

How can I detect an undefined field before crashing with CGI::Tiny on it?


NOTE: Before suggesting them, please understand I am not interested in Dancer, Dancer2, Mojolicious, Catalyst, Moose, etc. or other heavy-duty frameworks. I am not using PSGI nor FastCGI, and am not looking for something with large overhead. This is why I have tried CGI::Tiny.

Note 2: Online searches have not helped--results are mostly focused on folk with faulty package installations.

Blessings,

~Polyglot~

Replies are listed 'Best First'.
Re: CGI::Tiny versus undefined parameter/form field
by hv (Prior) on Dec 11, 2022 at 17:01 UTC

    Can't call method "param" on an undefined value at /Users/me/PERL/ScriptDir/dev.pl line 1026.

    This error message is telling you something very specific: you are invoking a method (called param) on something ($cgi) but the thing you are invoking it on is not a CGI::Tiny object but undef.

    So all the rest is irrelevant: $cgi is not the object it is supposed to be, but undef. So you need to look at where $cgi is set, and diagnose what went wrong there (or somewhere in the pathway from there to line 1026).

    Once you have fixed that, you can go back to your original line my $bookparam = $cgi->param('book') || ''; and I imagine it should work.

      Are you saying that the error has nothing to do with whether or not that form field whose value is requested exists in the form? Because that is what the error message leads me to believe.

      I have initiated the CGI as seemed to be indicated in the package description, even copying the example verbatim. But try as I might, it doesn't work.

      It seems that it is quite new. There are no examples of code using CGI::Tiny that I was able to find online beyond that which I've already tried that comes with the package itself. Sigh, it looks like I'll just have to go back to good ole CGI.

      Blessings,

      ~Polyglot~

        You could try printing or otherwise inspecting the type of $cgi

        use Scaler::Util qw( reftype ); print reftype $cgi;

        That will tell you conclusively if $cgi is a CGI::Tiny object or undef.

Re: CGI::Tiny versus undefined parameter/form field
by hippo (Bishop) on Dec 12, 2022 at 14:03 UTC

    It's pretty straightforward to construct an SSCCE showing this working just fine both with the specified parameter and without:

    $ cat foo.cgi #!/usr/bin/env perl use strict; use warnings; use CGI::Tiny; cgi { my $cgi = $_; my $bookparam = $cgi->param('book') || ''; $cgi->render (text => "bookparam is $bookparam\n"); } $ (export QUERY_STRING='book=bar'; ./foo.cgi) Date: Mon, 12 Dec 2022 13:57:29 GMT Content-Type: text/plain;charset=UTF-8 Content-Length: 17 bookparam is bar $ ./foo.cgi Date: Mon, 12 Dec 2022 14:01:26 GMT Content-Type: text/plain;charset=UTF-8 Content-Length: 14 bookparam is $

    As others have suggested, it seems that your $cgi is undefined. The error is in the code you haven't shown us.


    🦛

      Thank you. I didn't try that code yet, but I noticed something in it that differed from mine. You have this line...

      my $bookparam = $cgi->param('book') || '';

      ...inside the  cgi { ... } codeblock. I have "$cgi->param()" calls scattered across a multitude of subroutines, as each subroutine needs to deal with a particular set of form inputs. What is to be done if those only work inside that single code block?

      This would operate in a way that differed fundamentally from standard CGI. With CGI, I was able to create the "object," then use it throughout the script.

      It seems this may be the problem.

      Blessings,

      ~Polyglot~

        ...inside the cgi { ... } codeblock. I have "$cgi->param()" calls scattered across a multitude of subroutines

        Per the CGI::Tiny documentation, that $cgi object is only valid inside the cgi { ... } codeblock. "There is no CGI::Tiny object constructor; the object is accessible within the cgi block, only reads request data from the environment once it is accessed, and ensures that a valid response is rendered to avoid gateway errors even in the event of an exception or premature exit." You might be able to rework it so that the code in the cgi {...} block is calling all your subroutines, and you pass the $cgi object as an argument to each of those subroutines, but that may be a lot of refactoring.

        As I said, if you're really looking for a drop-in replacement for CGI.pm, where you can use the $cgi object throughout your code with the same syntax you are used to from CGI.pm, you will likely want to use something like CGI::Simple instead of CGI::Tiny.

        This would operate in a way that differed fundamentally from standard CGI.

        Of course. And the documentation goes to some lengths to explain this. Perhaps you have not read it yet?


        🦛

        Just put all the calls to those multitude of subroutines inside the cgi block and switch to our :)

        #!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11148743 use warnings; use CGI::Tiny; our $cgi; cgi { $cgi = $_; some_sub_somewhere_else(); }; sub some_sub_somewhere_else { my $bookparam = $cgi->param('book') || ''; $cgi->render (text => "bookparam is $bookparam\n"); }
Re: CGI::Tiny versus undefined parameter/form field
by Bod (Parson) on Dec 11, 2022 at 23:19 UTC
    Before suggesting them, please understand I am not interested in Dancer, Dancer2, Mojolicious, Catalyst, Moose, etc. or other heavy-duty frameworks

    I totally understand that - I am exactly the same...

    However, the wisdom of the Monastery suggested a framework or templating system to me. Like you, I discounted Dancer2, Mojolicious and the like but I am VERY pleased I took the time to try out Template. It didn't take long to make it work better than any of the CGI::* modules as it is not a huge learning curve.

    Adopting Template has been revolutionary for me. I now hate maintaining the web code I wrote previously. Separating the logic from the display makes maintenance so much easier, debugging a lot simpler and development quicker. There's no way I would go back and I strongly suggest you give it a go. There is plenty of support her in the Monastery to help you master Template or an alternative templating system.

      Honestly, if I have this much trouble adopting CGI::Tiny, Template would be beyond my ability. I have never understood OOP stuff. Abstractions like references and pointers and classes, etc. are over my head. I have to accept the reality that my mind is not gifted in those areas, and I work with what I have. I have tried. Lots of times. I've even read those chapters in the O'Reilly Perl guide more than once.

      Okay, so, downvote me to oblivion. In any case, Tiny's not working out. Either something is wrong with it or its installation on my system, or I don't know how to implement it--which implies, too, that the example code for it is flawed or incomplete, because I attempted to follow that exactly. I do wonder if anyone here is actually using it.

      Blessings,

      ~Polyglot~

Re: CGI::Tiny versus undefined parameter/form field
by pryrt (Abbot) on Dec 12, 2022 at 14:42 UTC
    I've been trying to "upgrade" one of my scripts from the now-outdated (so I am told) CGI.pm to a more modern implementation that I had hoped would be mostly a "drop-in" replacement for it: CGI::Tiny.

    What portion of the CGI::Tiny documention said to you "drop-in replacement"? Looking at that documentation, compared to my CGI.pm experience, it seems a completely different philosophy.

    Something like CGI::Simple, on the other hand, specifically says as the first sentence of the DESCRIPTION: "CGI::Simple provides a relatively lightweight drop in replacement for CGI.pm." It has all the parameter-handling interface, without any of CGI.pm's poorly-designed and deprecated HTML-generating code.

    • If your goal is a drop-in replacement, I would suggest going with CGI::Simple (or just using the non-HTML portions of CGI.pm -- because while the HTML generation portion is deprecated, and the whole module is now non-core, CGI.pm and the Common Gateway Interface it implements still works and is still available and useable); then you can spend your learning-effort in something like Template Toolkit for improved HTML generation, instead of learning a new philosophy for handling the parameters and everything.

    • If you want to learn something new and different on the interface side, then CGI::Tiny might do it; but looking briefly at its documentation, I would not have come up with a SSCCE like hippo was able to do here, so it might not have the easiest learning curve for someone who still has the CGI.pm thought processes...

    • But if you're going to bother trying to learn a whole new philosophy anyway, why not go with one of the "big 2" rather than CGI::Tiny , which I have rarely-if-ever remembered seeing mentioned here. For me, when I tried to expand my horizons a couple years ago, I was able to learn from the Mojolicious::Lite documentation sufficiently to get apps of similar complexity to the ones I used to do in CGI.pm, so that is what I personally use when doing a new script for my hobby website; I am not an expert by any means, but I can get some simple endpoints. (Something that I don't think is clear enough in their docs: if you have an old-fashioned CGI-based web host, like many of the shared hosts out there, you don't need to do any of their fancy stuff with the "server" side of things; you just put your Mojolicious::Lite-using script in your cgi-bin folder or wherever you used to put it with a CGI.pm-based app, and it will work the same.)

    CGI::Alternatives does a really good job of showing you an old style CGI+HTML-from-CGI.pm, then showing you the equivalent application in CGI.pm+TemplateToolkit (which would be virtually identical to CGI::Simple + Template Toolkit if you wanted to go down that path), and then in Mojolicious::Lite, Mojolicious "full", and Dancer2.

      Yes, I think you are correct: CGI::Tiny is fundamentally different. It won't work for me. Believe it or not, I have used (or tried to) CGI::Simple before. It won't work on my Mac, which is where I develop. So "Simple" didn't live up to its name for me.

      I don't use CGI for much, actually. I use it for the form inputs, and that's about it. So if that is not the portion of its codebase that landed it on the "deprecated" list, I guess I should be fine. In any case, for now at least, I've given up on the CGI::Tiny. It's a tool for someone else. I'm back to good old CGI. One thing that irritated me with CGI is that it only recognizes the "name" attribute of an element, and not its "id". But I guess I can live with assigning both, one for the JS, and one for the CGI. It just seems a shame to have to repeat so many names--fattens the code, and uses more bandwidth.

      Blessings,

      ~Polyglot~

        It won't work on my Mac, which is where I develop. So "Simple" didn't live up to its name for me.

        I find that hard to believe, given the green Darwin column in cpantesters report, unless the test suite is not sufficient. But since I don't have a Mac (and haven't used one since they looked like this), I won't be any help in that regard.

Re: CGI::Tiny versus undefined parameter/form field
by tangent (Parson) on Dec 12, 2022 at 17:14 UTC
    If you want an actual "drop-in replacement" for CGI I would recommend CGI::Minimal. It is simple and lightweight, and definitely works with older Perl versions (and older Mac OS).
      Since the 2015 reckoning, CGI.pm is just as "Simple", even more so. CGI.pm programs do not need drop in replacements period.
Re: CGI::Tiny versus undefined parameter/form field
by Anonymous Monk on Dec 12, 2022 at 12:29 UTC

    I've been trying to "upgrade" one of my scripts from the now-outdated (so I am told) CGI.pm to a more modern implementation that I had hoped would be mostly a "drop-in" replacement for it: CGI::Tiny.

    lies are busy work. Stick with CGI.pm.

Log In?
Username:
Password:

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

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

    No recent polls found