Elfinder update - preliminary

preliminary
This commit is contained in:
Buchholz 2021-10-10 15:44:47 +02:00
parent 45359b8192
commit f87d9830c6
27 changed files with 6194 additions and 2286 deletions

View file

@ -180,4 +180,9 @@ $opts = array(
// run elFinder
$connector = new elFinderConnector(new elFinder($opts));
$connector->run();
try {
$connector->run();
} catch (Exception $e) {
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -2,7 +2,7 @@ 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(256) 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',
@ -16,8 +16,32 @@ CREATE TABLE IF NOT EXISTS `elfinder_file` (
PRIMARY KEY (`id`),
UNIQUE KEY `parent_name` (`parent_id`, `name`),
KEY `parent_id` (`parent_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
) 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');
(`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');

View file

@ -26,6 +26,7 @@ function elFinderAutoloader($name)
'elFinderVolumeGroup' => 'elFinderVolumeGroup.class.php',
'elFinderVolumeLocalFileSystem' => 'elFinderVolumeLocalFileSystem.class.php',
'elFinderVolumeMySQL' => 'elFinderVolumeMySQL.class.php',
'elFinderVolumeSFTPphpseclib' => 'elFinderVolumeSFTPphpseclib.class.php',
'elFinderVolumeTrash' => 'elFinderVolumeTrash.class.php',
);
if (isset($map[$name])) {

View file

@ -0,0 +1,448 @@
<?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';
// // GoogleDrive Netmount driver need next two settings. You can get at https://dev.onedrive.com
// // 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();

View file

@ -2,6 +2,26 @@
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
@ -9,50 +29,55 @@ error_reporting(0); // Set E_ALL for debuging
// define('ELFINDER_IMAGEMAGICK_PS', true);
// ===============================================
// load composer autoload before load elFinder autoload If you need composer
//require './vendor/autoload.php';
// // 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
// // elFinder autoload
require './autoload.php';
// ===============================================
// Enable FTP connector netmount
// // Enable FTP connector netmount
elFinder::$netDrivers['ftp'] = 'FTP';
// ===============================================
// // Required for Dropbox network mount
// // Installation by composer
// // `composer require kunalvarma05/dropbox-php-sdk`
// // `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 reuire regist redirect url to "YOUR_CONNECTOR_URL?cmd=netmount&protocol=dropbox2&host=1"
// // 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`
// // `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 reuire regist redirect url to "YOUR_CONNECTOR_URL?cmd=netmount&protocol=googledrive&host=1"
// // 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 of without composer
// // 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`
// // `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 reuire regist redirect url to "YOUR_CONNECTOR_URL?cmd=netmount&protocol=googledrive&host=1"
// // 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
@ -61,7 +86,8 @@ elFinder::$netDrivers['ftp'] = 'FTP';
// // Enable network mount
// elFinder::$netDrivers['onedrive'] = 'OneDrive';
// // GoogleDrive Netmount driver need next two settings. You can get at https://dev.onedrive.com
// // AND reuire regist redirect url to "YOUR_CONNECTOR_URL/netmount/onedrive/1"
// // 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', '');
// ===============================================
@ -71,7 +97,8 @@ elFinder::$netDrivers['ftp'] = 'FTP';
// // Enable network mount
// elFinder::$netDrivers['box'] = 'Box';
// // Box Netmount driver need next two settings. You can get at https://developer.box.com
// // AND reuire regist redirect url to "YOUR_CONNECTOR_URL"
// // 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', '');
// ===============================================
@ -89,7 +116,7 @@ elFinder::$netDrivers['ftp'] = 'FTP';
// // Zip Archive editor
// // Installation by composer
// // `composer require nao-pon/elfinder-flysystem-ziparchive-netmount`
// // `composer require nao-pon/elfinder-flysystem-ziparchive-netmount` on php directory
// define('ELFINDER_DISABLE_ZIPEDITOR', false); // set `true` to disable zip editor
// ===============================================
@ -142,7 +169,7 @@ $opts = array(
'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
)
),
)
);

View file

@ -6,7 +6,7 @@ class elFinderEditorOnlineConvert extends elFinderEditor
public function enabled()
{
return !defined('ELFINDER_DISABLE_ONLINE_CONVERT') || !ELFINDER_DISABLE_ONLINE_CONVERT;
return defined('ELFINDER_ONLINE_CONVERT_APIKEY') && ELFINDER_ONLINE_CONVERT_APIKEY && (!defined('ELFINDER_DISABLE_ONLINE_CONVERT') || !ELFINDER_DISABLE_ONLINE_CONVERT);
}
public function init()

View file

@ -6,10 +6,21 @@ class elFinderEditorZohoOffice extends elFinderEditor
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://writer.zoho.com/writer/remotedoc.im',
'sheet' => 'https://sheet.zoho.com/sheet/remotedoc.im',
'show' => 'https://show.zoho.com/show/remotedoc.im',
'writer' => 'https://writer.zoho.com/writer/officeapi/v1/document',
'sheet' => 'https://sheet.zoho.com/sheet/officeapi/v1/spreadsheet',
'show' => 'https://show.zoho.com/show/officeapi/v1/presentation',
);
private $srvs = array(
@ -32,6 +43,14 @@ class elFinderEditorZohoOffice extends elFinderEditor
'application/vnd.sun.xml.impress' => 'show',
);
private $myName = '';
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');
@ -51,7 +70,8 @@ class elFinderEditorZohoOffice extends elFinderEditor
$cookie = $this->elfinder->getFetchCookieFile();
$save = false;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, elFinder::getConnectorUrl() . '?cmd=editor&name=ZohoOffice&method=chk&args[target]=' . rawurlencode($hash) . $cdata);
$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);
@ -94,18 +114,29 @@ class elFinderEditorZohoOffice extends elFinderEditor
$srvsName = $this->srvs[$file['mime']];
$data = array(
'apikey' => ELFINDER_ZOHO_OFFICE_APIKEY,
'output' => 'url',
'mode' => 'normaledit',
'filename' => $file['name'],
'id' => $hash,
'format' => $format,
'lang' => $lang
'callback_settings' => array(
'save_format' => $format,
'context_info' => 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) {
$data['saveurl'] = elFinder::getConnectorUrl() . '?cmd=editor&name=ZohoOffice&method=save' . $cdata;
$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['content'] = $cfile;
$data['document'] = $cfile;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->urls[$srvsName]);
@ -120,16 +151,12 @@ class elFinderEditorZohoOffice extends elFinderEditor
$fp && fclose($fp);
if ($res) {
if (strpos($res, 'RESULT=TRUE') !== false) {
list(, $url) = explode('URL=', $res);
preg_match('/URL=([^\s]+)/', $res, $m);
$ret = array('zohourl' => $m[1]);
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;
@ -137,23 +164,27 @@ class elFinderEditorZohoOffice extends elFinderEditor
}
if ($error) {
return array('error' => preg_split('/[\r\n]+/', $error));
return array('error' => is_string($error)? preg_split('/[\r\n]+/', $error) : 'Error code: ' . $error);
}
}
}
return array('error' => array('errCmdParams', 'editor.ZohoOffice.init'));
return array('error' => array('errCmdParams', 'editor.' . $this->myName . '.init'));
}
public function save()
{
if (isset($_POST) && !empty($_POST['id'])) {
$hash = $_POST['id'];
/** @var elFinderVolumeDriver $volume */
if ($volume = $this->elfinder->getVolume($hash)) {
$content = file_get_contents($_FILES['content']['tmp_name']);
if ($volume->putContents($hash, $content)) {
return array('raw' => true, 'error' => '', 'header' => 'HTTP/1.1 200 OK');
if (!empty($_POST) && !empty($_POST['id']) && !empty($_FILES) && !empty($_FILES['content'])) {
$data = @json_decode(str_replace('&quot;', '"', $_POST['id']), true);
if (!empty($data['hash'])) {
$hash = $data['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');
}
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -171,6 +171,16 @@ class elFinderConnector
}
}
/**
* Sets the header.
*
* @param array|string $value HTTP header(s)
*/
public function setHeader($value)
{
$this->header = $value;
}
/**
* Output json
*
@ -209,7 +219,7 @@ class elFinderConnector
$sendData = !($this->reqMethod === 'HEAD' || !empty($data['info']['xsendfile']));
$psize = null;
if (($this->reqMethod === 'GET' || !$sendData)
&& elFinder::isSeekableStream($fp)
&& (elFinder::isSeekableStream($fp) || elFinder::isSeekableUrl($fp))
&& (array_search('Accept-Ranges: none', headers_list()) === false)) {
header('Accept-Ranges: bytes');
if (!empty($_SERVER['HTTP_RANGE'])) {
@ -248,7 +258,7 @@ class elFinderConnector
}
}
$sendData && fseek($fp, $start);
$sendData && !elFinder::isSeekableUrl($fp) && fseek($fp, $start);
}
}
}
@ -267,7 +277,7 @@ class elFinderConnector
}
if ($sendData) {
if ($toEnd) {
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', '<')) {
@ -283,7 +293,9 @@ class elFinderConnector
}
if (!empty($data['volume'])) {
$data['volume']->close($data['pointer'], $data['info']['hash']);
$data['volume']->close($fp, $data['info']['hash']);
} else {
fclose($fp);
}
exit();
} else {
@ -349,8 +361,8 @@ class elFinderConnector
if (!empty($data['raw']) && isset($data['error'])) {
$out = $data['error'];
} else {
if (isset($data['debug']) && isset($data['debug']['phpErrors'])) {
$data['debug']['phpErrors'] = array_merge($data['debug']['phpErrors'], elFinder::$phpErrors);
if (isset($data['debug']) && isset($data['debug']['backendErrors'])) {
$data['debug']['backendErrors'] = array_merge($data['debug']['backendErrors'], elFinder::$phpErrors);
}
$out = json_encode($data);
}

View file

@ -126,16 +126,19 @@ class elFinderVolumeFlysystemGoogleDriveNetmount extends ExtDriver
}
if ($options['user'] === 'init') {
$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();
}
$callback = $options['url']
. '?cmd=netmount&protocol=googledrive&host=1';
$client->setRedirectUri($callback);
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($_GET['code'])) {
if (!$aToken && empty($code)) {
$client->setScopes([Google_Service_Drive::DRIVE]);
if (!empty($options['offline'])) {
$client->setApprovalPrompt('force');
@ -143,9 +146,9 @@ class elFinderVolumeFlysystemGoogleDriveNetmount extends ExtDriver
}
$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" onclick="window.open(\'' . $url . '\')">';
$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"});
$("#' . $options['id'] . '").elfinder("instance").trigger("netmount", {protocol: "googledrive", mode: "makebtn", url: "' . $url . '"});
</script>';
if (empty($options['pass']) && $options['host'] !== '1') {
$options['pass'] = 'return';
@ -160,16 +163,38 @@ class elFinderVolumeFlysystemGoogleDriveNetmount extends ExtDriver
return array('exit' => 'callback', 'out' => $out);
}
} else {
if (!empty($_GET['code'])) {
$aToken = $client->fetchAccessTokenWithAuthCode($_GET['code']);
$options['access_token'] = $aToken;
$this->session->set('GoogleDriveTokens', $aToken)->set('GoogleDriveAuthParams', $options);
$out = array(
'node' => $options['id'],
'json' => '{"protocol": "googledrive", "mode": "done", "reset": 1}',
'bind' => 'netmount'
);
return array('exit' => 'callback', 'out' => $out);
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([
@ -211,6 +236,9 @@ class elFinderVolumeFlysystemGoogleDriveNetmount extends ExtDriver
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) {
@ -277,7 +305,7 @@ class elFinderVolumeFlysystemGoogleDriveNetmount extends ExtDriver
if (!empty($opts['access_token'])) {
$client->setAccessToken($opts['access_token']);
}
if ($client->isAccessTokenExpired()) {
if ($this->needOnline && $client->isAccessTokenExpired()) {
try {
$creds = $client->fetchAccessTokenWithRefreshToken();
} catch (LogicException $e) {
@ -335,4 +363,18 @@ class elFinderVolumeFlysystemGoogleDriveNetmount extends ExtDriver
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;
}
}

View file

@ -49,7 +49,8 @@ class elFinderSession implements elFinderSessionInterface
'keys' => array(
'default' => 'elFinderCaches',
'netvolume' => 'elFinderNetVolumes'
)
),
'cookieParams' => array()
);
/**
@ -64,11 +65,9 @@ class elFinderSession implements elFinderSessionInterface
$this->opts = array_merge($this->opts, $opts);
$this->base64encode = !empty($this->opts['base64encode']);
$this->keys = $this->opts['keys'];
if (function_exists('apache_get_version')) {
if (function_exists('apache_get_version') || $this->opts['cookieParams']) {
$this->fixCookieRegist = true;
}
return $this;
}
/**
@ -123,23 +122,30 @@ class elFinderSession implements elFinderSessionInterface
*/
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) {
// 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
ini_set('session.use_cookies', 0);
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 {
set_error_handler(array($this, 'session_start_error'), E_NOTICE);
session_start();
restore_error_handler();
}
$this->started = session_id() ? true : false;
restore_error_handler();
return $this;
}
@ -217,7 +223,20 @@ class elFinderSession implements elFinderSessionInterface
if ($this->fixCookieRegist === true) {
// regist cookie only once for apache2 SAPI
$cParm = session_get_cookie_params();
setcookie(session_name(), session_id(), 0, $cParm['path'], $cParm['domain'], $cParm['secure'], $cParm['httponly']);
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();

View file

@ -26,12 +26,12 @@ class elFinderVolumeBox extends elFinderVolumeDriver
/**
* @var string The base URL for authorization requests
*/
const AUTH_URL = 'https://www.box.com/api/oauth2/authorize';
const AUTH_URL = 'https://account.box.com/api/oauth2/authorize';
/**
* @var string The base URL for token requests
*/
const TOKEN_URL = 'https://www.box.com/api/oauth2/token';
const TOKEN_URL = 'https://api.box.com/oauth2/token';
/**
* @var string The base URL for upload requests
@ -74,6 +74,13 @@ class elFinderVolumeBox extends elFinderVolumeDriver
**/
private $tmbPrefix = '';
/**
* Path to access token file for permanent mount
*
* @var string
*/
private $aTokenFile = '';
/**
* hasCache by folders.
*
@ -100,7 +107,7 @@ class elFinderVolumeBox extends elFinderVolumeDriver
'tmbPath' => '',
'tmbURL' => '',
'tmpPath' => '',
'acceptedName' => '#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#',
'acceptedName' => '#^[^\\\/]+$#',
'rootCssClass' => 'elfinder-navbar-root-box',
);
$this->options = array_merge($this->options, $opts);
@ -191,10 +198,15 @@ class elFinderVolumeBox extends elFinderVolumeDriver
$decoded = $this->_bd_curlExec($curl, true, array('Content-Length: ' . strlen($fields)));
return (object)array(
$res = (object)array(
'expires' => time() + $decoded->expires_in - 30,
'data' => $decoded,
'initialToken' => '',
'data' => $decoded
);
if (!empty($decoded->refresh_token)) {
$res->initialToken = md5($client_id . $decoded->refresh_token);
}
return $res;
}
/**
@ -206,14 +218,6 @@ class elFinderVolumeBox extends elFinderVolumeDriver
protected function _bd_refreshToken()
{
if (!property_exists($this->token, 'expires') || $this->token->expires < time()) {
if (!$token = $this->session->get('BoxTokens')) {
$token = $this->token;
}
if (empty($token->data->refresh_token)) {
$this->session->remove('BoxTokens');
throw new \Exception(elFinder::ERROR_REAUTH_REQUIRE);
}
if (!$this->options['client_id']) {
$this->options['client_id'] = ELFINDER_BOX_CLIENTID;
}
@ -222,6 +226,32 @@ class elFinderVolumeBox extends elFinderVolumeDriver
$this->options['client_secret'] = ELFINDER_BOX_CLIENTSECRET;
}
if (empty($this->token->data->refresh_token)) {
throw new \Exception(elFinder::ERROR_REAUTH_REQUIRE);
} else {
$refresh_token = $this->token->data->refresh_token;
$initialToken = $this->_bd_getInitialToken();
}
$lock = '';
$aTokenFile = $this->aTokenFile? $this->aTokenFile : $this->_bd_getATokenFile();
if ($aTokenFile && is_file($aTokenFile)) {
$lock = $aTokenFile . '.lock';
if (file_exists($lock)) {
// Probably updating on other instance
return true;
}
touch($lock);
$GLOBALS['elFinderTempFiles'][$lock] = true;
}
$postData = array(
'client_id' => $this->options['client_id'],
'client_secret' => $this->options['client_secret'],
'grant_type' => 'refresh_token',
'refresh_token' => $refresh_token
);
$url = self::TOKEN_URL;
$curl = curl_init();
@ -230,32 +260,67 @@ class elFinderVolumeBox extends elFinderVolumeDriver
// General options.
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true, // i am sending post data
CURLOPT_POSTFIELDS => 'client_id=' . urlencode($this->options['client_id'])
. '&client_secret=' . urlencode($this->options['client_secret'])
. '&grant_type=refresh_token'
. '&refresh_token=' . urlencode($token->data->refresh_token),
CURLOPT_POSTFIELDS => http_build_query($postData),
CURLOPT_URL => $url,
));
$decoded = $this->_bd_curlExec($curl);
$decoded = $error = '';
try {
$decoded = $this->_bd_curlExec($curl, true, array(), $postData);
} catch (Exception $e) {
$error = $e->getMessage();
}
if (!$decoded && !$error) {
$error = 'Tried to renew the access token, but did not get a response from the Box server.';
}
if ($error) {
$lock && unlink($lock);
throw new \Exception('Box access token update failed. ('.$error.') If this message appears repeatedly, please notify the administrator.');
}
if (empty($decoded->access_token)) {
throw new \Exception(elFinder::ERROR_REAUTH_REQUIRE);
if ($aTokenFile) {
if (is_file($aTokenFile)) {
unlink($aTokenFile);
}
}
$err = property_exists($decoded, 'error')? ' ' . $decoded->error : '';
$err .= property_exists($decoded, 'error_description')? ' ' . $decoded->error_description : '';
throw new \Exception($err? $err : elFinder::ERROR_REAUTH_REQUIRE);
}
$token = (object)array(
'expires' => time() + $decoded->expires_in - 30,
'expires' => time() + $decoded->expires_in - 300,
'initialToken' => $initialToken,
'data' => $decoded,
);
$this->session->set('BoxTokens', $token);
$this->options['accessToken'] = json_encode($token);
$this->token = $token;
$json = json_encode($token);
if (!empty($this->options['netkey'])) {
elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'accessToken', $this->options['accessToken']);
if (!empty($decoded->refresh_token)) {
if (empty($this->options['netkey']) && $aTokenFile) {
file_put_contents($aTokenFile, json_encode($token), LOCK_EX);
$this->options['accessToken'] = $json;
} else if (!empty($this->options['netkey'])) {
// OAuth2 refresh token can be used only once,
// so update it if it is the same as the token file
if ($aTokenFile && is_file($aTokenFile)) {
if ($_token = json_decode(file_get_contents($aTokenFile))) {
if ($_token->data->refresh_token === $refresh_token) {
file_put_contents($aTokenFile, $json, LOCK_EX);
}
}
}
$this->options['accessToken'] = $json;
// update session value
elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'accessToken', $json);
$this->session->set('BoxTokens', $token);
} else {
throw new \Exception(ERROR_CREATING_TEMP_DIR);
}
}
$lock && unlink($lock);
}
return true;
@ -341,13 +406,15 @@ class elFinderVolumeBox extends elFinderVolumeDriver
* @throws \Exception
* @return mixed
*/
protected function _bd_curlExec($curl, $decodeOrParent = true, $headers = array())
protected function _bd_curlExec($curl, $decodeOrParent = true, $headers = array(), $postData = array())
{
$headers = array_merge(array(
'Authorization: Bearer ' . $this->token->data->access_token,
), $headers);
if ($this->token) {
$headers = array_merge(array(
'Authorization: Bearer ' . $this->token->data->access_token,
), $headers);
}
$result = elFinder::curlExec($curl, array(), $headers);
$result = elFinder::curlExec($curl, array(), $headers, $postData);
if (!$decodeOrParent) {
return $result;
@ -355,12 +422,18 @@ class elFinderVolumeBox extends elFinderVolumeDriver
$decoded = json_decode($result);
if (!empty($decoded->error_code)) {
if ($error = !empty($decoded->error_code)) {
$errmsg = $decoded->error_code;
if (!empty($decoded->message)) {
$errmsg .= ': ' . $decoded->message;
}
throw new \Exception($errmsg);
} else if ($error = !empty($decoded->error)) {
$errmsg = $decoded->error;
if (!empty($decoded->error_description)) {
$errmsg .= ': ' . $decoded->error_description;
}
throw new \Exception($errmsg);
}
// make catch
@ -546,6 +619,39 @@ class elFinderVolumeBox extends elFinderVolumeDriver
return true;
}
/**
* Get AccessToken file path
*
* @return string ( description_of_the_return_value )
*/
protected function _bd_getATokenFile()
{
$tmp = $aTokenFile = '';
if (!empty($this->token->data->refresh_token)) {
if (!$this->tmp) {
$tmp = elFinder::getStaticVar('commonTempPath');
if (!$tmp) {
$tmp = $this->getTempPath();
}
$this->tmp = $tmp;
}
if ($tmp) {
$aTokenFile = $tmp . DIRECTORY_SEPARATOR . $this->_bd_getInitialToken() . '.btoken';
}
}
return $aTokenFile;
}
/**
* Get Initial Token (MD5 hash)
*
* @return string
*/
protected function _bd_getInitialToken()
{
return (empty($this->token->initialToken)? md5($this->options['client_id'] . (!empty($this->token->data->refresh_token)? $this->token->data->refresh_token : $this->token->data->access_token)) : $this->token->initialToken);
}
/*********************************************************************/
/* OVERRIDE FUNCTIONS */
/*********************************************************************/
@ -575,30 +681,57 @@ class elFinderVolumeBox extends elFinderVolumeDriver
if (isset($options['id'])) {
$this->session->set('nodeId', $options['id']);
} elseif ($_id = $this->session->get('nodeId')) {
} else if ($_id = $this->session->get('nodeId')) {
$options['id'] = $_id;
$this->session->set('nodeId', $_id);
}
if (!empty($options['tmpPath'])) {
if ((is_dir($options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($options['tmpPath'])) {
$this->tmp = $options['tmpPath'];
}
}
try {
if (empty($options['client_id']) || empty($options['client_secret'])) {
return array('exit' => true, 'body' => '{msg:errNetMountNoDriver}');
}
if (isset($_GET['code'])) {
$itpCare = isset($options['code']);
$code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : '');
if ($code) {
try {
// Obtain the token using the code received by the Box.com API
$this->session->set('BoxTokens',
$this->_bd_obtainAccessToken($options['client_id'], $options['client_secret'], $_GET['code']));
if (!empty($options['id'])) {
// Obtain the token using the code received by the Box.com API
$this->session->set('BoxTokens',
$this->_bd_obtainAccessToken($options['client_id'], $options['client_secret'], $code));
$out = array(
'node' => $options['id'],
'json' => '{"protocol": "box", "mode": "done", "reset": 1}',
'bind' => 'netmount',
);
return array('exit' => 'callback', 'out' => $out);
$out = array(
'node' => $options['id'],
'json' => '{"protocol": "box", "mode": "done", "reset": 1}',
'bind' => 'netmount'
);
} else {
$nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host'];
$out = array(
'node' => $nodeid,
'json' => json_encode(array(
'protocol' => 'box',
'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']);
}
} catch (Exception $e) {
$out = array(
'node' => $options['id'],
@ -640,34 +773,20 @@ class elFinderVolumeBox extends elFinderVolumeDriver
}
if ($result === false) {
$cdata = '';
$innerKeys = array('cmd', 'host', 'options', 'pass', 'protocol', 'user');
$this->ARGS = $_SERVER['REQUEST_METHOD'] === 'POST' ? $_POST : $_GET;
foreach ($this->ARGS as $k => $v) {
if (!in_array($k, $innerKeys)) {
$cdata .= '&' . $k . '=' . rawurlencode($v);
}
}
if (empty($options['url'])) {
$options['url'] = elFinder::getConnectorUrl();
}
$callback = $options['url']
. '?cmd=netmount&protocol=box&host=box.com&user=init&pass=return&node=' . $options['id'] . $cdata;
$redirect = elFinder::getConnectorUrl();
$redirect .= (strpos($redirect, '?') !== false? '&' : '?') . 'cmd=netmount&protocol=box&host=' . ($options['id'] === 'elfinder'? '1' : $options['id']);
try {
$this->session->set('BoxTokens', (object)array('token' => null));
$url = self::AUTH_URL . '?' . http_build_query(array('response_type' => 'code', 'client_id' => $options['client_id'], 'redirect_uri' => elFinder::getConnectorUrl() . '?cmd=netmount&protocol=box&host=1'));
$url .= '&oauth_callback=' . rawurlencode($callback);
$url = self::AUTH_URL . '?' . http_build_query(array('response_type' => 'code', 'client_id' => $options['client_id'], 'redirect_uri' => $redirect));
} catch (Exception $e) {
return array('exit' => true, 'body' => '{msg:errAccess}');
}
$html = '<input id="elf-volumedriver-box-host-btn" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" value="{msg:btnApprove}" type="button" onclick="window.open(\'' . $url . '\')">';
$html = '<input id="elf-volumedriver-box-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: "box", mode: "makebtn"});
</script>';
$("#' . $options['id'] . '").elfinder("instance").trigger("netmount", {protocol: "box", mode: "makebtn", url: "' . $url . '"});
</script>';
return array('exit' => true, 'body' => $html);
} else {
@ -690,11 +809,12 @@ class elFinderVolumeBox extends elFinderVolumeDriver
$folders = json_encode($folders);
$expires = empty($this->token->data->refresh_token) ? (int)$this->token->expires : 0;
$json = '{"protocol": "box", "mode": "done", "folders": ' . $folders . ', "expires": ' . $expires . '}';
$mnt2res = empty($this->token->data->refresh_token) ? '' : ', "mnt2res": 1';
$json = '{"protocol": "box", "mode": "done", "folders": ' . $folders . ', "expires": ' . $expires . $mnt2res . '}';
$html = 'Box.com';
$html .= '<script>
$("#' . $options['id'] . '").elfinder("instance").trigger("netmount", ' . $json . ');
</script>';
$("#' . $options['id'] . '").elfinder("instance").trigger("netmount", ' . $json . ');
</script>';
return array('exit' => true, 'body' => $html);
}
@ -705,7 +825,11 @@ class elFinderVolumeBox extends elFinderVolumeDriver
if ($_aToken = $this->session->get('BoxTokens')) {
$options['accessToken'] = json_encode($_aToken);
if ($this->options['path'] === 'root' || !$this->options['path']) {
$this->options['path'] = '/';
}
} else {
$this->session->remove('BoxTokens');
$this->setError(elFinder::ERROR_NETMOUNT, $options['host'], implode(' ', $this->error()));
return array('exit' => true, 'error' => $this->error());
@ -745,7 +869,7 @@ class elFinderVolumeBox extends elFinderVolumeDriver
public function debug()
{
$res = parent::debug();
if (!empty($this->options['accessToken'])) {
if (!empty($this->options['netkey']) && !empty($this->options['accessToken'])) {
$res['accessToken'] = $this->options['accessToken'];
}
@ -771,22 +895,62 @@ class elFinderVolumeBox extends elFinderVolumeDriver
return $this->setError('Required option `accessToken` is undefined.');
}
try {
$this->token = json_decode($this->options['accessToken']);
$this->_bd_refreshToken();
} catch (Exception $e) {
$this->token = null;
$this->session->remove('BoxTokens');
return $this->setError($e->getMessage());
if (!empty($this->options['tmpPath'])) {
if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) {
$this->tmp = $this->options['tmpPath'];
}
}
if (empty($options['netkey'])) {
$error = false;
try {
$this->token = json_decode($this->options['accessToken']);
if (!is_object($this->token)) {
throw new Exception('Required option `accessToken` is invalid JSON.');
}
// make net mount key
$_tokenKey = isset($this->token->data->refresh_token) ? $this->token->data->refresh_token : $this->token->data->access_token;
$this->netMountKey = md5(implode('-', array('box', $this->options['path'], $_tokenKey)));
} else {
$this->netMountKey = $options['netkey'];
if (empty($this->options['netkey'])) {
$this->netMountKey = $this->_bd_getInitialToken();
} else {
$this->netMountKey = $this->options['netkey'];
}
if ($this->aTokenFile = $this->_bd_getATokenFile()) {
if (empty($this->options['netkey'])) {
if ($this->aTokenFile) {
if (is_file($this->aTokenFile)) {
$this->token = json_decode(file_get_contents($this->aTokenFile));
if (!is_object($this->token)) {
unlink($this->aTokenFile);
throw new Exception('Required option `accessToken` is invalid JSON.');
}
} else {
file_put_contents($this->aTokenFile, json_encode($this->token), LOCK_EX);
}
}
} else if (is_file($this->aTokenFile)) {
// If the refresh token is the same as the permanent volume
$this->token = json_decode(file_get_contents($this->aTokenFile));
}
}
$this->needOnline && $this->_bd_refreshToken();
} catch (Exception $e) {
$this->token = null;
$error = true;
$this->setError($e->getMessage());
}
if ($this->netMountKey) {
$this->tmbPrefix = 'box' . base_convert($this->netMountKey, 16, 32);
}
if ($error) {
if (empty($this->options['netkey']) && $this->tmbPrefix) {
// for delete thumbnail
$this->netunmount(null, null);
}
return false;
}
// normalize root path
@ -796,27 +960,22 @@ class elFinderVolumeBox extends elFinderVolumeDriver
$this->root = $this->options['path'] = $this->_normpath($this->options['path']);
$this->options['root'] == '' ? $this->options['root'] = 'Box.com' : $this->options['root'];
$this->options['root'] = ($this->options['root'] == '')? 'Box.com' : $this->options['root'];
if (empty($this->options['alias'])) {
list(, $itemId) = $this->_bd_splitPath($this->options['path']);
$this->options['alias'] = ($this->options['path'] === '/') ? $this->options['root'] :
$this->_bd_query($itemId, $fetch_self = true)->name . '@Box.com';
}
$this->rootName = $this->options['alias'];
$this->tmbPrefix = 'box' . base_convert($this->netMountKey, 10, 32);
if (!empty($this->options['tmpPath'])) {
if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) {
$this->tmp = $this->options['tmpPath'];
if ($this->needOnline) {
list(, $itemId) = $this->_bd_splitPath($this->options['path']);
$this->options['alias'] = ($this->options['path'] === '/') ? $this->options['root'] :
$this->_bd_query($itemId, $fetch_self = true)->name . '@Box';
if (!empty($this->options['netkey'])) {
elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']);
}
} else {
$this->options['alias'] = $this->options['root'];
}
}
if (!$this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) {
$this->tmp = $tmp;
}
$this->rootName = $this->options['alias'];
// This driver dose not support `syncChkAsTs`
$this->options['syncChkAsTs'] = false;
@ -896,7 +1055,16 @@ class elFinderVolumeBox extends elFinderVolumeDriver
$this->options['searchExDirReg'] = $searchExDirReg;
if ($search) {
return $search[0];
$f = false;
foreach($search as $f) {
if ($f['name'] !== $name) {
$f = false;
}
if ($f) {
break;
}
}
return $f;
}
return false;
@ -1106,27 +1274,8 @@ class elFinderVolumeBox extends elFinderVolumeDriver
**/
protected function getSharedWebContentLink($raw)
{
$fExtension = pathinfo($raw->name, PATHINFO_EXTENSION);
list($fType) = explode('/', self::mimetypeInternalDetect($raw->name));
if ($raw->shared_link->url && ($fType == 'image' || $fType == 'video' || $fType == 'audio')) {
if ($fExtension == 'jpg' && $fType == 'image') {
$url = 'https://app.box.com/representation/file_version_' . $raw->file_version->id . '/image_2048_' . $fExtension . '/1.' . $fExtension . '?shared_name=' . basename($raw->shared_link->url);
return $url;
} elseif ($fExtension !== 'jpg' && $fType == 'image') {
$url = 'https://app.box.com/representation/file_version_' . $raw->file_version->id . '/image_2048/1.' . $fExtension . '?shared_name=' . basename($raw->shared_link->url);
return $url;
} elseif ($fType == 'video') {
$url = 'https://app.box.com/representation/file_version_' . $raw->file_version->id . '/video_480.' . $fExtension . '?shared_name=' . basename($raw->shared_link->url);
return $url;
} elseif ($fType == 'audio') {
$url = 'https://app.box.com/index.php?rm=preview_stream&amp&file_version_' . $raw->file_version->id . '/audio/mpeg:' . $raw->name . '&shared_name=' . basename($raw->shared_link->url);
return $url;
}
if ($raw->shared_link->url) {
return sprintf('https://app.box.com/index.php?rm=box_download_shared_file&shared_name=%s&file_id=f_%s', basename($raw->shared_link->url), $raw->id);
} elseif ($raw->shared_link->download_url) {
return $raw->shared_link->download_url;
}
@ -1384,7 +1533,8 @@ class elFinderVolumeBox extends elFinderVolumeDriver
$cache['height'] = $size[1];
$ret = array('dim' => $size[0] . 'x' . $size[1]);
$srcfp = fopen($work, 'rb');
if ($subImgLink = $this->getSubstituteImgLink(elFinder::$currentArgs['target'], $size, $srcfp)) {
$target = isset(elFinder::$currentArgs['target'])? elFinder::$currentArgs['target'] : '';
if ($subImgLink = $this->getSubstituteImgLink($target, $size, $srcfp)) {
$ret['url'] = $subImgLink;
}
}
@ -1431,6 +1581,16 @@ class elFinderVolumeBox extends elFinderVolumeDriver
'headers' => array('Authorization: Bearer ' . $this->token->data->access_token),
);
// to support range request
if (func_num_args() > 2) {
$opts = func_get_arg(2);
} else {
$opts = array();
}
if (!empty($opts['httpheaders'])) {
$data['headers'] = array_merge($opts['httpheaders'], $data['headers']);
}
return elFinder::getStreamByUrl($data);
}
@ -1448,7 +1608,7 @@ class elFinderVolumeBox extends elFinderVolumeDriver
*/
protected function _fclose($fp, $path = '')
{
fclose($fp);
is_resource($fp) && fclose($fp);
if ($path) {
unlink($this->getTempFile($path));
}

File diff suppressed because it is too large Load diff

View file

@ -68,7 +68,7 @@ class elFinderVolumeDropbox2 extends elFinderVolumeDriver
'aliasFormat' => '%s@Dropbox',
'path' => '/',
'separator' => '/',
'acceptedName' => '#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#',
'acceptedName' => '#^[^\\\/]+$#',
'rootCssClass' => 'elfinder-navbar-root-dropbox',
'publishPermission' => [
'requested_visibility' => 'public',
@ -287,7 +287,6 @@ class elFinderVolumeDropbox2 extends elFinderVolumeDriver
}
try {
$this->session->start();
$app = new DropboxApp($options['app_key'], $options['app_secret']);
$dropbox = new Dropbox($app);
$authHelper = $dropbox->getAuthHelper();
@ -326,20 +325,25 @@ class elFinderVolumeDropbox2 extends elFinderVolumeDriver
}
}
if ($options['user'] === 'init') {
if ((isset($options['user']) && $options['user'] === 'init') || (isset($_GET['host']) && $_GET['host'] == '1')) {
if (empty($options['url'])) {
$options['url'] = elFinder::getConnectorUrl();
}
$callback = $options['url']
. '?cmd=netmount&protocol=dropbox2&host=1';
if (!empty($options['id'])) {
$callback = $options['url']
. (strpos($options['url'], '?') !== false? '&' : '?') . 'cmd=netmount&protocol=dropbox2&host=' . ($options['id'] === 'elfinder'? '1' : $options['id']);
}
if (!$aToken && empty($_GET['code'])) {
$itpCare = isset($options['code']);
$code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : '');
$state = $itpCare? $options['state'] : (isset($_GET['state'])? $_GET['state'] : '');
if (!$aToken && empty($code)) {
$url = $authHelper->getAuthUrl($callback);
$html = '<input id="elf-volumedriver-dropbox2-host-btn" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" value="{msg:btnApprove}" type="button" onclick="window.open(\'' . $url . '\')">';
$html = '<input id="elf-volumedriver-dropbox2-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: "dropbox2", mode: "makebtn"});
$("#' . $options['id'] . '").elfinder("instance").trigger("netmount", {protocol: "dropbox2", mode: "makebtn", url: "' . $url . '"});
</script>';
if (empty($options['pass']) && $options['host'] !== '1') {
$options['pass'] = 'return';
@ -356,20 +360,44 @@ class elFinderVolumeDropbox2 extends elFinderVolumeDriver
return ['exit' => 'callback', 'out' => $out];
}
} else {
if (!empty($_GET['code']) && isset($_GET['state'])) {
$tokenObj = $authHelper->getAccessToken($_GET['code'], $_GET['state'], $callback);
$options['tokens'] = [
'access_token' => $tokenObj->getToken(),
'uid' => $tokenObj->getUid(),
];
$this->session->set('Dropbox2Tokens', $options['tokens'])->set('Dropbox2AuthParams', $options);
$out = [
'node' => $options['id'],
'json' => '{"protocol": "dropbox2", "mode": "done", "reset": 1}',
'bind' => 'netmount',
];
return ['exit' => 'callback', 'out' => $out];
if ($code && $state) {
if (!empty($options['id'])) {
// see https://github.com/kunalvarma05/dropbox-php-sdk/issues/115
$authHelper->getPersistentDataStore()->set('state', filter_var($state, FILTER_SANITIZE_STRING));
$tokenObj = $authHelper->getAccessToken($code, $state, $callback);
$options['tokens'] = [
'access_token' => $tokenObj->getToken(),
'uid' => $tokenObj->getUid(),
];
unset($options['code'], $options['state']);
$this->session->set('Dropbox2Tokens', $options['tokens'])->set('Dropbox2AuthParams', $options);
$out = [
'node' => $options['id'],
'json' => '{"protocol": "dropbox2", "mode": "done", "reset": 1}',
'bind' => 'netmount',
];
} else {
$nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host'];
$out = [
'node' => $nodeid,
'json' => json_encode(array(
'protocol' => 'dropbox2',
'host' => $nodeid,
'mode' => 'redirect',
'options' => array(
'id' => $nodeid,
'code' => $code,
'state' => $state
)
)),
'bind' => 'netmount'
];
}
if (!$itpCare) {
return array('exit' => 'callback', 'out' => $out);
} else {
return array('exit' => true, 'body' => $out['json']);
}
}
$path = $options['path'];
$folders = [];
@ -495,9 +523,11 @@ class elFinderVolumeDropbox2 extends elFinderVolumeDriver
$this->netMountKey = md5($aToken . '-' . $this->options['path']);
$errors = [];
if (!$this->service) {
if ($this->needOnline && !$this->service) {
$app = new DropboxApp($this->options['app_key'], $this->options['app_secret'], $aToken);
$this->service = new Dropbox($app);
// to check access_token
$this->service->getCurrentAccount();
}
} catch (DropboxClientException $e) {
$errors[] = 'Dropbox error: ' . $e->getMessage();
@ -505,9 +535,11 @@ class elFinderVolumeDropbox2 extends elFinderVolumeDriver
$errors[] = $e->getMessage();
}
if (!$this->service) {
if ($this->needOnline && !$this->service) {
$errors[] = 'Dropbox Service could not be loaded.';
}
if ($errors) {
return $this->setError($errors);
}
@ -519,7 +551,10 @@ class elFinderVolumeDropbox2 extends elFinderVolumeDriver
$this->root = $this->options['path'] = $this->_normpath($this->options['path']);
if (empty($this->options['alias'])) {
$this->options['alias'] = sprintf($this->options['aliasFormat'], ($this->options['path'] === '/') ? 'root' : $this->_basename($this->options['path']));
$this->options['alias'] = sprintf($this->options['aliasFormat'], ($this->options['path'] === '/') ? 'Root' : $this->_basename($this->options['path']));
if (!empty($this->options['netkey'])) {
elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']);
}
}
$this->rootName = $this->options['alias'];
@ -890,7 +925,7 @@ class elFinderVolumeDropbox2 extends elFinderVolumeDriver
public function debug()
{
$res = parent::debug();
if (isset($this->options['tokens']) && !empty($this->options['tokens']['uid'])) {
if (!empty($this->options['netkey']) && isset($this->options['tokens']) && !empty($this->options['tokens']['uid'])) {
$res['Dropbox uid'] = $this->options['tokens']['uid'];
$res['access_token'] = $this->options['tokens']['access_token'];
}
@ -1105,7 +1140,8 @@ class elFinderVolumeDropbox2 extends elFinderVolumeDriver
if ($size) {
$ret = array('dim' => $size[0] . 'x' . $size[1]);
$srcfp = fopen($tmp, 'rb');
if ($subImgLink = $this->getSubstituteImgLink(elFinder::$currentArgs['target'], $size, $srcfp)) {
$target = isset(elFinder::$currentArgs['target'])? elFinder::$currentArgs['target'] : '';
if ($subImgLink = $this->getSubstituteImgLink($target, $size, $srcfp)) {
$ret['url'] = $subImgLink;
}
}
@ -1151,6 +1187,16 @@ class elFinderVolumeDropbox2 extends elFinderVolumeDriver
'headers' => array('Authorization: Bearer ' . $access_token),
);
// to support range request
if (func_num_args() > 2) {
$opts = func_get_arg(2);
} else {
$opts = array();
}
if (!empty($opts['httpheaders'])) {
$data['headers'] = array_merge($opts['httpheaders'], $data['headers']);
}
return elFinder::getStreamByUrl($data);
}
}
@ -1169,7 +1215,7 @@ class elFinderVolumeDropbox2 extends elFinderVolumeDriver
**/
protected function _fclose($fp, $path = '')
{
fclose($fp);
is_resource($fp) && fclose($fp);
}
/******************** file/dir manipulations *************************/

View file

@ -112,6 +112,7 @@ class elFinderVolumeFTP extends elFinderVolumeDriver
'tmbPath' => '',
'tmpPath' => '',
'separator' => '/',
'checkSubfolders' => -1,
'dirMode' => 0755,
'fileMode' => 0644,
'rootCssClass' => 'elfinder-navbar-root-ftp',
@ -194,8 +195,9 @@ class elFinderVolumeFTP extends elFinderVolumeDriver
if (empty($this->options['alias'])) {
$this->options['alias'] = $this->options['user'] . '@' . $this->options['host'];
// $num = elFinder::$volumesCnt-1;
// $this->options['alias'] = $this->root == '/' || $this->root == '.' ? 'FTP folder '.$num : basename($this->root);
if (!empty($this->options['netkey'])) {
elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']);
}
}
$this->rootName = $this->options['alias'];
@ -209,7 +211,7 @@ class elFinderVolumeFTP extends elFinderVolumeDriver
$this->ftpListOption = $this->options['ftpListOption'];
}
return $this->connect();
return $this->needOnline? $this->connect() : true;
}
@ -382,7 +384,10 @@ class elFinderVolumeFTP extends elFinderVolumeDriver
$lastyear = date('Y') - 1;
}
$info = preg_split("/\s+/", $raw, 9);
$info = preg_split("/\s+/", $raw, 8);
if (isset($info[7])) {
list($info[7], $info[8]) = explode(' ', $info[7], 2);
}
$stat = array();
if (!isset($this->ftpOsUnix)) {
@ -829,33 +834,47 @@ class elFinderVolumeFTP extends elFinderVolumeDriver
$res = array(
'name' => $this->root,
'mime' => 'directory',
'dirs' => $this->_subdirs($path)
'dirs' => -1
);
if ($this->isMyReload()) {
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 $str) {
if (($stat = $this->parseRaw($str, $path))) {
if (!empty($stat['ts'])) {
$info = preg_split('/\s+/', $str, 9);
if ($info[8] === '.') {
$info[8] = 'root';
if ($stat = $this->parseRaw(join(' ', $info), $path)) {
unset($stat['name']);
$res = array_merge($res, $stat);
if ($res['ts']) {
$ts = 0;
unset($check['ts']);
}
}
}
if ($check && ($stat = $this->parseRaw($str, $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;
}
// stat of system root
if ($path === $this->separator) {
$res = array(
'name' => $this->separator,
'mime' => 'directory',
'dirs' => 1
);
$this->cache[$outPath] = $res;
return $res;
}
$pPath = $this->_dirname($path);
if ($this->_inPath($pPath, $this->root)) {

View file

@ -118,7 +118,7 @@ class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
'tmbPath' => '',
'separator' => '/',
'useGoogleTmb' => true,
'acceptedName' => '#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#',
'acceptedName' => '#.#',
'rootCssClass' => 'elfinder-navbar-root-googledrive',
'publishPermission' => [
'type' => 'anyone',
@ -157,8 +157,10 @@ class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
$id = 'root';
$parent = '';
} else {
$path = str_replace('\\/', chr(0), $path);
$paths = explode('/', $path);
$id = array_pop($paths);
$id = str_replace(chr(0), '/', $id);
if ($paths) {
$parent = '/' . implode('/', $paths);
$pid = array_pop($paths);
@ -676,16 +678,20 @@ class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
}
}
if (isset($options['user']) && $options['user'] === 'init') {
$itpCare = isset($options['code']);
$code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : '');
if ($code || (isset($options['user']) && $options['user'] === 'init')) {
if (empty($options['url'])) {
$options['url'] = elFinder::getConnectorUrl();
}
$callback = $options['url']
. '?cmd=netmount&protocol=googledrive&host=1';
$client->setRedirectUri($callback);
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($_GET['code'])) {
if (!$aToken && empty($code)) {
$client->setScopes([Google_Service_Drive::DRIVE]);
if (!empty($options['offline'])) {
$client->setApprovalPrompt('force');
@ -693,9 +699,9 @@ class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
}
$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" onclick="window.open(\'' . $url . '\')">';
$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"});
$("#' . $options['id'] . '").elfinder("instance").trigger("netmount", {protocol: "googledrive", mode: "makebtn", url: "' . $url . '"});
</script>';
if (empty($options['pass']) && $options['host'] !== '1') {
$options['pass'] = 'return';
@ -712,17 +718,38 @@ class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
return ['exit' => 'callback', 'out' => $out];
}
} else {
if (!empty($_GET['code'])) {
$aToken = $client->fetchAccessTokenWithAuthCode($_GET['code']);
$options['access_token'] = $aToken;
$this->session->set('GoogleDriveTokens', $aToken)->set('GoogleDriveAuthParams', $options);
$out = [
'node' => $options['id'],
'json' => '{"protocol": "googledrive", "mode": "done", "reset": 1}',
'bind' => 'netmount',
];
return ['exit' => 'callback', 'out' => $out];
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 = [
'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']);
}
}
$path = $options['path'];
if ($path === '/') {
@ -744,7 +771,8 @@ class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
$folders = ['root' => $rootObj->getName()] + $folders;
$folders = json_encode($folders);
$expires = empty($aToken['refresh_token']) ? $aToken['created'] + $aToken['expires_in'] - 30 : 0;
$json = '{"protocol": "googledrive", "mode": "done", "folders": ' . $folders . ', "expires": ' . $expires . '}';
$mnt2res = empty($aToken['refresh_token']) ? '' : ', "mnt2res": 1';
$json = '{"protocol": "googledrive", "mode": "done", "folders": ' . $folders . ', "expires": ' . $expires . $mnt2res . '}';
$options['pass'] = 'return';
$html = 'Google.com';
$html .= '<script>
@ -907,7 +935,7 @@ class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
}
$errors = [];
if (!$this->service) {
if ($this->needOnline && !$this->service) {
if (($this->options['googleApiClient'] || defined('ELFINDER_GOOGLEDRIVE_GOOGLEAPICLIENT')) && !class_exists('Google_Client')) {
include_once $this->options['googleApiClient'] ? $this->options['googleApiClient'] : ELFINDER_GOOGLEDRIVE_GOOGLEAPICLIENT;
}
@ -948,17 +976,21 @@ class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
$this->service = new \Google_Service_Drive($client);
}
$this->netMountKey = md5($aToken . '-' . $this->options['path']);
if ($this->needOnline) {
$this->netMountKey = md5($aToken . '-' . $this->options['path']);
}
} catch (InvalidArgumentException $e) {
$errors[] = $e->getMessage();
} catch (Google_Service_Exception $e) {
$errors[] = $e->getMessage();
}
if (!$this->service) {
if ($this->needOnline && !$this->service) {
$this->session->remove($this->id . $this->netMountKey);
if ($aTokenFile) {
unlink($aTokenFile);
if (is_file($aTokenFile)) {
unlink($aTokenFile);
}
}
$errors[] = 'Google Drive Service could not be loaded.';
@ -971,13 +1003,20 @@ class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
}
$this->root = $this->options['path'] = $this->_normpath($this->options['path']);
$this->options['root'] == '' ? $this->options['root'] = $this->_gd_getNameByPath('root') : $this->options['root'];
if (empty($this->options['alias'])) {
$this->options['alias'] = ($this->options['path'] === '/') ? $this->options['root'] : sprintf($this->options['gdAlias'], $this->_gd_getNameByPath($this->options['path']));
if ($this->needOnline) {
$this->options['root'] = ($this->options['root'] === '')? $this->_gd_getNameByPath('root') : $this->options['root'];
$this->options['alias'] = ($this->options['path'] === '/') ? $this->options['root'] : sprintf($this->options['gdAlias'], $this->_gd_getNameByPath($this->options['path']));
if (!empty($this->options['netkey'])) {
elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']);
}
} else {
$this->options['root'] = ($this->options['root'] === '')? 'GoogleDrive' : $this->options['root'];
$this->options['alias'] = $this->options['root'];
}
}
$this->rootName = $this->options['alias'];
$this->rootName = isset($this->options['alias'])? $this->options['alias'] : 'GoogleDrive';
if (!empty($this->options['tmpPath'])) {
if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) {
@ -1020,7 +1059,7 @@ class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
$this->tmp = $this->tmbPath;
}
if ($this->isMyReload()) {
if ($this->needOnline && $this->isMyReload()) {
$this->_gd_getDirectoryData(false);
}
}
@ -1375,7 +1414,7 @@ class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
public function debug()
{
$res = parent::debug();
if (empty($this->options['refresh_token']) && $this->options['access_token'] && isset($this->options['access_token']['refresh_token'])) {
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'];
}
@ -1425,7 +1464,7 @@ class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
**/
protected function _joinPath($dir, $name)
{
return $this->_normpath($dir . '/' . $name);
return $this->_normpath($dir . '/' . str_replace('/', '\\/', $name));
}
/**
@ -1658,6 +1697,16 @@ class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
'headers' => array('Authorization: Bearer ' . $access_token),
);
// to support range request
if (func_num_args() > 2) {
$opts = func_get_arg(2);
} else {
$opts = array();
}
if (!empty($opts['httpheaders'])) {
$data['headers'] = array_merge($opts['httpheaders'], $data['headers']);
}
return elFinder::getStreamByUrl($data);
}
}
@ -1677,7 +1726,7 @@ class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
**/
protected function _fclose($fp, $path = '')
{
fclose($fp);
is_resource($fp) && fclose($fp);
if ($path) {
unlink($this->getTempFile($path));
}
@ -1876,7 +1925,7 @@ class elFinderVolumeGoogleDrive extends elFinderVolumeDriver
protected function _save($fp, $path, $name, $stat)
{
if ($name !== '') {
$path .= '/' . $name;
$path .= '/' . str_replace('/', '\\/', $name);
}
list($parentId, $itemId, $parent) = $this->_gd_splitPath($path);
if ($name === '') {

View file

@ -75,7 +75,6 @@ class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver
$this->options['alias'] = ''; // alias to replace root dir name
$this->options['dirMode'] = 0755; // new dirs mode
$this->options['fileMode'] = 0644; // new files mode
$this->options['quarantine'] = '.quarantine'; // quarantine folder name - required to check archive (must be hidden)
$this->options['rootCssClass'] = 'elfinder-navbar-root-local';
$this->options['followSymLinks'] = true;
$this->options['detectDirIcon'] = ''; // file name that is detected as a folder icon e.g. '.diricon.png'
@ -114,11 +113,11 @@ class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver
}
// detect systemRoot
if (!isset($this->options['systemRoot'])) {
if ($cwd[0] === $this->separator || $this->root[0] === $this->separator) {
$this->systemRoot = $this->separator;
} else if (preg_match('/^([a-zA-Z]:' . preg_quote($this->separator, '/') . ')/', $this->root, $m)) {
if ($cwd[0] === DIRECTORY_SEPARATOR || $this->root[0] === DIRECTORY_SEPARATOR) {
$this->systemRoot = DIRECTORY_SEPARATOR;
} else if (preg_match('/^([a-zA-Z]:' . preg_quote(DIRECTORY_SEPARATOR, '/') . ')/', $this->root, $m)) {
$this->systemRoot = $m[1];
} else if (preg_match('/^([a-zA-Z]:' . preg_quote($this->separator, '/') . ')/', $cwd, $m)) {
} else if (preg_match('/^([a-zA-Z]:' . preg_quote(DIRECTORY_SEPARATOR, '/') . ')/', $cwd, $m)) {
$this->systemRoot = $m[1];
}
}
@ -150,28 +149,48 @@ class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver
*/
protected function configure()
{
$hiddens = array();
$root = $this->stat($this->root);
// chek thumbnails path
if ($this->options['tmbPath']) {
$this->options['tmbPath'] = strpos($this->options['tmbPath'], DIRECTORY_SEPARATOR) === false
// tmb path set as dirname under root dir
? $this->_abspath($this->options['tmbPath'])
// tmb path as full path
: $this->_normpath($this->options['tmbPath']);
// check thumbnails path
if (!empty($this->options['tmbPath'])) {
if (strpos($this->options['tmbPath'], DIRECTORY_SEPARATOR) === false) {
$hiddens['tmb'] = $this->options['tmbPath'];
$this->options['tmbPath'] = $this->_abspath($this->options['tmbPath']);
} else {
$this->options['tmbPath'] = $this->_normpath($this->options['tmbPath']);
}
}
// check temp path
if (!empty($this->options['tmpPath'])) {
if (strpos($this->options['tmpPath'], DIRECTORY_SEPARATOR) === false) {
$hiddens['temp'] = $this->options['tmpPath'];
$this->options['tmpPath'] = $this->_abspath($this->options['tmpPath']);
} else {
$this->options['tmpPath'] = $this->_normpath($this->options['tmpPath']);
}
}
// check quarantine path
$_quarantine = '';
if (!empty($this->options['quarantine'])) {
if (strpos($this->options['quarantine'], DIRECTORY_SEPARATOR) === false) {
//$hiddens['quarantine'] = $this->options['quarantine'];
//$this->options['quarantine'] = $this->_abspath($this->options['quarantine']);
$_quarantine = $this->_abspath($this->options['quarantine']);
$this->options['quarantine'] = '';
} else {
$this->options['quarantine'] = $this->_normpath($this->options['quarantine']);
}
} else {
$_quarantine = $this->_abspath('.quarantine');
}
is_dir($_quarantine) && self::localRmdirRecursive($_quarantine);
parent::configure();
// set $this->tmp by options['tmpPath']
$this->tmp = '';
if (!empty($this->options['tmpPath'])) {
if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'], 0755, true)) && is_writable($this->options['tmpPath'])) {
$this->tmp = $this->options['tmpPath'];
}
}
if (!$this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) {
$this->tmp = $tmp;
// check tmbPath
if (!$this->tmbPath && isset($hiddens['tmb'])) {
unset($hiddens['tmb']);
}
// if no thumbnails url - try detect it
@ -184,20 +203,33 @@ class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver
}
}
// set $this->tmp by options['tmpPath']
$this->tmp = '';
if (!empty($this->options['tmpPath'])) {
if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'], $this->options['dirMode'], true)) && is_writable($this->options['tmpPath'])) {
$this->tmp = $this->options['tmpPath'];
} else {
if (isset($hiddens['temp'])) {
unset($hiddens['temp']);
}
}
}
if (!$this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) {
$this->tmp = $tmp;
}
// check quarantine dir
$this->quarantine = '';
if (!empty($this->options['quarantine'])) {
if (is_dir($this->options['quarantine'])) {
if (is_writable($this->options['quarantine'])) {
$this->quarantine = $this->options['quarantine'];
}
$this->options['quarantine'] = '';
if ((is_dir($this->options['quarantine']) || mkdir($this->options['quarantine'], $this->options['dirMode'], true)) && is_writable($this->options['quarantine'])) {
$this->quarantine = $this->options['quarantine'];
} else {
$this->quarantine = $this->_abspath($this->options['quarantine']);
if ((!is_dir($this->quarantine) && !mkdir($this->quarantine)) || !is_writable($this->quarantine)) {
$this->options['quarantine'] = $this->quarantine = '';
if (isset($hiddens['quarantine'])) {
unset($hiddens['quarantine']);
}
}
} else if ($_path = elFinder::getCommonTempPath()) {
$this->quarantine = $_path;
}
if (!$this->quarantine) {
@ -209,14 +241,16 @@ class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver
}
}
if ($this->options['quarantine']) {
$this->attributes[] = array(
'pattern' => '~^' . preg_quote(DIRECTORY_SEPARATOR . $this->options['quarantine']) . '$~',
'read' => false,
'write' => false,
'locked' => true,
'hidden' => true
);
if ($hiddens) {
foreach ($hiddens as $hidden) {
$this->attributes[] = array(
'pattern' => '~^' . preg_quote(DIRECTORY_SEPARATOR . $hidden, '~') . '$~',
'read' => false,
'write' => false,
'locked' => true,
'hidden' => true
);
}
}
if (!empty($this->options['keepTimestamp'])) {
@ -319,7 +353,20 @@ class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver
**/
protected function _joinPath($dir, $name)
{
return rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $name;
$dir = rtrim($dir, DIRECTORY_SEPARATOR);
$path = realpath($dir . DIRECTORY_SEPARATOR . $name);
// realpath() returns FALSE if the file does not exist
if ($path === false || strpos($path, $this->root) !== 0) {
if (DIRECTORY_SEPARATOR !== '/') {
$name = str_replace('/', DIRECTORY_SEPARATOR, $name);
}
// Directory traversal measures
if (strpos($name, '..' . DIRECTORY_SEPARATOR) !== false) {
$name = basename($name);
}
$path = $dir . DIRECTORY_SEPARATOR . $name;
}
return $path;
}
/**
@ -423,8 +470,9 @@ class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver
if ($path === DIRECTORY_SEPARATOR) {
return $this->root;
} else {
if ($path[0] === DIRECTORY_SEPARATOR) {
// for link
if (strpos($path, $this->systemRoot) === 0) {
return $path;
} else if (DIRECTORY_SEPARATOR !== '/' && preg_match('/^[a-zA-Z]:' . preg_quote(DIRECTORY_SEPARATOR, '/') . '/', $path)) {
return $path;
} else {
return $this->_joinPath($this->root, $path);
@ -677,7 +725,7 @@ class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver
protected function _dimensions($path, $mime)
{
clearstatcache();
return strpos($mime, 'image') === 0 && is_readable($path) && ($s = getimagesize($path)) !== false
return strpos($mime, 'image') === 0 && is_readable($path) && filesize($path) && ($s = getimagesize($path)) !== false
? $s[0] . 'x' . $s[1]
: false;
}
@ -1116,7 +1164,11 @@ class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver
}
// extract in quarantine
$this->unpackArchive($path, $arc, $archive ? true : $dir);
try {
$this->unpackArchive($path, $arc, $archive ? true : $dir);
} catch(Exception $e) {
return $this->setError($e->getMessage());
}
// get files list
try {
@ -1387,5 +1439,23 @@ class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver
return ($this->stripos($name, $this->doSearchCurrentQuery['q']) === false) ? false : true;
}
/**
* Creates a symbolic link
*
* @param string $target The target
* @param string $link The link
*
* @return boolean ( result of symlink() )
*/
protected function localFileSystemSymlink($target, $link)
{
$res = false;
$errlev = error_reporting();
error_reporting($errlev ^ E_WARNING);
if ($res = symlink(realpath($target), $link)) {
$res = is_readable($link);
}
error_reporting($errlev);
return $res;
}
} // END class

View file

@ -79,7 +79,8 @@ class elFinderVolumeMySQL extends elFinderVolumeDriver
'tmbPath' => '',
'tmpPath' => '',
'rootCssClass' => 'elfinder-navbar-root-sql',
'noSessionCache' => array('hasdirs')
'noSessionCache' => array('hasdirs'),
'isLocalhost' => false
);
$this->options = array_merge($this->options, $opts);
$this->options['mimeDetect'] = 'internal';
@ -105,13 +106,25 @@ class elFinderVolumeMySQL extends elFinderVolumeDriver
|| !$this->options['db']
|| !$this->options['path']
|| !$this->options['files_table']) {
return false;
return $this->setError('Required options "host", "socket", "user", "pass", "db", "path" or "files_table" are undefined.');
}
$err = null;
if ($this->db = @new mysqli($this->options['host'], $this->options['user'], $this->options['pass'], $this->options['db'], $this->options['port'], $this->options['socket'])) {
if ($this->db && $this->db->connect_error) {
$err = $this->db->connect_error;
}
} else {
$err = mysqli_connect_error();
}
if ($err) {
return $this->setError(array('Unable to connect to MySQL server.', $err));
}
$this->db = new mysqli($this->options['host'], $this->options['user'], $this->options['pass'], $this->options['db'], $this->options['port'], $this->options['socket']);
if ($this->db->connect_error || mysqli_connect_error()) {
return false;
if (!$this->needOnline && empty($this->ARGS['init'])) {
$this->db->close();
$this->db = null;
return true;
}
$this->db->set_charset('utf8');
@ -126,7 +139,7 @@ class elFinderVolumeMySQL extends elFinderVolumeDriver
}
if (!$this->tbf) {
return false;
return $this->setError('The specified database table cannot be found.');
}
$this->updateCache($this->options['path'], $this->_stat($this->options['path']));
@ -134,6 +147,9 @@ class elFinderVolumeMySQL extends elFinderVolumeDriver
// enable command archive
$this->options['useRemoteArchive'] = true;
// check isLocalhost
$this->isLocalhost = $this->options['isLocalhost'] || $this->options['host'] === 'localhost' || $this->options['host'] === '127.0.0.1' || $this->options['host'] === '::1';
return true;
}
@ -178,7 +194,7 @@ class elFinderVolumeMySQL extends elFinderVolumeDriver
**/
public function umount()
{
$this->db->close();
$this->db && $this->db->close();
}
/**
@ -251,10 +267,10 @@ class elFinderVolumeMySQL extends elFinderVolumeDriver
$this->dirsCache[$path] = array();
$sql = 'SELECT f.id, f.parent_id, f.name, f.size, f.mtime AS ts, f.mime, f.read, f.write, f.locked, f.hidden, f.width, f.height, IF(ch.id, 1, 0) AS dirs
FROM ' . $this->tbf . ' AS f
LEFT JOIN ' . $this->tbf . ' AS ch ON ch.parent_id=f.id AND ch.mime=\'directory\'
WHERE f.parent_id=\'' . $path . '\'
GROUP BY f.id, ch.id';
FROM ' . $this->tbf . ' AS f
LEFT JOIN ' . $this->tbf . ' AS ch ON ch.parent_id=f.id AND ch.mime=\'directory\'
WHERE f.parent_id=\'' . $path . '\'
GROUP BY f.id, ch.id';
$res = $this->query($sql);
if ($res) {
@ -385,8 +401,8 @@ class elFinderVolumeMySQL extends elFinderVolumeDriver
}
$sql = 'SELECT f.id, f.parent_id, f.name, f.size, f.mtime AS ts, f.mime, f.read, f.write, f.locked, f.hidden, f.width, f.height, 0 AS dirs
FROM %s AS f
WHERE %s';
FROM %s AS f
WHERE %s';
$sql = sprintf($sql, $this->tbf, $whr);
@ -453,7 +469,7 @@ class elFinderVolumeMySQL extends elFinderVolumeDriver
**/
protected function _basename($path)
{
return ($stat = $this->stat($path)) ? $stat['name'] : false;
return (($stat = $this->stat($path)) && isset($stat['name'])) ? $stat['name'] : false;
}
/**
@ -577,10 +593,10 @@ class elFinderVolumeMySQL extends elFinderVolumeDriver
protected function _stat($path)
{
$sql = 'SELECT f.id, f.parent_id, f.name, f.size, f.mtime AS ts, f.mime, f.read, f.write, f.locked, f.hidden, f.width, f.height, IF(ch.id, 1, 0) AS dirs
FROM ' . $this->tbf . ' AS f
LEFT JOIN ' . $this->tbf . ' AS ch ON ch.parent_id=f.id AND ch.mime=\'directory\'
WHERE f.id=\'' . $path . '\'
GROUP BY f.id, ch.id';
FROM ' . $this->tbf . ' AS f
LEFT JOIN ' . $this->tbf . ' AS ch ON ch.parent_id=f.id AND ch.mime=\'directory\'
WHERE f.id=\'' . $path . '\'
GROUP BY f.id, ch.id';
$res = $this->query($sql);
@ -849,29 +865,32 @@ class elFinderVolumeMySQL extends elFinderVolumeDriver
{
$this->clearcache();
$mime = $stat['mime'];
$mime = !empty($stat['mime']) ? $stat['mime'] : $this->mimetype($name, true);
$w = !empty($stat['width']) ? $stat['width'] : 0;
$h = !empty($stat['height']) ? $stat['height'] : 0;
$ts = !empty($stat['ts']) ? $stat['ts'] : time();
$id = $this->_joinPath($dir, $name);
elFinder::rewind($fp);
$stat = fstat($fp);
$size = $stat['size'];
if (!isset($stat['size'])) {
$stat = fstat($fp);
$size = $stat['size'];
} else {
$size = $stat['size'];
}
if (($tmpfile = tempnam($this->tmpPath, $this->id))) {
if ($this->isLocalhost && ($tmpfile = tempnam($this->tmpPath, $this->id))) {
if (($trgfp = fopen($tmpfile, 'wb')) == false) {
unlink($tmpfile);
} else {
while (!feof($fp)) {
fwrite($trgfp, fread($fp, 8192));
}
elFinder::rewind($fp);
stream_copy_to_stream($fp, $trgfp);
fclose($trgfp);
chmod($tmpfile, 0644);
$sql = $id > 0
? 'REPLACE INTO %s (id, parent_id, name, content, size, mtime, mime, width, height) VALUES (' . $id . ', %d, \'%s\', LOAD_FILE(\'%s\'), %d, %d, \'%s\', %d, %d)'
: 'INSERT INTO %s (parent_id, name, content, size, mtime, mime, width, height) VALUES (%d, \'%s\', LOAD_FILE(\'%s\'), %d, %d, \'%s\', %d, %d)';
$sql = sprintf($sql, $this->tbf, $dir, $this->db->real_escape_string($name), $this->loadFilePath($tmpfile), $size, time(), $mime, $w, $h);
$sql = sprintf($sql, $this->tbf, $dir, $this->db->real_escape_string($name), $this->loadFilePath($tmpfile), $size, $ts, $mime, $w, $h);
$res = $this->query($sql);
unlink($tmpfile);
@ -892,7 +911,7 @@ class elFinderVolumeMySQL extends elFinderVolumeDriver
$sql = $id > 0
? 'REPLACE INTO %s (id, parent_id, name, content, size, mtime, mime, width, height) VALUES (' . $id . ', %d, \'%s\', \'%s\', %d, %d, \'%s\', %d, %d)'
: 'INSERT INTO %s (parent_id, name, content, size, mtime, mime, width, height) VALUES (%d, \'%s\', \'%s\', %d, %d, \'%s\', %d, %d)';
$sql = sprintf($sql, $this->tbf, $dir, $this->db->real_escape_string($name), $this->db->real_escape_string($content), $size, time(), $mime, $w, $h);
$sql = sprintf($sql, $this->tbf, $dir, $this->db->real_escape_string($name), $this->db->real_escape_string($content), $size, $ts, $mime, $w, $h);
unset($content);

View file

@ -83,6 +83,13 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
**/
private $expires;
/**
* Path to access token file for permanent mount
*
* @var string
*/
private $aTokenFile = '';
/**
* Constructor
* Extend options with required fields.
@ -127,7 +134,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
* @throws Exception Thrown if the redirect URI of this Client instance's
* state is not set
*/
protected function _od_obtainAccessToken($client_id, $client_secret, $code)
protected function _od_obtainAccessToken($client_id, $client_secret, $code, $nodeid)
{
if (null === $client_id) {
return 'The client ID must be set to call obtainAccessToken()';
@ -137,6 +144,11 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
return 'The client Secret must be set to call obtainAccessToken()';
}
$redirect = elFinder::getConnectorUrl();
if (strpos($redirect, '/netmount/onedrive/') === false) {
$redirect .= '/netmount/onedrive/' . ($nodeid === 'elfinder'? '1' : $nodeid);
}
$url = self::TOKEN_URL;
$curl = curl_init();
@ -144,7 +156,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
$fields = http_build_query(
array(
'client_id' => $client_id,
'redirect_uri' => elFinder::getConnectorUrl(),
'redirect_uri' => $redirect,
'client_secret' => $client_secret,
'code' => $code,
'grant_type' => 'authorization_code',
@ -164,17 +176,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
CURLOPT_URL => $url,
));
$result = curl_exec($curl);
if (false === $result) {
if (curl_errno($curl)) {
throw new \Exception('curl_setopt_array() failed: '
. curl_error($curl));
} else {
throw new \Exception('curl_setopt_array(): empty response');
}
}
curl_close($curl);
$result = elFinder::curlExec($curl);
$decoded = json_decode($result);
@ -182,29 +184,26 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
throw new \Exception('json_decode() failed');
}
return (object)array(
$res = (object)array(
'expires' => time() + $decoded->expires_in - 30,
'data' => $decoded,
'initialToken' => '',
'data' => $decoded
);
if (!empty($decoded->refresh_token)) {
$res->initialToken = md5($client_id . $decoded->refresh_token);
}
return $res;
}
/**
* Get token and auto refresh.
*
* @return true|Exception
* @return true
* @throws Exception
*/
protected function _od_refreshToken()
{
if (!property_exists($this->token, 'expires') || $this->token->expires < time()) {
if (!$token = $this->session->get('OneDriveTokens')) {
$token = $this->token;
}
if (empty($token->data->refresh_token)) {
$this->session->remove('OneDriveTokens');
throw new \Exception(elFinder::ERROR_REAUTH_REQUIRE);
}
if (!$this->options['client_id']) {
$this->options['client_id'] = ELFINDER_ONEDRIVE_CLIENTID;
}
@ -213,6 +212,13 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
$this->options['client_secret'] = ELFINDER_ONEDRIVE_CLIENTSECRET;
}
if (empty($this->token->data->refresh_token)) {
throw new \Exception(elFinder::ERROR_REAUTH_REQUIRE);
} else {
$refresh_token = $this->token->data->refresh_token;
$initialToken = $this->_od_getInitialToken();
}
$url = self::TOKEN_URL;
$curl = curl_init();
@ -224,21 +230,12 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
CURLOPT_POSTFIELDS => 'client_id=' . urlencode($this->options['client_id'])
. '&client_secret=' . urlencode($this->options['client_secret'])
. '&grant_type=refresh_token'
. '&refresh_token=' . urlencode($token->data->refresh_token),
. '&refresh_token=' . urlencode($this->token->data->refresh_token),
CURLOPT_URL => $url,
));
$result = curl_exec($curl);
if (!$result) {
if (curl_errno($curl)) {
throw new \Exception('curl_setopt_array() failed: ' . curl_error($curl));
} else {
throw new \Exception('curl_setopt_array(): empty response');
}
}
curl_close($curl);
$result = elFinder::curlExec($curl);
$decoded = json_decode($result);
@ -247,20 +244,47 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
}
if (empty($decoded->access_token)) {
throw new \Exception(elFinder::ERROR_REAUTH_REQUIRE);
if ($this->aTokenFile) {
if (is_file($this->aTokenFile)) {
unlink($this->aTokenFile);
}
}
$err = property_exists($decoded, 'error')? ' ' . $decoded->error : '';
$err .= property_exists($decoded, 'error_description')? ' ' . $decoded->error_description : '';
throw new \Exception($err? $err : elFinder::ERROR_REAUTH_REQUIRE);
}
$token = (object)array(
'expires' => time() + $decoded->expires_in - 30,
'initialToken' => $initialToken,
'data' => $decoded,
);
$this->session->set('OneDriveTokens', $token);
$this->options['accessToken'] = json_encode($token);
$this->token = $token;
$json = json_encode($token);
if (!empty($this->options['netkey'])) {
elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'accessToken', $this->options['accessToken']);
if (!empty($decoded->refresh_token)) {
if (empty($this->options['netkey']) && $this->aTokenFile) {
file_put_contents($this->aTokenFile, json_encode($token));
$this->options['accessToken'] = $json;
} else if (!empty($this->options['netkey'])) {
// OAuth2 refresh token can be used only once,
// so update it if it is the same as the token file
$aTokenFile = $this->_od_getATokenFile();
if ($aTokenFile && is_file($aTokenFile)) {
if ($_token = json_decode(file_get_contents($aTokenFile))) {
if ($_token->data->refresh_token === $refresh_token) {
file_put_contents($aTokenFile, $json);
}
}
}
$this->options['accessToken'] = $json;
// update session value
elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'accessToken', $this->options['accessToken']);
$this->session->set('OneDriveTokens', $token);
} else {
throw new \Exception(elFinder::ERROR_CREATING_TEMP_DIR);
}
}
}
@ -336,8 +360,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
if ($contents) {
$res = elFinder::curlExec($curl);
} else {
$result = json_decode(curl_exec($curl));
curl_close($curl);
$result = json_decode(elFinder::curlExec($curl));
if (isset($result->value)) {
$res = $result->value;
unset($result->value);
@ -524,8 +547,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => '{}',
));
$sess = json_decode(curl_exec($curl));
curl_close($curl);
$sess = json_decode(elFinder::curlExec($curl));
if ($sess) {
if (isset($sess->error)) {
@ -543,7 +565,8 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
elFinder::extendTimeLimit();
$putFp = tmpfile();
fwrite($putFp, $send);
fseek($putFp, 0);
rewind($putFp);
$_size = strlen($send);
$url = $sess->uploadUrl;
$curl = curl_init();
$options = array(
@ -551,14 +574,14 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
CURLOPT_PUT => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_INFILE => $putFp,
CURLOPT_INFILESIZE => $_size,
CURLOPT_HTTPHEADER => array(
'Content-Length: ' . strlen($send),
'Content-Length: ' . $_size,
'Content-Range: bytes ' . $range,
),
);
curl_setopt_array($curl, $options);
$sess = json_decode(curl_exec($curl));
curl_close($curl);
$sess = json_decode(elFinder::curlExec($curl));
if ($sess) {
if (isset($sess->error)) {
throw new Exception($sess->error->message);
@ -635,6 +658,39 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
return $contents;
}
/**
* Get AccessToken file path
*
* @return string ( description_of_the_return_value )
*/
protected function _od_getATokenFile()
{
$tmp = $aTokenFile = '';
if (!empty($this->token->data->refresh_token)) {
if (!$this->tmp) {
$tmp = elFinder::getStaticVar('commonTempPath');
if (!$tmp) {
$tmp = $this->getTempPath();
}
$this->tmp = $tmp;
}
if ($tmp) {
$aTokenFile = $tmp . DIRECTORY_SEPARATOR . $this->_od_getInitialToken() . '.otoken';
}
}
return $aTokenFile;
}
/**
* Get Initial Token (MD5 hash)
*
* @return string
*/
protected function _od_getInitialToken()
{
return (empty($this->token->initialToken)? md5($this->options['client_id'] . (!empty($this->token->data->refresh_token)? $this->token->data->refresh_token : $this->token->data->access_token)) : $this->token->initialToken);
}
/*********************************************************************/
/* OVERRIDE FUNCTIONS */
/*********************************************************************/
@ -669,24 +725,52 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
$this->session->set('nodeId', $_id);
}
if (!empty($options['tmpPath'])) {
if ((is_dir($options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($options['tmpPath'])) {
$this->tmp = $options['tmpPath'];
}
}
try {
if (empty($options['client_id']) || empty($options['client_secret'])) {
return array('exit' => true, 'body' => '{msg:errNetMountNoDriver}');
}
if (isset($_GET['code'])) {
$itpCare = isset($options['code']);
$code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : '');
if ($code) {
try {
// Obtain the token using the code received by the OneDrive API
$this->session->set('OneDriveTokens',
$this->_od_obtainAccessToken($options['client_id'], $options['client_secret'], $_GET['code']));
if (!empty($options['id'])) {
// Obtain the token using the code received by the OneDrive API
$this->session->set('OneDriveTokens',
$this->_od_obtainAccessToken($options['client_id'], $options['client_secret'], $code, $options['id']));
$out = array(
'node' => $options['id'],
'json' => '{"protocol": "onedrive", "mode": "done", "reset": 1}',
'bind' => 'netmount',
);
return array('exit' => 'callback', 'out' => $out);
$out = array(
'node' => $options['id'],
'json' => '{"protocol": "onedrive", "mode": "done", "reset": 1}',
'bind' => 'netmount',
);
} else {
$nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host'];
$out = array(
'node' => $nodeid,
'json' => json_encode(array(
'protocol' => 'onedrive',
'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']);
}
} catch (Exception $e) {
$out = array(
'node' => $options['id'],
@ -733,20 +817,6 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
}
if ($result === false) {
$cdata = '';
$innerKeys = array('cmd', 'host', 'options', 'pass', 'protocol', 'user');
$this->ARGS = $_SERVER['REQUEST_METHOD'] === 'POST' ? $_POST : $_GET;
foreach ($this->ARGS as $k => $v) {
if (!in_array($k, $innerKeys)) {
$cdata .= '&' . $k . '=' . rawurlencode($v);
}
}
if (empty($options['url'])) {
$options['url'] = elFinder::getConnectorUrl();
}
$callback = $options['url']
. '?cmd=netmount&protocol=onedrive&host=onedrive.com&user=init&pass=return&node=' . $options['id'] . $cdata;
try {
$this->session->set('OneDriveTokens', (object)array('token' => null));
@ -756,22 +826,21 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
$offline = ' offline_access';
}
$redirect_uri = $options['url'] . '/netmount/onedrive/1';
$redirect_uri = elFinder::getConnectorUrl() . '/netmount/onedrive/' . ($options['id'] === 'elfinder'? '1' : $options['id']);
$url = self::AUTH_URL
. '?client_id=' . urlencode($options['client_id'])
. '&scope=' . urlencode('files.readwrite.all' . $offline)
. '&response_type=code'
. '&redirect_uri=' . urlencode($redirect_uri);
$url .= '&oauth_callback=' . rawurlencode($callback);
} catch (Exception $e) {
return array('exit' => true, 'body' => '{msg:errAccess}');
}
$html = '<input id="elf-volumedriver-onedrive-host-btn" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" value="{msg:btnApprove}" type="button" onclick="window.open(\'' . $url . '\')">';
$html = '<input id="elf-volumedriver-onedrive-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: "onedrive", mode: "makebtn"});
</script>';
$("#' . $options['id'] . '").elfinder("instance").trigger("netmount", {protocol: "onedrive", mode: "makebtn", url: "' . $url . '"});
</script>';
return array('exit' => true, 'body' => $html);
} else {
@ -792,11 +861,12 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
$folders = json_encode($folders);
$expires = empty($this->token->data->refresh_token) ? (int)$this->token->expires : 0;
$json = '{"protocol": "onedrive", "mode": "done", "folders": ' . $folders . ', "expires": ' . $expires . '}';
$mnt2res = empty($this->token->data->refresh_token) ? '' : ', "mnt2res": 1';
$json = '{"protocol": "onedrive", "mode": "done", "folders": ' . $folders . ', "expires": ' . $expires . $mnt2res .'}';
$html = 'OneDrive.com';
$html .= '<script>
$("#' . $options['id'] . '").elfinder("instance").trigger("netmount", ' . $json . ');
</script>';
$("#' . $options['id'] . '").elfinder("instance").trigger("netmount", ' . $json . ');
</script>';
return array('exit' => true, 'body' => $html);
}
@ -807,7 +877,11 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
if ($_aToken = $this->session->get('OneDriveTokens')) {
$options['accessToken'] = json_encode($_aToken);
if ($this->options['path'] === 'root' || !$this->options['path']) {
$this->options['path'] = '/';
}
} else {
$this->session->remove('OneDriveTokens');
$this->setError(elFinder::ERROR_NETMOUNT, $options['host'], implode(' ', $this->error()));
return array('exit' => true, 'error' => $this->error());
@ -829,7 +903,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
*/
public function netunmount($netVolumes, $key)
{
if ($tmbs = glob(rtrim($this->options['tmbPath'], '\\/') . DIRECTORY_SEPARATOR . $this->tmbPrefix . '*.png')) {
if (!$this->options['useApiThumbnail'] && ($tmbs = glob(rtrim($this->options['tmbPath'], '\\/') . DIRECTORY_SEPARATOR . $this->tmbPrefix . '*.png'))) {
foreach ($tmbs as $file) {
unlink($file);
}
@ -846,7 +920,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
public function debug()
{
$res = parent::debug();
if (!empty($this->options['accessToken'])) {
if (!empty($this->options['netkey']) && !empty($this->options['accessToken'])) {
$res['accessToken'] = $this->options['accessToken'];
}
@ -872,24 +946,66 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
return $this->setError('Required option `accessToken` is undefined.');
}
try {
$this->token = json_decode($this->options['accessToken']);
$this->_od_refreshToken();
} catch (Exception $e) {
$this->token = null;
$this->session->remove('OneDriveTokens');
return $this->setError($e->getMessage());
if (!empty($this->options['tmpPath'])) {
if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) {
$this->tmp = $this->options['tmpPath'];
}
}
$this->expires = empty($this->token->data->refresh_token) ? (int)$this->token->expires : 0;
$error = false;
try {
$this->token = json_decode($this->options['accessToken']);
if (!is_object($this->token)) {
throw new Exception('Required option `accessToken` is invalid JSON.');
}
if (empty($options['netkey'])) {
// make net mount key
$_tokenKey = isset($this->token->data->refresh_token) ? $this->token->data->refresh_token : $this->token->data->access_token;
$this->netMountKey = md5(implode('-', array('box', $this->options['path'], $_tokenKey)));
} else {
$this->netMountKey = $options['netkey'];
if (empty($this->options['netkey'])) {
$this->netMountKey = $this->_od_getInitialToken();
} else {
$this->netMountKey = $this->options['netkey'];
}
if ($this->aTokenFile = $this->_od_getATokenFile()) {
if (empty($this->options['netkey'])) {
if ($this->aTokenFile) {
if (is_file($this->aTokenFile)) {
$this->token = json_decode(file_get_contents($this->aTokenFile));
if (!is_object($this->token)) {
unlink($this->aTokenFile);
throw new Exception('Required option `accessToken` is invalid JSON.');
}
} else {
file_put_contents($this->aTokenFile, $this->token);
}
}
} else if (is_file($this->aTokenFile)) {
// If the refresh token is the same as the permanent volume
$this->token = json_decode(file_get_contents($this->aTokenFile));
}
}
if ($this->needOnline) {
$this->_od_refreshToken();
$this->expires = empty($this->token->data->refresh_token) ? (int)$this->token->expires : 0;
}
} catch (Exception $e) {
$this->token = null;
$error = true;
$this->setError($e->getMessage());
}
if ($this->netMountKey) {
$this->tmbPrefix = 'onedrive' . base_convert($this->netMountKey, 16, 32);
}
if ($error) {
if (empty($this->options['netkey']) && $this->tmbPrefix) {
// for delete thumbnail
$this->netunmount(null, null);
}
return false;
}
// normalize root path
@ -899,26 +1015,21 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
$this->root = $this->options['path'] = $this->_normpath($this->options['path']);
$this->options['root'] == '' ? $this->options['root'] = 'OneDrive.com' : $this->options['root'];
$this->options['root'] = ($this->options['root'] == '')? 'OneDrive.com' : $this->options['root'];
if (empty($this->options['alias'])) {
$this->options['alias'] = ($this->options['path'] === '/') ? $this->options['root'] :
$this->_od_query(basename($this->options['path']), $fetch_self = true)->name . '@OneDrive';
}
$this->rootName = $this->options['alias'];
$this->tmbPrefix = 'onedrive' . base_convert($this->netMountKey, 10, 32);
if (!empty($this->options['tmpPath'])) {
if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) {
$this->tmp = $this->options['tmpPath'];
if ($this->needOnline) {
$this->options['alias'] = ($this->options['path'] === '/') ? $this->options['root'] :
$this->_od_query(basename($this->options['path']), $fetch_self = true)->name . '@OneDrive';
if (!empty($this->options['netkey'])) {
elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']);
}
} else {
$this->options['alias'] = $this->options['root'];
}
}
if (!$this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) {
$this->tmp = $tmp;
}
$this->rootName = $this->options['alias'];
// This driver dose not support `syncChkAsTs`
$this->options['syncChkAsTs'] = false;
@ -1234,8 +1345,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
CURLOPT_POSTFIELDS => json_encode($data),
));
$result = curl_exec($curl);
curl_close($curl);
$result = elFinder::curlExec($curl);
if ($result) {
$result = json_decode($result);
if (isset($result->link)) {
@ -1467,7 +1577,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
}
$raw = $this->_od_query($itemId, true, false, $options);
if ($raw && $img = $raw->image) {
if ($raw && property_exists($raw, 'image') && $img = $raw->image) {
if (isset($img->width) && isset($img->height)) {
$ret = array('dim' => $img->width . 'x' . $img->height);
if ($tmbSize) {
@ -1536,6 +1646,16 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
'headers' => array('Authorization: Bearer ' . $this->token->data->access_token),
);
// to support range request
if (func_num_args() > 2) {
$opts = func_get_arg(2);
} else {
$opts = array();
}
if (!empty($opts['httpheaders'])) {
$data['headers'] = array_merge($opts['httpheaders'], $data['headers']);
}
return elFinder::getStreamByUrl($data);
}
@ -1552,7 +1672,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
**/
protected function _fclose($fp, $path = '')
{
fclose($fp);
is_resource($fp) && fclose($fp);
if ($path) {
unlink($this->getTempFile($path));
}
@ -1592,8 +1712,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
));
//create the Folder in the Parent
$result = curl_exec($curl);
curl_close($curl);
$result = elFinder::curlExec($curl);
$folder = json_decode($result);
return $this->_joinPath($path, $folder->id);
@ -1671,8 +1790,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
),
CURLOPT_POSTFIELDS => json_encode($data),
));
$result = curl_exec($curl);
curl_close($curl);
$result = elFinder::curlExec($curl);
$res = new stdClass();
if (preg_match('/Location: (.+)/', $result, $m)) {
@ -1686,8 +1804,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
'Content-Type: application/json',
),
));
$res = json_decode(curl_exec($curl));
curl_close($curl);
$res = json_decode(elFinder::curlExec($curl));
if (isset($res->status)) {
if ($res->status === 'completed' || $res->status === 'failed') {
break;
@ -1748,8 +1865,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
CURLOPT_POSTFIELDS => json_encode($data),
));
$result = json_decode(curl_exec($curl));
curl_close($curl);
$result = json_decode(elFinder::curlExec($curl));
if ($result && isset($result->id)) {
return $targetDir . '/' . $result->id;
} else {
@ -1784,8 +1900,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
));
//unlink or delete File or Folder in the Parent
$result = curl_exec($curl);
curl_close($curl);
$result = elFinder::curlExec($curl);
} catch (Exception $e) {
return $this->setError('OneDrive error: ' . $e->getMessage());
}
@ -1851,6 +1966,16 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
}
try {
// for unseekable file pointer
if (!elFinder::isSeekableStream($fp)) {
if ($tfp = tmpfile()) {
if (stream_copy_to_stream($fp, $tfp, $size? $size : -1) !== false) {
rewind($tfp);
$fp = $tfp;
}
}
}
//Create or Update a file
if ($itemId === '') {
$url = self::API_URL . $parentId . ':/' . rawurlencode($name) . ':/content';
@ -1872,8 +1997,7 @@ class elFinderVolumeOneDrive extends elFinderVolumeDriver
curl_setopt_array($curl, $options);
//create or update File in the Target
$file = json_decode(curl_exec($curl));
curl_close($curl);
$file = json_decode(elFinder::curlExec($curl));
return $this->_joinPath($parent, $file->id);
} catch (Exception $e) {

View file

@ -0,0 +1,838 @@
<?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 {
/**
* 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 ?: '.') ?: [];
/*
$raw = $this->connect->rawlist($path ?: '.') ?: [];
$raw = array_map(function($key, $value) {
$value['name'] = $key;
return $value;
}, array_keys($raw), $raw);
return $raw;
*/
}
/*********************************************************************/
/* 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 string $raw line from rawlist() output
* @param $base
* @param bool $nameOnly
*
* @return array
* @author Dmitry Levashov
*/
protected function parseRaw($raw, $base, $nameOnly = false)
{
$info = $raw;
$stat = array();
if ($info['filename'] == '.' || $info['filename'] == '..') {
return false;
}
$name = $info['filename'];
if (preg_match('|(.+)\-\>(.+)|', $name, $m)) {
$name = trim($m[1]);
// check recursive processing
if ($this->cacheDirTarget && $this->_joinPath($base, $name) !== $this->cacheDirTarget) {
return array();
}
if (!$nameOnly) {
$target = trim($m[2]);
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;
$stat['mime'] = $info['type'] == NET_SFTP_TYPE_DIRECTORY ? 'directory' : $this->mimetype($stat['name'], true);
$stat['size'] = $stat['mime'] == 'directory' ? 0 : $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($permissions[-3]) : decbin($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 $raw) {
if (($stat = $this->parseRaw($raw, $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;
}
$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 $str) {
$info = preg_split('/\s+/', $str, 9);
if ($info[8] === '.') {
$info[8] = 'root';
if ($stat = $this->parseRaw(join(' ', $info), $path)) {
unset($stat['name']);
$res = array_merge($res, $stat);
if ($res['ts']) {
$ts = 0;
unset($check['ts']);
}
}
}
if ($check && ($stat = $this->parseRaw($str, $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;
}
}
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, 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, 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

View file

@ -84,6 +84,10 @@ class elFinderPluginAutoResize extends elFinderPlugin
public function onUpLoadPreSave(&$thash, &$name, $src, $elfinder, $volume)
{
if (!$src) {
return false;
}
$opts = $this->getCurrentOpts($volume);
if (!$this->iaEnabled($opts, $elfinder)) {

View file

@ -69,6 +69,10 @@ class elFinderPluginAutoRotate extends elFinderPlugin
public function onUpLoadPreSave(&$thash, &$name, $src, $elfinder, $volume)
{
if (!$src) {
return false;
}
$opts = $this->getCurrentOpts($volume);
if (!$this->iaEnabled($opts, $elfinder)) {
@ -114,7 +118,10 @@ class elFinderPluginAutoRotate extends elFinderPlugin
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:
@ -128,6 +135,9 @@ class elFinderPluginAutoRotate extends elFinderPlugin
break;
}
}
if (!$degree) {
return false;
}
$opts = array(
'degree' => $degree,
'jpgQuality' => $quality,

View file

@ -13,7 +13,7 @@
* 'upload.pre mkdir.pre mkfile.pre rename.pre archive.pre ls.pre' => array(
* 'Plugin.Normalizer.cmdPreprocess'
* ),
* 'upload.presave' => array(
* 'upload.presave paste.copyfrom' => array(
* 'Plugin.Normalizer.onUpLoadPreSave'
* )
* ),
@ -169,7 +169,11 @@ class elFinderPluginNormalizer extends elFinderPlugin
$str = Normalizer::normalize($str, Normalizer::FORM_KC);
} else {
if (!class_exists('I18N_UnicodeNormalizer', false)) {
include_once 'I18N/UnicodeNormalizer.php';
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();
@ -182,7 +186,7 @@ class elFinderPluginNormalizer extends elFinderPlugin
}
if ($opts['umlauts']) {
if (strpos($str = htmlentities($str, ENT_QUOTES, 'UTF-8'), '&') !== false) {
$str = html_entity_decode(preg_replace('~&([a-z]{1,2})(?:acute|cedil|circ|grave|lig|orn|ring|slash|tilde|uml);~i', '$1', $str), ENT_QUOTES, 'utf-8');
$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'])) {

View file

@ -9,7 +9,7 @@
* 'upload.pre mkdir.pre mkfile.pre rename.pre archive.pre ls.pre' => array(
* 'Plugin.Sanitizer.cmdPreprocess'
* ),
* 'upload.presave' => array(
* 'upload.presave paste.copyfrom' => array(
* 'Plugin.Sanitizer.onUpLoadPreSave'
* )
* ),

View file

@ -100,6 +100,10 @@ class elFinderPluginWatermark extends elFinderPlugin
public function onUpLoadPreSave(&$thash, &$name, $src, $elfinder, $volume)
{
if (!$src) {
return false;
}
$opts = $this->getCurrentOpts($volume);
if (!$this->iaEnabled($opts, $elfinder)) {
@ -232,15 +236,16 @@ class elFinderPluginWatermark extends elFinderPlugin
// check interlace
$opts['interlace'] = ($opts['interlace'] & $imgTypes[$imageType]);
if (class_exists('Imagick', false)) {
return $this->watermarkPrint_imagick($src, $watermark, $dest_x, $dest_y, $quality, $transparency, $watermarkImgInfo, $opts);
} else {
// 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, $watermark, $dest_x, $dest_y, $quality, $transparency, $watermarkImgInfo, $opts)
private function watermarkPrint_imagick($src, $watermarkSrc, $dest_x, $dest_y, $quality, $transparency, $watermarkImgInfo, $opts)
{
try {
@ -249,7 +254,7 @@ class elFinderPluginWatermark extends elFinderPlugin
$img = new Imagick($src);
// Open the watermark
$watermark = new Imagick($watermark);
$watermark = new Imagick($watermarkSrc);
// zoom
if ($opts['ratio']) {