]> git.koha-community.org Git - koha.git/blob - C4/Context.pm
Merge remote-tracking branch 'origin/new/bug_6530'
[koha.git] / C4 / Context.pm
1 package C4::Context;
2 # Copyright 2002 Katipo Communications
3 #
4 # This file is part of Koha.
5 #
6 # Koha is free software; you can redistribute it and/or modify it under the
7 # terms of the GNU General Public License as published by the Free Software
8 # Foundation; either version 2 of the License, or (at your option) any later
9 # version.
10 #
11 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
12 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License along
16 # with Koha; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19 use strict;
20 use warnings;
21 use vars qw($VERSION $AUTOLOAD $context @context_stack $servers $memcached $ismemcached);
22
23 BEGIN {
24         if ($ENV{'HTTP_USER_AGENT'})    {
25                 require CGI::Carp;
26         # FIXME for future reference, CGI::Carp doc says
27         #  "Note that fatalsToBrowser does not work with mod_perl version 2.0 and higher."
28                 import CGI::Carp qw(fatalsToBrowser);
29                         sub handle_errors {
30                             my $msg = shift;
31                             my $debug_level;
32                             eval {C4::Context->dbh();};
33                             if ($@){
34                                 $debug_level = 1;
35                             } 
36                             else {
37                                 $debug_level =  C4::Context->preference("DebugLevel");
38                             }
39
40                 print q(<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
41                             "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
42                        <html lang="en" xml:lang="en"  xmlns="http://www.w3.org/1999/xhtml">
43                        <head><title>Koha Error</title></head>
44                        <body>
45                 );
46                                 if ($debug_level eq "2"){
47                                         # debug 2 , print extra info too.
48                                         my %versions = get_versions();
49
50                 # a little example table with various version info";
51                                         print "
52                                                 <h1>Koha error</h1>
53                                                 <p>The following fatal error has occurred:</p> 
54                         <pre><code>$msg</code></pre>
55                                                 <table>
56                                                 <tr><th>Apache</th><td>  $versions{apacheVersion}</td></tr>
57                                                 <tr><th>Koha</th><td>    $versions{kohaVersion}</td></tr>
58                                                 <tr><th>Koha DB</th><td> $versions{kohaDbVersion}</td></tr>
59                                                 <tr><th>MySQL</th><td>   $versions{mysqlVersion}</td></tr>
60                                                 <tr><th>OS</th><td>      $versions{osVersion}</td></tr>
61                                                 <tr><th>Perl</th><td>    $versions{perlVersion}</td></tr>
62                                                 </table>";
63
64                                 } elsif ($debug_level eq "1"){
65                                         print "
66                                                 <h1>Koha error</h1>
67                                                 <p>The following fatal error has occurred:</p> 
68                         <pre><code>$msg</code></pre>";
69                                 } else {
70                                         print "<p>production mode - trapped fatal error</p>";
71                                 }       
72                 print "</body></html>";
73                         }
74                 #CGI::Carp::set_message(\&handle_errors);
75                 ## give a stack backtrace if KOHA_BACKTRACES is set
76                 ## can't rely on DebugLevel for this, as we're not yet connected
77                 if ($ENV{KOHA_BACKTRACES}) {
78                         $main::SIG{__DIE__} = \&CGI::Carp::confess;
79                 }
80     }   # else there is no browser to send fatals to!
81
82     # Check if there are memcached servers set
83     $servers = $ENV{'MEMCACHED_SERVERS'};
84     if ($servers) {
85         # Load required libraries and create the memcached object
86         require Cache::Memcached;
87         $memcached = Cache::Memcached->new({
88                       servers => [ $servers ],
89                       debug   => 0,
90                       compress_threshold => 10_000,
91                       namespace => $ENV{'MEMCACHED_NAMESPACE'} || 'koha'
92                   });
93         # Verify memcached available (set a variable and test the output)
94         $ismemcached = $memcached->set('ismemcached','1');
95     }
96
97         $VERSION = '3.00.00.036';
98 }
99
100 use DBI;
101 use ZOOM;
102 use XML::Simple;
103 use C4::Boolean;
104 use C4::Debug;
105 use POSIX ();
106
107 =head1 NAME
108
109 C4::Context - Maintain and manipulate the context of a Koha script
110
111 =head1 SYNOPSIS
112
113   use C4::Context;
114
115   use C4::Context("/path/to/koha-conf.xml");
116
117   $config_value = C4::Context->config("config_variable");
118
119   $koha_preference = C4::Context->preference("preference");
120
121   $db_handle = C4::Context->dbh;
122
123   $Zconn = C4::Context->Zconn;
124
125   $stopwordhash = C4::Context->stopwords;
126
127 =head1 DESCRIPTION
128
129 When a Koha script runs, it makes use of a certain number of things:
130 configuration settings in F</etc/koha/koha-conf.xml>, a connection to the Koha
131 databases, and so forth. These things make up the I<context> in which
132 the script runs.
133
134 This module takes care of setting up the context for a script:
135 figuring out which configuration file to load, and loading it, opening
136 a connection to the right database, and so forth.
137
138 Most scripts will only use one context. They can simply have
139
140   use C4::Context;
141
142 at the top.
143
144 Other scripts may need to use several contexts. For instance, if a
145 library has two databases, one for a certain collection, and the other
146 for everything else, it might be necessary for a script to use two
147 different contexts to search both databases. Such scripts should use
148 the C<&set_context> and C<&restore_context> functions, below.
149
150 By default, C4::Context reads the configuration from
151 F</etc/koha/koha-conf.xml>. This may be overridden by setting the C<$KOHA_CONF>
152 environment variable to the pathname of a configuration file to use.
153
154 =head1 METHODS
155
156 =cut
157
158 #'
159 # In addition to what is said in the POD above, a Context object is a
160 # reference-to-hash with the following fields:
161 #
162 # config
163 #    A reference-to-hash whose keys and values are the
164 #    configuration variables and values specified in the config
165 #    file (/etc/koha/koha-conf.xml).
166 # dbh
167 #    A handle to the appropriate database for this context.
168 # dbh_stack
169 #    Used by &set_dbh and &restore_dbh to hold other database
170 #    handles for this context.
171 # Zconn
172 #     A connection object for the Zebra server
173
174 # Koha's main configuration file koha-conf.xml
175 # is searched for according to this priority list:
176 #
177 # 1. Path supplied via use C4::Context '/path/to/koha-conf.xml'
178 # 2. Path supplied in KOHA_CONF environment variable.
179 # 3. Path supplied in INSTALLED_CONFIG_FNAME, as long
180 #    as value has changed from its default of 
181 #    '__KOHA_CONF_DIR__/koha-conf.xml', as happens
182 #    when Koha is installed in 'standard' or 'single'
183 #    mode.
184 # 4. Path supplied in CONFIG_FNAME.
185 #
186 # The first entry that refers to a readable file is used.
187
188 use constant CONFIG_FNAME => "/etc/koha/koha-conf.xml";
189                 # Default config file, if none is specified
190                 
191 my $INSTALLED_CONFIG_FNAME = '__KOHA_CONF_DIR__/koha-conf.xml';
192                 # path to config file set by installer
193                 # __KOHA_CONF_DIR__ is set by rewrite-confg.PL
194                 # when Koha is installed in 'standard' or 'single'
195                 # mode.  If Koha was installed in 'dev' mode, 
196                 # __KOHA_CONF_DIR__ is *not* rewritten; instead
197                 # developers should set the KOHA_CONF environment variable 
198
199 $context = undef;        # Initially, no context is set
200 @context_stack = ();        # Initially, no saved contexts
201
202
203 =head2 KOHAVERSION
204
205 returns the kohaversion stored in kohaversion.pl file
206
207 =cut
208
209 sub KOHAVERSION {
210     my $cgidir = C4::Context->intranetdir;
211
212     # Apparently the GIT code does not run out of a CGI-BIN subdirectory
213     # but distribution code does?  (Stan, 1jan08)
214     if(-d $cgidir . "/cgi-bin"){
215         my $cgidir .= "/cgi-bin";
216     }
217     
218     do $cgidir."/kohaversion.pl" || die "NO $cgidir/kohaversion.pl";
219     return kohaversion();
220 }
221 =head2 read_config_file
222
223 Reads the specified Koha config file. 
224
225 Returns an object containing the configuration variables. The object's
226 structure is a bit complex to the uninitiated ... take a look at the
227 koha-conf.xml file as well as the XML::Simple documentation for details. Or,
228 here are a few examples that may give you what you need:
229
230 The simple elements nested within the <config> element:
231
232     my $pass = $koha->{'config'}->{'pass'};
233
234 The <listen> elements:
235
236     my $listen = $koha->{'listen'}->{'biblioserver'}->{'content'};
237
238 The elements nested within the <server> element:
239
240     my $ccl2rpn = $koha->{'server'}->{'biblioserver'}->{'cql2rpn'};
241
242 Returns undef in case of error.
243
244 =cut
245
246 sub read_config_file {          # Pass argument naming config file to read
247     my $koha = XMLin(shift, keyattr => ['id'], forcearray => ['listen', 'server', 'serverinfo'], suppressempty => '');
248
249     if ($ismemcached) {
250       $memcached->set('kohaconf',$koha);
251     }
252
253     return $koha;                       # Return value: ref-to-hash holding the configuration
254 }
255
256 # db_scheme2dbi
257 # Translates the full text name of a database into de appropiate dbi name
258
259 sub db_scheme2dbi {
260     my $name = shift;
261     # for instance, we support only mysql, so don't care checking
262     return "mysql";
263     for ($name) {
264 # FIXME - Should have other databases. 
265         if (/mysql/) { return("mysql"); }
266         if (/Postgres|Pg|PostgresSQL/) { return("Pg"); }
267         if (/oracle/) { return("Oracle"); }
268     }
269     return undef;         # Just in case
270 }
271
272 sub import {
273     # Create the default context ($C4::Context::Context)
274     # the first time the module is called
275     # (a config file can be optionaly passed)
276
277     # default context allready exists? 
278     return if $context;
279
280     # no ? so load it!
281     my ($pkg,$config_file) = @_ ;
282     my $new_ctx = __PACKAGE__->new($config_file);
283     return unless $new_ctx;
284
285     # if successfully loaded, use it by default
286     $new_ctx->set_context;
287     1;
288 }
289
290 =head2 new
291
292   $context = new C4::Context;
293   $context = new C4::Context("/path/to/koha-conf.xml");
294
295 Allocates a new context. Initializes the context from the specified
296 file, which defaults to either the file given by the C<$KOHA_CONF>
297 environment variable, or F</etc/koha/koha-conf.xml>.
298
299 It saves the koha-conf.xml values in the declared memcached server(s)
300 if currently available and uses those values until them expire and
301 re-reads them.
302
303 C<&new> does not set this context as the new default context; for
304 that, use C<&set_context>.
305
306 =cut
307
308 #'
309 # Revision History:
310 # 2004-08-10 A. Tarallo: Added check if the conf file is not empty
311 sub new {
312     my $class = shift;
313     my $conf_fname = shift;        # Config file to load
314     my $self = {};
315
316     # check that the specified config file exists and is not empty
317     undef $conf_fname unless 
318         (defined $conf_fname && -s $conf_fname);
319     # Figure out a good config file to load if none was specified.
320     if (!defined($conf_fname))
321     {
322         # If the $KOHA_CONF environment variable is set, use
323         # that. Otherwise, use the built-in default.
324         if (exists $ENV{"KOHA_CONF"} and $ENV{'KOHA_CONF'} and -s  $ENV{"KOHA_CONF"}) {
325             $conf_fname = $ENV{"KOHA_CONF"};
326         } elsif ($INSTALLED_CONFIG_FNAME !~ /__KOHA_CONF_DIR/ and -s $INSTALLED_CONFIG_FNAME) {
327             # NOTE: be careful -- don't change __KOHA_CONF_DIR in the above
328             # regex to anything else -- don't want installer to rewrite it
329             $conf_fname = $INSTALLED_CONFIG_FNAME;
330         } elsif (-s CONFIG_FNAME) {
331             $conf_fname = CONFIG_FNAME;
332         } else {
333             warn "unable to locate Koha configuration file koha-conf.xml";
334             return undef;
335         }
336     }
337     
338     if ($ismemcached) {
339       # retreive from memcached
340       $self = $memcached->get('kohaconf');
341       if (not defined $self) {
342         # not in memcached yet
343         $self = read_config_file($conf_fname);
344       }
345     } else {
346       # non-memcached env, read from file
347       $self = read_config_file($conf_fname);
348     }
349
350     $self->{"config_file"} = $conf_fname;
351     warn "read_config_file($conf_fname) returned undef" if !defined($self->{"config"});
352     return undef if !defined($self->{"config"});
353
354     $self->{"dbh"} = undef;        # Database handle
355     $self->{"Zconn"} = undef;    # Zebra Connections
356     $self->{"stopwords"} = undef; # stopwords list
357     $self->{"marcfromkohafield"} = undef; # the hash with relations between koha table fields and MARC field/subfield
358     $self->{"userenv"} = undef;        # User env
359     $self->{"activeuser"} = undef;        # current active user
360     $self->{"shelves"} = undef;
361
362     bless $self, $class;
363     return $self;
364 }
365
366 =head2 set_context
367
368   $context = new C4::Context;
369   $context->set_context();
370 or
371   set_context C4::Context $context;
372
373   ...
374   restore_context C4::Context;
375
376 In some cases, it might be necessary for a script to use multiple
377 contexts. C<&set_context> saves the current context on a stack, then
378 sets the context to C<$context>, which will be used in future
379 operations. To restore the previous context, use C<&restore_context>.
380
381 =cut
382
383 #'
384 sub set_context
385 {
386     my $self = shift;
387     my $new_context;    # The context to set
388
389     # Figure out whether this is a class or instance method call.
390     #
391     # We're going to make the assumption that control got here
392     # through valid means, i.e., that the caller used an instance
393     # or class method call, and that control got here through the
394     # usual inheritance mechanisms. The caller can, of course,
395     # break this assumption by playing silly buggers, but that's
396     # harder to do than doing it properly, and harder to check
397     # for.
398     if (ref($self) eq "")
399     {
400         # Class method. The new context is the next argument.
401         $new_context = shift;
402     } else {
403         # Instance method. The new context is $self.
404         $new_context = $self;
405     }
406
407     # Save the old context, if any, on the stack
408     push @context_stack, $context if defined($context);
409
410     # Set the new context
411     $context = $new_context;
412 }
413
414 =head2 restore_context
415
416   &restore_context;
417
418 Restores the context set by C<&set_context>.
419
420 =cut
421
422 #'
423 sub restore_context
424 {
425     my $self = shift;
426
427     if ($#context_stack < 0)
428     {
429         # Stack underflow.
430         die "Context stack underflow";
431     }
432
433     # Pop the old context and set it.
434     $context = pop @context_stack;
435
436     # FIXME - Should this return something, like maybe the context
437     # that was current when this was called?
438 }
439
440 =head2 config
441
442   $value = C4::Context->config("config_variable");
443
444   $value = C4::Context->config_variable;
445
446 Returns the value of a variable specified in the configuration file
447 from which the current context was created.
448
449 The second form is more compact, but of course may conflict with
450 method names. If there is a configuration variable called "new", then
451 C<C4::Config-E<gt>new> will not return it.
452
453 =cut
454
455 sub _common_config ($$) {
456         my $var = shift;
457         my $term = shift;
458     return undef if !defined($context->{$term});
459        # Presumably $self->{$term} might be
460        # undefined if the config file given to &new
461        # didn't exist, and the caller didn't bother
462        # to check the return value.
463
464     # Return the value of the requested config variable
465     return $context->{$term}->{$var};
466 }
467
468 sub config {
469         return _common_config($_[1],'config');
470 }
471 sub zebraconfig {
472         return _common_config($_[1],'server');
473 }
474 sub ModZebrations {
475         return _common_config($_[1],'serverinfo');
476 }
477
478 =head2 preference
479
480   $sys_preference = C4::Context->preference('some_variable');
481
482 Looks up the value of the given system preference in the
483 systempreferences table of the Koha database, and returns it. If the
484 variable is not set or does not exist, undef is returned.
485
486 In case of an error, this may return 0.
487
488 Note: It is impossible to tell the difference between system
489 preferences which do not exist, and those whose values are set to NULL
490 with this method.
491
492 =cut
493
494 # FIXME: running this under mod_perl will require a means of
495 # flushing the caching mechanism.
496
497 my %sysprefs;
498
499 sub preference {
500     my $self = shift;
501     my $var  = lc(shift);                          # The system preference to return
502
503     if (exists $sysprefs{$var}) {
504         return $sysprefs{$var};
505     }
506
507     my $dbh  = C4::Context->dbh or return 0;
508
509     # Look up systempreferences.variable==$var
510     my $sql = <<'END_SQL';
511         SELECT    value
512         FROM    systempreferences
513         WHERE    variable=?
514         LIMIT    1
515 END_SQL
516     $sysprefs{$var} = $dbh->selectrow_array( $sql, {}, $var );
517     return $sysprefs{$var};
518 }
519
520 sub boolean_preference ($) {
521     my $self = shift;
522     my $var = shift;        # The system preference to return
523     my $it = preference($self, $var);
524     return defined($it)? C4::Boolean::true_p($it): undef;
525 }
526
527 =head2 clear_syspref_cache
528
529   C4::Context->clear_syspref_cache();
530
531 cleans the internal cache of sysprefs. Please call this method if
532 you update the systempreferences table. Otherwise, your new changes
533 will not be seen by this process.
534
535 =cut
536
537 sub clear_syspref_cache {
538     %sysprefs = ();
539 }
540
541 =head2 set_preference
542
543   C4::Context->set_preference( $variable, $value );
544
545 This updates a preference's value both in the systempreferences table and in
546 the sysprefs cache.
547
548 =cut
549
550 sub set_preference {
551     my $self = shift;
552     my $var = shift;
553     my $value = shift;
554
555     my $dbh = C4::Context->dbh or return 0;
556
557     my $type = $dbh->selectrow_array( "SELECT type FROM systempreferences WHERE variable = ?", {}, $var );
558
559     $value = 0 if ( $type && $type eq 'YesNo' && $value eq '' );
560
561     my $sth = $dbh->prepare( "
562       INSERT INTO systempreferences
563         ( variable, value )
564         VALUES( ?, ? )
565         ON DUPLICATE KEY UPDATE value = VALUES(value)
566     " );
567
568     $sth->execute( $var, $value );
569     $sth->finish;
570 }
571
572 # AUTOLOAD
573 # This implements C4::Config->foo, and simply returns
574 # C4::Context->config("foo"), as described in the documentation for
575 # &config, above.
576
577 # FIXME - Perhaps this should be extended to check &config first, and
578 # then &preference if that fails. OTOH, AUTOLOAD could lead to crappy
579 # code, so it'd probably be best to delete it altogether so as not to
580 # encourage people to use it.
581 sub AUTOLOAD
582 {
583     my $self = shift;
584
585     $AUTOLOAD =~ s/.*:://;        # Chop off the package name,
586                     # leaving only the function name.
587     return $self->config($AUTOLOAD);
588 }
589
590 =head2 Zconn
591
592   $Zconn = C4::Context->Zconn
593
594 Returns a connection to the Zebra database for the current
595 context. If no connection has yet been made, this method 
596 creates one and connects.
597
598 C<$self> 
599
600 C<$server> one of the servers defined in the koha-conf.xml file
601
602 C<$async> whether this is a asynchronous connection
603
604 C<$auth> whether this connection has rw access (1) or just r access (0 or NULL)
605
606
607 =cut
608
609 sub Zconn {
610     my $self=shift;
611     my $server=shift;
612     my $async=shift;
613     my $auth=shift;
614     my $piggyback=shift;
615     my $syntax=shift;
616     if ( defined($context->{"Zconn"}->{$server}) && (0 == $context->{"Zconn"}->{$server}->errcode()) ) {
617         return $context->{"Zconn"}->{$server};
618     # No connection object or it died. Create one.
619     }else {
620         # release resources if we're closing a connection and making a new one
621         # FIXME: this needs to be smarter -- an error due to a malformed query or
622         # a missing index does not necessarily require us to close the connection
623         # and make a new one, particularly for a batch job.  However, at
624         # first glance it does not look like there's a way to easily check
625         # the basic health of a ZOOM::Connection
626         $context->{"Zconn"}->{$server}->destroy() if defined($context->{"Zconn"}->{$server});
627
628         $context->{"Zconn"}->{$server} = &_new_Zconn($server,$async,$auth,$piggyback,$syntax);
629         return $context->{"Zconn"}->{$server};
630     }
631 }
632
633 =head2 _new_Zconn
634
635 $context->{"Zconn"} = &_new_Zconn($server,$async);
636
637 Internal function. Creates a new database connection from the data given in the current context and returns it.
638
639 C<$server> one of the servers defined in the koha-conf.xml file
640
641 C<$async> whether this is a asynchronous connection
642
643 C<$auth> whether this connection has rw access (1) or just r access (0 or NULL)
644
645 =cut
646
647 sub _new_Zconn {
648     my ($server,$async,$auth,$piggyback,$syntax) = @_;
649
650     my $tried=0; # first attempt
651     my $Zconn; # connection object
652     $server = "biblioserver" unless $server;
653     $syntax = "usmarc" unless $syntax;
654
655     my $host = $context->{'listen'}->{$server}->{'content'};
656     my $servername = $context->{"config"}->{$server};
657     my $user = $context->{"serverinfo"}->{$server}->{"user"};
658     my $password = $context->{"serverinfo"}->{$server}->{"password"};
659  $auth = 1 if($user && $password);   
660     retry:
661     eval {
662         # set options
663         my $o = new ZOOM::Options();
664         $o->option(user=>$user) if $auth;
665         $o->option(password=>$password) if $auth;
666         $o->option(async => 1) if $async;
667         $o->option(count => $piggyback) if $piggyback;
668         $o->option(cqlfile=> $context->{"server"}->{$server}->{"cql2rpn"});
669         $o->option(cclfile=> $context->{"serverinfo"}->{$server}->{"ccl2rpn"});
670         $o->option(preferredRecordSyntax => $syntax);
671         $o->option(elementSetName => "F"); # F for 'full' as opposed to B for 'brief'
672         $o->option(databaseName => ($servername?$servername:"biblios"));
673
674         # create a new connection object
675         $Zconn= create ZOOM::Connection($o);
676
677         # forge to server
678         $Zconn->connect($host, 0);
679
680         # check for errors and warn
681         if ($Zconn->errcode() !=0) {
682             warn "something wrong with the connection: ". $Zconn->errmsg();
683         }
684
685     };
686 #     if ($@) {
687 #         # Koha manages the Zebra server -- this doesn't work currently for me because of permissions issues
688 #         # Also, I'm skeptical about whether it's the best approach
689 #         warn "problem with Zebra";
690 #         if ( C4::Context->preference("ManageZebra") ) {
691 #             if ($@->code==10000 && $tried==0) { ##No connection try restarting Zebra
692 #                 $tried=1;
693 #                 warn "trying to restart Zebra";
694 #                 my $res=system("zebrasrv -f $ENV{'KOHA_CONF'} >/koha/log/zebra-error.log");
695 #                 goto "retry";
696 #             } else {
697 #                 warn "Error ", $@->code(), ": ", $@->message(), "\n";
698 #                 $Zconn="error";
699 #                 return $Zconn;
700 #             }
701 #         }
702 #     }
703     return $Zconn;
704 }
705
706 # _new_dbh
707 # Internal helper function (not a method!). This creates a new
708 # database connection from the data given in the current context, and
709 # returns it.
710 sub _new_dbh
711 {
712
713     ## $context
714     ## correct name for db_schme        
715     my $db_driver;
716     if ($context->config("db_scheme")){
717         $db_driver=db_scheme2dbi($context->config("db_scheme"));
718     }else{
719         $db_driver="mysql";
720     }
721
722     my $db_name   = $context->config("database");
723     my $db_host   = $context->config("hostname");
724     my $db_port   = $context->config("port") || '';
725     my $db_user   = $context->config("user");
726     my $db_passwd = $context->config("pass");
727     # MJR added or die here, as we can't work without dbh
728     my $dbh= DBI->connect("DBI:$db_driver:dbname=$db_name;host=$db_host;port=$db_port",
729     $db_user, $db_passwd, {'RaiseError' => $ENV{DEBUG}?1:0 }) or die $DBI::errstr;
730         my $tz = $ENV{TZ};
731     if ( $db_driver eq 'mysql' ) { 
732         # Koha 3.0 is utf-8, so force utf8 communication between mySQL and koha, whatever the mysql default config.
733         # this is better than modifying my.cnf (and forcing all communications to be in utf8)
734         $dbh->{'mysql_enable_utf8'}=1; #enable
735         $dbh->do("set NAMES 'utf8'");
736         ($tz) and $dbh->do(qq(SET time_zone = "$tz"));
737     }
738     elsif ( $db_driver eq 'Pg' ) {
739             $dbh->do( "set client_encoding = 'UTF8';" );
740         ($tz) and $dbh->do(qq(SET TIME ZONE = "$tz"));
741     }
742     return $dbh;
743 }
744
745 =head2 dbh
746
747   $dbh = C4::Context->dbh;
748
749 Returns a database handle connected to the Koha database for the
750 current context. If no connection has yet been made, this method
751 creates one, and connects to the database.
752
753 This database handle is cached for future use: if you call
754 C<C4::Context-E<gt>dbh> twice, you will get the same handle both
755 times. If you need a second database handle, use C<&new_dbh> and
756 possibly C<&set_dbh>.
757
758 =cut
759
760 #'
761 sub dbh
762 {
763     my $self = shift;
764     my $sth;
765
766     if (defined($context->{"dbh"}) && $context->{"dbh"}->ping()) {
767         return $context->{"dbh"};
768     }
769
770     # No database handle or it died . Create one.
771     $context->{"dbh"} = &_new_dbh();
772
773     return $context->{"dbh"};
774 }
775
776 =head2 new_dbh
777
778   $dbh = C4::Context->new_dbh;
779
780 Creates a new connection to the Koha database for the current context,
781 and returns the database handle (a C<DBI::db> object).
782
783 The handle is not saved anywhere: this method is strictly a
784 convenience function; the point is that it knows which database to
785 connect to so that the caller doesn't have to know.
786
787 =cut
788
789 #'
790 sub new_dbh
791 {
792     my $self = shift;
793
794     return &_new_dbh();
795 }
796
797 =head2 set_dbh
798
799   $my_dbh = C4::Connect->new_dbh;
800   C4::Connect->set_dbh($my_dbh);
801   ...
802   C4::Connect->restore_dbh;
803
804 C<&set_dbh> and C<&restore_dbh> work in a manner analogous to
805 C<&set_context> and C<&restore_context>.
806
807 C<&set_dbh> saves the current database handle on a stack, then sets
808 the current database handle to C<$my_dbh>.
809
810 C<$my_dbh> is assumed to be a good database handle.
811
812 =cut
813
814 #'
815 sub set_dbh
816 {
817     my $self = shift;
818     my $new_dbh = shift;
819
820     # Save the current database handle on the handle stack.
821     # We assume that $new_dbh is all good: if the caller wants to
822     # screw himself by passing an invalid handle, that's fine by
823     # us.
824     push @{$context->{"dbh_stack"}}, $context->{"dbh"};
825     $context->{"dbh"} = $new_dbh;
826 }
827
828 =head2 restore_dbh
829
830   C4::Context->restore_dbh;
831
832 Restores the database handle saved by an earlier call to
833 C<C4::Context-E<gt>set_dbh>.
834
835 =cut
836
837 #'
838 sub restore_dbh
839 {
840     my $self = shift;
841
842     if ($#{$context->{"dbh_stack"}} < 0)
843     {
844         # Stack underflow
845         die "DBH stack underflow";
846     }
847
848     # Pop the old database handle and set it.
849     $context->{"dbh"} = pop @{$context->{"dbh_stack"}};
850
851     # FIXME - If it is determined that restore_context should
852     # return something, then this function should, too.
853 }
854
855 =head2 marcfromkohafield
856
857   $dbh = C4::Context->marcfromkohafield;
858
859 Returns a hash with marcfromkohafield.
860
861 This hash is cached for future use: if you call
862 C<C4::Context-E<gt>marcfromkohafield> twice, you will get the same hash without real DB access
863
864 =cut
865
866 #'
867 sub marcfromkohafield
868 {
869     my $retval = {};
870
871     # If the hash already exists, return it.
872     return $context->{"marcfromkohafield"} if defined($context->{"marcfromkohafield"});
873
874     # No hash. Create one.
875     $context->{"marcfromkohafield"} = &_new_marcfromkohafield();
876
877     return $context->{"marcfromkohafield"};
878 }
879
880 # _new_marcfromkohafield
881 # Internal helper function (not a method!). This creates a new
882 # hash with stopwords
883 sub _new_marcfromkohafield
884 {
885     my $dbh = C4::Context->dbh;
886     my $marcfromkohafield;
887     my $sth = $dbh->prepare("select frameworkcode,kohafield,tagfield,tagsubfield from marc_subfield_structure where kohafield > ''");
888     $sth->execute;
889     while (my ($frameworkcode,$kohafield,$tagfield,$tagsubfield) = $sth->fetchrow) {
890         my $retval = {};
891         $marcfromkohafield->{$frameworkcode}->{$kohafield} = [$tagfield,$tagsubfield];
892     }
893     return $marcfromkohafield;
894 }
895
896 =head2 stopwords
897
898   $dbh = C4::Context->stopwords;
899
900 Returns a hash with stopwords.
901
902 This hash is cached for future use: if you call
903 C<C4::Context-E<gt>stopwords> twice, you will get the same hash without real DB access
904
905 =cut
906
907 #'
908 sub stopwords
909 {
910     my $retval = {};
911
912     # If the hash already exists, return it.
913     return $context->{"stopwords"} if defined($context->{"stopwords"});
914
915     # No hash. Create one.
916     $context->{"stopwords"} = &_new_stopwords();
917
918     return $context->{"stopwords"};
919 }
920
921 # _new_stopwords
922 # Internal helper function (not a method!). This creates a new
923 # hash with stopwords
924 sub _new_stopwords
925 {
926     my $dbh = C4::Context->dbh;
927     my $stopwordlist;
928     my $sth = $dbh->prepare("select word from stopwords");
929     $sth->execute;
930     while (my $stopword = $sth->fetchrow_array) {
931         $stopwordlist->{$stopword} = uc($stopword);
932     }
933     $stopwordlist->{A} = "A" unless $stopwordlist;
934     return $stopwordlist;
935 }
936
937 =head2 userenv
938
939   C4::Context->userenv;
940
941 Retrieves a hash for user environment variables.
942
943 This hash shall be cached for future use: if you call
944 C<C4::Context-E<gt>userenv> twice, you will get the same hash without real DB access
945
946 =cut
947
948 #'
949 sub userenv {
950     my $var = $context->{"activeuser"};
951     return $context->{"userenv"}->{$var} if (defined $var and defined $context->{"userenv"}->{$var});
952     # insecure=1 management
953     if ($context->{"dbh"} && $context->preference('insecure') eq 'yes') {
954         my %insecure;
955         $insecure{flags} = '16382';
956         $insecure{branchname} ='Insecure';
957         $insecure{number} ='0';
958         $insecure{cardnumber} ='0';
959         $insecure{id} = 'insecure';
960         $insecure{branch} = 'INS';
961         $insecure{emailaddress} = 'test@mode.insecure.com';
962         return \%insecure;
963     } else {
964         return;
965     }
966 }
967
968 =head2 set_userenv
969
970   C4::Context->set_userenv($usernum, $userid, $usercnum, $userfirstname, 
971                   $usersurname, $userbranch, $userflags, $emailaddress);
972
973 Establish a hash of user environment variables.
974
975 set_userenv is called in Auth.pm
976
977 =cut
978
979 #'
980 sub set_userenv {
981     my ($usernum, $userid, $usercnum, $userfirstname, $usersurname, $userbranch, $branchname, $userflags, $emailaddress, $branchprinter)= @_;
982     my $var=$context->{"activeuser"};
983     my $cell = {
984         "number"     => $usernum,
985         "id"         => $userid,
986         "cardnumber" => $usercnum,
987         "firstname"  => $userfirstname,
988         "surname"    => $usersurname,
989         #possibly a law problem
990         "branch"     => $userbranch,
991         "branchname" => $branchname,
992         "flags"      => $userflags,
993         "emailaddress"     => $emailaddress,
994         "branchprinter"    => $branchprinter
995     };
996     $context->{userenv}->{$var} = $cell;
997     return $cell;
998 }
999
1000 sub set_shelves_userenv ($$) {
1001         my ($type, $shelves) = @_ or return undef;
1002         my $activeuser = $context->{activeuser} or return undef;
1003         $context->{userenv}->{$activeuser}->{barshelves} = $shelves if $type eq 'bar';
1004         $context->{userenv}->{$activeuser}->{pubshelves} = $shelves if $type eq 'pub';
1005         $context->{userenv}->{$activeuser}->{totshelves} = $shelves if $type eq 'tot';
1006 }
1007
1008 sub get_shelves_userenv () {
1009         my $active;
1010         unless ($active = $context->{userenv}->{$context->{activeuser}}) {
1011                 $debug and warn "get_shelves_userenv cannot retrieve context->{userenv}->{context->{activeuser}}";
1012                 return undef;
1013         }
1014         my $totshelves = $active->{totshelves} or undef;
1015         my $pubshelves = $active->{pubshelves} or undef;
1016         my $barshelves = $active->{barshelves} or undef;
1017         return ($totshelves, $pubshelves, $barshelves);
1018 }
1019
1020 =head2 _new_userenv
1021
1022   C4::Context->_new_userenv($session);  # FIXME: This calling style is wrong for what looks like an _internal function
1023
1024 Builds a hash for user environment variables.
1025
1026 This hash shall be cached for future use: if you call
1027 C<C4::Context-E<gt>userenv> twice, you will get the same hash without real DB access
1028
1029 _new_userenv is called in Auth.pm
1030
1031 =cut
1032
1033 #'
1034 sub _new_userenv
1035 {
1036     shift;  # Useless except it compensates for bad calling style
1037     my ($sessionID)= @_;
1038      $context->{"activeuser"}=$sessionID;
1039 }
1040
1041 =head2 _unset_userenv
1042
1043   C4::Context->_unset_userenv;
1044
1045 Destroys the hash for activeuser user environment variables.
1046
1047 =cut
1048
1049 #'
1050
1051 sub _unset_userenv
1052 {
1053     my ($sessionID)= @_;
1054     undef $context->{"activeuser"} if ($context->{"activeuser"} eq $sessionID);
1055 }
1056
1057
1058 =head2 get_versions
1059
1060   C4::Context->get_versions
1061
1062 Gets various version info, for core Koha packages, Currently called from carp handle_errors() sub, to send to browser if 'DebugLevel' syspref is set to '2'.
1063
1064 =cut
1065
1066 #'
1067
1068 # A little example sub to show more debugging info for CGI::Carp
1069 sub get_versions {
1070     my %versions;
1071     $versions{kohaVersion}  = KOHAVERSION();
1072     $versions{kohaDbVersion} = C4::Context->preference('version');
1073     $versions{osVersion} = join(" ", POSIX::uname());
1074     $versions{perlVersion} = $];
1075     {
1076         no warnings qw(exec); # suppress warnings if unable to find a program in $PATH
1077         $versions{mysqlVersion}  = `mysql -V`;
1078         $versions{apacheVersion} = `httpd -v`;
1079         $versions{apacheVersion} = `httpd2 -v`            unless  $versions{apacheVersion} ;
1080         $versions{apacheVersion} = `apache2 -v`           unless  $versions{apacheVersion} ;
1081         $versions{apacheVersion} = `/usr/sbin/apache2 -v` unless  $versions{apacheVersion} ;
1082     }
1083     return %versions;
1084 }
1085
1086
1087 1;
1088 __END__
1089
1090 =head1 ENVIRONMENT
1091
1092 =head2 C<KOHA_CONF>
1093
1094 Specifies the configuration file to read.
1095
1096 =head1 SEE ALSO
1097
1098 XML::Simple
1099
1100 =head1 AUTHORS
1101
1102 Andrew Arensburger <arensb at ooblick dot com>
1103
1104 Joshua Ferraro <jmf at liblime dot com>
1105
1106 =cut