/kernel/private/classes/clusterfilehandlers/dfsbackends/dfs.php

https://github.com/edorfaus/ezpublish · PHP · 342 lines · 184 code · 55 blank · 103 comment · 21 complexity · bab073ea991790ac580fc4f43a07adce MD5 · raw file

  1. <?php
  2. /**
  3. * File containing the eZDFSFileHandlerDFSBackend class.
  4. *
  5. * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved.
  6. * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2
  7. * @version //autogentag//
  8. * @package kernel
  9. */
  10. class eZDFSFileHandlerDFSBackend
  11. {
  12. public function __construct()
  13. {
  14. $mountPointPath = eZINI::instance( 'file.ini' )->variable( 'eZDFSClusteringSettings', 'MountPointPath' );
  15. if ( !$mountPointPath = realpath( $mountPointPath ) )
  16. throw new eZDFSFileHandlerNFSMountPointNotFoundException( $mountPointPath );
  17. if ( !is_writeable( $mountPointPath ) )
  18. throw new eZDFSFileHandlerNFSMountPointNotWriteableException( $mountPointPath );
  19. if ( substr( $mountPointPath, -1 ) != '/' )
  20. $mountPointPath = "$mountPointPath/";
  21. $this->mountPointPath = $mountPointPath;
  22. $this->filePermissionMask = octdec( eZINI::instance()->variable( 'FileSettings', 'StorageFilePermissions' ) );
  23. }
  24. /**
  25. * Creates a copy of $srcFilePath from DFS to $dstFilePath on DFS
  26. *
  27. * @param string $srcFilePath Local source file path
  28. * @param string $dstFilePath Local destination file path
  29. */
  30. public function copyFromDFSToDFS( $srcFilePath, $dstFilePath )
  31. {
  32. $this->accumulatorStart();
  33. $srcFilePath = $this->makeDFSPath( $srcFilePath );
  34. $dstFilePath = $this->makeDFSPath( $dstFilePath );
  35. if ( file_exists( dirname( $dstFilePath ) ) )
  36. {
  37. $ret = copy( $srcFilePath, $dstFilePath );
  38. if ( $ret )
  39. $this->fixPermissions( $dstFilePath );
  40. }
  41. else
  42. {
  43. $ret = $this->createFile( $dstFilePath, file_get_contents( $srcFilePath ), false );
  44. }
  45. $this->accumulatorStop();
  46. return $ret;
  47. }
  48. /**
  49. * Copies the DFS file $srcFilePath to FS
  50. * @param string $srcFilePath Source file path (on DFS)
  51. * @param string $dstFilePath
  52. * Destination file path (on FS). If not specified, $srcFilePath is
  53. * used
  54. * @return bool
  55. */
  56. public function copyFromDFS( $srcFilePath, $dstFilePath = false )
  57. {
  58. $this->accumulatorStart();
  59. if ( $dstFilePath === false )
  60. {
  61. $dstFilePath = $srcFilePath;
  62. }
  63. $srcFilePath = $this->makeDFSPath( $srcFilePath );
  64. if ( file_exists( dirname( $dstFilePath ) ) )
  65. {
  66. $ret = copy( $srcFilePath, $dstFilePath );
  67. if ( $ret )
  68. $this->fixPermissions( $dstFilePath );
  69. }
  70. else
  71. {
  72. $ret = $this->createFile( $dstFilePath, file_get_contents( $srcFilePath ) );
  73. }
  74. $this->accumulatorStop();
  75. return $ret;
  76. }
  77. /**
  78. * Copies the local file $filePath to DFS under the same name, or a new name
  79. * if specified
  80. *
  81. * @param string $srcFilePath Local file path to copy from
  82. * @param bool|string $dstFilePath
  83. * Optional path to copy to. If not specified, $srcFilePath is used
  84. * @return bool
  85. */
  86. public function copyToDFS( $srcFilePath, $dstFilePath = false )
  87. {
  88. $this->accumulatorStart();
  89. $srcFileContents = file_get_contents( $srcFilePath );
  90. if ( $srcFileContents === false )
  91. {
  92. $this->accumulatorStop();
  93. eZDebug::writeError( "Error getting contents of file FS://'$srcFilePath'.", __METHOD__ );
  94. return false;
  95. }
  96. if ( $dstFilePath === false )
  97. {
  98. $dstFilePath = $srcFilePath;
  99. }
  100. $dstFilePath = $this->makeDFSPath( $dstFilePath );
  101. $ret = $this->createFile( $dstFilePath, $srcFileContents, true );
  102. if ( $ret )
  103. {
  104. // Double checking if the file has been correctly created
  105. $srcFileSize = strlen( $srcFileContents );
  106. clearstatcache( true, $dstFilePath );
  107. $dstFileSize = filesize( $dstFilePath );
  108. if ( $dstFileSize != $srcFileSize )
  109. {
  110. eZDebug::writeError( "Size ($dstFileSize) of written data for file FS://$dstFilePath does not match expected size of original DFS file ($srcFileSize)", __METHOD__ );
  111. return false;
  112. }
  113. }
  114. $this->accumulatorStop();
  115. return $ret;
  116. }
  117. /**
  118. * Deletes one or more files from DFS
  119. *
  120. * @param string|array $filePath
  121. * Single local filename, or array of local filenames
  122. * @return bool true if deletion was successful, false otherwise
  123. * @todo Improve error handling using exceptions
  124. */
  125. public function delete( $filePath )
  126. {
  127. $this->accumulatorStart();
  128. if ( is_array( $filePath ) )
  129. {
  130. $ret = true;
  131. foreach( $filePath as $file )
  132. {
  133. $dfsPath = $this->makeDFSPath( $file );
  134. $locRet = @unlink( $dfsPath );
  135. $ret = $ret and $locRet;
  136. if ( $locRet )
  137. eZClusterFileHandler::cleanupEmptyDirectories( $dfsPath );
  138. }
  139. }
  140. else
  141. {
  142. $dfsPath = $this->makeDFSPath( $filePath );
  143. $ret = @unlink( $dfsPath );
  144. if ( $ret )
  145. eZClusterFileHandler::cleanupEmptyDirectories( $dfsPath );
  146. }
  147. $this->accumulatorStop();
  148. return $ret;
  149. }
  150. /**
  151. * Sends the contents of $filePath to default output
  152. *
  153. * @param string $filePath File path
  154. * @param int $startOffset Starting offset
  155. * @param bool|int $length Length to transmit, false means everything
  156. * @return bool true, or false if operation failed
  157. */
  158. public function passthrough( $filePath, $startOffset = 0, $length = false )
  159. {
  160. return eZFile::downloadContent(
  161. $this->makeDFSPath( $filePath ),
  162. $startOffset,
  163. $length
  164. );
  165. }
  166. /**
  167. * Returns the binary content of $filePath from DFS
  168. *
  169. * @param string $filePath local file path
  170. * @return binary|bool file's content, or false
  171. * @todo Handle errors using exceptions
  172. */
  173. public function getContents( $filePath )
  174. {
  175. $this->accumulatorStart();
  176. // @todo Throw an exception if it fails
  177. // (FileNotFound, or FileNotReadable, depends on testing)
  178. $ret = @file_get_contents( $this->makeDFSPath( $filePath ) );
  179. $this->accumulatorStop();
  180. return $ret;
  181. }
  182. /**
  183. * Creates the file $filePath on DFS with content $contents
  184. *
  185. * @param string $filePath
  186. * @param binary $contents
  187. *
  188. * @return bool
  189. */
  190. public function createFileOnDFS( $filePath, $contents )
  191. {
  192. $this->accumulatorStart();
  193. $filePath = $this->makeDFSPath( $filePath );
  194. $ret = $this->createFile( $filePath, $contents, false );
  195. $this->accumulatorStop();
  196. return $ret;
  197. }
  198. /**
  199. * Renamed DFS file $oldPath to DFS file $newPath
  200. *
  201. * @param string $oldPath
  202. * @param string $newPath
  203. * @return bool
  204. */
  205. public function renameOnDFS( $oldPath, $newPath )
  206. {
  207. $this->accumulatorStart();
  208. $oldPath = $this->makeDFSPath( $oldPath );
  209. $newPath = $this->makeDFSPath( $newPath );
  210. $ret = eZFile::rename( $oldPath, $newPath, true );
  211. if ( $ret )
  212. eZClusterFileHandler::cleanupEmptyDirectories( $oldPath );
  213. $this->accumulatorStop();
  214. return $ret;
  215. }
  216. /**
  217. * Checks if a file exists on the DFS
  218. *
  219. * @param string $filePath
  220. * @return bool
  221. */
  222. public function existsOnDFS( $filePath )
  223. {
  224. return file_exists( $this->makeDFSPath( $filePath ) );
  225. }
  226. /**
  227. * Returns the mount point
  228. *
  229. * @return string
  230. */
  231. public function getMountPoint()
  232. {
  233. return $this->mountPointPath;
  234. }
  235. /**
  236. * Computes the DFS file path based on a relative file path
  237. * @param string $filePath
  238. * @return string the absolute DFS file path
  239. */
  240. protected function makeDFSPath( $filePath )
  241. {
  242. return $this->mountPointPath . $filePath;
  243. }
  244. protected function accumulatorStart()
  245. {
  246. eZDebug::accumulatorStart( 'mysql_cluster_dfs_operations', 'MySQL Cluster', 'DFS operations' );
  247. }
  248. protected function accumulatorStop()
  249. {
  250. eZDebug::accumulatorStop( 'mysql_cluster_dfs_operations' );
  251. }
  252. protected function fixPermissions( $filePath )
  253. {
  254. chmod( $filePath, $this->filePermissionMask );
  255. }
  256. protected function createFile( $filePath, $contents, $atomic = true )
  257. {
  258. // $contents can result from a failed file_get_contents(). In this case
  259. if ( $contents === false )
  260. return false;
  261. $createResult = eZFile::create( basename( $filePath ), dirname( $filePath ), $contents, $atomic );
  262. if ( $createResult )
  263. $this->fixPermissions( $filePath );
  264. return $createResult;
  265. }
  266. /**
  267. * Returns size of a file in the DFS backend, from a relative path.
  268. *
  269. * @param string $filePath The relative file path we want to get size of
  270. * @return int
  271. */
  272. public function getDfsFileSize( $filePath )
  273. {
  274. return filesize( $this->makeDFSPath( $filePath ) );
  275. }
  276. /**
  277. * Path to the local distributed filesystem mount point
  278. * @var string
  279. */
  280. protected $mountPointPath;
  281. /**
  282. * Permission mask that must be applied to created files
  283. * @var int
  284. */
  285. private $filePermissionMask;
  286. }
  287. ?>