PageRenderTime 65ms CodeModel.GetById 38ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/ezfile/classes/ezfile.php

https://github.com/eeggenberger/ezpublish
PHP | 315 lines | 167 code | 29 blank | 119 comment | 31 complexity | 928ed95dcb5d760c2bc4e775ae406538 MD5 | raw file
  1. <?php
  2. /**
  3. * File containing the eZFile class.
  4. *
  5. * @copyright Copyright (C) 1999-2011 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 lib
  9. */
  10. /*!
  11. \class eZFile ezfile.php
  12. \ingroup eZUtils
  13. \brief Tool class which has convencience functions for files and directories
  14. */
  15. class eZFile
  16. {
  17. /**
  18. * Number of bytes read per fread() operation.
  19. *
  20. * @see downloadContent()
  21. */
  22. const READ_PACKET_SIZE = 16384;
  23. /**
  24. * Reads the whole contents of the file \a $file and
  25. * splits it into lines which is collected into an array and returned.
  26. * It will handle Unix (\n), Windows (\r\n) and Mac (\r) style newlines.
  27. * \note The newline character(s) are not present in the line string.
  28. *
  29. * @deprecated Since 4.4, use file( $file, FILE_IGNORE_NEW_LINES ) instead.
  30. * @return array|false
  31. */
  32. static function splitLines( $file )
  33. {
  34. $contents = file_get_contents( $file );
  35. if ( $contents === false )
  36. return false;
  37. $lines = preg_split( "#\r\n|\r|\n#", $contents );
  38. unset( $contents );
  39. return $lines;
  40. }
  41. /*!
  42. Creates a file called \a $filename.
  43. If \a $directory is specified the file is placed there, the directory will also be created if missing.
  44. if \a $data is specified the file will created with the content of this variable.
  45. \param $atomic If true the file contents will be written to a temporary file and renamed to the correct file.
  46. */
  47. static function create( $filename, $directory = false, $data = false, $atomic = false )
  48. {
  49. $filepath = $filename;
  50. if ( $directory )
  51. {
  52. if ( !file_exists( $directory ) )
  53. {
  54. eZDir::mkdir( $directory, false, true );
  55. // eZDebugSetting::writeNotice( 'ezfile-create', "Created directory $directory", 'eZFile::create' );
  56. }
  57. $filepath = $directory . '/' . $filename;
  58. }
  59. // If atomic creation is needed we will use a temporary
  60. // file when writing the data, then rename it to the correct path.
  61. if ( $atomic )
  62. {
  63. $realpath = $filepath;
  64. $dirname = dirname( $filepath );
  65. if ( strlen( $dirname ) != 0 )
  66. $dirname .= "/";
  67. $filepath = $dirname . "ezfile-tmp." . md5( $filepath . getmypid() . mt_rand() );
  68. }
  69. $file = fopen( $filepath, 'wb' );
  70. if ( $file )
  71. {
  72. // eZDebugSetting::writeNotice( 'ezfile-create', "Created file $filepath", 'eZFile::create' );
  73. if ( $data )
  74. fwrite( $file, $data );
  75. fclose( $file );
  76. if ( $atomic )
  77. {
  78. if ( !eZFile::rename( $filepath, $realpath ) )
  79. {
  80. // If the renaming process fails, delete the temporary file
  81. unlink( $filepath );
  82. }
  83. }
  84. return true;
  85. }
  86. // eZDebugSetting::writeNotice( 'ezfile-create', "Failed creating file $filepath", 'eZFile::create' );
  87. return false;
  88. }
  89. /*!
  90. \static
  91. Read all content of file.
  92. \param filename
  93. \return file contents, false if error
  94. \deprecated since eZ Publish 4.1, use file_get_contents() instead
  95. */
  96. static function getContents( $filename )
  97. {
  98. eZDebug::writeWarning( __METHOD__ . ' is deprecated, use file_get_contents() instead' );
  99. if ( function_exists( 'file_get_contents' ) )
  100. {
  101. return file_get_contents( $filename );
  102. }
  103. else
  104. {
  105. $fp = fopen( $filename, 'r' );
  106. if ( !$fp )
  107. {
  108. eZDebug::writeError( 'Could not read contents of ' . $filename, __METHOD__ );
  109. return false;
  110. }
  111. return fread( $fp, filesize( $filename ) );
  112. }
  113. }
  114. /*!
  115. \static
  116. Get suffix from filename
  117. \param filename
  118. \return suffix, extends: file/to/readme.txt return txt
  119. */
  120. static function suffix( $filename )
  121. {
  122. $parts = explode( '.', $filename);
  123. return array_pop( $parts );
  124. }
  125. /*!
  126. \static
  127. Check if a given file is writeable
  128. \return TRUE/FALSE
  129. */
  130. static function isWriteable( $filename )
  131. {
  132. if ( eZSys::osType() != 'win32' )
  133. return is_writable( $filename );
  134. /* PHP function is_writable() doesn't work correctly on Windows NT descendants.
  135. * So we have to use the following hack on those OSes.
  136. */
  137. if ( !( $fd = @fopen( $filename, 'a' ) ) )
  138. return FALSE;
  139. fclose( $fd );
  140. return TRUE;
  141. }
  142. /*!
  143. \static
  144. Renames a file atomically on Unix, and provides a workaround for Windows
  145. \param $srcFile from filename
  146. \param $destFile to filename
  147. \param $mkdir make directory for dest file if needed
  148. \return rename status. ( true if successful, false if not )
  149. */
  150. static function rename( $srcFile, $destFile, $mkdir = false )
  151. {
  152. /* On windows we need to unlink the destination file first */
  153. if ( strtolower( substr( PHP_OS, 0, 3 ) ) == 'win' )
  154. {
  155. @unlink( $destFile );
  156. }
  157. if( $mkdir )
  158. {
  159. eZDir::mkdir( dirname( $destFile ), false, true );
  160. }
  161. return rename( $srcFile, $destFile );
  162. }
  163. /**
  164. * Prepares a file for Download and terminates the execution.
  165. * This method will:
  166. * - empty the output buffer
  167. * - stop buffering
  168. * - stop the active session (in order to allow concurrent browsing while downloading)
  169. *
  170. * @param string $file Path to the local file
  171. * @param bool $isAttachedDownload Determines weather to download the file as an attachment ( download popup box ) or not.
  172. * @param string $overrideFilename
  173. * @param int $startOffset Offset to start transfer from, in bytes
  174. * @param int $length Data size to transfer
  175. *
  176. * @return bool false if error
  177. */
  178. static function download( $file, $isAttachedDownload = true, $overrideFilename = false, $startOffset = 0, $length = false )
  179. {
  180. if ( !file_exists( $file ) )
  181. {
  182. return false;
  183. }
  184. ob_end_clean();
  185. eZSession::stop();
  186. self::downloadHeaders( $file, $isAttachedDownload, $overrideFilename, $startOffset, $length );
  187. self::downloadContent( $file, $startOffset, $length );
  188. eZExecution::cleanExit();
  189. }
  190. /**
  191. * Handles the header part of a file transfer to the client
  192. *
  193. * @see download()
  194. *
  195. * @param string $file Path to the local file
  196. * @param bool $isAttachedDownload Determines weather to download the file as an attachment ( download popup box ) or not.
  197. * @param string $overrideFilename Filename to send in headers instead of the actual file's name
  198. * @param int $startOffset Offset to start transfer from, in bytes
  199. * @param int $length Data size to transfer
  200. * @param string $fileSize The file's size. If not given, actual filesize will be queried. Required to work with clusterized files...
  201. */
  202. public static function downloadHeaders( $file, $isAttachedDownload = true, $overrideFilename = false, $startOffset = 0, $length = false, $fileSize = false )
  203. {
  204. if ( $fileSize === false )
  205. {
  206. if ( !file_exists( $file ) )
  207. {
  208. eZDebug::writeError( "\$fileSize not given, and file not found", __METHOD__ );
  209. return false;
  210. }
  211. $fileSize = filesize( $file );
  212. }
  213. header( 'X-Powered-By: eZ Publish' );
  214. header( "Content-Length: $fileSize" );
  215. $mimeinfo = eZMimeType::findByURL( $file );
  216. header( "Content-Type: {$mimeinfo['name']}" );
  217. // Fixes problems with IE when opening a file directly
  218. header( "Pragma: " );
  219. header( "Cache-Control: " );
  220. /* Set cache time out to 10 minutes, this should be good enough to work
  221. around an IE bug */
  222. header( "Expires: ". gmdate( 'D, d M Y H:i:s', time() + 600 ) . ' GMT' );
  223. header(
  224. "Content-Disposition: " .
  225. ( $isAttachedDownload ? 'attachment' : 'inline' ) .
  226. ( $overrideFilename !== false ? "; filename={$overrideFilename}" : '' )
  227. );
  228. // partial download (HTTP 'Range' header)
  229. if ( $startOffset !== 0 )
  230. {
  231. $endOffset = ( $length !== false ) ? ( $length + $startOffset - 1 ) : $fileSize - 1;
  232. header( "Content-Range: bytes {$startOffset}-{$endOffset}/{$fileSize}" );
  233. header( "HTTP/1.1 206 Partial Content" );
  234. }
  235. header( 'Content-Transfer-Encoding: binary' );
  236. header( 'Accept-Ranges: bytes' );
  237. }
  238. /**
  239. * Handles the data part of a file transfer to the client
  240. *
  241. * @see download()
  242. *
  243. * @param string $file Path to the local file
  244. * @param int $startOffset Offset to start transfer from, in bytes
  245. * @param int $length Data size to transfer
  246. */
  247. public static function downloadContent( $file, $startOffset = 0, $length = false )
  248. {
  249. if ( ( $fp = fopen( $file, 'rb' ) ) === false )
  250. {
  251. eZDebug::writeError( "An error occured opening '$file' for reading", __METHOD__ );
  252. return false;
  253. }
  254. $fileSize = filesize( $file );
  255. // an offset has been given: move the pointer to that offset if it seems valid
  256. if ( $startOffset !== false && $startOffset <= $fileSize && fseek( $fp, $startOffset ) === -1 )
  257. {
  258. eZDebug::writeError( "Error while setting offset on '{$file}'", __METHOD__ );
  259. return false;
  260. }
  261. $transferred = $startOffset;
  262. $packetSize = self::READ_PACKET_SIZE;
  263. $endOffset = ( $length === false ) ? $fileSize - 1 : $length + $startOffset - 1;
  264. while ( !feof( $fp ) && $transferred < $endOffset + 1 )
  265. {
  266. if ( $transferred + $packetSize > $endOffset + 1 )
  267. {
  268. $packetSize = $endOffset + 1 - $transferred;
  269. }
  270. echo fread( $fp, $packetSize );
  271. $transferred += $packetSize;
  272. }
  273. fclose( $fp );
  274. return true;
  275. }
  276. }
  277. ?>