/[drupal]/contributions/modules/search_files/search_files.module
ViewVC logotype

Contents of /contributions/modules/search_files/search_files.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.32 - (show annotations) (download) (as text)
Tue Jul 21 21:16:52 2009 UTC (4 months ago) by thl
Branch: MAIN
CVS Tags: HEAD
Changes since 1.31: +2 -1 lines
File MIME type: text/x-php
#514324 by Thomas Lotterer: import fix for "Undefined variable: output" from patch posted by Brenda Wallace
1 <?php
2 // $Id: search_files.module,v 1.31 2009/06/22 21:45:04 thl Exp $
3
4 /**
5 * @file
6 * Used to index all files in directory(s) on the server
7 */
8
9
10 /**
11 * Implementation of hook_menu()
12 *
13 * @return $items = array of menu items
14 */
15 function search_files_menu() {
16 $items['admin/settings/search_files'] = array(
17 'title' => t('Search Files'),
18 'description' => t('Manage files search'),
19 'page callback' => 'search_files_dashboard',
20 'access arguments' => array('administer search_files configuration'),
21 'type' => MENU_NORMAL_ITEM,
22 );
23 $items['admin/settings/search_files/dashboard'] = array(
24 'title' => t('Dashboard'),
25 'description' => t('Dashboard for Search Files Module'),
26 'page callback' => 'search_files_dashboard',
27 'access arguments' => array('administer search_files configuration'),
28 'type' => MENU_DEFAULT_LOCAL_TASK,
29 );
30 $items['admin/settings/search_files/settings'] = array(
31 'title' => t('Settings'),
32 'description' => t('Change settings for Search Files Module'),
33 'page callback' => 'drupal_get_form',
34 'page arguments' => array('search_files_settings'),
35 'access arguments' => array('administer search_files configuration'),
36 'type' => MENU_LOCAL_TASK,
37 );
38 $items['admin/settings/search_files/helpers'] = array(
39 'title' => t('Helpers'),
40 'description' => t('List Helper Apps for Search Files'),
41 'page callback' => 'search_files_helper_list',
42 'access arguments' => array('administer search_files configuration'),
43 'type' => MENU_LOCAL_TASK,
44 );
45 $items['admin/settings/search_files/helpers/list'] = array(
46 'title' => t('List'),
47 'description' => t('List Helper Apps for Search Files'),
48 'page callback' => 'search_files_helper_list',
49 'access arguments' => array('administer search_files configuration'),
50 'type' => MENU_DEFAULT_LOCAL_TASK,
51 );
52 $items['admin/settings/search_files/helpers/add'] = array(
53 'title' => t('Add'),
54 'description' => t('Add Helper Apps for Search Files'),
55 'page callback' => 'drupal_get_form',
56 'page arguments' => array('search_files_helper_add'),
57 'access arguments' => array('administer search_files configuration'),
58 'type' => MENU_LOCAL_TASK,
59 );
60 $items['admin/settings/search_files/directories'] = array(
61 'title' => t('Directories'),
62 'description' => t('list directories that will be searched'),
63 'page callback' => 'search_files_directories_list',
64 'access arguments' => array('administer search_files configuration'),
65 'type' => MENU_LOCAL_TASK,
66 );
67 $items['admin/settings/search_files/directories/list'] = array(
68 'title' => t('List'),
69 'description' => t('list directories that will be searched'),
70 'page callback' => 'search_files_directories_list',
71 'access arguments' => array('administer search_files configuration'),
72 'type' => MENU_DEFAULT_LOCAL_TASK,
73 );
74 $items['admin/settings/search_files/directories/add'] = array(
75 'title' => t('Add'),
76 'description' => t('Add a directory that will be searched'),
77 'page callback' => 'drupal_get_form',
78 'page arguments' => array('search_files_directories_add'),
79 'access arguments' => array('administer search_files configuration'),
80 'type' => MENU_LOCAL_TASK,
81 );
82 $items['admin/settings/search_files/directory/delete'] = array(
83 'title' => t('Delete Directory'),
84 'description' => t('Delete Searchable Driectory'),
85 'page callback' => 'search_files_directory_confirm_delete',
86 'access arguments' => array('administer search_files configuration'),
87 'type' => MENU_CALLBACK,
88 );
89 $items['admin/settings/search_files/directory/edit'] = array(
90 'title' => t('Edit Directory'),
91 'description' => t('Edit directory path'),
92 'page callback' => 'drupal_get_form',
93 'page arguments' => array('search_files_directory_edit'),
94 'access arguments' => array('administer search_files configuration'),
95 'type' => MENU_CALLBACK,
96 );
97 $items['admin/settings/search_files/helpers/edit'] = array(
98 'title' => t('Edit Helper'),
99 'description' => t('Edit a Helper App'),
100 'page callback' => 'drupal_get_form',
101 'page arguments' => array('search_files_helper_edit'),
102 'access arguments' => array('administer search_files configuration'),
103 'type' => MENU_CALLBACK,
104 );
105 $items['admin/settings/search_files/helpers/delete'] = array(
106 'title' => t('Delete Helper'),
107 'description' => t('Delete a Helper App'),
108 'page callback' => 'search_files_helper_confirm_delete',
109 'access arguments' => array('administer search_files configuration'),
110 'type' => MENU_CALLBACK,
111 );
112 $items['admin/settings/search_files/update_index'] = array(
113 'title' => t('Update the index'),
114 'description' => t('manually run hook_upate_index'),
115 'page callback' => 'search_files_update_index',
116 'access arguments' => array('administer search_files configuration'),
117 'type' => MENU_CALLBACK,
118 );
119 return $items;
120 }
121 /**
122 * get an array of helper programs
123 *
124 * @return $helpers = array($helper->extension => $helper->helper_path);
125 */
126 function search_files_get_helpers() {
127 // Get all the registered helper applications and put them in static variable to elimiate unnecessary db queries
128 // in search_files_nodeapi(). The query log feature of the dev module pointed out that this query was done
129 // many times instead of once. Making $helpers a static variable reduced the number of queries by 25%.
130 static $helpers = array();
131 $result = db_query('SELECT * FROM {search_files_helpers}');
132 while ($helper = db_fetch_object($result)) {
133 $helpers[$helper->extension] = $helper->helper_path;
134 }
135 return $helpers;
136 }
137 /**
138 * check to make sure the directory the user wants to delete is a
139 * valid directory id number, then call the function to generate
140 * the confirmation form
141 *
142 * @return $output = html of the form
143 */
144 function search_files_directory_confirm_delete() {
145 $directory_id = arg(5) ;
146 if ($directory_id > 0 && is_numeric($directory_id)) {
147 return drupal_get_form('search_files_directory_confirm_delete_form', $directory_id);
148 }
149 }
150 /**
151 * get the confirmation form to confirm deletion of a directory
152 * from the search_files_directories table
153 *
154 * @param (array) $form_state
155 * @param (int) $directory_id
156 * @return $output = html of the form
157 */
158 function search_files_directory_confirm_delete_form(&$form_state, $directory_id) {
159 $directory_path = db_result(db_query("SELECT directory FROM {search_files_directories} WHERE id = '%s'", $directory_id));
160 $form = array();
161 $form['search_files_directory_id'] = array(
162 '#type' => 'hidden',
163 '#value' => $directory_id
164 );
165 $form['search_files_directory_path'] = array(
166 '#type' => 'hidden',
167 '#value' => $directory_path,
168 );
169 return confirm_form($form,
170 t('Are you sure you want to delete the %directory directory? The text extracted from this directory be removed from the search index.', array('%directory' => $directory_path)),
171 'admin/settings/search_files/directories/list',
172 t('This action cannot be undone.'),
173 t('Delete'),
174 t('Cancel'));
175 }
176 /**
177 * deletes the directory from the search_files_directories table after
178 * confirmation from the user, also deletes the files from the
179 * search_files_files table and removes the data from the search_dataset
180 * table
181 *
182 * @param unknown_type $form_id
183 * @param unknown_type $form_values
184 */
185 function search_files_directory_confirm_delete_form_submit($form_id, $form_values) {
186 //drupal_set_message('form_values = <pre>'.print_r($form_values, true).'</pre>');
187 $directory_path = $form_values['values']['search_files_directory_path'];
188 search_files_delete_content_by_directory_fullpath($directory_path);
189 drupal_set_message(t('Directory %directory removed from search index', array('%directory' => $directory_path)));
190 drupal_goto('admin/settings/search_files/directories/list');
191 }
192
193 function search_files_delete_content_by_directory_fullpath($full_path) {
194 $sql = "DELETE s.*, f.*, d.*
195 FROM {search_dataset} AS s
196 INNER JOIN {search_files_files} AS f ON s.`sid` = f.`id`
197 INNER JOIN {search_files_directories} AS d ON f.`directory_id` = d.`id`
198 WHERE ( s.`type` = 'search_files'
199 AND d.`directory` = '%s'
200 )";
201 db_query($sql, $full_path);
202 }
203
204 function search_files_delete_content_by_file_fullpath($full_path) {
205 $sql = "DELETE s.*, f.*
206 FROM {search_dataset} AS s
207 INNER JOIN {search_files_files} AS f ON s.`sid` = f.`id`
208 WHERE ( s.`type` = 'search_files'
209 AND f.`full_path` = '%s'
210 )";
211 db_query($sql, $full_path);
212 }
213
214 /**
215 * Check whether we run in PHP safe_mode
216 */
217 function search_files_issafemode() {
218 return preg_match('/(1|on)/i', @ini_get("safe_mode"));
219 }
220
221 /**
222 * generates the directory edit form, it does this by grabbing the
223 * directory add form and populates the #default_value fields for
224 * the directory in question
225 *
226 * @return (array) $form
227 */
228 function search_files_directory_edit() {
229 $sql = "
230 SELECT
231 *
232 FROM
233 {search_files_directories}
234 WHERE
235 ID = '%s'
236 ";
237 $result = db_fetch_object(db_query($sql, arg(5)));
238 $form = array();
239
240 $form = search_files_directories_add();
241 $form['search_files_directory']['#default_value'] = $result->directory;
242 $form['search_files_id'] = array(
243 '#type' => 'value',
244 '#value' => $result->id,
245 );
246 return $form;
247 }
248
249 /**
250 * Updates the directory row in the serach_files_directories table from
251 * data given by the search_files_directory_edit form
252 *
253 * @param (array) $form_id
254 * @param (array) $form_values
255 */
256 function search_files_directory_edit_submit($form_id, $form_values) {
257 //drupal_set_message('form_values= <pre>'.print_r($form_values, true).'</pre>');
258 $sql = "
259 UPDATE
260 {search_files_directories}
261 SET
262 `directory`='%s'
263 WHERE
264 `id`='%s'
265 ";
266 $result = db_query($sql, $form_values['values']['search_files_directory'], $form_values['values']['search_files_id']);
267 if ($result) {
268 drupal_set_message(t('Directory %directory has been updated', array('%directory' => $form_values['values']['search_files_directory'])));
269 drupal_goto('admin/settings/search_files/directories/list');
270 }
271 }
272
273 /**
274 * gets a list of directories to inde from the search_files_directories
275 * table and themes the list in a table
276 *
277 * @return (string) $output = themed table of directories
278 */
279 function search_files_directories_list() {
280 $result = db_query('SELECT * FROM {search_files_directories}');
281 $directories[] = array();
282 $destination = drupal_get_destination();
283 while ($directory = db_fetch_object($result)) {
284 $directories[] = array( $directory->directory, l(t('Edit'), 'admin/settings/search_files/directory/edit/'. $directory->id), l(t('Delete'), 'admin/settings/search_files/directory/delete/'. $directory->id), array($destination));
285 }
286 $header = array( 'Directory', array('data' => t('Operations'), 'colspan' => '3'));
287 $output .= theme('table', $header, $directories);
288 return $output;
289 }
290
291 /**
292 * generates the form to add a directory to search_files_directories table
293 *
294 * @return (array) $form
295 */
296 function search_files_directories_add() {
297 $form = array();
298 $form['instructions']= array(
299 '#type' => 'markup',
300 '#value' => t('Make sure the directory is readable by the web server, i.e. apache.'),
301 );
302 $form['search_files_directory'] = array(
303 '#type' => 'textfield',
304 '#title' => t('Directory Path'),
305 '#size' => 80,
306 '#maxlength' => 150,
307 '#required' => FALSE,
308 '#description' => t('The path of the directory to search. Relative pathes are based on %directory.', array('%directory' => getcwd())),
309 );
310 $form['submit'] = array(
311 '#type' => 'submit',
312 '#value' => 'Submit',
313 );
314 return $form;
315 }
316
317 /**
318 * adds a row to the search_files directories table with the
319 * information provided by the search_files_directory_add_form
320 *
321 * @param unknown_type $form_id
322 * @param unknown_type $form_values
323 */
324 function search_files_directories_add_submit($form_id, $form_values) {
325 //drupal_set_message('$form_values = <pre>'.print_r($form_values, true).'</pre>');
326 $sql = "
327 INSERT INTO
328 {search_files_directories}
329 SET
330 `directory`='%s'
331 ";
332 $directory = $form_values['values']['search_files_directory'];
333 if (!preg_match('/^\//', $directory)) {
334 $directory = sprintf("%s/%s", getcwd(), $directory);
335 }
336 $directory = preg_replace('/\/+$/', '', $directory);
337 $result = db_query($sql, $directory, $form_values['values']['search_files_label']);
338 if ($result) {
339 drupal_set_message(t('Directory %directory has been added.', array('%directory' => $form_values['values']['search_files_directory'])));
340 drupal_goto('admin/settings/search_files/directories/list');
341 }
342 }
343
344 /**
345 * check to make sure the $helper_id is valid (a number greater
346 * than zero) then it fetches the deletion confirmation form,
347 * then returns it
348 *
349 * @return (array) $form
350 */
351 function search_files_helper_confirm_delete() {
352 $helper_id = arg(5) ;
353 if ($helper_id > 0 && is_numeric($helper_id)) {
354 return drupal_get_form('search_files_helper_confirm_delete_form', $helper_id);
355 }
356 }
357
358 /**
359 * generate the deletion confirmation form for helper apps and return the form
360 *
361 * @param unknown_type $form_state
362 * @param (int) $helper_id
363 * @return (array) $form
364 */
365 function search_files_helper_confirm_delete_form(&$form_state, $helper_id) {
366 $helper_name = db_result(db_query("SELECT name FROM {search_files_helpers} WHERE id = '%s'", $helper_id));
367 $form = array();
368 $form['search_files_helper_id'] = array(
369 '#type' => 'hidden',
370 '#value' => $helper_id
371 );
372 $form['search_files_helper_name'] = array(
373 '#type' => 'hidden',
374 '#value' => $helper_name,
375 );
376 return confirm_form($form,
377 t('Are you sure you want to delete the %name helper? The text extracted by this helper will remain in the search index until the directory is reindexed.', array('%name' => $helper_name)),
378 'admin/settings/search_files/helpers/list',
379 t('This action cannot be undone.'),
380 t('Delete'),
381 t('Cancel'));
382 }
383
384 /**
385 * remove row for the helper app from the search_files_helpers table
386 *
387 * @param unknown_type $form_id
388 * @param (array) $form_values
389 */
390 function search_files_helper_confirm_delete_form_submit($form_id, $form_values) {
391 //drupal_set_message('form_values = <pre>'.print_r($form_values, true).'</pre>');
392 $sql = "
393 DELETE FROM
394 {search_files_helpers}
395 WHERE
396 `id`='%s'
397 ";
398 $result = db_query($sql, $form_values['values']['search_files_helper_id']);
399 drupal_goto('admin/settings/search_files/helpers/list');
400 }
401 /**
402 * display a themes table of the current helper apps set up in the system
403 *
404 * @return (string) html table
405 */
406 function search_files_helper_list() {
407 $sql = "
408 SELECT
409 *
410 FROM
411 {search_files_helpers}
412 ORDER BY
413 `extension`
414 ";
415 $result = db_query($sql);
416 $helpers[] = array();
417 $destination = drupal_get_destination();
418 while ($helper = db_fetch_object($result)) {
419 $helpers[] = array($helper->name, $helper->extension, l(t('Edit'), 'admin/settings/search_files/helpers/edit/'. $helper->id), l(t('Delete'), 'admin/settings/search_files/helpers/delete/'. $helper->id), array($destination));
420 }
421 $header = array(t('Helper name'), t('Extension'), array('data' => t('Operations'), 'colspan' => '3'));
422 $output .= theme('table', $header, $helpers);
423 return $output;
424 }
425
426 /**
427 * Implementation of hook_perm()
428 *
429 * @return (array) permissions
430 */
431 function search_files_perm() {
432 return array('administer search_files configuration', 'view search_files results');
433 }
434
435 /**
436 * generate form to add a helper app to the system
437 *
438 * @return (array) $form
439 */
440 function search_files_helper_add() {
441 $form['instructions'] = array('#type' => 'markup', '#value' => $instruction_text);
442 $form['search_files_name'] = array(
443 '#type' => 'textfield',
444 '#title' => t('Helper name'),
445 '#size' => 50,
446 '#maxlength' => 50,
447 '#required' => TRUE,
448 '#description' => t('A name for this helper configuration.'),
449 );
450 $form['search_files_extension'] = array(
451 '#type' => 'textfield',
452 '#title' => t('Extension'),
453 '#size' => 10,
454 '#maxlength' => 10,
455 '#required' => TRUE,
456 '#description' => t('Enter the extension for the files that you want the helper application to process. Do not include the period.'),
457 );
458 $form['search_files_helper_path'] = array(
459 '#type' => 'textfield',
460 '#title' => t('Helper path'),
461 '#size' => 100,
462 '#maxlength' => 100,
463 '#default_value' => '/path/to/helper/command %file%',
464 '#validate' => array('search_files_helpers_validate_add_edit' => array()),
465 '#required' => TRUE,
466 '#description' => t('Enter the path to the helper application installed on your server. "%file%" is a placeholder for the path of the attachment file and is required. Include any command-line parameters as well (for example, pdftotext requires a - after the file to be processed).'),
467 );
468 $form['submit_done'] = array(
469 '#type' => 'submit',
470 '#value' => 'Save and Done',
471 );
472 $form['submit'] = array(
473 '#type' => 'submit',
474 '#value' => 'Save add another',
475 );
476 return $form;
477 }
478
479 /**
480 * validate the existance of the helper app supplied by the
481 * helper_add or helper_edit form
482 *
483 * @param unknown_type $field
484 */
485 function search_files_helpers_validate_add_edit($field) {
486 if (!preg_match('/%file%/', $field['#value'])) {
487 form_set_error($field['#title'], t('"%field" must contain the token %file%', array('%field' => $field['#title'])));
488 }
489
490 // Check to see if helper app can be found
491 $helper_file = preg_replace('/\s.+$/', '', $field['#value']);
492 if (!file_exists($helper_file)) {
493 form_set_error($field['#title'], t("Can't find helper app %helper -- please verify it is installed.", array('%helper' => $helper_file)));
494 }
495 }
496
497 /**
498 * fetch the helper add form, alter the form for use as an edit form,
499 * populate the #default_values fields and return the form
500 *
501 * @return unknown
502 */
503 function search_files_helper_edit() {
504 $sql = "
505 SELECT
506 *
507 FROM
508 {search_files_helpers}
509 WHERE
510 ID = '%s'
511 ";
512 $result = db_fetch_object(db_query($sql, arg(5)));
513 $form = search_files_helper_add();
514 $form['search_file_id'] = array(
515 '#type' => 'value',
516 '#value' => $result->id,
517 );
518 $form['search_files_helper_path']['#value'] = $result->helper_path;
519 $form['search_files_extension']['#value'] = $result->extension;
520 $form['search_files_name']['#value']= $result->name;
521 unset($form['submit_done']);
522 $form['submit']['#value'] = 'Update';
523
524
525 return $form;
526 }
527
528 /**
529 * update the row in the table search_files_helpers for the given helper app
530 *
531 * @param unknown_type $form_id
532 * @param unknown_type $form_values
533 */
534 function search_files_helper_edit_submit($form_id, $form_values) {
535 //drupal_set_message('form_values = <pre>'.print_r($form_values, true).'</pre>');
536 $sql = "
537 UPDATE
538 {search_files_helpers}
539 SET
540 `name`='%s',
541 `extension`='%s',
542 `helper_path`='%s'
543 WHERE
544 `id`='%s'
545 ";
546 $result = db_query($sql, $form_values['clicked_button']['#post']['search_files_name'], $form_values['clicked_button']['#post']['search_files_extension'], $form_values['clicked_button']['#post']['search_files_helper_path'], $form_values['values']['search_file_id']);
547 if ($result) {
548 drupal_set_message(t('Helper app %helper_name has been updated', array('%helper_name' => $form_values['values']['search_files_name'])));
549 drupal_goto('admin/settings/search_files/helpers/list');
550 }
551 }
552
553 /**
554 * insert a row in the search_files_helpers table for the helper
555 * app given by the form
556 *
557 * @param unknown_type $form_id
558 * @param unknown_type $form_values
559 */
560 function search_files_helper_add_submit($form_id, $form_values) {
561 //drupal_set_message('form_values = <pre>'.print_r($form_values, true).'</pre>');
562 $sql = "
563 INSERT INTO
564 {search_files_helpers}
565 SET
566 `name`='%s',
567 `extension`='%s',
568 `helper_path`='%s'
569 ";
570 $result = db_query($sql, $form_values['values']['search_files_name'], $form_values['values']['search_files_extension'], $form_values['values']['search_files_helper_path']);
571 if ($result) {
572 drupal_set_message(t('%helper helper added', array('%helper' => $form_values['values']['search_files_name'])));
573 }
574 if ($form_values['clicked_button']['#id'] == 'edit-submit-done') {
575 drupal_goto('admin/settings/search_files/helpers/list');
576 }
577 }
578
579 /**
580 * generate the dashboard page
581 */
582 function search_files_dashboard() {
583 $output = '';
584 $lastindex = variable_get('search_files_last_index', '0');
585 $output .= sprintf("%s = %s UTC<br>\n", t('Last Index'),
586 format_date($lastindex, $type = 'custom', $format = 'Y-m-d H:i:s', $timezone = NULL, $langcode = NULL));
587
588 $directoryrescanage = variable_get('search_files_directoryrescanage', 'unset');
589 $output .= sprintf("%s = %s [sec]<br>\n", t('Directory Rescan Age'), $directoryrescanage);
590
591 $nextdirectoryrescan = $lastindex + $directoryrescanage;
592 $output .= sprintf("%s = %s UTC<br>\n", t('Next Directory (Re-)Scan at or after'),
593 format_date($nextdirectoryrescan, $type = 'custom', $format = 'Y-m-d H:i:s', $timezone = NULL, $langcode = NULL));
594
595 $sql = "SELECT count(*) FROM {search_files_directories};";
596 $result = db_query($sql);
597 $result = db_result($result);
598 $output .= sprintf("Number of Directories configured = %s<br>\n", $result);
599
600 $sql = "SELECT count(*) FROM {search_files_files};";
601 $result = db_query($sql);
602 $result = db_result($result);
603 $output .= sprintf("Files found in configured Directories and Subdirectories = %s<br>\n", $result);
604
605 $sql = "SELECT count(*) FROM {search_files_files} WHERE ( `index_attempts` = 0 );";
606 $result = db_query($sql);
607 $result = db_result($result);
608 $output .= sprintf("Files without index attempt = %s<br>\n", $result);
609
610 $sql = "SELECT count(*) from {search_dataset} WHERE ( `type` = 'search_files' );";
611 $result = db_query($sql);
612 $result = db_result($result);
613 $output .= sprintf("Files indexed = %s<br>\n", $result);
614
615 $sql = "SELECT count(*) from {search_dataset} WHERE ( `type` = 'search_files' AND `reindex` > 0 );";
616 $result = db_query($sql);
617 $result = db_result($result);
618 $output .= sprintf("Files indexed and scheduled for reindexing = %s<br>\n", $result);
619
620 $sql = "SELECT count(*) FROM {search_files_helpers};";
621 $result = db_query($sql);
622 $result = db_result($result);
623 $output .= sprintf("Number of Helpers configured = %s<br>\n", $result);
624
625 // safe_mode will inhibit shell_exec()
626 if (search_files_issafemode()) {
627 $output .= t('WARNING! This server has safe_mode enabled, which inhibits use of helper applications');
628 }
629 else {
630 $output .= t('Good. This server has safe_mode disabled, which allows use of helper applications');
631 }
632
633 return $output;
634 }
635
636 /**
637 * generate the settings form for the search_files module using the
638 * system_settings_form() function
639 *
640 * @return unknown
641 */
642 function search_files_settings() {
643 $form = array();
644 $form['search_files_label'] = array(
645 '#title' => 'Search Label',
646 '#type' => 'textfield',
647 '#description' => 'What do you want the Search tab to be labeled?',
648 '#default_value' => variable_get('search_files_label', 'Server Files'),
649 );
650 $form['search_files_directoryrescanage'] = array(
651 '#title' => t('Directory Rescan Age'),
652 '#type' => 'textfield',
653 '#description' => 'Minimum time to wait before directories are (re)scanned for new files.',
654 '#default_value' => search_files_variable_get_directoryrescanage(),
655 '#field_suffix' => t('[sec]'),
656 );
657 return system_settings_form($form);
658 }
659
660 /*
661 * Handle configuration setting and provide global default
662 */
663 function search_files_variable_get_directoryrescanage()
664 {
665 return variable_get('search_files_directoryrescanage', '86400');
666 }
667
668 /**
669 * Implementation of hook_update_index()
670 *
671 * lists all the files in the director(y/ies) and puts the files
672 * into the "search_files_files" table
673 *
674 * then indexes X(configurable) number of these files
675 */
676 function search_files_update_index() {
677 $helpers = search_files_get_helpers();
678 // only update the list of files in the directories once per day
679 if (variable_get('search_files_last_index', 0) < (time() - search_files_variable_get_directoryrescanage())) {
680 variable_set('search_files_last_index', time());
681
682 // hunt configured directories for new files and add them to the database
683 $result = db_query('SELECT * FROM {search_files_directories}');
684 while ($directory = db_fetch_object($result)) {
685 search_files_list_directory($directory->directory, $directory->id);
686 }
687
688 // compare database to filesystem and remove vanished files from database
689 $vanished = 0;
690 $result = db_query('SELECT full_path FROM {search_files_files}');
691 while ($file = db_fetch_object($result)) {
692 $full_path = $file->full_path;
693 if(!file_exists($full_path)) {
694 $vanished++;
695 search_files_delete_content_by_file_fullpath($full_path);
696 }
697 }
698 if ($vanished > 0) {
699 watchdog('Search Files', t('removed %vanished vanished files from index', array('%vanished' => $vanished)), array(), WATCHDOG_NOTICE);
700 }
701 }
702
703 // premature end, safe_mode will inhibit shell_exec()
704 if (search_files_issafemode()) {
705 return;
706 }
707
708 $index_number = (int)variable_get('search_cron_limit', 100);
709 $sql = "
710 SELECT
711 *
712 FROM
713 {search_files_files}
714 LEFT JOIN
715 (
716 SELECT
717 *
718 FROM
719 {search_dataset}
720 WHERE
721 `type` = 'search_files'
722 ) AS `dataset` ON {search_files_files}.`id` = `dataset`.`sid`
723 WHERE
724 (
725 `dataset`.`reindex` IS NULL OR
726 `dataset`.`reindex` != 0
727 ) AND {search_files_files}.`index_attempts` <= 5
728 LIMIT %s
729 ";
730
731 $result = db_query($sql, $index_number);
732
733 while ($file = db_fetch_object($result)) {
734 $full_path = $file->full_path;
735 $file_name = explode('/', $full_path);
736 $file_name = $file_name[count($file_name)-1];
737 $file_extension = explode('.', $file_name);
738 $file_extension = $file_extension[count($file_extension)-1];
739
740 if (in_array($file_extension, array_keys($helpers))) {
741 // record that we are attempting to index the file in case it hangs
742 $increment_sql = "
743 UPDATE
744 {search_files_files}
745 SET
746 `index_attempts` = `index_attempts` + 1
747 WHERE
748 `id` = '%s'
749 ";
750 $increment_result = db_query($increment_sql, $file->id);
751 if ($file->index_attempts >= 5) {
752 // indexind failed too many times, record this to the log and continue
753 watchdog('Search Files', t('failed to index %full_path after %attempts attempts', array('%full_path' => $file->full_path, '%attempts' => $file->index_attempts)), array(), WATCHDOG_ERROR);
754 continue;
755 }
756
757 // skip over files which vanished before being indexed - cleanup is left to search_files_update_index()
758 if(!file_exists($full_path)) {
759 continue;
760 }
761
762 // %file% is a token that is placed in the helper's parameter list to represent the file path to the attachment.
763 // We need to put the filename in quotes in case it contains spaces.
764 $quoted_file_path = '"'. escapeshellcmd($full_path) .'"';
765 $helper_command = preg_replace('/%file%/', $quoted_file_path, $helpers[$file_extension]);
766
767 $file_text = shell_exec($helper_command);
768 $file_text = search_files_convert_to_utf8($file_text);
769 search_index($file->id, 'search_files', 'file name: '. $quoted_file_path .', text: '. $file_text);
770 }
771 else{
772 search_index($file->id, 'search_files', '');
773 }
774 }
775 }
776
777 /**
778 * Get the host system's character encoding and convert text from it to UTF-8,
779 * Drupal's default HTTP and database character encoding.
780 */
781 function search_files_convert_to_utf8($text) {
782 $encoding = iconv_get_encoding("output_encoding");
783 $text = drupal_convert_to_utf8($text, $encoding);
784 return $text;
785 }
786
787 /**
788 * search_files_list_directory($directory, $id) will be called recursively
789 * to traverse the directory tree and list all the files in the given
790 * directory, it will take the files it find and put them into the
791 * search_files_files table
792 *
793 * @param (string) $directory
794 * @param (int) $id
795 */
796 function search_files_list_directory($directory, $id) {
797 if (!is_dir($directory)) {
798 return;
799 }
800 watchdog('Search Files', 'Starting to list files in %directory', array('%directory' => $directory));
801 $file_count = 0;
802 $dir_count = 0;
803 if ($dir = opendir($directory)) {
804 while ($file = readdir($dir)) {
805 $type = filetype($directory .'/'. $file);
806
807 $full_path = escapeshellcmd(search_files_convert_to_utf8($directory .'/'. $file));
808 if ($type == 'dir') {
809
810 // make sure we don't retreverse the current or parent directory
811 if (($file != '.') && ($file != '..')) {
812 $dir_count++;
813 search_files_list_directory($directory .'/'. $file, $id);
814 }
815 }
816 else if ($type == 'file') {
817 // Check to see if the file is already in the table,
818 $sql = "
819 SELECT
820 `id`
821 FROM
822 {search_files_files}
823 WHERE
824 `full_path`='%s'
825 ";
826 $result = db_result(db_query($sql, $full_path));
827 // If the file is not in the table, insert it
828 if (!$result) {
829 $file_count++;
830 $insert_sql = "
831 INSERT INTO
832 {search_files_files}
833 SET
834 `full_path`=\"%s\",
835 `directory_id`='%s'
836 ";
837 // MySQL keeps throwing errors because of some file names that it doesn't like, this needs fixed
838 $insert_result = db_query($insert_sql, $full_path, $id);
839 }
840 }
841 }
842 }
843 watchdog('Search Files', 'Finished Listing files in %directory, found %file_count new file(s)', array('%directory' => $directory, '%file_count' => $file_count));
844 }
845
846 /**
847 * implementation of hook_search()
848 *
849 * @param (string) $op
850 * @param (string) $keywords
851 * @return (mixed)
852 */
853 function search_files_search($op = 'search', $keywords = null) {
854 switch ($op) {
855 case 'name':
856 return variable_get('search_files_label', 'Server Files');
857 case 'reset':
858 $sql="
859 UPDATE
860 {search_dataset}
861 SET
862 `reindex`='%s'
863 WHERE
864 `type`='search_files'
865 ";
866 $result = db_query($sql, time());
867 $sql = "UPDATE {search_files_files} SET `index_attempts`='0' WHERE 1";
868 db_query($sql);
869 break;
870 case 'status':
871 $return = array();
872 $sql = "SELECT COUNT(*) as `count` FROM {search_files_files}";
873 $return['total'] = db_result(db_query($sql));
874 $sql = "
875 SELECT
876 COUNT(*) AS `count`
877 FROM
878 {search_files_files}
879 LEFT JOIN
880 (
881 SELECT
882 *
883 FROM
884 {search_dataset}
885 WHERE
886 `type` = 'search_files'
887 ) AS `dataset` ON {search_files_files}.`id` = `dataset`.`sid`
888 WHERE
889 (
890 `dataset`.`reindex` IS NULL OR
891 `dataset`.`reindex` != 0
892 )
893 ";
894 $return['remaining'] = db_result(db_query($sql));
895 return $return;
896 break;
897 case 'search':
898 //drupal_set_message('$keywords = '.$keywords);
899 if (!user_access('view search_files results')) {
900 return null;
901 }
902 $doc_root = $_SERVER['DOCUMENT_ROOT'];
903 //drupal_set_message($doc_root);
904 $file_extensions = search_files_get_file_extensions();
905 $results = array();
906 $find = do_search($keywords, 'search_files');
907 //drupal_set_message('find = <pre>'.var_export($find, true).'</pre>');
908 date_default_timezone_set('GMT');
909 foreach ($find as $item) {
910 //drupal_set_message('item = <pre>'. var_export($item, true).'</pre>');
911 $sql = "
912 SELECT
913 *
914 FROM
915 {search_files_files}
916 WHERE
917 `id`='%s'
918 ";
919 $result = db_fetch_object(db_query($sql, $item->sid));
920 $search_results = db_query("SELECT * FROM {search_dataset} s WHERE sid = %d AND type = '%s'", $item->sid, 'search_files');
921 if ($dataset = db_fetch_object($search_results)) {
922 //drupal_set_message('result = <pre>'.print_r($result, true).'</pre>');
923 $file_name = explode('/', $result->full_path);
924 $file_name = $file_name[count($file_name)-1];
925 $file_extension = explode('.', $file_name);
926 $file_extension = $file_extension[count($file_extension)-1];
927 $link = str_replace($doc_root, '', $result->full_path);
928 // we have had a problem where some links were returned relative to the search page,
929 // not the document root, basically there was no beginning forward slash '/' in the
930 // path
931 if (strpos($link, '/') !== 0) {
932 $link = '/'. $link;
933 }
934 // skip over files which vanished after being indexed - cleanup is left to search_files_update_index()
935 if(file_exists($result->full_path)) {
936 $results[] = array(
937 'link' => $link,
938 'date' => filectime($result->full_path),
939 'type' => $file_extensions[$file_extension] .' file',
940 'title' => $file_name .' ('. format_size(filesize($result->full_path)) .')',
941 'snippet' => search_excerpt($keywords, $dataset->data),
942 );
943 }
944 }
945 date_default_timezone_set('MST');
946 }
947 //drupal_set_message('results = <pre>'.var_export($results, true).'</pre>');
948 return $results;
949 break;
950 }
951 }
952
953 /**
954 * generate the results page
955 *
956 * @param (array) $results
957 * @param (string) $type
958 * @return (string) $output
959 */
960 function search_files_search_page($results, $type = 'search_files') {
961
962 $output = '<dl class="search-results">';
963 foreach ($results as $entry) {
964 $output .= search_files_search_item_format($entry, $type);
965 }
966 $output .= '</dl>';
967 $output .= theme('pager', NULL, 20, 0);
968 return $output;
969 }
970
971 /**
972 * format the result items before that are displayed
973 *
974 * @param (array) $item
975 * @param (string) $type
976 * @return (string) $output formatted string
977 */
978 function search_files_search_item_format($item, $type) {
979 //drupal_set_message('entry = <pre>'.var_export($item, true).'</pre>');
980 $output = ' <dt class="title"><a href="'. check_url($item['link']) .'">'. check_plain($item['title']) .'</a></dt>';
981 $info = array();
982 if ($item['type']) {
983 $info[] = check_plain($item['type']);
984 }
985 if ($item['user']) {
986 // Add this here so the user name appears at the end of the output
987 $item['extra'][] = $item['user'];
988 }
989 if ($item['date']) {
990 $info[] = format_date($item['date'], 'small');
991 }
992 if (is_array($item['extra'])) {
993 $info = array_merge($info, $item['extra']);
994 }
995 $output .= ' <dd>'. ($item['snippet'] ? '<p>'. $item['snippet'] .'</p>' : '') .'<p class="search-info">'. implode(' - ', $info) .'</p></dd>';
996
997 return $output;
998 }
999
1000 /**
1001 * returns an array of the file extensions with the extension as
1002 * the key and the name of the file type as the value, this data
1003 * is retrieved from the search_files_helpers table
1004 *
1005 * @return (array)
1006 */
1007 function search_files_get_file_extensions() {
1008 $extensions = array();
1009 $result = db_query('SELECT extension, name FROM {search_files_helpers}');
1010 while ($helper = db_fetch_object($result)) {
1011 $extensions[$helper->extension] = $helper->name;
1012 }
1013 return $extensions;
1014 }

  ViewVC Help
Powered by ViewVC 1.1.2