function COPY($options, $drop = false)
{
$statusSymlinkDelete = false;
$arCacheCleanID = array();
if(!$this->CheckWebRights("", array("action" => "create"), true))
{
return $this->ThrowAccessDenied(__LINE__);
}
elseif($_SERVER['REQUEST_METHOD'] == "MOVE" && !empty($_SERVER["CONTENT_LENGTH"]))
{
return "415 Unsupported media type";
}
elseif($options["path"] == $options["dest_url"])
{
return "204 No Content";
}
elseif(empty($options["dest_url"]))
{
return $this->ThrowError("502 bad gateway", "EMPTY_DESTINATION_URL", GetMessage("WD_FILE_ERROR2"), __LINE__);
}
$destUrl = $options["dest_url"];
if(mb_substr($destUrl, -1) === "/")
{
$destUrl = mb_substr($destUrl, 0, -1);
}
$destName = GetFileName($destUrl);
if($destUrl !== "" && $destName !== "")
{
$destParentDir = GetDirPath($destUrl);
$destParentDir = $destParentDir ?: '/';
$o = array("path" => $destParentDir, "depth" => 1);
$result = $this->PROPFIND($o, $files, array("COLUMNS" => array("ID", "NAME"), "return" => "array"));
if (!empty($result["RESULT"]))
{
foreach ($result["RESULT"] as $key => $res)
{
if($res["NAME"] === $destName)
{
if(GetFileExtension($destName) <> '')
{
return $this->ThrowError("400 Bad Request", "FOLDER_IS_EXISTS", str_replace("#FILE#", '"' .$res["NAME"] . '"', GetMessage("WD_FILE_ERROR8")), __LINE__);
}
elseif(isset($options['section_id']) && $res['ID'] == $options['section_id'])
{
return $this->ThrowError("400 Bad Request", "SAME_FOLDER_IS_EXISTS", str_replace("#FOLDER#", '"' .$res["NAME"] . '"', GetMessage("WD_FILE_ERROR5")), __LINE__);
}
else
{
return $this->ThrowError("400 Bad Request", "FOLDER_IS_EXISTS", str_replace("#FOLDER#", '"' .$res["NAME"] . '"', GetMessage("WD_FILE_ERROR5")), __LINE__);
}
}
}
}
}
//$this->CheckUniqueName($basename, $section_id, &$res)
//GetFileName()
$arFrom = array();
$arTo = array();
$is_dir = false;
////////////// CHECK FROM
$this->IsDir($options);
$arFrom = $this->arParams;
if($this->arParams["not_found"])
{
return $this->ThrowError("404 Not Found", "DESTINATION_FILE_OR_FOLDER_IS_NOT_FOUND", GetMessage("WD_FILE_ERROR3"), __LINE__);
}
elseif($this->arParams["is_dir"] === true)
{
$is_dir = true;
if ($_SERVER['REQUEST_METHOD'] == "MOVE" && ($options["depth"] != "infinity"))
{
return "400 Bad request";
}
elseif($this->check_creator)
{
return $this->ThrowAccessDenied("USER_IS_NOT_CREATOR", __LINE__);
}
elseif(empty($options["path"]))
{
$options["path"] = $this->_get_path($arFrom["item_id"], false);
}
$res = $this->_udecode($options["dest_url"]);
$res2 = str_replace("//", "/", $res."/"); $res1 = str_replace("//", "/", $options["path"]."/");
if ($res1 === $res2)
{
return "204 No Content";
}
elseif (
mb_strtolower(mb_substr($res2, 0, mb_strlen($res1))) == mb_strtolower($res1)
&& (mb_strlen($res1) != mb_strlen($res2)) // is not the same dir rename
)
{
return $this->ThrowError("400 Bad Request", "SECTION_IS_NOT_UPDATED", GetMessage("WD_FILE_ERROR100"), __LINE__);
}
}
else
{ // found and is_file
}
if(!empty($arFrom['parent_id']))
{
list($contextType, $contextEntityId) = $this->getContextData();
$sectionData = $this->getSectionDataForLinkAnalyze($arFrom['parent_id']);
if(CWebDavSymlinkHelper::isLink($contextType, $contextEntityId, $sectionData))
{
$arFrom['is_symlink'] = true;
$arFrom['symlink_section_data'] = $sectionData;
$arFrom['symlink_section_data_link'] = CWebDavSymlinkHelper::getLinkData($contextType, $contextEntityId, $sectionData);
}
}
////////////// CHECK TO
$arToParams = array("path" => $options['dest_url']);
if (mb_strpos($options['dest_url'], '.Trash') !== false)
{
$arToParams['check_permissions'] = false;
}
$this->IsDir($arToParams);
$arTo = $this->arParams;
if(!empty($arTo['parent_id']))
{
list($contextType, $contextEntityId) = $this->getContextData();
$sectionData = $this->getSectionDataForLinkAnalyze($arTo['parent_id']);
if(CWebDavSymlinkHelper::isLink($contextType, $contextEntityId, $sectionData))
{
$arTo['is_symlink'] = true;
$arTo['symlink_section_data'] = $sectionData;
$arTo['symlink_section_data_link'] = CWebDavSymlinkHelper::getLinkData($contextType, $contextEntityId, $sectionData);
}
}
if($this->arParams["not_found"] == true)
{
if (
$this->e_rights
&& (mb_strpos($options['dest_url'], '.Trash') === false)
&& !$this->CheckWebRights(
"COPY",
array(
'action' => ($drop?'move':'copy'),
'from' => array($arFrom),
'to' => array($arTo)
),
false
)
)
{
return $this->ThrowAccessDenied(__LINE__);
}
//$arTo = false;
}
elseif (
$arFrom["is_dir"] === true
&& $arTo["is_file"] === true
|| $arFrom["is_file"] === true
&& $arTo["is_dir"] === true
)
{
return $this->ThrowError("400 Bad Request", "FOLDER_IS_EXISTS", str_replace("#FOLDER#", $this->arParams["item_id"], GetMessage("WD_FILE_ERROR5")), __LINE__);
}
elseif (
!$this->CheckWebRights(
"COPY",
array(
'action' => ($drop?'move':'copy'),
'from' => array($arFrom),
'to' => array($arTo)
),
false)
)
{
return $this->ThrowAccessDenied(__LINE__);
}
elseif(($arFrom["item_id"] == $arTo["item_id"]) && ($arFrom['basename'] == $arTo['basename']))
{
// else - trying to change case in name
return "204 No Content";
}
elseif($arFrom["element_array"]["WF_PARENT_ELEMENT_ID"] > 0)
{
unset($arTo["item_id"]);
}
elseif(isset($options['rename']) && $options['rename'] === true)
{
// fix fast delete to trash from different folders with the same file name
$nameSuffix = 1;
do
{
$tmpName = $options["dest_url"]." (". $nameSuffix++ .")";
$this->IsDir(array("path" => $tmpName));
$arTo = $this->arParams;
} while ($arTo["not_found"] !== true);
$options['dest_url'] = $tmpName;
}
elseif(!$options["overwrite"])
{
return $this->ThrowError('412 Precondition failed', "FILE_OR_FOLDER_ALREADY_EXISTS", GetMessage("WD_FILE_ERROR4"), __LINE__);
}
elseif(!$this->CheckName($arTo["basename"]))
{
return $this->ThrowError("400 bad request", "BAD_NAME", GetMessage("WD_FILE_ERROR101"), __LINE__);
}
elseif(
$arTo["is_file"]
&& $this->check_creator
&& $arTo["element_array"]["CREATED_BY"] != $GLOBALS["USER"]->GetID()
)
{
return $this->ThrowAccessDenied("USER_IS_NOT_CREATOR", __LINE__);
}
if(
($this->workflow == 'workflow')
&& $arFrom["is_file"]
&& (! CWorkflow::IsAdmin())
&& (! $GLOBALS['USER']->CanDoOperation('webdav_change_settings'))
)
{
$bNeedCheckWfRights = false;
if ($this->e_rights)
{
$arToParent = $this->GetObject(array('section_id' => $arTo['parent_id']));
if ($arToParent['is_dir'])
{
$bNeedCheckWfRights = ! $this->GetPermission('SECTION', $arToParent['item_id'], 'element_edit_any_wf_status');
}
}
else
{
$bNeedCheckWfRights = ($this->permission < 'W');
}
if (
$bNeedCheckWfRights
&& (CIBlockElement::WF_GetStatusPermission($arFrom["element_array"]["WF_STATUS_ID"]) != 2)
)
{
return $this->ThrowError("400 bad request", "BAD_WF_RIGHTS", GetMessage("WD_FILE_ERROR110"), __LINE__);
}
}
if ($arTo['parent_id'] == $this->GetMetaID('TRASH'))
{
$arCheckTrashElement = $arFrom[($arFrom['is_dir']?'dir_array':'element_array')];
if ( $this->_parse_webdav_info($arCheckTrashElement) && (! isset($arCheckTrashElement['PROPS']['BX:']['UNDELETE'])))
{
return $this->ThrowAccessDenied("BAD_NAME", __LINE__);
}
}
if ($arFrom["is_file"])
{
$el = new CIBlockElement();
if (
$arTo["item_id"]
&& ($arTo['item_id'] !== $arFrom['item_id']) // rename
)
{
$this->_ib_elm_delete($arTo['item_id']); // TODO: need to check permissions ?
}
//drop == true if this action is @move@
//is file
if ($drop)
{
$actionRename = $arFrom['parent_id'] == $arTo['parent_id'];
$arFields = array(
"NAME" => $arTo["basename"],
"MODIFIED_BY" => $GLOBALS['USER']->GetID(),
"IBLOCK_SECTION_ID" => $arTo["parent_id"]);
$this->_onEvent(
(($arFrom['parent_id'] != $arTo['parent_id'])?'Move':'Rename'),
$arFrom['element_id'],
'FILE',
array( 'TO' => ( ($arFrom['parent_id'] != $arTo['parent_id']) ? $arTo["parent_id"] : $arTo["basename"] ))
);
//from symlink move. Not rename!!!!
if(!$actionRename && (!empty($arFrom['is_symlink']) || !empty($arTo['is_symlink'])))
{
$targetIblockId = $this->IBLOCK_ID;
if(!empty($arTo['is_symlink']))
{
$targetIblockId = $arTo['symlink_section_data']['IBLOCK_ID'];
}
//move and don't delete item
if(self::_move_from_iblock_to_iblock($arFrom['item_id'], $targetIblockId, $arTo['parent_id'], false, true))
{
$statusSymlinkDelete = $this->DELETE(array("element_id" => $arFrom['item_id']));
}
}
else
{
if ($this->workflow == 'workflow')
{
if ($arTo["parent_id"] != $arFrom["parent_id"])
{
$arFields["WF_COMMENTS"] = GetMessage("WD_FILE_IS_MOVED");
$el->SetElementSection($arFrom["item_id"], $arTo["parent_id"]); // TODO: need to check permissions ???
}
else
{
$arFields["WF_COMMENTS"] = GetMessage("WD_FILE_IS_RENAMED");
}
if ($arTo["parent_id"] != $arFrom["parent_id"] && $arTo["basename"] != $arFrom["element_name"])
$arFields["WF_COMMENTS"] = GetMessage("WD_FILE_IS_MOVED_AND_RENAMED");
}
if ($this->workflow == 'bizproc' || $this->workflow == 'bizproc_limited')
{
$this->AddDocumentToHistory($arFrom['item_id'], $arFrom['element_name']);
}
$el->Update($arFrom["item_id"], $arFields, $this->workflow == 'workflow', true, false, false); // TODO: need to check permissions ???
$arCacheCleanID[] = 'element'.$arFrom["item_id"];
if ($this->workflow == 'bizproc' || $this->workflow == 'bizproc_limited')
{
$db_res2 = CIBlockElement::GetList(array(), array("WF_PARENT_ELEMENT_ID" => $arFrom["item_id"], "SHOW_HISTORY" => "Y"), false, false, array("ID"));
if ($db_res2 && $res2 = $db_res2->Fetch())
{
do
{
$res = $el->Update($res2["ID"], array("IBLOCK_SECTION_ID" => $arFields["IBLOCK_SECTION_ID"]), false, true, false, false);
$arCacheCleanID[] = 'element'.$res2["ID"];
} while ($res2 = $db_res2->Fetch());
}
}
}
}
else
{
//from symlink copy
if(!empty($arFrom['is_symlink']) || !empty($arTo['is_symlink']))
{
$targetIblockId = $this->IBLOCK_ID;
if(!empty($arTo['is_symlink']))
{
$targetIblockId = $arTo['symlink_section_data']['IBLOCK_ID'];
}
//move and don't delete item
if(!self::_move_from_iblock_to_iblock($arFrom['item_id'], $targetIblockId, $arTo['parent_id'], false, true))
{
return '403 Forbidden';
}
}
else
{
$options = array(
'path' => $options["dest_url"],
'content_length' => $arFrom["file_array"]['FILE_SIZE'],
'content_type' => $arFrom["file_array"]['CONTENT_TYPE']);
$stat = $this->PUT($options);
if ($stat === false)
{
return '403 Forbidden';
}
elseif (is_resource($stat) && get_resource_type($stat) == 'stream')
{
fclose($stat);
$arTmpFile = CFile::MakeFileArray($arFrom['element_array']['PROPERTY_FILE_VALUE']); // since CopyDirFiles doesn't support clouds
if (!(is_array($arTmpFile) && is_set($arTmpFile, 'tmp_name')))
return false;
CopyDirFiles($arTmpFile['tmp_name'], $options["TMP_FILE"]);
clearstatcache();
$options['USER_FIELDS'] = $this->GetUfFieldsSimpleArray($arFrom['item_id']);
if (!$this->put_commit($options))
{
return $this->ThrowError('409 Conflict', "BAD_BP_PERMISSIONS", GetMessage("WD_FILE_ERROR110"), __LINE__);
}
}
}
}
$this->_onEvent(
(($arFrom['parent_id'] != $arTo['parent_id'])?'Move':'Rename').'Finished',
$arFrom['element_id'],
'FILE'
);
}
else
{
$se = new CIBlockSection();
$actionRename = $arFrom['parent_id'] == $arTo['parent_id'];
$actionWithSymlink = !empty($arFrom['is_symlink']) || !empty($arTo['is_symlink']);
$actionMoveInSymlink = false;
if($actionWithSymlink)
{
$actionMoveInSymlink = $arFrom['symlink_section_data_link'] == $arTo['symlink_section_data_link'];
}
//drop == true if this action is @move@
//not symlink and move! but if action rename in symlink - run this code block
if (!$actionWithSymlink && $drop || $actionWithSymlink && $actionRename || $actionMoveInSymlink)
{
$this->_onEvent(
(($arFrom['parent_id'] != $arTo['parent_id'])?'Move':'Rename'),
$arFrom['item_id'],
'FOLDER',
array('TO' => ( ($arFrom['parent_id'] != $arTo['parent_id']) ? $arTo["parent_id"] : $arTo["basename"]) )
);
$GLOBALS['DB']->StartTransaction();
if (
isset($options['overwrite'])
&& ($arTo['is_dir'] === true)
&& ($arTo['item_id'] !== $arFrom['item_id']) // rename
)
{
$se->Delete($arTo['item_id']);
}
$result = $se->Update($arFrom["item_id"], array("NAME" => $arTo["basename"], "IBLOCK_SECTION_ID" => $arTo["parent_id"])); // TODO: need to check permissions ???
if ($result == false)
{
$GLOBALS['DB']->Rollback();
return $this->ThrowError("409 Conflict", "SECTION_IS_NOT_UPDATED", ($se->LAST_ERROR ? $se->LAST_ERROR : GetMessage("WD_FILE_ERROR102")), __LINE__);
}
else
{
$arCacheCleanID[] = 'section'.$arFrom["item_id"];
$this->ClearCache("section");
$GLOBALS['DB']->Commit();
}
}
else
{
if (isset($options['overwrite']) && ($arTo['is_dir'] === true))
$se->Delete($arTo['item_id']);
if ($arTo["item_id"] === false)
{
$arPath = explode("/", $options["dest_url"]);
$this->IsDir(array('path' => "/".implode("/", array_slice($arPath, 0, -1))));
if ($this->arParams["not_found"] === false)
{
if ($this->arParams["item_id"] == 0) // root
$arTo["dir_array"] = array("LEFT_MARGIN" => 0, "RIGHT_MARGIN" => $this->INT_MAX);
if (($arTo["dir_array"]["LEFT_MARGIN"] - 1) < $arFrom["dir_array"]["LEFT_MARGIN"] &&
$arFrom["dir_array"]["RIGHT_MARGIN"] < ($arTo["dir_array"]["RIGHT_MARGIN"] + 1))
{
// If folder moved to upper folder
}
elseif (
$arTo["dir_array"]["RIGHT_MARGIN"] < $arFrom["dir_array"]["LEFT_MARGIN"] ||
$arFrom["dir_array"]["RIGHT_MARGIN"] < $arTo["dir_array"]["LEFT_MARGIN"])
{
// if folder moved to neighbourhood folder
}
elseif (
(
(($arFrom["dir_array"]["LEFT_MARGIN"] - 1) <= $arTo["dir_array"]["LEFT_MARGIN"])
&&
($arTo["dir_array"]["RIGHT_MARGIN"] <= ($arFrom["dir_array"]["RIGHT_MARGIN"] + 1))
)
||
(
$arTo["dir_array"]["ID"] == $arFrom["dir_array"]["ID"]
)
)
{
return $this->ThrowError( "400 Bad Request", "SECTION_IS_NOT_UPDATED", GetMessage("WD_FILE_ERROR100"), __LINE__);
}
$pathBasename = array_slice($arPath, -1, 1);
if(!empty($arTo['is_symlink']))
{
$parentSectionId = $this->arParams["item_id"];
if($this->arParams["item_id"] == $arTo['symlink_section_data_link']['ID'])
{
$parentSectionId = $arTo['symlink_section_data_link'][self::UF_LINK_SECTION_ID];
}
$arTo["dir_array"]["ID"] = $se->Add(array(
"IBLOCK_ID" => $arTo['symlink_section_data']['IBLOCK_ID'],
"IBLOCK_SECTION_ID" => $parentSectionId,
"NAME" => end($pathBasename)
));
$arTo["dir_array"]['IBLOCK_ID'] = $arTo['symlink_section_data']['IBLOCK_ID'];
}
else
{
$arTo["dir_array"]["ID"] = $se->Add(array(
"IBLOCK_ID" => $this->IBLOCK_ID,
"IBLOCK_SECTION_ID" => $this->arParams["item_id"],
"NAME" => end($pathBasename)
));
}
if ($arTo["dir_array"]["ID"] === false)
{
return $this->ThrowError("409 Conflict", "FOLDER_IS_NOT_MOVED", str_replace(array(
"#FOLDER#",
"#TEXT_ERROR#"
), array(
"/" . implode("/", $arPath),
$se->LAST_ERROR
), GetMessage("WD_FILE_ERROR103")), __LINE__);
}
else
{
$returnSection = $arTo["dir_array"]["ID"];
$this->_onEvent('Add', $returnSection, 'FOLDER');
}
}
}
else
{
return $this->ThrowError( "409 Conflict", "FOLDER_IS_NOT_MOVED", str_replace(
array("#FOLDER#", "#TEXT_ERROR#"),
array($options["dest_url"], $se->LAST_ERROR), GetMessage("WD_FILE_ERROR103")), __LINE__);
}
$arFrom["dir_array"]['is_symlink'] = !empty($arFrom['is_symlink']);
$arFrom["dir_array"]['symlink_section_data'] = empty($arFrom['symlink_section_data'])? array() : $arFrom['symlink_section_data'];
$arTo["dir_array"]['is_symlink'] = !empty($arTo['is_symlink']);
$arTo["dir_array"]['symlink_section_data'] = empty($arTo['symlink_section_data'])? array() : $arTo['symlink_section_data'];
$result = $this->copy_commit($arFrom["dir_array"], $arTo["dir_array"], $options, $drop);
if ($result === true && $drop === true)
{
if($actionWithSymlink)
{
$this::$lastActionMoveWithSymlink = true;
$this->DELETE(array("section_id" => $arFrom["item_id"]));
}
else
{
CIBlockSection::Delete($arFrom["item_id"]);
}
$this->ClearCache("section");
}
elseif (is_string($result) && mb_strpos($result, "403") !== false)
return $this->ThrowAccessDenied(__LINE__);
}
if ($result !== true)
return $result;
}
if($arFrom['element_id'])
{
CWebDavDiskDispatcher::sendEventToOwners($arFrom['element_array'], null, 'copy');
}
elseif($arFrom['is_dir'])
{
CWebDavDiskDispatcher::sendEventToOwners(null, $arFrom['dir_array'], 'copy');
}
$this->ClearCache($arCacheCleanID, 'local');
if (isset($returnSection))
{
$this->arParams["changed_section_id"] = $returnSection;
}
if($statusSymlinkDelete !== false)
{
return $statusSymlinkDelete;
}
return ($arTo["not_found"]) ? "201 Created" : "204 No Content";
}