summaryrefslogtreecommitdiff
path: root/includes/ajax_file_browser_inc.php
blob: 06d02320d8848356d1f84a9db8e1c4f5fd83df53 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
<?php
/**
 * @version $Header$
 *
 * Copyright (c) 2008 bitweaver.org
 * All Rights Reserved. See below for details and a complete list of authors.
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See http://www.gnu.org/copyleft/lesser.html for details
 *
 * @package kernel
 * @subpackage functions
 */

/**
 * Quick guide to this file:
 * $_REQUEST['ajax_path_conf'] is the kernel configuration name that contains the absolute path to the directory where the files are.
 *
 * Safety first:
 * This method was chosen to provide a measure of security since we never pass in an absolute path via the URL this way.
 * Another safety measure is provided that the configuration value set in $gBitSystem->mConfig['$_REQUEST['ajax_path_conf']] is used as 'jail'.
 * Paths outside this 'jail' will be ignored including ../../ or symbolic links.
 * Evil extensions as defined in EVIL_EXTENSION_PATTERN will be ignored as are [dot] files e.g.: .private.txt
 *
 * e.g.:
 * /home/ftp/public/ is the 'jail'
 * /home/ftp/public/ftp -> /home/ftp/ is a symbolic link that points outside the 'jail' and will therefore be ignored completely.
 * Also makes it impossible to import stuff like /home/ftp/public/../../../../../etc/passwd
 *
 * You can define ajax_path_conf in two places with different effects:
 * 1. define the ajax_path_conf when you include the template:
 *    {include file="bitpackage:kernel/ajax_file_browser.tpl" ajax_path_conf=treasury_file_import_path}
 *    This will show a link to "Load Files" which will then load the file list when you click on the link.
 * 2. If you provide $_REQUEST['ajax_path_conf'] when you include it from your php file, all files in the root directory will already be loaded.
 *    $_REQUEST['ajax_path_conf'] = 'treasury_file_import_path';
 *    require_once( KERNEL_PKG_PATH.'ajax_file_browser.php' );
 *
 * NOTE: when you process the imported files, make sure you use realpath() to check of files are really in your 'jail'.
 */
require_once 'setup_inc.php';
// we need to set these global that we can include this file from functions
global $gBitThemes, $gBitSystem, $gBitSmarty;

if( !empty( $_REQUEST['ajax_path_conf'] ) && $gBitSystem->isFeatureActive( $_REQUEST['ajax_path_conf'] ) ) {
	$fileList = ajax_dir_list( $gBitSystem->getConfig( $_REQUEST['ajax_path_conf'] ), !empty( $_REQUEST['relpath'] ) ? $_REQUEST['relpath'] . "/" : null);
	$gBitSmarty->assign( 'fileList', $fileList );
}
$gBitThemes->loadJavascript( KERNEL_PKG_PATH."scripts/BitFileBrowser.js", true );

if( $gBitThemes->isAjaxRequest() ) {
	$gBitSmarty->display( 'bitpackage:kernel/ajax_file_browser_inc.tpl' );
}

/**
 * ajax_dir_list
 *
 * @param string $pDir Base directory
 * @param string $pRelPath relative path on top of base directory
 * @access public
 * @return array
 */
function ajax_dir_list( $pDir, $pRelPath = null ) {
	global $gBitSystem;
	$ret = $files = [];

	if( !empty( $pDir ) && is_dir( $pDir.$pRelPath )) {
		if( $handle = opendir( $pDir.$pRelPath )) {
			while( false !== ( $file = readdir( $handle ))) {
				if( !preg_match( "#^\.#",$file ) && is_readable( $pDir.$pRelPath.$file )) {
					array_push( $files, $file );
				}
			}
			sort( $files );
			foreach( $files as $i ) {
				$relFile = $pRelPath.$i;
				$file = realpath( $pDir.$relFile );
				if( strpos( $file, $pDir ) === 0 ) {
					$info = [
						'name'    => $i,
						'relpath' => $relFile,
						'indent'  => ( count( explode( '/', $relFile )) * 10 ),
						'size'    => filesize( $file ),
						'mtime'   => filemtime( $file ),
					];
					if( is_dir( $file )) {
						$ret['dir'][$i] = $info;
					} elseif( !preg_match( EVIL_EXTENSION_PATTERN, $file )) {
						$ret['file'][$i] = $info;
					}
				}
			}
			closedir( $handle );
		}
	}

	if( empty( $ret )) {
		$ret['file'][] = [
			'indent'  => ( count( explode( '/', $pRelPath )) * 10 ),
		];
	}

	return $ret;
}