PageRenderTime 44ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/titania/includes/library/ezcomponents/Archive/file/file.php

https://github.com/Lurttinen/customisation-db
PHP | 509 lines | 246 code | 61 blank | 202 comment | 53 complexity | ea67f0c29b57203e6d4e91656a6094b2 MD5 | raw file
  1. <?php
  2. /**
  3. * File containing the ezcArchiveFile class.
  4. *
  5. * @package Archive
  6. * @version //autogentag//
  7. * @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved.
  8. * @license http://ez.no/licenses/new_bsd New BSD License
  9. * @access private
  10. */
  11. /**
  12. * The ezcArchiveFile should implement the common interface between the
  13. * ezcArchiveBlockFile and ezcArchiveCharacterFile.
  14. *
  15. * @package Archive
  16. * @version //autogentag//
  17. * @access private
  18. */
  19. abstract class ezcArchiveFile implements Iterator
  20. {
  21. /**
  22. * The file is read-only.
  23. * The file permissions can be set to read-only or file is compressed with a
  24. * stream that can only be read. E.g. bzip2.
  25. */
  26. const READ_ONLY = 1;
  27. /**
  28. * The file is write-only.
  29. * The file permissions can be set to write-only or file should be compressed with a
  30. * stream that can only write. E.g. bzip2.
  31. */
  32. const WRITE_ONLY = 2;
  33. /**
  34. * The file is either read or append mode.
  35. * Some compressed streams (zlib) do not support reading and writing. But seperate reading
  36. * and appending does work.
  37. */
  38. const READ_APPEND = 3;
  39. /**
  40. * The file is opened in a read and write mode.
  41. */
  42. const READ_WRITE = 4;
  43. /**
  44. * The mode the file is opened in. It has one of the following constant values:
  45. * READ_ONLY, WRITE_ONLY, READ_APPEND, or READ_WRITE.
  46. *
  47. * @var int
  48. */
  49. protected $fileAccess = null;
  50. /**
  51. * The current resource of the opened file.
  52. * If the file is closed, this resource should point to NULL.
  53. *
  54. * @var resource
  55. */
  56. protected $fp = null;
  57. /**
  58. * The name of the file.
  59. *
  60. * @var string
  61. */
  62. protected $fileName;
  63. /**
  64. * True when the current file does not have any blocks, otherwise false.
  65. *
  66. * @var boolean
  67. */
  68. protected $isEmpty;
  69. /**
  70. * True if the file-pointer supports seeking, otherwise false.
  71. * For example, files that use the bzip2 stream cannot seek.
  72. *
  73. * @var boolean
  74. */
  75. protected $fileMetaData;
  76. /**
  77. * True when the current block is valid, otherwise false.
  78. *
  79. * @var boolean
  80. */
  81. protected $isValid = false;
  82. /**
  83. * Read-mode for the archive file.
  84. */
  85. const SWITCH_READ = 0;
  86. /**
  87. * Append-mode for the archive file.
  88. */
  89. const SWITCH_APPEND = 1;
  90. /**
  91. * Switch for read-mode and append-mode.
  92. *
  93. * @var int
  94. */
  95. protected $readAppendSwitch;
  96. /**
  97. * Is the file new.
  98. *
  99. * @var bool
  100. */
  101. protected $isNew;
  102. /**
  103. * Is the file modified.
  104. *
  105. * @var bool
  106. */
  107. protected $isModified;
  108. /**
  109. * Opens the specified archive.
  110. *
  111. * If $createIfNotExist is true, then the file will be created if it does
  112. * not exist.
  113. *
  114. * @param string $fileName
  115. * @param bool $createIfNotExist
  116. * @param bool $readOnly
  117. * @return bool
  118. */
  119. protected function openFile( $fileName, $createIfNotExist, $readOnly = false )
  120. {
  121. if ( !$readOnly && $createIfNotExist && !self::fileExists( $fileName ) )
  122. {
  123. $this->isNew = true;
  124. $this->isEmpty = true;
  125. if ( !self::touch( $fileName ) )
  126. {
  127. throw new ezcBaseFilePermissionException( self::getPureFileName( $fileName ), ezcBaseFilePermissionException::WRITE );
  128. }
  129. }
  130. else
  131. {
  132. $this->isNew = false;
  133. }
  134. // Try to open it in read and write mode.
  135. $opened = false;
  136. if ( !$readOnly )
  137. {
  138. $this->fp = @fopen( $fileName, "r+b" );
  139. if ( $this->fp )
  140. {
  141. $this->fileAccess = self::READ_WRITE;
  142. $opened = true;
  143. }
  144. }
  145. if ( !$opened )
  146. {
  147. // Try to open it in read-only mode.
  148. $this->fp = @fopen( $fileName, "rb" );
  149. $this->fileAccess = self::READ_ONLY;
  150. // Check if we opened the file.
  151. if ( !$this->fp )
  152. {
  153. if ( !self::fileExists( $fileName ) )
  154. {
  155. throw new ezcBaseFileNotFoundException( $fileName );
  156. }
  157. // Cannot read the file.
  158. throw new ezcBaseFilePermissionException( $fileName, ezcBaseFilePermissionException::READ );
  159. }
  160. }
  161. $this->fileMetaData = stream_get_meta_data( $this->fp );
  162. // Hardcode BZip2 to read-only.
  163. // For some reason we can open the file in read-write mode, but we cannot rewind the fp. Strange..
  164. if ( $this->fileMetaData["wrapper_type"] == "BZip2" )
  165. {
  166. $this->fileAccess = self::READ_ONLY;
  167. }
  168. // Why is it read only?
  169. if ( !$readOnly && $this->fileAccess == self::READ_ONLY )
  170. {
  171. if ( $this->fileMetaData["wrapper_type"] == "ZLIB" || $this->fileMetaData["wrapper_type"] == "BZip2" )
  172. {
  173. // Append mode available?
  174. $b = @fopen( $fileName, "ab" );
  175. if ( $b !== false )
  176. {
  177. // We have also a write-only mode.
  178. fclose( $b );
  179. // The file is either read-only or write-only.
  180. $this->fileAccess = self::READ_APPEND;
  181. $this->readAppendSwitch = self::SWITCH_READ;
  182. }
  183. else
  184. {
  185. // Maybe we should write only to the archive.
  186. // Test this only, when the archive is new.
  187. if ( $this->isNew )
  188. {
  189. $b = @fopen( $fileName, "wb" );
  190. if ( $b !== false )
  191. {
  192. // XXX Clean up.
  193. $this->fp = $b;
  194. $this->isEmpty = true;
  195. $this->fileAccess = self::WRITE_ONLY;
  196. $this->fileName = $fileName;
  197. $this->isModified = false;
  198. return true;
  199. }
  200. }
  201. }
  202. }
  203. }
  204. // Check if the archive is empty.
  205. if ( fgetc( $this->fp ) === false )
  206. {
  207. $this->isEmpty = true;
  208. }
  209. else
  210. {
  211. $this->rewind();
  212. $this->isEmpty = false;
  213. }
  214. $this->fileName = $fileName;
  215. $this->isModified = false;
  216. }
  217. /**
  218. * Returns the file name or file path.
  219. *
  220. * @return string
  221. */
  222. public function getFileName()
  223. {
  224. return $this->fileName;
  225. }
  226. /**
  227. * Switch to write mode.
  228. */
  229. public function switchWriteMode()
  230. {
  231. // Switch only when we are in read (only) mode.
  232. if ( $this->fileAccess == self::READ_APPEND && $this->readAppendSwitch == self::SWITCH_READ )
  233. {
  234. fclose( $this->fp );
  235. $this->fp = @fopen( $this->fileName, "ab" );
  236. if ( $this->fp === false )
  237. {
  238. throw new ezcBaseFilePermissionException( self::getPureFileName( $this->fileName ), ezcBaseFilePermissionException::WRITE, "Cannot switch to write mode" );
  239. }
  240. $this->readAppendSwitch = self::SWITCH_APPEND;
  241. }
  242. }
  243. /**
  244. * Switch to read mode.
  245. *
  246. * @param int $pos Position to seek to; not used
  247. */
  248. public function switchReadMode( $pos = 0 )
  249. {
  250. // Switch only when we are in write (only) mode.
  251. if ( $this->fileAccess == self::READ_APPEND && $this->readAppendSwitch == self::SWITCH_APPEND )
  252. {
  253. fclose( $this->fp );
  254. $this->fp = fopen( $this->fileName, "rb" );
  255. if ( $this->fp === false )
  256. {
  257. throw new ezcBaseFilePermissionException( self::getPureFileName( $this->fileName ), ezcBaseFilePermissionException::READ, "Cannot switch back to read mode" );
  258. }
  259. $this->readAppendSwitch = self::SWITCH_READ;
  260. $this->positionSeek( 0, SEEK_END );
  261. // Doesn't Make sense, Seek-end should be at the end!
  262. while ( fgetc( $this->fp ) !== false );
  263. }
  264. }
  265. /**
  266. * Returns if the file access is in append mode.
  267. *
  268. * @return bool
  269. */
  270. public function isReadOnlyWriteOnlyStream()
  271. {
  272. return $this->fileAccess == self::READ_APPEND;
  273. }
  274. /**
  275. * Touches the specified file (sets the access and modification time).
  276. *
  277. * PHP system touch doesn't work correctly with the compress.zlib file.
  278. *
  279. * @param string $fileName
  280. * @return bool
  281. */
  282. public static function touch( $fileName )
  283. {
  284. return touch( self::getPureFileName( $fileName ) );
  285. }
  286. /**
  287. * Returns if the specified file exists.
  288. *
  289. * @param string $fileName
  290. * @return bool
  291. */
  292. public static function fileExists( $fileName )
  293. {
  294. return file_exists( self::getPureFileName( $fileName ) );
  295. }
  296. /**
  297. * Returns the specified file name without any filters or compression stream.
  298. *
  299. * @param string $fileName
  300. * @return string
  301. */
  302. private static function getPureFileName( $fileName )
  303. {
  304. // TODO: Multistream goes wrong.
  305. if ( strncmp( $fileName, "compress.zlib://", 16 ) == 0 )
  306. {
  307. return substr( $fileName, 16 );
  308. }
  309. if ( strncmp( $fileName, "compress.bzip2://", 17 ) == 0 )
  310. {
  311. return substr( $fileName, 17 );
  312. }
  313. return $fileName;
  314. }
  315. /**
  316. * Rewind the current file, and the current() method will return the
  317. * data from the first block, if available.
  318. */
  319. public function rewind()
  320. {
  321. if ( !is_null( $this->fp ) )
  322. {
  323. $this->isValid = true;
  324. if ( !$this->fileMetaData["seekable"] )
  325. {
  326. fclose( $this->fp );
  327. $this->fp = fopen( $this->fileMetaData["uri"], $this->fileMetaData["mode"] );
  328. }
  329. else
  330. {
  331. rewind( $this->fp );
  332. }
  333. $this->next();
  334. }
  335. else
  336. {
  337. $this->isValid = false;
  338. }
  339. }
  340. /**
  341. * Seeks in the file to/by the specified position.
  342. *
  343. * Ways of seeking ($whence):
  344. * - SEEK_SET - $pos is absolute, seek to that position in the file
  345. * - SEEK_CUR - $pos is relative, seek by $pos bytes from the current position
  346. *
  347. * @throws ezcArchiveException
  348. * if trying to use SEEK_END for $whence
  349. * @param int $pos
  350. * @param int $whence
  351. * @return int If seek was successful or not
  352. */
  353. protected function positionSeek( $pos, $whence = SEEK_SET )
  354. {
  355. // Seek the end of the file in a write only file always succeeds.
  356. if ( $this->fileAccess == self::WRITE_ONLY && $pos == 0 && $whence == SEEK_END )
  357. {
  358. return true;
  359. }
  360. if ( $this->fileMetaData["seekable"] )
  361. {
  362. /**
  363. * Ugh, for some reason fseek starts throwing warnings for
  364. * zlib streams with SEEK_END. And there is no way to know this
  365. * upfront, so we need to use @ here. #fail.
  366. */
  367. return @fseek( $this->fp, $pos, $whence );
  368. }
  369. else
  370. {
  371. switch ( $whence )
  372. {
  373. case SEEK_SET:
  374. $transPos = $pos;
  375. break;
  376. case SEEK_CUR:
  377. $transPos = $pos + ftell( $this->fp );
  378. break;
  379. case SEEK_END:
  380. throw new ezcArchiveException( "SEEK_END in a non-seekable file is not supported (yet)." );
  381. }
  382. $cur = ftell( $this->fp );
  383. if ( $transPos < $cur )
  384. {
  385. fclose( $this->fp );
  386. $this->fp = fopen( $this->fileMetaData["uri"], $this->fileMetaData["mode"] );
  387. $cur = 0;
  388. }
  389. for ( $i = $cur; $i < $transPos; $i++ )
  390. {
  391. $c = fgetc( $this->fp );
  392. if ( $c === false )
  393. {
  394. return -1;
  395. }
  396. }
  397. return 0;
  398. }
  399. }
  400. /**
  401. * Returns the current file access mode.
  402. *
  403. * @var int
  404. */
  405. public function getFileAccess()
  406. {
  407. return $this->fileAccess;
  408. }
  409. /**
  410. * Returns if the file is in read-only mode.
  411. *
  412. * @var bool
  413. */
  414. public function isReadOnly()
  415. {
  416. return $this->fileAccess == self::READ_ONLY;
  417. }
  418. /**
  419. * Returns if the file is new.
  420. *
  421. * @var bool
  422. */
  423. public function isNew()
  424. {
  425. return $this->isNew;
  426. }
  427. /**
  428. * Returns if the file is modified.
  429. *
  430. * @var bool
  431. */
  432. public function isModified()
  433. {
  434. return $this->isModified;
  435. }
  436. /**
  437. * Closes the file.
  438. */
  439. public function close()
  440. {
  441. if ( is_resource( $this->fp ) )
  442. {
  443. fclose( $this->fp );
  444. $this->fp = null;
  445. }
  446. }
  447. }
  448. ?>