8d23d3d039dd88cb20d4399dd561da4253d05b8c
[asterisk/asterisk.git] / contrib / scripts / dbsep.cgi
1 #!/usr/bin/perl
2 #
3 # Copyright (c) 2008 Digium, Inc.
4 #
5 # Tilghman Lesher <dbsep.cgi@the-tilghman.com>
6 #
7 # See http://www.asterisk.org for more information about
8 # the Asterisk project. Please do not directly contact
9 # any of the maintainers of this project for assistance;
10 # the project provides a web site, mailing lists and IRC
11 # channels for your use.
12 #
13 # This program is free software, distributed under the terms of
14 # the GNU General Public License Version 2. See the LICENSE file
15 # at the top of the source tree.
16 #
17 # $Id$
18 #
19
20 use CGI;
21 use DBI;
22 use strict;
23
24 my ($cgi, $dbh, %cfg, $table, $mode);
25
26 # The following settings are expected:
27 #
28 # dsn=<some valid dsn>
29 # dbuser=<user>
30 # dbpass=<passwd>
31 # backslash_is_escape={yes|no}
32 #
33 open CFG, "</etc/asterisk/dbsep.conf";
34 while (<CFG>) {
35         chomp;
36         next if (m/^[#;]/);
37         next if (m/^\s*$/);
38         my ($name,$value) = split '=';
39         $cfg{lc($name)} = $value;
40 }
41 close CFG;
42
43 $cgi = new CGI;
44
45 $ENV{PATH_INFO} =~ m/\/([^\/]*)\/([^\/]*)$/;
46 ($table, $mode) = ($1, lc($2));
47
48 print STDERR "PATH_INFO=$ENV{PATH_INFO}, table=$table, mode=$mode\n";
49
50 if ($mode eq 'single') {
51         # All parameters as POST
52         my ($sql, $sth, $row, @answer);
53         $sql = "SELECT * FROM $table WHERE " . join(" AND ", cgi_to_where_clause($cgi, \%cfg));
54         $dbh = DBI->connect($cfg{dsn}, $cfg{dbuser}, $cfg{dbpass});
55         $sth = $dbh->prepare($sql) || throw_error("Invalid query: $sql");
56         $sth->execute() || throw_error("Invalid query: $sql");
57         $row = $sth->fetchrow_hashref();
58         foreach (keys %$row) {
59                 push @answer, encode($_) . "=" . encode($row->{$_});
60         }
61         $sth->finish();
62         $dbh->disconnect();
63         print "Content-type: text/plain\n\n";
64         print join("&", @answer) . "\n";
65 } elsif ($ENV{PATH_INFO} =~ m/multi$/) {
66         # All parameters as POST
67         my ($sql, $sth, @answer);
68         $sql = "SELECT * FROM $table WHERE " . join(" AND ", cgi_to_where_clause($cgi, \%cfg));
69         $dbh = DBI->connect($cfg{dsn}, $cfg{dbuser}, $cfg{dbpass});
70         $sth = $dbh->prepare($sql) || throw_error("Invalid query: $sql");
71         $sth->execute() || throw_error("Invalid query: $sql");
72         print "Content-type: text/plain\n\n";
73         while (my $row = $sth->fetchrow_hashref()) {
74                 @answer = ();
75                 foreach (keys %$row) {
76                         push @answer, encode($_) . "=" . encode($row->{$_});
77                 }
78                 print join("&", @answer) . "\n";
79         }
80         $sth->finish();
81         $dbh->disconnect();
82 } elsif ($ENV{PATH_INFO} =~ m/update$/) {
83         # where clause in GET, update parameters in POST
84         my (%get, @get, $sql, $name, $value, $affected);
85         foreach (split '&', $ENV{QUERY_STRING}) {
86                 ($name, $value) = split '=';
87                 $name = decode($name);
88                 next if (!isname($name));
89                 $value = escape_value(decode($value));
90                 if ($name =~ m/ /) {
91                         push @get, "$name '$value'";
92                 } else {
93                         push @get, "$name='$value'";
94                 }
95                 $get{$name}++;
96         }
97         $sql = "SELECT " . join(",", cgi_to_where_clause($cgi, \%cfg, \%get)) . " FROM $table WHERE " . join(" AND ", @get);
98         $dbh = DBI->connect($cfg{dsn}, $cfg{dbuser}, $cfg{dbpass});
99         $affected = $dbh->do($sql);
100         $dbh->disconnect();
101         print "Content-type: text/html\n\n$affected\n";
102 } elsif ($ENV{PATH_INFO} =~ m/store$/) {
103         # All parameters as POST
104         my (@param, $sql, @fields, @values, $affected);
105         foreach my $param (cgi_to_where_clause($cgi, \%cfg)) {
106                 my ($name, $value) = split /=/, $param;
107                 push @fields, $name;
108                 push @values, $value;
109         }
110         $sql = "INSERT INTO $table (" . join(",", @fields) . ") VALUES (" . join(",", @values) . ")";
111         $dbh = DBI->connect($cfg{dsn}, $cfg{dbuser}, $cfg{dbpass});
112         $affected = $dbh->do($sql);
113         $dbh->disconnect();
114         print "Content-type: text/html\n\n$affected\n";
115 } elsif ($ENV{PATH_INFO} =~ m/destroy$/) {
116         # All parameters as POST
117         my ($sql, $affected);
118         $sql = "DELETE FROM $table WHERE " . join(" AND ", cgi_to_where_clause($cgi, \%cfg));
119         $dbh = DBI->connect($cfg{dsn}, $cfg{dbuser}, $cfg{dbpass});
120         $affected = $dbh->do($sql);
121         $dbh->disconnect();
122         print "Content-type: text/html\n\n$affected\n";
123 } elsif ($ENV{PATH_INFO} =~ m/static$/) {
124         # file parameter in GET, no POST
125         my (@get, $filename, $sql, $sth);
126         @get = split '&', $ENV{QUERY_STRING};
127         foreach (@get) {
128                 my ($name, $value) = split '=';
129                 if (decode($name) eq 'file') {
130                         $filename = decode($value);
131                         last;
132                 }
133         }
134         $sql = "SELECT cat_metric, category, var_name, var_val FROM $table WHERE filename=" . escape_value($filename) . " AND commented=0 ORDER BY cat_metric DESC, var_metric ASC, category, var_name";
135         $dbh = DBI->connect($cfg{dsn}, $cfg{dbuser}, $cfg{dbpass});
136         $sth = $dbh->prepare($sql) || throw_error("Invalid query: $sql");
137         $sth->execute() || throw_error("Invalid query: $sql");
138         print "Content-type: text/plain\n\n";
139         while (my $row = $sth->fetchrow_hashref()) {
140                 my @answer = ();
141                 foreach (keys %$row) {
142                         push @answer, encode($_) . "=" . encode($row->{$_});
143                 }
144                 print join("&", @answer) . "\n";
145         }
146         $sth->finish();
147         $dbh->disconnect();
148 } else {
149         print "Content-type: text/plain\n\nUnknown query\n";
150 }
151
152 sub encode {
153         my ($stuff) = @_;
154         $stuff =~ s/([^a-zA-Z0-9_\.])/uc sprintf("%%%02x",ord($1))/eg;
155         return $stuff;
156 }
157
158 sub decode {
159         my ($stuff) = @_;
160         $stuff =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
161         return $stuff;
162 }
163
164 sub isname {
165         my ($name) = @_;
166         if ($name =~ m#[^A-Za-z0-9_ ]#) {
167                 return 0;
168         } else {
169                 return 1;
170         }
171 }
172
173 sub escape_value {
174         my ($value, $cfg) = @_;
175         if ($cfg->{backslash_is_escape} =~ m/^(no|0|false)$/i) {
176                 $value =~ s#'#''#g;
177         } else {
178                 $value =~ s#(['\\])#$1$1#g;
179         }
180         return $value;
181 }
182
183 sub cgi_to_where_clause {
184         my ($cgi, $cfg, $get) = @_;
185         my @param = ();
186
187         foreach my $name ($cgi->param()) {
188                 my $value = escape_value($cgi->param($name), $cfg);
189
190                 # Ensure name isn't funny-like
191                 next if (!isname($name));
192                 next if ($get->{$name});
193
194                 if ($name =~ m# #) {
195                         push @param, "$name '$value'";
196                 } else {
197                         push @param, "$name='$value'";
198                 }
199         }
200         return join(" AND ", @param);
201 }
202
203 sub throw_error {
204         my ($msg) = @_;
205         print "Content-type: text/plain\n\n$msg\n";
206         print STDERR $msg . "\n";
207         exit;
208 }
209