# Suite 330, Boston, MA 02111-1307 USA
use strict;
+use vars qw($VERSION $AUTOLOAD $context @context_stack);
BEGIN {
if ($ENV{'HTTP_USER_AGENT'}) {
require CGI::Carp;
+ # FIXME for future reference, CGI::Carp doc says
+ # "Note that fatalsToBrowser does not work with mod_perl version 2.0 and higher."
import CGI::Carp qw(fatalsToBrowser);
sub handle_errors {
- my $msg = shift;
- my $debug_level = C4::Context->preference("DebugLevel");
-
+ my $msg = shift;
+ my $debug_level;
+ eval {C4::Context->dbh();};
+ if ($@){
+ $debug_level = 1;
+ }
+ else {
+ $debug_level = C4::Context->preference("DebugLevel");
+ }
+
+ print q(<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+ <html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
+ <head><title>Koha Error</title></head>
+ <body>
+ );
if ($debug_level eq "2"){
# debug 2 , print extra info too.
my %versions = get_versions();
# a little example table with various version info";
print "
- <h1>debug level $debug_level </h1>
- <p>Got an error: $msg</p>
+ <h1>Koha error</h1>
+ <p>The following fatal error has occurred:</p>
+ <pre><code>$msg</code></pre>
<table>
- <tr><th>Apache<td> $versions{apacheVersion}</tr>
- <tr><th>Koha<td> $versions{kohaVersion}</tr>
- <tr><th>MySQL<td> $versions{mysqlVersion}</tr>
- <tr><th>OS<td> $versions{osVersion}</tr>
- <tr><th>Perl<td> $versions{perlVersion}</tr>
+ <tr><th>Apache</th><td> $versions{apacheVersion}</td></tr>
+ <tr><th>Koha</th><td> $versions{kohaVersion}</td></tr>
+ <tr><th>Koha DB</th><td> $versions{kohaDbVersion}</td></tr>
+ <tr><th>MySQL</th><td> $versions{mysqlVersion}</td></tr>
+ <tr><th>OS</th><td> $versions{osVersion}</td></tr>
+ <tr><th>Perl</th><td> $versions{perlVersion}</td></tr>
</table>";
} elsif ($debug_level eq "1"){
- print "<h1>debug level $debug_level </h1>";
- print "<p>Got an error: $msg</p>";
+ print "
+ <h1>Koha error</h1>
+ <p>The following fatal error has occurred:</p>
+ <pre><code>$msg</code></pre>";
} else {
- print "production mode - trapped fatal";
+ print "<p>production mode - trapped fatal error</p>";
}
- }
- CGI::Carp->set_message(\&handle_errors);
+ print "</body></html>";
+ }
+ CGI::Carp::set_message(\&handle_errors);
+ ## give a stack backtrace if KOHA_BACKTRACES is set
+ ## can't rely on DebugLevel for this, as we're not yet connected
+ if ($ENV{KOHA_BACKTRACES}) {
+ $main::SIG{__DIE__} = \&CGI::Carp::confess;
+ }
} # else there is no browser to send fatals to!
+ $VERSION = '3.00.00.036';
}
use DBI;
use ZOOM;
use XML::Simple;
-
use C4::Boolean;
-
-use vars qw($VERSION $AUTOLOAD $context @context_stack);
-
-$VERSION = '3.00.00.028';
+use C4::Debug;
=head1 NAME
use C4::Context;
- use C4::Context("/path/to/koha.xml");
+ use C4::Context("/path/to/koha-conf.xml");
$config_value = C4::Context->config("config_variable");
=head1 DESCRIPTION
When a Koha script runs, it makes use of a certain number of things:
-configuration settings in F</etc/koha.xml>, a connection to the Koha
+configuration settings in F</etc/koha/koha-conf.xml>, a connection to the Koha
databases, and so forth. These things make up the I<context> in which
the script runs.
the C<&set_context> and C<&restore_context> functions, below.
By default, C4::Context reads the configuration from
-F</etc/koha.xml>. This may be overridden by setting the C<$KOHA_CONF>
+F</etc/koha/koha-conf.xml>. This may be overridden by setting the C<$KOHA_CONF>
environment variable to the pathname of a configuration file to use.
=head1 METHODS
# config
# A reference-to-hash whose keys and values are the
# configuration variables and values specified in the config
-# file (/etc/koha.xml).
+# file (/etc/koha/koha-conf.xml).
# dbh
# A handle to the appropriate database for this context.
# dbh_stack
# Zconn
# A connection object for the Zebra server
-use constant CONFIG_FNAME => "/etc/koha.xml";
+# Koha's main configuration file koha-conf.xml
+# is searched for according to this priority list:
+#
+# 1. Path supplied via use C4::Context '/path/to/koha-conf.xml'
+# 2. Path supplied in KOHA_CONF environment variable.
+# 3. Path supplied in INSTALLED_CONFIG_FNAME, as long
+# as value has changed from its default of
+# '__KOHA_CONF_DIR__/koha-conf.xml', as happens
+# when Koha is installed in 'standard' or 'single'
+# mode.
+# 4. Path supplied in CONFIG_FNAME.
+#
+# The first entry that refers to a readable file is used.
+
+use constant CONFIG_FNAME => "/etc/koha/koha-conf.xml";
# Default config file, if none is specified
+
+my $INSTALLED_CONFIG_FNAME = '__KOHA_CONF_DIR__/koha-conf.xml';
+ # path to config file set by installer
+ # __KOHA_CONF_DIR__ is set by rewrite-confg.PL
+ # when Koha is installed in 'standard' or 'single'
+ # mode. If Koha was installed in 'dev' mode,
+ # __KOHA_CONF_DIR__ is *not* rewritten; instead
+ # developers should set the KOHA_CONF environment variable
$context = undef; # Initially, no context is set
@context_stack = (); # Initially, no saved contexts
=item KOHAVERSION
returns the kohaversion stored in kohaversion.pl file
+
=cut
sub KOHAVERSION {
Returns an object containing the configuration variables. The object's
structure is a bit complex to the uninitiated ... take a look at the
-koha.xml file as well as the XML::Simple documentation for details. Or,
+koha-conf.xml file as well as the XML::Simple documentation for details. Or,
here are a few examples that may give you what you need:
The simple elements nested within the <config> element:
}
sub import {
- my $package = shift;
- my $conf_fname = shift; # Config file name
- my $context;
-
- # Create a new context from the given config file name, if
- # any, then set it as the current context.
- $context = new C4::Context($conf_fname);
- return undef if !defined($context);
- $context->set_context;
+ # Create the default context ($C4::Context::Context)
+ # the first time the module is called
+ # (a config file can be optionaly passed)
+
+ # default context allready exists?
+ return if $context;
+
+ # no ? so load it!
+ my ($pkg,$config_file) = @_ ;
+ my $new_ctx = __PACKAGE__->new($config_file);
+ return unless $new_ctx;
+
+ # if successfully loaded, use it by default
+ $new_ctx->set_context;
+ 1;
}
=item new
$context = new C4::Context;
- $context = new C4::Context("/path/to/koha.xml");
+ $context = new C4::Context("/path/to/koha-conf.xml");
Allocates a new context. Initializes the context from the specified
file, which defaults to either the file given by the C<$KOHA_CONF>
-environment variable, or F</etc/koha.xml>.
+environment variable, or F</etc/koha/koha-conf.xml>.
C<&new> does not set this context as the new default context; for
that, use C<&set_context>.
# check that the specified config file exists and is not empty
undef $conf_fname unless
- (defined $conf_fname && -e $conf_fname && -s $conf_fname);
+ (defined $conf_fname && -s $conf_fname);
# Figure out a good config file to load if none was specified.
if (!defined($conf_fname))
{
# If the $KOHA_CONF environment variable is set, use
# that. Otherwise, use the built-in default.
- $conf_fname = $ENV{"KOHA_CONF"} || CONFIG_FNAME;
+ if (exists $ENV{"KOHA_CONF"} and $ENV{'KOHA_CONF'} and -s $ENV{"KOHA_CONF"}) {
+ $conf_fname = $ENV{"KOHA_CONF"};
+ } elsif ($INSTALLED_CONFIG_FNAME !~ /__KOHA_CONF_DIR/ and -s $INSTALLED_CONFIG_FNAME) {
+ # NOTE: be careful -- don't change __KOHA_CONF_DIR in the above
+ # regex to anything else -- don't want installer to rewrite it
+ $conf_fname = $INSTALLED_CONFIG_FNAME;
+ } elsif (-s CONFIG_FNAME) {
+ $conf_fname = CONFIG_FNAME;
+ } else {
+ warn "unable to locate Koha configuration file koha-conf.xml";
+ return undef;
+ }
}
# Load the desired config file.
$self = read_config_file($conf_fname);
$self->{"marcfromkohafield"} = undef; # the hash with relations between koha table fields and MARC field/subfield
$self->{"userenv"} = undef; # User env
$self->{"activeuser"} = undef; # current active user
+ $self->{"shelves"} = undef;
bless $self, $class;
return $self;
=cut
-#'
-sub config
-{
- my $self = shift;
- my $var = shift; # The config variable to return
-
- return undef if !defined($context->{"config"});
- # Presumably $self->{config} might be
- # undefined if the config file given to &new
- # didn't exist, and the caller didn't bother
- # to check the return value.
+sub _common_config ($$) {
+ my $var = shift;
+ my $term = shift;
+ return undef if !defined($context->{$term});
+ # Presumably $self->{$term} might be
+ # undefined if the config file given to &new
+ # didn't exist, and the caller didn't bother
+ # to check the return value.
# Return the value of the requested config variable
- return $context->{"config"}->{$var};
+ return $context->{$term}->{$var};
}
-sub zebraconfig
-{
- my $self = shift;
- my $var = shift; # The config variable to return
-
- return undef if !defined($context->{"server"});
- # Presumably $self->{config} might be
- # undefined if the config file given to &new
- # didn't exist, and the caller didn't bother
- # to check the return value.
-
- # Return the value of the requested config variable
- return $context->{"server"}->{$var};
+sub config {
+ return _common_config($_[1],'config');
}
-sub ModZebrations
-{
- my $self = shift;
- my $var = shift; # The config variable to return
-
- return undef if !defined($context->{"serverinfo"});
- # Presumably $self->{config} might be
- # undefined if the config file given to &new
- # didn't exist, and the caller didn't bother
- # to check the return value.
-
- # Return the value of the requested config variable
- return $context->{"serverinfo"}->{$var};
+sub zebraconfig {
+ return _common_config($_[1],'server');
+}
+sub ModZebrations {
+ return _common_config($_[1],'serverinfo');
}
+
=item preference
- $sys_preference = C4::Context->preference("some_variable");
+ $sys_preference = C4::Context->preference('some_variable');
Looks up the value of the given system preference in the
systempreferences table of the Koha database, and returns it. If the
-variable is not set, or in case of error, returns the undefined value.
+variable is not set or does not exist, undef is returned.
+
+In case of an error, this may return 0.
+
+Note: It is impossible to tell the difference between system
+preferences which do not exist, and those whose values are set to NULL
+with this method.
=cut
-#'
# FIXME - The preferences aren't likely to change over the lifetime of
# the script (and things might break if they did change), so perhaps
# this function should cache the results it finds.
-sub preference
-{
+sub preference {
my $self = shift;
- my $var = shift; # The system preference to return
- my $retval; # Return value
- my $dbh = C4::Context->dbh or return 0;
+ my $var = shift; # The system preference to return
+ my $dbh = C4::Context->dbh or return 0;
+
# Look up systempreferences.variable==$var
- $retval = $dbh->selectrow_array(<<EOT);
+ my $sql = <<'END_SQL';
SELECT value
FROM systempreferences
- WHERE variable='$var'
+ WHERE variable=?
LIMIT 1
-EOT
+END_SQL
+ my $retval = $dbh->selectrow_array( $sql, {}, $var );
return $retval;
}
C<$self>
-C<$server> one of the servers defined in the koha.xml file
+C<$server> one of the servers defined in the koha-conf.xml file
C<$async> whether this is a asynchronous connection
my $auth=shift;
my $piggyback=shift;
my $syntax=shift;
- if ( defined($context->{"Zconn"}->{$server}) ) {
+ if ( defined($context->{"Zconn"}->{$server}) && (0 == $context->{"Zconn"}->{$server}->errcode()) ) {
return $context->{"Zconn"}->{$server};
# No connection object or it died. Create one.
}else {
+ # release resources if we're closing a connection and making a new one
+ # FIXME: this needs to be smarter -- an error due to a malformed query or
+ # a missing index does not necessarily require us to close the connection
+ # and make a new one, particularly for a batch job. However, at
+ # first glance it does not look like there's a way to easily check
+ # the basic health of a ZOOM::Connection
+ $context->{"Zconn"}->{$server}->destroy() if defined($context->{"Zconn"}->{$server});
+
$context->{"Zconn"}->{$server} = &_new_Zconn($server,$async,$auth,$piggyback,$syntax);
return $context->{"Zconn"}->{$server};
}
Internal function. Creates a new database connection from the data given in the current context and returns it.
-C<$server> one of the servers defined in the koha.xml file
+C<$server> one of the servers defined in the koha-conf.xml file
C<$async> whether this is a asynchronous connection
my $db_name = $context->config("database");
my $db_host = $context->config("hostname");
- my $db_port = $context->config("port") or "";
+ my $db_port = $context->config("port") || '';
my $db_user = $context->config("user");
my $db_passwd = $context->config("pass");
+ # MJR added or die here, as we can't work without dbh
my $dbh= DBI->connect("DBI:$db_driver:dbname=$db_name;host=$db_host;port=$db_port",
- $db_user, $db_passwd);
+ $db_user, $db_passwd) or die $DBI::errstr;
+ my $tz = $ENV{TZ};
if ( $db_driver eq 'mysql' ) {
# Koha 3.0 is utf-8, so force utf8 communication between mySQL and koha, whatever the mysql default config.
# this is better than modifying my.cnf (and forcing all communications to be in utf8)
- $dbh->do("set NAMES 'utf8'") if ($dbh);
$dbh->{'mysql_enable_utf8'}=1; #enable
+ $dbh->do("set NAMES 'utf8'");
+ ($tz) and $dbh->do(qq(SET time_zone = "$tz"));
}
elsif ( $db_driver eq 'Pg' ) {
$dbh->do( "set client_encoding = 'UTF8';" );
+ ($tz) and $dbh->do(qq(SET TIME ZONE = "$tz"));
}
return $dbh;
}
if ($context->{"dbh"} && $context->preference('insecure')) {
my %insecure;
$insecure{flags} = '16382';
- $insecure{branchname} ='Insecure',
+ $insecure{branchname} ='Insecure';
$insecure{number} ='0';
$insecure{cardnumber} ='0';
$insecure{id} = 'insecure';
return $cell;
}
+sub set_shelves_userenv ($$) {
+ my ($type, $shelves) = @_ or return undef;
+ my $activeuser = $context->{activeuser} or return undef;
+ $context->{userenv}->{$activeuser}->{barshelves} = $shelves if $type eq 'bar';
+ $context->{userenv}->{$activeuser}->{pubshelves} = $shelves if $type eq 'pub';
+ $context->{userenv}->{$activeuser}->{totshelves} = $shelves if $type eq 'tot';
+}
+
+sub get_shelves_userenv () {
+ my $active;
+ unless ($active = $context->{userenv}->{$context->{activeuser}}) {
+ $debug and warn "get_shelves_userenv cannot retrieve context->{userenv}->{context->{activeuser}}";
+ return undef;
+ }
+ my $totshelves = $active->{totshelves} or undef;
+ my $pubshelves = $active->{pubshelves} or undef;
+ my $barshelves = $active->{barshelves} or undef;
+ return ($totshelves, $pubshelves, $barshelves);
+}
+
=item _new_userenv
C4::Context->_new_userenv($session);
# A little example sub to show more debugging info for CGI::Carp
sub get_versions {
my %versions;
- $versions{kohaVersion} = C4::Context->config("kohaversion");
+ $versions{kohaVersion} = KOHAVERSION();
+ $versions{kohaDbVersion} = C4::Context->preference('version');
$versions{osVersion} = `uname -a`;
$versions{perlVersion} = $];
$versions{mysqlVersion} = `mysql -V`;
=head1 SEE ALSO
+XML::Simple
+
=head1 AUTHORS
Andrew Arensburger <arensb at ooblick dot com>