/lib/ezfile/classes/ezfilehandler.php

https://bitbucket.org/ericsagnes/ezpublish-multisite · PHP · 1050 lines · 641 code · 67 blank · 342 comment · 93 complexity · 0697173213e0d0d44f19f8ce088cd4cd MD5 · raw file

  1. <?php
  2. /**
  3. * File containing the eZFileHandler 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 2012.8
  8. * @package lib
  9. */
  10. /*!
  11. \class eZFileHandler ezfilehandler.php
  12. \brief Interface for file handlers
  13. Generic interface for all file handlers.
  14. Using this class i divided into five areas, they are:
  15. File handling using open(), close(), read(), write() and flush().
  16. File position handling using seek(), tell(), rewind() and eof().
  17. Quick output of the file using passtrough().
  18. Error handling with error(), errorString() and errorNumber().
  19. \h1 Creating specific handlers
  20. The file handlers must inherit from this class and reimplement
  21. some virtual functions.
  22. For dealing with files the following functions must be reimplemented.
  23. doOpen(), doClose(), doRead(), doWrite() and doFlush().
  24. For dealing with file positions the following functions must be reimplemented.
  25. doSeek(), doTell(), doRewind() and doEOF().
  26. For dealing with quick output the passtrough() function must be reimplemented,
  27. if not reimplemented the default implemententation will simply read n bytes
  28. using read() and output it with print.
  29. Also the errorString() and errorNumber() functions must be reimplemented
  30. to provide proper error handler. The error() function is not required
  31. to be implemented since it has a default implementation, for speed
  32. it might be wise to implement the function.
  33. This class will handle most of the generic logic, like checking that
  34. the filename is correct and if the open succeded, and give error
  35. messages based on this.
  36. The actual implementations will only have to execute the specific
  37. code and return a result.
  38. */
  39. class eZFileHandler
  40. {
  41. /*!
  42. Initializes the handler. Optionally the parameters \a $filename
  43. and \a $mode may be provided to automatically open the file.
  44. */
  45. function eZFileHandler( $handlerIdentifier = false, $handlerName = false )
  46. {
  47. if ( !$handlerIdentifier )
  48. {
  49. $handlerIdentifier = 'plain';
  50. $handlerName = 'Plain';
  51. }
  52. $this->Name = $handlerName;
  53. $this->Identifier = $handlerIdentifier;
  54. $this->FileName = false;
  55. $this->FileHandler = false;
  56. $this->Mode = false;
  57. $this->IsOpen = false;
  58. $this->IsBinary = false;
  59. }
  60. /*!
  61. \return \c true if a file is opened, \c false otherwise.
  62. */
  63. function isOpen()
  64. {
  65. return $this->IsOpen;
  66. }
  67. /*!
  68. \return \c true if the file was opened in binary mode.
  69. */
  70. function isBinaryMode()
  71. {
  72. return $this->IsBinary;
  73. }
  74. /*!
  75. \return the filename currently in use.
  76. */
  77. function filename()
  78. {
  79. return $this->FileName;
  80. }
  81. /*!
  82. \return the mode which was used to open the currently used file.
  83. */
  84. function mode()
  85. {
  86. return $this->Mode;
  87. }
  88. /*!
  89. \return the name of current handler.
  90. \sa identifier
  91. */
  92. function name()
  93. {
  94. return $this->Name;
  95. }
  96. /*!
  97. \return the identifier of the current handler.
  98. \sa name
  99. */
  100. function identifier()
  101. {
  102. return $this->Identifier;
  103. }
  104. /*!
  105. \return true if this handler can be used.
  106. \note The default implementation is to return \c true for all handlers.
  107. */
  108. static function isAvailable()
  109. {
  110. return true;
  111. }
  112. /*!
  113. Links the file \a $sourceFilename to \a $destinationFilename.
  114. If \a $destinationFilename is a directory then the filename is taken from \a $sourceFilename and appended to the destination.
  115. It will use symbolic links for the operating system that support it and file copy for all others.
  116. \param $symbolicLink if \c true then the files will be made as symbolic links, otherwise as hard links.
  117. \return \c true if sucessful or \c false if the copy failed.
  118. */
  119. static function linkCopy( $sourceFilename, $destinationFilename, $symbolicLink = true )
  120. {
  121. if ( in_array( eZSys::osType(),
  122. array( 'unix', 'linux', 'mac' ) ) )
  123. {
  124. if ( $symbolicLink )
  125. $result = eZFileHandler::symlink( $sourceFilename, $destinationFilename );
  126. else
  127. $result = eZFileHandler::link( $sourceFilename, $destinationFilename );
  128. if ( $result )
  129. return $result;
  130. return eZFileHandler::copy( $sourceFilename, $destinationFilename );
  131. }
  132. else
  133. {
  134. return eZFileHandler::copy( $sourceFilename, $destinationFilename );
  135. }
  136. }
  137. /*!
  138. Creates a symbolic link to the file \a $sourceFilename on the destination \a $destinationFilename.
  139. This means that if someone tries to open \a $destinationFilename they will infact open \a $sourceFilename.
  140. If \a $destinationFilename is a directory then the filename is taken from \a $sourceFilename and appended to the destination.
  141. It will first try to rename the file and if that does not work copy the file and unlink.
  142. \return \c true if sucessful or \c false if the copy failed.
  143. */
  144. static function symlink( $sourceFilename, $destinationFilename )
  145. {
  146. if ( !file_exists( $sourceFilename ) and
  147. !is_link( $sourceFilename ) )
  148. {
  149. eZDebug::writeError( "Cannot symbolicly link to file $sourceFilename, it does not exist", __METHOD__ );
  150. return false;
  151. }
  152. $isDir = false;
  153. if ( is_dir( $destinationFilename ) )
  154. {
  155. $isDir = true;
  156. $dirPosition = strrpos( $sourceFilename, '/' );
  157. $filePosition = 0;
  158. if ( $dirPosition !== false )
  159. $filePosition = $dirPosition + 1;
  160. if ( strlen( $destinationFilename ) > 0 and
  161. $destinationFilename[strlen( $destinationFilename ) - 1] == '/' )
  162. $destinationFilename .= substr( $sourceFilename, $filePosition );
  163. else
  164. $destinationFilename .= '/' . substr( $sourceFilename, $filePosition );
  165. }
  166. $destinationFilename = preg_replace( "#/+#", '/', $destinationFilename );
  167. $sourceDir = $sourceFilename;
  168. $sourceName = false;
  169. $sourceDirPos = strrpos( $sourceDir, '/' );
  170. if ( $sourceDirPos !== false )
  171. {
  172. $sourceName = substr( $sourceDir, $sourceDirPos + 1 );
  173. $sourceDir = substr( $sourceDir, 0, $sourceDirPos );
  174. }
  175. $commonOffset = 0;
  176. for ( $i = 0; $i < strlen( $sourceFilename ) and $i < strlen( $sourceDir ); ++$i )
  177. {
  178. if ( $sourceFilename[$i] != $sourceDir[$i] )
  179. break;
  180. $commonOffset = $i;
  181. }
  182. if ( $commonOffset > 0 )
  183. $sourceDir = substr( $sourceDir, $commonOffset + 1 );
  184. $directoryCount = substr_count( $sourceDir, '/' );
  185. $cdupText = str_repeat( '../', $directoryCount );
  186. if ( file_exists( $destinationFilename ) and
  187. !is_dir( $destinationFilename ) )
  188. {
  189. if ( !@unlink( $destinationFilename ) )
  190. {
  191. eZDebug::writeError( "Cannot symbolicly link to file $sourceFilename on destination $destinationFilename, destination file cannot be removed", __METHOD__ );
  192. return false;
  193. }
  194. }
  195. if ( $sourceDir )
  196. $sourceDir = $sourceDir . '/' . $sourceName;
  197. else
  198. $sourceDir = $sourceName;
  199. if ( symlink( $cdupText . $sourceDir, $destinationFilename ) )
  200. {
  201. return true;
  202. }
  203. eZDebug::writeError( "Failed to symbolicly link to $sourceFilename on destination $destinationFilename", __METHOD__ );
  204. return false;
  205. }
  206. /*!
  207. Creates a symbolic link to the file \a $sourceFilename on the destination \a $destinationFilename.
  208. This means that if someone tries to open \a $destinationFilename they will infact open \a $sourceFilename.
  209. If \a $destinationFilename is a directory then the filename is taken from \a $sourceFilename and appended to the destination.
  210. It will first try to rename the file and if that does not work copy the file and unlink.
  211. \return \c true if sucessful or \c false if the copy failed.
  212. */
  213. static function link( $sourceFilename, $destinationFilename )
  214. {
  215. if ( !file_exists( $sourceFilename ) and
  216. !is_link( $sourceFilename ) )
  217. {
  218. eZDebug::writeError( "Cannot link to file $sourceFilename, it does not exist", __METHOD__ );
  219. return false;
  220. }
  221. $isDir = false;
  222. if ( is_dir( $destinationFilename ) )
  223. {
  224. $isDir = true;
  225. $dirPosition = strrpos( $sourceFilename, '/' );
  226. $filePosition = 0;
  227. if ( $dirPosition !== false )
  228. $filePosition = $dirPosition + 1;
  229. if ( strlen( $destinationFilename ) > 0 and
  230. $destinationFilename[strlen( $destinationFilename ) - 1] == '/' )
  231. $destinationFilename .= substr( $sourceFilename, $filePosition );
  232. else
  233. $destinationFilename .= '/' . substr( $sourceFilename, $filePosition );
  234. }
  235. $destinationFilename = preg_replace( "#/+#", '/', $destinationFilename );
  236. if ( file_exists( $destinationFilename ) and
  237. !is_dir( $destinationFilename ) )
  238. {
  239. if ( !@unlink( $destinationFilename ) )
  240. {
  241. eZDebug::writeError( "Cannot link to file $sourceFilename on destination $destinationFilename, destination file cannot be removed", __METHOD__ );
  242. return false;
  243. }
  244. }
  245. if ( link( $sourceFilename, $destinationFilename ) )
  246. {
  247. return true;
  248. }
  249. eZDebug::writeError( "Failed to link to $sourceFilename on destination $destinationFilename", __METHOD__ );
  250. return false;
  251. }
  252. /*!
  253. Moves the file \a $sourceFilename to \a $destinationFilename.
  254. If \a $destinationFilename is a directory then the filename is taken from \a $sourceFilename and appended to the destination.
  255. It will first try to rename the file and if that does not work copy the file and unlink.
  256. \return \c true if sucessful or \c false if the copy failed.
  257. */
  258. static function move( $sourceFilename, $destinationFilename )
  259. {
  260. if ( !file_exists( $sourceFilename ) and
  261. !is_link( $sourceFilename ) )
  262. {
  263. eZDebug::writeError( "Cannot rename file $sourceFilename, it does not exist", __METHOD__ );
  264. return false;
  265. }
  266. $isDir = false;
  267. if ( is_dir( $destinationFilename ) )
  268. {
  269. $isDir = true;
  270. $dirPosition = strrpos( $sourceFilename, '/' );
  271. $filePosition = 0;
  272. if ( $dirPosition !== false )
  273. $filePosition = $dirPosition + 1;
  274. if ( strlen( $destinationFilename ) > 0 and
  275. $destinationFilename[strlen( $destinationFilename ) - 1] == '/' )
  276. $destinationFilename .= substr( $sourceFilename, $filePosition );
  277. else
  278. $destinationFilename .= '/' . substr( $sourceFilename, $filePosition );
  279. }
  280. // If source and destination are the same files we just return true
  281. if ( $sourceFilename == $destinationFilename )
  282. {
  283. return true;
  284. }
  285. if ( file_exists( $destinationFilename ) and
  286. !is_dir( $destinationFilename ) )
  287. {
  288. if ( !@unlink( $destinationFilename ) )
  289. {
  290. eZDebug::writeError( "Cannot move file $sourceFilename to destination $destinationFilename, destination file cannot be removed", __METHOD__ );
  291. return false;
  292. }
  293. }
  294. $isLink = false;
  295. if ( is_link( $sourceFilename ) )
  296. {
  297. $isLink = true;
  298. }
  299. if ( !$isLink and
  300. eZFile::rename( $sourceFilename, $destinationFilename ) )
  301. {
  302. return true;
  303. }
  304. if ( eZFileHandler::copy( $sourceFilename, $destinationFilename ) )
  305. {
  306. if ( !@unlink( $sourceFilename ) )
  307. {
  308. eZDebug::writeError( "Cannot remove source file $sourceFilename, file was not succesfully moved", __METHOD__ );
  309. @unlink( $destinationFilename );
  310. return false;
  311. }
  312. return true;
  313. }
  314. eZDebug::writeError( "Failed to copy $sourceFilename to $destinationFilename, file was not succesfully moved", __METHOD__ );
  315. return false;
  316. }
  317. /*!
  318. Copies the file \a $sourceFilename to \a $destinationFilename.
  319. \return \c true if sucessful or \c false if the copy failed.
  320. */
  321. static function copy( $sourceFilename, $destinationFilename )
  322. {
  323. if ( is_dir( $sourceFilename ) )
  324. {
  325. eZDebug::writeError( "Unable to copy directory $sourceFilename, use eZDir::copy instead", __METHOD__ );
  326. return false;
  327. }
  328. $sourceFD = @fopen( $sourceFilename, 'rb' );
  329. if ( !$sourceFD )
  330. {
  331. eZDebug::writeError( "Unable to open source file $sourceFilename in read mode", __METHOD__ );
  332. return false;
  333. }
  334. if ( is_dir( $destinationFilename ) )
  335. {
  336. $dirPosition = strrpos( $sourceFilename, '/' );
  337. $filePosition = 0;
  338. if ( $dirPosition !== false )
  339. $filePosition = $dirPosition + 1;
  340. if ( strlen( $destinationFilename ) > 0 and
  341. $destinationFilename[strlen( $destinationFilename ) - 1] == '/' )
  342. $destinationFilename .= substr( $sourceFilename, $filePosition );
  343. else
  344. $destinationFilename .= '/' . substr( $sourceFilename, $filePosition );
  345. }
  346. // If source and destination are the same files we just return true
  347. if ( $sourceFilename == $destinationFilename )
  348. {
  349. @fclose( $sourceFD );
  350. return true;
  351. }
  352. $destinationFD = fopen( $destinationFilename, 'wb' );
  353. chmod( $destinationFilename, octdec( eZINI::instance()->variable( 'FileSettings', 'StorageFilePermissions' ) ) );
  354. if ( !$destinationFD )
  355. {
  356. @fclose( $sourceFD );
  357. eZDebug::writeError( "Unable to open destination file $destinationFilename in write mode", __METHOD__ );
  358. return false;
  359. }
  360. $bytesCopied = 0;
  361. do
  362. {
  363. $data = fread( $sourceFD, 4096 );
  364. if ( strlen( $data ) == 0 )
  365. break;
  366. fwrite( $destinationFD, $data );
  367. $bytesCopied += strlen( $data );
  368. } while( true );
  369. @fclose( $sourceFD );
  370. @fclose( $destinationFD );
  371. return true;
  372. }
  373. /*!
  374. \return \c true if the filename \a $filename exists.
  375. If \a $filename is not specified the filename is taken from the one used in open().
  376. */
  377. function exists( $filename = false )
  378. {
  379. if ( !$filename )
  380. $filename = $this->FileName;
  381. return $this->doExists( $filename );
  382. }
  383. /*!
  384. \return \c true if \a $filename is a directory.
  385. */
  386. function isDirectory( $filename = false )
  387. {
  388. if ( !$filename )
  389. $filename = $this->FileName;
  390. return $this->doIsDirectory( $filename );
  391. }
  392. /*!
  393. \return \c true if \a $filename is executable.
  394. */
  395. function isExecutable( $filename = false )
  396. {
  397. if ( !$filename )
  398. $filename = $this->FileName;
  399. return $this->doIsExecutable( $filename );
  400. }
  401. /*!
  402. \return \c true if \a $filename is a file.
  403. */
  404. function isFile( $filename = false )
  405. {
  406. if ( !$filename )
  407. $filename = $this->FileName;
  408. return $this->doIsFile( $filename );
  409. }
  410. /*!
  411. \return \c true if \a $filename is a link.
  412. */
  413. function isLink( $filename = false )
  414. {
  415. if ( !$filename )
  416. $filename = $this->FileName;
  417. return $this->doIsLink( $filename );
  418. }
  419. /*!
  420. \return \c true if \a $filename is readable.
  421. */
  422. function isReadable( $filename = false )
  423. {
  424. if ( !$filename )
  425. $filename = $this->FileName;
  426. return $this->doIsReadable( $filename );
  427. }
  428. /*!
  429. \return \c true if \a $filename is writeable.
  430. */
  431. function isWriteable( $filename = false )
  432. {
  433. if ( !$filename )
  434. $filename = $this->FileName;
  435. return $this->doIsWriteable( $filename );
  436. }
  437. /*!
  438. \return the statitistics for the file \a $filename.
  439. */
  440. function statistics( $filename = false )
  441. {
  442. if ( !$filename )
  443. $filename = $this->FileName;
  444. return $this->doStatistics( $filename );
  445. }
  446. /*!
  447. Tries to open the file \a $filename with mode \a $mode and returns
  448. the file resource if succesful.
  449. \return \c false if the file could not be opened.
  450. \param $mode If false the file will be opened in read mode using 'r'
  451. \param $binaryFile If true file will be opened in binary mode (default),
  452. otherwise text mode is used.
  453. \note Parameter $binaryFile will only have effect on the Windows operating system.
  454. */
  455. function open( $filename, $mode, $binaryFile = true )
  456. {
  457. if ( $this->isOpen() )
  458. {
  459. eZDebug::writeError( "A file is already open (" . $this->FileName . "), close the file before opening a new one.",
  460. 'eZFileHandler::open' );
  461. return false;
  462. }
  463. if ( !$filename and
  464. !$this->FileName )
  465. {
  466. eZDebug::writeError( "The supplied filename is empty and no filename set for object, cannot open any file", __METHOD__ );
  467. return false;
  468. }
  469. if ( !$filename )
  470. $filename = $this->FileName;
  471. if ( !$mode )
  472. $mode = 'r';
  473. if ( strpos( $mode, 'b' ) !== false )
  474. $binaryFile = true;
  475. $mode = str_replace( 'b', '', $mode );
  476. if ( $binaryFile )
  477. $mode .= 'b';
  478. $this->IsBinary = $binaryFile;
  479. $result = $this->doOpen( $filename, $mode );
  480. if ( $result )
  481. {
  482. // eZDebugSetting::writeNotice( 'lib-ezfile-openclose',
  483. // "Opened file $filename with mode '$mode'",
  484. // 'eZFileHandler::open' );
  485. $this->FileName = $filename;
  486. $this->Mode = $mode;
  487. $this->IsOpen = true;
  488. }
  489. else
  490. eZDebug::writeError( "Failed opening file $filename with mode $mode", __METHOD__ );
  491. return $result;
  492. }
  493. /*!
  494. Tries to close an open file and returns \c true if succesful, \c false otherwise.
  495. */
  496. function close()
  497. {
  498. if ( !$this->isOpen() )
  499. {
  500. eZDebug::writeError( "A file is not currently opened, cannot close.", __METHOD__ );
  501. return false;
  502. }
  503. // eZDebugSetting::writeNotice( 'lib-ezfile-openclose',
  504. // "Closing file " . $this->filename() . " with previously opened mode '" . $this->mode() . "'",
  505. // 'eZFileHandler::close' );
  506. $result = $this->doClose();
  507. if ( !$result )
  508. eZDebug::writeError( "Failed closing file " . $this->FileName . " opened with mode " . $this->Mode, __METHOD__ );
  509. else
  510. $this->IsOpen = false;
  511. return $result;
  512. }
  513. /*!
  514. Tries to unlink the file from the file system.
  515. */
  516. function unlink( $filename = false )
  517. {
  518. if ( !$filename )
  519. {
  520. if ( $this->isOpen() )
  521. $this->close();
  522. $filename = $this->FileName;
  523. }
  524. $result = eZFileHandler::doUnlink( $filename );
  525. if ( !$result )
  526. eZDebug::writeError( "Failed unlinking file " . $filename, __METHOD__ );
  527. return $result;
  528. }
  529. /*!
  530. Renames the file \a $sourceFilename to \a $destinationFilename.
  531. If \a $sourceFilename is not supplied then filename() is used,
  532. it will also close the current file connection and reopen it again if
  533. was already open.
  534. */
  535. function rename( $destinationFilename, $sourceFilename = false )
  536. {
  537. if ( !$sourceFilename )
  538. {
  539. $wasOpen = $this->isOpen();
  540. if ( $wasOpen )
  541. $this->close();
  542. $result = $this->doRename( $destinationFilename, $this->filename() );
  543. if ( $wasOpen and
  544. $result )
  545. $this->open( $destinationFilename, $this->mode() );
  546. }
  547. else
  548. $result = $this->doRename( $destinationFilename, $sourceFilename );
  549. return $result;
  550. }
  551. /*!
  552. Reads up to \a $length bytes from file. Reading stops when
  553. \a $length has been read or \c EOF is reached, whichever comes first.
  554. If the optional parameter \a $length is not specified it will
  555. read bytes until \c EOF is reached.
  556. \return a \c string or \c false if something fails.
  557. */
  558. function read( $length = false )
  559. {
  560. if ( !$this->isOpen() )
  561. {
  562. eZDebug::writeError( "A file is not currently opened, cannot read.", __METHOD__ );
  563. return false;
  564. }
  565. if ( $length < 0 )
  566. {
  567. eZDebug::writeError( "length cannot be negative ($length)", __METHOD__ );
  568. return false;
  569. }
  570. if ( $length )
  571. {
  572. return $this->doRead( $length );
  573. }
  574. else
  575. {
  576. $string = '';
  577. $data = false;
  578. do
  579. {
  580. $data = $this->doRead( 1024 );
  581. if ( $data )
  582. $string .= $data;
  583. } while( $data );
  584. return $string;
  585. }
  586. }
  587. /*!
  588. Writes the content of the string \a $data to the file.
  589. If optional \c $length parameter is supplied writing will stop after
  590. length is reached or the end of the string is reached, whichever comes first.
  591. \return the number of bytes that was written.
  592. */
  593. function write( $data, $length = false )
  594. {
  595. if ( !$this->isOpen() )
  596. {
  597. eZDebug::writeError( "A file is not currently opened, cannot write.", __METHOD__ );
  598. return false;
  599. }
  600. if ( $length < 0 )
  601. {
  602. eZDebug::writeError( "length cannot be negative ($length)", __METHOD__ );
  603. return false;
  604. }
  605. return $this->doWrite( $data, $length );
  606. }
  607. /*!
  608. Force a write of all buffered data.
  609. \return \c true if succesful or \c false if something failed.
  610. */
  611. function flush()
  612. {
  613. if ( !$this->isOpen() )
  614. {
  615. eZDebug::writeError( "A file is not currently opened, cannot flush.", __METHOD__ );
  616. return false;
  617. }
  618. return $this->doFlush();
  619. }
  620. /*!
  621. Seeks to position in file determined by \a $offset and \a $whence.
  622. - SEEK_SET - Set position equal to offset bytes.
  623. - SEEK_CUR - Set position to current location plus offset.
  624. - SEEK_END - Set position to end-of-file plus offset. (To move to a position before the end-of-file, you need to pass a negative value in offset.)
  625. \note Not all handlers supports all types for \a $whence
  626. \return \c 0 if succesful or \c -1 if something failed.
  627. */
  628. function seek( $offset, $whence = SEEK_SET )
  629. {
  630. if ( !$this->isOpen() )
  631. {
  632. eZDebug::writeError( "A file is not currently opened, cannot seek.", __METHOD__ );
  633. return false;
  634. }
  635. return $this->doSeek( $offset, $whence );
  636. }
  637. /*!
  638. Rewinds the file position to the beginning of the file.
  639. \return \c 0 if something went wrong.
  640. */
  641. function rewind()
  642. {
  643. if ( !$this->isOpen() )
  644. {
  645. eZDebug::writeError( "A file is not currently opened, cannot rewind.", __METHOD__ );
  646. return false;
  647. }
  648. return $this->doRewind();
  649. }
  650. /*!
  651. Tells the current file position.
  652. \return \c false if something failed.
  653. */
  654. function tell()
  655. {
  656. if ( !$this->isOpen() )
  657. {
  658. eZDebug::writeError( "A file is not currently opened, cannot tell position.", __METHOD__ );
  659. return false;
  660. }
  661. return $this->doTell();
  662. }
  663. /*!
  664. \return \c true if the file pointer is at the end of the file or an error occured, otherwise \c false.
  665. */
  666. function eof()
  667. {
  668. if ( !$this->isOpen() )
  669. {
  670. eZDebug::writeError( "A file is not currently opened, cannot report EOF status.", __METHOD__ );
  671. return false;
  672. }
  673. return $this->doEOF();
  674. }
  675. /*!
  676. Passes the data from the file to the standard output.
  677. \param $closeFile If \c true the file will be closed after output is done.
  678. \return \c false if something failed.
  679. */
  680. function passtrough( $closeFile = true )
  681. {
  682. if ( !$this->isOpen() )
  683. {
  684. eZDebug::writeError( "A file is not currently opened, cannot do a data passtrough.", __METHOD__ );
  685. return false;
  686. }
  687. return $this->doPasstrough( $closeFile );
  688. }
  689. /*!
  690. \pure
  691. Does the actual file opening.
  692. \sa open
  693. */
  694. function doOpen( $filename, $mode )
  695. {
  696. $this->FileHandler = @fopen( $filename, $mode );
  697. return $this->FileHandler;
  698. }
  699. /*!
  700. \pure
  701. Does the actual file closing.
  702. \sa close
  703. */
  704. function doClose()
  705. {
  706. $result = @fclose( $this->FileHandler );
  707. $this->FileHandler = false;
  708. return $result;
  709. }
  710. /*!
  711. \pure
  712. Does the actual file unlinking.
  713. \sa unlink
  714. */
  715. static function doUnlink( $filename )
  716. {
  717. return @unlink( $filename );
  718. }
  719. /*!
  720. \pure
  721. Does the actual file exists checking.
  722. \sa exists
  723. */
  724. static function doExists( $filename )
  725. {
  726. return file_exists( $filename );
  727. }
  728. /*!
  729. \pure
  730. Does the actual directory checking.
  731. \sa isDirectory
  732. */
  733. static function doIsDirectory( $filename )
  734. {
  735. return is_dir( $filename );
  736. }
  737. /*!
  738. \pure
  739. Does the actual executable checking.
  740. \sa isExecutable
  741. */
  742. static function doIsExecutable( $filename )
  743. {
  744. return is_executable( $filename );
  745. }
  746. /*!
  747. \pure
  748. Does the actual file checking.
  749. \sa isFile
  750. */
  751. static function doIsFile( $filename )
  752. {
  753. return is_file( $filename );
  754. }
  755. /*!
  756. \pure
  757. Does the actual link checking.
  758. \sa isLink
  759. */
  760. static function doIsLink( $filename )
  761. {
  762. return is_link( $filename );
  763. }
  764. /*!
  765. \pure
  766. Does the actual readable checking.
  767. \sa isReadable
  768. */
  769. static function doIsReadable( $filename )
  770. {
  771. return is_readable( $filename );
  772. }
  773. /*!
  774. \pure
  775. Does the actual writeable checking.
  776. \sa isWriteable
  777. */
  778. static function doIsWriteable( $filename )
  779. {
  780. return is_writable( $filename );
  781. }
  782. /*!
  783. \pure
  784. Does the actual writeable checking.
  785. \sa isWriteable
  786. */
  787. static function doStatistics( $filename )
  788. {
  789. return @stat( $filename );
  790. }
  791. /*!
  792. \pure
  793. Does the actual file seek.
  794. \sa seek
  795. */
  796. function doSeek( $offset, $whence )
  797. {
  798. return @fseek( $this->FileHandler, $offset, $whence );
  799. }
  800. /*!
  801. Does the actual file rewind.
  802. \sa rewind
  803. \note Default implementation calls seek with offset set to 0 from the file start.
  804. */
  805. function doRewind()
  806. {
  807. $this->doSeek( 0, SEEK_SET );
  808. }
  809. /*!
  810. \pure
  811. Does the actual file telling.
  812. \sa tell
  813. */
  814. function doTell()
  815. {
  816. return @ftell( $this->FileHandler );
  817. }
  818. /*!
  819. \pure
  820. Does the actual file eof detection.
  821. \sa eof
  822. */
  823. function doEOF()
  824. {
  825. return @feof( $this->FileHandler );
  826. }
  827. /*!
  828. \pure
  829. Does the actual file passtrough.
  830. \sa eof
  831. */
  832. function doPasstrough( $closeFile = true )
  833. {
  834. $result = @fpassthru( $this->FileHandler );
  835. if ( $closeFile )
  836. {
  837. @fclose( $this->FileHandler );
  838. $this->FileHandler = false;
  839. }
  840. }
  841. /*!
  842. \pure
  843. Does the actual file reading.
  844. \sa read
  845. */
  846. function doRead( $length = false )
  847. {
  848. return @fread( $this->FileHandler, $length );
  849. }
  850. /*!
  851. \pure
  852. Does the actual file writing.
  853. \sa write
  854. */
  855. function doWrite( $data, $length = false )
  856. {
  857. if ( $length === false )
  858. return @fwrite( $this->FileHandler, $data );
  859. else
  860. return @fwrite( $this->FileHandler, $data, $length );
  861. }
  862. /*!
  863. \pure
  864. Does the actual file flushing.
  865. \sa flush
  866. */
  867. function doFlush()
  868. {
  869. return @fflush( $this->FileHandler );
  870. }
  871. /*!
  872. \pure
  873. Does the actual file renaming.
  874. \sa rename
  875. */
  876. static function doRename( $destinationFilename, $sourceFilename )
  877. {
  878. return eZFile::rename( $sourceFilename, $destinationFilename );
  879. }
  880. /*!
  881. Returns error data as an associative array, the array contains:
  882. - string - The error string
  883. - number - The error number
  884. \note The default implementation calls errorString() and errorNumber().
  885. */
  886. function error()
  887. {
  888. return array( 'string' => $this->errorString(),
  889. 'number' => $this->errorNumber() );
  890. }
  891. /*!
  892. \pure
  893. \return the error string from the last error that occured.
  894. */
  895. function errorString()
  896. {
  897. return false;
  898. }
  899. /*!
  900. \pure
  901. \return the error number from the last error that occured.
  902. */
  903. function errorNumber()
  904. {
  905. return false;
  906. }
  907. /*!
  908. Creates a copy of the current handler and returns a reference to the copy.
  909. \note The default does a simple copy of \c $this, this method must be reimplemented for specific handlers.
  910. */
  911. function duplicate()
  912. {
  913. $copy = clone $this;
  914. return $copy;
  915. }
  916. /*!
  917. Returns the handler for the identifier \a $identifier.
  918. The parameters \a $filename, \a $mode and \a $binaryFile is passed to the handler.
  919. \return \c false if the handler could not be created.
  920. */
  921. /**
  922. * Returns a shared instance of the eZFileHandler class.
  923. * $identifier if set is used to specify specific file handlers as
  924. * defined in file.ini [FileSettings]Handlers.
  925. * If $filename and later params are set, then file is opened straigt away.
  926. *
  927. * @param string|false $identifier Global eZFileHandler used if false
  928. * @param string|false $filename
  929. * @param string|false $mode set to 'r' if false
  930. * @param bool $binaryFile Binary or text mode, default true.
  931. * @return eZFileHandler|false
  932. */
  933. static function instance( $identifier, $filename = false, $mode = false, $binaryFile = true )
  934. {
  935. $ini = eZINI::instance( 'file.ini' );
  936. $handlers = $ini->variable( 'FileSettings', 'Handlers' );
  937. $instance = false;
  938. if ( !$identifier )
  939. {
  940. $instance = new eZFileHandler();
  941. }
  942. else if ( isset( $handlers[$identifier] ) )
  943. {
  944. $className = $handlers[$identifier];
  945. $includeFile = 'lib/ezfile/classes/' . $className . '.php';
  946. include_once( $includeFile );
  947. $instance = new $className();
  948. if ( $instance->isAvailable() )
  949. {
  950. if ( $filename )
  951. $instance->open( $filename, $mode, $binaryFile );
  952. }
  953. else
  954. {
  955. unset( $instance );
  956. $instance = false;
  957. }
  958. }
  959. return $instance;
  960. }
  961. /// \privatesection
  962. public $Name;
  963. public $FileName;
  964. public $Mode;
  965. public $IsBinary;
  966. public $IsOpen;
  967. }
  968. ?>