Undefined subroutine error in perl package - perl

This is main file upload.cgi
#!/usr/bin/perl
use strict;
use lib '.';
use XFSConfig;
use XUpload ;
use CGI::Carp qw(fatalsToBrowser);
use CGI;
use Fcntl ':flock';
use LWP::UserAgent;
use HTTP::Cookies;
use HTML::Form;
use Encode;
sub xmessage
{
my ($msg) = #_;
&lmsg($msg);
$msg=~s/'/\\'/g;
$msg=~s/<br>/\\n/g;
print"Content-type: text/html\n\n";
print"<HTML><HEAD><Script>alert('$msg');</Script></HEAD><BODY><b>$msg</b></BODY></HTML>";
exit;
}
sub lmsg
{
my $msg = shift;
open(F,">$c->{htdocs_tmp_dir}/$sid.html");
print F qq[new Object({"state":"error", "msg":"$msg"})];
close F;
&logit($msg);
}
and this function calls a function
&XUpload::ProcessFile()
and XUpload::ProcessFile() function calls a function &xmessage("Fatal"); which is defined in upload.cgi
and now i get this error
Undefined subroutine &XUpload::xmessage called at Modules/XUpload.pm line 17.
It seems package XUpload is unable to find function xmessage defined in upload.cgi at all

The xmessage sub in your cgi script is defined in the main package, while the XUpload module is (apparently) operating in the XUpload namespace.
Resolving this issue will ultimately involve learning about Perl's namespaces and the Exporter module. But a quick and dirty fix is to create an alias for your sub in the XUpload package. Add this line to your main script:
*XUpload::xmessage = *message;

Related

Not able to export methods using Exporter module in perl

I'm trying to export the methods written in my custom module using Exporter perl module. Below is my custom module ops.pm
use strict;
use warnings;
use Exporter;
package ops;
our #ISA= qw/Exporter/;
our #EXPORT=qw/add/;
our #EXPORT_OK=qw/mutliply/;
sub new
{
my $class=shift;
my $self={};
bless($self,$class);
return $self;
}
sub add
{
my $self=shift;
my $num1=shift;
my $num2=shift;
return $num1+$num2;
}
sub mutliply
{
my $self=shift;
my $num1=shift;
my $num2=shift;
return $num1*$num2;
}
1;
Below is the script ops_export.pl using ops.pm
#!/usr/bin/perl
use strict;
use warnings;
use ops;
my $num=add(1,2);
print "$num\n";
when i execute the above script i'm getting below error.
Undefined subroutine &main::add called at ops_export.pl line 8.
I'm not getting why my script is checking in &main package even though i have exported the add in ops.pm using #EXPORT
Where am i going wrong?
ops is a pragma already used by Perl. From the docs:
ops - Perl pragma to restrict unsafe operations when compiling
I don't know what that actually means but that's the issue here.
Rename your module to something else, preferably something with uppercase characters as #simbabque suggests in a comment, because lowercase "modules" are somehow reserved for pragmas (think of warnings or strict).
Also: Calling your add function won't work because you mix up OO code and regular functions. Your add expects three parameters and you supply only two (1 and 2).
When writing OO modules you shouldn't export anything (not even new), i.e.:
package Oops;
use strict; use warnings;
use OtherModules;
# don't mention 'Export' at all
sub new {
...
}
sub add {
...
}
1;
And then in your scripts:
use strict; use warnings;
use Oops;
my $calculator = Oops->new();
my $result = $calculator->add(1, 2);
print $result, "\n"; # gives 3

Log4perl Singleton usage

I'm new to Log4perl and am trying to figure out why I get two different loggers in the below setup. My understanding is that this should be a singleton and calling get_logger() would return the same instance of the object each time.
Test.pm
#!/usr/bin/perl
package Example::Test;
use strict;
use warnings;
use Exporter;
our #ISA = qw(Exporter);
our #EXPORT = qw(test);
sub test
{
my $logger = Log::Log4perl->get_logger();
print $logger, "\n";
}
test.pl
#!/usr/bin/perl
use strict;
use warnings;
use Log::Log4perl;
use Example::Test;
# Logger configuration
Log::Log4perl->init('/etc/log4perl.conf');
my $logger = Log::Log4perl->get_logger();
print $logger, "\n";
my $engine = test();
Output
Log::Log4perl::Logger=HASH(0x12093d0)
Log::Log4perl::Logger=HASH(0x29b4950)
You didn't specify a logging category, so your code does the equivalent of
Log::Log4perl->get_logger(__PACKAGE__);
where __PACKAGE__ is Example::Test inside your module and main inside your script.
From the documentation:
Categories are also called "Loggers" in Log4perl, both refer to the same thing and these terms are used interchangeably. Log::Log4perl uses categories to determine if a log statement in a component should be executed or suppressed at the current logging level. Most of the time, these categories are just the classes the log statements are located in...
In general, you probably want a separate logger for each module so you can handle log messages from different parts of your codebase differently.
On the other hand, if Example::Test is supposed to be a wrapper for Log::Log4perl, register it:
package My::Wrapper;
use strict;
use warnings 'all';
use 5.010;
use Log::Log4perl;
Log::Log4perl->wrapper_register(__PACKAGE__);
sub foo {
my $logger = Log::Log4perl->get_logger;
say $logger;
$logger->warn('foo');
}
1;
When you call My::Wrapper::foo() from package main, the logging category will be main::.

perl : how to share variables and subroutines across various perl files

I am trying something of this sort:
main.pl
use YAML::XS
our $yaml_input = YAML::XS::LoadFile("$input_file");
parse_yaml($yaml_input);
#this variable has to be passed to the function parse_yaml which is in other file.
parser.pl
sub parse_yaml($yaml_input)
{
#some processing
}
I have read few answers about using a package but how do we use it in this case.
Basically you need to import the parse_yaml subroutine into you current program, rather than trying to export the value of the parameter, but I'm uncertain why you have written your own parse_yaml utility when YAML::XS::LoadFile has already done it for you
This is all very clearly described in the documentation for the Exporter module
Here's a brief example
main.pl
use strict;
use warnings 'all';
use YAML::XS 'LoadFile';
use MyUtils 'parse_yaml';
my $input_file = 'data.yaml';
my $yaml_input = LoadFile($input_file);
parse_yaml($input_file);
# this variable has to be passed to the function parse_yaml which is in other file.
MyUtils.pm
package MyUtils;
use strict;
use warnings;
use Exporter 'import';
our #EXPORT_OK = 'parse_yaml';
sub parse_yaml {
my ($yaml_file) = #_;
# some processing
}
1;

The "wrong" package specification is required to call a subroutine

I would like to ask you for advice on writing a Perl module. We have three files.
(1) main.pl : uses my_function()
#!/usr/bin/perl
use strict;
use warnings;
use MyClass;
require "./subroutines.pl";
my $instance = MyClass->new({});
$instance->my_method("a");
MyClass::my_function("b"); # This works.
my_function("c"); # Undefined subroutine &main::my_function called
exit;
(2) MyClass.pm : defines MyClass class. my_method() uses my_function() which is defined in "subroutines.pl".
package MyClass;
use strict;
use warnings;
require "./subroutines.pl";
sub new {
my $class = shift;
my $self = shift;
return bless $self, $class;
}
sub my_method{
my $self = shift;
my $text = shift;
my_function($text);
}
1;
(3) subroutines.pl : defines my_function().
use strict;
use warnings;
sub my_function {
print "[$_[0]] My function is working!\n";
}
1;
The problem is that my_function() is not working in main.pl, even though the source code has require "./subroutines.pl", while MyClass::my_function() works.
[a] My function is working!
[b] My function is working!
Undefined subroutine &main::my_function called at main.pl line 11.
Because my_function() is useful for me, I want to use it in both main.pl and MyClass.pm, but the subroutine is so general that it is quite strange to define it as a method in MyClass.pm. But it is also strange (to me) that we have to write MyClass:: before my_function(), because the subroutine does not depend on MyClass.
My question is: is it possible to modify the above codes so that my_function() works in main.pl without adding MyClass:: before the function call?
require only executes a given file once, so you would need do, but that would created two copies of the subroutine. Use a proper module instead, and use Exporter to export the symbol.
Subroutines.pm:
package Subroutines;
use strict;
use warnings;
use Exporter qw( import );
our #EXPORT = qw( my_function );
sub my_function {
print "[$_[0]] My function is working!\n";
}
1;
and
use Subroutines;

Why do I get the error-message "Undefined subroutine" when calling a function from a module?

I have a module named Helpers.pm:
use warnings;
use 5.012;
package Helpers;
use Exporter qw(import);
our #EXPORT_OK = qw(my_function);
sub my_function {
return { one => 1, two => 2 };
}
1;
an call it in the script:
#!/usr/bin/env perl
use warnings;
use 5.012;
use Data::Dumper;
use FindBin qw($RealBin);
use lib $RealBin;
use Helpers qw(my_function);
my $ref = my_function();
say Dumper $ref;
and I get no error-messages.
But when I put the module in the directory TestDir an modify the script like this:
#!/usr/bin/env perl
use warnings;
use 5.012;
use Data::Dumper;
use FindBin qw($RealBin);
use lib $RealBin;
use TestDir::Helpers qw(my_function);
my $ref = my_function();
say Dumper $ref;
I get this error-message:
Undefined subroutine &main::my_function called at ./perl.pl line 10.
Why do I get this error-message?
You probably forgot to change the package declaration from
package Helpers;
to:
package TestDir::Helpers;
i think it is because it cannot find your module in lib path, http://perldoc.perl.org/lib.html.
use lib 'TestDir';
use Helpers qw(my_function);