* Default elFinder connector
* @author Dmitry (dio) Levashov
protected $options = array();
* Must be use output($data) $data['header']
protected $reqMethod = '';
* Content type of output JSON
protected static $contentType = 'Content-Type: application/json; charset=utf-8';
* @author Dmitry (dio) Levashov
public function __construct($elFinder, $debug = false)
$this->elFinder = $elFinder;
$this->reqMethod = strtoupper($_SERVER["REQUEST_METHOD"]);
self::$contentType = 'Content-Type: text/plain; charset=utf-8';
* Execute elFinder command and output result
* @author Dmitry (dio) Levashov
$isPost = $this->reqMethod === 'POST';
$src = $isPost ? array_merge($_GET, $_POST) : $_GET;
$maxInputVars = (!$src || isset($src['targets'])) ? ini_get('max_input_vars') : null;
if ((!$src || $maxInputVars) && $rawPostData = file_get_contents('php://input')) {
// for max_input_vars and supports IE XDomainRequest()
$parts = explode('&', $rawPostData);
if (!$src || $maxInputVars < count($parts)) {
foreach ($parts as $part) {
list($key, $value) = array_pad(explode('=', $part), 2, '');
$key = rawurldecode($key);
if (preg_match('/^(.+?)\[([^\[\]]*)\]$/', $key, $m)) {
if (!isset($src[$key])) {
$src[$key][$idx] = rawurldecode($value);
$src[$key][] = rawurldecode($value);
$src[$key] = rawurldecode($value);
$_POST = $this->input_filter($src);
$_REQUEST = $this->input_filter(array_merge_recursive($src, $_REQUEST));
if (isset($src['targets']) && $this->elFinder->maxTargets && count($src['targets']) > $this->elFinder->maxTargets) {
$this->output(array('error' => $this->elFinder->error(elFinder::ERROR_MAX_TARGTES)));
$cmd = isset($src['cmd']) ? $src['cmd'] : '';
if (!function_exists('json_encode')) {
$error = $this->elFinder->error(elFinder::ERROR_CONF, elFinder::ERROR_CONF_NO_JSON);
$this->output(array('error' => '{"error":["' . implode('","', $error) . '"]}', 'raw' => true));
if (!$this->elFinder->loaded()) {
$this->output(array('error' => $this->elFinder->error(elFinder::ERROR_CONF, elFinder::ERROR_CONF_NO_VOL), 'debug' => $this->elFinder->mountErrors));
$this->output(array('error' => $this->elFinder->error(elFinder::ERROR_UPLOAD, elFinder::ERROR_UPLOAD_TOTAL_SIZE), 'header' => 'Content-Type: text/html'));
if (!$this->elFinder->commandExists($cmd)) {
$this->output(array('error' => $this->elFinder->error(elFinder::ERROR_UNKNOWN_CMD)));
// collect required arguments to exec command
foreach ($this->elFinder->commandArgsList($cmd) as $name => $req) {
$this->output(array('error' => $this->elFinder->error(elFinder::ERROR_INV_PARAMS, $cmd)));
$arg = isset($src[$name]) ? $src[$name] : '';
if (!is_array($arg) && $req !== '') {
if ($req && $arg === '') {
$this->output(array('error' => $this->elFinder->error(elFinder::ERROR_INV_PARAMS, $cmd)));
$args['debug'] = isset($src['debug']) ? !!$src['debug'] : false;
$args = $this->input_filter($args);
$args['FILES'] = $_FILES;
$this->output($this->elFinder->exec($cmd, $args));
} catch (elFinderAbortException $e) {
// unlock session data for multiple access
$this->elFinder->getSession()->close();
header('HTTP/1.0 204 No Content');
while (ob_get_level() && ob_end_clean()) {
* @param array|string $value HTTP header(s)
public function setHeader($value)
* @param array data to output
* @throws elFinderAbortException
* @author Dmitry (dio) Levashov
protected function output(array $data)
// unlock session data for multiple access
$this->elFinder->getSession()->close();
// client disconnect should abort
ignore_user_abort(false);
self::sendHeader($this->header);
if (isset($data['pointer'])) {
elFinder::extendTimeLimit(0);
if (!empty($data['header'])) {
self::sendHeader($data['header']);
while (ob_get_level() && ob_end_clean()) {
$sendData = !($this->reqMethod === 'HEAD' || !empty($data['info']['xsendfile']));
if (($this->reqMethod === 'GET' || !$sendData)
&& (elFinder::isSeekableStream($fp) || elFinder::isSeekableUrl($fp))
&& (array_search('Accept-Ranges: none', headers_list()) === false)) {
header('Accept-Ranges: bytes');
if (!empty($_SERVER['HTTP_RANGE'])) {
$size = $data['info']['size'];
if (preg_match('/bytes=(\d*)-(\d*)(,?)/i', $_SERVER['HTTP_RANGE'], $matches)) {
if (empty($matches[3])) {
if (empty($matches[1]) && $matches[1] !== '0') {
$start = $size - $matches[2];
$start = intval($matches[1]);
if (!empty($matches[2])) {
$end = intval($matches[2]);
$toEnd = ($end == ($size - 1));
$psize = $end - $start + 1;
header('HTTP/1.1 206 Partial Content');
header('Content-Length: ' . $psize);
header('Content-Range: bytes ' . $start . '-' . $end . '/' . $size);
// Apache mod_xsendfile dose not support range request
if (isset($data['info']['xsendfile']) && strtolower($data['info']['xsendfile']) === 'x-sendfile') {
if (function_exists('header_remove')) {
header_remove($data['info']['xsendfile']);
header($data['info']['xsendfile'] . ':');
unset($data['info']['xsendfile']);
if ($this->reqMethod !== 'HEAD') {
$sendData && !elFinder::isSeekableUrl($fp) && fseek($fp, $start);
if ($sendData && is_null($psize)) {
header('Accept-Ranges: none');
if (isset($data['info']) && !$data['info']['size']) {
if (function_exists('header_remove')) {
header_remove('Content-Length');
header('Content-Length:');
if ($toEnd || elFinder::isSeekableUrl($fp)) {
// PHP < 5.6 has a bug of fpassthru
// see https://bugs.php.net/bug.php?id=66736
if (version_compare(PHP_VERSION, '5.6', '<')) {
file_put_contents('php://output', $fp);
if(function_exists('fpassthru')) {
file_put_contents('php://output', $fp);
$out = fopen('php://output', 'wb');
stream_copy_to_stream($fp, $out, $psize);
if (!empty($data['volume'])) {
$data['volume']->close($fp, $data['info']['hash']);
* Remove null & stripslashes applies on "magic_quotes_gpc"
protected function input_filter($args)
static $magic_quotes_gpc = NULL;
if ($magic_quotes_gpc === NULL)
$magic_quotes_gpc = (version_compare(PHP_VERSION, '5.4', '<') && get_magic_quotes_gpc());
return array_map(array(& $this, 'input_filter'), $args);
$res = str_replace("\0", '', $args);
$magic_quotes_gpc && ($res = stripslashes($res));
$res = stripslashes($res);
* @param string|array $header optional header
protected static function sendHeader($header = null)
foreach ($header as $h) {
public static function outputJson($data)
$header = isset($data['header']) ? $data['header'] : self::$contentType;
self::sendHeader($header);
if (!empty($data['raw']) && isset($data['error'])) {
if (isset($data['debug']) && isset($data['debug']['backendErrors'])) {
$data['debug']['backendErrors'] = array_merge($data['debug']['backendErrors'], elFinder::$phpErrors);
$out = json_encode($data);
while (ob_get_level() && ob_end_clean()) {
header('Content-Length: ' . strlen($out));