I am not trying to be difficult. I was trying to narrow my question to the issue of defining a variable in one subroutine so that it can be used else where in another subroutine.

My program is an online auction for the commercial fishing industry and has been up and running since 2010. Everything works fine. However, I would like to make an improvement.

Currently, when an listed item does not sell, the seller receives an email with a link that he can follow and repost his item. He will be displayed a list of all of his recent listings and he can choose which one he wants to relist.

The form is re-populated with the data from the original listing. He can make edits if he wishes and then repost.

Again currently, the display he sees of his unsold listing includes those that he has relisted.

I want to add code that will delete the old listing once it has been reposted.

Therefore I need to capture the original file name and hold it until the new listing has been posted. Deleting the old listing prior to reposting will not allow the re-populating of the new form.

There is around 15,000 line of code in the main program with many subroutines. The two subroutines that I mention are both contained in the main script. I could post a lot of code but doubt that it changes the issue of how to define a variable in one subroutine and pass it to another.

If you want to see complete subroutine code let know. I will be traveling today and through the weekend so I may be slow in getting back to you.

Are you using the strict pragma i.e., does your script have this line?

Code

use strict;

Based on the code you've posted your script doesn't have that line.

If you are using the strict pragma, then a var declared/defined in one sub would be local to that sub and will not be accessible in another sub.

If you are not using the strict pragma, then all vars defined are global and accessible from any location. However, doing that is a very very bad coding practice and makes troubleshooting much more difficult.

Instead of posting your entire 15,000 line script, write a short but complete test script that demonstrates the problem and post that script. With that I will be able to tell you what's wrong.

In case it's not obvious to you I'll point out that if a global var is defined in a subroutine and you want to use that same var somewhere else, then the sub that defines the var will need to be executed prior to trying to use it in another location.

Unimportantly, I haven't used CGI::Session for a few years, my preference is to use either my own session handling module or Data::Session, both have various improvements and simplifications.

When handling sessions, I use a particular design pattern:

- Create or load a single persistent session. Don't destroy the old / create a new session in order to destroy the old / create a new variable, the overhead has never been an issue. Instead handle this at a higher level via the param and clear methods, testing for definedness of relevant parameters. I mention this in particular because you pass an undefined value as the second argument to new in your "first sub", which as far as I can tell from the tutorial, will force CGI::Session to create a new session each time. - Write a maintainable / reusable session instantation function or object method to instantiate the session no matter your later intentions. This section of your session code will commonly be reused. - It is recommended to call flush at minimum before your program exits because automatic flushing can be unreliable. - In your case its easiest just to pass a CGI object to new and use CGI::Sessions header method to handle setting the cookie and header. But CGI Session remains flexible in that you don't necessarily have to use CGI or CGI::Cookie, or even the HTTP protocol.

I can't tell from your code, but my best guess is its purpose is to provide an intermediate interface for the user to confirm if they would like to delete a particular file. If this is the case then you might not need a session at all, simply pass the "FILENAME" parameter down the chain via a hidden input field. Of course this is dependent on the actual complexity of your application.

Below is a very rough standalone example that creates / loads a persistent session using CGI::Session, providing functions to get, set and reset a particular parameter. Its purpose is to demonstate a basic session process, the general application itself is not particularly well written. A demo is available here, change the do url parameter to get, set or reset the session parameter:

Code

use strict; use warnings FATAL => qw/all/; use CGI::Carp qw/fatalsToBrowser/; use CGI; use CGI::Session;

This is the general form of my script at this time. At the beginning I have:

Code

use strict; use warnings; use CGI::Carp qw(fatalsToBrowser); use CGI; use CGI::Session; use Data::Dumper; use DBI;

A user would would receive an email notice telling him that an item listed on the auction did not sell. They would click the provided link and be taken to a table on the website showing them a list of the items that they had listed but that did not sell. They would click on the item that they would like to relist. This takes them to a display of the item showing them all of the details they had originally provide when they first listed the item. It is in this subroutine that I wish to capture the file name for the session. The file name is there and and available. I have tested this by printing it out on this page. He is the code that I have in this subroutine:

On this page there is a button labeled "Re-post". When they click this button they are taken to a page with the listing form. All of the original data have populated the form. Here they can edit the information if they like. From here they click a but to "preview" the listing. If they are happy with the listing they then click a button labeled "sell it" and the item is listed on the auction.

Is is here, when they click "sell it" that I wish to to use the session variable holding the file name to delete the old file for the listing. That way if they were to return to the table showing the listing of their unsold items, the old listing would no longer be shown. The code that I have to obtain the session variable is:

The $cgi and $session objects should have file scope. Instead of declaring and assigning them inside the subs, they should be declared and assigned shortly after the use statements so that they can be used anywhere in the script.

Have you compared the session id between each of your subs to make sure they are identical? I suspect that they are not, which would explain why the session var you need isn't being carried over.

I have declared $sid and $session earlier following the use statements and tested the script. It still is not carrying the file name to the next subroutine.

I have not compared session id's. From your comment I gather that they should be identical. I did not see how the id in the second subroutine would be set identical to the id generated in the first subroutine. Can you help me with code?

Your problem is possibly as a result of something you have done elsewhere in your code, not in the session code you have provided. When I take your latest two snippets of code, make a couple of adjustments ( define form hash, print header ), put them in two separate scripts, they work just fine. Your best bet is to start with a fresh slate, write a new script which contains just the necessary code, that demonstrates your problem. Use an inspector tool, if using Mozilla Firefox, get the Firebug extension. It has a cookies section where you can check if the session id cookie has been set properly and is maintained as you navigate. You can also check the headers of requests and responses.

Here are some further suggestions as to what could be wrong with your code:

- Your description of the problem "but is still not passing the variable to the second subroutine" is a little vague based on the code we have, how are you confirming this, if its simply because the file is not being deleted perhaps this is where your problem lies, you should use the syntax unlink $file or die $! to help confirm this. - The value of $form{'BIDTOVIEW'} is not what you think, you haven't shown us how this is defined. Thus its value is undefined. - You have forgotten to print the header. Your original snippet does this, but not your latest. Thus the cookie is not being set. - You are already printing a header beforehand and not seeing the output of the later header due to the positioning of html elements. Thus the header that sets the cookie is not working. - You describe your two snippets of code as being part of two subroutines, perhaps one or the other subroutine is not being called, or returns before reaching your session code. - ( long shot ) You are doing something that changes the behaviour of CGI::Carp i.e. re-adjusted %SIG. Thus fatals and/or warnings are not being displayed in browser.

Chris thanks for the reply. Following your advise I installed Firebug in Firefox and I do not see cookies being set by my code. Let me respond to some of your suggestions.

1)

Quote

- Your description of the problem "but is still not passing the variable to the second subroutine" is a little vague based on the code we have, how are you confirming this, if its simply because the file is not being deleted perhaps this is where your problem lies, you should use the syntax unlink $file or die $! to help confirm this.

I placed the variable "$deletefile" in the text of page generated in the second subroutine. If the value was being passed to the routine it would be seen in the text.

2)

Quote

- The value of $form{'BIDTOVIEW'} is not what you think, you haven't shown us how this is defined. Thus its value is undefined.

Using the same approach as in 1) I place "$delfile" in the text of the page generated in first subroutine. The file name prints in the text. Similarly, I placed $gci, $sid, $session, and $cookie in the text and they printed out as: $cgi - CGI=HASH(0x2310ae0) $sid - 0c8c3cf354e7bbf62650e4c8bf4133cc $cookie - CGISESSID=0c8c3cf354e7bbf62650e4c8bf4133cc; path=/ $session - CGI::Session=HASH(0x235f938)

3) I replaced the print header code and obtained the same result.

4) I am still exploring this comment.

5) both subroutines are part of the original code and they work fine reposting unsold items on the auction.

We're not going to be able to solve the problem based on your incomplete code snippets which don't give us enough context on what your code is doing.

It would be best if you could write a short but complete test script which demonstrates the problem so that we can review it and run some tests.

If you must, you could post your complete script and assuming it's not a huge mess, I might be willing to look it over to see if I can spot the problem. However, since it's about 15,000 lines, I'm not going to spend a lot of time troubleshooting that much code.

Stick to writing your test scripts, they will be most valuable, but just another thought. If its an auction script with a user system already in place, does it already use a stateful session via CGI::Session, if so then this would likely collide with your new session if both use the default cookie name.

Also, your I/O code inevitably works for a single user, but multiple users would share the same file. You would need a file per user identified by a unique id. This is effectively a session and the process CGI::Session is designed to handle.

Its regularly difficult when modifying a large script, particularly one someone else wrote carelessly. Perl scripts are especially difficult with their vast range of syntax styles. It gets easier the more you do it and hitting problems only helps to develop your knowledge and understanding in areas you would otherwise never cover.