I managed to create PHP script that searches for file or folder. It is written
for MySQL database and tested on Bacula 3 with Firefox browser. It supports
case insensitive search for file or folder, with or without regular expressions
and possibility to specify date range. Don't set too high number for "Results
per page". I have about 20 milions filenames in database and search tool works
fast enough for not too complex search.
To use the sript create folder somewhere in your apache folder (there must be
access to bacula database from this server), and create empty files config.php,
index.php, script.js, search.php and style.css.
Here is the code:
-------------------
config.php (don't forget to set the values for your environment)
<?php
//Database data
$DB_HOST = "localhost";
$DB_NAME = "baculdatabasename";
$DB_USER = "baculamysqluser";
$DB_PASS = "baculamysqlpass";
$DB_SET_NAMES = "UTF8";
//Character encoding for WEB page
$WEB_CHARSET = "UTF-8";
//Maximum number of seconds for script execution
$TIME_LIMIT_SECONDS = 300;
?>
-------------------
index.php
<?php
include(dirname(__FILE__)."/config.php");
$today = date("Y-m-d");
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Bacula search tool</title>
<meta http-equiv="Content-Type" content="text/html; charset=<?php
echo $WEB_CHARSET; ?>" />
<link href="style.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="./script.js"></script>
</head>
<body>
<h1>Bacula search tool</h1>
<form method="get" action="<?php echo basename(
__FILE__); ?>">
<table cellspacing="0" cellpadding="5"
id="searchformtable">
<tr>
<td>Type of
search:</td>
<td>
<input
type="radio" name="searchobject" value="folder" checked />Search for folder<br
/>
<input
type="radio" name="searchobject" value="file" />Search for file
</td>
</tr>
<tr>
<td>Search for:</td>
<td>
<input
type="text" name="searchstr" id="searchstr" size="30" maxlength="255" value=""
/>
<input
type="checkbox" id="regexp" /> Regular expression
</td>
</tr>
<tr>
<td>Date range</td>
<td>
<input
type="checkbox" id="daterange" />Only search for files that were created
between selected dates:<br />
<table>
<tr><td>Start date:</td><td><input type="text" name="startdate"
id="startdate" size="10" maxlength="10" value="<?php echo $today; ?>" />
(e.g. 2010-05-28)</td></tr>
<tr><td>End date:</td><td><input type="text" name="enddate"
id="enddate" size="10" maxlength="10" value="<?php echo $today; ?>" /></td></tr>
</table>
</td>
</tr>
<tr><td valign="top">Results per
page:</td><td><input type="text" name="limit" id="limit" value="20"
size="5" maxlength="5" /></td></tr>
<tr><td> </td><td><input
type="button" value="Search" onclick="javascript:
get_search_results('<?php echo $WEB_CHARSET; ?>', 0);" /></td></tr>
</table>
</form>
<br />
<!-- Here comes previous and next button -->
<div id="prev_next"></div>
<!-- Here comes search results -->
<div id="search_results"></div>
</body>
</html>
-------------------
script.js
/**
* Use AJAX to get data
*/
function get_search_results(charset, limitstart) {
//Div for results
var res_div = document.getElementById("search_results");
//Are we looking for folder or for a file
if
(document.getElementsByName("searchobject")[0].checked)
{
var so = "folder";
} else {
var so = "file";
}
//Get number of pages per page
var limit =
parseInt(document.getElementById("limit").value);
//Get search string
var search_str =
document.getElementById("searchstr").value;
//Is search string regular expression
if (document.getElementById("regexp").checked)
{
var is_regexp = "1";
} else {
var is_regexp = "0";
}
//Search between two dates
if (document.getElementById("daterange").checked)
{
var start_date =
document.getElementById("startdate").value;
var end_date =
document.getElementById("enddate").value;
var use_dates = true;
} else {
var use_dates = false;
}
//Build POST parameters
var params = "searchstr=" + escape(search_str) +
"&searchobject=" + so + "&start=" + limitstart + "&limit=" + limit;
params += "&isregexp=" + is_regexp;
if (use_dates) {
params += "&startdate=" +
escape(start_date) + "&enddate=" + escape(end_date);
}
res_div.innerHTML = "Loading ... (Please be patient)";
//Create AJAX object
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else {
xmlhttp = new
ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status
== 200) {
//Display search results
res_div.innerHTML =
xmlhttp.responseText;
//Get number of results
var result_rows =
document.getElementById('resulttable').getElementsByTagName("TR").length
- 1;
//Display previous and next button
display_prev_next_btn(charset,
limitstart, limit, result_rows);
}
}
xmlhttp.open("POST", "search.php", true);
xmlhttp.setRequestHeader("Content-type",
"application/x-www-form-urlencoded; Charset= " + charset)
xmlhttp.send(params);
}
/**
* Display previous and next button
*/
function display_prev_next_btn(charset, limitstart, limit, result_rows)
{
//Div for buttons
var pn_div = document.getElementById("prev_next");
//Display buttons
pn_div.innerHTML = '';
if (limitstart >= 1) { //Previous page
var prev_limitstart = limitstart - limit;
pn_div.innerHTML += '<input type="button"
value="<" onclick="get_search_results(' + "'" + charset + "'" + ', ' +
prev_limitstart + ',' + limit + ')" />';
}
pn_div.innerHTML += ' ';
pn_div.innerHTML += 'Page ' + ((limitstart / limit) +
1);
pn_div.innerHTML += ' ';
if (result_rows == limit) { //Next page
var next_limitstart = limitstart + limit;
pn_div.innerHTML += '<input type="button"
value=">" onclick="get_search_results(' + "'" + charset + "'" + ', ' +
next_limitstart + ',' + limit + ')" />';
}
}
-------------------
search.php
<?php
include(dirname(__FILE__)."/config.php");
//Set higher time limit than normal
set_time_limit($TIME_LIMIT_SECONDS);
if (isset($_POST["searchstr"]) &&
$_POST["searchstr"] != "") {
$searchstr = $_POST["searchstr"];
if
(isset($_POST["searchobject"])) { //Search for
path or search for file must be set
//Get start for limit
if
(isset($_POST["start"]) &&
is_numeric($_POST["start"])) {
$start =
$_POST["start"];
} else {
$start = 0;
}
//Get limit
if
(isset($_POST["limit"]) &&
is_numeric($_POST["limit"])) {
$limit =
$_POST["limit"];
} else {
$limit = 20;
}
//Connect to mysql database
$c = @mysql_connect($DB_HOST,
$DB_USER, $DB_PASS) or die ("<br />Error: <b>Cannot connect to
database</b>: ".mysql_error()."");
@mysql_select_db ($DB_NAME,
$c) or die("<br />Error: ".mysql_error());
@mysql_query("SET NAMES
{$DB_SET_NAMES}");
//Use date range?
if
(isset($_POST["startdate"]) &&
isset($_POST["enddate"])) {
$startdate =
$_POST["startdate"];
$enddate =
$_POST["enddate"];
$date_qubquery = " AND
J.StartTime >= '{$startdate} 00:00:00' AND J.EndTime <=
'{$enddate} 23:59:59'";
}
//Escape search string
$searchstr_esc =
mysql_real_escape_string($searchstr, $c);
//If the search string is regular
expression, use "REXEXP" instead "LIKE"
if
(isset($_POST["isregexp"]) &&
($_POST["isregexp"] == "1")) {
$comparison = "REGEXP
'{$searchstr_esc}'";
} else { //not regular
expression
$comparison = "LIKE
'%{$searchstr_esc}%'";
}
//Build SQL statement
if
($_POST["searchobject"] == "file") {
//SELECT By Filename
$query_string = "
SELECT
DISTINCT CONCAT(P.Path, FN.Name), F.JobId AS JID, J.Name, J.StartTime,
J.EndTime
FROM
Filename FN, File F, Path P, Job J
WHERE
FN.FilenameId=F.FilenameId AND F.PathId=P.PathId{$date_qubquery}
AND J.JobId=F.JobId AND CONVERT(FN.Name USING
{$DB_SET_NAMES}) {$comparison}
LIMIT {$start},{$limit}";
} else {
//Select By Folder name
$query_string = "
SELECT
DISTINCT P.Path, F.JobId AS JID, J.Name, J.StartTime, J.EndTime
FROM Path
P, File F, Job J
WHERE
P.PathId=F.PathId AND J.JobId=F.JobId{$date_qubquery}
AND CONVERT(P.Path USING {$DB_SET_NAMES})
{$comparison}
LIMIT
{$start},{$limit}";
}
//Execute query
$result =
@mysql_query($query_string, $c) or die("<br />SQL Error:
".mysql_error()."<br />QUERY: ".$query);
//Display search results
if
(mysql_num_rows($result) > 0) {
$DATA_ARR =
array(); //Temporary array of data
$JOB_IDS =
array(); //Array of job IDs for current limit
while ($row =
mysql_fetch_array($result)) {
array_push($DATA_ARR, $row);
if
(is_numeric($row["JID"]) &&
!in_array($row["JID"], $JOB_IDS)) {
array_push($JOB_IDS, $row["JID"]);
}
}
//Get volume names for
media used by job ids
$query = "Select
DISTINCT JM.JobId, M.VolumeName FROM JobMedia JM LEFT JOIN Media M ON
M.MediaId=JM.MediaId WHERE JM.JobId IN (".implode(",",
$JOB_IDS).")";
$r2 =
@mysql_query($query, $c) or die("<br />SQL Error:
".mysql_error()."<br />QUERY: ".$query);
$JOBMEDIA =
array();
while
(list($jobid, $volname) = mysql_fetch_array($r2)) {
$JOBMEDIA[$jobid] = $volname;
}
//Display table of data
echo "\n\t<table
cellspacing=\"0\" cellpadding=\"2\" id=\"resulttable\" width=\"100%\">";
echo "\n\t\t<tr
class=\"thead\"><td>Path</td><td>JobID</td><td>Job name</td><td>Job
time</td><td>Media</td></tr>";
foreach ($DATA_ARR
as $row) {
list($path, $jobid, $jobname, $jobstart, $jobend) = $row;
//Mark
folder/file in green color
$path =
preg_replace("/({$searchstr})/iU", "<font
style=\"color: #090;\">\\1</font>", $path);
//Get
media name
if
(isset($JOBMEDIA[$jobid])) {
$medianame = $JOBMEDIA[$jobid];
}
else {
$medianame = "???";
}
//Display
result row
echo
"\n\t\t<tr
class=\"datarow\"><td>{$path}</td><td><b>{$jobid}</b></td><td>{$jobname}</td><td>{$jobstart}<br
/>{$jobend}</td><td>{$medianame}</td></tr>";
}
echo "\n\t</table>";
echo "<br
/><b>Displaying results {$start} - ".($start + $limit)."</b>";
} else {
echo "<br />No records
has been found!";
}
//Close connection to mysql
@mysql_close($c);
} else {
echo "<br /><b>Please select
"Search file" or "Search folder".</b>";
}
} else {
echo "Search string has not been submitted!";
}
?>
-------------------
style.css
body {
background-color: #ddf;
font-family: Verdana, Helvetica, Tahoma, Arial;
font-size: 10px;
color: #000;
}
input {
border: solid 1px #aaa;
background-color: #feb;
margin-left: 0px;
}
input[type="button"] {
border: solid 2px #aaa;
border-right: solid 2px #777;
border-bottom: solid 2px #777;
background-color: #eee;
}
#searchformtable {
background-color: #ddd;
border: 1px solid #000;
}
#searchformtable td {
vertical-align: top;
}
#resulttable {
border: 1px solid #000;
}
.thead {
background-color: #ffbb1d;
font-weight: bold;
}
.datarow {
background-color: #eee;
}
.datarow td {
border-top: 1px solid #000;
vertical-align: top;
}
[/code]
+----------------------------------------------------------------------
|This was sent by lado.langof AT gmail DOT com via Backup Central.
|Forward SPAM to abuse AT backupcentral DOT com.
+----------------------------------------------------------------------
------------------------------------------------------------------------------
Nokia and AT&T present the 2010 Calling All Innovators-North America contest
Create new apps & games for the Nokia N8 for consumers in U.S. and Canada
$10 million total in prizes - $4M cash, 500 devices, nearly $6M in marketing
Develop with Nokia Qt SDK, Web Runtime, or Java and Publish to Ovi Store
http://p.sf.net/sfu/nokia-dev2dev
_______________________________________________
Bacula-users mailing list
Bacula-users AT lists.sourceforge DOT net
https://lists.sourceforge.net/lists/listinfo/bacula-users
|