File Coverage

blib/lib/CMS/Joomla.pm
Criterion Covered Total %
statement 45 82 54.8
branch 8 28 28.5
condition 1 6 16.6
subroutine 10 13 76.9
pod 4 4 100.0
total 68 133 51.1


line stmt bran cond sub pod time code
1             #
2             # CMS::Joomla - Joomla! CMS configuration and database access Perl module
3             #
4             # Copyright (c) 2008, 2011 EPIPE Communications
5             #
6             # This program is free software; you can redistribute it and/or modify it
7             # under the same terms as Perl itself.
8             #
9              
10             package CMS::Joomla;
11              
12 4     4   138947 use warnings;
  4         13  
  4         170  
13 4     4   21 use strict;
  4         9  
  4         146  
14              
15 4     4   22 use Carp;
  4         11  
  4         403  
16 4     4   12361 use DBI;
  4         136821  
  4         373  
17 4     4   5643 use IO::File;
  4         82675  
  4         6958  
18              
19             our $VERSION = '0.04';
20              
21             =head1 NAME
22              
23             CMS::Joomla - Joomla! CMS configuration and database access Perl module
24              
25              
26             =head1 SYNOPSIS
27              
28             Read Joomla! configuration variables:
29              
30             use CMS::Joomla;
31              
32             my ($joomla) = CMS::Joomla->new("/path/to/joomla/configuration.php");
33              
34             print "Site name: " . $joomla->cfg->{'sitename'} . "\n";
35              
36              
37             Access Joomla! database:
38              
39             my ($jdb) = $joomla->dbhandle( { AutoCommit => 1 } );
40             my ($sth) = $jdb->prepare("SELECT introtext "
41             . "FROM " . $joomla->dbprefix . "content "
42             . "WHERE title=?");
43              
44             $sth->execute("about");
45              
46             while (my ($introtext) = $sth->fetchrow_array) {
47             print "$introtext\n";
48             }
49              
50             ...
51              
52             =head1 DESCRIPTION
53              
54             This module provides an interface for reading Joomla! CMS configuration
55             variables and connecting to the Joomla! database from Perl script.
56              
57             =head1 CONSTRUCTOR
58              
59             =head2 new(I)
60              
61             Creates C object. The I parameter should be a
62             file name of a valid readable Joomla! F file.
63             Returns undef in case of error.
64              
65             =cut
66              
67             sub new ($$) {
68 3     3 1 42 my $type = shift;
69 3         8 my $cfgname = shift;
70 3         9 my $self = {};
71 3         9 bless $self, $type;
72 3         24 $self->{'_cfgname'} = $cfgname;
73 3         12 $self->{'_phptype'} = undef;
74 3         17 $self->{'cfg'} = $self->_jcfgread($cfgname);
75 3 100       88 return defined($self->{'cfg'}) ? $self : undef;
76             }
77              
78             =head1 METHODS
79              
80             =head2 cfg()
81              
82             Return a reference to a hash containing all Joomla! configuration
83             variables in this C object.
84              
85             =cut
86              
87             sub cfg ($) {
88 0     0 1 0 my $self = shift;
89              
90 0         0 return $self->{'cfg'};
91             }
92              
93             =head2 dbhandle(I)
94              
95             Returns a C database handle object which is connected to the
96             corresponding Joomla! database. See L for more information
97             on how to use the returned database handle. Consecutive calls to
98             this function will return the same C handle instead of opening
99             a new connection each time.
100              
101             I is passed directly to the C handle constructor.
102              
103             Returns undef in case of error.
104              
105             =cut
106              
107             sub dbhandle ($$) {
108 0     0 1 0 my $self = shift;
109 0         0 my $opt = shift;
110              
111 0 0       0 if (!defined($self->{'cfg'}->{'dbtype'})) {
112 0         0 carp "Joomla! database type is not defined";
113 0         0 return undef;
114             }
115 0 0       0 if (!defined($self->{'cfg'}->{'db'})) {
116 0         0 carp "Joomla! database name is not defined";
117 0         0 return undef;
118             }
119 0 0       0 if (!defined($self->{'cfg'}->{'host'})) {
120 0         0 carp "Joomla! database host is not defined";
121 0         0 return undef;
122             }
123 0 0       0 if (!defined($self->{'cfg'}->{'user'})) {
124 0         0 carp "Joomla! database user is not defined";
125 0         0 return undef;
126             }
127 0 0       0 if (!defined($self->{'cfg'}->{'password'})) {
128 0         0 carp "Joomla! database password is not defined";
129 0         0 return undef;
130             }
131              
132 0         0 my $dbtype = $self->{'cfg'}->{'dbtype'};
133              
134 0         0 $dbtype =~ s/mysqli/mysql/;
135              
136 0 0       0 return $self->{'_dbhandle'} if defined($self->{'_dbhandle'});
137              
138 0         0 $self->{'_dbhandle'} = DBI->connect("dbi:$dbtype:"
139             . 'database=' . $self->{'cfg'}->{'db'}
140             . ';host=' . $self->{'cfg'}->{'host'},
141             $self->{'cfg'}->{'user'}, $self->{'cfg'}->{'password'}, $opt);
142              
143 0         0 return $self->{'_dbhandle'};
144             }
145              
146             =head2 dbprefix()
147              
148             Return a reference to the Joomla! database prefix. This is effectively
149             a shortcut for C<$joomla-Ecfg-E{'dbprefix'}>.
150              
151             =cut
152              
153             sub dbprefix ($) {
154 2     2 1 4352 my $self = shift;
155              
156 2         13 return $self->{'cfg'}->{'dbprefix'};
157             }
158              
159              
160             =head1 EXAMPLES
161              
162             Some functional example scripts are available at:
163              
164             L
165              
166              
167             =head1 SEE ALSO
168              
169             L, L, L
170              
171              
172             =head1 COPYRIGHT & LICENSE
173              
174             Copyright (c) 2008, 2011 EPIPE Communications Eepipe at cpan.orgE
175             L
176              
177             This program is free software; you can redistribute it and/or modify it
178             under the same terms as Perl itself.
179              
180              
181             =cut
182              
183             # internal methods follow
184              
185             sub _probephp ($) {
186              
187             # Simple test to see if we have a working PHP command line program.
188             # The sub-shell re-direction is there to avoid "php: not found"
189             # error messages (which are not relevant as we resort to internal
190             # parser in case the PHP command line binary does not exist).
191              
192 3     3   29588 my ($r) = `(php -r 'echo strrev("raboof") . "\n";') 2> /dev/null`;
193              
194 3 50 33     357 if (defined($r) && $r =~ /foobar/) {
195             # have PHP command-line binary
196 0         0 return 1;
197             }
198             # no have
199 3         79 return 0;
200             }
201              
202             sub _jcfgread_cmdline ($$) {
203 0     0   0 my $self = shift;
204 0         0 my $cfgname = shift;
205 0         0 my %cfg;
206              
207 0 0       0 return undef unless defined($cfgname);
208              
209 0         0 my ($php) = '
210             require_once("' . $cfgname . '");
211             $c = new JConfig();
212             foreach ($c as $key => $value) {
213             echo "$key: \"$value\"\n";
214             }';
215              
216            
217 0         0 my $r = `php -r '$php'`;
218              
219 0 0 0     0 return undef unless defined($r) && $? == 0;
220              
221 0         0 while ($r =~ /^(\w+): \"([^\"]*?)\"$/m) {
222 0         0 $cfg{$1} = $2;
223 0         0 $r = $';
224             }
225 0         0 return \%cfg;
226             }
227              
228             sub _jcfgread_kludge ($$) {
229 3     3   16 my $self = shift;
230 3         38 my $cfgname = shift;
231 3         9 my %cfg;
232             my $str;
233              
234 3 50       23 return undef unless defined($cfgname);
235              
236 3         126 my $fh = IO::File->new($cfgname, '<');
237              
238 3 100       950 return undef unless defined($fh);
239              
240 2         216 $str = join('', $fh->getlines());
241              
242 2         735 while ($str =~ /^\s*(var|public)\s+\$(\w+)\s+=\s+\'([^\']*?)\'\;/m) {
243 101         397 $cfg{$2} = $3;
244 101         637 $str = $';
245             }
246 2         56 return \%cfg;
247             }
248              
249             sub _jcfgread ($$) {
250 3     3   8 my $self = shift;
251 3         9 my $cfgname = shift;
252              
253 3 50       15 if (!defined($self->{'_phptype'})) {
254 3         15 $self->{'_phptype'} = $self->_probephp();
255             }
256              
257 3 50       54 if ($self->{'_phptype'} == 1) {
258             # use command-line php binary
259 0         0 return $self->_jcfgread_cmdline($cfgname);
260             } else {
261             # phptype is 0 or unknown, use internal parser kludge
262 3         58 return $self->_jcfgread_kludge($cfgname);
263             }
264             }
265              
266             1; # End of CMS::Joomla