jDawg
jDawg

Reputation:

Perl - why won't this simple file open request work?

OK, so this is so simple but for the life of me I can't figure out why the code below doesn't work.

I'm trying to simply write a CGI script that creates sequentially numbered files. I'm using a counter (stored in a separate file) to keep track of the last ordinal used, and then generating a unique filename using sprintf. The uniquely named file is NOT created. I suspect it's an issue with sprintf(...) not correctly converting $ordinal to a scalar?

If I assign $ordinal by say replacing the line $ordinal = <NUMPHOTOS>; with $ordinal=42; the code works fine and a file named 00000042.jpg is created.

What am I doing wrong here?

Help!

my ($filename, $ordinal);

local $| = 1;
print "Content-type: text/plain\n\n";

# NOTE: $ordinal is set to zero if the file doesn't exist
open (NUMPHOTOS, "<numpics.dat");
$ordinal = <NUMPHOTOS>;
print "ordinal = $ordinal";
$filename = sprintf("%08d.jpg", $ordinal );
close (NUMPHOTOS);

open (NUMPHOTOS, ">numpics.dat");
$ordinal += 1;
print NUMPHOTOS $ordinal;
close (NUMPHOTOS);

open ( UPLOADFILE, ">$filename" ) or die "ERROR: can't open $filename: $! \n"; 
print "writing out file $filename...\n";
print UPLOADFILE 'hello world';
close UPLOADFILE;

Upvotes: 0

Views: 2117

Answers (6)

Brad Gilbert
Brad Gilbert

Reputation: 34110

Here is my attempt to fix up your program.

I think your problem was the lack of chomp();

use strict;
use warnings;
use autodie; # don't need to check the return value of open() or close()

my( $filename, $ordinal );

local $| = 1;
print "Content-type: text/plain\n\n";

# NOTE: $ordinal is set to zero if the file doesn't exist
{
  open( my $num_photos, '<', 'numpics.dat' );
  $ordinal = <$num_photos>;
  chomp $ordinal; # <--

  print "ordinal = $ordinal\n";
  $filename = sprintf("%08d.jpg", $ordinal );
  print "filename = $filename\n";
  close ($num_photos);
}
{
  open( my $num_photos, '>', 'numpics.dat' );
  $ordinal += 1;
  print {$num_photos} $ordinal;
  close( $num_photos );
}
{
  open( my $upload_file, '>', $filename );
  print "writing out file $filename...\n";
  print {$upload_file} 'hello world';
  close $upload_file;
}

Note that this still doesn't attempt to resolve locking problems. So if this needs to be atomic, you may want to ask another question

Upvotes: 0

cliveholloway
cliveholloway

Reputation: 369

Is there a newline in the file? What happens to $ordinal if you change:

$ordinal = <NUMPHOTOS>;

to

<NUMPHOTOS> =~ /(\d+)/ and $ordinal = $1;

?

Upvotes: 0

mleykamp
mleykamp

Reputation: 1366

  1. Does print "ordinal = $ordinal"; print "ordinal = 42"?
  2. What number is getting stored in numpics.dat after a run?
  3. Is it possible the script is writing 00000000.jpg over and over again?

Upvotes: 0

Massa
Massa

Reputation: 8972

As everybody mentioned, you should:

Use strictures --

use strict;
use warnings;
use diagnostics; # will help you understand the error messages

Check the file name, the current directory and the permissions on writing the filename;

Use the 3-parameter open, and lexical filehandles, AND check the operations --

open my $uploadfile, '>', $filename or die "could not open $filename: $!";
print $uploadfile "Hello, uploadfile!\n" or die "could not print at $filename: $!";
close $uploadfile or die "could not close $filename: $!";

Upvotes: 1

Alexandr Ciornii
Alexandr Ciornii

Reputation: 7394

First add "use strict;use warnings;use diagnostics;use Fatal qw/:void open close/;" at start of your code, after #!.

my $ordinal=0;
if (-e 'numpics.dat') {
 open (my $NUMPHOTOS, "<","numpics.dat");
 $ordinal = <$NUMPHOTOS>;
 close ($NUMPHOTOS);
}
print "ordinal = $ordinal\n";
my $filename = sprintf("%08d.jpg", $ordinal );

Also it is a good idea to read Ovid's CGI Course.

Upvotes: 3

J-16 SDiZ
J-16 SDiZ

Reputation: 26910

Perl have no problem sprintf() a string-number --- it is not strongly typed.

Make sure you have the permission to create files with CGI. Some web hosting require chmod 755 on the directory you write.

Upvotes: 1

Related Questions