diff --git a/core/src/core/src/pydio/Core/Controller/XMLWriter.php b/core/src/core/src/pydio/Core/Controller/XMLWriter.php
index 1d372e9dc8..2d3fae8185 100644
--- a/core/src/core/src/pydio/Core/Controller/XMLWriter.php
+++ b/core/src/core/src/pydio/Core/Controller/XMLWriter.php
@@ -73,11 +73,16 @@ public static function header($docNode="tree", $attributes=array())
* Outputs a closing root not ()
* @static
* @param string $docNode
- * @return void
+ * @param bool $print
+ * @return void|string
*/
- public static function close($docNode="tree")
+ public static function close($docNode="tree", $print = true)
{
- print("$docNode>");
+ if($print){
+ print("$docNode>");
+ }else{
+ return "$docNode>";
+ }
}
public static function wrapDocument($content, $docNode = "tree", $attributes = array()){
@@ -126,15 +131,17 @@ public static function write($data, $print)
* @param integer $totalPages
* @param integer $dirsCount
* @param null $remoteSortAttributes
+ * @param bool $print
+ * @return void|string
*/
- public static function renderPaginationData($count, $currentPage, $totalPages, $dirsCount = -1, $remoteSortAttributes = null)
+ public static function renderPaginationData($count, $currentPage, $totalPages, $dirsCount = -1, $remoteSortAttributes = null, $print = true)
{
$remoteSortString = "";
if (is_array($remoteSortAttributes)) {
foreach($remoteSortAttributes as $k => $v) $remoteSortString .= " $k='$v'";
}
$string = '';
- XMLWriter::write($string, true);
+ return XMLWriter::write($string, $print);
}
/**
diff --git a/core/src/plugins/access.fs/class.fsAccessDriver.php b/core/src/plugins/access.fs/class.fsAccessDriver.php
index 6646962023..2fce18a9e7 100644
--- a/core/src/plugins/access.fs/class.fsAccessDriver.php
+++ b/core/src/plugins/access.fs/class.fsAccessDriver.php
@@ -34,6 +34,7 @@
use Pydio\Access\Core\Model\AJXP_Node;
use Pydio\Access\Core\IAjxpWrapperProvider;
use Pydio\Access\Core\Model\NodesDiff;
+use Pydio\Access\Core\Model\NodesList;
use Pydio\Access\Core\RecycleBinManager;
use Pydio\Access\Core\Model\Repository;
use Pydio\Access\Core\Model\UserSelection;
@@ -46,7 +47,6 @@
use Pydio\Core\Controller\Controller;
use Pydio\Core\Exception\PydioException;
use Pydio\Core\Utils\Utils;
-use Pydio\Core\Controller\XMLWriter;
use Pydio\Core\Controller\HTMLWriter;
use Pydio\Core\PluginFramework\PluginsService;
use Pydio\Core\Utils\TextEncoder;
@@ -641,25 +641,23 @@ public function switchAction(ServerRequestInterface &$request, ResponseInterface
case "stat" :
clearstatcache();
- header("Content-type:application/json");
+ $jsonData = new \stdClass;
if($selection->isUnique()){
$stat = @stat($this->urlBase.$selection->getUniqueFile());
- if (!$stat || !is_readable($selection->getUniqueNode()->getUrl())) {
- print '{}';
- } else {
- print json_encode($stat);
+ if ($stat !== false && is_readable($selection->getUniqueNode()->getUrl())) {
+ $jsonData = $stat;
}
}else{
$files = $selection->getFiles();
- print '{';
foreach($files as $index => $path){
$stat = @stat($this->urlBase.$path);
- if(!$stat || !is_readable($this->urlBase.$path)) $stat = '{}';
- else $stat = json_encode($stat);
- print json_encode($path).':'.$stat . (($index < count($files) -1) ? "," : "");
+ if(!$stat || !is_readable($this->urlBase.$path)) {
+ $stat = new \stdClass();
+ }
+ $jsonData->$path = $stat;
}
- print '}';
}
+ $response = new Response\JsonResponse($jsonData);
break;
@@ -679,16 +677,15 @@ public function switchAction(ServerRequestInterface &$request, ResponseInterface
} else {
$code=str_replace("<","<",TextEncoder::magicDequote($code));
}
+ $response = $response->withHeader("Content-Type", "text/plain");
try {
Controller::applyHook("node.before_change", array(&$currentNode, strlen($code)));
} catch (\Exception $e) {
- header("Content-Type:text/plain");
- print $e->getMessage();
+ $response->getBody()->write($e->getMessage());
break;
}
if (!is_file($fileName) || !$this->isWriteable($fileName, "file")) {
- header("Content-Type:text/plain");
- print((!$this->isWriteable($fileName, "file")?"1001":"1002"));
+ $response->getBody()->write((!$this->isWriteable($fileName, "file")?"1001":"1002"));
break;
}
$fp=fopen($fileName,"w");
@@ -696,8 +693,7 @@ public function switchAction(ServerRequestInterface &$request, ResponseInterface
fclose($fp);
clearstatcache(true, $fileName);
Controller::applyHook("node.change", array($currentNode, $currentNode, false));
- header("Content-Type:text/plain");
- print($mess[115]);
+ $response->getBody()->write($mess[115]);
break;
@@ -943,6 +939,8 @@ public function switchAction(ServerRequestInterface &$request, ResponseInterface
//------------------------------------
case "ls":
+ $nodesList = new NodesList();
+
if(!isSet($dir) || $dir == "/") $dir = "";
$lsOptions = $this->parseLsOptions((isSet($httpVars["options"])?$httpVars["options"]:"a"));
@@ -964,7 +962,7 @@ public function switchAction(ServerRequestInterface &$request, ResponseInterface
if($selection->isUnique() && strpos($selection->getUniqueFile(), "/") !== 0){
$selection->setFiles(array($dir . "/" . $selection->getUniqueFile()));
}
-
+
$orderField = $orderDirection = null;
$threshold = 500; $limitPerPage = 200;
$defaultOrder = $this->repository->getOption("REMOTE_SORTING_DEFAULT_COLUMN");
@@ -976,12 +974,7 @@ public function switchAction(ServerRequestInterface &$request, ResponseInterface
$orderField = $defaultOrder;
}
}
- if(isSet($httpVars["recursive"]) && $httpVars["recursive"] == "true"){
- $max_depth = (isSet($httpVars["max_depth"])?intval($httpVars["max_depth"]):0);
- $max_nodes = (isSet($httpVars["max_nodes"])?intval($httpVars["max_nodes"]):0);
- $crt_depth = (isSet($httpVars["crt_depth"])?intval($httpVars["crt_depth"])+1:1);
- $crt_nodes = (isSet($httpVars["crt_nodes"])?intval($httpVars["crt_nodes"]):0);
- }else{
+ if(!isSet($httpVars["recursive"]) || $httpVars["recursive"] != "true"){
$threshold = $this->repository->getOption("PAGINATION_THRESHOLD");
if(!isSet($threshold) || intval($threshold) == 0) $threshold = 500;
$limitPerPage = $this->repository->getOption("PAGINATION_NUMBER");
@@ -992,11 +985,7 @@ public function switchAction(ServerRequestInterface &$request, ResponseInterface
$uniqueNodes = $selection->buildNodes();
$parentAjxpNode = new AJXP_Node($this->urlBase."/", array());
Controller::applyHook("node.read", array(&$parentAjxpNode));
- if (XMLWriter::$headerSent == "tree") {
- XMLWriter::renderAjxpNode($parentAjxpNode, false);
- } else {
- XMLWriter::renderAjxpHeaderNode($parentAjxpNode);
- }
+ $nodesList->setParentNode($parentAjxpNode);
foreach($uniqueNodes as $node){
if(!file_exists($node->getUrl()) || (!is_readable($node->getUrl()) && !is_writable($node->getUrl()))) continue;
$nodeName = $node->getLabel();
@@ -1031,9 +1020,8 @@ public function switchAction(ServerRequestInterface &$request, ResponseInterface
$node->mergeMetadata(array("page_position" => floor($index / $limitPerPage) +1));
}
}
- XMLWriter::renderAjxpNode($node);
+ $nodesList->addBranch($node);
}
- XMLWriter::close();
break;
}
@@ -1048,9 +1036,6 @@ public function switchAction(ServerRequestInterface &$request, ResponseInterface
if(isSet($sharedHandle)){
rewind($handle);
}
- if(isSet($crt_nodes)){
- $crt_nodes += $countFiles;
- }
$totalPages = $crtPage = 1;
if (isSet($threshold) && isSet($limitPerPage) && $countFiles > $threshold) {
$offset = 0;
@@ -1071,11 +1056,7 @@ public function switchAction(ServerRequestInterface &$request, ResponseInterface
$parentAjxpNode = new AJXP_Node($nonPatchedPath, $metaData);
$parentAjxpNode->loadNodeInfo(false, true, ($lsOptions["l"]?"all":"minimal"));
Controller::applyHook("node.read", array(&$parentAjxpNode));
- if (XMLWriter::$headerSent == "tree") {
- XMLWriter::renderAjxpNode($parentAjxpNode, false);
- } else {
- XMLWriter::renderAjxpHeaderNode($parentAjxpNode);
- }
+ $nodesList->setParentNode($parentAjxpNode);
if (isSet($totalPages) && isSet($crtPage) && ($totalPages > 1 || ! Utils::userAgentIsNativePydioApp())) {
$remoteOptions = null;
if ($this->getFilteredOption("REMOTE_SORTING")) {
@@ -1089,15 +1070,8 @@ public function switchAction(ServerRequestInterface &$request, ResponseInterface
if(isSet($sharedHandle)) {
rewind($sharedHandle);
}
- XMLWriter::renderPaginationData(
- $countFiles,
- $crtPage,
- $totalPages,
- $foldersCounts,
- $remoteOptions
- );
- if (!$lsOptions["f"]) {
- XMLWriter::close();
+ $nodesList->setPaginationData($countFiles, $crtPage, $totalPages, $foldersCounts, $remoteOptions);
+ if ($totalPages > 1 && !$lsOptions["f"]) {
if(isSet($sharedHandle)) {
closedir($sharedHandle);
}
@@ -1181,6 +1155,13 @@ public function switchAction(ServerRequestInterface &$request, ResponseInterface
$cursor ++;
}
if (isSet($httpVars["recursive"]) && $httpVars["recursive"] == "true") {
+
+ $max_depth = (isSet($httpVars["max_depth"])?intval($httpVars["max_depth"]):0);
+ $max_nodes = (isSet($httpVars["max_nodes"])?intval($httpVars["max_nodes"]):0);
+ $crt_depth = (isSet($httpVars["crt_depth"])?intval($httpVars["crt_depth"])+1:1);
+ $crt_nodes = (isSet($httpVars["crt_nodes"])?intval($httpVars["crt_nodes"]):0);
+ $crt_nodes += $countFiles;
+
$breakNow = false;
if(isSet($max_depth) && $max_depth > 0 && $crt_depth >= $max_depth) $breakNow = true;
if(isSet($max_nodes) && $max_nodes > 0 && $crt_nodes >= $max_nodes) $breakNow = true;
@@ -1190,7 +1171,7 @@ public function switchAction(ServerRequestInterface &$request, ResponseInterface
foreach ($fullList["d"] as &$nodeDir) {
if($breakNow){
$nodeDir->mergeMetadata(array("ajxp_has_children" => $this->countFiles($nodeDir->getUrl(), false, true)?"true":"false"));
- XMLWriter::renderAjxpNode($nodeDir, true);
+ $nodesList->addBranch($nodeDir);
continue;
}
$newBody = array(
@@ -1204,36 +1185,50 @@ public function switchAction(ServerRequestInterface &$request, ResponseInterface
);
$fakeRequest = ServerRequestFactory::fromGlobals($request->getServerParams(), array(), $newBody, $request->getCookieParams());
$fakeRequest = $fakeRequest->withAttribute("action", "ls");
+ $fakeRequest = $fakeRequest->withAttribute("parent_node_list", $nodesList);
$this->switchAction($fakeRequest, new Response());
}
+
} else {
- array_map(array("\Pydio\Core\Controller\XMLWriter", "renderAjxpNode"), $fullList["d"]);
+
+ array_map(array($nodesList, "addBranch"), $fullList["d"]);
+
}
- array_map(array("\Pydio\Core\Controller\XMLWriter", "renderAjxpNode"), $fullList["z"]);
- array_map(array("\Pydio\Core\Controller\XMLWriter", "renderAjxpNode"), $fullList["f"]);
+ array_map(array($nodesList, "addBranch"), $fullList["z"]);
+ array_map(array($nodesList, "addBranch"), $fullList["f"]);
// ADD RECYCLE BIN TO THE LIST
- if ($dir == "" && RecycleBinManager::recycleEnabled() && $this->getFilteredOption("HIDE_RECYCLE", $this->repository) !== true) {
+ if ($dir == "" && $lsOptions["d"] && RecycleBinManager::recycleEnabled() && $this->getFilteredOption("HIDE_RECYCLE", $this->repository) !== true) {
$recycleBinOption = RecycleBinManager::getRelativeRecycle();
if (file_exists($this->urlBase.$recycleBinOption)) {
$recycleNode = new AJXP_Node($this->urlBase.$recycleBinOption);
$recycleNode->loadNodeInfo();
- XMLWriter::renderAjxpNode($recycleNode);
+ $nodesList->addBranch($recycleNode);
}
}
$this->logDebug("LS Time : ".intval((microtime()-$startTime)*1000)."ms");
- XMLWriter::close();
+ $parentList = $request->getAttribute("parent_node_list", null);
+ if($parentList !== null){
+ $parentList->addBranch($nodesList);
+ }
break;
}
- if(isSet($logMessage) || !$nodesDiffs->isEmpty()){
+ if(isSet($logMessage) || !$nodesDiffs->isEmpty() || isSet($nodesList)){
$body = new SerializableResponseStream();
- if(isSet($logMessage)) $body->addChunk($logMessage);
- if(!$nodesDiffs->isEmpty()) $body->addChunk($nodesDiffs);
+ if(isSet($logMessage)) {
+ $body->addChunk($logMessage);
+ }
+ if(!$nodesDiffs->isEmpty()) {
+ $body->addChunk($nodesDiffs);
+ }
+ if(isSet($nodesList)) {
+ $body->addChunk($nodesList);
+ }
$response = $response->withBody($body);
}
@@ -1615,22 +1610,22 @@ public function readFile($filePathOrData, $headerType="plain", $localName="", $d
header('Content-Disposition: attachment; filename="' . basename($filePathOrData) . '"');
return;
}
- if ($this->getFilteredOption("USE_XACCELREDIRECT", $this->repository->getId()) && AJXP_MetaStreamWrapper::actualRepositoryWrapperClass($this->repository->getId()) == "fsAccessWrapper" && array_key_exists("X-Accel-Mapping",$_SERVER)) {
- if(!$realfileSystem) $filePathOrData = AJXP_MetaStreamWrapper::getRealFSReference($filePathOrData);
- $filePathOrData = str_replace("\\", "/", $filePathOrData);
- $filePathOrData = TextEncoder::toUTF8($filePathOrData);
- $mapping = explode('=',$_SERVER['X-Accel-Mapping']);
- $replacecount = 0;
- $accelfile = str_replace($mapping[0],$mapping[1],$filePathOrData,$replacecount);
- if ($replacecount == 1) {
- header("X-Accel-Redirect: $accelfile");
- header("Content-type: application/octet-stream");
- header('Content-Disposition: attachment; filename="' . basename($accelfile) . '"');
- return;
- } else {
- $this->logError("X-Accel-Redirect","Problem with X-Accel-Mapping for file $filePathOrData");
- }
- }
+ if ($this->getFilteredOption("USE_XACCELREDIRECT", $this->repository->getId()) && AJXP_MetaStreamWrapper::actualRepositoryWrapperClass($this->repository->getId()) == "fsAccessWrapper" && array_key_exists("X-Accel-Mapping",$_SERVER)) {
+ if(!$realfileSystem) $filePathOrData = AJXP_MetaStreamWrapper::getRealFSReference($filePathOrData);
+ $filePathOrData = str_replace("\\", "/", $filePathOrData);
+ $filePathOrData = TextEncoder::toUTF8($filePathOrData);
+ $mapping = explode('=',$_SERVER['X-Accel-Mapping']);
+ $replacecount = 0;
+ $accelfile = str_replace($mapping[0],$mapping[1],$filePathOrData,$replacecount);
+ if ($replacecount == 1) {
+ header("X-Accel-Redirect: $accelfile");
+ header("Content-type: application/octet-stream");
+ header('Content-Disposition: attachment; filename="' . basename($accelfile) . '"');
+ return;
+ } else {
+ $this->logError("X-Accel-Redirect","Problem with X-Accel-Mapping for file $filePathOrData");
+ }
+ }
$stream = fopen("php://output", "a");
if ($realfileSystem) {
$this->logDebug("realFS!", array("file"=>$filePathOrData));
diff --git a/core/src/plugins/core.access/src/Model/NodesList.php b/core/src/plugins/core.access/src/Model/NodesList.php
new file mode 100644
index 0000000000..26d09a2a28
--- /dev/null
+++ b/core/src/plugins/core.access/src/Model/NodesList.php
@@ -0,0 +1,100 @@
+
+ * This file is part of Pydio.
+ *
+ * Pydio is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pydio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pydio. If not, see .
+ *
+ * The latest code can be found at .
+ */
+namespace Pydio\Access\Core\Model;
+
+defined('AJXP_EXEC') or die('Access not allowed');
+
+use Pydio\Core\Controller\XMLWriter;
+use Pydio\Core\Http\XMLSerializableResponseChunk;
+
+class NodesList implements XMLSerializableResponseChunk
+{
+
+ /**
+ * @var AJXP_Node
+ */
+ private $parentNode;
+ /**
+ * @var (AJXP_Node|NodesList)[]
+ */
+ private $children = array();
+
+ private $isRoot = true;
+
+ private $paginationData;
+
+ public function __construct(){
+ }
+
+ public function setParentNode(AJXP_Node $parentNode){
+ $this->parentNode = $parentNode;
+ }
+ /**
+ * @param AJXP_Node|NodesList $nodeOrList
+ */
+ public function addBranch($nodeOrList){
+ $this->children[] = $nodeOrList;
+ if($nodeOrList instanceof NodesList){
+ $nodeOrList->setRoot(false);
+ }
+ }
+
+ public function setPaginationData($count, $currentPage, $totalPages, $dirsCount = -1, $remoteSortAttributes = null){
+ $this->paginationData = [
+ 'count' => $count,
+ 'current' => $currentPage,
+ 'total' => $totalPages,
+ 'dirs' => $dirsCount,
+ 'remoteSort' => $remoteSortAttributes
+ ];
+ }
+
+ public function setRoot($bool){
+ $this->isRoot = $bool;
+ }
+
+ /**
+ * @return string
+ */
+ public function toXML()
+ {
+ $buffer = "";
+ $buffer .= XMLWriter::renderAjxpNode($this->parentNode, false, false);
+ if(isSet($this->paginationData)){
+ $buffer .= XMLWriter::renderPaginationData(
+ $this->paginationData["count"],
+ $this->paginationData["current"],
+ $this->paginationData["total"],
+ $this->paginationData["dirs"],
+ $this->paginationData["remoteSort"],
+ false);
+ }
+ foreach ($this->children as $child){
+ if($child instanceof NodesList){
+ $buffer .= $child->toXML();
+ }else{
+ $buffer .= XMLWriter::renderAjxpNode($child, true, false);
+ }
+ }
+ $buffer .= XMLWriter::close("tree", false);
+ return $buffer;
+ }
+}
\ No newline at end of file