PageRenderTime 911ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/access.ftp/class.ftpAccessDriver.php

https://github.com/drucko/AjaXplorer
PHP | 300 lines | 239 code | 18 blank | 43 comment | 46 complexity | 7dfd89fd67287e5a8863265d62290199 MD5 | raw file
Possible License(s): LGPL-2.0, BSD-3-Clause, BSD-2-Clause, Apache-2.0, LGPL-2.1, LGPL-3.0
  1. <?php
  2. /**
  3. * @package info.ajaxplorer.plugins
  4. *
  5. * Copyright 2007-2009 Charles du Jeu
  6. * This file is part of AjaXplorer.
  7. * The latest code can be found at http://www.ajaxplorer.info/
  8. *
  9. * This program is published under the LGPL Gnu Lesser General Public License.
  10. * You should have received a copy of the license along with AjaXplorer.
  11. *
  12. * The main conditions are as follow :
  13. * You must conspicuously and appropriately publish on each copy distributed
  14. * an appropriate copyright notice and disclaimer of warranty and keep intact
  15. * all the notices that refer to this License and to the absence of any warranty;
  16. * and give any other recipients of the Program a copy of the GNU Lesser General
  17. * Public License along with the Program.
  18. *
  19. * If you modify your copy or copies of the library or any portion of it, you may
  20. * distribute the resulting library provided you do so under the GNU Lesser
  21. * General Public License. However, programs that link to the library may be
  22. * licensed under terms of your choice, so long as the library itself can be changed.
  23. * Any translation of the GNU Lesser General Public License must be accompanied by the
  24. * GNU Lesser General Public License.
  25. *
  26. * If you copy or distribute the program, you must accompany it with the complete
  27. * corresponding machine-readable source code or with a written offer, valid for at
  28. * least three years, to furnish the complete corresponding machine-readable source code.
  29. *
  30. * Any of the above conditions can be waived if you get permission from the copyright holder.
  31. * AjaXplorer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  32. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  33. *
  34. * Description : FTP access
  35. */
  36. defined('AJXP_EXEC') or die( 'Access not allowed');
  37. class ftpAccessDriver extends fsAccessDriver {
  38. public function loadManifest(){
  39. parent::loadManifest();
  40. // BACKWARD COMPATIBILITY!
  41. $res = $this->xPath->query('//param[@name="USER"] | //param[@name="PASS"] | //user_param[@name="USER"] | //user_param[@name="PASS"]');
  42. foreach($res as $node){
  43. if($node->getAttribute("name") == "USER"){
  44. $node->setAttribute("name", "FTP_USER");
  45. }else if($node->getAttribute("name") == "PASS"){
  46. $node->setAttribute("name", "FTP_PASS");
  47. }
  48. }
  49. $this->reloadXPath();
  50. }
  51. /**
  52. * Parse
  53. * @param DOMNode $contribNode
  54. */
  55. protected function parseSpecificContributions(&$contribNode){
  56. parent::parseSpecificContributions($contribNode);
  57. if($contribNode->nodeName != "actions") return ;
  58. $this->disableArchiveBrowsingContributions($contribNode);
  59. }
  60. function initRepository(){
  61. if(is_array($this->pluginConf)){
  62. $this->driverConf = $this->pluginConf;
  63. }else{
  64. $this->driverConf = array();
  65. }
  66. $create = $this->repository->getOption("CREATE");
  67. $wrapperData = $this->detectStreamWrapper(true);
  68. $this->wrapperClassName = $wrapperData["classname"];
  69. $this->urlBase = $wrapperData["protocol"]."://".$this->repository->getId();
  70. $recycle = $this->repository->getOption("RECYCLE_BIN");
  71. if($recycle != ""){
  72. RecycleBinManager::init($this->urlBase, "/".$recycle);
  73. }
  74. }
  75. function uploadActions($action, $httpVars, $filesVars){
  76. switch ($action){
  77. case "trigger_remote_copy":
  78. if(!$this->hasFilesToCopy()) break;
  79. $toCopy = $this->getFileNameToCopy();
  80. AJXP_XMLWriter::header();
  81. AJXP_XMLWriter::triggerBgAction("next_to_remote", array(), "Copying file ".$toCopy." to ftp server");
  82. AJXP_XMLWriter::close();
  83. exit(1);
  84. break;
  85. case "next_to_remote":
  86. if(!$this->hasFilesToCopy()) break;
  87. $fData = $this->getNextFileToCopy();
  88. $nextFile = '';
  89. if($this->hasFilesToCopy()){
  90. $nextFile = $this->getFileNameToCopy();
  91. }
  92. AJXP_Logger::debug("Base64 : ", array("from"=>$fData["destination"], "to"=>base64_decode($fData['destination'])));
  93. $destPath = $this->urlBase.base64_decode($fData['destination'])."/".$fData['name'];
  94. //$destPath = AJXP_Utils::decodeSecureMagic($destPath);
  95. // DO NOT "SANITIZE", THE URL IS ALREADY IN THE FORM ajxp.ftp://repoId/filename
  96. $destPath = SystemTextEncoding::fromPostedFileName($destPath);
  97. AJXP_Logger::debug("Copying file to server", array("from"=>$fData["tmp_name"], "to"=>$destPath, "name"=>$fData["name"]));
  98. try {
  99. $fp = fopen($destPath, "w");
  100. $fSource = fopen($fData["tmp_name"], "r");
  101. while(!feof($fSource)){
  102. fwrite($fp, fread($fSource, 4096));
  103. }
  104. fclose($fSource);
  105. AJXP_Logger::debug("Closing target : begin ftp copy");
  106. // Make sur the script does not time out!
  107. @set_time_limit(240);
  108. fclose($fp);
  109. AJXP_Logger::debug("FTP Upload : end of ftp copy");
  110. @unlink($fData["tmp_name"]);
  111. }catch (Exception $e){
  112. AJXP_Logger::debug("Error during ftp copy", array($e->getMessage(), $e->getTrace()));
  113. }
  114. AJXP_Logger::debug("FTP Upload : shoud trigger next or reload nextFile=$nextFile");
  115. AJXP_XMLWriter::header();
  116. if($nextFile!=''){
  117. AJXP_XMLWriter::triggerBgAction("next_to_remote", array(), "Copying file ".$nextFile." to remote server");
  118. }else{
  119. AJXP_XMLWriter::triggerBgAction("reload_node", array(), "Upload done, reloading client.");
  120. }
  121. AJXP_XMLWriter::close();
  122. exit(1);
  123. break;
  124. case "upload":
  125. $rep_source = AJXP_Utils::securePath("/".$httpVars['dir']);
  126. AJXP_Logger::debug("Upload : rep_source ", array($rep_source));
  127. $logMessage = "";
  128. foreach ($filesVars as $boxName => $boxData)
  129. {
  130. if(substr($boxName, 0, 9) != "userfile_") continue;
  131. AJXP_Logger::debug("Upload : rep_source ", array($rep_source));
  132. $err = AJXP_Utils::parseFileDataErrors($boxData, $fancyLoader);
  133. if($err != null)
  134. {
  135. $errorCode = $err[0];
  136. $errorMessage = $err[1];
  137. break;
  138. }
  139. $boxData["destination"] = base64_encode($rep_source);
  140. $destCopy = AJXP_XMLWriter::replaceAjxpXmlKeywords($this->repository->getOption("TMP_UPLOAD"));
  141. AJXP_Logger::debug("Upload : tmp upload folder", array($destCopy));
  142. if(!is_dir($destCopy)){
  143. if(! @mkdir($destCopy)){
  144. AJXP_Logger::debug("Upload error : cannot create temporary folder", array($destCopy));
  145. $errorCode = 413;
  146. $errorMessage = "Warning, cannot create folder for temporary copy.";
  147. break;
  148. }
  149. }
  150. if(!$this->isWriteable($destCopy)){
  151. AJXP_Logger::debug("Upload error: cannot write into temporary folder");
  152. $errorCode = 414;
  153. $errorMessage = "Warning, cannot write into temporary folder.";
  154. break;
  155. }
  156. AJXP_Logger::debug("Upload : tmp upload folder", array($destCopy));
  157. if(isSet($boxData["input_upload"])){
  158. try{
  159. $destName .= tempnam($destCopy, "");
  160. AJXP_Logger::debug("Begining reading INPUT stream");
  161. $input = fopen("php://input", "r");
  162. $output = fopen($destName, "w");
  163. $sizeRead = 0;
  164. while($sizeRead < intval($boxData["size"])){
  165. $chunk = fread($input, 4096);
  166. $sizeRead += strlen($chunk);
  167. fwrite($output, $chunk, strlen($chunk));
  168. }
  169. fclose($input);
  170. fclose($output);
  171. $boxData["tmp_name"] = $destName;
  172. $this->storeFileToCopy($boxData);
  173. AJXP_Logger::debug("End reading INPUT stream");
  174. }catch (Exception $e){
  175. $errorCode=411;
  176. $errorMessage = $e->getMessage();
  177. break;
  178. }
  179. }else{
  180. $destName = $destCopy."/".basename($boxData["tmp_name"]);
  181. if ($destName == $boxData["tmp_name"]) $destName .= "1";
  182. if(move_uploaded_file($boxData["tmp_name"], $destName)){
  183. $boxData["tmp_name"] = $destName;
  184. $this->storeFileToCopy($boxData);
  185. }else{
  186. $mess = ConfService::getMessages();
  187. $errorCode = 411;
  188. $errorMessage="$mess[33] ".$boxData["name"];
  189. break;
  190. }
  191. }
  192. }
  193. if(isSet($errorMessage)){
  194. AJXP_Logger::debug("Return error $errorCode $errorMessage");
  195. return array("ERROR" => array("CODE" => $errorCode, "MESSAGE" => $errorMessage));
  196. }else{
  197. AJXP_Logger::debug("Return success");
  198. return array("SUCCESS" => true);
  199. }
  200. break;
  201. default:
  202. break;
  203. }
  204. session_write_close();
  205. exit;
  206. }
  207. public function isWriteable($path, $type="dir"){
  208. $parts = parse_url($path);
  209. $dir = $parts["path"];
  210. if($type == "dir" && ($dir == "" || $dir == "/" || $dir == "\\")){ // ROOT, WE ARE NOT SURE TO BE ABLE TO READ THE PARENT
  211. return true;
  212. }else{
  213. return is_writable($path);
  214. }
  215. }
  216. function deldir($location)
  217. {
  218. if(is_dir($location))
  219. {
  220. $dirsToRecurse = array();
  221. $all=opendir($location);
  222. while ($file=readdir($all))
  223. {
  224. if (is_dir("$location/$file") && $file !=".." && $file!=".")
  225. {
  226. $dirsToRecurse[] = "$location/$file";
  227. }
  228. elseif (!is_dir("$location/$file"))
  229. {
  230. if(file_exists("$location/$file")){
  231. unlink("$location/$file");
  232. }
  233. unset($file);
  234. }
  235. }
  236. closedir($all);
  237. foreach ($dirsToRecurse as $recurse){
  238. $this->deldir($recurse);
  239. }
  240. rmdir($location);
  241. }
  242. else
  243. {
  244. if(file_exists("$location")) {
  245. $test = @unlink("$location");
  246. if(!$test) throw new Exception("Cannot delete file ".$location);
  247. }
  248. }
  249. if(basename(dirname($location)) == $this->repository->getOption("RECYCLE_BIN"))
  250. {
  251. // DELETING FROM RECYCLE
  252. RecycleBinManager::deleteFromRecycle($location);
  253. }
  254. }
  255. function storeFileToCopy($fileData){
  256. $user = AuthService::getLoggedUser();
  257. $files = $user->getTemporaryData("tmp_upload");
  258. AJXP_Logger::debug("Saving user temporary data", array($fileData));
  259. $files[] = $fileData;
  260. $user->saveTemporaryData("tmp_upload", $files);
  261. }
  262. function getFileNameToCopy(){
  263. $user = AuthService::getLoggedUser();
  264. $files = $user->getTemporaryData("tmp_upload");
  265. return $files[0]["name"];
  266. }
  267. function getNextFileToCopy(){
  268. if(!$this->hasFilesToCopy()) return "";
  269. $user = AuthService::getLoggedUser();
  270. $files = $user->getTemporaryData("tmp_upload");
  271. $fData = $files[0];
  272. array_shift($files);
  273. $user->saveTemporaryData("tmp_upload", $files);
  274. return $fData;
  275. }
  276. function hasFilesToCopy(){
  277. $user = AuthService::getLoggedUser();
  278. $files = $user->getTemporaryData("tmp_upload");
  279. return (count($files)?true:false);
  280. }
  281. }
  282. ?>