How to delete temporary file after displaying in browser ?

Y

Yohan N Leder

How do you proceed to unlink a temporary file at the end of your CGI
treatment. I have to upload an image from client, display-it in his
browser with some info about it, then delete it on server.

Would you fork the unlink ? Would you add a sleep prior to unlink after
printing toward browser ? Do you write a separate script which would
delete all temporaries file periodically ?

What's the right way according to you ?
 
B

Bart Van der Donck

Yohan said:
How do you proceed to unlink a temporary file at the end of your CGI
treatment. I have to upload an image from client, display-it in his
browser with some info about it, then delete it on server.

Would you fork the unlink ?
No.

Would you add a sleep prior to unlink after printing toward browser ?

Maybe just to make sure - it won't hurt anyhow. But be careful for max
runtime flags, esp. in combintation with potentially large file
uploads.
Do you write a separate script which would
delete all temporaries file periodically ?

Yes, a low-priority job deleting files older than X.
What's the right way according to you ?

Normally you can just use unlink without need for extra precautions
here. The CGI has sent everything before the unlink-command is invoked,
that is, unlink will "wait" until the output stream is closed.
 
Y

Yohan N Leder

Normally you can just use unlink without need for extra precautions
here. The CGI has sent everything before the unlink-command is invoked,
that is, unlink will "wait" until the output stream is closed.

Sure ? So, you say something like this is enough without any more
precaution ?

#!/usr/bin/perl
use CGI::Carp qw/fatalsToBrowser/;
use strict;
use warnings;
$|=1;
print "Content-type: text/html; charset=iso-8859-1\n\n";
my $imgpath = "../httpdocs/upload/tmp.gif";
my $imgurl = "/upload/tmp.gif";
my $imghtm = "<img src='".$imgurl."' border=0 width=150 height=150>";
print "<html><head></head><body>".$imghtm."</body></html>";
unlink $imgpath;
exit 0;

Knowing, of course, that tmp.gif has been correctly uploaded previously
and exists on server now.
 
Y

Yohan N Leder

I'm not really sure if I understand. It seems that you create a
temporary but *static* file to be served directly by the browser. Why
don't you serve it dinamically instead?

The file I have to display, then delete has been previously uploaded
from client to server. After this upload stage (done), I have to do
something like this (shorten at its maximum) :

#!/usr/bin/perl
use CGI::Carp qw/fatalsToBrowser/;
use strict;
use warnings;
$|=1;
print "Content-type: text/html; charset=iso-8859-1\n\n";
my $imgpath = "../httpdocs/upload/tmp.gif";
my $imgurl = "/upload/tmp.gif";
my $imghtm = "<img src='".$imgurl."' border=0 width=150 height=150>";
print "<html><head></head><body>".$imghtm."</body></html>";
#... now I need to unlink this $imgpath ...
exit 0;

So, how to achive the commented step ? Can I just unlink after printing
?
 
B

Bart Van der Donck

Yohan said:
Sure ? So, you say something like this is enough without any more
precaution ?

#!/usr/bin/perl
use CGI::Carp qw/fatalsToBrowser/;
use strict;
use warnings;
$|=1;
print "Content-type: text/html; charset=iso-8859-1\n\n";
my $imgpath = "../httpdocs/upload/tmp.gif";
my $imgurl = "/upload/tmp.gif";
my $imghtm = "<img src='".$imgurl."' border=0 width=150 height=150>";
print "<html><head></head><body>".$imghtm."</body></html>";
unlink $imgpath;
exit 0;

That's a different story; the image is not part of the CGI's output
stream here. It just generates the HTML. When client receives the HTML,
it sees that there is an <img> in it and fires off a second request to
server for that image file. It's perfectly possible that the file has
been deleted on server by then.

As a general principle, I meant something like this:

#!/usr/bin/perl
print "Content-Type: image/gif\n\n";
use strict;
use warnings;
my $file = 'image.gif';
my $gif;
open my $F, '<', $file || die "Cant open $file: $!";
$gif.=$_ while(<$F>);
close $F || die "Cant close $file: $!";
unlink $file; # safe to unlink here

You're right that unlink is not good in your code. I would probably use
a cronjob to delete temporary files older than X.
 
Y

Yohan N Leder

As a general principle, I meant something like this:

#!/usr/bin/perl
print "Content-Type: image/gif\n\n";
use strict;
use warnings;
my $file = 'image.gif';
my $gif;
open my $F, '<', $file || die "Cant open $file: $!";
$gif.=$_ while(<$F>);
close $F || die "Cant close $file: $!";
unlink $file; # safe to unlink here

So, if I well understand, I could print out something like this in my
main CGI script :

my imgb64 = ... here the base64 encoding of the temp image file
my $imghtm = "<img src='"/cgi-bin/getimg.cgi?$imgbase64."' border=0
width=150 height=150>";
print "<html><head></head><body>".$imghtm."</body></html>";
unlink $imgpath;
exit 0;

with getimg.cgi processing to print the base64 content toward the
browser : right ?
You're right that unlink is not good in your code. I would probably use
a cronjob to delete temporary files older than X.

Yes, I known it also a possibility, but the reason why I'm trying to
work around this is that this script will be used on several servers,
some being hosted by a third party company and it implies to add some
more documentation about script shell editing, about cronjob scheduling
and in the worst case something saying webmaster has to contact the
admin. Well, even if it's a lot easier, if I could do the job from
within my CGI script(s) it would be better for future install.
 
B

Bart Van der Donck

Yohan said:
[...]
So, if I well understand, I could print out something like this in my
main CGI script :

my imgb64 = ... here the base64 encoding of the temp image file
my $imghtm = "<img src='"/cgi-bin/getimg.cgi?$imgbase64."' border=0
width=150 height=150>";
print "<html><head></head><body>".$imghtm."</body></html>";
unlink $imgpath;
exit 0;

with getimg.cgi processing to print the base64 content toward the
browser : right ?

URLs have length limitations both at server side and at client side
(IIRC I think MSIE allows up to 2048 characters). You could use POST in
stead of GET to work around this:

<form method="post" action="/cgi-bin/getimg.cgi">
<input type="hidden" name="imgbase64" value="$imgbase64">
<input type="submit" value="View image">
</form>

Or use a frame/iframe to display the image and automatically submit the
form.

Or you could use GET with another encryption algorithm that guarantees
a URL that is short enough.

Or let the main program sleep for 30 seconds or so and then perform the
unlink before quitting.

Plenty of choice :)
 
Y

Yohan N Leder

As a side note, you know that this will have to go away in
"production", don't you?

Of course : I use this line during all dev stage until final touch. And,
better, all final CGI uses tainted mode.
".$imgurl." ?
^
^

You don't print() the image, but its url which will make the browser
issue another request. If you unlink() the image at this point it may
not be available when the request is done.

I've effectively realised that it's the difficulty reading the Bart
reply too ; thanks Michele. Well, so it sounds it lets 3 solutions : 1)
cronjob, but complicate the install on some hosted sites 2) <img>
requesting to a separate cgi returning the image data, but the problem
seems to be the url limitation (unless POST of a form autosubmitted) 3)
unlink really later in the script.
 
Y

Yohan N Leder

Or use a frame/iframe to display the image and automatically submit the
form.

Hmmm, thanks Bart, nut not really happy to go through iframe :-(
Or you could use GET with another encryption algorithm that guarantees
a URL that is short enough.

What for example ?
Or let the main program sleep for 30 seconds or so and then perform the
unlink before quitting.

Well, maybe the easier : I've just to found where is the best place...
Humm, maybe an idea : I could write down name of temporary image in a
log, then delete the one produced by previous session at the beginning
of every new one.
 
J

J. Gleixner

Yohan said:
I've effectively realised that it's the difficulty reading the Bart
reply too ; thanks Michele. Well, so it sounds it lets 3 solutions : 1)
cronjob, but complicate the install on some hosted sites 2) <img>
requesting to a separate cgi returning the image data, but the problem
seems to be the url limitation (unless POST of a form autosubmitted) 3)
unlink really later in the script.

Also, you could fork a process that sleep for X seconds, then unlink
the file, or look at using 'at' or 'batch', if you're on a *nix platform.
 
X

xhoster

Yohan N Leder said:
Of course : I use this line during all dev stage until final touch. And,
better, all final CGI uses tainted mode.

I don't really see why it will have to go away anyway, taint or no.
I've effectively realised that it's the difficulty reading the Bart
reply too ; thanks Michele. Well, so it sounds it lets 3 solutions : 1)
cronjob, but complicate the install on some hosted sites

You could just make the cgi script, once it is done, close all it's file
handles and fork and exit, then have the child go on to do whatever the
cron job would do. That way everything stays as part of one script, and
you don't need to mess around with cronjob. If you don't want the clean up
to be run too often (i.e. not once per "hit"), you could check a file.

if ( -M 'log/cleanup' > 1/24 ) { #
fork and exit;
open STDERR, ">>log/cleanup';
close STDOUT;
#.....whatever the cron job would do
warn "Done cleaning up"
}

This has a race condition that will (rarely) allow more than one clean-up
to run at the same time. If that is not okay, then do something else.
2) <img>
requesting to a separate cgi returning the image data, but the problem
seems to be the url limitation (unless POST of a form autosubmitted)

I really like this method if you know the data will be small. Also, for
some browsers you don't even need to do the extra server round trip for
each image. Google this group on "exploder_render" for info.


Xho
 
Y

Yohan N Leder

glex_no- said:
Also, you could fork a process that sleep for X seconds, then unlink
the file, or look at using 'at' or 'batch', if you're on a *nix platform.

Yes, unlink through fork was an idea, but Bart told me it was not a good
idea... So, I didn't gone deeper towards this direction... And more
knowing this script will run under Fedora, Windows and FreeBSD and, at
least, some Perl releases crashe using under Win32.
 
Y

Yohan N Leder

[quoted text muted]
2) <img>
requesting to a separate cgi returning the image data, but the problem
seems to be the url limitation (unless POST of a form autosubmitted)

I really like this method if you know the data will be small. Also, for
some browsers you don't even need to do the extra server round trip for
each image. Google this group on "exploder_render" for info.

Yep, it sounds nice unless limitation. So, I think I'll go toward two
solutions : a 1st one I'll reserve for small images, passing image data
through GET as said here ; and a snd one passing the image file path,
then the cgi called will delete the file itself after sending toward
browser.

Also, about fork : as replied to J.G., I would be agree of it was not so
problematic under Win32 (some Perl crash on fork under Win).
 
B

Bart Van der Donck

Yohan said:
What for example ?

I'm not sure if such a 'shortener' exists. If yes, it probably requires
quite some memory resources.
[...]
Humm, maybe an idea : I could write down name of temporary image in a
log, then delete the one produced by previous session at the beginning
of every new one.

A classical design mistake, I'm afraid. A process could unlink a file
from a previous process that is still reading the file (or even hasn't
start reading it, or is even writing the file, e.g. when the second
process deals with a light image and the first one with a heavy image).
 
B

Brian Helterline

Yohan said:
Sure ? So, you say something like this is enough without any more
precaution ?

#!/usr/bin/perl
use CGI::Carp qw/fatalsToBrowser/;
use strict;
use warnings;
$|=1;
print "Content-type: text/html; charset=iso-8859-1\n\n";
my $imgpath = "../httpdocs/upload/tmp.gif";
my $imgurl = "/upload/tmp.gif";
my $imghtm = "<img src='".$imgurl."' border=0 width=150 height=150>";

An alternate approach would be to output something like this:
my $imghtm = "<img src='"/cgi/fetch.pl?image=$imgurl"' border=0
width=150 height=150>";

and then when the browser issues another request to get this image,
fetch.pl serves it up and then deletes it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,201
Messages
2,571,049
Members
47,655
Latest member
eizareri

Latest Threads

Top