Project

General

Profile

Revision 236

- added date range filtering to file search
- simplified search function

View differences:

branches/extplorer2/CHANGELOG.txt
2 2
Changelog for eXtplorer
3 3
Version $Id$
4 4
****************************
5
--- version 2.1.6 ---
6
- added date range filtering to file search
7
- simplified search function
8
- fixed scrambled non-ASCII file names on UTF-8 systems
9

  
5 10
--- version 2.1.5 ---
6 11
- fixed doubled subdirectories in directory tree
7 12
- fixed wrong Joomla path detection (security issue on some systems)
branches/extplorer2/include/search.php
4 4
/**
5 5
 * @version $Id$
6 6
 * @package eXtplorer
7
 * @copyright soeren 2007-2013
7
 * @copyright soeren 2007-2014
8 8
 * @author The eXtplorer project (http://extplorer.net)
9 9
 * @author The	The QuiX project (http://quixplorer.sourceforge.net)
10 10
 *
......
32 32
 *
33 33
 * File-Search Functions
34 34
 */
35
function ext_search_items($dir)
36
{ // search for item
37
    if (empty($dir) && !empty($GLOBALS['__POST']["item"])) {
38
        $dir = $GLOBALS['__POST']["item"];
39
    }
40
    if (isset($GLOBALS['__POST']["searchitem"])) {
35 41

  
36
function find_item($dir,$pat,&$list,$recur, $content) {	// find items
42
        $searchitem = stripslashes($GLOBALS['__POST']["searchitem"]);
43
        $subdir = !empty($GLOBALS['__POST']["subdir"]);
44
        $content = $GLOBALS['__POST']["content"];
45
        $list = make_list($dir, $searchitem, $subdir, $content);
46
    } else {
47
        $searchitem = NULL;
48
        $subdir = true;
49
    }
50

  
51
    if (empty($searchitem)) {
52
        show_searchform($dir);
53
        return;
54
    }
55

  
56
    // Results in JSON
57
    $items['totalCount'] = count($list);
58
    $result = get_result_array($list);
59
    $start = (int)$GLOBALS['__POST']["start"];
60
    $limit = (int)$GLOBALS['__POST']["limit"];
61

  
62
    if ($start < $items['totalCount'] && $limit < $items['totalCount']) {
63
        $result = array_splice($result, $start, $limit);
64
    }
65

  
66
    $items['items'] = $result;
67
    $json = new ext_Json();
68

  
69
    while (@ob_end_clean()) ;
70

  
71
    echo $json->encode($items);
72

  
73
}
74

  
75
//------------------------------------------------------------------------------
76
function make_list($dir, $item, $subdir, $content)
77
{ // make list of found items
78

  
79
    // search
80
    if (ext_isFTPMode()) {
81
        find_item_ftp($dir, $item, $list, $subdir, $content);
82
    } else {
83
        find_item($dir, $item, $list, $subdir, $content);
84
    }
85
    if (is_array($list)) sort($list);
86
    return $list;
87
}
88

  
89
function find_item_ftp($dir,$item,&$list,$recur, $content) {	// find items
37 90
	$homedir = realpath($GLOBALS['home_dir']);
38 91
    $opendir = $dir;
92
	// convert shell-wildcards to PCRE Regex Syntax
93
	$pat=str_replace("?",".",str_replace("*",".*",str_replace(".","\\.",$item)));
94
	
39 95
    if( !is_dir( $dir )) {
40 96
        $opendir = get_abs_dir($dir);
41 97
    }
......
46 102
	}
47 103

  
48 104
	if($handle===false) {
49

  
50 105
		ext_Result::sendResult('search', false, $opendir .": ".$GLOBALS["error_msg"]["opendir"]);
51 106
	}
52 107

  
......
63 118

  
64 119
		$isDir = get_is_dir($abs_new_item);
65 120
		// match?
66

  
121
		$include = false;
67 122
		if(@preg_match('@'.$pat.'@is',$new_item) > 0 ) {
68
		    $list[]=array($dir,$new_item);
69
		} else if (!$isDir) {
70
		    if ($content && $GLOBALS['ext_File']->filesize($abs_new_item) < 524288) {
123
		    $include = true;
124
		}
125
		if (!$isDir && $include && 
126
			$content && 
127
			$GLOBALS['ext_File']->filesize($abs_new_item) < 524288) {
71 128

  
72
    		  $data = $GLOBALS['ext_File']->file_get_contents( $abs_new_item );
73
              //$data = fread($handle, 524288); // Only read first 512kb
74
    		  if (preg_match('@'.$pat.'@is', $data) > 0 ) {
75
    		      $list[]=array($dir,$new_item);
76
    		  }
129
		    $data = $GLOBALS['ext_File']->file_get_contents( $abs_new_item );
130
            $pattern = preg_quote($content, '/');
131
            // finalise the regular expression, matching the whole line
132
            $pattern = "/^.*$pattern.*\$/m";
133
    		if (preg_match('@'. $pattern.'@is', $data) > 0 ) {
134
	    	    $include = true;
77 135
		    }
136
		    
78 137
		}
79

  
138
        if( $include ) {
139
            $list[]=array($dir,$new_item);
140
        }
80 141
		// search sub-directories
81 142
		if($isDir && $recur) {
82 143
			find_item($abs_new_item,$pat,$list,$recur, $content);
......
84 145
	}
85 146

  
86 147
	$GLOBALS['ext_File']->closedir($handle);
148
}
149
function find_item($dir,$pat,&$files,$subdir, $content) {
150
    if (!is_dir($dir)) {
151
        $dir = get_abs_dir($dir);
152
    }
153
	if( !$subdir ) {
154
		$files = glob($dir.'/'.$pat);
155
	} else {
156
        $files = glob_recursive($dir.'/'.$pat);
157
	}
87 158

  
159
	if($files===false) {
160
		ext_Result::sendResult('search', false, $dir .": ".$GLOBALS["error_msg"]["opendir"]);
161
	}
162
	if( $content ) {
163
		$newList = array();
164
		foreach( $files as $file ) {
165
            $contents = file_get_contents($file);
166
			$pattern = preg_quote($content, '/');
167
			// finalise the regular expression, matching the whole line
168
			$pattern = "/^.*$pattern.*\$/m";
169
			// search, and store all matching occurences in $matches
170
			if(preg_match_all($pattern, $contents, $matches)){
171
				$newList[] = $file;
172
			}
173
		}
174
		$files = $newList;
175
	}
176
	if( !empty( $_POST['mdate_start'] )) {
177
        $mdate_start = strtotime($_POST['mdate_start']);
178
		if( empty($_POST['mdate_end'] )) {
179
			$mdate_end = time();
180
		} else {
181
			$mdate_end = strtotime( $_POST['mdate_end'] );
182
		}
183
		if( $mdate_start  && $mdate_end ) {
184
			$newList = array();
185
			foreach( $files as $file ) {
186
				$filemtime = filemtime( $file );
187
				if( $filemtime > $mdate_start && $filemtime < $mdate_end ) {
188
					$newList[] = $file;
189
				}
190
			}
191
			$files = $newList;
192
		}
193
	}
194
	if( !empty( $_POST['age_value'] )) {
195
		$age_value =(int)$_POST['age_value'];
196
		$age_units = array("minutes", "hours", "days", "weeks", "months", "years");
197
		if (in_array($_POST['age_unit'], $age_units)) {
198
			$age_unit = $_POST['age_unit'];
199
		} else {
200
			$age_unit = "days";
201
		}
202
		$age_time = strtotime("-".$age_value." ".$age_unit);
203

  
204
		if( $age_time ) {
205
			$newList = array();
206
			foreach( $files as $file ) {
207
				$filemtime = filemtime( $file );
208
				if( $filemtime > $age_time ) {
209
					$newList[] = $file;
210
				}
211
			}
212
			$files = $newList;
213
		}
214
	}
215
    $newList = array();
216
    foreach( $files as $file ) {
217
        $newList[] = array(dirname($file),basename($file));
218
    }
219
    $files  = $newList;
88 220
}
89
//------------------------------------------------------------------------------
90
function make_list($dir,$item,$subdir, $content) {	// make list of found items
91
	// convert shell-wildcards to PCRE Regex Syntax
92
	$pat=str_replace("?",".",str_replace("*",".*",str_replace(".","\\.",$item)));
93 221

  
94
	// search
95
	find_item($dir,$pat,$list,$subdir, $content);
96
	if(is_array($list)) sort($list);
97
	return $list;
98
}
99 222
//------------------------------------------------------------------------------
100 223
function get_result_table($list) {			// print table of found items
101 224
	if(!is_array($list)) return;
......
152 275
			$target = "_blank";
153 276
			//}
154 277
		}
155
		$array[$i]['last_mtime'] = $GLOBALS['ext_File']->filemtime($GLOBALS['home_dir'].'/'.$dir.'/'.$item);
278
		$array[$i]['last_mtime'] = ext_isFTPMode() ? $GLOBALS['ext_File']->filemtime($GLOBALS['home_dir'].'/'.$dir.'/'.$item) : filemtime($dir.'/'.$item);
156 279
		$array[$i]['file_id'] = md5($s_dir.$s_item);
157 280
		$array[$i]['dir'] = str_replace($GLOBALS['home_dir'], '', $dir );
158 281
		$array[$i]['s_dir'] = empty($s_dir) ? '' : $s_dir;
......
162 285
	}
163 286
	return $array;
164 287
}
165
//------------------------------------------------------------------------------
166
function ext_search_items($dir) {	// search for item
167
    if( empty($dir) && !empty($GLOBALS['__POST']["item"]) ) {
168
        $dir = $GLOBALS['__POST']["item"];
288

  
289
/**
290
 * Recursive implementation of glob
291
 * @param $pattern
292
 * @param int $flags
293
 * @return array
294
 */
295
function glob_recursive($pattern, $flags = 0)
296
{
297
    $files = glob($pattern, $flags);
298
    if ($files === false) return array();
299
    foreach (glob(dirname($pattern) . '/*', GLOB_ONLYDIR | GLOB_NOSORT) as $dir) {
300
        $files = array_merge($files, glob_recursive($dir . '/' . basename($pattern), $flags));
169 301
    }
170
	if(isset($GLOBALS['__POST']["searchitem"])) {
171 302

  
172
		$searchitem=stripslashes($GLOBALS['__POST']["searchitem"]);
173
		$subdir= !empty( $GLOBALS['__POST']["subdir"] );
174
        $content = $GLOBALS['__POST']["content"];
175
		$list=make_list($dir,$searchitem,$subdir, $content);
176
	} else {
177
		$searchitem=NULL;
178
		$subdir=true;
179
	}
180

  
181
	if( empty( $searchitem)) {
182
		show_searchform($dir);
183
		return;
184
	}	
185

  
186
	// Results in JSON	
187
	$items['totalCount'] = count($list);
188
	$result = get_result_array($list);
189
	$start = (int)$GLOBALS['__POST']["start"];
190
	$limit = (int)$GLOBALS['__POST']["limit"];
191
	
192
	if( $start < $items['totalCount'] && $limit < $items['totalCount'] ) {
193
		$result = array_splice($result, $start, $limit );
194
	}
195
	
196
	$items['items'] = $result;
197
	$json = new ext_Json();
198
	
199
	while( @ob_end_clean() );
200
	
201
	echo $json->encode($items);
202

  
303
    return $files;
203 304
}
305
//------------------------------------------------------------------------------
204 306

  
205 307
function show_searchform($dir='') {
206 308
	?>
207 309
{
208
     "title":"<?php echo $GLOBALS["messages"]["searchlink"] ?>",
209
     "height":300,
310
     "height":400,
210 311
     "autoScroll":true,
211 312

  
212
     items: new Ext.DataView({
213
     	"id": "dataview",
214
         tpl: new Ext.XTemplate(
215
	        '<tpl for=".">',
216
	        '<div class="search-item">',
217
	            '<h3>',
218
	            '<a onclick="selectFile(\'{dir}\', \'{file}\');Ext.getCmp(\'dialog\').destroy();return false;" href="#" target="_blank">{s_dir}/{file}, {lastModified:date("M j, Y")}</a>',
219
	            '</h3>',
220
	        '</div></tpl>'
221
	    ),
222
         store: new Ext.data.Store({
223
		        proxy: new Ext.data.HttpProxy({
224
		            url: "<?php echo $GLOBALS['script_name'] ?>"
225
		        }),
226
		        reader: new Ext.data.JsonReader({
227
		            root: 'items',
228
		            totalProperty: 'totalCount',
229
		            id: 'file_id'
230
		        }, [			            
231
		            {name: 'fileId', mapping: 'file_id'},
232
		            {name: 'file', mapping: 'file'},
233
		            {name: 'dir', mapping: 'dir'},
234
		            {name: 's_dir', mapping: 's_dir'},
235
		            {name: 'lastModified', mapping: 'last_mtime', type: 'date', dateFormat: 'timestamp'}
236
		        ]),
237
		        baseParams: {
238
		        	limit:20, 
239
		        	option: "com_extplorer",
240
		        	action:"search",
241
		        	dir: "<?php echo $dir ?>",
242
		        	content: '0',
243
	        		subdir: '1'
244
		        }
245
		    }),
246
         itemSelector: 'div.search-item'
247
     }),
313
     items: [
314
        new Ext.TabPanel({
315
        activeTab: 0,
316
        items: [{
317
            "title":"<?php echo $GLOBALS["messages"]["searchlink"] ?>",
318
            "height": "370",
319
            "autoScroll":true,
320
            "items":
321
                new Ext.DataView({
322
                "id": "dataview",
323
                 tpl: new Ext.XTemplate(
324
                    '<tpl for=".">',
325
                    '<div class="search-item">',
326
                        '<h3>',
327
                        '<a onclick="selectFile(\'{dir}\', \'{file}\');Ext.getCmp(\'dialog\').destroy();return false;" href="#" target="_blank">{s_dir}/{file}, {lastModified:date("M j, Y")}</a>',
328
                        '</h3>',
329
                    '</div></tpl>'
330
                ),
331
                 store: new Ext.data.Store({
332
                        proxy: new Ext.data.HttpProxy({
333
                            url: "<?php echo $GLOBALS['script_name'] ?>"
334
                        }),
335
                        reader: new Ext.data.JsonReader({
336
                            root: 'items',
337
                            totalProperty: 'totalCount',
338
                            id: 'file_id'
339
                        }, [
340
                            {name: 'fileId', mapping: 'file_id'},
341
                            {name: 'file', mapping: 'file'},
342
                            {name: 'dir', mapping: 'dir'},
343
                            {name: 's_dir', mapping: 's_dir'},
344
                            {name: 'lastModified', mapping: 'last_mtime', type: 'date', dateFormat: 'timestamp'}
345
                        ]),
346
                        baseParams: {
347
                            limit:20,
348
                            option: "com_extplorer",
349
                            action:"search",
350
                            dir: "<?php echo $dir ?>",
351
                            content: '0',
352
                            subdir: '1'
353
                        }
354
                    }),
355
                 itemSelector: 'div.search-item'
356
            }),
248 357

  
249
     tbar: [
250
         'Search: ', ' ',
251
         new Ext.app.SearchField({
358
         tbar: [
359
             'Search: ', ' ',
360
             new Ext.app.SearchField({
361
                 store: Ext.getCmp("dataview").store,
362
                 width:320,
363
                value: "*"
364
             })
365
         ],
366

  
367
         bbar: new Ext.PagingToolbar({
252 368
             store: Ext.getCmp("dataview").store,
253
             width:420
254
         }),' ',' ',' ',
255
         {	
256
         	"id": "searchsubdir",
257
			text: "Subdirs",
258
			tooltip: "<?php echo ext_Lang::msg( 'miscsubdirs', true ) ?>?",
259
			name: "subdir",
260
			"listeners": {
261
				"toggle": {
262
					fn: function(btn, pressed) {
263
							Ext.getCmp("dataview").store.baseParams.subdir = (pressed ? '1' : '0');
264
					}
265
				}
266
			},
267
			 enableToggle: true,
268
			 pressed: true
269
		},' ',' ',' ',{
270
			
271
			"id": "searchcontent",
272
			text: "Content",
273
			tooltip: "<?php echo ext_Lang::msg( 'misccontent', true ) ?>?",
274
			name: 'content',
275
			"listeners": {
276
				"toggle": {
277
					fn: function(btn, pressed) {
278
							Ext.getCmp("dataview").store.baseParams.content = (pressed ? '1' : '0');
279
							
280
					}
281
				}
282
			},
283
			 enableToggle: true,
284
			 pressed: false
285
		}
286
     ],
369
             pageSize: 20,
370
             displayInfo: true,
371
             displayMsg: 'Results {0} - {1} of {2}',
372
             emptyMsg: "No files to display"
373
         })
374
    },
375
    {
376
        title: "Search Options",
377
        xtype:"form",
378
        layout: "form",
379
        "height": "350",
380
        items: [
287 381

  
288
     bbar: new Ext.PagingToolbar({
289
         store: Ext.getCmp("dataview").store,
290
         pageSize: 20,
291
         displayInfo: true,
292
         displayMsg: 'Results {0} - {1} of {2}',
293
         emptyMsg: "No files to display"
294
     })
382
            {
383
                id:'myGroup',
384
                xtype: 'checkboxgroup',
385
                fieldLabel: 'Extensive Search',
386
                itemCls: 'x-check-group-alt',
387
                // Put all controls in a single column with width 100%
388
                columns: 1,
389
                items: [
390
                {
391
                    boxLabel: 'Search within Subdirectories?', name: 'subdir',
392
                    checked: true,
393
                    tooltip: "<?php echo ext_Lang::msg( 'miscsubdirs', true ) ?>?",
394
                    "listeners": {
395
                        "check": {
396
                            fn: function(box, checked) {
397
                                Ext.getCmp("dataview").store.baseParams.subdir = (checked ? '1' : '0');
398
                            }
399
                        }
400
                    }
401
                 }
402
                ]
403
            },{
404
                fieldLabel: "<?php echo ext_Lang::msg('misccontent', true) ?>",
405
                xtype: "textfield",
406
                width: 200,
407
                id: "contentfield",
408
                name: "content",
409
                "listeners": {
410
                    "change": {
411
                        fn: function(field, newValue) {
412
                            Ext.getCmp("dataview").store.baseParams.content = newValue;
413
                        }
414
                    }
415
                }
416

  
417
            },
418
            {
419
                xtype: "compositefield",
420
                items: [
421
                {
422
                    xtype: "checkbox",
423
                    fieldLabel: "Modification Date between",
424
                    "listeners": {
425
                    "check": {
426
                        fn: function(box, checked) {
427
                            if( checked ) {Ext.getCmp( "mdate_start" ).enable(); Ext.getCmp( "mdate_end" ).enable(); }
428
                            else {
429
								Ext.getCmp( "mdate_start" ).disable(); Ext.getCmp( "mdate_end" ).disable(); 	
430
								Ext.getCmp("dataview").store.baseParams.mdate_start = "";
431
								Ext.getCmp("dataview").store.baseParams.mdate_end = "";							
432
							}
433
                        }
434
                    }
435
                }
436
                },
437
                new Ext.form.DateField({
438
                    tooltip: 'Start',
439
                    name: 'mdate_start',
440
                    id: 'mdate_start',
441
                    "listeners": {
442
                        "change": {
443
                            fn: function(field, newValue) {
444
                                Ext.getCmp("dataview").store.baseParams.mdate_start = newValue;
445
                            }
446
                        }
447
                    },
448
                    width:90,
449
                    disabled: true
450
                }),
451
                new Ext.form.DateField({
452
                    tooltip: 'End',
453
                    name: 'mdate_end',
454
                    id: 'mdate_end',
455
                    disabled: true,
456
                    "listeners": {
457
                        "change": {
458
                            fn: function(field, newValue) {
459
                                Ext.getCmp("dataview").store.baseParams.mdate_end = newValue;
460
                            }
461
                        }
462
                    },
463
                    width:90
464
                })
465

  
466
                ]
467
            },
468
            {
469
                xtype: "compositefield",
470
                items: [
471
                {
472
                    xtype: "checkbox",
473
                    name: "age_enabled",
474
                    fieldLabel: "max. File Age",
475
                    "listeners": {
476
                        "check": {
477
                            fn: function(box, checked) {
478
                                if( checked ) {Ext.getCmp( "age_unit" ).enable(); Ext.getCmp( "age_value" ).enable(); }
479
								else {
480
									Ext.getCmp( "age_value" ).disable(); Ext.getCmp( "age_unit" ).disable(); 	
481
									Ext.getCmp("dataview").store.baseParams.age_value = "";
482
									Ext.getCmp("dataview").store.baseParams.age_unit = "";							
483
								}
484
                            }
485
                        }
486
                    }
487
                },
488
				{
489
					xtype: "textfield",
490
					name: "age_value",
491
					id: "age_value",
492
					value: 1,
493
					width: 40,
494
                    "listeners": {
495
                        "change": {
496
                            fn: function(field, newValue) {
497
                                Ext.getCmp("dataview").store.baseParams.age_value = newValue;
498
                            }
499
                        }
500
                    },
501
					disabled: true
502
				},
503
					new Ext.form.ComboBox({
504
						triggerAction: 'all',
505
						lazyRender:true,
506
						mode: 'local',
507
						disabled: true,
508
						name: "age_unit",
509
						id: "age_unit",
510
						value: "days",
511
                        "listeners": {
512
                            "change": {
513
                                fn: function(field, newValue) {
514
                                    Ext.getCmp("dataview").store.baseParams.age_unit = newValue;
515
                                }
516
                            }
517
                        },
518
						store: new Ext.data.ArrayStore({
519
							id: 0,
520
							fields: [
521
								'myId',
522
								'displayText'
523
							],
524
							data: [["minute", 'Minute(s)'], ["hours", 'Hour(s)'],
525
								["days", "Day(s)"], ["weeks", "Week(s)"], ["months", "Month(s)"], ["years", "Year(s)" ]
526
								]
527
						}),
528
						valueField: 'myId',
529
						displayField: 'displayText'
530
					})
531
                ]
532
            }
533

  
534
    ]
535
    }]
536
    })
537
    ]
295 538
}
296 539

  
297 540
<?php 
298 541
	
299 542
}
543

  
300 544
//------------------------------------------------------------------------------

Also available in: Unified diff