line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package WWW::phpBB::Mod::Installer;
|
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
65627
|
use 5.008008;
|
|
2
|
|
|
|
|
14
|
|
|
2
|
|
|
|
|
86
|
|
4
|
2
|
|
|
2
|
|
12
|
use strict;
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
204
|
|
5
|
2
|
|
|
2
|
|
11
|
use warnings;
|
|
2
|
|
|
|
|
23
|
|
|
2
|
|
|
|
|
63
|
|
6
|
|
|
|
|
|
|
|
7
|
2
|
|
|
2
|
|
12
|
use Carp;
|
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
211
|
|
8
|
2
|
|
|
2
|
|
17
|
use File::Basename;
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
218
|
|
9
|
2
|
|
|
2
|
|
3997
|
use Data::Dumper;
|
|
2
|
|
|
|
|
25573
|
|
|
2
|
|
|
|
|
158
|
|
10
|
2
|
|
|
2
|
|
18
|
use Cwd 'abs_path';
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
98
|
|
11
|
2
|
|
|
2
|
|
2010
|
use File::Copy;
|
|
2
|
|
|
|
|
5549
|
|
|
2
|
|
|
|
|
125
|
|
12
|
2
|
|
|
2
|
|
2242
|
use XML::Xerces;
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
use DBI;
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
our $VERSION = '0.03';
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
require Exporter;
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
our @ISA = qw(Exporter);
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( 'all' => [ qw() ] );
|
24
|
|
|
|
|
|
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
|
25
|
|
|
|
|
|
|
our @EXPORT = qw(uninstall_phpbb_mod
|
26
|
|
|
|
|
|
|
install_phpbb_mod
|
27
|
|
|
|
|
|
|
);
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
use constant ERROR => 'ERROR';
|
31
|
|
|
|
|
|
|
use constant DEBUG => 'DEBUG';
|
32
|
|
|
|
|
|
|
use constant AUDIT => 'AUDIT';
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
use constant INSTALL => 'INSTALL';
|
35
|
|
|
|
|
|
|
use constant UNINSTALL => 'UNINSTALL';
|
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
use constant DEFAULT_LANG => 'en';
|
38
|
|
|
|
|
|
|
use constant DEFAULT_STYLE => 'prosilver';
|
39
|
|
|
|
|
|
|
use constant DEFAULT_VERSION => 0;
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
my $script_absolute_path;
|
43
|
|
|
|
|
|
|
my $install_absolute_path;
|
44
|
|
|
|
|
|
|
my $install_absolute_file;
|
45
|
|
|
|
|
|
|
my $web_root_absolute_path;
|
46
|
|
|
|
|
|
|
my $backup_dir;
|
47
|
|
|
|
|
|
|
my $config_file;
|
48
|
|
|
|
|
|
|
my %log_handles;
|
49
|
|
|
|
|
|
|
my %headers;
|
50
|
|
|
|
|
|
|
my $phpbb_config_ref;
|
51
|
|
|
|
|
|
|
my $dbh;
|
52
|
|
|
|
|
|
|
my $phpbb_version;
|
53
|
|
|
|
|
|
|
my $style;
|
54
|
|
|
|
|
|
|
my $lang;
|
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
###############################
|
58
|
|
|
|
|
|
|
# TODO
|
59
|
|
|
|
|
|
|
# 1. Support the uninstall command
|
60
|
|
|
|
|
|
|
# which will remove any edits made
|
61
|
|
|
|
|
|
|
# and also delete files copied as part of the install
|
62
|
|
|
|
|
|
|
# It will not modify the database.
|
63
|
|
|
|
|
|
|
#
|
64
|
|
|
|
|
|
|
##############################
|
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub uninstall_phpbb_mod{
|
67
|
|
|
|
|
|
|
my %args = shift;
|
68
|
|
|
|
|
|
|
$args{OPERATION} = UNINSTALL;
|
69
|
|
|
|
|
|
|
install_mod(%args);
|
70
|
|
|
|
|
|
|
}
|
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub install_phpbb_mod{
|
73
|
|
|
|
|
|
|
my %args = (@_);
|
74
|
|
|
|
|
|
|
my $install_file = $args{INSTALL_FILE};
|
75
|
|
|
|
|
|
|
my $web_root = $args{WEB_ROOT};
|
76
|
|
|
|
|
|
|
my $tmp_style = $args{STYLE};
|
77
|
|
|
|
|
|
|
my $tmp_lang = $args{LANG};
|
78
|
|
|
|
|
|
|
my $operation = $args{OPERATION} || INSTALL;
|
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
_setup();
|
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
unless (-f $install_file) {
|
83
|
|
|
|
|
|
|
_write_log_entry(ERROR, "The install file '$install_file' does not exist.");
|
84
|
|
|
|
|
|
|
croak "\n\nThe install file '$install_file' does not exist.\n\n";
|
85
|
|
|
|
|
|
|
}
|
86
|
|
|
|
|
|
|
unless (-d $web_root) {
|
87
|
|
|
|
|
|
|
_write_log_entry(ERROR, "The phpbb web root directory '$web_root' does not exist.");
|
88
|
|
|
|
|
|
|
croak "\n\nThe phpbb web root directory '$web_root' does not exist.\n\n";
|
89
|
|
|
|
|
|
|
}
|
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
$install_absolute_path = abs_path( dirname($install_file) );
|
92
|
|
|
|
|
|
|
if ($install_absolute_path =~ /^(.*)\/templates$/){
|
93
|
|
|
|
|
|
|
$install_absolute_path = $1;
|
94
|
|
|
|
|
|
|
}
|
95
|
|
|
|
|
|
|
_write_log_entry(DEBUG, "Install root path: $install_absolute_path");
|
96
|
|
|
|
|
|
|
$install_absolute_file = abs_path($install_file);
|
97
|
|
|
|
|
|
|
_write_log_entry(DEBUG, "Install file: $install_absolute_file");
|
98
|
|
|
|
|
|
|
$web_root_absolute_path = abs_path( $web_root);
|
99
|
|
|
|
|
|
|
_write_log_entry(DEBUG, "phpBB web root: $web_root_absolute_path");
|
100
|
|
|
|
|
|
|
$config_file = "$web_root_absolute_path/config.php";
|
101
|
|
|
|
|
|
|
_write_log_entry(DEBUG, "phpBB config file: $config_file");
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
unless (-f $config_file) {
|
104
|
|
|
|
|
|
|
_write_log_entry(ERROR, "The phpbb web root directory '$web_root_absolute_path' does not contain a config.php");
|
105
|
|
|
|
|
|
|
croak "\n\nThe phpbb web root directory '$web_root_absolute_path' does not contain a config.php\n\n";
|
106
|
|
|
|
|
|
|
}
|
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
$phpbb_config_ref = _read_phpbb_config();
|
109
|
|
|
|
|
|
|
eval {my $dbh = _mysql_connect();};
|
110
|
|
|
|
|
|
|
$phpbb_version = _get_phpbb_version();
|
111
|
|
|
|
|
|
|
$lang = $tmp_lang || _get_phpbb_lang();
|
112
|
|
|
|
|
|
|
_write_log_entry(AUDIT, "Language: '$lang'");
|
113
|
|
|
|
|
|
|
$style = $tmp_style || _get_phpbb_style();
|
114
|
|
|
|
|
|
|
_write_log_entry(AUDIT, "Style: '$style'");
|
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
_write_log_entry(AUDIT, "Initialisation complete, processing installation file '$install_absolute_file'");
|
117
|
|
|
|
|
|
|
my $doc = _load_install_file($install_absolute_file);
|
118
|
|
|
|
|
|
|
my $instruction_ref = _process_document($doc);
|
119
|
|
|
|
|
|
|
_write_log_entry(DEBUG, 'Instruction list: ' . Data::Dumper->Dump([$instruction_ref]));
|
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
if ($headers{target_version} ne $phpbb_version){
|
122
|
|
|
|
|
|
|
warn "\nWARNING: This mod is intended for a different version of phpbb\n" .
|
123
|
|
|
|
|
|
|
"\tBoard Version $phpbb_version\n" .
|
124
|
|
|
|
|
|
|
"\tMod written for version $headers{target_version}\n\n";
|
125
|
|
|
|
|
|
|
}
|
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
if ($operation eq INSTALL){
|
128
|
|
|
|
|
|
|
_write_log_entry(AUDIT, "Beginning installation for mod $headers{title} " .
|
129
|
|
|
|
|
|
|
"version $headers{version_major}.$headers{version_minor}".
|
130
|
|
|
|
|
|
|
".$headers{version_revision}$headers{version_release} " .
|
131
|
|
|
|
|
|
|
"by $headers{author}");
|
132
|
|
|
|
|
|
|
_process_instructions($instruction_ref, $backup_dir);
|
133
|
|
|
|
|
|
|
}
|
134
|
|
|
|
|
|
|
elsif($operation eq UNINSTALL){
|
135
|
|
|
|
|
|
|
_write_log_entry(AUDIT, "Beginning uninstall for mod $headers{title} " .
|
136
|
|
|
|
|
|
|
"version $headers{version_major}.$headers{version_minor}".
|
137
|
|
|
|
|
|
|
".$headers{version_revision}$headers{version_release} " .
|
138
|
|
|
|
|
|
|
"by $headers{author}");
|
139
|
|
|
|
|
|
|
_process_uninstall($instruction_ref, $backup_dir);
|
140
|
|
|
|
|
|
|
}
|
141
|
|
|
|
|
|
|
else{
|
142
|
|
|
|
|
|
|
_write_log_entry(ERROR, "Unsupported operation '$operation'.\n");
|
143
|
|
|
|
|
|
|
croak "Unsupported operation '$operation'.\n" .
|
144
|
|
|
|
|
|
|
"Only\n\tOPERATION => 'INSTALL'\n\tOPERATION => 'UNINSTALL'\n" .
|
145
|
|
|
|
|
|
|
"are supported.\n";
|
146
|
|
|
|
|
|
|
}
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
_write_log_entry(AUDIT, 'Complete');
|
149
|
|
|
|
|
|
|
_tear_down();
|
150
|
|
|
|
|
|
|
}
|
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub _setup{
|
154
|
|
|
|
|
|
|
$script_absolute_path = abs_path( dirname($0) );
|
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
$backup_dir = _create_backup_dirs($script_absolute_path);
|
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
my $log_dir = "$script_absolute_path/logs";
|
159
|
|
|
|
|
|
|
if (!-d $log_dir){
|
160
|
|
|
|
|
|
|
_create_dir_recursive($log_dir);
|
161
|
|
|
|
|
|
|
}
|
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
open(my $error_handle, '>>', "$log_dir/error.log")
|
164
|
|
|
|
|
|
|
or croak "Can't open error log file $log_dir/error.log: $!\n";
|
165
|
|
|
|
|
|
|
open(my $debug_handle, '>>', "$log_dir/debug.log")
|
166
|
|
|
|
|
|
|
or croak "Can't open debug log file $log_dir/debug.log: $!\n";
|
167
|
|
|
|
|
|
|
open(my $audit_handle, '>>', "$log_dir/audit.log")
|
168
|
|
|
|
|
|
|
or croak "Can't open audit log file $log_dir/audit.log: $!\n";
|
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
$log_handles{ERROR} = $error_handle;
|
171
|
|
|
|
|
|
|
$log_handles{DEBUG} = $debug_handle;
|
172
|
|
|
|
|
|
|
$log_handles{AUDIT} = $audit_handle;
|
173
|
|
|
|
|
|
|
}
|
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub _tear_down{
|
176
|
|
|
|
|
|
|
$dbh->disconnect() if $dbh;
|
177
|
|
|
|
|
|
|
foreach my $handle (keys %log_handles){
|
178
|
|
|
|
|
|
|
close $log_handles{$handle};
|
179
|
|
|
|
|
|
|
}
|
180
|
|
|
|
|
|
|
}
|
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub _get_phpbb_version{
|
183
|
|
|
|
|
|
|
my $version;
|
184
|
|
|
|
|
|
|
if ($dbh){
|
185
|
|
|
|
|
|
|
my $sql = "select * from " . $phpbb_config_ref->{table_prefix} .
|
186
|
|
|
|
|
|
|
"config where config_name = 'version'" ;
|
187
|
|
|
|
|
|
|
my $res ;
|
188
|
|
|
|
|
|
|
#selectall_hashref causes warnings from File::Copy under windows
|
189
|
|
|
|
|
|
|
#eval{$res = $dbh->selectall_hashref($sql, 'config_name') } ;
|
190
|
|
|
|
|
|
|
eval{$res = $dbh->selectall_arrayref($sql) } ;
|
191
|
|
|
|
|
|
|
$version = $res->[0]->[1];
|
192
|
|
|
|
|
|
|
_write_log_entry(AUDIT, "phpBB version: $version");
|
193
|
|
|
|
|
|
|
}
|
194
|
|
|
|
|
|
|
else{
|
195
|
|
|
|
|
|
|
_write_log_entry(AUDIT, 'No database connection, cannot get phpBB version');
|
196
|
|
|
|
|
|
|
}
|
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
if (!$version){
|
199
|
|
|
|
|
|
|
$version = DEFAULT_VERSION;
|
200
|
|
|
|
|
|
|
}
|
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
return $version;
|
203
|
|
|
|
|
|
|
}
|
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
sub _get_phpbb_lang{
|
206
|
|
|
|
|
|
|
my $lang;
|
207
|
|
|
|
|
|
|
if ($dbh){
|
208
|
|
|
|
|
|
|
my $sql = "select config_value from " . $phpbb_config_ref->{table_prefix} .
|
209
|
|
|
|
|
|
|
"config where config_name = 'default_lang'" ;
|
210
|
|
|
|
|
|
|
my $res ;
|
211
|
|
|
|
|
|
|
#selectall_hashref causes warnings from File::Copy under windows
|
212
|
|
|
|
|
|
|
#eval{$res = $dbh->selectall_hashref($sql, 'config_name') } ;
|
213
|
|
|
|
|
|
|
eval{$res = $dbh->selectall_arrayref($sql) } ;
|
214
|
|
|
|
|
|
|
$lang = $res->[0]->[0];
|
215
|
|
|
|
|
|
|
_write_log_entry(DEBUG, "phpBB default lang: $lang");
|
216
|
|
|
|
|
|
|
}
|
217
|
|
|
|
|
|
|
else{
|
218
|
|
|
|
|
|
|
_write_log_entry(AUDIT, 'No database connection, cannot get phpBB language');
|
219
|
|
|
|
|
|
|
}
|
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
if (!$lang){
|
222
|
|
|
|
|
|
|
$lang = DEFAULT_LANG;
|
223
|
|
|
|
|
|
|
}
|
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
return $lang;
|
226
|
|
|
|
|
|
|
}
|
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub _get_phpbb_style{
|
229
|
|
|
|
|
|
|
my $style;
|
230
|
|
|
|
|
|
|
if ($dbh){
|
231
|
|
|
|
|
|
|
my $sql = "select template_path from " . $phpbb_config_ref->{table_prefix} .
|
232
|
|
|
|
|
|
|
"styles_template where template_id = " .
|
233
|
|
|
|
|
|
|
"(select template_id from " . $phpbb_config_ref->{table_prefix} .
|
234
|
|
|
|
|
|
|
"styles where style_id = " .
|
235
|
|
|
|
|
|
|
"(select config_value from " . $phpbb_config_ref->{table_prefix} .
|
236
|
|
|
|
|
|
|
"config where config_name = 'default_style'))" ;
|
237
|
|
|
|
|
|
|
my $res ;
|
238
|
|
|
|
|
|
|
#selectall_hashref causes warnings from File::Copy under windows
|
239
|
|
|
|
|
|
|
#eval{$res = $dbh->selectall_hashref($sql, 'config_name') } ;
|
240
|
|
|
|
|
|
|
eval{$res = $dbh->selectall_arrayref($sql) } ;
|
241
|
|
|
|
|
|
|
$style = $res->[0]->[0];
|
242
|
|
|
|
|
|
|
_write_log_entry(DEBUG, "phpBB default style path: $style");
|
243
|
|
|
|
|
|
|
}
|
244
|
|
|
|
|
|
|
else{
|
245
|
|
|
|
|
|
|
_write_log_entry(AUDIT, 'No database connection, cannot get phpBB style');
|
246
|
|
|
|
|
|
|
}
|
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
if (!$style){
|
249
|
|
|
|
|
|
|
$style = DEFAULT_STYLE;
|
250
|
|
|
|
|
|
|
}
|
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
return $style;
|
253
|
|
|
|
|
|
|
}
|
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub _mysql_connect {
|
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
if ($phpbb_config_ref->{dbms} eq 'mysql'){
|
258
|
|
|
|
|
|
|
$dbh = DBI->connect(
|
259
|
|
|
|
|
|
|
'DBI:mysql:database=' . $phpbb_config_ref->{dbname} .';host=' . $phpbb_config_ref->{dbhost},
|
260
|
|
|
|
|
|
|
$phpbb_config_ref->{dbuser},
|
261
|
|
|
|
|
|
|
$phpbb_config_ref->{dbpasswd},
|
262
|
|
|
|
|
|
|
{ RaiseError => 1,
|
263
|
|
|
|
|
|
|
AutoCommit => 1,
|
264
|
|
|
|
|
|
|
}
|
265
|
|
|
|
|
|
|
);
|
266
|
|
|
|
|
|
|
}
|
267
|
|
|
|
|
|
|
else{
|
268
|
|
|
|
|
|
|
_write_log_entry(AUDIT, 'Only mysql databases are supported, database updates are not possible');
|
269
|
|
|
|
|
|
|
}
|
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
return $dbh;
|
272
|
|
|
|
|
|
|
}
|
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
sub _read_phpbb_config{
|
275
|
|
|
|
|
|
|
my %phpbb_config;
|
276
|
|
|
|
|
|
|
open IN, '<', $config_file or croak "Can't open phpbb config file: $!\n";
|
277
|
|
|
|
|
|
|
while() {
|
278
|
|
|
|
|
|
|
my $line=$_;
|
279
|
|
|
|
|
|
|
if ($line =~ /^\s*\$(\w+)\s*=\s*'(\w*)'\;\s*$/) {
|
280
|
|
|
|
|
|
|
$phpbb_config{$1} = $2;
|
281
|
|
|
|
|
|
|
}
|
282
|
|
|
|
|
|
|
elsif ($line =~ /^\s*\@define\('(\w+)',\s*(\w+)\);\s*$/){
|
283
|
|
|
|
|
|
|
$phpbb_config{$1} = $2;
|
284
|
|
|
|
|
|
|
}
|
285
|
|
|
|
|
|
|
}
|
286
|
|
|
|
|
|
|
close (IN);
|
287
|
|
|
|
|
|
|
_write_log_entry(DEBUG, "phpBB Config: " . Data::Dumper->Dump([\%phpbb_config]));
|
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
return \%phpbb_config;
|
290
|
|
|
|
|
|
|
}
|
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
sub _load_install_file {
|
293
|
|
|
|
|
|
|
my $install_filename = shift;
|
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
#create a parser and attempt to parse the XML document
|
296
|
|
|
|
|
|
|
my $dom = XML::Xerces::XercesDOMParser->new();
|
297
|
|
|
|
|
|
|
my $error_handler = XML::Xerces::PerlErrorHandler->new();
|
298
|
|
|
|
|
|
|
$dom->setErrorHandler($error_handler);
|
299
|
|
|
|
|
|
|
eval{$dom->parse($install_filename)};
|
300
|
|
|
|
|
|
|
croak("Couldn't parse file: $install_filename\n$@") if $@;
|
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
#the parse was successful, we have a well formed xml instance
|
303
|
|
|
|
|
|
|
my $doc = $dom->getDocument();
|
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
return $doc;
|
306
|
|
|
|
|
|
|
}
|
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
sub _write_log_entry{
|
309
|
|
|
|
|
|
|
my $type = shift;
|
310
|
|
|
|
|
|
|
my $message = shift;
|
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst)
|
313
|
|
|
|
|
|
|
= localtime(time);
|
314
|
|
|
|
|
|
|
my $curr_time = sprintf "%4d-%02d-%02d %02d:%02d:%02d", $year+1900,$mon+1,$mday,$hour,$min,$sec;
|
315
|
|
|
|
|
|
|
my $log_line = "$curr_time - $message\n";
|
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
my $file_handle = $log_handles{$type};
|
318
|
|
|
|
|
|
|
if ($file_handle){
|
319
|
|
|
|
|
|
|
print $file_handle $log_line;
|
320
|
|
|
|
|
|
|
}
|
321
|
|
|
|
|
|
|
else{
|
322
|
|
|
|
|
|
|
warn $log_line;
|
323
|
|
|
|
|
|
|
}
|
324
|
|
|
|
|
|
|
}
|
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
sub _process_document {
|
327
|
|
|
|
|
|
|
my $install_doc = shift;
|
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
my @instruction_list;
|
330
|
|
|
|
|
|
|
my $root = $install_doc->getDocumentElement();
|
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
if ($root->hasChildNodes()) {
|
333
|
|
|
|
|
|
|
ROOT: foreach my $child ($root->getChildNodes) {
|
334
|
|
|
|
|
|
|
my $child_name = $child->getNodeName();
|
335
|
|
|
|
|
|
|
if ($child->isa('XML::Xerces::DOMElement')){
|
336
|
|
|
|
|
|
|
if ($child_name eq 'action-group'){
|
337
|
|
|
|
|
|
|
#process this node
|
338
|
|
|
|
|
|
|
if ($child->hasChildNodes()) {
|
339
|
|
|
|
|
|
|
foreach my $action ($child->getChildNodes) {
|
340
|
|
|
|
|
|
|
my $action_name = $action->getNodeName();
|
341
|
|
|
|
|
|
|
if ($action->isa('XML::Xerces::DOMElement')){
|
342
|
|
|
|
|
|
|
if ($action_name eq 'copy'){
|
343
|
|
|
|
|
|
|
my $copy_ref = _process_copy($action);
|
344
|
|
|
|
|
|
|
push (@instruction_list, $copy_ref);
|
345
|
|
|
|
|
|
|
}
|
346
|
|
|
|
|
|
|
elsif ($action_name eq 'sql'){
|
347
|
|
|
|
|
|
|
my $sql_ref = _process_sql($action);
|
348
|
|
|
|
|
|
|
push (@instruction_list, $sql_ref);
|
349
|
|
|
|
|
|
|
}
|
350
|
|
|
|
|
|
|
elsif ($action_name eq 'open'){
|
351
|
|
|
|
|
|
|
my $open_ref = _process_open($action);
|
352
|
|
|
|
|
|
|
push (@instruction_list, $open_ref);
|
353
|
|
|
|
|
|
|
}
|
354
|
|
|
|
|
|
|
elsif ($action_name eq 'diy-instructions'){
|
355
|
|
|
|
|
|
|
my $diy_ref = _process_diy_instructions($action);
|
356
|
|
|
|
|
|
|
push (@instruction_list, $diy_ref);
|
357
|
|
|
|
|
|
|
}
|
358
|
|
|
|
|
|
|
}
|
359
|
|
|
|
|
|
|
}
|
360
|
|
|
|
|
|
|
}
|
361
|
|
|
|
|
|
|
else{
|
362
|
|
|
|
|
|
|
#no actions
|
363
|
|
|
|
|
|
|
croak "No actions to perform\n";
|
364
|
|
|
|
|
|
|
}
|
365
|
|
|
|
|
|
|
}
|
366
|
|
|
|
|
|
|
elsif ($child_name eq 'header'){
|
367
|
|
|
|
|
|
|
_process_header($child);
|
368
|
|
|
|
|
|
|
}
|
369
|
|
|
|
|
|
|
else{
|
370
|
|
|
|
|
|
|
_write_log_entry(DEBUG, "Found additional first level child '$child_name' - skipping....");
|
371
|
|
|
|
|
|
|
}
|
372
|
|
|
|
|
|
|
}
|
373
|
|
|
|
|
|
|
}
|
374
|
|
|
|
|
|
|
}
|
375
|
|
|
|
|
|
|
else{
|
376
|
|
|
|
|
|
|
croak "Empty document nothing to process\n";
|
377
|
|
|
|
|
|
|
}
|
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
return \@instruction_list;
|
380
|
|
|
|
|
|
|
}
|
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
sub _process_header{
|
383
|
|
|
|
|
|
|
my $header = shift;
|
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
foreach my $child ($header->getChildNodes) {
|
386
|
|
|
|
|
|
|
my $child_name = $child->getNodeName();
|
387
|
|
|
|
|
|
|
if ($child->isa('XML::Xerces::DOMElement')){
|
388
|
|
|
|
|
|
|
if ($child_name eq 'title'){
|
389
|
|
|
|
|
|
|
$headers{title} = $headers{title} || $child->getTextContent();
|
390
|
|
|
|
|
|
|
my %child_attrs = $child->getAttributes();
|
391
|
|
|
|
|
|
|
foreach my $attr_name (keys %child_attrs) {
|
392
|
|
|
|
|
|
|
if ($attr_name eq 'lang'){
|
393
|
|
|
|
|
|
|
if ($child_attrs{$attr_name} eq $lang){
|
394
|
|
|
|
|
|
|
$headers{title} = $child->getTextContent();
|
395
|
|
|
|
|
|
|
}
|
396
|
|
|
|
|
|
|
}
|
397
|
|
|
|
|
|
|
}
|
398
|
|
|
|
|
|
|
}
|
399
|
|
|
|
|
|
|
elsif ($child_name eq 'description'){
|
400
|
|
|
|
|
|
|
$headers{description} = $headers{description} || $child->getTextContent();
|
401
|
|
|
|
|
|
|
my %child_attrs = $child->getAttributes();
|
402
|
|
|
|
|
|
|
foreach my $attr_name (keys %child_attrs) {
|
403
|
|
|
|
|
|
|
if ($attr_name eq 'lang'){
|
404
|
|
|
|
|
|
|
if ($child_attrs{$attr_name} eq $lang){
|
405
|
|
|
|
|
|
|
$headers{description} = $child->getTextContent();
|
406
|
|
|
|
|
|
|
}
|
407
|
|
|
|
|
|
|
}
|
408
|
|
|
|
|
|
|
}
|
409
|
|
|
|
|
|
|
}
|
410
|
|
|
|
|
|
|
elsif ($child_name eq 'author-group'){
|
411
|
|
|
|
|
|
|
foreach my $ag_child($child->getChildNodes) {
|
412
|
|
|
|
|
|
|
my $ag_name = $ag_child->getNodeName();
|
413
|
|
|
|
|
|
|
if ($ag_child->isa('XML::Xerces::DOMElement')){
|
414
|
|
|
|
|
|
|
if ($ag_name eq 'author'){
|
415
|
|
|
|
|
|
|
foreach my $author_child($ag_child->getChildNodes) {
|
416
|
|
|
|
|
|
|
my $author_name = $author_child->getNodeName();
|
417
|
|
|
|
|
|
|
if ($author_child->isa('XML::Xerces::DOMElement')){
|
418
|
|
|
|
|
|
|
if ($author_name eq 'realname'){
|
419
|
|
|
|
|
|
|
$headers{author} = $author_child->getTextContent();
|
420
|
|
|
|
|
|
|
}
|
421
|
|
|
|
|
|
|
elsif ($author_name eq 'username'){
|
422
|
|
|
|
|
|
|
$headers{author_username} = $author_child->getTextContent();
|
423
|
|
|
|
|
|
|
}
|
424
|
|
|
|
|
|
|
}
|
425
|
|
|
|
|
|
|
}
|
426
|
|
|
|
|
|
|
}
|
427
|
|
|
|
|
|
|
}
|
428
|
|
|
|
|
|
|
}
|
429
|
|
|
|
|
|
|
}
|
430
|
|
|
|
|
|
|
elsif ($child_name eq 'mod-version'){
|
431
|
|
|
|
|
|
|
foreach my $mv_child($child->getChildNodes) {
|
432
|
|
|
|
|
|
|
my $mv_name = $mv_child->getNodeName();
|
433
|
|
|
|
|
|
|
if ($mv_child->isa('XML::Xerces::DOMElement')){
|
434
|
|
|
|
|
|
|
if ($mv_name eq 'major'){
|
435
|
|
|
|
|
|
|
$headers{version_major} = $mv_child->getTextContent();
|
436
|
|
|
|
|
|
|
}
|
437
|
|
|
|
|
|
|
elsif ($mv_name eq 'minor'){
|
438
|
|
|
|
|
|
|
$headers{version_minor} = $mv_child->getTextContent();
|
439
|
|
|
|
|
|
|
}
|
440
|
|
|
|
|
|
|
elsif ($mv_name eq 'revision'){
|
441
|
|
|
|
|
|
|
$headers{version_revision} = $mv_child->getTextContent();
|
442
|
|
|
|
|
|
|
}
|
443
|
|
|
|
|
|
|
elsif ($mv_name eq 'release'){
|
444
|
|
|
|
|
|
|
$headers{version_release} = $mv_child->getTextContent();
|
445
|
|
|
|
|
|
|
}
|
446
|
|
|
|
|
|
|
}
|
447
|
|
|
|
|
|
|
}
|
448
|
|
|
|
|
|
|
}
|
449
|
|
|
|
|
|
|
elsif ($child_name eq 'installation'){
|
450
|
|
|
|
|
|
|
foreach my $i_child($child->getChildNodes) {
|
451
|
|
|
|
|
|
|
my $i_name = $i_child->getNodeName();
|
452
|
|
|
|
|
|
|
if ($i_child->isa('XML::Xerces::DOMElement')){
|
453
|
|
|
|
|
|
|
if ($i_name eq 'target-version'){
|
454
|
|
|
|
|
|
|
foreach my $tv_child($i_child->getChildNodes) {
|
455
|
|
|
|
|
|
|
my $tv_name = $tv_child->getNodeName();
|
456
|
|
|
|
|
|
|
if ($tv_child->isa('XML::Xerces::DOMElement')){
|
457
|
|
|
|
|
|
|
if ($tv_name eq 'target-primary'){
|
458
|
|
|
|
|
|
|
$headers{target_version} = $tv_child->getTextContent();
|
459
|
|
|
|
|
|
|
}
|
460
|
|
|
|
|
|
|
}
|
461
|
|
|
|
|
|
|
}
|
462
|
|
|
|
|
|
|
}
|
463
|
|
|
|
|
|
|
}
|
464
|
|
|
|
|
|
|
}
|
465
|
|
|
|
|
|
|
}
|
466
|
|
|
|
|
|
|
}
|
467
|
|
|
|
|
|
|
}
|
468
|
|
|
|
|
|
|
foreach my $nv_name(qw{author author_username version_major
|
469
|
|
|
|
|
|
|
version_minor version_revision
|
470
|
|
|
|
|
|
|
version_release title description}){
|
471
|
|
|
|
|
|
|
if (!defined $headers{$nv_name}){
|
472
|
|
|
|
|
|
|
$headers{$nv_name} = '';
|
473
|
|
|
|
|
|
|
}
|
474
|
|
|
|
|
|
|
}
|
475
|
|
|
|
|
|
|
_write_log_entry(DEBUG, "Install file header values: " . Data::Dumper->Dump([\%headers]));
|
476
|
|
|
|
|
|
|
}
|
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
sub _process_copy{
|
479
|
|
|
|
|
|
|
my $copy_node = shift;
|
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
my %return_hash;
|
482
|
|
|
|
|
|
|
my @file_array;
|
483
|
|
|
|
|
|
|
$return_hash{action} = 'copy';
|
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
foreach my $child ($copy_node->getChildNodes) {
|
486
|
|
|
|
|
|
|
my $child_name = $child->getNodeName();
|
487
|
|
|
|
|
|
|
if ($child->isa('XML::Xerces::DOMElement')){
|
488
|
|
|
|
|
|
|
if ($child_name eq 'file'){
|
489
|
|
|
|
|
|
|
my %file_hash;
|
490
|
|
|
|
|
|
|
my %file_attrs = $child->getAttributes();
|
491
|
|
|
|
|
|
|
foreach my $attr_name (keys %file_attrs) {
|
492
|
|
|
|
|
|
|
$file_hash{$attr_name} = $file_attrs{$attr_name};
|
493
|
|
|
|
|
|
|
}
|
494
|
|
|
|
|
|
|
push (@file_array, \%file_hash);
|
495
|
|
|
|
|
|
|
}
|
496
|
|
|
|
|
|
|
}
|
497
|
|
|
|
|
|
|
}
|
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
$return_hash{files} = \@file_array;
|
500
|
|
|
|
|
|
|
return \%return_hash;
|
501
|
|
|
|
|
|
|
}
|
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
sub _process_open{
|
504
|
|
|
|
|
|
|
my $open_node = shift;
|
505
|
|
|
|
|
|
|
my %return_hash;
|
506
|
|
|
|
|
|
|
my @edits;
|
507
|
|
|
|
|
|
|
$return_hash{action} = 'open';
|
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
my %open_attrs = $open_node->getAttributes();
|
510
|
|
|
|
|
|
|
foreach my $attr_name (keys %open_attrs) {
|
511
|
|
|
|
|
|
|
if ($attr_name eq 'src'){
|
512
|
|
|
|
|
|
|
$return_hash{src} = $open_attrs{$attr_name};
|
513
|
|
|
|
|
|
|
}
|
514
|
|
|
|
|
|
|
}
|
515
|
|
|
|
|
|
|
foreach my $child ($open_node->getChildNodes) {
|
516
|
|
|
|
|
|
|
my $child_name = $child->getNodeName();
|
517
|
|
|
|
|
|
|
if ($child->isa('XML::Xerces::DOMElement')){
|
518
|
|
|
|
|
|
|
if ($child_name eq 'edit'){
|
519
|
|
|
|
|
|
|
my %edit_hash;
|
520
|
|
|
|
|
|
|
foreach my $edit_child ($child->getChildNodes) {
|
521
|
|
|
|
|
|
|
my $edit_child_name = $edit_child->getNodeName();
|
522
|
|
|
|
|
|
|
if ($edit_child->isa('XML::Xerces::DOMElement')){
|
523
|
|
|
|
|
|
|
if ($edit_child_name eq 'find'){
|
524
|
|
|
|
|
|
|
$edit_hash{find} = $edit_child->getTextContent();
|
525
|
|
|
|
|
|
|
my %find_attrs = $edit_child->getAttributes();
|
526
|
|
|
|
|
|
|
foreach my $attr_name (keys %find_attrs) {
|
527
|
|
|
|
|
|
|
if ($attr_name eq 'type'){
|
528
|
|
|
|
|
|
|
$edit_hash{find_type} = $find_attrs{$attr_name};
|
529
|
|
|
|
|
|
|
}
|
530
|
|
|
|
|
|
|
}
|
531
|
|
|
|
|
|
|
}
|
532
|
|
|
|
|
|
|
elsif ($edit_child_name eq 'action'){
|
533
|
|
|
|
|
|
|
my %action_attrs = $edit_child->getAttributes();
|
534
|
|
|
|
|
|
|
foreach my $attr_name (keys %action_attrs) {
|
535
|
|
|
|
|
|
|
if ($attr_name eq 'type'){
|
536
|
|
|
|
|
|
|
my $type_name = $action_attrs{$attr_name};
|
537
|
|
|
|
|
|
|
if ($type_name eq 'after-add'){
|
538
|
|
|
|
|
|
|
$edit_hash{action_after_add} = $edit_child->getTextContent();
|
539
|
|
|
|
|
|
|
}
|
540
|
|
|
|
|
|
|
elsif ($type_name eq 'before-add'){
|
541
|
|
|
|
|
|
|
$edit_hash{action_before_add} = $edit_child->getTextContent();
|
542
|
|
|
|
|
|
|
}
|
543
|
|
|
|
|
|
|
elsif ($type_name eq 'replace-with'){
|
544
|
|
|
|
|
|
|
$edit_hash{action_replace_with} = $edit_child->getTextContent();
|
545
|
|
|
|
|
|
|
}
|
546
|
|
|
|
|
|
|
}
|
547
|
|
|
|
|
|
|
}
|
548
|
|
|
|
|
|
|
}
|
549
|
|
|
|
|
|
|
elsif ($edit_child_name eq 'inline-edit'){
|
550
|
|
|
|
|
|
|
foreach my $ie_child ($edit_child->getChildNodes) {
|
551
|
|
|
|
|
|
|
my $ie_name = $ie_child->getNodeName();
|
552
|
|
|
|
|
|
|
if ($ie_child->isa('XML::Xerces::DOMElement')){
|
553
|
|
|
|
|
|
|
if ($ie_name eq 'inline-find'){
|
554
|
|
|
|
|
|
|
$edit_hash{inline_find} = $ie_child->getTextContent();
|
555
|
|
|
|
|
|
|
my %find_attrs = $ie_child->getAttributes();
|
556
|
|
|
|
|
|
|
foreach my $attr_name (keys %find_attrs) {
|
557
|
|
|
|
|
|
|
if ($attr_name eq 'type'){
|
558
|
|
|
|
|
|
|
$edit_hash{find_type} = $find_attrs{$attr_name};
|
559
|
|
|
|
|
|
|
}
|
560
|
|
|
|
|
|
|
}
|
561
|
|
|
|
|
|
|
}
|
562
|
|
|
|
|
|
|
elsif ($ie_name eq 'inline-action'){
|
563
|
|
|
|
|
|
|
my %action_attrs = $ie_child->getAttributes();
|
564
|
|
|
|
|
|
|
foreach my $attr_name (keys %action_attrs) {
|
565
|
|
|
|
|
|
|
if ($attr_name eq 'type'){
|
566
|
|
|
|
|
|
|
my $type_name = $action_attrs{$attr_name};
|
567
|
|
|
|
|
|
|
if ($type_name eq 'after-add'){
|
568
|
|
|
|
|
|
|
$edit_hash{inline_action_after_add} = $ie_child->getTextContent();
|
569
|
|
|
|
|
|
|
}
|
570
|
|
|
|
|
|
|
elsif ($type_name eq 'before-add'){
|
571
|
|
|
|
|
|
|
$edit_hash{inline_action_before_add} = $ie_child->getTextContent();
|
572
|
|
|
|
|
|
|
}
|
573
|
|
|
|
|
|
|
elsif ($type_name eq 'replace-with'){
|
574
|
|
|
|
|
|
|
$edit_hash{inline_action_replace_with} = $ie_child->getTextContent();
|
575
|
|
|
|
|
|
|
}
|
576
|
|
|
|
|
|
|
}
|
577
|
|
|
|
|
|
|
}
|
578
|
|
|
|
|
|
|
}
|
579
|
|
|
|
|
|
|
}
|
580
|
|
|
|
|
|
|
}
|
581
|
|
|
|
|
|
|
}
|
582
|
|
|
|
|
|
|
}
|
583
|
|
|
|
|
|
|
}
|
584
|
|
|
|
|
|
|
push (@edits, \%edit_hash);
|
585
|
|
|
|
|
|
|
}
|
586
|
|
|
|
|
|
|
}
|
587
|
|
|
|
|
|
|
}
|
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
$return_hash{edits} = \@edits;
|
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
return \%return_hash;
|
592
|
|
|
|
|
|
|
}
|
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
sub _process_sql{
|
595
|
|
|
|
|
|
|
my $sql_node = shift;
|
596
|
|
|
|
|
|
|
my %return_hash;
|
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
my %sql_attrs = $sql_node->getAttributes();
|
599
|
|
|
|
|
|
|
foreach my $attr_name (keys %sql_attrs) {
|
600
|
|
|
|
|
|
|
if ($attr_name eq 'dbms'){
|
601
|
|
|
|
|
|
|
$return_hash{dbms} = $sql_attrs{$attr_name};
|
602
|
|
|
|
|
|
|
}
|
603
|
|
|
|
|
|
|
}
|
604
|
|
|
|
|
|
|
$return_hash{action} = 'sql';
|
605
|
|
|
|
|
|
|
$return_hash{sql} = $sql_node->getTextContent();
|
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
#process everything as mysql
|
608
|
|
|
|
|
|
|
#if (defined $return_hash{dbms}){
|
609
|
|
|
|
|
|
|
# if ($return_hash{dbms} ne 'mysql'){
|
610
|
|
|
|
|
|
|
# _write_log_entry(ERROR, "The only supported database is mysql, can't process SQL statement");
|
611
|
|
|
|
|
|
|
# croak "Can't process SQL statement only mysql is supported\n";
|
612
|
|
|
|
|
|
|
# }
|
613
|
|
|
|
|
|
|
# elsif ($return_hash{dbms} ne $phpbb_config_ref->{dbms}){
|
614
|
|
|
|
|
|
|
# _write_log_entry(ERROR, "php DBMS type is different to the SQL statement DBMS type");
|
615
|
|
|
|
|
|
|
# croak "php DBMS type is different to the SQL statement DBMS type\n";
|
616
|
|
|
|
|
|
|
# }
|
617
|
|
|
|
|
|
|
#}
|
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
return \%return_hash;
|
620
|
|
|
|
|
|
|
}
|
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
sub _process_diy_instructions{
|
623
|
|
|
|
|
|
|
my $diy_node = shift;
|
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
my %return_hash;
|
626
|
|
|
|
|
|
|
$return_hash{action} = 'diy-instructions';
|
627
|
|
|
|
|
|
|
$return_hash{instruction} = $return_hash{instruction} || $diy_node->getTextContent();
|
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
my %child_attrs = $diy_node->getAttributes();
|
630
|
|
|
|
|
|
|
foreach my $attr_name (keys %child_attrs) {
|
631
|
|
|
|
|
|
|
if ($attr_name eq 'lang'){
|
632
|
|
|
|
|
|
|
if ($child_attrs{$attr_name} eq $lang){
|
633
|
|
|
|
|
|
|
$return_hash{instruction} = $diy_node->getTextContent();
|
634
|
|
|
|
|
|
|
}
|
635
|
|
|
|
|
|
|
}
|
636
|
|
|
|
|
|
|
}
|
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
return \%return_hash;
|
639
|
|
|
|
|
|
|
}
|
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
sub _process_uninstall{
|
642
|
|
|
|
|
|
|
my $instructions_ref = shift;
|
643
|
|
|
|
|
|
|
my $backup_dir = shift;
|
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
warn ("WARNING: Uninstall not yet implemented\n\n");
|
646
|
|
|
|
|
|
|
return;
|
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
foreach my $instruction_ref (@{$instructions_ref}){
|
649
|
|
|
|
|
|
|
if ($instruction_ref->{action} eq 'copy'){
|
650
|
|
|
|
|
|
|
#phpbb_uninstall_copy_file($instruction_ref, $backup_dir);
|
651
|
|
|
|
|
|
|
}
|
652
|
|
|
|
|
|
|
elsif ($instruction_ref->{action} eq 'sql'){
|
653
|
|
|
|
|
|
|
#phpbb_uninstall_run_sql($instruction_ref);
|
654
|
|
|
|
|
|
|
}
|
655
|
|
|
|
|
|
|
elsif ($instruction_ref->{action} eq 'open'){
|
656
|
|
|
|
|
|
|
#phpbb_uninstall_open_file($instruction_ref);
|
657
|
|
|
|
|
|
|
}
|
658
|
|
|
|
|
|
|
elsif ($instruction_ref->{action} eq 'diy-instructions'){
|
659
|
|
|
|
|
|
|
#phpbb_uninstall_diy_instructions($instruction_ref);
|
660
|
|
|
|
|
|
|
}
|
661
|
|
|
|
|
|
|
}
|
662
|
|
|
|
|
|
|
}
|
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
sub _process_instructions{
|
666
|
|
|
|
|
|
|
my $instructions_ref = shift;
|
667
|
|
|
|
|
|
|
my $backup_dir = shift;
|
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
foreach my $instruction_ref (@{$instructions_ref}){
|
670
|
|
|
|
|
|
|
if ($instruction_ref->{action} eq 'copy'){
|
671
|
|
|
|
|
|
|
_phpbb_copy_file($instruction_ref, $backup_dir);
|
672
|
|
|
|
|
|
|
}
|
673
|
|
|
|
|
|
|
elsif ($instruction_ref->{action} eq 'sql'){
|
674
|
|
|
|
|
|
|
_phpbb_run_sql($instruction_ref);
|
675
|
|
|
|
|
|
|
}
|
676
|
|
|
|
|
|
|
elsif ($instruction_ref->{action} eq 'open'){
|
677
|
|
|
|
|
|
|
_phpbb_open_file($instruction_ref);
|
678
|
|
|
|
|
|
|
}
|
679
|
|
|
|
|
|
|
elsif ($instruction_ref->{action} eq 'diy-instructions'){
|
680
|
|
|
|
|
|
|
_phpbb_diy_instructions($instruction_ref);
|
681
|
|
|
|
|
|
|
}
|
682
|
|
|
|
|
|
|
}
|
683
|
|
|
|
|
|
|
}
|
684
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
sub _phpbb_copy_file{
|
686
|
|
|
|
|
|
|
my $instruction_ref = shift;
|
687
|
|
|
|
|
|
|
my $backup_dir = shift;
|
688
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
foreach my $file_ref (@{$instruction_ref->{files}}){
|
690
|
|
|
|
|
|
|
my $to = $file_ref->{to};
|
691
|
|
|
|
|
|
|
if ( (defined $style) && ($to =~ /^(.*)prosilver(.*)$/) ){
|
692
|
|
|
|
|
|
|
$to = $1 . $style . $2;
|
693
|
|
|
|
|
|
|
}
|
694
|
|
|
|
|
|
|
elsif ( (defined $style) && ($to =~ /^(.*)subsilver2(.*)$/) ){
|
695
|
|
|
|
|
|
|
$to = $1 . $style . $2;
|
696
|
|
|
|
|
|
|
}
|
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
my $source = "$install_absolute_path/" . $file_ref->{from};
|
699
|
|
|
|
|
|
|
my $destination = "$web_root_absolute_path/" . $to;
|
700
|
|
|
|
|
|
|
if (index($destination, '*') >= 0){
|
701
|
|
|
|
|
|
|
$destination = dirname ($destination);
|
702
|
|
|
|
|
|
|
}
|
703
|
|
|
|
|
|
|
_write_log_entry(AUDIT, "Copy file: $source to $destination");
|
704
|
|
|
|
|
|
|
if (-f $destination){
|
705
|
|
|
|
|
|
|
my $backup_filename = "$backup_dir/" . $to;
|
706
|
|
|
|
|
|
|
_create_dir_recursive( dirname ($backup_filename) );
|
707
|
|
|
|
|
|
|
_write_log_entry(DEBUG, "Backup file: $destination to $backup_filename");
|
708
|
|
|
|
|
|
|
copy ($destination, $backup_filename)
|
709
|
|
|
|
|
|
|
or croak "Failed to backup $destination\n";
|
710
|
|
|
|
|
|
|
}
|
711
|
|
|
|
|
|
|
_create_dir_recursive( dirname ($destination) );
|
712
|
|
|
|
|
|
|
copy ($source, $destination)
|
713
|
|
|
|
|
|
|
or croak "Copy failed from $source to $destination\n";
|
714
|
|
|
|
|
|
|
}
|
715
|
|
|
|
|
|
|
}
|
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
sub _phpbb_run_sql{
|
718
|
|
|
|
|
|
|
my $instruction_ref = shift;
|
719
|
|
|
|
|
|
|
if ($dbh){
|
720
|
|
|
|
|
|
|
my $sql = $instruction_ref->{sql};
|
721
|
|
|
|
|
|
|
$sql =~ s/phpbb_/$phpbb_config_ref->{table_prefix}/g;
|
722
|
|
|
|
|
|
|
my @statements = split /;/, $sql;
|
723
|
|
|
|
|
|
|
foreach my $statement (@statements){
|
724
|
|
|
|
|
|
|
$statement = _trim($statement);
|
725
|
|
|
|
|
|
|
if (length($statement) > 0){
|
726
|
|
|
|
|
|
|
_write_log_entry(AUDIT, "Updating database: $statement");
|
727
|
|
|
|
|
|
|
my $sth;
|
728
|
|
|
|
|
|
|
eval{$sth = $dbh->prepare($statement)};
|
729
|
|
|
|
|
|
|
eval{$sth->execute();};
|
730
|
|
|
|
|
|
|
if ($@){
|
731
|
|
|
|
|
|
|
_write_log_entry(ERROR, "Unable to run SQL: '$statement' : " . $dbh->err . " : $@");
|
732
|
|
|
|
|
|
|
carp "Database error trying to run SQL. $@\n";
|
733
|
|
|
|
|
|
|
}
|
734
|
|
|
|
|
|
|
}
|
735
|
|
|
|
|
|
|
}
|
736
|
|
|
|
|
|
|
}
|
737
|
|
|
|
|
|
|
else{
|
738
|
|
|
|
|
|
|
_write_log_entry(ERROR, "Cannot update database, no database connection");
|
739
|
|
|
|
|
|
|
croak "Can't update database, no connection\n";
|
740
|
|
|
|
|
|
|
}
|
741
|
|
|
|
|
|
|
}
|
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
sub _phpbb_open_file{
|
744
|
|
|
|
|
|
|
my $instruction_ref = shift;
|
745
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
my $src = $instruction_ref->{src};
|
747
|
|
|
|
|
|
|
if ( (defined $style) && ($src =~ /^(.*)prosilver(.*)$/) ){
|
748
|
|
|
|
|
|
|
$src = $1 . $style . $2;
|
749
|
|
|
|
|
|
|
}
|
750
|
|
|
|
|
|
|
if ( (defined $style) && ($src =~ /^(.*)subsilver2(.*)$/) ){
|
751
|
|
|
|
|
|
|
$src = $1 . $style . $2;
|
752
|
|
|
|
|
|
|
}
|
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
my $file_to_open = "$web_root_absolute_path/$src";
|
755
|
|
|
|
|
|
|
if (!-f $file_to_open){
|
756
|
|
|
|
|
|
|
_write_log_entry(ERROR, "File to open '$file_to_open' doesn't exist");
|
757
|
|
|
|
|
|
|
warn "WARNING: File to open '$file_to_open' doesn't exist\n";
|
758
|
|
|
|
|
|
|
}
|
759
|
|
|
|
|
|
|
_write_log_entry(AUDIT, "Opening file '$file_to_open'");
|
760
|
|
|
|
|
|
|
my $backup_filename = "$backup_dir/" . $src;
|
761
|
|
|
|
|
|
|
_create_dir_recursive( dirname ($backup_filename) );
|
762
|
|
|
|
|
|
|
_write_log_entry(DEBUG, "Backup file: $file_to_open to $backup_filename");
|
763
|
|
|
|
|
|
|
copy ($file_to_open, $backup_filename)
|
764
|
|
|
|
|
|
|
or croak "Failed to backup $file_to_open\n";
|
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
{
|
767
|
|
|
|
|
|
|
local( $/, *FH ) ;
|
768
|
|
|
|
|
|
|
open( FH, '<', $file_to_open ) or croak "Couldn't open file for editing: $!\n";
|
769
|
|
|
|
|
|
|
my $file_text = ;
|
770
|
|
|
|
|
|
|
close (FH);
|
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
foreach my $edit_ref (@{$instruction_ref->{edits}}){
|
773
|
|
|
|
|
|
|
my $find_start = index($file_text, $edit_ref->{find});
|
774
|
|
|
|
|
|
|
if($find_start >= 0){
|
775
|
|
|
|
|
|
|
my $find_text = $edit_ref->{find};
|
776
|
|
|
|
|
|
|
my $pre_text = substr $file_text, 0, $find_start;
|
777
|
|
|
|
|
|
|
my $post_text = substr $file_text, $find_start + length($find_text);
|
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
if (defined $edit_ref->{inline_find}){
|
780
|
|
|
|
|
|
|
my $inline_find_start = index($find_text, $edit_ref->{inline_find});
|
781
|
|
|
|
|
|
|
if($inline_find_start >= 0){
|
782
|
|
|
|
|
|
|
my $inline_find_text = $edit_ref->{inline_find};
|
783
|
|
|
|
|
|
|
my $inline_pre_text = substr $find_text, 0, $inline_find_start;
|
784
|
|
|
|
|
|
|
my $inline_post_text = substr $find_text, $inline_find_start + length($inline_find_text);
|
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
my $already_installed = 0;
|
787
|
|
|
|
|
|
|
if (defined $edit_ref->{inline_action_after_add}){
|
788
|
|
|
|
|
|
|
if (index($file_text, $inline_find_text . $edit_ref->{inline_action_after_add}) >= 0){
|
789
|
|
|
|
|
|
|
$already_installed = 1;
|
790
|
|
|
|
|
|
|
}
|
791
|
|
|
|
|
|
|
}
|
792
|
|
|
|
|
|
|
if (defined $edit_ref->{inline_action_before_add}){
|
793
|
|
|
|
|
|
|
if (index($file_text, $edit_ref->{inline_action_before_add} . $inline_find_text) >= 0){
|
794
|
|
|
|
|
|
|
$already_installed = 1;
|
795
|
|
|
|
|
|
|
}
|
796
|
|
|
|
|
|
|
}
|
797
|
|
|
|
|
|
|
if($already_installed){
|
798
|
|
|
|
|
|
|
_write_log_entry(ERROR, "It looks like the mod has already been applied to $file_to_open");
|
799
|
|
|
|
|
|
|
croak "It looks like the mod has already been applied to $file_to_open\n";
|
800
|
|
|
|
|
|
|
}
|
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
if (defined $edit_ref->{inline_action_replace_with}){
|
803
|
|
|
|
|
|
|
$inline_find_text = $edit_ref->{inline_action_replace_with};
|
804
|
|
|
|
|
|
|
}
|
805
|
|
|
|
|
|
|
if (defined $edit_ref->{inline_action_after_add}){
|
806
|
|
|
|
|
|
|
$inline_find_text = $inline_find_text . $edit_ref->{inline_action_after_add};
|
807
|
|
|
|
|
|
|
}
|
808
|
|
|
|
|
|
|
if (defined $edit_ref->{inline_action_before_add}){
|
809
|
|
|
|
|
|
|
$inline_find_text = $edit_ref->{inline_action_before_add} . $inline_find_text;
|
810
|
|
|
|
|
|
|
}
|
811
|
|
|
|
|
|
|
$find_text = $inline_pre_text . $inline_find_text . $inline_post_text;
|
812
|
|
|
|
|
|
|
}
|
813
|
|
|
|
|
|
|
else{
|
814
|
|
|
|
|
|
|
_write_log_entry(ERROR, "Couldn't find the required inline edit: $edit_ref->{inline_find}");
|
815
|
|
|
|
|
|
|
warn "WARNING: Inline edit find failed, it must be dealt with manually. $edit_ref->{inline_find}\n";
|
816
|
|
|
|
|
|
|
}
|
817
|
|
|
|
|
|
|
}
|
818
|
|
|
|
|
|
|
if (defined $edit_ref->{action_replace_with} ||
|
819
|
|
|
|
|
|
|
defined $edit_ref->{action_before_add} ||
|
820
|
|
|
|
|
|
|
defined $edit_ref->{action_after_add}){
|
821
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
#check if the mod has already been applied
|
823
|
|
|
|
|
|
|
my $already_installed = 0;
|
824
|
|
|
|
|
|
|
if (defined $edit_ref->{action_before_add}){
|
825
|
|
|
|
|
|
|
my $action_start = index($file_text, $edit_ref->{action_before_add});
|
826
|
|
|
|
|
|
|
if ($action_start >= 0){
|
827
|
|
|
|
|
|
|
$already_installed = 1;
|
828
|
|
|
|
|
|
|
}
|
829
|
|
|
|
|
|
|
}
|
830
|
|
|
|
|
|
|
if (defined $edit_ref->{action_after_add}){
|
831
|
|
|
|
|
|
|
my $action_start = index($file_text, $edit_ref->{action_after_add});
|
832
|
|
|
|
|
|
|
if ($action_start >= 0){
|
833
|
|
|
|
|
|
|
$already_installed = 1;
|
834
|
|
|
|
|
|
|
}
|
835
|
|
|
|
|
|
|
}
|
836
|
|
|
|
|
|
|
if($already_installed){
|
837
|
|
|
|
|
|
|
_write_log_entry(ERROR, "It looks like the mod has already been applied to $file_to_open");
|
838
|
|
|
|
|
|
|
croak "It looks like the mod has already been applied to $file_to_open\n";
|
839
|
|
|
|
|
|
|
}
|
840
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
if (defined $edit_ref->{action_replace_with}){
|
842
|
|
|
|
|
|
|
$find_text = $edit_ref->{action_replace_with};
|
843
|
|
|
|
|
|
|
}
|
844
|
|
|
|
|
|
|
if (defined $edit_ref->{action_after_add}){
|
845
|
|
|
|
|
|
|
$find_text = $find_text . "\n\n" . $edit_ref->{action_after_add} . "\n";
|
846
|
|
|
|
|
|
|
}
|
847
|
|
|
|
|
|
|
if (defined $edit_ref->{action_before_add}){
|
848
|
|
|
|
|
|
|
$find_text = "\n" . $edit_ref->{action_before_add} . "\n\n" . $find_text;
|
849
|
|
|
|
|
|
|
}
|
850
|
|
|
|
|
|
|
}
|
851
|
|
|
|
|
|
|
$file_text = $pre_text . $find_text . $post_text;
|
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
open (OUT, '>', $file_to_open) or croak "Unable to rewrite file '$file_to_open': $!\n";
|
854
|
|
|
|
|
|
|
binmode OUT;
|
855
|
|
|
|
|
|
|
print OUT $file_text;
|
856
|
|
|
|
|
|
|
close (OUT);
|
857
|
|
|
|
|
|
|
}
|
858
|
|
|
|
|
|
|
else{
|
859
|
|
|
|
|
|
|
_write_log_entry(ERROR, "Couldn't find the required edit: $edit_ref->{find}");
|
860
|
|
|
|
|
|
|
warn "WARNING: Edit find failed, it must be dealt with manually. $edit_ref->{find}\n";
|
861
|
|
|
|
|
|
|
}
|
862
|
|
|
|
|
|
|
}
|
863
|
|
|
|
|
|
|
}
|
864
|
|
|
|
|
|
|
}
|
865
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
sub _phpbb_diy_instructions{
|
867
|
|
|
|
|
|
|
my $instruction_ref = shift;
|
868
|
|
|
|
|
|
|
_write_log_entry(AUDIT, "DIY Instruction: " . $instruction_ref->{instruction});
|
869
|
|
|
|
|
|
|
print STDOUT "\n\nDIY Instructions:\n" . $instruction_ref->{instruction} . "\n\n";
|
870
|
|
|
|
|
|
|
}
|
871
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
sub _create_dir_recursive{
|
874
|
|
|
|
|
|
|
my $complete_dir = shift;
|
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
my @file_parts = split /\//, $complete_dir;
|
877
|
|
|
|
|
|
|
my $curr_dir = '';
|
878
|
|
|
|
|
|
|
foreach my $file_part (@file_parts){
|
879
|
|
|
|
|
|
|
$curr_dir .= "$file_part/";
|
880
|
|
|
|
|
|
|
if (!-d $curr_dir){
|
881
|
|
|
|
|
|
|
mkdir ($curr_dir) or croak "mkdir failed for '$curr_dir'\n";
|
882
|
|
|
|
|
|
|
}
|
883
|
|
|
|
|
|
|
}
|
884
|
|
|
|
|
|
|
}
|
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
sub _create_backup_dirs{
|
888
|
|
|
|
|
|
|
my $working_dir = shift;
|
889
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
my $backup_dir = "$working_dir/backups";
|
891
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
if (!-d $backup_dir){
|
893
|
|
|
|
|
|
|
mkdir ($backup_dir)
|
894
|
|
|
|
|
|
|
or croak "Can't create backup directory '$backup_dir'\n";
|
895
|
|
|
|
|
|
|
}
|
896
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst)
|
898
|
|
|
|
|
|
|
= localtime(time);
|
899
|
|
|
|
|
|
|
my $curr_time = sprintf "%4d-%02d-%02d_%02d-%02d-%02d", $year+1900,$mon+1,$mday,$hour,$min,$sec;
|
900
|
|
|
|
|
|
|
my $current_backup_dir = "$backup_dir/$curr_time";
|
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
if (!-d $current_backup_dir){
|
903
|
|
|
|
|
|
|
mkdir ($current_backup_dir)
|
904
|
|
|
|
|
|
|
or croak "Can't create backup directory '$current_backup_dir'\n";
|
905
|
|
|
|
|
|
|
}
|
906
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
return $current_backup_dir;
|
908
|
|
|
|
|
|
|
}
|
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
sub _trim {
|
911
|
|
|
|
|
|
|
my $txt=shift;
|
912
|
|
|
|
|
|
|
$_=$txt;
|
913
|
|
|
|
|
|
|
$txt =~ s/^\s+|\s+$//g ;
|
914
|
|
|
|
|
|
|
return $txt
|
915
|
|
|
|
|
|
|
}
|
916
|
|
|
|
|
|
|
|
917
|
|
|
|
|
|
|
1;
|
918
|
|
|
|
|
|
|
|
919
|
|
|
|
|
|
|
__END__
|