This commit is contained in:
2026-07-02 15:54:39 -06:00
commit 9883323161
17470 changed files with 4470592 additions and 0 deletions
@@ -0,0 +1,2 @@
order deny,allow
deny from all
@@ -0,0 +1,47 @@
DROP TABLE IF EXISTS `elfinder_file`;
CREATE TABLE IF NOT EXISTS `elfinder_file` (
`id` int(7) unsigned NOT NULL auto_increment,
`parent_id` int(7) unsigned NOT NULL,
`name` varchar(255) NOT NULL,
`content` longblob NOT NULL,
`size` int(10) unsigned NOT NULL default '0',
`mtime` int(10) unsigned NOT NULL default '0',
`mime` varchar(256) NOT NULL default 'unknown',
`read` enum('1', '0') NOT NULL default '1',
`write` enum('1', '0') NOT NULL default '1',
`locked` enum('1', '0') NOT NULL default '0',
`hidden` enum('1', '0') NOT NULL default '0',
`width` int(5) NOT NULL default '0',
`height` int(5) NOT NULL default '0',
PRIMARY KEY (`id`),
UNIQUE KEY `parent_name` (`parent_id`, `name`),
KEY `parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
INSERT INTO `elfinder_file`
(`id`, `parent_id`, `name`, `content`, `size`, `mtime`, `mime`, `read`, `write`, `locked`, `hidden`, `width`, `height`) VALUES
('1' , '0', 'DATABASE', '', '0', '0','directory', '1', '1', '0', '0', '0', '0');
DROP TABLE IF EXISTS `elfinder_trash`;
CREATE TABLE IF NOT EXISTS `elfinder_trash` (
`id` int(7) unsigned NOT NULL auto_increment,
`parent_id` int(7) unsigned NOT NULL,
`name` varchar(255) NOT NULL,
`content` longblob NOT NULL,
`size` int(10) unsigned NOT NULL default '0',
`mtime` int(10) unsigned NOT NULL default '0',
`mime` varchar(256) NOT NULL default 'unknown',
`read` enum('1', '0') NOT NULL default '1',
`write` enum('1', '0') NOT NULL default '1',
`locked` enum('1', '0') NOT NULL default '0',
`hidden` enum('1', '0') NOT NULL default '0',
`width` int(5) NOT NULL default '0',
`height` int(5) NOT NULL default '0',
PRIMARY KEY (`id`),
UNIQUE KEY `parent_name` (`parent_id`, `name`),
KEY `parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
INSERT INTO `elfinder_trash`
(`id`, `parent_id`, `name`, `content`, `size`, `mtime`, `mime`, `read`, `write`, `locked`, `hidden`, `width`, `height`) VALUES
('1' , '0', 'DB Trash', '', '0', '0','directory', '1', '1', '0', '0', '0', '0');
@@ -0,0 +1,56 @@
<?php
define('ELFINDER_PHP_ROOT_PATH', dirname(__FILE__));
function elFinderAutoloader($name)
{
$map = array(
'elFinder' => 'elFinder.class.php',
'elFinderConnector' => 'elFinderConnector.class.php',
'elFinderEditor' => 'editors/editor.php',
'elFinderLibGdBmp' => 'libs/GdBmp.php',
'elFinderPlugin' => 'elFinderPlugin.php',
'elFinderPluginAutoResize' => 'plugins/AutoResize/plugin.php',
'elFinderPluginAutoRotate' => 'plugins/AutoRotate/plugin.php',
'elFinderPluginNormalizer' => 'plugins/Normalizer/plugin.php',
'elFinderPluginSanitizer' => 'plugins/Sanitizer/plugin.php',
'elFinderPluginWatermark' => 'plugins/Watermark/plugin.php',
'elFinderSession' => 'elFinderSession.php',
'elFinderSessionInterface' => 'elFinderSessionInterface.php',
'elFinderVolumeDriver' => 'elFinderVolumeDriver.class.php',
'elFinderVolumeDropbox2' => 'elFinderVolumeDropbox2.class.php',
'elFinderVolumeFTP' => 'elFinderVolumeFTP.class.php',
'elFinderVolumeFlysystemGoogleDriveCache' => 'elFinderFlysystemGoogleDriveNetmount.php',
'elFinderVolumeFlysystemGoogleDriveNetmount' => 'elFinderFlysystemGoogleDriveNetmount.php',
'elFinderVolumeGoogleDrive' => 'elFinderVolumeGoogleDrive.class.php',
'elFinderVolumeGroup' => 'elFinderVolumeGroup.class.php',
'elFinderVolumeLocalFileSystem' => 'elFinderVolumeLocalFileSystem.class.php',
'elFinderVolumeMySQL' => 'elFinderVolumeMySQL.class.php',
'elFinderVolumeSFTPphpseclib' => 'elFinderVolumeSFTPphpseclib.class.php',
'elFinderVolumeTrash' => 'elFinderVolumeTrash.class.php',
);
if (isset($map[$name])) {
return include_once(ELFINDER_PHP_ROOT_PATH . '/' . $map[$name]);
}
$prefix = substr($name, 0, 14);
if (substr($prefix, 0, 8) === 'elFinder') {
if ($prefix === 'elFinderVolume') {
$file = ELFINDER_PHP_ROOT_PATH . '/' . $name . '.class.php';
return (is_file($file) && include_once($file));
} else if ($prefix === 'elFinderPlugin') {
$file = ELFINDER_PHP_ROOT_PATH . '/plugins/' . substr($name, 14) . '/plugin.php';
return (is_file($file) && include_once($file));
} else if ($prefix === 'elFinderEditor') {
$file = ELFINDER_PHP_ROOT_PATH . '/editors/' . substr($name, 14) . '/editor.php';
return (is_file($file) && include_once($file));
}
}
return false;
}
if (version_compare(PHP_VERSION, '5.3', '<')) {
spl_autoload_register('elFinderAutoloader');
} else {
spl_autoload_register('elFinderAutoloader', true, true);
}
@@ -0,0 +1,449 @@
<?php
error_reporting(0); // Set E_ALL for debuging
// // Optional exec path settings (Default is called with command name only)
// define('ELFINDER_TAR_PATH', '/PATH/TO/tar');
// define('ELFINDER_GZIP_PATH', '/PATH/TO/gzip');
// define('ELFINDER_BZIP2_PATH', '/PATH/TO/bzip2');
// define('ELFINDER_XZ_PATH', '/PATH/TO/xz');
// define('ELFINDER_ZIP_PATH', '/PATH/TO/zip');
// define('ELFINDER_UNZIP_PATH', '/PATH/TO/unzip');
// define('ELFINDER_RAR_PATH', '/PATH/TO/rar');
// define('ELFINDER_UNRAR_PATH', '/PATH/TO/unrar');
// define('ELFINDER_7Z_PATH', '/PATH/TO/7za');
// define('ELFINDER_CONVERT_PATH', '/PATH/TO/convert');
// define('ELFINDER_IDENTIFY_PATH', '/PATH/TO/identify');
// define('ELFINDER_EXIFTRAN_PATH', '/PATH/TO/exiftran');
// define('ELFINDER_JPEGTRAN_PATH', '/PATH/TO/jpegtran');
// define('ELFINDER_FFMPEG_PATH', '/PATH/TO/ffmpeg');
// define('ELFINDER_CONNECTOR_URL', 'URL to this connector script'); // see elFinder::getConnectorUrl()
// define('ELFINDER_DEBUG_ERRORLEVEL', -1); // Error reporting level of debug mode
// // To Enable(true) handling of PostScript files by ImageMagick
// // It is disabled by default as a countermeasure
// // of Ghostscript multiple -dSAFER sandbox bypass vulnerabilities
// // see https://www.kb.cert.org/vuls/id/332928
// define('ELFINDER_IMAGEMAGICK_PS', true);
// ===============================================
// // load composer autoload before load elFinder autoload If you need composer
// // You need to run the composer command in the php directory.
is_readable('./vendor/autoload.php') && require './vendor/autoload.php';
// // elFinder autoload
require './autoload.php';
// ===============================================
// // Enable FTP connector netmount
elFinder::$netDrivers['ftp'] = 'FTP';
// ===============================================
// // Required for Dropbox network mount
// // Installation by composer
// // `composer require kunalvarma05/dropbox-php-sdk` on php directory
// // Enable network mount
// elFinder::$netDrivers['dropbox2'] = 'Dropbox2';
// // Dropbox2 Netmount driver need next two settings. You can get at https://www.dropbox.com/developers/apps
// // AND require register redirect url to "YOUR_CONNECTOR_URL?cmd=netmount&protocol=dropbox2&host=1"
// define('ELFINDER_DROPBOX_APPKEY', '');
// define('ELFINDER_DROPBOX_APPSECRET', '');
// ===============================================
// // Required for Google Drive network mount
// // Installation by composer
// // `composer require google/apiclient:^2.0` on php directory
// // Enable network mount
// elFinder::$netDrivers['googledrive'] = 'GoogleDrive';
// // GoogleDrive Netmount driver need next two settings. You can get at https://console.developers.google.com
// // AND require register redirect url to "YOUR_CONNECTOR_URL?cmd=netmount&protocol=googledrive&host=1"
// define('ELFINDER_GOOGLEDRIVE_CLIENTID', '');
// define('ELFINDER_GOOGLEDRIVE_CLIENTSECRET', '');
// // Required case when Google API is NOT added via composer
// define('ELFINDER_GOOGLEDRIVE_GOOGLEAPICLIENT', '/path/to/google-api-php-client/vendor/autoload.php');
// ===============================================
// // Required for Google Drive network mount with Flysystem
// // Installation by composer
// // `composer require nao-pon/flysystem-google-drive:~1.1 nao-pon/elfinder-flysystem-driver-ext` on php directory
// // Enable network mount
// elFinder::$netDrivers['googledrive'] = 'FlysystemGoogleDriveNetmount';
// // GoogleDrive Netmount driver need next two settings. You can get at https://console.developers.google.com
// // AND require register redirect url to "YOUR_CONNECTOR_URL?cmd=netmount&protocol=googledrive&host=1"
// define('ELFINDER_GOOGLEDRIVE_CLIENTID', '');
// define('ELFINDER_GOOGLEDRIVE_CLIENTSECRET', '');
// // And "php/.tmp" directory must exist and be writable by PHP.
// ===============================================
// // Required for One Drive network mount
// // * cURL PHP extension required
// // * HTTP server PATH_INFO supports required
// // Enable network mount
// elFinder::$netDrivers['onedrive'] = 'OneDrive';
// // OneDrive Netmount driver need next two settings. You can get at
// // https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps
// // AND require register redirect url to "YOUR_CONNECTOR_URL/netmount/onedrive/1"
// define('ELFINDER_ONEDRIVE_CLIENTID', '');
// define('ELFINDER_ONEDRIVE_CLIENTSECRET', '');
// ===============================================
// // Required for Box network mount
// // * cURL PHP extension required
// // Enable network mount
// elFinder::$netDrivers['box'] = 'Box';
// // Box Netmount driver need next two settings. You can get at https://developer.box.com
// // AND require register redirect url to "YOUR_CONNECTOR_URL?cmd=netmount&protocol=box&host=1"
// define('ELFINDER_BOX_CLIENTID', '');
// define('ELFINDER_BOX_CLIENTSECRET', '');
// ===============================================
// // Zoho Office Editor APIKey
// // https://www.zoho.com/docs/help/office-apis.html
// define('ELFINDER_ZOHO_OFFICE_APIKEY', '');
// ===============================================
// // Online converter (online-convert.com) APIKey
// // https://apiv2.online-convert.com/docs/getting_started/api_key.html
// define('ELFINDER_ONLINE_CONVERT_APIKEY', '');
// ===============================================
// // Zip Archive editor
// // Installation by composer
// // `composer require nao-pon/elfinder-flysystem-ziparchive-netmount` on php directory
// define('ELFINDER_DISABLE_ZIPEDITOR', false); // set `true` to disable zip editor
// ===============================================
/**
* Simple function to demonstrate how to control file access using "accessControl" callback.
* This method will disable accessing files/folders starting from '.' (dot)
*
* @param string $attr attribute name (read|write|locked|hidden)
* @param string $path absolute file path
* @param string $data value of volume option `accessControlData`
* @param object $volume elFinder volume driver object
* @param bool|null $isDir path is directory (true: directory, false: file, null: unknown)
* @param string $relpath file path relative to volume root directory started with directory separator
* @return bool|null
**/
function access($attr, $path, $data, $volume, $isDir, $relpath) {
$basename = basename($path);
return $basename[0] === '.' // if file/folder begins with '.' (dot)
&& strlen($relpath) !== 1 // but with out volume root
? !($attr == 'read' || $attr == 'write') // set read+write to false, other (locked+hidden) set to true
: null; // else elFinder decide it itself
}
/**
* Simple debug function
* Usage: debug($anyVal[, $anyVal2 ...]);
*/
function debug() {
$arg = func_get_args();
ob_start();
foreach($arg as $v) {
var_dump($v);
}
$o = ob_get_contents();
ob_end_clean();
file_put_contents('.debug.txt', $o, FILE_APPEND);
}
/**
* Simple logger function.
* Demonstrate how to work with elFinder event api.
*
* @package elFinder
* @author Dmitry (dio) Levashov
**/
class elFinderSimpleLogger {
/**
* Log file path
*
* @var string
**/
protected $file = '';
/**
* constructor
*
* @return void
* @author Dmitry (dio) Levashov
**/
public function __construct($path)
{
$this->file = $path;
$dir = dirname($path);
if (!is_dir($dir)) {
mkdir($dir);
}
}
/**
* Create log record
*
* @param string $cmd command name
* @param array $result command result
* @param array $args command arguments from client
* @param elFinder $elfinder elFinder instance
* @param elFinderVolumeDriver $volume current volume driver instance
* @return void|true
* @author Dmitry (dio) Levashov
**/
public function log($cmd, $result, $args, $elfinder, $volume)
{
$log = $cmd.' ['.date('d.m H:s')."]\n";
if (!empty($result['error'])) {
$log .= "\tERROR: ".implode(' ', $result['error'])."\n";
}
if (!empty($result['warning'])) {
$log .= "\tWARNING: ".implode(' ', $result['warning'])."\n";
}
if (!empty($result['removed'])) {
foreach ($result['removed'] as $file) {
// removed file contain additional field "realpath"
$log .= "\tREMOVED: ".$file['realpath']."\n";
}
}
if (!empty($result['added'])) {
foreach ($result['added'] as $file) {
$log .= "\tADDED: ".$elfinder->realpath($file['hash'])."\n";
}
}
if (!empty($result['changed'])) {
foreach ($result['changed'] as $file) {
$log .= "\tCHANGED: ".$elfinder->realpath($file['hash'])."\n";
}
}
$this->write($log);
}
/**
* Write log into file
*
* @param string $log log record
* @return void
* @author Dmitry (dio) Levashov
**/
protected function write($log)
{
if (($fp = @fopen($this->file, 'a'))) {
fwrite($fp, $log."\n");
fclose($fp);
}
}
} // END class
// Make logger instance
$logger = new elFinderSimpleLogger('.log.txt');
// Documentation for connector options:
// https://github.com/Studio-42/elFinder/wiki/Connector-configuration-options
$opts = array(
'debug' => true, // enable debug mode
'roots' => array(
// Items volume
array(
'driver' => 'LocalFileSystem', // driver for accessing file system (REQUIRED)
'path' => '../files/', // path to files (REQUIRED)
'URL' => dirname($_SERVER['PHP_SELF']) . '/../files/', // URL to files (REQUIRED)
'trashHash' => 't1_Lw', // elFinder's hash of trash folder
'winHashFix' => DIRECTORY_SEPARATOR !== '/', // to make hash same to Linux one on windows too
'uploadDeny' => array('all'), // All Mimetypes not allowed to upload
'uploadAllow' => array('image/x-ms-bmp', 'image/gif', 'image/jpeg', 'image/png', 'image/x-icon', 'text/plain'), // Mimetype `image` and `text/plain` allowed to upload
'uploadOrder' => array('deny', 'allow'), // allowed Mimetype `image` and `text/plain` only
'accessControl' => 'access', // disable and hide dot starting files (OPTIONAL)
'attributes' => array( // additional thumbnail directories
'pattern' => '~^/\.tmb(?:Cloud|Netmount)$~',
'read' => false,
'write' => false,
'locked' => true,
'hidden' => true ),
),
// Trash volume
array(
'id' => '1',
'driver' => 'Trash',
'path' => '../files/.trash/',
'tmbURL' => dirname($_SERVER['PHP_SELF']) . '/../files/.trash/.tmb/',
'winHashFix' => DIRECTORY_SEPARATOR !== '/', // to make hash same to Linux one on windows too
'uploadDeny' => array('all'), // Recomend the same settings as the original volume that uses the trash
'uploadAllow' => array('image/x-ms-bmp', 'image/gif', 'image/jpeg', 'image/png', 'image/x-icon', 'text/plain'), // Same as above
'uploadOrder' => array('deny', 'allow'), // Same as above
'accessControl' => 'access', // Same as above
),
),
// some bind functions
'bind' => array(
// enable logger
// '*' => array($logger, 'log'),
'mkdir mkfile rename duplicate upload rm paste' => array($logger, 'log'),
// enable plugins
'archive.pre ls.pre mkdir.pre mkfile.pre rename.pre upload.pre' => array(
'Plugin.Normalizer.cmdPreprocess',
'Plugin.Sanitizer.cmdPreprocess'
),
'upload.presave' => array(
'Plugin.AutoRotate.onUpLoadPreSave',
'Plugin.AutoResize.onUpLoadPreSave',
'Plugin.Watermark.onUpLoadPreSave',
'Plugin.Normalizer.onUpLoadPreSave',
'Plugin.Sanitizer.onUpLoadPreSave',
),
),
// volume options of netmount volumes
'optionsNetVolumes' => array(
'*' => array( // "*" is all of netmount volumes
'tmbURL' => dirname($_SERVER['PHP_SELF']) . '/../files/.tmbNetmount/',
'tmbPath' => '../files/.tmbNetmount',
'tmbGcMaxlifeHour' => 1, // 1 hour
'tmbGcPercentage' => 10, // 10 execute / 100 tmb querys
'plugin' => array(
'AutoResize' => array(
'enable' => false
),
'Watermark' => array(
'enable' => false
),
'Normalizer' => array(
'enable' => false
),
'Sanitizer' => array(
'enable' => false
)
),
)
),
);
// Extended other volume types
// To get an access token or refresh token, see the elFinder wiki.
// https://github.com/Studio-42/elFinder/wiki/How-to-get-OAuth-token
// Thumbnail settings for cloud volumes
$tmbConfig = array(
'tmbPath' => '../files/.tmbCloud',
'tmbURL' => dirname($_SERVER['PHP_SELF']) . '/../files/.tmbCloud/',
'tmbGcMaxlifeHour' => 2160, // 90 days
'tmbGcPercentage' => 5, // 5 execute / 100 tmb querys
);
// MySQL config
$mySqlConfig = array(
'path' => 1,
'host' => '127.0.0.1',
'user' => '', // @String DB user name
'pass' => '', // @String DB user password
'db' => '', // @String Database name
'uploadMaxSize' => '10M', // It should be less than "max_allowed_packet" value of MySQL setting
);
// MySQL volume
$opts['roots'][] = array_merge($tmbConfig, $mySqlConfig, array(
'driver' => 'MySQL',
'trashHash' => 'tm1_MQ', // set trash to MySQL trash (tm1_) 1 (MQ)
'files_table' => 'elfinder_file',
));
// MySQL trash volume
$opts['roots'][] = array_merge($tmbConfig, $mySqlConfig, array(
'id' => '1', // volume id became "tm1_"
'alias' => 'DB Trash',
'driver' => 'TrashMySQL',
'files_table' => 'elfinder_trash',
));
// Volume group
$opts['roots'][] = array(
'id' => '1', // volume id became "g1_"
'alias' => 'CloudVolumes',
'driver' => 'Group',
'rootCssClass' => 'elfinder-navbar-root-network' // set volume icon
);
// FTP volume
$opts['roots'][] = array_merge($tmbConfig, array(
'phash' => 'g1_Lw', // set parent to Volume group (g1_) root "/" (Lw)
'driver' => 'FTP',
'host' => 'ftp.jaist.ac.jp',
'user' => 'anonymous',
'path' => '/',
'owner' => false,
));
// To enable the following cloud volumes, first complete the steps
// for enabling each network-mounted volume described earlier in this file.
// Box volume
// Require constant "ELFINDER_BOX_CLIENTID" and "ELFINDER_BOX_CLIENTSECRET"
$opts['roots'][] = array_merge($tmbConfig, array(
'phash' => 'g1_Lw', // set parent to Volume group (g1_) root "/" (Lw)
'driver' => 'Box',
'path' => '/', // or folder id as root
'accessToken' => '', // @JSON String access token including refresh token
));
// Dropbox volume
// Require constant "ELFINDER_DROPBOX_APPKEY" and "ELFINDER_DROPBOX_APPSECRET"
$opts['roots'][] = array_merge($tmbConfig, array(
'phash' => 'g1_Lw', // set parent to Volume group (g1_) root "/" (Lw)
'driver' => 'Dropbox2',
'path' => '/', // or folder path as root
'access_token' => '', // @String your access token
));
// GoogleDrive volume with refresh token
// Require constant "ELFINDER_GOOGLEDRIVE_CLIENTID" and "ELFINDER_GOOGLEDRIVE_CLIENTSECRET"
$opts['roots'][] = array_merge($tmbConfig, array(
'phash' => 'g1_Lw', // set parent to Volume group (g1_) root "/" (Lw)
'driver' => 'GoogleDrive',
'path' => '/', // or folder id as root
'refresh_token' => '', // @String your refresh token
));
// GoogleDrive volume with service account
// Require constant "ELFINDER_GOOGLEDRIVE_CLIENTID" and "ELFINDER_GOOGLEDRIVE_CLIENTSECRET"
$opts['roots'][] = array_merge($tmbConfig, array(
'phash' => 'g1_Lw', // set parent to Volume group (g1_) root "/" (Lw)
'driver' => 'GoogleDrive',
'path' => '/', // or folder id as root
'serviceAccountConfigFile' => '', // @String path to config json file
));
// OneDrive volume
// Require constant "ELFINDER_ONEDRIVE_CLIENTID" and "ELFINDER_ONEDRIVE_CLIENTSECRET"
$opts['roots'][] = array_merge($tmbConfig, array(
'phash' => 'g1_Lw', // set parent to Volume group (g1_) root "/" (Lw)
'driver' => 'OneDrive',
'path' => '/', // or folder id as root
'accessToken' => '', // @JSON String access token including refresh token
));
// SFTP volume
// Require phpseclib 1 installed (http://phpseclib.sourceforge.net)
// pear install example:
//sudo pear channel-discover phpseclib.sourceforge.net
//sudo pear remote-list -c phpseclib
//sudo pear install phpseclib/Net_SFTP
/*$opts['roots'][] = array_merge($tmbConfig, array(
'phash' => 'g1_Lw', // set parent to Volume group (g1_) root "/" (Lw)
'driver' => 'SFTPphpseclib',
'host' => '127.0.0.1',
'path' => '/tmp', // or folder id as root
'user' => 'test', // @JSON String access token including refresh token
'pass' => 'test',
));*/
// run elFinder
$connector = new elFinderConnector(new elFinder($opts));
$connector->run();
@@ -0,0 +1,180 @@
<?php
error_reporting(0); // Set E_ALL for debuging
// // Optional exec path settings (Default is called with command name only)
// define('ELFINDER_TAR_PATH', '/PATH/TO/tar');
// define('ELFINDER_GZIP_PATH', '/PATH/TO/gzip');
// define('ELFINDER_BZIP2_PATH', '/PATH/TO/bzip2');
// define('ELFINDER_XZ_PATH', '/PATH/TO/xz');
// define('ELFINDER_ZIP_PATH', '/PATH/TO/zip');
// define('ELFINDER_UNZIP_PATH', '/PATH/TO/unzip');
// define('ELFINDER_RAR_PATH', '/PATH/TO/rar');
// define('ELFINDER_UNRAR_PATH', '/PATH/TO/unrar');
// define('ELFINDER_7Z_PATH', '/PATH/TO/7za');
// define('ELFINDER_CONVERT_PATH', '/PATH/TO/convert');
// define('ELFINDER_IDENTIFY_PATH', '/PATH/TO/identify');
// define('ELFINDER_EXIFTRAN_PATH', '/PATH/TO/exiftran');
// define('ELFINDER_JPEGTRAN_PATH', '/PATH/TO/jpegtran');
// define('ELFINDER_FFMPEG_PATH', '/PATH/TO/ffmpeg');
// define('ELFINDER_CONNECTOR_URL', 'URL to this connector script'); // see elFinder::getConnectorUrl()
// define('ELFINDER_DEBUG_ERRORLEVEL', -1); // Error reporting level of debug mode
// // To Enable(true) handling of PostScript files by ImageMagick
// // It is disabled by default as a countermeasure
// // of Ghostscript multiple -dSAFER sandbox bypass vulnerabilities
// // see https://www.kb.cert.org/vuls/id/332928
// define('ELFINDER_IMAGEMAGICK_PS', true);
// ===============================================
// // load composer autoload before load elFinder autoload If you need composer
// // You need to run the composer command in the php directory.
is_readable('./vendor/autoload.php') && require './vendor/autoload.php';
// // elFinder autoload
require './autoload.php';
// ===============================================
// // Enable FTP connector netmount
elFinder::$netDrivers['ftp'] = 'FTP';
// ===============================================
// // Required for Dropbox network mount
// // Installation by composer
// // `composer require kunalvarma05/dropbox-php-sdk` on php directory
// // Enable network mount
// elFinder::$netDrivers['dropbox2'] = 'Dropbox2';
// // Dropbox2 Netmount driver need next two settings. You can get at https://www.dropbox.com/developers/apps
// // AND require register redirect url to "YOUR_CONNECTOR_URL?cmd=netmount&protocol=dropbox2&host=1"
// // If the elFinder HTML element ID is not "elfinder", you need to change "host=1" to "host=ElementID"
// define('ELFINDER_DROPBOX_APPKEY', '');
// define('ELFINDER_DROPBOX_APPSECRET', '');
// ===============================================
// // Required for Google Drive network mount
// // Installation by composer
// // `composer require google/apiclient:^2.0` on php directory
// // Enable network mount
// elFinder::$netDrivers['googledrive'] = 'GoogleDrive';
// // GoogleDrive Netmount driver need next two settings. You can get at https://console.developers.google.com
// // AND require register redirect url to "YOUR_CONNECTOR_URL?cmd=netmount&protocol=googledrive&host=1"
// // If the elFinder HTML element ID is not "elfinder", you need to change "host=1" to "host=ElementID"
// define('ELFINDER_GOOGLEDRIVE_CLIENTID', '');
// define('ELFINDER_GOOGLEDRIVE_CLIENTSECRET', '');
// // Required case when Google API is NOT added via composer
// define('ELFINDER_GOOGLEDRIVE_GOOGLEAPICLIENT', '/path/to/google-api-php-client/vendor/autoload.php');
// ===============================================
// // Required for Google Drive network mount with Flysystem
// // Installation by composer
// // `composer require nao-pon/flysystem-google-drive:~1.1 nao-pon/elfinder-flysystem-driver-ext` on php directory
// // Enable network mount
// elFinder::$netDrivers['googledrive'] = 'FlysystemGoogleDriveNetmount';
// // GoogleDrive Netmount driver need next two settings. You can get at https://console.developers.google.com
// // AND require register redirect url to "YOUR_CONNECTOR_URL?cmd=netmount&protocol=googledrive&host=1"
// // If the elFinder HTML element ID is not "elfinder", you need to change "host=1" to "host=ElementID"
// define('ELFINDER_GOOGLEDRIVE_CLIENTID', '');
// define('ELFINDER_GOOGLEDRIVE_CLIENTSECRET', '');
// // And "php/.tmp" directory must exist and be writable by PHP.
// ===============================================
// // Required for One Drive network mount
// // * cURL PHP extension required
// // * HTTP server PATH_INFO supports required
// // Enable network mount
// elFinder::$netDrivers['onedrive'] = 'OneDrive';
// // OneDrive Netmount driver need next two settings. You can get at
// // https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps
// // AND require register redirect url to "YOUR_CONNECTOR_URL/netmount/onedrive/1"
// // If the elFinder HTML element ID is not "elfinder", you need to change "/1" to "/ElementID"
// define('ELFINDER_ONEDRIVE_CLIENTID', '');
// define('ELFINDER_ONEDRIVE_CLIENTSECRET', '');
// ===============================================
// // Required for Box network mount
// // * cURL PHP extension required
// // Enable network mount
// elFinder::$netDrivers['box'] = 'Box';
// // Box Netmount driver need next two settings. You can get at https://developer.box.com
// // AND require register redirect url to "YOUR_CONNECTOR_URL?cmd=netmount&protocol=box&host=1"
// // If the elFinder HTML element ID is not "elfinder", you need to change "host=1" to "host=ElementID"
// define('ELFINDER_BOX_CLIENTID', '');
// define('ELFINDER_BOX_CLIENTSECRET', '');
// ===============================================
// // Zoho Office Editor APIKey
// // https://www.zoho.com/docs/help/office-apis.html
// define('ELFINDER_ZOHO_OFFICE_APIKEY', '');
// ===============================================
// // Online converter (online-convert.com) APIKey
// // https://apiv2.online-convert.com/docs/getting_started/api_key.html
// define('ELFINDER_ONLINE_CONVERT_APIKEY', '');
// ===============================================
// // Zip Archive editor
// // Installation by composer
// // `composer require nao-pon/elfinder-flysystem-ziparchive-netmount` on php directory
// define('ELFINDER_DISABLE_ZIPEDITOR', false); // set `true` to disable zip editor
// ===============================================
/**
* Simple function to demonstrate how to control file access using "accessControl" callback.
* This method will disable accessing files/folders starting from '.' (dot)
*
* @param string $attr attribute name (read|write|locked|hidden)
* @param string $path absolute file path
* @param string $data value of volume option `accessControlData`
* @param object $volume elFinder volume driver object
* @param bool|null $isDir path is directory (true: directory, false: file, null: unknown)
* @param string $relpath file path relative to volume root directory started with directory separator
* @return bool|null
**/
function access($attr, $path, $data, $volume, $isDir, $relpath) {
$basename = basename($path);
return $basename[0] === '.' // if file/folder begins with '.' (dot)
&& strlen($relpath) !== 1 // but with out volume root
? !($attr == 'read' || $attr == 'write') // set read+write to false, other (locked+hidden) set to true
: null; // else elFinder decide it itself
}
// Documentation for connector options:
// https://github.com/Studio-42/elFinder/wiki/Connector-configuration-options
$opts = array(
// 'debug' => true,
'roots' => array(
// Items volume
array(
'driver' => 'LocalFileSystem', // driver for accessing file system (REQUIRED)
'path' => '../files/', // path to files (REQUIRED)
'URL' => dirname($_SERVER['PHP_SELF']) . '/../files/', // URL to files (REQUIRED)
'trashHash' => 't1_Lw', // elFinder's hash of trash folder
'winHashFix' => DIRECTORY_SEPARATOR !== '/', // to make hash same to Linux one on windows too
'uploadDeny' => array('all'), // All Mimetypes not allowed to upload
'uploadAllow' => array('image/x-ms-bmp', 'image/gif', 'image/jpeg', 'image/png', 'image/x-icon', 'text/plain'), // Mimetype `image` and `text/plain` allowed to upload
'uploadOrder' => array('deny', 'allow'), // allowed Mimetype `image` and `text/plain` only
'accessControl' => 'access' // disable and hide dot starting files (OPTIONAL)
),
// Trash volume
array(
'id' => '1',
'driver' => 'Trash',
'path' => '../files/.trash/',
'tmbURL' => dirname($_SERVER['PHP_SELF']) . '/../files/.trash/.tmb/',
'winHashFix' => DIRECTORY_SEPARATOR !== '/', // to make hash same to Linux one on windows too
'uploadDeny' => array('all'), // Recomend the same settings as the original volume that uses the trash
'uploadAllow' => array('image/x-ms-bmp', 'image/gif', 'image/jpeg', 'image/png', 'image/x-icon', 'text/plain'), // Same as above
'uploadOrder' => array('deny', 'allow'), // Same as above
'accessControl' => 'access', // Same as above
),
)
);
// run elFinder
$connector = new elFinderConnector(new elFinder($opts));
$connector->run();
@@ -0,0 +1,113 @@
<?php
class elFinderEditorOnlineConvert extends elFinderEditor
{
protected $allowed = array('init', 'api');
public function enabled()
{
return defined('ELFINDER_ONLINE_CONVERT_APIKEY') && ELFINDER_ONLINE_CONVERT_APIKEY && (!defined('ELFINDER_DISABLE_ONLINE_CONVERT') || !ELFINDER_DISABLE_ONLINE_CONVERT);
}
public function init()
{
return array('api' => defined('ELFINDER_ONLINE_CONVERT_APIKEY') && ELFINDER_ONLINE_CONVERT_APIKEY && function_exists('curl_init'));
}
public function api()
{
// return array('apires' => array('message' => 'Currently disabled for developping...'));
$endpoint = 'https://api2.online-convert.com/jobs';
$category = $this->argValue('category');
$convert = $this->argValue('convert');
$options = $this->argValue('options');
$source = $this->argValue('source');
$filename = $this->argValue('filename');
$mime = $this->argValue('mime');
$jobid = $this->argValue('jobid');
$string_method = '';
$options = array();
// Currently these converts are make error with API call. I don't know why.
$nonApi = array('android', 'blackberry', 'dpg', 'ipad', 'iphone', 'ipod', 'nintendo-3ds', 'nintendo-ds', 'ps3', 'psp', 'wii', 'xbox');
if (in_array($convert, $nonApi)) {
return array('apires' => array());
}
$ch = null;
if ($convert && $source) {
$request = array(
'input' => array(array(
'type' => 'remote',
'source' => $source
)),
'conversion' => array(array(
'target' => $convert
))
);
if ($filename !== '') {
$request['input'][0]['filename'] = $filename;
}
if ($mime !== '') {
$request['input'][0]['content_type'] = $mime;
}
if ($category) {
$request['conversion'][0]['category'] = $category;
}
if ($options && $options !== 'null') {
$options = json_decode($options, true);
}
if (!is_array($options)) {
$options = array();
}
if ($options) {
$request['conversion'][0]['options'] = $options;
}
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($request));
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'X-Oc-Api-Key: ' . ELFINDER_ONLINE_CONVERT_APIKEY,
'Content-Type: application/json',
'cache-control: no-cache'
));
} else if ($jobid) {
$ch = curl_init($endpoint . '/' . $jobid);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'X-Oc-Api-Key: ' . ELFINDER_ONLINE_CONVERT_APIKEY,
'cache-control: no-cache'
));
}
if ($ch) {
$response = curl_exec($ch);
$info = curl_getinfo($ch);
$error = curl_error($ch);
curl_close($ch);
if (!empty($error)) {
$res = array('error' => $error);
} else {
$data = json_decode($response, true);
if (isset($data['status']) && isset($data['status']['code']) && $data['status']['code'] === 'completed') {
/** @var elFinderSession $session */
$session = $this->elfinder->getSession();
$urlContentSaveIds = $session->get('urlContentSaveIds', array());
$urlContentSaveIds['OnlineConvert-' . $data['id']] = true;
$session->set('urlContentSaveIds', $urlContentSaveIds);
}
$res = array('apires' => $data);
}
return $res;
} else {
return array('error' => array('errCmdParams', 'editor.OnlineConvert.api'));
}
}
}
@@ -0,0 +1,12 @@
<?php
class elFinderEditorZipArchive extends elFinderEditor
{
public function enabled()
{
return (!defined('ELFINDER_DISABLE_ZIPEDITOR') || !ELFINDER_DISABLE_ZIPEDITOR) &&
class_exists('Barryvdh\elFinderFlysystemDriver\Driver') &&
class_exists('League\Flysystem\Filesystem') &&
class_exists('League\Flysystem\ZipArchive\ZipArchiveAdapter');
}
}
@@ -0,0 +1,225 @@
<?php
class elFinderEditorZohoOffice extends elFinderEditor
{
private static $curlTimeout = 20;
protected $allowed = array('init', 'save', 'chk');
protected $editor_settings = array(
'writer' => array(
'unit' => 'mm',
'view' => 'pageview'
),
'sheet' => array(
'country' => 'US'
),
'show' => array()
);
private $urls = array(
'writer' => 'https://api.office-integrator.com/writer/officeapi/v1/document',
'sheet' => 'https://api.office-integrator.com/sheet/officeapi/v1/spreadsheet',
'show' => 'https://api.office-integrator.com/show/officeapi/v1/presentation',
);
private $srvs = array(
'application/msword' => 'writer',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'writer',
'application/pdf' => 'writer',
'application/vnd.oasis.opendocument.text' => 'writer',
'application/rtf' => 'writer',
'text/html' => 'writer',
'application/vnd.ms-excel' => 'sheet',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'sheet',
'application/vnd.oasis.opendocument.spreadsheet' => 'sheet',
'application/vnd.sun.xml.calc' => 'sheet',
'text/csv' => 'sheet',
'text/tab-separated-values' => 'sheet',
'application/vnd.ms-powerpoint' => 'show',
'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'show',
'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => 'show',
'application/vnd.oasis.opendocument.presentation' => 'show',
'application/vnd.sun.xml.impress' => 'show',
);
private $myName = '';
protected function extentionNormrize($extention, $srvsName) {
switch($srvsName) {
case 'writer':
if (!in_array($extention, array('zdoc', 'docx', 'rtf', 'odt', 'html', 'txt'))) {
$extention = 'docx';
}
break;
case 'sheet':
if (!in_array($extention, array('zsheet', 'xls', 'xlsx', 'ods', 'csv', 'tsv'))) {
$extention = 'xlsx';
}
break;
case 'show':
if (!in_array($extention, array('zslides', 'pptx', 'pps', 'ppsx', 'odp', 'sxi'))) {
$extention = 'pptx';
}
break;
}
return $extention;
}
public function __construct($elfinder, $args)
{
parent::__construct($elfinder, $args);
$this->myName = preg_replace('/^elFinderEditor/i', '', get_class($this));
}
public function enabled()
{
return defined('ELFINDER_ZOHO_OFFICE_APIKEY') && ELFINDER_ZOHO_OFFICE_APIKEY && function_exists('curl_init');
}
public function init()
{
if (!defined('ELFINDER_ZOHO_OFFICE_APIKEY') || !function_exists('curl_init')) {
return array('error', array(elFinder::ERROR_CONF, '`ELFINDER_ZOHO_OFFICE_APIKEY` or curl extension'));
}
if (!empty($this->args['target'])) {
$fp = $cfile = null;
$hash = $this->args['target'];
/** @var elFinderVolumeDriver $srcVol */
if (($srcVol = $this->elfinder->getVolume($hash)) && ($file = $srcVol->file($hash))) {
$cdata = empty($this->args['cdata']) ? '' : $this->args['cdata'];
$cookie = $this->elfinder->getFetchCookieFile();
$save = false;
$ch = curl_init();
$conUrl = elFinder::getConnectorUrl();
curl_setopt($ch, CURLOPT_URL, $conUrl . (strpos($conUrl, '?') !== false? '&' : '?') . 'cmd=editor&name=' . $this->myName . '&method=chk&args[target]=' . rawurlencode($hash) . $cdata);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
if ($cookie) {
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie);
}
$res = curl_exec($ch);
curl_close($ch);
if ($res) {
if ($data = json_decode($res, true)) {
$save = !empty($data['cansave']);
}
}
if ($size = $file['size']) {
$src = $srcVol->open($hash);
$fp = tmpfile();
stream_copy_to_stream($src, $fp);
$srcVol->close($src, $hash);
$info = stream_get_meta_data($fp);
if ($info && !empty($info['uri'])) {
$srcFile = $info['uri'];
if (class_exists('CURLFile')) {
$cfile = new CURLFile($srcFile);
$cfile->setPostFilename($file['name']);
$cfile->setMimeType($file['mime']);
} else {
$cfile = '@' . $srcFile;
}
}
}
//$srv = $this->args['service'];
$srvsName = $this->srvs[$file['mime']];
$format = $this->extentionNormrize($srcVol->getExtentionByMime($file['mime']), $srvsName);
if (!$format) {
$format = substr($file['name'], strrpos($file['name'], '.') * -1);
}
$lang = $this->args['lang'];
if ($lang === 'jp') {
$lang = 'ja';
}
$data = array(
'apikey' => ELFINDER_ZOHO_OFFICE_APIKEY,
'callback_settings' => array(
'save_format' => $format,
'save_url_params' => array(
'hash' => $hash
)
),
'editor_settings' => $this->editor_settings[$srvsName],
'document_info' => array(
'document_name' => substr($file['name'], 0, strlen($file['name']) - strlen($format)- 1)
)
);
$data['editor_settings']['language'] = $lang;
if ($save) {
$conUrl = elFinder::getConnectorUrl();
$data['callback_settings']['save_url'] = $conUrl . (strpos($conUrl, '?') !== false? '&' : '?') . 'cmd=editor&name=' . $this->myName . '&method=save' . $cdata;
}
foreach($data as $_k => $_v) {
if (is_array($_v)){
$data[$_k] = json_encode($_v);
}
}
if ($cfile) {
$data['document'] = $cfile;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->urls[$srvsName]);
curl_setopt($ch, CURLOPT_TIMEOUT, self::$curlTimeout);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$res = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
$fp && fclose($fp);
if ($res && $res = @json_decode($res, true)) {
if (!empty($res['document_url'])) {
$ret = array('zohourl' => $res['document_url']);
if (!$save) {
$ret['warning'] = 'exportToSave';
}
return $ret;
} else {
$error = $res;
}
}
if ($error) {
return array('error' => is_string($error)? preg_split('/[\r\n]+/', $error) : 'Error code: ' . $error);
}
}
}
return array('error' => array('errCmdParams', 'editor.' . $this->myName . '.init'));
}
public function save()
{
if (!empty($_POST) && !empty($_POST['hash']) && !empty($_FILES) && !empty($_FILES['content'])) {
$hash = $_POST['hash'];
/** @var elFinderVolumeDriver $volume */
if ($volume = $this->elfinder->getVolume($hash)) {
if ($content = file_get_contents($_FILES['content']['tmp_name'])) {
if ($volume->putContents($hash, $content)) {
return array('raw' => true, 'error' => '', 'header' => 'HTTP/1.1 200 OK');
}
}
}
}
return array('raw' => true, 'error' => '', 'header' => 'HTTP/1.1 500 Internal Server Error');
}
public function chk()
{
$hash = $this->args['target'];
$res = false;
/** @var elFinderVolumeDriver $volume */
if ($volume = $this->elfinder->getVolume($hash)) {
if ($file = $volume->file($hash)) {
$res = (bool)$file['write'];
}
}
return array('cansave' => $res);
}
}
@@ -0,0 +1,79 @@
<?php
/**
* Abstract class of editor plugins.
*
* @author Naoki Sawada
*/
class elFinderEditor
{
/**
* Array of allowed method by request from client side.
*
* @var array
*/
protected $allowed = array();
/**
* elFinder instance
*
* @var object elFinder instance
*/
protected $elfinder;
/**
* Arguments
*
* @var array argValues
*/
protected $args;
/**
* Constructor.
*
* @param object $elfinder
* @param array $args
*/
public function __construct($elfinder, $args)
{
$this->elfinder = $elfinder;
$this->args = $args;
}
/**
* Return boolean that this plugin is enabled.
*
* @return bool
*/
public function enabled()
{
return true;
}
/**
* Return boolean that $name method is allowed.
*
* @param string $name
*
* @return bool
*/
public function isAllowedMethod($name)
{
$checker = array_flip($this->allowed);
return isset($checker[$name]);
}
/**
* Return $this->args value of the key
*
* @param string $key target key
* @param string $empty empty value
*
* @return mixed
*/
public function argValue($key, $empty = '')
{
return isset($this->args[$key]) ? $this->args[$key] : $empty;
}
}
@@ -0,0 +1,380 @@
<?php
/**
* Default elFinder connector
*
* @author Dmitry (dio) Levashov
**/
class elFinderConnector
{
/**
* elFinder instance
*
* @var elFinder
**/
protected $elFinder;
/**
* Options
*
* @var array
**/
protected $options = array();
/**
* Must be use output($data) $data['header']
*
* @var string
* @deprecated
**/
protected $header = '';
/**
* HTTP request method
*
* @var string
*/
protected $reqMethod = '';
/**
* Content type of output JSON
*
* @var string
*/
protected static $contentType = 'Content-Type: application/json; charset=utf-8';
/**
* Constructor
*
* @param $elFinder
* @param bool $debug
*
* @author Dmitry (dio) Levashov
*/
public function __construct($elFinder, $debug = false)
{
$this->elFinder = $elFinder;
$this->reqMethod = strtoupper($_SERVER["REQUEST_METHOD"]);
if ($debug) {
self::$contentType = 'Content-Type: text/plain; charset=utf-8';
}
}
/**
* Execute elFinder command and output result
*
* @return void
* @throws Exception
* @author Dmitry (dio) Levashov
*/
public function run()
{
$isPost = $this->reqMethod === 'POST';
$src = $isPost ? array_merge($_GET, $_POST) : $_GET;
$maxInputVars = (!$src || isset($src['targets'])) ? ini_get('max_input_vars') : null;
if ((!$src || $maxInputVars) && $rawPostData = file_get_contents('php://input')) {
// for max_input_vars and supports IE XDomainRequest()
$parts = explode('&', $rawPostData);
if (!$src || $maxInputVars < count($parts)) {
$src = array();
foreach ($parts as $part) {
list($key, $value) = array_pad(explode('=', $part), 2, '');
$key = rawurldecode($key);
if (preg_match('/^(.+?)\[([^\[\]]*)\]$/', $key, $m)) {
$key = $m[1];
$idx = $m[2];
if (!isset($src[$key])) {
$src[$key] = array();
}
if ($idx) {
$src[$key][$idx] = rawurldecode($value);
} else {
$src[$key][] = rawurldecode($value);
}
} else {
$src[$key] = rawurldecode($value);
}
}
$_POST = $this->input_filter($src);
$_REQUEST = $this->input_filter(array_merge_recursive($src, $_REQUEST));
}
}
if (isset($src['targets']) && $this->elFinder->maxTargets && count($src['targets']) > $this->elFinder->maxTargets) {
$this->output(array('error' => $this->elFinder->error(elFinder::ERROR_MAX_TARGTES)));
}
$cmd = isset($src['cmd']) ? $src['cmd'] : '';
$args = array();
if (!function_exists('json_encode')) {
$error = $this->elFinder->error(elFinder::ERROR_CONF, elFinder::ERROR_CONF_NO_JSON);
$this->output(array('error' => '{"error":["' . implode('","', $error) . '"]}', 'raw' => true));
}
if (!$this->elFinder->loaded()) {
$this->output(array('error' => $this->elFinder->error(elFinder::ERROR_CONF, elFinder::ERROR_CONF_NO_VOL), 'debug' => $this->elFinder->mountErrors));
}
// telepat_mode: on
if (!$cmd && $isPost) {
$this->output(array('error' => $this->elFinder->error(elFinder::ERROR_UPLOAD, elFinder::ERROR_UPLOAD_TOTAL_SIZE), 'header' => 'Content-Type: text/html'));
}
// telepat_mode: off
if (!$this->elFinder->commandExists($cmd)) {
$this->output(array('error' => $this->elFinder->error(elFinder::ERROR_UNKNOWN_CMD)));
}
// collect required arguments to exec command
$hasFiles = false;
foreach ($this->elFinder->commandArgsList($cmd) as $name => $req) {
if ($name === 'FILES') {
if (isset($_FILES)) {
$hasFiles = true;
} elseif ($req) {
$this->output(array('error' => $this->elFinder->error(elFinder::ERROR_INV_PARAMS, $cmd)));
}
} else {
$arg = isset($src[$name]) ? $src[$name] : '';
if (!is_array($arg) && $req !== '') {
$arg = trim($arg);
}
if ($req && $arg === '') {
$this->output(array('error' => $this->elFinder->error(elFinder::ERROR_INV_PARAMS, $cmd)));
}
$args[$name] = $arg;
}
}
$args['debug'] = isset($src['debug']) ? !!$src['debug'] : false;
$args = $this->input_filter($args);
if ($hasFiles) {
$args['FILES'] = $_FILES;
}
try {
$this->output($this->elFinder->exec($cmd, $args));
} catch (elFinderAbortException $e) {
// connection aborted
// unlock session data for multiple access
$this->elFinder->getSession()->close();
// HTTP response code
header('HTTP/1.0 204 No Content');
// clear output buffer
while (ob_get_level() && ob_end_clean()) {
}
exit();
}
}
/**
* Sets the header.
*
* @param array|string $value HTTP header(s)
*/
public function setHeader($value)
{
$this->header = $value;
}
/**
* Output json
*
* @param array data to output
*
* @return void
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov
*/
protected function output(array $data)
{
// unlock session data for multiple access
$this->elFinder->getSession()->close();
// client disconnect should abort
ignore_user_abort(false);
if ($this->header) {
self::sendHeader($this->header);
}
if (isset($data['pointer'])) {
// set time limit to 0
elFinder::extendTimeLimit(0);
// send optional header
if (!empty($data['header'])) {
self::sendHeader($data['header']);
}
// clear output buffer
while (ob_get_level() && ob_end_clean()) {
}
$toEnd = true;
$fp = $data['pointer'];
$sendData = !($this->reqMethod === 'HEAD' || !empty($data['info']['xsendfile']));
$psize = null;
if (($this->reqMethod === 'GET' || !$sendData)
&& (elFinder::isSeekableStream($fp) || elFinder::isSeekableUrl($fp))
&& (array_search('Accept-Ranges: none', headers_list()) === false)) {
header('Accept-Ranges: bytes');
if (!empty($_SERVER['HTTP_RANGE'])) {
$size = $data['info']['size'];
$end = $size - 1;
if (preg_match('/bytes=(\d*)-(\d*)(,?)/i', $_SERVER['HTTP_RANGE'], $matches)) {
if (empty($matches[3])) {
if (empty($matches[1]) && $matches[1] !== '0') {
$start = $size - $matches[2];
} else {
$start = intval($matches[1]);
if (!empty($matches[2])) {
$end = intval($matches[2]);
if ($end >= $size) {
$end = $size - 1;
}
$toEnd = ($end == ($size - 1));
}
}
$psize = $end - $start + 1;
header('HTTP/1.1 206 Partial Content');
header('Content-Length: ' . $psize);
header('Content-Range: bytes ' . $start . '-' . $end . '/' . $size);
// Apache mod_xsendfile dose not support range request
if (isset($data['info']['xsendfile']) && strtolower($data['info']['xsendfile']) === 'x-sendfile') {
if (function_exists('header_remove')) {
header_remove($data['info']['xsendfile']);
} else {
header($data['info']['xsendfile'] . ':');
}
unset($data['info']['xsendfile']);
if ($this->reqMethod !== 'HEAD') {
$sendData = true;
}
}
$sendData && !elFinder::isSeekableUrl($fp) && fseek($fp, $start);
}
}
}
if ($sendData && is_null($psize)) {
elFinder::rewind($fp);
}
} else {
header('Accept-Ranges: none');
if (isset($data['info']) && !$data['info']['size']) {
if (function_exists('header_remove')) {
header_remove('Content-Length');
} else {
header('Content-Length:');
}
}
}
if ($sendData) {
if ($toEnd || elFinder::isSeekableUrl($fp)) {
// PHP < 5.6 has a bug of fpassthru
// see https://bugs.php.net/bug.php?id=66736
if (version_compare(PHP_VERSION, '5.6', '<')) {
file_put_contents('php://output', $fp);
} else {
fpassthru($fp);
}
} else {
$out = fopen('php://output', 'wb');
stream_copy_to_stream($fp, $out, $psize);
fclose($out);
}
}
if (!empty($data['volume'])) {
$data['volume']->close($fp, $data['info']['hash']);
} else {
fclose($fp);
}
exit();
} else {
self::outputJson($data);
exit(0);
}
}
/**
* Remove null & stripslashes applies on "magic_quotes_gpc"
*
* @param mixed $args
*
* @return mixed
* @author Naoki Sawada
*/
protected function input_filter($args)
{
static $magic_quotes_gpc = NULL;
if ($magic_quotes_gpc === NULL)
$magic_quotes_gpc = (version_compare(PHP_VERSION, '5.4', '<') && get_magic_quotes_gpc());
if (is_array($args)) {
return array_map(array(& $this, 'input_filter'), $args);
}
$res = str_replace("\0", '', $args);
$magic_quotes_gpc && ($res = stripslashes($res));
return $res;
}
/**
* Send HTTP header
*
* @param string|array $header optional header
*/
protected static function sendHeader($header = null)
{
if ($header) {
if (is_array($header)) {
foreach ($header as $h) {
header($h);
}
} else {
header($header);
}
}
}
/**
* Output JSON
*
* @param array $data
*/
public static function outputJson($data)
{
// send header
$header = isset($data['header']) ? $data['header'] : self::$contentType;
self::sendHeader($header);
unset($data['header']);
if (!empty($data['raw']) && isset($data['error'])) {
$out = $data['error'];
} else {
if (isset($data['debug']) && isset($data['debug']['backendErrors'])) {
$data['debug']['backendErrors'] = array_merge($data['debug']['backendErrors'], elFinder::$phpErrors);
}
$out = json_encode($data);
}
// clear output buffer
while (ob_get_level() && ob_end_clean()) {
}
header('Content-Length: ' . strlen($out));
echo $out;
flush();
}
}// END class
@@ -0,0 +1,380 @@
<?php
use League\Flysystem\Filesystem;
use League\Flysystem\Adapter\Local;
use League\Flysystem\Cached\CachedAdapter;
use League\Flysystem\Cached\Storage\Adapter as ACache;
use Hypweb\Flysystem\GoogleDrive\GoogleDriveAdapter;
use Hypweb\Flysystem\Cached\Extra\Hasdir;
use Hypweb\Flysystem\Cached\Extra\DisableEnsureParentDirectories;
use Hypweb\elFinderFlysystemDriverExt\Driver as ExtDriver;
elFinder::$netDrivers['googledrive'] = 'FlysystemGoogleDriveNetmount';
if (!class_exists('elFinderVolumeFlysystemGoogleDriveCache', false)) {
class elFinderVolumeFlysystemGoogleDriveCache extends ACache
{
use Hasdir;
use DisableEnsureParentDirectories;
}
}
class elFinderVolumeFlysystemGoogleDriveNetmount extends ExtDriver
{
public function __construct()
{
parent::__construct();
$opts = array(
'acceptedName' => '#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#',
'rootCssClass' => 'elfinder-navbar-root-googledrive',
'gdAlias' => '%s@GDrive',
'gdCacheDir' => __DIR__ . '/.tmp',
'gdCachePrefix' => 'gd-',
'gdCacheExpire' => 600
);
$this->options = array_merge($this->options, $opts);
}
/**
* Prepare driver before mount volume.
* Return true if volume is ready.
*
* @return bool
**/
protected function init()
{
if (empty($this->options['icon'])) {
$this->options['icon'] = true;
}
if ($res = parent::init()) {
if ($this->options['icon'] === true) {
unset($this->options['icon']);
}
// enable command archive
$this->options['useRemoteArchive'] = true;
}
return $res;
}
/**
* Prepare
* Call from elFinder::netmout() before volume->mount()
*
* @param $options
*
* @return Array
* @author Naoki Sawada
*/
public function netmountPrepare($options)
{
if (empty($options['client_id']) && defined('ELFINDER_GOOGLEDRIVE_CLIENTID')) {
$options['client_id'] = ELFINDER_GOOGLEDRIVE_CLIENTID;
}
if (empty($options['client_secret']) && defined('ELFINDER_GOOGLEDRIVE_CLIENTSECRET')) {
$options['client_secret'] = ELFINDER_GOOGLEDRIVE_CLIENTSECRET;
}
if (!isset($options['pass'])) {
$options['pass'] = '';
}
try {
$client = new \Google_Client();
$client->setClientId($options['client_id']);
$client->setClientSecret($options['client_secret']);
if ($options['pass'] === 'reauth') {
$options['pass'] = '';
$this->session->set('GoogleDriveAuthParams', [])->set('GoogleDriveTokens', []);
} else if ($options['pass'] === 'googledrive') {
$options['pass'] = '';
}
$options = array_merge($this->session->get('GoogleDriveAuthParams', []), $options);
if (!isset($options['access_token'])) {
$options['access_token'] = $this->session->get('GoogleDriveTokens', []);
$this->session->remove('GoogleDriveTokens');
}
$aToken = $options['access_token'];
$rootObj = $service = null;
if ($aToken) {
try {
$client->setAccessToken($aToken);
if ($client->isAccessTokenExpired()) {
$aToken = array_merge($aToken, $client->fetchAccessTokenWithRefreshToken());
$client->setAccessToken($aToken);
}
$service = new \Google_Service_Drive($client);
$rootObj = $service->files->get('root');
$options['access_token'] = $aToken;
$this->session->set('GoogleDriveAuthParams', $options);
} catch (Exception $e) {
$aToken = [];
$options['access_token'] = [];
if ($options['user'] !== 'init') {
$this->session->set('GoogleDriveAuthParams', $options);
return array('exit' => true, 'error' => elFinder::ERROR_REAUTH_REQUIRE);
}
}
}
$itpCare = isset($options['code']);
$code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : '');
if ($code || $options['user'] === 'init') {
if (empty($options['url'])) {
$options['url'] = elFinder::getConnectorUrl();
}
if (isset($options['id'])) {
$callback = $options['url'] . (strpos($options['url'], '?') !== false? '&' : '?') . 'cmd=netmount&protocol=googledrive&host=' . ($options['id'] === 'elfinder'? '1' : $options['id']);
$client->setRedirectUri($callback);
}
if (!$aToken && empty($code)) {
$client->setScopes([Google_Service_Drive::DRIVE]);
if (!empty($options['offline'])) {
$client->setApprovalPrompt('force');
$client->setAccessType('offline');
}
$url = $client->createAuthUrl();
$html = '<input id="elf-volumedriver-googledrive-host-btn" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" value="{msg:btnApprove}" type="button">';
$html .= '<script>
$("#' . $options['id'] . '").elfinder("instance").trigger("netmount", {protocol: "googledrive", mode: "makebtn", url: "' . $url . '"});
</script>';
if (empty($options['pass']) && $options['host'] !== '1') {
$options['pass'] = 'return';
$this->session->set('GoogleDriveAuthParams', $options);
return array('exit' => true, 'body' => $html);
} else {
$out = array(
'node' => $options['id'],
'json' => '{"protocol": "googledrive", "mode": "makebtn", "body" : "' . str_replace($html, '"', '\\"') . '", "error" : "' . elFinder::ERROR_ACCESS_DENIED . '"}',
'bind' => 'netmount'
);
return array('exit' => 'callback', 'out' => $out);
}
} else {
if ($code) {
if (!empty($options['id'])) {
$aToken = $client->fetchAccessTokenWithAuthCode($code);
$options['access_token'] = $aToken;
unset($options['code']);
$this->session->set('GoogleDriveTokens', $aToken)->set('GoogleDriveAuthParams', $options);
$out = array(
'node' => $options['id'],
'json' => '{"protocol": "googledrive", "mode": "done", "reset": 1}',
'bind' => 'netmount'
);
} else {
$nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host'];
$out = array(
'node' => $nodeid,
'json' => json_encode(array(
'protocol' => 'googledrive',
'host' => $nodeid,
'mode' => 'redirect',
'options' => array(
'id' => $nodeid,
'code'=> $code
)
)),
'bind' => 'netmount'
);
}
if (!$itpCare) {
return array('exit' => 'callback', 'out' => $out);
} else {
return array('exit' => true, 'body' => $out['json']);
}
}
$folders = [];
foreach ($service->files->listFiles([
'pageSize' => 1000,
'q' => 'trashed = false and mimeType = "application/vnd.google-apps.folder"'
]) as $f) {
$folders[$f->getId()] = $f->getName();
}
natcasesort($folders);
$folders = ['root' => $rootObj->getName()] + $folders;
$folders = json_encode($folders);
$json = '{"protocol": "googledrive", "mode": "done", "folders": ' . $folders . '}';
$options['pass'] = 'return';
$html = 'Google.com';
$html .= '<script>
$("#' . $options['id'] . '").elfinder("instance").trigger("netmount", ' . $json . ');
</script>';
$this->session->set('GoogleDriveAuthParams', $options);
return array('exit' => true, 'body' => $html);
}
}
} catch (Exception $e) {
$this->session->remove('GoogleDriveAuthParams')->remove('GoogleDriveTokens');
if (empty($options['pass'])) {
return array('exit' => true, 'body' => '{msg:' . elFinder::ERROR_ACCESS_DENIED . '}' . ' ' . $e->getMessage());
} else {
return array('exit' => true, 'error' => [elFinder::ERROR_ACCESS_DENIED, $e->getMessage()]);
}
}
if (!$aToken) {
return array('exit' => true, 'error' => elFinder::ERROR_REAUTH_REQUIRE);
}
if ($options['path'] === '/') {
$options['path'] = 'root';
}
try {
$file = $service->files->get($options['path']);
$options['alias'] = sprintf($this->options['gdAlias'], $file->getName());
if (!empty($this->options['netkey'])) {
elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']);
}
} catch (Google_Service_Exception $e) {
$err = json_decode($e->getMessage(), true);
if (isset($err['error']) && $err['error']['code'] == 404) {
return array('exit' => true, 'error' => [elFinder::ERROR_TRGDIR_NOT_FOUND, $options['path']]);
} else {
return array('exit' => true, 'error' => $e->getMessage());
}
} catch (Exception $e) {
return array('exit' => true, 'error' => $e->getMessage());
}
foreach (['host', 'user', 'pass', 'id', 'offline'] as $key) {
unset($options[$key]);
}
return $options;
}
/**
* process of on netunmount
* Drop table `dropbox` & rm thumbs
*
* @param $netVolumes
* @param $key
*
* @return bool
* @internal param array $options
*/
public function netunmount($netVolumes, $key)
{
$cache = $this->options['gdCacheDir'] . DIRECTORY_SEPARATOR . $this->options['gdCachePrefix'] . $this->netMountKey;
if (file_exists($cache) && is_writeable($cache)) {
unlink($cache);
}
if ($tmbs = glob($this->tmbPath . DIRECTORY_SEPARATOR . $this->netMountKey . '*')) {
foreach ($tmbs as $file) {
unlink($file);
}
}
return true;
}
/**
* "Mount" volume.
* Return true if volume available for read or write,
* false - otherwise
*
* @param array $opts
*
* @return bool
* @author Naoki Sawada
*/
public function mount(array $opts)
{
$creds = null;
if (isset($opts['access_token'])) {
$this->netMountKey = md5(join('-', array('googledrive', $opts['path'], (isset($opts['access_token']['refresh_token']) ? $opts['access_token']['refresh_token'] : $opts['access_token']['access_token']))));
}
$client = new \Google_Client();
$client->setClientId($opts['client_id']);
$client->setClientSecret($opts['client_secret']);
if (!empty($opts['access_token'])) {
$client->setAccessToken($opts['access_token']);
}
if ($this->needOnline && $client->isAccessTokenExpired()) {
try {
$creds = $client->fetchAccessTokenWithRefreshToken();
} catch (LogicException $e) {
$this->session->remove('GoogleDriveAuthParams');
throw $e;
}
}
$service = new \Google_Service_Drive($client);
// If path is not set, use the root
if (!isset($opts['path']) || $opts['path'] === '') {
$opts['path'] = 'root';
}
$googleDrive = new GoogleDriveAdapter($service, $opts['path'], ['useHasDir' => true]);
$opts['fscache'] = null;
if ($this->options['gdCacheDir'] && is_writeable($this->options['gdCacheDir'])) {
if ($this->options['gdCacheExpire']) {
$opts['fscache'] = new elFinderVolumeFlysystemGoogleDriveCache(new Local($this->options['gdCacheDir']), $this->options['gdCachePrefix'] . $this->netMountKey, $this->options['gdCacheExpire']);
}
}
if ($opts['fscache']) {
$filesystem = new Filesystem(new CachedAdapter($googleDrive, $opts['fscache']));
} else {
$filesystem = new Filesystem($googleDrive);
}
$opts['driver'] = 'FlysystemExt';
$opts['filesystem'] = $filesystem;
$opts['separator'] = '/';
$opts['checkSubfolders'] = true;
if (!isset($opts['alias'])) {
$opts['alias'] = 'GoogleDrive';
}
if ($res = parent::mount($opts)) {
// update access_token of session data
if ($creds) {
$netVolumes = $this->session->get('netvolume');
$netVolumes[$this->netMountKey]['access_token'] = array_merge($netVolumes[$this->netMountKey]['access_token'], $creds);
$this->session->set('netvolume', $netVolumes);
}
}
return $res;
}
/**
* @inheritdoc
*/
protected function tmbname($stat)
{
return $this->netMountKey . substr(substr($stat['hash'], strlen($this->id)), -38) . $stat['ts'] . '.png';
}
/**
* Return debug info for client.
*
* @return array
**/
public function debug()
{
$res = parent::debug();
if (!empty($this->options['netkey']) && empty($this->options['refresh_token']) && $this->options['access_token'] && isset($this->options['access_token']['refresh_token'])) {
$res['refresh_token'] = $this->options['access_token']['refresh_token'];
}
return $res;
}
}
@@ -0,0 +1,113 @@
<?php
/**
* elFinder Plugin Abstract
*
* @package elfinder
* @author Naoki Sawada
* @license New BSD
*/
class elFinderPlugin
{
/**
* This plugin's options
*
* @var array
*/
protected $opts = array();
/**
* Get current volume's options
*
* @param object $volume
*
* @return array options
*/
protected function getCurrentOpts($volume)
{
$name = substr(get_class($this), 14); // remove "elFinderPlugin"
$opts = $this->opts;
if (is_object($volume)) {
$volOpts = $volume->getOptionsPlugin($name);
if (is_array($volOpts)) {
$opts = array_merge($opts, $volOpts);
}
}
return $opts;
}
/**
* Is enabled with options
*
* @param array $opts
* @param elFinder $elfinder
*
* @return boolean
*/
protected function iaEnabled($opts, $elfinder = null)
{
if (!$opts['enable']) {
return false;
}
// check post var 'contentSaveId' to disable this plugin
if ($elfinder && !empty($opts['disableWithContentSaveId'])) {
$session = $elfinder->getSession();
$urlContentSaveIds = $session->get('urlContentSaveIds', array());
if (!empty(elFinder::$currentArgs['contentSaveId']) && ($contentSaveId = elFinder::$currentArgs['contentSaveId'])) {
if (!empty($urlContentSaveIds[$contentSaveId])) {
$elfinder->removeUrlContentSaveId($contentSaveId);
return false;
}
}
}
if (isset($opts['onDropWith']) && !is_null($opts['onDropWith'])) {
// plugin disabled by default, enabled only if given key is pressed
if (isset($_REQUEST['dropWith']) && $_REQUEST['dropWith']) {
$onDropWith = $opts['onDropWith'];
$action = (int)$_REQUEST['dropWith'];
if (!is_array($onDropWith)) {
$onDropWith = array($onDropWith);
}
foreach ($onDropWith as $key) {
$key = (int)$key;
if (($action & $key) === $key) {
return true;
}
}
}
return false;
}
if (isset($opts['offDropWith']) && !is_null($opts['offDropWith']) && isset($_REQUEST['dropWith'])) {
// plugin enabled by default, disabled only if given key is pressed
$offDropWith = $opts['offDropWith'];
$action = (int)$_REQUEST['dropWith'];
if (!is_array($offDropWith)) {
$offDropWith = array($offDropWith);
}
$res = true;
foreach ($offDropWith as $key) {
$key = (int)$key;
if ($key === 0) {
if ($action === 0) {
$res = false;
break;
}
} else {
if (($action & $key) === $key) {
$res = false;
break;
}
}
}
if (!$res) {
return false;
}
}
return true;
}
}
@@ -0,0 +1,335 @@
<?php
/**
* elFinder - file manager for web.
* Session Wrapper Class.
*
* @package elfinder
* @author Naoki Sawada
**/
class elFinderSession implements elFinderSessionInterface
{
/**
* A flag of session started
*
* @var boolean
*/
protected $started = false;
/**
* To fix PHP bug that duplicate Set-Cookie header to be sent
*
* @var boolean
* @see https://bugs.php.net/bug.php?id=75554
*/
protected $fixCookieRegist = false;
/**
* Array of session keys of this instance
*
* @var array
*/
protected $keys = array();
/**
* Is enabled base64encode
*
* @var boolean
*/
protected $base64encode = false;
/**
* Default options array
*
* @var array
*/
protected $opts = array(
'base64encode' => false,
'keys' => array(
'default' => 'elFinderCaches',
'netvolume' => 'elFinderNetVolumes'
),
'cookieParams' => array()
);
/**
* Constractor
*
* @param array $opts The options
*
* @return self Instanse of this class
*/
public function __construct($opts)
{
$this->opts = array_merge($this->opts, $opts);
$this->base64encode = !empty($this->opts['base64encode']);
$this->keys = $this->opts['keys'];
if (function_exists('apache_get_version') || $this->opts['cookieParams']) {
$this->fixCookieRegist = true;
}
}
/**
* {@inheritdoc}
*/
public function get($key, $empty = null)
{
$closed = false;
if (!$this->started) {
$closed = true;
$this->start();
}
$data = null;
if ($this->started) {
$session =& $this->getSessionRef($key);
$data = $session;
if ($data && $this->base64encode) {
$data = $this->decodeData($data);
}
}
$checkFn = null;
if (!is_null($empty)) {
if (is_string($empty)) {
$checkFn = 'is_string';
} elseif (is_array($empty)) {
$checkFn = 'is_array';
} elseif (is_object($empty)) {
$checkFn = 'is_object';
} elseif (is_float($empty)) {
$checkFn = 'is_float';
} elseif (is_int($empty)) {
$checkFn = 'is_int';
}
}
if (is_null($data) || ($checkFn && !$checkFn($data))) {
$session = $data = $empty;
}
if ($closed) {
$this->close();
}
return $data;
}
/**
* {@inheritdoc}
*/
public function start()
{
set_error_handler(array($this, 'session_start_error'), E_NOTICE | E_WARNING);
// apache2 SAPI has a bug of session cookie register
// see https://bugs.php.net/bug.php?id=75554
// see https://github.com/php/php-src/pull/3231
if ($this->fixCookieRegist === true) {
if ((int)ini_get('session.use_cookies') === 1) {
if (ini_set('session.use_cookies', 0) === false) {
$this->fixCookieRegist = false;
}
}
}
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
if (session_status() !== PHP_SESSION_ACTIVE) {
session_start();
}
} else {
session_start();
}
$this->started = session_id() ? true : false;
restore_error_handler();
return $this;
}
/**
* Get variable reference of $_SESSION
*
* @param string $key key of $_SESSION array
*
* @return mixed|null
*/
protected function & getSessionRef($key)
{
$session = null;
if ($this->started) {
list($cat, $name) = array_pad(explode('.', $key, 2), 2, null);
if (is_null($name)) {
if (!isset($this->keys[$cat])) {
$name = $cat;
$cat = 'default';
}
}
if (isset($this->keys[$cat])) {
$cat = $this->keys[$cat];
} else {
$name = $cat . '.' . $name;
$cat = $this->keys['default'];
}
if (is_null($name)) {
if (!isset($_SESSION[$cat])) {
$_SESSION[$cat] = null;
}
$session =& $_SESSION[$cat];
} else {
if (!isset($_SESSION[$cat]) || !is_array($_SESSION[$cat])) {
$_SESSION[$cat] = array();
}
if (!isset($_SESSION[$cat][$name])) {
$_SESSION[$cat][$name] = null;
}
$session =& $_SESSION[$cat][$name];
}
}
return $session;
}
/**
* base64 decode of session val
*
* @param $data
*
* @return bool|mixed|string|null
*/
protected function decodeData($data)
{
if ($this->base64encode) {
if (is_string($data)) {
if (($data = base64_decode($data)) !== false) {
$data = unserialize($data);
} else {
$data = null;
}
} else {
$data = null;
}
}
return $data;
}
/**
* {@inheritdoc}
*/
public function close()
{
if ($this->started) {
if ($this->fixCookieRegist === true) {
// regist cookie only once for apache2 SAPI
$cParm = session_get_cookie_params();
if ($this->opts['cookieParams'] && is_array($this->opts['cookieParams'])) {
$cParm = array_merge($cParm, $this->opts['cookieParams']);
}
if (version_compare(PHP_VERSION, '7.3', '<')) {
setcookie(session_name(), session_id(), 0, $cParm['path'] . (!empty($cParm['SameSite'])? '; SameSite=' . $cParm['SameSite'] : ''), $cParm['domain'], $cParm['secure'], $cParm['httponly']);
} else {
$allows = array('expires' => true, 'path' => true, 'domain' => true, 'secure' => true, 'httponly' => true, 'samesite' => true);
foreach(array_keys($cParm) as $_k) {
if (!isset($allows[$_k])) {
unset($cParm[$_k]);
}
}
setcookie(session_name(), session_id(), $cParm);
}
$this->fixCookieRegist = false;
}
session_write_close();
}
$this->started = false;
return $this;
}
/**
* {@inheritdoc}
*/
public function set($key, $data)
{
$closed = false;
if (!$this->started) {
$closed = true;
$this->start();
}
$session =& $this->getSessionRef($key);
if ($this->base64encode) {
$data = $this->encodeData($data);
}
$session = $data;
if ($closed) {
$this->close();
}
return $this;
}
/**
* base64 encode for session val
*
* @param $data
*
* @return string
*/
protected function encodeData($data)
{
if ($this->base64encode) {
$data = base64_encode(serialize($data));
}
return $data;
}
/**
* {@inheritdoc}
*/
public function remove($key)
{
$closed = false;
if (!$this->started) {
$closed = true;
$this->start();
}
list($cat, $name) = array_pad(explode('.', $key, 2), 2, null);
if (is_null($name)) {
if (!isset($this->keys[$cat])) {
$name = $cat;
$cat = 'default';
}
}
if (isset($this->keys[$cat])) {
$cat = $this->keys[$cat];
} else {
$name = $cat . '.' . $name;
$cat = $this->keys['default'];
}
if (is_null($name)) {
unset($_SESSION[$cat]);
} else {
if (isset($_SESSION[$cat]) && is_array($_SESSION[$cat])) {
unset($_SESSION[$cat][$name]);
}
}
if ($closed) {
$this->close();
}
return $this;
}
/**
* sessioin error handler (Only for suppression of error at session start)
*
* @param $errno
* @param $errstr
*/
protected function session_start_error($errno, $errstr)
{
}
}
@@ -0,0 +1,57 @@
<?php
/**
* elFinder - file manager for web.
* Session Wrapper Interface.
*
* @package elfinder
* @author Naoki Sawada
**/
interface elFinderSessionInterface
{
/**
* Session start
*
* @return self
**/
public function start();
/**
* Session write & close
*
* @return self
**/
public function close();
/**
* Get session data
* This method must be equipped with an automatic start / close.
*
* @param string $key Target key
* @param mixed $empty Return value of if session target key does not exist
*
* @return mixed
**/
public function get($key, $empty = '');
/**
* Set session data
* This method must be equipped with an automatic start / close.
*
* @param string $key Target key
* @param mixed $data Value
*
* @return self
**/
public function set($key, $data);
/**
* Get session data
*
* @param string $key Target key
*
* @return self
**/
public function remove($key);
}
@@ -0,0 +1,315 @@
<?php
/**
* elFinder driver for Volume Group.
*
* @author Naoki Sawada
**/
class elFinderVolumeGroup extends elFinderVolumeDriver
{
/**
* Driver id
* Must be started from letter and contains [a-z0-9]
* Used as part of volume id
*
* @var string
**/
protected $driverId = 'g';
/**
* Constructor
* Extend options with required fields
*/
public function __construct()
{
$this->options['type'] = 'group';
$this->options['path'] = '/';
$this->options['dirUrlOwn'] = true;
$this->options['syncMinMs'] = 0;
$this->options['tmbPath'] = '';
$this->options['disabled'] = array(
'archive',
'copy',
'cut',
'duplicate',
'edit',
'empty',
'extract',
'getfile',
'mkdir',
'mkfile',
'paste',
'resize',
'rm',
'upload'
);
}
/*********************************************************************/
/* FS API */
/*********************************************************************/
/*********************** paths/urls *************************/
/**
* @inheritdoc
**/
protected function _dirname($path)
{
return '/';
}
/**
* {@inheritDoc}
**/
protected function _basename($path)
{
return '';
}
/**
* {@inheritDoc}
**/
protected function _joinPath($dir, $name)
{
return '/' . $name;
}
/**
* {@inheritDoc}
**/
protected function _normpath($path)
{
return '/';
}
/**
* {@inheritDoc}
**/
protected function _relpath($path)
{
return '/';
}
/**
* {@inheritDoc}
**/
protected function _abspath($path)
{
return '/';
}
/**
* {@inheritDoc}
**/
protected function _path($path)
{
return '/';
}
/**
* {@inheritDoc}
**/
protected function _inpath($path, $parent)
{
return false;
}
/***************** file stat ********************/
/**
* {@inheritDoc}
**/
protected function _stat($path)
{
if ($path === '/') {
return array(
'size' => 0,
'ts' => 0,
'mime' => 'directory',
'read' => true,
'write' => false,
'locked' => true,
'hidden' => false,
'dirs' => 0
);
}
return false;
}
/**
* {@inheritDoc}
**/
protected function _subdirs($path)
{
return false;
}
/**
* {@inheritDoc}
**/
protected function _dimensions($path, $mime)
{
return false;
}
/******************** file/dir content *********************/
/**
* {@inheritDoc}
**/
protected function readlink($path)
{
return null;
}
/**
* {@inheritDoc}
**/
protected function _scandir($path)
{
return array();
}
/**
* {@inheritDoc}
**/
protected function _fopen($path, $mode = 'rb')
{
return false;
}
/**
* {@inheritDoc}
**/
protected function _fclose($fp, $path = '')
{
return true;
}
/******************** file/dir manipulations *************************/
/**
* {@inheritDoc}
**/
protected function _mkdir($path, $name)
{
return false;
}
/**
* {@inheritDoc}
**/
protected function _mkfile($path, $name)
{
return false;
}
/**
* {@inheritDoc}
**/
protected function _symlink($source, $targetDir, $name)
{
return false;
}
/**
* {@inheritDoc}
**/
protected function _copy($source, $targetDir, $name)
{
return false;
}
/**
* {@inheritDoc}
**/
protected function _move($source, $targetDir, $name)
{
return false;
}
/**
* {@inheritDoc}
**/
protected function _unlink($path)
{
return false;
}
/**
* {@inheritDoc}
**/
protected function _rmdir($path)
{
return false;
}
/**
* {@inheritDoc}
**/
protected function _save($fp, $dir, $name, $stat)
{
return false;
}
/**
* {@inheritDoc}
**/
protected function _getContents($path)
{
return false;
}
/**
* {@inheritDoc}
**/
protected function _filePutContents($path, $content)
{
return false;
}
/**
* {@inheritDoc}
**/
protected function _checkArchivers()
{
return;
}
/**
* {@inheritDoc}
**/
protected function _chmod($path, $mode)
{
return false;
}
/**
* {@inheritDoc}
**/
protected function _findSymlinks($path)
{
return false;
}
/**
* {@inheritDoc}
**/
protected function _extract($path, $arc)
{
return false;
}
/**
* {@inheritDoc}
**/
protected function _archive($dir, $files, $name, $arc)
{
return false;
}
}
@@ -0,0 +1,853 @@
<?php
/**
* Simple elFinder driver for SFTP using phpseclib 1
*
* @author Dmitry (dio) Levashov
* @author Cem (discofever), sitecode
* @reference http://phpseclib.sourceforge.net/sftp/2.0/examples.html
**/
class elFinderVolumeSFTPphpseclib extends elFinderVolumeFTP {
/**
* Simple hack that could break for quick compatibility with phpseclib version 1-3
* Same value substitue for reference NET_SFTP_LOCAL_FILE and SFTP::SOURCE_LOCAL_FILE
*/
const NET_SFTP_LOCAL_FILE = 1;
/**
* Constructor
* Extend options with required fields
*
* @author Dmitry (dio) Levashov
* @author Cem (DiscoFever)
*/
public function __construct()
{
$opts = array(
'host' => 'localhost',
'user' => '',
'pass' => '',
'port' => 22,
'path' => '/',
'timeout' => 20,
'owner' => true,
'tmbPath' => '',
'tmpPath' => '',
'separator' => '/',
'phpseclibDir' => '../phpseclib/',
'connectCallback' => null, //provide your own already instantiated phpseclib $Sftp object returned by this callback
//'connectCallback'=> function($options) {
// //load and instantiate phpseclib $sftp
// return $sftp;
// },
'checkSubfolders' => -1,
'dirMode' => 0755,
'fileMode' => 0644,
'rootCssClass' => 'elfinder-navbar-root-ftp',
);
$this->options = array_merge($this->options, $opts);
$this->options['mimeDetect'] = 'internal';
}
/**
* Prepare
* Call from elFinder::netmout() before volume->mount()
*
* @param $options
*
* @return array volume root options
* @author Naoki Sawada
*/
public function netmountPrepare($options)
{
$options['statOwner'] = true;
$options['allowChmodReadOnly'] = true;
$options['acceptedName'] = '#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#';
return $options;
}
/*********************************************************************/
/* INIT AND CONFIGURE */
/*********************************************************************/
/**
* Prepare SFTP connection
* Connect to remote server and check if credentials are correct, if so, store the connection
*
* @return bool
* @author Dmitry (dio) Levashov
* @author Cem (DiscoFever)
**/
protected function init()
{
if (!$this->options['connectCallback']) {
if (!$this->options['host']
|| !$this->options['port']) {
return $this->setError('Required options undefined.');
}
if (!$this->options['path']) {
$this->options['path'] = '/';
}
// make net mount key
$this->netMountKey = md5(join('-', array('sftpphpseclib', $this->options['host'], $this->options['port'], $this->options['path'], $this->options['user'])));
set_include_path(get_include_path() . PATH_SEPARATOR . getcwd().'/'.$this->options['phpseclibDir']);
include_once('Net/SFTP.php');
if (!class_exists('Net_SFTP')) {
return $this->setError('SFTP extension not loaded. Install phpseclib version 1: http://phpseclib.sourceforge.net/ Set option "phpseclibDir" accordingly.');
}
// remove protocol from host
$scheme = parse_url($this->options['host'], PHP_URL_SCHEME);
if ($scheme) {
$this->options['host'] = substr($this->options['host'], strlen($scheme) + 3);
}
} else {
// make net mount key
$this->netMountKey = md5(join('-', array('sftpphpseclib', $this->options['path'])));
}
// normalize root path
$this->root = $this->options['path'] = $this->_normpath($this->options['path']);
if (empty($this->options['alias'])) {
$this->options['alias'] = $this->options['user'] . '@' . $this->options['host'];
if (!empty($this->options['netkey'])) {
elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']);
}
}
$this->rootName = $this->options['alias'];
$this->options['separator'] = '/';
if (is_null($this->options['syncChkAsTs'])) {
$this->options['syncChkAsTs'] = true;
}
return $this->needOnline? $this->connect() : true;
}
/**
* Configure after successfull mount.
*
* @return void
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov
*/
protected function configure()
{
parent::configure();
if (!$this->tmp) {
$this->disabled[] = 'mkfile';
$this->disabled[] = 'paste';
$this->disabled[] = 'upload';
$this->disabled[] = 'edit';
//$this->disabled[] = 'archive';
//$this->disabled[] = 'extract';
}
$this->disabled[] = 'archive';
$this->disabled[] = 'extract';
}
/**
* Connect to sftp server
*
* @return bool
* @author sitecode
**/
protected function connect()
{
//use ca
if ($this->options['connectCallback']) {
$this->connect = $this->options['connectCallback']($this->options);
if (!$this->connect || !$this->connect->isConnected()) {
return $this->setError('Unable to connect successfully');
}
return true;
}
try{
$host = $this->options['host'] . ($this->options['port'] != 22 ? ':' . $this->options['port'] : '');
$this->connect = new Net_SFTP($host);
//TODO check fingerprint before login, fail if no match to last time
if (!$this->connect->login($this->options['user'], $this->options['pass'])) {
return $this->setError('Unable to connect to SFTP server ' . $host);
}
} catch (Exception $e) {
return $this->setError('Error while connecting to SFTP server ' . $host . ': ' . $e->getMessage());
}
if (!$this->connect->chdir($this->root)
/*|| $this->root != $this->connect->pwd()*/) {
//$this->umount();
return $this->setError('Unable to open root folder.');
}
return true;
}
/**
* Call rawlist
*
* @param string $path
*
* @return array
*/
protected function ftpRawList($path)
{
return $this->connect->rawlist($path ?: '.') ?: [];
}
/*********************************************************************/
/* FS API */
/*********************************************************************/
/**
* Close opened connection
*
* @return void
* @author Dmitry (dio) Levashov
**/
public function umount()
{
$this->connect && $this->connect->disconnect();
}
/**
* Parse line from rawlist() output and return file stat (array)
*
* @param array $info from rawlist() output
* @param $base
* @param bool $nameOnly
*
* @return array
* @author Dmitry Levashov
*/
protected function parseRaw($info, $base, $nameOnly = false)
{
$stat = array();
if ($info['filename'] == '.' || $info['filename'] == '..') {
return false;
}
$name = $info['filename'];
//for compatability with phpseclib version 2/3
if (empty($info['permissions'])) {
$info['permissions'] = $info['mode'];
}
if ($info['type'] === 3) {
// check recursive processing
if ($this->cacheDirTarget && $this->_joinPath($base, $name) !== $this->cacheDirTarget) {
return array();
}
if (!$nameOnly) {
$target = $this->connect->readlink($name);
if (substr($target, 0, 1) !== $this->separator) {
$target = $this->getFullPath($target, $base);
}
$target = $this->_normpath($target);
$stat['name'] = $name;
$stat['target'] = $target;
return $stat;
}
}
if ($nameOnly) {
return array('name' => $name);
}
$stat['ts'] = $info['mtime'];
if ($this->options['statOwner']) {
$stat['owner'] = $info['uid'];
$stat['group'] = $info['gid'];
$stat['perm'] = $info['permissions'];
$stat['isowner'] = isset($stat['owner']) ? ($this->options['owner'] ? true : ($stat['owner'] == $this->options['user'])) : true;
}
$owner_computed = isset($stat['isowner']) ? $stat['isowner'] : $this->options['owner'];
$perm = $this->parsePermissions($info['permissions'], $owner_computed);
$stat['name'] = $name;
if ($info['type'] === NET_SFTP_TYPE_DIRECTORY) {
$stat['mime'] = 'directory';
$stat['size'] = 0;
} elseif ($info['type'] === NET_SFTP_TYPE_SYMLINK) {
$stat['mime'] = 'symlink';
$stat['size'] = 0;
} else {
$stat['mime'] = $this->mimetype($stat['name'], true);
$stat['size'] = $info['size'];
}
$stat['read'] = $perm['read'];
$stat['write'] = $perm['write'];
return $stat;
}
/**
* Parse permissions string. Return array(read => true/false, write => true/false)
*
* @param int $perm
* The isowner parameter is computed by the caller.
* If the owner parameter in the options is true, the user is the actual owner of all objects even if the user used in the ftp Login
* is different from the file owner id.
* If the owner parameter is false to understand if the user is the file owner we compare the ftp user with the file owner id.
* @param Boolean $isowner . Tell if the current user is the owner of the object.
*
* @return array
* @author Dmitry (dio) Levashov
* @author sitecode
*/
protected function parsePermissions($permissions, $isowner = true)
{
$permissions = decoct($permissions);
$perm = $isowner ? decbin((int)$permissions[-3]) : decbin((int)$permissions[-1]);
return array(
'read' => $perm[-3],
'write' => $perm[-2]
);
}
/**
* Cache dir contents
*
* @param string $path dir path
*
* @return void
* @author Dmitry Levashov, sitecode
**/
protected function cacheDir($path)
{
$this->dirsCache[$path] = array();
$hasDir = false;
$list = array();
$encPath = $this->convEncIn($path);
foreach ($this->ftpRawList($encPath) as $info) {
if (($stat = $this->parseRaw($info, $encPath))) {
$list[] = $stat;
}
}
$list = $this->convEncOut($list);
$prefix = ($path === $this->separator) ? $this->separator : $path . $this->separator;
$targets = array();
foreach ($list as $stat) {
$p = $prefix . $stat['name'];
if (isset($stat['target'])) {
// stat later
$targets[$stat['name']] = $stat['target'];
} else {
$stat = $this->updateCache($p, $stat);
if (empty($stat['hidden'])) {
if (!$hasDir && $stat['mime'] === 'directory') {
$hasDir = true;
} elseif (!$hasDir && $stat['mime'] === 'symlink') {
$hasDir = true;
}
$this->dirsCache[$path][] = $p;
}
}
}
// stat link targets
foreach ($targets as $name => $target) {
$stat = array();
$stat['name'] = $name;
$p = $prefix . $name;
$cacheDirTarget = $this->cacheDirTarget;
$this->cacheDirTarget = $this->convEncIn($target, true);
if ($tstat = $this->stat($target)) {
$stat['size'] = $tstat['size'];
$stat['alias'] = $target;
$stat['thash'] = $tstat['hash'];
$stat['mime'] = $tstat['mime'];
$stat['read'] = $tstat['read'];
$stat['write'] = $tstat['write'];
if (isset($tstat['ts'])) {
$stat['ts'] = $tstat['ts'];
}
if (isset($tstat['owner'])) {
$stat['owner'] = $tstat['owner'];
}
if (isset($tstat['group'])) {
$stat['group'] = $tstat['group'];
}
if (isset($tstat['perm'])) {
$stat['perm'] = $tstat['perm'];
}
if (isset($tstat['isowner'])) {
$stat['isowner'] = $tstat['isowner'];
}
} else {
$stat['mime'] = 'symlink-broken';
$stat['read'] = false;
$stat['write'] = false;
$stat['size'] = 0;
}
$this->cacheDirTarget = $cacheDirTarget;
$stat = $this->updateCache($p, $stat);
if (empty($stat['hidden'])) {
if (!$hasDir && $stat['mime'] === 'directory') {
$hasDir = true;
}
$this->dirsCache[$path][] = $p;
}
}
if (isset($this->sessionCache['subdirs'])) {
$this->sessionCache['subdirs'][$path] = $hasDir;
}
}
/***************** file stat ********************/
/**
* Return stat for given path.
* Stat contains following fields:
* - (int) size file size in b. required
* - (int) ts file modification time in unix time. required
* - (string) mime mimetype. required for folders, others - optionally
* - (bool) read read permissions. required
* - (bool) write write permissions. required
* - (bool) locked is object locked. optionally
* - (bool) hidden is object hidden. optionally
* - (string) alias for symlinks - link target path relative to root path. optionally
* - (string) target for symlinks - link target path. optionally
* If file does not exists - returns empty array or false.
*
* @param string $path file path
*
* @return array|false
* @author Dmitry (dio) Levashov
**/
protected function _stat($path)
{
$outPath = $this->convEncOut($path);
if (isset($this->cache[$outPath])) {
return $this->convEncIn($this->cache[$outPath]);
} else {
$this->convEncIn();
}
if ($path === $this->root) {
$res = array(
'name' => $this->root,
'mime' => 'directory',
'dirs' => -1
);
if ($this->needOnline && (($this->ARGS['cmd'] === 'open' && $this->ARGS['target'] === $this->encode($this->root)) || $this->isMyReload())) {
$check = array(
'ts' => true,
'dirs' => true,
);
$ts = 0;
foreach ($this->ftpRawList($path) as $info) {
if ($info['filename'] === '.') {
$info['filename'] = 'root';
if ($stat = $this->parseRaw($info, $path)) {
unset($stat['name']);
$res = array_merge($res, $stat);
if ($res['ts']) {
$ts = 0;
unset($check['ts']);
}
}
}
if ($check && ($stat = $this->parseRaw($info, $path))) {
if (isset($stat['ts']) && !empty($stat['ts'])) {
$ts = max($ts, $stat['ts']);
}
if (isset($stat['dirs']) && $stat['mime'] === 'directory') {
$res['dirs'] = 1;
unset($stat['dirs']);
}
if (!$check) {
break;
}
}
}
if ($ts) {
$res['ts'] = $ts;
}
$this->cache[$outPath] = $res;
}
return $res;
}
$pPath = $this->_dirname($path);
if ($this->_inPath($pPath, $this->root)) {
$outPPpath = $this->convEncOut($pPath);
if (!isset($this->dirsCache[$outPPpath])) {
$parentSubdirs = null;
if (isset($this->sessionCache['subdirs']) && isset($this->sessionCache['subdirs'][$outPPpath])) {
$parentSubdirs = $this->sessionCache['subdirs'][$outPPpath];
}
$this->cacheDir($outPPpath);
if ($parentSubdirs) {
$this->sessionCache['subdirs'][$outPPpath] = $parentSubdirs;
}
}
}
$stat = $this->convEncIn(isset($this->cache[$outPath]) ? $this->cache[$outPath] : array());
if (!$this->mounted) {
// dispose incomplete cache made by calling `stat` by 'startPath' option
$this->cache = array();
}
return $stat;
}
/**
* Return true if path is dir and has at least one childs directory
*
* @param string $path dir path
*
* @return bool
* @author Dmitry (dio) Levashov, sitecode
**/
protected function _subdirs($path)
{
foreach ($this->ftpRawList($path) as $info) {
$name = $info['filename'];
if ($name && $name !== '.' && $name !== '..' && $info['type'] == NET_SFTP_TYPE_DIRECTORY) {
return true;
}
if ($name && $name !== '.' && $name !== '..' && $info['type'] == NET_SFTP_TYPE_SYMLINK) {
//return true;
}
}
return false;
}
/******************** file/dir content *********************/
/**
* Open file and return file pointer
*
* @param string $path file path
* @param string $mode
*
* @return false|resource
* @throws elFinderAbortException
* @internal param bool $write open file for writing
* @author Dmitry (dio) Levashov
*/
protected function _fopen($path, $mode = 'rb')
{
if ($this->tmp) {
$local = $this->getTempFile($path);
$this->connect->get($path, $local);
return @fopen($local, $mode);
}
return false;
}
/**
* Close opened file
*
* @param resource $fp file pointer
* @param string $path
*
* @return void
* @author Dmitry (dio) Levashov
*/
protected function _fclose($fp, $path = '')
{
is_resource($fp) && fclose($fp);
if ($path) {
unlink($this->getTempFile($path));
}
}
/******************** file/dir manipulations *************************/
/**
* Create dir and return created dir path or false on failed
*
* @param string $path parent dir path
* @param string $name new directory name
*
* @return string|bool
* @author Dmitry (dio) Levashov
**/
protected function _mkdir($path, $name)
{
$path = $this->_joinPath($path, $this->_basename($name));
if ($this->connect->mkdir($path) === false) {
return false;
}
$this->options['dirMode'] && $this->connect->chmod($this->options['dirMode'], $path);
return $path;
}
/**
* Create file and return it's path or false on failed
*
* @param string $path parent dir path
* @param string $name new file name
*
* @return string|bool
* @author sitecode
**/
protected function _mkfile($path, $name)
{
$path = $this->_joinPath($path, $this->_basename($name));
return $this->connect->put($path, '') ? $path : false;
/*
if ($this->tmp) {
$path = $this->_joinPath($path, $name);
$local = $this->getTempFile();
$res = touch($local) && $this->connect->put($path, $local, self::NET_SFTP_LOCAL_FILE);
unlink($local);
return $res ? $path : false;
}
return false;
*/
}
/**
* Copy file into another file
*
* @param string $source source file path
* @param string $targetDir target directory path
* @param string $name new file name
*
* @return bool
* @author Dmitry (dio) Levashov, sitecode
**/
protected function _copy($source, $targetDir, $name)
{
$res = false;
$target = $this->_joinPath($targetDir, $this->_basename($name));
if ($this->tmp) {
$local = $this->getTempFile();
if ($this->connect->get($source, $local)
&& $this->connect->put($target, $local, self::NET_SFTP_LOCAL_FILE)) {
$res = true;
}
unlink($local);
} else {
//not memory efficient
$res = $this->_filePutContents($target, $this->_getContents($source));
}
return $res;
}
/**
* Move file into another parent dir.
* Return new file path or false.
*
* @param string $source source file path
* @param $targetDir
* @param string $name file name
*
* @return bool|string
* @internal param string $target target dir path
* @author Dmitry (dio) Levashov
*/
protected function _move($source, $targetDir, $name)
{
$target = $this->_joinPath($targetDir, $this->_basename($name));
return $this->connect->rename($source, $target) ? $target : false;
}
/**
* Remove file
*
* @param string $path file path
*
* @return bool
* @author Dmitry (dio) Levashov
**/
protected function _unlink($path)
{
return $this->connect->delete($path, false);
}
/**
* Remove dir
*
* @param string $path dir path
*
* @return bool
* @author Dmitry (dio) Levashov
**/
protected function _rmdir($path)
{
return $this->connect->delete($path);
}
/**
* Create new file and write into it from file pointer.
* Return new file path or false on error.
*
* @param resource $fp file pointer
* @param string $dir target dir path
* @param string $name file name
* @param array $stat file stat (required by some virtual fs)
*
* @return bool|string
* @author Dmitry (dio) Levashov
**/
protected function _save($fp, $dir, $name, $stat)
{
//TODO optionally encrypt $fp before uploading if mime is not already encrypted type
$path = $this->_joinPath($dir, $this->_basename($name));
return $this->connect->put($path, $fp)
? $path
: false;
}
/**
* Get file contents
*
* @param string $path file path
*
* @return string|false
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov
*/
protected function _getContents($path)
{
return $this->connect->get($path);
}
/**
* Write a string to a file
*
* @param string $path file path
* @param string $content new file content
*
* @return bool
* @author Dmitry (dio) Levashov
**/
protected function _filePutContents($path, $content)
{
return $this->connect->put($path, $content);
}
/**
* chmod availability
*
* @param string $path
* @param string $mode
*
* @return bool
*/
protected function _chmod($path, $mode)
{
$modeOct = is_string($mode) ? octdec($mode) : octdec(sprintf("%04o", $mode));
return $this->connect->chmod($modeOct, $path);
}
/**
* Extract files from archive
*
* @param string $path archive path
* @param array $arc archiver command and arguments (same as in $this->archivers)
*
* @return true
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov,
* @author Alexey Sukhotin
*/
protected function _extract($path, $arc)
{
return false; //TODO
}
/**
* Create archive and return its path
*
* @param string $dir target dir
* @param array $files files names list
* @param string $name archive name
* @param array $arc archiver options
*
* @return string|bool
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov,
* @author Alexey Sukhotin
*/
protected function _archive($dir, $files, $name, $arc)
{
return false; //TODO
}
/**
* Gets an array of absolute remote SFTP paths of files and
* folders in $remote_directory omitting symbolic links.
*
* @param $remote_directory string remote SFTP path to scan for file and folders recursively
* @param $targets array Array of target item. `null` is to get all of items
*
* @return array of elements each of which is an array of two elements:
* <ul>
* <li>$item['path'] - absolute remote SFTP path</li>
* <li>$item['type'] - either 'f' for file or 'd' for directory</li>
* </ul>
*/
protected function ftp_scan_dir($remote_directory, $targets = null)
{
$buff = $this->ftpRawList($remote_directory);
$items = array();
if ($targets && is_array($targets)) {
$targets = array_flip($targets);
} else {
$targets = false;
}
foreach ($buff as $info) {
$name = $info['filename'];
if ($name !== '.' && $name !== '..' && (!$targets || isset($targets[$name]))) {
switch ($info['type']) {
case NET_SFTP_TYPE_SYMLINK : //omit symbolic links
case NET_SFTP_TYPE_DIRECTORY :
$remote_file_path = $this->_joinPath($remote_directory, $name);
$item = array();
$item['path'] = $remote_file_path;
$item['type'] = 'd'; // normal file
$items[] = $item;
$items = array_merge($items, $this->ftp_scan_dir($remote_file_path));
break;
default:
$remote_file_path = $this->_joinPath($remote_directory, $name);
$item = array();
$item['path'] = $remote_file_path;
$item['type'] = 'f'; // normal file
$items[] = $item;
}
}
}
return $items;
}
} // END class
@@ -0,0 +1,51 @@
<?php
/**
* elFinder driver for trash bin at local filesystem.
*
* @author NaokiSawada
**/
class elFinderVolumeTrash extends elFinderVolumeLocalFileSystem
{
/**
* Driver id
* Must be started from letter and contains [a-z0-9]
* Used as part of volume id.
*
* @var string
**/
protected $driverId = 't';
public function __construct()
{
parent::__construct();
// original option of the Trash
$this->options['lockEverything'] = false; // Lock all items in the trash to disable delete, move, rename.
// common options as the volume driver
$this->options['alias'] = 'Trash';
$this->options['quarantine'] = '';
$this->options['rootCssClass'] = 'elfinder-navbar-root-trash';
$this->options['copyOverwrite'] = false;
$this->options['uiCmdMap'] = array('paste' => 'hidden', 'mkdir' => 'hidden', 'copy' => 'restore');
$this->options['disabled'] = array('archive', 'duplicate', 'edit', 'extract', 'mkfile', 'places', 'put', 'rename', 'resize', 'upload');
}
public function mount(array $opts)
{
if ($this->options['lockEverything']) {
if (!is_array($opts['attributes'])) {
$opts['attributes'] = array();
}
$attr = array(
'pattern' => '/./',
'locked' => true,
);
array_unshift($opts['attributes'], $attr);
}
// force set `copyJoin` to true
$opts['copyJoin'] = true;
return parent::mount($opts);
}
}
@@ -0,0 +1,51 @@
<?php
/**
* elFinder driver for trash bin at MySQL Database
*
* @author NaokiSawada
**/
class elFinderVolumeTrashMySQL extends elFinderVolumeMySQL
{
/**
* Driver id
* Must be started from letter and contains [a-z0-9]
* Used as part of volume id.
*
* @var string
**/
protected $driverId = 'tm';
public function __construct()
{
parent::__construct();
// original option of the Trash
$this->options['lockEverything'] = false; // Lock all items in the trash to disable delete, move, rename.
// common options as the volume driver
$this->options['alias'] = 'Trash';
$this->options['quarantine'] = '';
$this->options['rootCssClass'] = 'elfinder-navbar-root-trash';
$this->options['copyOverwrite'] = false;
$this->options['uiCmdMap'] = array('paste' => 'hidden', 'mkdir' => 'hidden', 'copy' => 'restore');
$this->options['disabled'] = array('archive', 'duplicate', 'edit', 'extract', 'mkfile', 'places', 'put', 'rename', 'resize', 'upload');
}
public function mount(array $opts)
{
if ($this->options['lockEverything']) {
if (!is_array($opts['attributes'])) {
$opts['attributes'] = array();
}
$attr = array(
'pattern' => '/./',
'locked' => true,
);
array_unshift($opts['attributes'], $attr);
}
// force set `copyJoin` to true
$opts['copyJoin'] = true;
return parent::mount($opts);
}
}
@@ -0,0 +1,473 @@
<?php
/**
* Copyright (c) 2011, oov. All rights reserved.
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the oov nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior
* written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* bmp ファイルを GD で使えるように
* 使用例:
* //ファイルから読み込む場合はGDでPNGなどを読み込むのと同じような方法で可
* $image = imagecreatefrombmp("test.bmp");
* imagedestroy($image);
* //文字列から読み込む場合は以下の方法で可
* $image = GdBmp::loadFromString(file_get_contents("test.bmp"));
* //自動判定されるので破損ファイルでなければこれでも上手くいく
* //$image = imagecreatefrombmp(file_get_contents("test.bmp"));
* imagedestroy($image);
* //その他任意のストリームからの読み込みも可能
* $stream = fopen("http://127.0.0.1/test.bmp");
* $image = GdBmp::loadFromStream($stream);
* //自動判定されるのでこれでもいい
* //$image = imagecreatefrombmp($stream);
* fclose($stream);
* imagedestroy($image);
* 対応フォーマット
* 1bit
* 4bit
* 4bitRLE
* 8bit
* 8bitRLE
* 16bit(任意のビットフィールド)
* 24bit
* 32bit(任意のビットフィールド)
* BITMAPINFOHEADER の biCompression が BI_PNG / BI_JPEG の画像
* すべての形式でトップダウン/ボトムアップの両方をサポート
* 特殊なビットフィールドでもビットフィールドデータが正常なら読み込み可能
* 以下のものは非対応
* BITMAPV4HEADER と BITMAPV5HEADER に含まれる色空間に関する様々な機能
*
* @param $filename_or_stream_or_binary
*
* @return bool|resource
*/
if (!function_exists('imagecreatefrombmp')) {
function imagecreatefrombmp($filename_or_stream_or_binary)
{
return elFinderLibGdBmp::load($filename_or_stream_or_binary);
}
}
class elFinderLibGdBmp
{
public static function load($filename_or_stream_or_binary)
{
if (is_resource($filename_or_stream_or_binary)) {
return self::loadFromStream($filename_or_stream_or_binary);
} else if (is_string($filename_or_stream_or_binary) && strlen($filename_or_stream_or_binary) >= 26) {
$bfh = unpack("vtype/Vsize", $filename_or_stream_or_binary);
if ($bfh["type"] == 0x4d42 && ($bfh["size"] == 0 || $bfh["size"] == strlen($filename_or_stream_or_binary))) {
return self::loadFromString($filename_or_stream_or_binary);
}
}
return self::loadFromFile($filename_or_stream_or_binary);
}
public static function loadFromFile($filename)
{
$fp = fopen($filename, "rb");
if ($fp === false) {
return false;
}
$bmp = self::loadFromStream($fp);
fclose($fp);
return $bmp;
}
public static function loadFromString($str)
{
//data scheme より古いバージョンから対応しているようなので php://memory を使う
$fp = fopen("php://memory", "r+b");
if ($fp === false) {
return false;
}
if (fwrite($fp, $str) != strlen($str)) {
fclose($fp);
return false;
}
if (fseek($fp, 0) === -1) {
fclose($fp);
return false;
}
$bmp = self::loadFromStream($fp);
fclose($fp);
return $bmp;
}
public static function loadFromStream($stream)
{
$buf = fread($stream, 14); //2+4+2+2+4
if ($buf === false) {
return false;
}
//シグネチャチェック
if ($buf[0] != 'B' || $buf[1] != 'M') {
return false;
}
$bitmap_file_header = unpack(
//BITMAPFILEHEADER構造体
"vtype/" .
"Vsize/" .
"vreserved1/" .
"vreserved2/" .
"Voffbits", $buf
);
return self::loadFromStreamAndFileHeader($stream, $bitmap_file_header);
}
public static function loadFromStreamAndFileHeader($stream, array $bitmap_file_header)
{
if ($bitmap_file_header["type"] != 0x4d42) {
return false;
}
//情報ヘッダサイズを元に形式を区別して読み込み
$buf = fread($stream, 4);
if ($buf === false) {
return false;
}
list(, $header_size) = unpack("V", $buf);
if ($header_size == 12) {
$buf = fread($stream, $header_size - 4);
if ($buf === false) {
return false;
}
extract(unpack(
//BITMAPCOREHEADER構造体 - OS/2 Bitmap
"vwidth/" .
"vheight/" .
"vplanes/" .
"vbit_count", $buf
));
//飛んでこない分は 0 で初期化しておく
$clr_used = $clr_important = $alpha_mask = $compression = 0;
//マスク類は初期化されないのでここで割り当てておく
$red_mask = 0x00ff0000;
$green_mask = 0x0000ff00;
$blue_mask = 0x000000ff;
} else if (124 < $header_size || $header_size < 40) {
//未知の形式
return false;
} else {
//この時点で36バイト読めることまではわかっている
$buf = fread($stream, 36); //既に読んだ部分は除外しつつBITMAPINFOHEADERのサイズだけ読む
if ($buf === false) {
return false;
}
//BITMAPINFOHEADER構造体 - Windows Bitmap
extract(unpack(
"Vwidth/" .
"Vheight/" .
"vplanes/" .
"vbit_count/" .
"Vcompression/" .
"Vsize_image/" .
"Vx_pels_per_meter/" .
"Vy_pels_per_meter/" .
"Vclr_used/" .
"Vclr_important", $buf
));
/**
* @var integer $width
* @var integer $height
* @var integer $planes
* @var integer $bit_count
* @var integer $compression
* @var integer $size_image
* @var integer $x_pels_per_meter
* @var integer $y_pels_per_meter
* @var integer $clr_used
* @var integer $clr_important
*/
//負の整数を受け取る可能性があるものは自前で変換する
if ($width & 0x80000000) {
$width = -(~$width & 0xffffffff) - 1;
}
if ($height & 0x80000000) {
$height = -(~$height & 0xffffffff) - 1;
}
if ($x_pels_per_meter & 0x80000000) {
$x_pels_per_meter = -(~$x_pels_per_meter & 0xffffffff) - 1;
}
if ($y_pels_per_meter & 0x80000000) {
$y_pels_per_meter = -(~$y_pels_per_meter & 0xffffffff) - 1;
}
//ファイルによっては BITMAPINFOHEADER のサイズがおかしい(書き込み間違い?)ケースがある
//自分でファイルサイズを元に逆算することで回避できることもあるので再計算できそうなら正当性を調べる
//シークできないストリームの場合全体のファイルサイズは取得できないので、$bitmap_file_headerにサイズ申告がなければやらない
if ($bitmap_file_header["size"] != 0) {
$colorsize = $bit_count == 1 || $bit_count == 4 || $bit_count == 8 ? ($clr_used ? $clr_used : pow(2, $bit_count)) << 2 : 0;
$bodysize = $size_image ? $size_image : ((($width * $bit_count + 31) >> 3) & ~3) * abs($height);
$calcsize = $bitmap_file_header["size"] - $bodysize - $colorsize - 14;
//本来であれば一致するはずなのに合わない時は、値がおかしくなさそうなら(BITMAPV5HEADERの範囲内なら)計算して求めた値を採用する
if ($header_size < $calcsize && 40 <= $header_size && $header_size <= 124) {
$header_size = $calcsize;
}
}
//BITMAPV4HEADER や BITMAPV5HEADER の場合まだ読むべきデータが残っている可能性がある
if ($header_size - 40 > 0) {
$buf = fread($stream, $header_size - 40);
if ($buf === false) {
return false;
}
extract(unpack(
//BITMAPV4HEADER構造体(Windows95以降)
//BITMAPV5HEADER構造体(Windows98/2000以降)
"Vred_mask/" .
"Vgreen_mask/" .
"Vblue_mask/" .
"Valpha_mask", $buf . str_repeat("\x00", 120)
));
} else {
$alpha_mask = $red_mask = $green_mask = $blue_mask = 0;
}
//パレットがないがカラーマスクもない時
if (
($bit_count == 16 || $bit_count == 24 || $bit_count == 32) &&
$compression == 0 &&
$red_mask == 0 && $green_mask == 0 && $blue_mask == 0
) {
//もしカラーマスクを所持していない場合は
//規定のカラーマスクを適用する
switch ($bit_count) {
case 16:
$red_mask = 0x7c00;
$green_mask = 0x03e0;
$blue_mask = 0x001f;
break;
case 24:
case 32:
$red_mask = 0x00ff0000;
$green_mask = 0x0000ff00;
$blue_mask = 0x000000ff;
break;
}
}
}
if (
($width == 0) ||
($height == 0) ||
($planes != 1) ||
(($alpha_mask & $red_mask) != 0) ||
(($alpha_mask & $green_mask) != 0) ||
(($alpha_mask & $blue_mask) != 0) ||
(($red_mask & $green_mask) != 0) ||
(($red_mask & $blue_mask) != 0) ||
(($green_mask & $blue_mask) != 0)
) {
//不正な画像
return false;
}
//BI_JPEG と BI_PNG の場合は jpeg/png がそのまま入ってるだけなのでそのまま取り出してデコードする
if ($compression == 4 || $compression == 5) {
$buf = stream_get_contents($stream, $size_image);
if ($buf === false) {
return false;
}
return imagecreatefromstring($buf);
}
//画像本体の読み出し
//1行のバイト数
$line_bytes = (($width * $bit_count + 31) >> 3) & ~3;
//全体の行数
$lines = abs($height);
//y軸進行量(ボトムアップかトップダウンか)
$y = $height > 0 ? $lines - 1 : 0;
$line_step = $height > 0 ? -1 : 1;
//256色以下の画像か?
if ($bit_count == 1 || $bit_count == 4 || $bit_count == 8) {
$img = imagecreate($width, $lines);
//画像データの前にパレットデータがあるのでパレットを作成する
$palette_size = $header_size == 12 ? 3 : 4; //OS/2形式の場合は x に相当する箇所のデータは最初から確保されていない
$colors = $clr_used ? $clr_used : pow(2, $bit_count); //色数
$palette = array();
for ($i = 0; $i < $colors; ++$i) {
$buf = fread($stream, $palette_size);
if ($buf === false) {
imagedestroy($img);
return false;
}
extract(unpack("Cb/Cg/Cr/Cx", $buf . "\x00"));
/**
* @var integer $b
* @var integer $g
* @var integer $r
* @var integer $x
*/
$palette[] = imagecolorallocate($img, $r, $g, $b);
}
$shift_base = 8 - $bit_count;
$mask = ((1 << $bit_count) - 1) << $shift_base;
//圧縮されている場合とされていない場合でデコード処理が大きく変わる
if ($compression == 1 || $compression == 2) {
$x = 0;
$qrt_mod2 = $bit_count >> 2 & 1;
for (; ;) {
//もし描写先が範囲外になっている場合デコード処理がおかしくなっているので抜ける
//変なデータが渡されたとしても最悪なケースで255回程度の無駄なので目を瞑る
if ($x < -1 || $x > $width || $y < -1 || $y > $height) {
imagedestroy($img);
return false;
}
$buf = fread($stream, 1);
if ($buf === false) {
imagedestroy($img);
return false;
}
switch ($buf) {
case "\x00":
$buf = fread($stream, 1);
if ($buf === false) {
imagedestroy($img);
return false;
}
switch ($buf) {
case "\x00": //EOL
$y += $line_step;
$x = 0;
break;
case "\x01": //EOB
$y = 0;
$x = 0;
break 3;
case "\x02": //MOV
$buf = fread($stream, 2);
if ($buf === false) {
imagedestroy($img);
return false;
}
list(, $xx, $yy) = unpack("C2", $buf);
$x += $xx;
$y += $yy * $line_step;
break;
default: //ABS
list(, $pixels) = unpack("C", $buf);
$bytes = ($pixels >> $qrt_mod2) + ($pixels & $qrt_mod2);
$buf = fread($stream, ($bytes + 1) & ~1);
if ($buf === false) {
imagedestroy($img);
return false;
}
for ($i = 0, $pos = 0; $i < $pixels; ++$i, ++$x, $pos += $bit_count) {
list(, $c) = unpack("C", $buf[$pos >> 3]);
$b = $pos & 0x07;
imagesetpixel($img, $x, $y, $palette[($c & ($mask >> $b)) >> ($shift_base - $b)]);
}
break;
}
break;
default:
$buf2 = fread($stream, 1);
if ($buf2 === false) {
imagedestroy($img);
return false;
}
list(, $size, $c) = unpack("C2", $buf . $buf2);
for ($i = 0, $pos = 0; $i < $size; ++$i, ++$x, $pos += $bit_count) {
$b = $pos & 0x07;
imagesetpixel($img, $x, $y, $palette[($c & ($mask >> $b)) >> ($shift_base - $b)]);
}
break;
}
}
} else {
for ($line = 0; $line < $lines; ++$line, $y += $line_step) {
$buf = fread($stream, $line_bytes);
if ($buf === false) {
imagedestroy($img);
return false;
}
$pos = 0;
for ($x = 0; $x < $width; ++$x, $pos += $bit_count) {
list(, $c) = unpack("C", $buf[$pos >> 3]);
$b = $pos & 0x7;
imagesetpixel($img, $x, $y, $palette[($c & ($mask >> $b)) >> ($shift_base - $b)]);
}
}
}
} else {
$img = imagecreatetruecolor($width, $lines);
imagealphablending($img, false);
if ($alpha_mask) {
//αデータがあるので透過情報も保存できるように
imagesavealpha($img, true);
}
//x軸進行量
$pixel_step = $bit_count >> 3;
$alpha_max = $alpha_mask ? 0x7f : 0x00;
$alpha_mask_r = $alpha_mask ? 1 / $alpha_mask : 1;
$red_mask_r = $red_mask ? 1 / $red_mask : 1;
$green_mask_r = $green_mask ? 1 / $green_mask : 1;
$blue_mask_r = $blue_mask ? 1 / $blue_mask : 1;
for ($line = 0; $line < $lines; ++$line, $y += $line_step) {
$buf = fread($stream, $line_bytes);
if ($buf === false) {
imagedestroy($img);
return false;
}
$pos = 0;
for ($x = 0; $x < $width; ++$x, $pos += $pixel_step) {
list(, $c) = unpack("V", substr($buf, $pos, $pixel_step) . "\x00\x00");
$a_masked = $c & $alpha_mask;
$r_masked = $c & $red_mask;
$g_masked = $c & $green_mask;
$b_masked = $c & $blue_mask;
$a = $alpha_max - ((($a_masked << 7) - $a_masked) * $alpha_mask_r);
$r = (($r_masked << 8) - $r_masked) * $red_mask_r;
$g = (($g_masked << 8) - $g_masked) * $green_mask_r;
$b = (($b_masked << 8) - $b_masked) * $blue_mask_r;
imagesetpixel($img, $x, $y, ($a << 24) | ($r << 16) | ($g << 8) | $b);
}
}
imagealphablending($img, true); //デフォルト値に戻しておく
}
return $img;
}
}
@@ -0,0 +1,782 @@
# This file maps Internet media types to unique file extension(s).
# Although created for httpd, this file is used by many software systems
# and has been placed in the public domain for unlimited redisribution.
#
# The table below contains both registered and (common) unregistered types.
# A type that has no unique extension can be ignored -- they are listed
# here to guide configurations toward known types and to make it easier to
# identify "new" types. File extensions are also commonly used to indicate
# content languages and encodings, so choose them carefully.
#
# Internet media types should be registered as described in RFC 4288.
# The registry is at <http://www.iana.org/assignments/media-types/>.
#
# MIME type (lowercased) Extensions
application/andrew-inset ez
application/applixware aw
application/atom+xml atom
application/atomcat+xml atomcat
application/atomsvc+xml atomsvc
application/ccxml+xml ccxml
application/cdmi-capability cdmia
application/cdmi-container cdmic
application/cdmi-domain cdmid
application/cdmi-object cdmio
application/cdmi-queue cdmiq
application/cu-seeme cu
application/davmount+xml davmount
application/docbook+xml dbk
application/dssc+der dssc
application/dssc+xml xdssc
application/ecmascript ecma
application/emma+xml emma
application/epub+zip epub
application/exi exi
application/font-tdpfr pfr
application/gml+xml gml
application/gpx+xml gpx
application/gxf gxf
application/hyperstudio stk
application/inkml+xml ink inkml
application/ipfix ipfix
application/java-archive jar
application/java-serialized-object ser
application/java-vm class
application/javascript js
application/json json
application/jsonml+json jsonml
application/lost+xml lostxml
application/mac-binhex40 hqx
application/mac-compactpro cpt
application/mads+xml mads
application/marc mrc
application/marcxml+xml mrcx
application/mathematica ma nb mb
application/mathml+xml mathml
application/mbox mbox
application/mediaservercontrol+xml mscml
application/metalink+xml metalink
application/metalink4+xml meta4
application/mets+xml mets
application/mods+xml mods
application/mp21 m21 mp21
application/mp4 mp4s
application/msword doc dot
application/mxf mxf
application/octet-stream bin dms lrf mar so dist distz pkg bpk dump elc deploy
application/oda oda
application/oebps-package+xml opf
application/ogg ogx
application/omdoc+xml omdoc
application/onenote onetoc onetoc2 onetmp onepkg
application/oxps oxps
application/patch-ops-error+xml xer
application/pdf pdf
application/pgp-encrypted pgp
application/pgp-signature asc sig
application/pics-rules prf
application/pkcs10 p10
application/pkcs7-mime p7m p7c
application/pkcs7-signature p7s
application/pkcs8 p8
application/pkix-attr-cert ac
application/pkix-cert cer
application/pkix-crl crl
application/pkix-pkipath pkipath
application/pkixcmp pki
application/pls+xml pls
application/postscript ai eps ps
application/prs.cww cww
application/pskc+xml pskcxml
application/rdf+xml rdf
application/reginfo+xml rif
application/relax-ng-compact-syntax rnc
application/resource-lists+xml rl
application/resource-lists-diff+xml rld
application/rls-services+xml rs
application/rpki-ghostbusters gbr
application/rpki-manifest mft
application/rpki-roa roa
application/rsd+xml rsd
application/rss+xml rss
application/rtf rtf
application/sbml+xml sbml
application/scvp-cv-request scq
application/scvp-cv-response scs
application/scvp-vp-request spq
application/scvp-vp-response spp
application/sdp sdp
application/set-payment-initiation setpay
application/set-registration-initiation setreg
application/shf+xml shf
application/smil+xml smi smil
application/sparql-query rq
application/sparql-results+xml srx
application/srgs gram
application/srgs+xml grxml
application/sru+xml sru
application/ssdl+xml ssdl
application/ssml+xml ssml
application/tei+xml tei teicorpus
application/thraud+xml tfi
application/timestamped-data tsd
application/vnd.3gpp.pic-bw-large plb
application/vnd.3gpp.pic-bw-small psb
application/vnd.3gpp.pic-bw-var pvb
application/vnd.3gpp2.tcap tcap
application/vnd.3m.post-it-notes pwn
application/vnd.accpac.simply.aso aso
application/vnd.accpac.simply.imp imp
application/vnd.acucobol acu
application/vnd.acucorp atc acutc
application/vnd.adobe.air-application-installer-package+zip air
application/vnd.adobe.formscentral.fcdt fcdt
application/vnd.adobe.fxp fxp fxpl
application/vnd.adobe.xdp+xml xdp
application/vnd.adobe.xfdf xfdf
application/vnd.ahead.space ahead
application/vnd.airzip.filesecure.azf azf
application/vnd.airzip.filesecure.azs azs
application/vnd.amazon.ebook azw
application/vnd.americandynamics.acc acc
application/vnd.amiga.ami ami
application/vnd.android.package-archive apk
application/vnd.anser-web-certificate-issue-initiation cii
application/vnd.anser-web-funds-transfer-initiation fti
application/vnd.antix.game-component atx
application/vnd.apple.installer+xml mpkg
application/vnd.apple.mpegurl m3u8
application/vnd.aristanetworks.swi swi
application/vnd.astraea-software.iota iota
application/vnd.audiograph aep
application/vnd.blueice.multipass mpm
application/vnd.bmi bmi
application/vnd.businessobjects rep
application/vnd.chemdraw+xml cdxml
application/vnd.chipnuts.karaoke-mmd mmd
application/vnd.cinderella cdy
application/vnd.claymore cla
application/vnd.cloanto.rp9 rp9
application/vnd.clonk.c4group c4g c4d c4f c4p c4u
application/vnd.cluetrust.cartomobile-config c11amc
application/vnd.cluetrust.cartomobile-config-pkg c11amz
application/vnd.commonspace csp
application/vnd.contact.cmsg cdbcmsg
application/vnd.cosmocaller cmc
application/vnd.crick.clicker clkx
application/vnd.crick.clicker.keyboard clkk
application/vnd.crick.clicker.palette clkp
application/vnd.crick.clicker.template clkt
application/vnd.crick.clicker.wordbank clkw
application/vnd.criticaltools.wbs+xml wbs
application/vnd.ctc-posml pml
application/vnd.cups-ppd ppd
application/vnd.curl.car car
application/vnd.curl.pcurl pcurl
application/vnd.dart dart
application/vnd.data-vision.rdz rdz
application/vnd.dece.data uvf uvvf uvd uvvd
application/vnd.dece.ttml+xml uvt uvvt
application/vnd.dece.unspecified uvx uvvx
application/vnd.dece.zip uvz uvvz
application/vnd.denovo.fcselayout-link fe_launch
application/vnd.dna dna
application/vnd.dolby.mlp mlp
application/vnd.dpgraph dpg
application/vnd.dreamfactory dfac
application/vnd.ds-keypoint kpxx
application/vnd.dvb.ait ait
application/vnd.dvb.service svc
application/vnd.dynageo geo
application/vnd.ecowin.chart mag
application/vnd.enliven nml
application/vnd.epson.esf esf
application/vnd.epson.msf msf
application/vnd.epson.quickanime qam
application/vnd.epson.salt slt
application/vnd.epson.ssf ssf
application/vnd.eszigno3+xml es3 et3
application/vnd.ezpix-album ez2
application/vnd.ezpix-package ez3
application/vnd.fdf fdf
application/vnd.fdsn.mseed mseed
application/vnd.fdsn.seed seed dataless
application/vnd.flographit gph
application/vnd.fluxtime.clip ftc
application/vnd.framemaker fm frame maker book
application/vnd.frogans.fnc fnc
application/vnd.frogans.ltf ltf
application/vnd.fsc.weblaunch fsc
application/vnd.fujitsu.oasys oas
application/vnd.fujitsu.oasys2 oa2
application/vnd.fujitsu.oasys3 oa3
application/vnd.fujitsu.oasysgp fg5
application/vnd.fujitsu.oasysprs bh2
application/vnd.fujixerox.ddd ddd
application/vnd.fujixerox.docuworks xdw
application/vnd.fujixerox.docuworks.binder xbd
application/vnd.fuzzysheet fzs
application/vnd.genomatix.tuxedo txd
application/vnd.geogebra.file ggb
application/vnd.geogebra.tool ggt
application/vnd.geometry-explorer gex gre
application/vnd.geonext gxt
application/vnd.geoplan g2w
application/vnd.geospace g3w
application/vnd.gmx gmx
application/vnd.google-earth.kml+xml kml
application/vnd.google-earth.kmz kmz
application/vnd.grafeq gqf gqs
application/vnd.groove-account gac
application/vnd.groove-help ghf
application/vnd.groove-identity-message gim
application/vnd.groove-injector grv
application/vnd.groove-tool-message gtm
application/vnd.groove-tool-template tpl
application/vnd.groove-vcard vcg
application/vnd.hal+xml hal
application/vnd.handheld-entertainment+xml zmm
application/vnd.hbci hbci
application/vnd.hhe.lesson-player les
application/vnd.hp-hpgl hpgl
application/vnd.hp-hpid hpid
application/vnd.hp-hps hps
application/vnd.hp-jlyt jlt
application/vnd.hp-pcl pcl
application/vnd.hp-pclxl pclxl
application/vnd.hydrostatix.sof-data sfd-hdstx
application/vnd.ibm.minipay mpy
application/vnd.ibm.modcap afp listafp list3820
application/vnd.ibm.rights-management irm
application/vnd.ibm.secure-container sc
application/vnd.iccprofile icc icm
application/vnd.igloader igl
application/vnd.immervision-ivp ivp
application/vnd.immervision-ivu ivu
application/vnd.insors.igm igm
application/vnd.intercon.formnet xpw xpx
application/vnd.intergeo i2g
application/vnd.intu.qbo qbo
application/vnd.intu.qfx qfx
application/vnd.ipunplugged.rcprofile rcprofile
application/vnd.irepository.package+xml irp
application/vnd.is-xpr xpr
application/vnd.isac.fcs fcs
application/vnd.jam jam
application/vnd.jcp.javame.midlet-rms rms
application/vnd.jisp jisp
application/vnd.joost.joda-archive joda
application/vnd.kahootz ktz ktr
application/vnd.kde.karbon karbon
application/vnd.kde.kchart chrt
application/vnd.kde.kformula kfo
application/vnd.kde.kivio flw
application/vnd.kde.kontour kon
application/vnd.kde.kpresenter kpr kpt
application/vnd.kde.kspread ksp
application/vnd.kde.kword kwd kwt
application/vnd.kenameaapp htke
application/vnd.kidspiration kia
application/vnd.kinar kne knp
application/vnd.koan skp skd skt skm
application/vnd.kodak-descriptor sse
application/vnd.las.las+xml lasxml
application/vnd.llamagraphics.life-balance.desktop lbd
application/vnd.llamagraphics.life-balance.exchange+xml lbe
application/vnd.lotus-1-2-3 123
application/vnd.lotus-approach apr
application/vnd.lotus-freelance pre
application/vnd.lotus-notes nsf
application/vnd.lotus-organizer org
application/vnd.lotus-screencam scm
application/vnd.lotus-wordpro lwp
application/vnd.macports.portpkg portpkg
application/vnd.mcd mcd
application/vnd.medcalcdata mc1
application/vnd.mediastation.cdkey cdkey
application/vnd.mfer mwf
application/vnd.mfmp mfm
application/vnd.micrografx.flo flo
application/vnd.micrografx.igx igx
application/vnd.mif mif
application/vnd.mobius.daf daf
application/vnd.mobius.dis dis
application/vnd.mobius.mbk mbk
application/vnd.mobius.mqy mqy
application/vnd.mobius.msl msl
application/vnd.mobius.plc plc
application/vnd.mobius.txf txf
application/vnd.mophun.application mpn
application/vnd.mophun.certificate mpc
application/vnd.mozilla.xul+xml xul
application/vnd.ms-artgalry cil
application/vnd.ms-cab-compressed cab
application/vnd.ms-excel xls xlm xla xlc xlt xlw
application/vnd.ms-excel.addin.macroenabled.12 xlam
application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb
application/vnd.ms-excel.sheet.macroenabled.12 xlsm
application/vnd.ms-excel.template.macroenabled.12 xltm
application/vnd.ms-fontobject eot
application/vnd.ms-htmlhelp chm
application/vnd.ms-ims ims
application/vnd.ms-lrm lrm
application/vnd.ms-officetheme thmx
application/vnd.ms-outlook msg
application/vnd.ms-pki.seccat cat
application/vnd.ms-pki.stl stl
application/vnd.ms-powerpoint ppt pps pot
application/vnd.ms-powerpoint.addin.macroenabled.12 ppam
application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm
application/vnd.ms-powerpoint.slide.macroenabled.12 sldm
application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm
application/vnd.ms-powerpoint.template.macroenabled.12 potm
application/vnd.ms-project mpp mpt
application/vnd.ms-word.document.macroenabled.12 docm
application/vnd.ms-word.template.macroenabled.12 dotm
application/vnd.ms-works wps wks wcm wdb
application/vnd.ms-wpl wpl
application/vnd.ms-xpsdocument xps
application/vnd.mseq mseq
application/vnd.musician mus
application/vnd.muvee.style msty
application/vnd.mynfc taglet
application/vnd.neurolanguage.nlu nlu
application/vnd.nitf ntf nitf
application/vnd.noblenet-directory nnd
application/vnd.noblenet-sealer nns
application/vnd.noblenet-web nnw
application/vnd.nokia.n-gage.data ngdat
application/vnd.nokia.n-gage.symbian.install n-gage
application/vnd.nokia.radio-preset rpst
application/vnd.nokia.radio-presets rpss
application/vnd.novadigm.edm edm
application/vnd.novadigm.edx edx
application/vnd.novadigm.ext ext
application/vnd.oasis.opendocument.chart odc
application/vnd.oasis.opendocument.chart-template otc
application/vnd.oasis.opendocument.database odb
application/vnd.oasis.opendocument.formula odf
application/vnd.oasis.opendocument.formula-template odft
application/vnd.oasis.opendocument.graphics odg
application/vnd.oasis.opendocument.graphics-template otg
application/vnd.oasis.opendocument.image odi
application/vnd.oasis.opendocument.image-template oti
application/vnd.oasis.opendocument.presentation odp
application/vnd.oasis.opendocument.presentation-template otp
application/vnd.oasis.opendocument.spreadsheet ods
application/vnd.oasis.opendocument.spreadsheet-template ots
application/vnd.oasis.opendocument.text odt
application/vnd.oasis.opendocument.text-master odm
application/vnd.oasis.opendocument.text-template ott
application/vnd.oasis.opendocument.text-web oth
application/vnd.olpc-sugar xo
application/vnd.oma.dd2+xml dd2
application/vnd.openofficeorg.extension oxt
application/vnd.openxmlformats-officedocument.presentationml.presentation pptx
application/vnd.openxmlformats-officedocument.presentationml.slide sldx
application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx
application/vnd.openxmlformats-officedocument.presentationml.template potx
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx
application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx
application/vnd.openxmlformats-officedocument.wordprocessingml.document docx
application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx
application/vnd.osgeo.mapguide.package mgp
application/vnd.osgi.dp dp
application/vnd.osgi.subsystem esa
application/vnd.palm pdb pqa oprc
application/vnd.pawaafile paw
application/vnd.pg.format str
application/vnd.pg.osasli ei6
application/vnd.picsel efif
application/vnd.pmi.widget wg
application/vnd.pocketlearn plf
application/vnd.powerbuilder6 pbd
application/vnd.previewsystems.box box
application/vnd.proteus.magazine mgz
application/vnd.publishare-delta-tree qps
application/vnd.pvi.ptid1 ptid
application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb
application/vnd.realvnc.bed bed
application/vnd.recordare.musicxml mxl
application/vnd.recordare.musicxml+xml musicxml
application/vnd.rig.cryptonote cryptonote
application/vnd.rim.cod cod
application/vnd.rn-realmedia rm
application/vnd.rn-realmedia-vbr rmvb
application/vnd.route66.link66+xml link66
application/vnd.sailingtracker.track st
application/vnd.seemail see
application/vnd.sema sema
application/vnd.semd semd
application/vnd.semf semf
application/vnd.shana.informed.formdata ifm
application/vnd.shana.informed.formtemplate itp
application/vnd.shana.informed.interchange iif
application/vnd.shana.informed.package ipk
application/vnd.simtech-mindmapper twd twds
application/vnd.smaf mmf
application/vnd.smart.teacher teacher
application/vnd.solent.sdkm+xml sdkm sdkd
application/vnd.spotfire.dxp dxp
application/vnd.spotfire.sfs sfs
application/vnd.stardivision.calc sdc
application/vnd.stardivision.draw sda
application/vnd.stardivision.impress sdd
application/vnd.stardivision.math smf
application/vnd.stardivision.writer sdw vor
application/vnd.stardivision.writer-global sgl
application/vnd.stepmania.package smzip
application/vnd.stepmania.stepchart sm
application/vnd.sun.xml.calc sxc
application/vnd.sun.xml.calc.template stc
application/vnd.sun.xml.draw sxd
application/vnd.sun.xml.draw.template std
application/vnd.sun.xml.impress sxi
application/vnd.sun.xml.impress.template sti
application/vnd.sun.xml.math sxm
application/vnd.sun.xml.writer sxw
application/vnd.sun.xml.writer.global sxg
application/vnd.sun.xml.writer.template stw
application/vnd.sus-calendar sus susp
application/vnd.svd svd
application/vnd.symbian.install sis sisx
application/vnd.syncml+xml xsm
application/vnd.syncml.dm+wbxml bdm
application/vnd.syncml.dm+xml xdm
application/vnd.tao.intent-module-archive tao
application/vnd.tcpdump.pcap pcap cap dmp
application/vnd.tmobile-livetv tmo
application/vnd.trid.tpt tpt
application/vnd.triscape.mxs mxs
application/vnd.trueapp tra
application/vnd.ufdl ufd ufdl
application/vnd.uiq.theme utz
application/vnd.umajin umj
application/vnd.unity unityweb
application/vnd.uoml+xml uoml
application/vnd.vcx vcx
application/vnd.visio vsd vst vss vsw
application/vnd.visionary vis
application/vnd.vsf vsf
application/vnd.wap.wbxml wbxml
application/vnd.wap.wmlc wmlc
application/vnd.wap.wmlscriptc wmlsc
application/vnd.webturbo wtb
application/vnd.wolfram.player nbp
application/vnd.wordperfect wpd
application/vnd.wqd wqd
application/vnd.wt.stf stf
application/vnd.xara xar
application/vnd.xfdl xfdl
application/vnd.yamaha.hv-dic hvd
application/vnd.yamaha.hv-script hvs
application/vnd.yamaha.hv-voice hvp
application/vnd.yamaha.openscoreformat osf
application/vnd.yamaha.openscoreformat.osfpvg+xml osfpvg
application/vnd.yamaha.smaf-audio saf
application/vnd.yamaha.smaf-phrase spf
application/vnd.yellowriver-custom-menu cmp
application/vnd.zul zir zirz
application/vnd.zzazz.deck+xml zaz
application/voicexml+xml vxml
application/widget wgt
application/winhlp hlp
application/wsdl+xml wsdl
application/wspolicy+xml wspolicy
application/x-7z-compressed 7z
application/x-abiword abw
application/x-ace-compressed ace
application/x-apple-diskimage dmg
application/x-authorware-bin aab x32 u32 vox
application/x-authorware-map aam
application/x-authorware-seg aas
application/x-bcpio bcpio
application/x-bittorrent torrent
application/x-blorb blb blorb
application/x-bzip bz
application/x-bzip2 bz2 boz
application/x-cbr cbr cba cbt cbz cb7
application/x-cdlink vcd
application/x-cfs-compressed cfs
application/x-chat chat
application/x-chess-pgn pgn
application/x-conference nsc
application/x-cpio cpio
application/x-csh csh
application/x-debian-package deb udeb
application/x-dgc-compressed dgc
application/x-director dir dcr dxr cst cct cxt w3d fgd swa
application/x-doom wad
application/x-dtbncx+xml ncx
application/x-dtbook+xml dtb
application/x-dtbresource+xml res
application/x-dvi dvi
application/x-envoy evy
application/x-eva eva
application/x-font-bdf bdf
application/x-font-ghostscript gsf
application/x-font-linux-psf psf
application/x-font-pcf pcf
application/x-font-snf snf
application/x-font-type1 pfa pfb pfm afm
application/x-freearc arc
application/x-futuresplash spl
application/x-gca-compressed gca
application/x-glulx ulx
application/x-gnumeric gnumeric
application/x-gramps-xml gramps
application/x-gtar gtar
application/x-hdf hdf
application/x-install-instructions install
application/x-iso9660-image iso
application/x-java-jnlp-file jnlp
application/x-latex latex
application/x-lzh-compressed lzh lha
application/x-mie mie
application/x-mobipocket-ebook prc mobi
application/x-ms-application application
application/x-ms-shortcut lnk
application/x-ms-wmd wmd
application/x-ms-wmz wmz
application/x-ms-xbap xbap
application/x-msaccess mdb
application/x-msbinder obd
application/x-mscardfile crd
application/x-msclip clp
application/x-msdownload exe dll com bat msi
application/x-msmediaview mvb m13 m14
application/x-msmetafile wmf wmz emf emz
application/x-msmoney mny
application/x-mspublisher pub
application/x-msschedule scd
application/x-msterminal trm
application/x-mswrite wri
application/x-netcdf nc cdf
application/x-nzb nzb
application/x-pkcs12 p12 pfx
application/x-pkcs7-certificates p7b spc
application/x-pkcs7-certreqresp p7r
application/x-rar-compressed rar
application/x-research-info-systems ris
application/x-sh sh
application/x-shar shar
application/x-shockwave-flash swf
application/x-silverlight-app xap
application/x-sql sql
application/x-stuffit sit
application/x-stuffitx sitx
application/x-subrip srt
application/x-sv4cpio sv4cpio
application/x-sv4crc sv4crc
application/x-t3vm-image t3
application/x-tads gam
application/x-tar tar
application/x-tcl tcl
application/x-tex tex
application/x-tex-tfm tfm
application/x-texinfo texinfo texi
application/x-tgif obj
application/x-ustar ustar
application/x-wais-source src
application/x-x509-ca-cert der crt
application/x-xfig fig
application/x-xliff+xml xlf
application/x-xpinstall xpi
application/x-xz xz
application/x-zmachine z1 z2 z3 z4 z5 z6 z7 z8
application/xaml+xml xaml
application/xcap-diff+xml xdf
application/xenc+xml xenc
application/xhtml+xml xhtml xht
application/xml xml xsl
application/xml-dtd dtd
application/xop+xml xop
application/xproc+xml xpl
application/xslt+xml xslt
application/xspf+xml xspf
application/xv+xml mxml xhvml xvml xvm
application/yang yang
application/yin+xml yin
application/zip zip
audio/adpcm adp
audio/basic au snd
audio/midi mid midi kar rmi
audio/mp4 m4a mp4a
audio/mpeg mpga mp2 mp2a mp3 m2a m3a
audio/ogg oga ogg spx
audio/s3m s3m
audio/silk sil
audio/vnd.dece.audio uva uvva
audio/vnd.digital-winds eol
audio/vnd.dra dra
audio/vnd.dts dts
audio/vnd.dts.hd dtshd
audio/vnd.lucent.voice lvp
audio/vnd.ms-playready.media.pya pya
audio/vnd.nuera.ecelp4800 ecelp4800
audio/vnd.nuera.ecelp7470 ecelp7470
audio/vnd.nuera.ecelp9600 ecelp9600
audio/vnd.rip rip
audio/webm weba
audio/x-aac aac
audio/x-aiff aif aiff aifc
audio/x-caf caf
audio/x-flac flac
audio/x-matroska mka
audio/x-mpegurl m3u
audio/x-ms-wax wax
audio/x-ms-wma wma
audio/x-pn-realaudio ram ra
audio/x-pn-realaudio-plugin rmp
audio/x-wav wav
audio/xm xm
chemical/x-cdx cdx
chemical/x-cif cif
chemical/x-cmdf cmdf
chemical/x-cml cml
chemical/x-csml csml
chemical/x-xyz xyz
font/collection ttc
font/otf otf
font/ttf ttf
font/woff woff
font/woff2 woff2
image/bmp bmp
image/cgm cgm
image/g3fax g3
image/gif gif
image/ief ief
image/jpeg jpeg jpg jpe
image/ktx ktx
image/png png
image/prs.btif btif
image/sgi sgi
image/svg+xml svg svgz
image/tiff tiff tif
image/vnd.adobe.photoshop psd
image/vnd.dece.graphic uvi uvvi uvg uvvg
image/vnd.djvu djvu djv
image/vnd.dvb.subtitle sub
image/vnd.dwg dwg
image/vnd.dxf dxf
image/vnd.fastbidsheet fbs
image/vnd.fpx fpx
image/vnd.fst fst
image/vnd.fujixerox.edmics-mmr mmr
image/vnd.fujixerox.edmics-rlc rlc
image/vnd.ms-modi mdi
image/vnd.ms-photo wdp
image/vnd.net-fpx npx
image/vnd.wap.wbmp wbmp
image/vnd.xiff xif
image/webp webp
image/x-3ds 3ds
image/x-cmu-raster ras
image/x-cmx cmx
image/x-freehand fh fhc fh4 fh5 fh7
image/x-icon ico
image/x-mrsid-image sid
image/x-pcx pcx
image/x-pict pic pct
image/x-portable-anymap pnm
image/x-portable-bitmap pbm
image/x-portable-graymap pgm
image/x-portable-pixmap ppm
image/x-rgb rgb
image/x-tga tga
image/x-xbitmap xbm
image/x-xpixmap xpm
image/x-xwindowdump xwd
message/rfc822 eml mime
model/iges igs iges
model/mesh msh mesh silo
model/vnd.collada+xml dae
model/vnd.dwf dwf
model/vnd.gdl gdl
model/vnd.gtw gtw
model/vnd.mts mts
model/vnd.vtu vtu
model/vrml wrl vrml
model/x3d+binary x3db x3dbz
model/x3d+vrml x3dv x3dvz
model/x3d+xml x3d x3dz
text/cache-manifest appcache
text/calendar ics ifb
text/css css
text/csv csv
text/html html htm
text/n3 n3
text/plain txt text conf def list log in
text/prs.lines.tag dsc
text/richtext rtx
text/sgml sgml sgm
text/tab-separated-values tsv
text/troff t tr roff man me ms
text/turtle ttl
text/uri-list uri uris urls
text/vcard vcard
text/vnd.curl curl
text/vnd.curl.dcurl dcurl
text/vnd.curl.mcurl mcurl
text/vnd.curl.scurl scurl
text/vnd.dvb.subtitle sub
text/vnd.fly fly
text/vnd.fmi.flexstor flx
text/vnd.graphviz gv
text/vnd.in3d.3dml 3dml
text/vnd.in3d.spot spot
text/vnd.sun.j2me.app-descriptor jad
text/vnd.wap.wml wml
text/vnd.wap.wmlscript wmls
text/x-asm s asm
text/x-c c cc cxx cpp h hh dic
text/x-fortran f for f77 f90
text/x-java-source java
text/x-nfo nfo
text/x-opml opml
text/x-pascal p pas
text/x-setext etx
text/x-sfv sfv
text/x-uuencode uu
text/x-vcalendar vcs
text/x-vcard vcf
video/3gpp 3gp
video/3gpp2 3g2
video/h261 h261
video/h263 h263
video/h264 h264
video/jpeg jpgv
video/jpm jpm jpgm
video/mj2 mj2 mjp2
video/mp4 mp4 mp4v mpg4
video/mpeg mpeg mpg mpe m1v m2v
video/ogg ogv
video/quicktime qt mov
video/vnd.dece.hd uvh uvvh
video/vnd.dece.mobile uvm uvvm
video/vnd.dece.pd uvp uvvp
video/vnd.dece.sd uvs uvvs
video/vnd.dece.video uvv uvvv
video/vnd.dvb.file dvb
video/vnd.fvt fvt
video/vnd.mpegurl mxu m4u
video/vnd.ms-playready.media.pyv pyv
video/vnd.uvvu.mp4 uvu uvvu
video/vnd.vivo viv
video/webm webm
video/x-f4v f4v
video/x-fli fli
video/x-flv flv
video/x-m4v m4v
video/x-matroska mkv mk3d mks
video/x-mng mng
video/x-ms-asf asf asx
video/x-ms-vob vob
video/x-ms-wm wm
video/x-ms-wmv wmv
video/x-ms-wmx wmx
video/x-ms-wvx wvx
video/x-msvideo avi
video/x-sgi-movie movie
video/x-smv smv
x-conference/x-cooltalk ice
@@ -0,0 +1,151 @@
<?php
/**
* elFinder Plugin AutoResize
* Auto resize on file upload.
* ex. binding, configure on connector options
* $opts = array(
* 'bind' => array(
* 'upload.presave' => array(
* 'Plugin.AutoResize.onUpLoadPreSave'
* )
* ),
* // global configure (optional)
* 'plugin' => array(
* 'AutoResize' => array(
* 'enable' => true, // For control by volume driver
* 'maxWidth' => 1024, // Path to Water mark image
* 'maxHeight' => 1024, // Margin right pixel
* 'quality' => 95, // JPEG image save quality
* 'preserveExif' => false, // Preserve EXIF data (Imagick only)
* 'forceEffect' => false, // For change quality or make progressive JPEG of small images
* 'targetType' => IMG_GIF|IMG_JPG|IMG_PNG|IMG_WBMP, // Target image formats ( bit-field )
* 'offDropWith' => null, // Enabled by default. To disable it if it is dropped with pressing the meta key
* // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value
* // In case of using any key, specify it as an array
* 'onDropWith' => null // Disabled by default. To enable it if it is dropped with pressing the meta key
* // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value
* // In case of using any key, specify it as an array
* )
* ),
* // each volume configure (optional)
* 'roots' => array(
* array(
* 'driver' => 'LocalFileSystem',
* 'path' => '/path/to/files/',
* 'URL' => 'http://localhost/to/files/'
* 'plugin' => array(
* 'AutoResize' => array(
* 'enable' => true, // For control by volume driver
* 'maxWidth' => 1024, // Path to Water mark image
* 'maxHeight' => 1024, // Margin right pixel
* 'quality' => 95, // JPEG image save quality
* 'preserveExif' => false, // Preserve EXIF data (Imagick only)
* 'forceEffect' => false, // For change quality or make progressive JPEG of small images
* 'targetType' => IMG_GIF|IMG_JPG|IMG_PNG|IMG_WBMP, // Target image formats ( bit-field )
* 'offDropWith' => null, // Enabled by default. To disable it if it is dropped with pressing the meta key
* // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value
* // In case of using any key, specify it as an array
* 'onDropWith' => null // Disabled by default. To enable it if it is dropped with pressing the meta key
* // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value
* // In case of using any key, specify it as an array
* )
* )
* )
* )
* );
*
* @package elfinder
* @author Naoki Sawada
* @license New BSD
*/
class elFinderPluginAutoResize extends elFinderPlugin
{
public function __construct($opts)
{
$defaults = array(
'enable' => true, // For control by volume driver
'maxWidth' => 1024, // Path to Water mark image
'maxHeight' => 1024, // Margin right pixel
'quality' => 95, // JPEG image save quality
'preserveExif' => false, // Preserve EXIF data (Imagick only)
'forceEffect' => false, // For change quality or make progressive JPEG of small images
'targetType' => IMG_GIF | IMG_JPG | IMG_PNG | IMG_WBMP, // Target image formats ( bit-field )
'offDropWith' => null, // To disable it if it is dropped with pressing the meta key
// Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value
// In case of using any key, specify it as an array
'disableWithContentSaveId' => true // Disable on URL upload with post data "contentSaveId"
);
$this->opts = array_merge($defaults, $opts);
}
public function onUpLoadPreSave(&$thash, &$name, $src, $elfinder, $volume)
{
if (!$src) {
return false;
}
$opts = $this->getCurrentOpts($volume);
if (!$this->iaEnabled($opts, $elfinder)) {
return false;
}
$imageType = null;
$srcImgInfo = null;
if (extension_loaded('fileinfo') && function_exists('mime_content_type')) {
$mime = mime_content_type($src);
if (substr($mime, 0, 5) !== 'image') {
return false;
}
}
if (extension_loaded('exif') && function_exists('exif_imagetype')) {
$imageType = exif_imagetype($src);
if ($imageType === false) {
return false;
}
} else {
$srcImgInfo = getimagesize($src);
if ($srcImgInfo === false) {
return false;
}
$imageType = $srcImgInfo[2];
}
// check target image type
$imgTypes = array(
IMAGETYPE_GIF => IMG_GIF,
IMAGETYPE_JPEG => IMG_JPEG,
IMAGETYPE_PNG => IMG_PNG,
IMAGETYPE_BMP => IMG_WBMP,
IMAGETYPE_WBMP => IMG_WBMP
);
if (!isset($imgTypes[$imageType]) || !($opts['targetType'] & $imgTypes[$imageType])) {
return false;
}
if (!$srcImgInfo) {
$srcImgInfo = getimagesize($src);
}
if ($opts['forceEffect'] || $srcImgInfo[0] > $opts['maxWidth'] || $srcImgInfo[1] > $opts['maxHeight']) {
return $this->resize($volume, $src, $srcImgInfo, $opts['maxWidth'], $opts['maxHeight'], $opts['quality'], $opts['preserveExif']);
}
return false;
}
private function resize($volume, $src, $srcImgInfo, $maxWidth, $maxHeight, $jpgQuality, $preserveExif)
{
$zoom = min(($maxWidth / $srcImgInfo[0]), ($maxHeight / $srcImgInfo[1]));
$width = round($srcImgInfo[0] * $zoom);
$height = round($srcImgInfo[1] * $zoom);
$unenlarge = true;
$checkAnimated = true;
return $volume->imageUtil('resize', $src, compact('width', 'height', 'jpgQuality', 'preserveExif', 'unenlarge', 'checkAnimated'));
}
}
@@ -0,0 +1,148 @@
<?php
/**
* elFinder Plugin AutoRotate
* Auto rotation on file upload of JPEG file by EXIF Orientation.
* ex. binding, configure on connector options
* $opts = array(
* 'bind' => array(
* 'upload.presave' => array(
* 'Plugin.AutoRotate.onUpLoadPreSave'
* )
* ),
* // global configure (optional)
* 'plugin' => array(
* 'AutoRotate' => array(
* 'enable' => true, // For control by volume driver
* 'quality' => 95, // JPEG image save quality
* 'offDropWith' => null, // Enabled by default. To disable it if it is dropped with pressing the meta key
* // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value
* // In case of using any key, specify it as an array
* 'onDropWith' => null // Disabled by default. To enable it if it is dropped with pressing the meta key
* // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value
* // In case of using any key, specify it as an array
* )
* ),
* // each volume configure (optional)
* 'roots' => array(
* array(
* 'driver' => 'LocalFileSystem',
* 'path' => '/path/to/files/',
* 'URL' => 'http://localhost/to/files/'
* 'plugin' => array(
* 'AutoRotate' => array(
* 'enable' => true, // For control by volume driver
* 'quality' => 95, // JPEG image save quality
* 'offDropWith' => null, // Enabled by default. To disable it if it is dropped with pressing the meta key
* // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value
* // In case of using any key, specify it as an array
* 'onDropWith' => null // Disabled by default. To enable it if it is dropped with pressing the meta key
* // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value
* // In case of using any key, specify it as an array
* )
* )
* )
* )
* );
*
* @package elfinder
* @author Naoki Sawada
* @license New BSD
*/
class elFinderPluginAutoRotate extends elFinderPlugin
{
public function __construct($opts)
{
$defaults = array(
'enable' => true, // For control by volume driver
'quality' => 95, // JPEG image save quality
'offDropWith' => null, // To disable it if it is dropped with pressing the meta key
// Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value
// In case of using any key, specify it as an array
'disableWithContentSaveId' => true // Disable on URL upload with post data "contentSaveId"
);
$this->opts = array_merge($defaults, $opts);
}
public function onUpLoadPreSave(&$thash, &$name, $src, $elfinder, $volume)
{
if (!$src) {
return false;
}
$opts = $this->getCurrentOpts($volume);
if (!$this->iaEnabled($opts, $elfinder)) {
return false;
}
$imageType = null;
$srcImgInfo = null;
if (extension_loaded('fileinfo') && function_exists('mime_content_type')) {
$mime = mime_content_type($src);
if (substr($mime, 0, 5) !== 'image') {
return false;
}
}
if (extension_loaded('exif') && function_exists('exif_imagetype')) {
$imageType = exif_imagetype($src);
if ($imageType === false) {
return false;
}
} else {
$srcImgInfo = getimagesize($src);
if ($srcImgInfo === false) {
return false;
}
$imageType = $srcImgInfo[2];
}
// check target image type
if ($imageType !== IMAGETYPE_JPEG) {
return false;
}
if (!$srcImgInfo) {
$srcImgInfo = getimagesize($src);
}
return $this->rotate($volume, $src, $srcImgInfo, $opts['quality']);
}
private function rotate($volume, $src, $srcImgInfo, $quality)
{
if (!function_exists('exif_read_data')) {
return false;
}
$degree = 0;
$errlev =error_reporting();
error_reporting($errlev ^ E_WARNING);
$exif = exif_read_data($src);
error_reporting($errlev);
if ($exif && !empty($exif['Orientation'])) {
switch ($exif['Orientation']) {
case 8:
$degree = 270;
break;
case 3:
$degree = 180;
break;
case 6:
$degree = 90;
break;
}
}
if (!$degree) {
return false;
}
$opts = array(
'degree' => $degree,
'jpgQuality' => $quality,
'checkAnimated' => true
);
return $volume->imageUtil('rotate', $src, $opts);
}
}
@@ -0,0 +1,204 @@
<?php
/**
* elFinder Plugin Normalizer
* UTF-8 Normalizer of file-name and file-path etc.
* nfc(NFC): Canonical Decomposition followed by Canonical Composition
* nfkc(NFKC): Compatibility Decomposition followed by Canonical
* This plugin require Class "Normalizer" (PHP 5 >= 5.3.0, PECL intl >= 1.0.0)
* or PEAR package "I18N_UnicodeNormalizer"
* ex. binding, configure on connector options
* $opts = array(
* 'bind' => array(
* 'upload.pre mkdir.pre mkfile.pre rename.pre archive.pre ls.pre' => array(
* 'Plugin.Normalizer.cmdPreprocess'
* ),
* 'upload.presave paste.copyfrom' => array(
* 'Plugin.Normalizer.onUpLoadPreSave'
* )
* ),
* // global configure (optional)
* 'plugin' => array(
* 'Normalizer' => array(
* 'enable' => true,
* 'nfc' => true,
* 'nfkc' => true,
* 'umlauts' => false,
* 'lowercase' => false,
* 'convmap' => array()
* )
* ),
* // each volume configure (optional)
* 'roots' => array(
* array(
* 'driver' => 'LocalFileSystem',
* 'path' => '/path/to/files/',
* 'URL' => 'http://localhost/to/files/'
* 'plugin' => array(
* 'Normalizer' => array(
* 'enable' => true,
* 'nfc' => true,
* 'nfkc' => true,
* 'umlauts' => false,
* 'lowercase' => false,
* 'convmap' => array()
* )
* )
* )
* )
* );
*
* @package elfinder
* @author Naoki Sawada
* @license New BSD
*/
class elFinderPluginNormalizer extends elFinderPlugin
{
private $replaced = array();
private $keyMap = array(
'ls' => 'intersect',
'upload' => 'renames',
'mkdir' => array('name', 'dirs')
);
public function __construct($opts)
{
$defaults = array(
'enable' => true, // For control by volume driver
'nfc' => true, // Canonical Decomposition followed by Canonical Composition
'nfkc' => true, // Compatibility Decomposition followed by Canonical
'umlauts' => false, // Convert umlauts with their closest 7 bit ascii equivalent
'lowercase' => false, // Make chars lowercase
'convmap' => array()// Convert map ('FROM' => 'TO') array
);
$this->opts = array_merge($defaults, $opts);
}
public function cmdPreprocess($cmd, &$args, $elfinder, $volume)
{
$opts = $this->getCurrentOpts($volume);
if (!$opts['enable']) {
return false;
}
$this->replaced[$cmd] = array();
$key = (isset($this->keyMap[$cmd])) ? $this->keyMap[$cmd] : 'name';
if (is_array($key)) {
$keys = $key;
} else {
$keys = array($key);
}
foreach ($keys as $key) {
if (isset($args[$key])) {
if (is_array($args[$key])) {
foreach ($args[$key] as $i => $name) {
if ($cmd === 'mkdir' && $key === 'dirs') {
// $name need '/' as prefix see #2607
$name = '/' . ltrim($name, '/');
$_names = explode('/', $name);
$_res = array();
foreach ($_names as $_name) {
$_res[] = $this->normalize($_name, $opts);
}
$this->replaced[$cmd][$name] = $args[$key][$i] = join('/', $_res);
} else {
$this->replaced[$cmd][$name] = $args[$key][$i] = $this->normalize($name, $opts);
}
}
} else if ($args[$key] !== '') {
$name = $args[$key];
$this->replaced[$cmd][$name] = $args[$key] = $this->normalize($name, $opts);
}
}
}
if ($cmd === 'ls' || $cmd === 'mkdir') {
if (!empty($this->replaced[$cmd])) {
// un-regist for legacy settings
$elfinder->unbind($cmd, array($this, 'cmdPostprocess'));
$elfinder->bind($cmd, array($this, 'cmdPostprocess'));
}
}
return true;
}
public function cmdPostprocess($cmd, &$result, $args, $elfinder, $volume)
{
if ($cmd === 'ls') {
if (!empty($result['list']) && !empty($this->replaced['ls'])) {
foreach ($result['list'] as $hash => $name) {
if ($keys = array_keys($this->replaced['ls'], $name)) {
if (count($keys) === 1) {
$result['list'][$hash] = $keys[0];
} else {
$result['list'][$hash] = $keys;
}
}
}
}
} else if ($cmd === 'mkdir') {
if (!empty($result['hashes']) && !empty($this->replaced['mkdir'])) {
foreach ($result['hashes'] as $name => $hash) {
if ($keys = array_keys($this->replaced['mkdir'], $name)) {
$result['hashes'][$keys[0]] = $hash;
}
}
}
}
}
// NOTE: $thash is directory hash so it unneed to process at here
public function onUpLoadPreSave(&$thash, &$name, $src, $elfinder, $volume)
{
$opts = $this->getCurrentOpts($volume);
if (!$opts['enable']) {
return false;
}
$name = $this->normalize($name, $opts);
return true;
}
protected function normalize($str, $opts)
{
if ($opts['nfc'] || $opts['nfkc']) {
if (class_exists('Normalizer', false)) {
if ($opts['nfc'] && !Normalizer::isNormalized($str, Normalizer::FORM_C))
$str = Normalizer::normalize($str, Normalizer::FORM_C);
if ($opts['nfkc'] && !Normalizer::isNormalized($str, Normalizer::FORM_KC))
$str = Normalizer::normalize($str, Normalizer::FORM_KC);
} else {
if (!class_exists('I18N_UnicodeNormalizer', false)) {
if (is_readable('I18N/UnicodeNormalizer.php')) {
include_once 'I18N/UnicodeNormalizer.php';
} else {
trigger_error('Plugin Normalizer\'s options "nfc" or "nfkc" require PHP class "Normalizer" or PEAR package "I18N_UnicodeNormalizer"', E_USER_WARNING);
}
}
if (class_exists('I18N_UnicodeNormalizer', false)) {
$normalizer = new I18N_UnicodeNormalizer();
if ($opts['nfc'])
$str = $normalizer->normalize($str, 'NFC');
if ($opts['nfkc'])
$str = $normalizer->normalize($str, 'NFKC');
}
}
}
if ($opts['umlauts']) {
if (strpos($str = htmlentities($str, ENT_QUOTES, 'UTF-8'), '&') !== false) {
$str = html_entity_decode(preg_replace('~&([a-z]{1,2})(?:acute|caron|cedil|circ|grave|lig|orn|ring|slash|tilde|uml);~i', '$1', $str), ENT_QUOTES, 'utf-8');
}
}
if ($opts['convmap'] && is_array($opts['convmap'])) {
$str = strtr($str, $opts['convmap']);
}
if ($opts['lowercase']) {
if (function_exists('mb_strtolower')) {
$str = mb_strtolower($str, 'UTF-8');
} else {
$str = strtolower($str);
}
}
return $str;
}
}
@@ -0,0 +1,157 @@
<?php
/**
* elFinder Plugin Sanitizer
* Sanitizer of file-name and file-path etc.
* ex. binding, configure on connector options
* $opts = array(
* 'bind' => array(
* 'upload.pre mkdir.pre mkfile.pre rename.pre archive.pre ls.pre' => array(
* 'Plugin.Sanitizer.cmdPreprocess'
* ),
* 'upload.presave paste.copyfrom' => array(
* 'Plugin.Sanitizer.onUpLoadPreSave'
* )
* ),
* // global configure (optional)
* 'plugin' => array(
* 'Sanitizer' => array(
* 'enable' => true,
* 'targets' => array('\\','/',':','*','?','"','<','>','|'), // target chars
* 'replace' => '_', // replace to this
* 'callBack' => null // Or @callable sanitize function
* )
* ),
* // each volume configure (optional)
* 'roots' => array(
* array(
* 'driver' => 'LocalFileSystem',
* 'path' => '/path/to/files/',
* 'URL' => 'http://localhost/to/files/'
* 'plugin' => array(
* 'Sanitizer' => array(
* 'enable' => true,
* 'targets' => array('\\','/',':','*','?','"','<','>','|'), // target chars
* 'replace' => '_', // replace to this
* 'callBack' => null // Or @callable sanitize function
* )
* )
* )
* )
* );
*
* @package elfinder
* @author Naoki Sawada
* @license New BSD
*/
class elFinderPluginSanitizer extends elFinderPlugin
{
private $replaced = array();
private $keyMap = array(
'ls' => 'intersect',
'upload' => 'renames',
'mkdir' => array('name', 'dirs')
);
public function __construct($opts)
{
$defaults = array(
'enable' => true, // For control by volume driver
'targets' => array('\\', '/', ':', '*', '?', '"', '<', '>', '|'), // target chars
'replace' => '_', // replace to this
'callBack' => null // Or callable sanitize function
);
$this->opts = array_merge($defaults, $opts);
}
public function cmdPreprocess($cmd, &$args, $elfinder, $volume)
{
$opts = $this->getCurrentOpts($volume);
if (!$opts['enable']) {
return false;
}
$this->replaced[$cmd] = array();
$key = (isset($this->keyMap[$cmd])) ? $this->keyMap[$cmd] : 'name';
if (is_array($key)) {
$keys = $key;
} else {
$keys = array($key);
}
foreach ($keys as $key) {
if (isset($args[$key])) {
if (is_array($args[$key])) {
foreach ($args[$key] as $i => $name) {
if ($cmd === 'mkdir' && $key === 'dirs') {
// $name need '/' as prefix see #2607
$name = '/' . ltrim($name, '/');
$_names = explode('/', $name);
$_res = array();
foreach ($_names as $_name) {
$_res[] = $this->sanitizeFileName($_name, $opts);
}
$this->replaced[$cmd][$name] = $args[$key][$i] = join('/', $_res);
} else {
$this->replaced[$cmd][$name] = $args[$key][$i] = $this->sanitizeFileName($name, $opts);
}
}
} else if ($args[$key] !== '') {
$name = $args[$key];
$this->replaced[$cmd][$name] = $args[$key] = $this->sanitizeFileName($name, $opts);
}
}
}
if ($cmd === 'ls' || $cmd === 'mkdir') {
if (!empty($this->replaced[$cmd])) {
// un-regist for legacy settings
$elfinder->unbind($cmd, array($this, 'cmdPostprocess'));
$elfinder->bind($cmd, array($this, 'cmdPostprocess'));
}
}
return true;
}
public function cmdPostprocess($cmd, &$result, $args, $elfinder, $volume)
{
if ($cmd === 'ls') {
if (!empty($result['list']) && !empty($this->replaced['ls'])) {
foreach ($result['list'] as $hash => $name) {
if ($keys = array_keys($this->replaced['ls'], $name)) {
if (count($keys) === 1) {
$result['list'][$hash] = $keys[0];
} else {
$result['list'][$hash] = $keys;
}
}
}
}
} else if ($cmd === 'mkdir') {
if (!empty($result['hashes']) && !empty($this->replaced['mkdir'])) {
foreach ($result['hashes'] as $name => $hash) {
if ($keys = array_keys($this->replaced['mkdir'], $name)) {
$result['hashes'][$keys[0]] = $hash;
}
}
}
}
}
// NOTE: $thash is directory hash so it unneed to process at here
public function onUpLoadPreSave(&$thash, &$name, $src, $elfinder, $volume)
{
$opts = $this->getCurrentOpts($volume);
if (!$opts['enable']) {
return false;
}
$name = $this->sanitizeFileName($name, $opts);
return true;
}
protected function sanitizeFileName($filename, $opts)
{
if (!empty($opts['callBack']) && is_callable($opts['callBack'])) {
return call_user_func_array($opts['callBack'], array($filename, $opts));
}
return str_replace($opts['targets'], $opts['replace'], $filename);
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

@@ -0,0 +1,432 @@
<?php
/**
* elFinder Plugin Watermark
* Print watermark on file upload.
* ex. binding, configure on connector options
* $opts = array(
* 'bind' => array(
* 'upload.presave' => array(
* 'Plugin.Watermark.onUpLoadPreSave'
* )
* ),
* // global configure (optional)
* 'plugin' => array(
* 'Watermark' => array(
* 'enable' => true, // For control by volume driver
* 'source' => 'logo.png', // Path to Water mark image
* 'ratio' => 0.2, // Ratio to original image (ratio > 0 and ratio <= 1)
* 'position' => 'RB', // Position L(eft)/C(enter)/R(ight) and T(op)/M(edium)/B(ottom)
* 'marginX' => 5, // Margin horizontal pixel
* 'marginY' => 5, // Margin vertical pixel
* 'quality' => 95, // JPEG image save quality
* 'transparency' => 70, // Water mark image transparency ( other than PNG )
* 'targetType' => IMG_GIF|IMG_JPG|IMG_PNG|IMG_WBMP, // Target image formats ( bit-field )
* 'targetMinPixel' => 200, // Target image minimum pixel size
* 'interlace' => IMG_GIF|IMG_JPG, // Set interlacebit image formats ( bit-field )
* 'offDropWith' => null, // Enabled by default. To disable it if it is dropped with pressing the meta key
* // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value
* // In case of using any key, specify it as an array
* 'onDropWith' => null // Disabled by default. To enable it if it is dropped with pressing the meta key
* // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value
* // In case of using any key, specify it as an array
* )
* ),
* // each volume configure (optional)
* 'roots' => array(
* array(
* 'driver' => 'LocalFileSystem',
* 'path' => '/path/to/files/',
* 'URL' => 'http://localhost/to/files/'
* 'plugin' => array(
* 'Watermark' => array(
* 'enable' => true, // For control by volume driver
* 'source' => 'logo.png', // Path to Water mark image
* 'ratio' => 0.2, // Ratio to original image (ratio > 0 and ratio <= 1)
* 'position' => 'RB', // Position L(eft)/C(enter)/R(ight) and T(op)/M(edium)/B(ottom)
* 'marginX' => 5, // Margin horizontal pixel
* 'marginY' => 5, // Margin vertical pixel
* 'quality' => 95, // JPEG image save quality
* 'transparency' => 70, // Water mark image transparency ( other than PNG )
* 'targetType' => IMG_GIF|IMG_JPG|IMG_PNG|IMG_WBMP, // Target image formats ( bit-field )
* 'targetMinPixel' => 200, // Target image minimum pixel size
* 'interlace' => IMG_GIF|IMG_JPG, // Set interlacebit image formats ( bit-field )
* 'offDropWith' => null, // Enabled by default. To disable it if it is dropped with pressing the meta key
* // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value
* // In case of using any key, specify it as an array
* 'onDropWith' => null // Disabled by default. To enable it if it is dropped with pressing the meta key
* // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value
* // In case of using any key, specify it as an array
* )
* )
* )
* )
* );
*
* @package elfinder
* @author Naoki Sawada
* @license New BSD
*/
class elFinderPluginWatermark extends elFinderPlugin
{
private $watermarkImgInfo = null;
public function __construct($opts)
{
$defaults = array(
'enable' => true, // For control by volume driver
'source' => 'logo.png', // Path to Water mark image
'ratio' => 0.2, // Ratio to original image (ratio > 0 and ratio <= 1)
'position' => 'RB', // Position L(eft)/C(enter)/R(ight) and T(op)/M(edium)/B(ottom)
'marginX' => 5, // Margin horizontal pixel
'marginY' => 5, // Margin vertical pixel
'quality' => 95, // JPEG image save quality
'transparency' => 70, // Water mark image transparency ( other than PNG )
'targetType' => IMG_GIF | IMG_JPG | IMG_PNG | IMG_WBMP, // Target image formats ( bit-field )
'targetMinPixel' => 200, // Target image minimum pixel size
'interlace' => IMG_GIF | IMG_JPG, // Set interlacebit image formats ( bit-field )
'offDropWith' => null, // To disable it if it is dropped with pressing the meta key
// Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value
// In case of using any key, specify it as an array
'marginRight' => 0, // Deprecated - marginX should be used
'marginBottom' => 0, // Deprecated - marginY should be used
'disableWithContentSaveId' => true // Disable on URL upload with post data "contentSaveId"
);
$this->opts = array_merge($defaults, $opts);
}
public function onUpLoadPreSave(&$thash, &$name, $src, $elfinder, $volume)
{
if (!$src) {
return false;
}
$opts = $this->getCurrentOpts($volume);
if (!$this->iaEnabled($opts, $elfinder)) {
return false;
}
$imageType = null;
$srcImgInfo = null;
if (extension_loaded('fileinfo') && function_exists('mime_content_type')) {
$mime = mime_content_type($src);
if (substr($mime, 0, 5) !== 'image') {
return false;
}
}
if (extension_loaded('exif') && function_exists('exif_imagetype')) {
$imageType = exif_imagetype($src);
if ($imageType === false) {
return false;
}
} else {
$srcImgInfo = getimagesize($src);
if ($srcImgInfo === false) {
return false;
}
$imageType = $srcImgInfo[2];
}
// check target image type
$imgTypes = array(
IMAGETYPE_GIF => IMG_GIF,
IMAGETYPE_JPEG => IMG_JPEG,
IMAGETYPE_PNG => IMG_PNG,
IMAGETYPE_BMP => IMG_WBMP,
IMAGETYPE_WBMP => IMG_WBMP
);
if (!isset($imgTypes[$imageType]) || !($opts['targetType'] & $imgTypes[$imageType])) {
return false;
}
// check Animation Gif
if ($imageType === IMAGETYPE_GIF && elFinder::isAnimationGif($src)) {
return false;
}
// check Animation Png
if ($imageType === IMAGETYPE_PNG && elFinder::isAnimationPng($src)) {
return false;
}
// check water mark image
if (!file_exists($opts['source'])) {
$opts['source'] = dirname(__FILE__) . "/" . $opts['source'];
}
if (is_readable($opts['source'])) {
$watermarkImgInfo = getimagesize($opts['source']);
if (!$watermarkImgInfo) {
return false;
}
} else {
return false;
}
if (!$srcImgInfo) {
$srcImgInfo = getimagesize($src);
}
$watermark = $opts['source'];
$quality = $opts['quality'];
$transparency = $opts['transparency'];
// check target image size
if ($opts['targetMinPixel'] > 0 && $opts['targetMinPixel'] > min($srcImgInfo[0], $srcImgInfo[1])) {
return false;
}
$watermark_width = $watermarkImgInfo[0];
$watermark_height = $watermarkImgInfo[1];
// Specified as a ratio to the image size
if ($opts['ratio'] && $opts['ratio'] > 0 && $opts['ratio'] <= 1) {
$maxW = $srcImgInfo[0] * $opts['ratio'] - ($opts['marginX'] * 2);
$maxH = $srcImgInfo[1] * $opts['ratio'] - ($opts['marginY'] * 2);
$dx = $dy = 0;
if (($maxW >= $watermarkImgInfo[0] && $maxH >= $watermarkImgInfo[0]) || ($maxW <= $watermarkImgInfo[0] && $maxH <= $watermarkImgInfo[0])) {
$dx = abs($srcImgInfo[0] - $watermarkImgInfo[0]);
$dy = abs($srcImgInfo[1] - $watermarkImgInfo[1]);
} else if ($maxW < $watermarkImgInfo[0]) {
$dx = -1;
} else {
$dy = -1;
}
if ($dx < $dy) {
$ww = $maxW;
$wh = $watermarkImgInfo[1] * ($ww / $watermarkImgInfo[0]);
} else {
$wh = $maxH;
$ww = $watermarkImgInfo[0] * ($wh / $watermarkImgInfo[1]);
}
$watermarkImgInfo[0] = $ww;
$watermarkImgInfo[1] = $wh;
} else {
$opts['ratio'] = null;
}
$opts['position'] = strtoupper($opts['position']);
// Set vertical position
if (strpos($opts['position'], 'T') !== false) {
// Top
$dest_x = $opts['marginX'];
} else if (strpos($opts['position'], 'M') !== false) {
// Middle
$dest_x = ($srcImgInfo[0] - $watermarkImgInfo[0]) / 2;
} else {
// Bottom
$dest_x = $srcImgInfo[0] - $watermarkImgInfo[0] - max($opts['marginBottom'], $opts['marginX']);
}
// Set horizontal position
if (strpos($opts['position'], 'L') !== false) {
// Left
$dest_y = $opts['marginY'];
} else if (strpos($opts['position'], 'C') !== false) {
// Middle
$dest_y = ($srcImgInfo[1] - $watermarkImgInfo[1]) / 2;
} else {
// Right
$dest_y = $srcImgInfo[1] - $watermarkImgInfo[1] - max($opts['marginRight'], $opts['marginY']);
}
// check interlace
$opts['interlace'] = ($opts['interlace'] & $imgTypes[$imageType]);
// Repeated use of Imagick::compositeImage() may cause PHP to hang, so disable it
//if (class_exists('Imagick', false)) {
// return $this->watermarkPrint_imagick($src, $watermark, $dest_x, $dest_y, $quality, $transparency, $watermarkImgInfo, $opts);
//} else {
elFinder::expandMemoryForGD(array($watermarkImgInfo, $srcImgInfo));
return $this->watermarkPrint_gd($src, $watermark, $dest_x, $dest_y, $quality, $transparency, $watermarkImgInfo, $srcImgInfo, $opts);
//}
}
private function watermarkPrint_imagick($src, $watermarkSrc, $dest_x, $dest_y, $quality, $transparency, $watermarkImgInfo, $opts)
{
try {
// Open the original image
$img = new Imagick($src);
// Open the watermark
$watermark = new Imagick($watermarkSrc);
// zoom
if ($opts['ratio']) {
$watermark->scaleImage($watermarkImgInfo[0], $watermarkImgInfo[1]);
}
// Set transparency
if (strtoupper($watermark->getImageFormat()) !== 'PNG') {
$watermark->setImageOpacity($transparency / 100);
}
// Overlay the watermark on the original image
$img->compositeImage($watermark, imagick::COMPOSITE_OVER, $dest_x, $dest_y);
// Set quality
if (strtoupper($img->getImageFormat()) === 'JPEG') {
$img->setImageCompression(imagick::COMPRESSION_JPEG);
$img->setCompressionQuality($quality);
}
// set interlace
$opts['interlace'] && $img->setInterlaceScheme(Imagick::INTERLACE_PLANE);
$result = $img->writeImage($src);
$img->clear();
$img->destroy();
$watermark->clear();
$watermark->destroy();
return $result ? true : false;
} catch (Exception $e) {
$ermsg = $e->getMessage();
$ermsg && trigger_error($ermsg);
return false;
}
}
private function watermarkPrint_gd($src, $watermark, $dest_x, $dest_y, $quality, $transparency, $watermarkImgInfo, $srcImgInfo, $opts)
{
$watermark_width = $watermarkImgInfo[0];
$watermark_height = $watermarkImgInfo[1];
$ermsg = '';
switch ($watermarkImgInfo['mime']) {
case 'image/gif':
if (imagetypes() & IMG_GIF) {
$oWatermarkImg = imagecreatefromgif($watermark);
} else {
$ermsg = 'GIF images are not supported as watermark image';
}
break;
case 'image/jpeg':
if (imagetypes() & IMG_JPG) {
$oWatermarkImg = imagecreatefromjpeg($watermark);
} else {
$ermsg = 'JPEG images are not supported as watermark image';
}
break;
case 'image/png':
if (imagetypes() & IMG_PNG) {
$oWatermarkImg = imagecreatefrompng($watermark);
} else {
$ermsg = 'PNG images are not supported as watermark image';
}
break;
case 'image/wbmp':
if (imagetypes() & IMG_WBMP) {
$oWatermarkImg = imagecreatefromwbmp($watermark);
} else {
$ermsg = 'WBMP images are not supported as watermark image';
}
break;
default:
$oWatermarkImg = false;
$ermsg = $watermarkImgInfo['mime'] . ' images are not supported as watermark image';
break;
}
if (!$ermsg) {
// zoom
if ($opts['ratio']) {
$tmpImg = imagecreatetruecolor($watermarkImgInfo[0], $watermarkImgInfo[1]);
imagealphablending($tmpImg, false);
imagesavealpha($tmpImg, true);
imagecopyresampled($tmpImg, $oWatermarkImg, 0, 0, 0, 0, $watermarkImgInfo[0], $watermarkImgInfo[1], imagesx($oWatermarkImg), imagesy($oWatermarkImg));
imageDestroy($oWatermarkImg);
$oWatermarkImg = $tmpImg;
$tmpImg = null;
}
switch ($srcImgInfo['mime']) {
case 'image/gif':
if (imagetypes() & IMG_GIF) {
$oSrcImg = imagecreatefromgif($src);
} else {
$ermsg = 'GIF images are not supported as source image';
}
break;
case 'image/jpeg':
if (imagetypes() & IMG_JPG) {
$oSrcImg = imagecreatefromjpeg($src);
} else {
$ermsg = 'JPEG images are not supported as source image';
}
break;
case 'image/png':
if (imagetypes() & IMG_PNG) {
$oSrcImg = imagecreatefrompng($src);
} else {
$ermsg = 'PNG images are not supported as source image';
}
break;
case 'image/wbmp':
if (imagetypes() & IMG_WBMP) {
$oSrcImg = imagecreatefromwbmp($src);
} else {
$ermsg = 'WBMP images are not supported as source image';
}
break;
default:
$oSrcImg = false;
$ermsg = $srcImgInfo['mime'] . ' images are not supported as source image';
break;
}
}
if ($ermsg || false === $oSrcImg || false === $oWatermarkImg) {
$ermsg && trigger_error($ermsg);
return false;
}
if ($srcImgInfo['mime'] === 'image/png') {
if (function_exists('imagecolorallocatealpha')) {
$bg = imagecolorallocatealpha($oSrcImg, 255, 255, 255, 127);
imagefill($oSrcImg, 0, 0, $bg);
}
}
if ($watermarkImgInfo['mime'] === 'image/png') {
imagecopy($oSrcImg, $oWatermarkImg, $dest_x, $dest_y, 0, 0, $watermark_width, $watermark_height);
} else {
imagecopymerge($oSrcImg, $oWatermarkImg, $dest_x, $dest_y, 0, 0, $watermark_width, $watermark_height, $transparency);
}
// set interlace
$opts['interlace'] && imageinterlace($oSrcImg, true);
switch ($srcImgInfo['mime']) {
case 'image/gif':
imagegif($oSrcImg, $src);
break;
case 'image/jpeg':
imagejpeg($oSrcImg, $src, $quality);
break;
case 'image/png':
if (function_exists('imagesavealpha') && function_exists('imagealphablending')) {
imagealphablending($oSrcImg, false);
imagesavealpha($oSrcImg, true);
}
imagepng($oSrcImg, $src);
break;
case 'image/wbmp':
imagewbmp($oSrcImg, $src);
break;
}
imageDestroy($oSrcImg);
imageDestroy($oWatermarkImg);
return true;
}
}
@@ -0,0 +1,114 @@
<?php
/**
* This class describes elFinder plugin window remove tail dots.
* This plugin is automatically loaded on the Windows server
* and enabled in the LocalFileSystem driver.
*/
class elFinderPluginWinRemoveTailDots extends elFinderPlugin
{
private $replaced = array();
private $keyMap = array(
'ls' => 'intersect',
'upload' => 'renames',
'mkdir' => array('name', 'dirs')
);
public function __construct($opts)
{
$defaults = array(
'enable' => false, // For control by volume driver
);
$this->opts = array_merge($defaults, $opts);
}
public function cmdPreprocess($cmd, &$args, $elfinder, $volume)
{
$opts = $this->getCurrentOpts($volume);
if (!$opts['enable']) {
return false;
}
$this->replaced[$cmd] = array();
$key = (isset($this->keyMap[$cmd])) ? $this->keyMap[$cmd] : 'name';
if (is_array($key)) {
$keys = $key;
} else {
$keys = array($key);
}
foreach ($keys as $key) {
if (isset($args[$key])) {
if (is_array($args[$key])) {
foreach ($args[$key] as $i => $name) {
if ($cmd === 'mkdir' && $key === 'dirs') {
// $name need '/' as prefix see #2607
$name = '/' . ltrim($name, '/');
$_names = explode('/', $name);
$_res = array();
foreach ($_names as $_name) {
$_res[] = $this->normalize($_name, $opts);
}
$this->replaced[$cmd][$name] = $args[$key][$i] = join('/', $_res);
} else {
$this->replaced[$cmd][$name] = $args[$key][$i] = $this->normalize($name, $opts);
}
}
} else if ($args[$key] !== '') {
$name = $args[$key];
$this->replaced[$cmd][$name] = $args[$key] = $this->normalize($name, $opts);
}
}
}
if ($cmd === 'ls' || $cmd === 'mkdir') {
if (!empty($this->replaced[$cmd])) {
// un-regist for legacy settings
$elfinder->unbind($cmd, array($this, 'cmdPostprocess'));
$elfinder->bind($cmd, array($this, 'cmdPostprocess'));
}
}
return true;
}
public function cmdPostprocess($cmd, &$result, $args, $elfinder, $volume)
{
if ($cmd === 'ls') {
if (!empty($result['list']) && !empty($this->replaced['ls'])) {
foreach ($result['list'] as $hash => $name) {
if ($keys = array_keys($this->replaced['ls'], $name)) {
if (count($keys) === 1) {
$result['list'][$hash] = $keys[0];
} else {
$result['list'][$hash] = $keys;
}
}
}
}
} else if ($cmd === 'mkdir') {
if (!empty($result['hashes']) && !empty($this->replaced['mkdir'])) {
foreach ($result['hashes'] as $name => $hash) {
if ($keys = array_keys($this->replaced['mkdir'], $name)) {
$result['hashes'][$keys[0]] = $hash;
}
}
}
}
}
// NOTE: $thash is directory hash so it unneed to process at here
public function onUpLoadPreSave(&$thash, &$name, $src, $elfinder, $volume)
{
$opts = $this->getCurrentOpts($volume);
if (!$opts['enable']) {
return false;
}
$name = $this->normalize($name, $opts);
return true;
}
protected function normalize($str, $opts)
{
$str = rtrim($str, '.');
return $str;
}
} // END class elFinderPluginWinRemoveTailDots
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB