PageRenderTime 38ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/libraries/joomla/filesystem/stream.php

https://bitbucket.org/pastor399/newcastleunifc
PHP | 1423 lines | 736 code | 188 blank | 499 comment | 85 complexity | bbd997f3638a1ae98de97654881c2a0b MD5 | raw file
  1. <?php
  2. /**
  3. * @package Joomla.Platform
  4. * @subpackage FileSystem
  5. *
  6. * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE
  8. */
  9. defined('JPATH_PLATFORM') or die;
  10. /**
  11. * Joomla! Stream Interface
  12. *
  13. * The Joomla! stream interface is designed to handle files as streams
  14. * where as the legacy JFile static class treated files in a rather
  15. * atomic manner.
  16. *
  17. * @package Joomla.Platform
  18. * @subpackage FileSystem
  19. *
  20. * This class adheres to the stream wrapper operations:
  21. *
  22. * @see http://php.net/manual/en/function.stream-get-wrappers.php
  23. * @see http://php.net/manual/en/intro.stream.php PHP Stream Manual
  24. * @see http://php.net/manual/en/wrappers.php Stream Wrappers
  25. * @see http://php.net/manual/en/filters.php Stream Filters
  26. * @see http://php.net/manual/en/transports.php Socket Transports (used by some options, particularly HTTP proxy)
  27. * @since 11.1
  28. */
  29. class JStream extends JObject
  30. {
  31. // Publicly settable vars (protected to let our parent read them)
  32. /**
  33. * File Mode
  34. * @var integer
  35. * @since 11.1
  36. * */
  37. protected $filemode = 0644;
  38. /**
  39. * Directory Mode
  40. * @var integer
  41. * @since 11.1
  42. * */
  43. protected $dirmode = 0755;
  44. /**
  45. * Default Chunk Size
  46. * @var integer
  47. * @since 11.1
  48. */
  49. protected $chunksize = 8192;
  50. /**
  51. * Filename
  52. * @var string
  53. * @since 11.1
  54. */
  55. protected $filename;
  56. /**
  57. * Prefix of the connection for writing
  58. * @var string
  59. * @since 11.1
  60. */
  61. protected $writeprefix;
  62. /**
  63. * Prefix of the connection for reading
  64. * @var string
  65. * @since 11.1
  66. */
  67. protected $readprefix;
  68. /**
  69. *
  70. *Read Processing method
  71. * @var string gz, bz, f
  72. * If a scheme is detected, fopen will be defaulted
  73. * To use compression with a network stream use a filter
  74. * @since 11.1
  75. */
  76. protected $processingmethod = 'f';
  77. /**
  78. * Filters applied to the current stream
  79. * @var array
  80. * @since 11.1
  81. */
  82. protected $filters = array();
  83. /**
  84. * File Handle
  85. * @var array
  86. * @since 12.1
  87. */
  88. protected $fh;
  89. /**
  90. * File size
  91. * @var integer
  92. * @since 12.1
  93. */
  94. protected $filesize;
  95. /**
  96. *Context to use when opening the connection
  97. * @var
  98. * @since 12.1
  99. */
  100. protected $context = null;
  101. /**
  102. * Context options; used to rebuild the context
  103. * @var
  104. * @since 12.1
  105. */
  106. protected $contextOptions;
  107. /**
  108. * The mode under which the file was opened
  109. * @var
  110. * @since 12.1
  111. */
  112. protected $openmode;
  113. /**
  114. * Constructor
  115. *
  116. * @param string $writeprefix Prefix of the stream (optional). Unlike the JPATH_*, this has a final path separator!
  117. * @param string $readprefix The read prefix (optional).
  118. * @param array $context The context options (optional).
  119. *
  120. * @since 11.1
  121. */
  122. public function __construct($writeprefix = '', $readprefix = '', $context = array())
  123. {
  124. $this->writeprefix = $writeprefix;
  125. $this->readprefix = $readprefix;
  126. $this->contextOptions = $context;
  127. $this->_buildContext();
  128. }
  129. /**
  130. * Destructor
  131. *
  132. * @since 11.1
  133. */
  134. public function __destruct()
  135. {
  136. // Attempt to close on destruction if there is a file handle
  137. if ($this->fh)
  138. {
  139. @$this->close();
  140. }
  141. }
  142. /**
  143. * Generic File Operations
  144. *
  145. * Open a stream with some lazy loading smarts
  146. *
  147. * @param string $filename Filename
  148. * @param string $mode Mode string to use
  149. * @param boolean $use_include_path Use the PHP include path
  150. * @param resource $context Context to use when opening
  151. * @param boolean $use_prefix Use a prefix to open the file
  152. * @param boolean $relative Filename is a relative path (if false, strips JPATH_ROOT to make it relative)
  153. * @param boolean $detectprocessingmode Detect the processing method for the file and use the appropriate function
  154. * to handle output automatically
  155. *
  156. * @return boolean
  157. *
  158. * @since 11.1
  159. */
  160. public function open($filename, $mode = 'r', $use_include_path = false, $context = null,
  161. $use_prefix = false, $relative = false, $detectprocessingmode = false)
  162. {
  163. $filename = $this->_getFilename($filename, $mode, $use_prefix, $relative);
  164. if (!$filename)
  165. {
  166. $this->setError(JText::_('JLIB_FILESYSTEM_ERROR_STREAMS_FILENAME'));
  167. return false;
  168. }
  169. $this->filename = $filename;
  170. $this->openmode = $mode;
  171. $url = parse_url($filename);
  172. $retval = false;
  173. if (isset($url['scheme']))
  174. {
  175. // If we're dealing with a Joomla! stream, load it
  176. if (JFilesystemHelper::isJoomlaStream($url['scheme']))
  177. {
  178. require_once __DIR__ . '/streams/' . $url['scheme'] . '.php';
  179. }
  180. // We have a scheme! force the method to be f
  181. $this->processingmethod = 'f';
  182. }
  183. elseif ($detectprocessingmode)
  184. {
  185. $ext = strtolower(JFile::getExt($this->filename));
  186. switch ($ext)
  187. {
  188. case 'tgz':
  189. case 'gz':
  190. case 'gzip':
  191. $this->processingmethod = 'gz';
  192. break;
  193. case 'tbz2':
  194. case 'bz2':
  195. case 'bzip2':
  196. $this->processingmethod = 'bz';
  197. break;
  198. default:
  199. $this->processingmethod = 'f';
  200. break;
  201. }
  202. }
  203. // Capture PHP errors
  204. $php_errormsg = 'Error Unknown whilst opening a file';
  205. $track_errors = ini_get('track_errors');
  206. ini_set('track_errors', true);
  207. // Decide which context to use:
  208. switch ($this->processingmethod)
  209. {
  210. // Gzip doesn't support contexts or streams
  211. case 'gz':
  212. $this->fh = gzopen($filename, $mode, $use_include_path);
  213. break;
  214. // Bzip2 is much like gzip except it doesn't use the include path
  215. case 'bz':
  216. $this->fh = bzopen($filename, $mode);
  217. break;
  218. // Fopen can handle streams
  219. case 'f':
  220. default:
  221. // One supplied at open; overrides everything
  222. if ($context)
  223. {
  224. $this->fh = fopen($filename, $mode, $use_include_path, $context);
  225. }
  226. // One provided at initialisation
  227. elseif ($this->context)
  228. {
  229. $this->fh = fopen($filename, $mode, $use_include_path, $this->context);
  230. }
  231. // No context; all defaults
  232. else
  233. {
  234. $this->fh = fopen($filename, $mode, $use_include_path);
  235. }
  236. break;
  237. }
  238. if (!$this->fh)
  239. {
  240. $this->setError($php_errormsg);
  241. }
  242. else
  243. {
  244. $retval = true;
  245. }
  246. // Restore error tracking to what it was before
  247. ini_set('track_errors', $track_errors);
  248. // Return the result
  249. return $retval;
  250. }
  251. /**
  252. * Attempt to close a file handle
  253. *
  254. * Will return false if it failed and true on success
  255. * If the file is not open the system will return true, this function destroys the file handle as well
  256. *
  257. * @return boolean
  258. *
  259. * @since 11.1
  260. */
  261. public function close()
  262. {
  263. if (!$this->fh)
  264. {
  265. $this->setError(JText::_('JLIB_FILESYSTEM_ERROR_STREAMS_FILE_NOT_OPEN'));
  266. return true;
  267. }
  268. $retval = false;
  269. // Capture PHP errors
  270. $php_errormsg = 'Error Unknown';
  271. $track_errors = ini_get('track_errors');
  272. ini_set('track_errors', true);
  273. switch ($this->processingmethod)
  274. {
  275. case 'gz':
  276. $res = gzclose($this->fh);
  277. break;
  278. case 'bz':
  279. $res = bzclose($this->fh);
  280. break;
  281. case 'f':
  282. default:
  283. $res = fclose($this->fh);
  284. break;
  285. }
  286. if (!$res)
  287. {
  288. $this->setError($php_errormsg);
  289. }
  290. else
  291. {
  292. // Reset this
  293. $this->fh = null;
  294. $retval = true;
  295. }
  296. // If we wrote, chmod the file after it's closed
  297. if ($this->openmode[0] == 'w')
  298. {
  299. $this->chmod();
  300. }
  301. // Restore error tracking to what it was before
  302. ini_set('track_errors', $track_errors);
  303. // Return the result
  304. return $retval;
  305. }
  306. /**
  307. * Work out if we're at the end of the file for a stream
  308. *
  309. * @return boolean
  310. *
  311. * @since 11.1
  312. */
  313. public function eof()
  314. {
  315. if (!$this->fh)
  316. {
  317. $this->setError(JText::_('JLIB_FILESYSTEM_ERROR_STREAMS_FILE_NOT_OPEN'));
  318. return false;
  319. }
  320. // Capture PHP errors
  321. $php_errormsg = '';
  322. $track_errors = ini_get('track_errors');
  323. ini_set('track_errors', true);
  324. switch ($this->processingmethod)
  325. {
  326. case 'gz':
  327. $res = gzeof($this->fh);
  328. break;
  329. case 'bz':
  330. case 'f':
  331. default:
  332. $res = feof($this->fh);
  333. break;
  334. }
  335. if ($php_errormsg)
  336. {
  337. $this->setError($php_errormsg);
  338. }
  339. // Restore error tracking to what it was before
  340. ini_set('track_errors', $track_errors);
  341. // Return the result
  342. return $res;
  343. }
  344. /**
  345. * Retrieve the file size of the path
  346. *
  347. * @return mixed
  348. *
  349. * @since 11.1
  350. */
  351. public function filesize()
  352. {
  353. if (!$this->filename)
  354. {
  355. $this->setError(JText::_('JLIB_FILESYSTEM_ERROR_STREAMS_FILE_NOT_OPEN'));
  356. return false;
  357. }
  358. $retval = false;
  359. // Capture PHP errors
  360. $php_errormsg = '';
  361. $track_errors = ini_get('track_errors');
  362. ini_set('track_errors', true);
  363. $res = @filesize($this->filename);
  364. if (!$res)
  365. {
  366. $tmp_error = '';
  367. if ($php_errormsg)
  368. {
  369. // Something went wrong.
  370. // Store the error in case we need it.
  371. $tmp_error = $php_errormsg;
  372. }
  373. $res = JFilesystemHelper::remotefsize($this->filename);
  374. if (!$res)
  375. {
  376. if ($tmp_error)
  377. {
  378. // Use the php_errormsg from before
  379. $this->setError($tmp_error);
  380. }
  381. else
  382. {
  383. // Error but nothing from php? How strange! Create our own
  384. $this->setError(JText::_('JLIB_FILESYSTEM_ERROR_STREAMS_FILE_SIZE'));
  385. }
  386. }
  387. else
  388. {
  389. $this->filesize = $res;
  390. $retval = $res;
  391. }
  392. }
  393. else
  394. {
  395. $this->filesize = $res;
  396. $retval = $res;
  397. }
  398. // Restore error tracking to what it was before.
  399. ini_set('track_errors', $track_errors);
  400. // Return the result
  401. return $retval;
  402. }
  403. /**
  404. * Get a line from the stream source.
  405. *
  406. * @param integer $length The number of bytes (optional) to read.
  407. *
  408. * @return mixed
  409. *
  410. * @since 11.1
  411. */
  412. public function gets($length = 0)
  413. {
  414. if (!$this->fh)
  415. {
  416. $this->setError(JText::_('JLIB_FILESYSTEM_ERROR_STREAMS_FILE_NOT_OPEN'));
  417. return false;
  418. }
  419. $retval = false;
  420. // Capture PHP errors
  421. $php_errormsg = 'Error Unknown';
  422. $track_errors = ini_get('track_errors');
  423. ini_set('track_errors', true);
  424. switch ($this->processingmethod)
  425. {
  426. case 'gz':
  427. $res = $length ? gzgets($this->fh, $length) : gzgets($this->fh);
  428. break;
  429. case 'bz':
  430. case 'f':
  431. default:
  432. $res = $length ? fgets($this->fh, $length) : fgets($this->fh);
  433. break;
  434. }
  435. if (!$res)
  436. {
  437. $this->setError($php_errormsg);
  438. }
  439. else
  440. {
  441. $retval = $res;
  442. }
  443. // Restore error tracking to what it was before
  444. ini_set('track_errors', $track_errors);
  445. // Return the result
  446. return $retval;
  447. }
  448. /**
  449. * Read a file
  450. *
  451. * Handles user space streams appropriately otherwise any read will return 8192
  452. *
  453. * @param integer $length Length of data to read
  454. *
  455. * @return mixed
  456. *
  457. * @see http://php.net/manual/en/function.fread.php
  458. * @since 11.1
  459. */
  460. public function read($length = 0)
  461. {
  462. if (!$this->filesize && !$length)
  463. {
  464. // Get the filesize
  465. $this->filesize();
  466. if (!$this->filesize)
  467. {
  468. // Set it to the biggest and then wait until eof
  469. $length = -1;
  470. }
  471. else
  472. {
  473. $length = $this->filesize;
  474. }
  475. }
  476. if (!$this->fh)
  477. {
  478. $this->setError(JText::_('JLIB_FILESYSTEM_ERROR_STREAMS_FILE_NOT_OPEN'));
  479. return false;
  480. }
  481. $retval = false;
  482. // Capture PHP errors
  483. $php_errormsg = 'Error Unknown';
  484. $track_errors = ini_get('track_errors');
  485. ini_set('track_errors', true);
  486. $remaining = $length;
  487. do
  488. {
  489. // Do chunked reads where relevant
  490. switch ($this->processingmethod)
  491. {
  492. case 'bz':
  493. $res = ($remaining > 0) ? bzread($this->fh, $remaining) : bzread($this->fh, $this->chunksize);
  494. break;
  495. case 'gz':
  496. $res = ($remaining > 0) ? gzread($this->fh, $remaining) : gzread($this->fh, $this->chunksize);
  497. break;
  498. case 'f':
  499. default:
  500. $res = ($remaining > 0) ? fread($this->fh, $remaining) : fread($this->fh, $this->chunksize);
  501. break;
  502. }
  503. if (!$res)
  504. {
  505. $this->setError($php_errormsg);
  506. // Jump from the loop
  507. $remaining = 0;
  508. }
  509. else
  510. {
  511. if (!$retval)
  512. {
  513. $retval = '';
  514. }
  515. $retval .= $res;
  516. if (!$this->eof())
  517. {
  518. $len = strlen($res);
  519. $remaining -= $len;
  520. }
  521. else
  522. {
  523. // If it's the end of the file then we've nothing left to read; reset remaining and len
  524. $remaining = 0;
  525. $length = strlen($retval);
  526. }
  527. }
  528. }
  529. while ($remaining || !$length);
  530. // Restore error tracking to what it was before
  531. ini_set('track_errors', $track_errors);
  532. // Return the result
  533. return $retval;
  534. }
  535. /**
  536. * Seek the file
  537. *
  538. * Note: the return value is different to that of fseek
  539. *
  540. * @param integer $offset Offset to use when seeking.
  541. * @param integer $whence Seek mode to use.
  542. *
  543. * @return boolean True on success, false on failure
  544. *
  545. * @see http://php.net/manual/en/function.fseek.php
  546. * @since 11.1
  547. */
  548. public function seek($offset, $whence = SEEK_SET)
  549. {
  550. if (!$this->fh)
  551. {
  552. $this->setError(JText::_('JLIB_FILESYSTEM_ERROR_STREAMS_FILE_NOT_OPEN'));
  553. return false;
  554. }
  555. $retval = false;
  556. // Capture PHP errors
  557. $php_errormsg = '';
  558. $track_errors = ini_get('track_errors');
  559. ini_set('track_errors', true);
  560. switch ($this->processingmethod)
  561. {
  562. case 'gz':
  563. $res = gzseek($this->fh, $offset, $whence);
  564. break;
  565. case 'bz':
  566. case 'f':
  567. default:
  568. $res = fseek($this->fh, $offset, $whence);
  569. break;
  570. }
  571. // Seek, interestingly, returns 0 on success or -1 on failure.
  572. if ($res == -1)
  573. {
  574. $this->setError($php_errormsg);
  575. }
  576. else
  577. {
  578. $retval = true;
  579. }
  580. // Restore error tracking to what it was before
  581. ini_set('track_errors', $track_errors);
  582. // Return the result
  583. return $retval;
  584. }
  585. /**
  586. * Returns the current position of the file read/write pointer.
  587. *
  588. * @return mixed
  589. *
  590. * @since 11.1
  591. */
  592. public function tell()
  593. {
  594. if (!$this->fh)
  595. {
  596. $this->setError(JText::_('JLIB_FILESYSTEM_ERROR_STREAMS_FILE_NOT_OPEN'));
  597. return false;
  598. }
  599. $res = false;
  600. // Capture PHP errors
  601. $php_errormsg = '';
  602. $track_errors = ini_get('track_errors');
  603. ini_set('track_errors', true);
  604. switch ($this->processingmethod)
  605. {
  606. case 'gz':
  607. $res = gztell($this->fh);
  608. break;
  609. case 'bz':
  610. case 'f':
  611. default:
  612. $res = ftell($this->fh);
  613. break;
  614. }
  615. // May return 0 so check if it's really false
  616. if ($res === false)
  617. {
  618. $this->setError($php_errormsg);
  619. }
  620. // Restore error tracking to what it was before
  621. ini_set('track_errors', $track_errors);
  622. // Return the result
  623. return $res;
  624. }
  625. /**
  626. * File write
  627. *
  628. * Whilst this function accepts a reference, the underlying fwrite
  629. * will do a copy! This will roughly double the memory allocation for
  630. * any write you do. Specifying chunked will get around this by only
  631. * writing in specific chunk sizes. This defaults to 8192 which is a
  632. * sane number to use most of the time (change the default with
  633. * JStream::set('chunksize', newsize);)
  634. * Note: This doesn't support gzip/bzip2 writing like reading does
  635. *
  636. * @param string &$string Reference to the string to write.
  637. * @param integer $length Length of the string to write.
  638. * @param integer $chunk Size of chunks to write in.
  639. *
  640. * @return boolean
  641. *
  642. * @see http://php.net/manual/en/function.fwrite.php
  643. * @since 11.1
  644. */
  645. public function write(&$string, $length = 0, $chunk = 0)
  646. {
  647. if (!$this->fh)
  648. {
  649. $this->setError(JText::_('JLIB_FILESYSTEM_ERROR_STREAMS_FILE_NOT_OPEN'));
  650. return false;
  651. }
  652. // If the length isn't set, set it to the length of the string.
  653. if (!$length)
  654. {
  655. $length = strlen($string);
  656. }
  657. // If the chunk isn't set, set it to the default.
  658. if (!$chunk)
  659. {
  660. $chunk = $this->chunksize;
  661. }
  662. $retval = true;
  663. // Capture PHP errors
  664. $php_errormsg = '';
  665. $track_errors = ini_get('track_errors');
  666. ini_set('track_errors', true);
  667. $remaining = $length;
  668. $start = 0;
  669. do
  670. {
  671. // If the amount remaining is greater than the chunk size, then use the chunk
  672. $amount = ($remaining > $chunk) ? $chunk : $remaining;
  673. $res = fwrite($this->fh, substr($string, $start), $amount);
  674. // Returns false on error or the number of bytes written
  675. if ($res === false)
  676. {
  677. // Returned error
  678. $this->setError($php_errormsg);
  679. $retval = false;
  680. $remaining = 0;
  681. }
  682. elseif ($res === 0)
  683. {
  684. // Wrote nothing?
  685. $remaining = 0;
  686. $this->setError(JText::_('JLIB_FILESYSTEM_ERROR_NO_DATA_WRITTEN'));
  687. }
  688. else
  689. {
  690. // Wrote something
  691. $start += $amount;
  692. $remaining -= $res;
  693. }
  694. }
  695. while ($remaining);
  696. // Restore error tracking to what it was before.
  697. ini_set('track_errors', $track_errors);
  698. // Return the result
  699. return $retval;
  700. }
  701. /**
  702. * Chmod wrapper
  703. *
  704. * @param string $filename File name.
  705. * @param mixed $mode Mode to use.
  706. *
  707. * @return boolean
  708. *
  709. * @since 11.1
  710. */
  711. public function chmod($filename = '', $mode = 0)
  712. {
  713. if (!$filename)
  714. {
  715. if (!isset($this->filename) || !$this->filename)
  716. {
  717. $this->setError(JText::_('JLIB_FILESYSTEM_ERROR_STREAMS_FILENAME'));
  718. return false;
  719. }
  720. $filename = $this->filename;
  721. }
  722. // If no mode is set use the default
  723. if (!$mode)
  724. {
  725. $mode = $this->filemode;
  726. }
  727. $retval = false;
  728. // Capture PHP errors
  729. $php_errormsg = '';
  730. $track_errors = ini_get('track_errors');
  731. ini_set('track_errors', true);
  732. $sch = parse_url($filename, PHP_URL_SCHEME);
  733. // Scheme specific options; ftp's chmod support is fun.
  734. switch ($sch)
  735. {
  736. case 'ftp':
  737. case 'ftps':
  738. $res = JFilesystemHelper::ftpChmod($filename, $mode);
  739. break;
  740. default:
  741. $res = chmod($filename, $mode);
  742. break;
  743. }
  744. // Seek, interestingly, returns 0 on success or -1 on failure
  745. if (!$res)
  746. {
  747. $this->setError($php_errormsg);
  748. }
  749. else
  750. {
  751. $retval = true;
  752. }
  753. // Restore error tracking to what it was before.
  754. ini_set('track_errors', $track_errors);
  755. // Return the result
  756. return $retval;
  757. }
  758. /**
  759. * Get the stream metadata
  760. *
  761. * @return array header/metadata
  762. *
  763. * @see http://php.net/manual/en/function.stream-get-meta-data.php
  764. * @since 11.1
  765. */
  766. public function get_meta_data()
  767. {
  768. if (!$this->fh)
  769. {
  770. $this->setError(JText::_('JLIB_FILESYSTEM_ERROR_STREAMS_FILE_NOT_OPEN'));
  771. return false;
  772. }
  773. return stream_get_meta_data($this->fh);
  774. }
  775. /**
  776. * Stream contexts
  777. * Builds the context from the array
  778. *
  779. * @return mixed
  780. *
  781. * @since 11.1
  782. */
  783. public function _buildContext()
  784. {
  785. // According to the manual this always works!
  786. if (count($this->contextOptions))
  787. {
  788. $this->context = @stream_context_create($this->contextOptions);
  789. }
  790. else
  791. {
  792. $this->context = null;
  793. }
  794. }
  795. /**
  796. * Updates the context to the array
  797. *
  798. * Format is the same as the options for stream_context_create
  799. *
  800. * @param array $context Options to create the context with
  801. *
  802. * @return void
  803. *
  804. * @see http://php.net/stream_context_create
  805. * @since 11.1
  806. */
  807. public function setContextOptions($context)
  808. {
  809. $this->contextOptions = $context;
  810. $this->_buildContext();
  811. }
  812. /**
  813. * Adds a particular options to the context
  814. *
  815. * @param string $wrapper The wrapper to use
  816. * @param string $name The option to set
  817. * @param string $value The value of the option
  818. *
  819. * @return void
  820. *
  821. * @see http://php.net/stream_context_create Stream Context Creation
  822. * @see http://php.net/manual/en/context.php Context Options for various streams
  823. * @since 11.1
  824. */
  825. public function addContextEntry($wrapper, $name, $value)
  826. {
  827. $this->contextOptions[$wrapper][$name] = $value;
  828. $this->_buildContext();
  829. }
  830. /**
  831. * Deletes a particular setting from a context
  832. *
  833. * @param string $wrapper The wrapper to use
  834. * @param string $name The option to unset
  835. *
  836. * @return void
  837. *
  838. * @see http://php.net/stream_context_create
  839. * @since 11.1
  840. */
  841. public function deleteContextEntry($wrapper, $name)
  842. {
  843. // Check whether the wrapper is set
  844. if (isset($this->contextOptions[$wrapper]))
  845. {
  846. // Check that entry is set for that wrapper
  847. if (isset($this->contextOptions[$wrapper][$name]))
  848. {
  849. // Unset the item
  850. unset($this->contextOptions[$wrapper][$name]);
  851. // Check that there are still items there
  852. if (!count($this->contextOptions[$wrapper]))
  853. {
  854. // Clean up an empty wrapper context option
  855. unset($this->contextOptions[$wrapper]);
  856. }
  857. }
  858. }
  859. // Rebuild the context and apply it to the stream
  860. $this->_buildContext();
  861. }
  862. /**
  863. * Applies the current context to the stream
  864. *
  865. * Use this to change the values of the context after you've opened a stream
  866. *
  867. * @return mixed
  868. *
  869. * @since 11.1
  870. */
  871. public function applyContextToStream()
  872. {
  873. $retval = false;
  874. if ($this->fh)
  875. {
  876. // Capture PHP errors
  877. $php_errormsg = 'Unknown error setting context option';
  878. $track_errors = ini_get('track_errors');
  879. ini_set('track_errors', true);
  880. $retval = @stream_context_set_option($this->fh, $this->contextOptions);
  881. if (!$retval)
  882. {
  883. $this->setError($php_errormsg);
  884. }
  885. // Restore error tracking to what it was before
  886. ini_set('track_errors', $track_errors);
  887. }
  888. return $retval;
  889. }
  890. /**
  891. * Stream filters
  892. * Append a filter to the chain
  893. *
  894. * @param string $filtername The key name of the filter.
  895. * @param integer $read_write Optional. Defaults to STREAM_FILTER_READ.
  896. * @param array $params An array of params for the stream_filter_append call.
  897. *
  898. * @return mixed
  899. *
  900. * @see http://php.net/manual/en/function.stream-filter-append.php
  901. * @since 11.1
  902. */
  903. public function appendFilter($filtername, $read_write = STREAM_FILTER_READ, $params = array())
  904. {
  905. $res = false;
  906. if ($this->fh)
  907. {
  908. // Capture PHP errors
  909. $php_errormsg = '';
  910. $track_errors = ini_get('track_errors');
  911. ini_set('track_errors', true);
  912. $res = @stream_filter_append($this->fh, $filtername, $read_write, $params);
  913. if (!$res && $php_errormsg)
  914. {
  915. $this->setError($php_errormsg);
  916. }
  917. else
  918. {
  919. $this->filters[] = &$res;
  920. }
  921. // Restore error tracking to what it was before.
  922. ini_set('track_errors', $track_errors);
  923. }
  924. return $res;
  925. }
  926. /**
  927. * Prepend a filter to the chain
  928. *
  929. * @param string $filtername The key name of the filter.
  930. * @param integer $read_write Optional. Defaults to STREAM_FILTER_READ.
  931. * @param array $params An array of params for the stream_filter_prepend call.
  932. *
  933. * @return mixed
  934. *
  935. * @see http://php.net/manual/en/function.stream-filter-prepend.php
  936. * @since 11.1
  937. */
  938. public function prependFilter($filtername, $read_write = STREAM_FILTER_READ, $params = array())
  939. {
  940. $res = false;
  941. if ($this->fh)
  942. {
  943. // Capture PHP errors
  944. $php_errormsg = '';
  945. $track_errors = ini_get('track_errors');
  946. ini_set('track_errors', true);
  947. $res = @stream_filter_prepend($this->fh, $filtername, $read_write, $params);
  948. if (!$res && $php_errormsg)
  949. {
  950. // Set the error msg
  951. $this->setError($php_errormsg);
  952. }
  953. else
  954. {
  955. array_unshift($res, '');
  956. $res[0] = &$this->filters;
  957. }
  958. // Restore error tracking to what it was before.
  959. ini_set('track_errors', $track_errors);
  960. }
  961. return $res;
  962. }
  963. /**
  964. * Remove a filter, either by resource (handed out from the append or prepend function)
  965. * or via getting the filter list)
  966. *
  967. * @param resource &$resource The resource.
  968. * @param boolean $byindex The index of the filter.
  969. *
  970. * @return boolean Result of operation
  971. *
  972. * @since 11.1
  973. */
  974. public function removeFilter(&$resource, $byindex = false)
  975. {
  976. $res = false;
  977. // Capture PHP errors
  978. $php_errormsg = '';
  979. $track_errors = ini_get('track_errors');
  980. ini_set('track_errors', true);
  981. if ($byindex)
  982. {
  983. $res = stream_filter_remove($this->filters[$resource]);
  984. }
  985. else
  986. {
  987. $res = stream_filter_remove($resource);
  988. }
  989. if ($res && $php_errormsg)
  990. {
  991. $this->setError($php_errormsg);
  992. }
  993. // Restore error tracking to what it was before.
  994. ini_set('track_errors', $track_errors);
  995. return $res;
  996. }
  997. /**
  998. * Copy a file from src to dest
  999. *
  1000. * @param string $src The file path to copy from.
  1001. * @param string $dest The file path to copy to.
  1002. * @param resource $context A valid context resource (optional) created with stream_context_create.
  1003. * @param boolean $use_prefix Controls the use of a prefix (optional).
  1004. * @param boolean $relative Determines if the filename given is relative. Relative paths do not have JPATH_ROOT stripped.
  1005. *
  1006. * @return mixed
  1007. *
  1008. * @since 11.1
  1009. */
  1010. public function copy($src, $dest, $context = null, $use_prefix = true, $relative = false)
  1011. {
  1012. $res = false;
  1013. // Capture PHP errors
  1014. $php_errormsg = '';
  1015. $track_errors = ini_get('track_errors');
  1016. ini_set('track_errors', true);
  1017. $chmodDest = $this->_getFilename($dest, 'w', $use_prefix, $relative);
  1018. // Since we're going to open the file directly we need to get the filename.
  1019. // We need to use the same prefix so force everything to write.
  1020. $src = $this->_getFilename($src, 'w', $use_prefix, $relative);
  1021. $dest = $this->_getFilename($dest, 'w', $use_prefix, $relative);
  1022. if ($context)
  1023. {
  1024. // Use the provided context
  1025. $res = @copy($src, $dest, $context);
  1026. }
  1027. elseif ($this->context)
  1028. {
  1029. // Use the objects context
  1030. $res = @copy($src, $dest, $this->context);
  1031. }
  1032. else
  1033. {
  1034. // Don't use any context
  1035. $res = @copy($src, $dest);
  1036. }
  1037. if (!$res && $php_errormsg)
  1038. {
  1039. $this->setError($php_errormsg);
  1040. }
  1041. else
  1042. {
  1043. $this->chmod($chmodDest);
  1044. }
  1045. // Restore error tracking to what it was before
  1046. ini_set('track_errors', $track_errors);
  1047. return $res;
  1048. }
  1049. /**
  1050. * Moves a file
  1051. *
  1052. * @param string $src The file path to move from.
  1053. * @param string $dest The file path to move to.
  1054. * @param resource $context A valid context resource (optional) created with stream_context_create.
  1055. * @param boolean $use_prefix Controls the use of a prefix (optional).
  1056. * @param boolean $relative Determines if the filename given is relative. Relative paths do not have JPATH_ROOT stripped.
  1057. *
  1058. * @return mixed
  1059. *
  1060. * @since 11.1
  1061. */
  1062. public function move($src, $dest, $context = null, $use_prefix = true, $relative = false)
  1063. {
  1064. $res = false;
  1065. // Capture PHP errors
  1066. $php_errormsg = '';
  1067. $track_errors = ini_get('track_errors');
  1068. ini_set('track_errors', true);
  1069. $src = $this->_getFilename($src, 'w', $use_prefix, $relative);
  1070. $dest = $this->_getFilename($dest, 'w', $use_prefix, $relative);
  1071. if ($context)
  1072. {
  1073. // Use the provided context
  1074. $res = @rename($src, $dest, $context);
  1075. }
  1076. elseif ($this->context)
  1077. {
  1078. // Use the object's context
  1079. $res = @rename($src, $dest, $this->context);
  1080. }
  1081. else
  1082. {
  1083. // Don't use any context
  1084. $res = @rename($src, $dest);
  1085. }
  1086. if (!$res && $php_errormsg)
  1087. {
  1088. $this->setError($php_errormsg());
  1089. }
  1090. $this->chmod($dest);
  1091. // Restore error tracking to what it was before
  1092. ini_set('track_errors', $track_errors);
  1093. return $res;
  1094. }
  1095. /**
  1096. * Delete a file
  1097. *
  1098. * @param string $filename The file path to delete.
  1099. * @param resource $context A valid context resource (optional) created with stream_context_create.
  1100. * @param boolean $use_prefix Controls the use of a prefix (optional).
  1101. * @param boolean $relative Determines if the filename given is relative. Relative paths do not have JPATH_ROOT stripped.
  1102. *
  1103. * @return mixed
  1104. *
  1105. * @since 11.1
  1106. */
  1107. public function delete($filename, $context = null, $use_prefix = true, $relative = false)
  1108. {
  1109. $res = false;
  1110. // Capture PHP errors
  1111. $php_errormsg = '';
  1112. $track_errors = ini_get('track_errors');
  1113. ini_set('track_errors', true);
  1114. $filename = $this->_getFilename($filename, 'w', $use_prefix, $relative);
  1115. if ($context)
  1116. {
  1117. // Use the provided context
  1118. $res = @unlink($filename, $context);
  1119. }
  1120. elseif ($this->context)
  1121. {
  1122. // Use the object's context
  1123. $res = @unlink($filename, $this->context);
  1124. }
  1125. else
  1126. {
  1127. // Don't use any context
  1128. $res = @unlink($filename);
  1129. }
  1130. if (!$res && $php_errormsg)
  1131. {
  1132. $this->setError($php_errormsg());
  1133. }
  1134. // Restore error tracking to what it was before.
  1135. ini_set('track_errors', $track_errors);
  1136. return $res;
  1137. }
  1138. /**
  1139. * Upload a file
  1140. *
  1141. * @param string $src The file path to copy from (usually a temp folder).
  1142. * @param string $dest The file path to copy to.
  1143. * @param resource $context A valid context resource (optional) created with stream_context_create.
  1144. * @param boolean $use_prefix Controls the use of a prefix (optional).
  1145. * @param boolean $relative Determines if the filename given is relative. Relative paths do not have JPATH_ROOT stripped.
  1146. *
  1147. * @return mixed
  1148. *
  1149. * @since 11.1
  1150. */
  1151. public function upload($src, $dest, $context = null, $use_prefix = true, $relative = false)
  1152. {
  1153. if (is_uploaded_file($src))
  1154. {
  1155. // Make sure it's an uploaded file
  1156. return $this->copy($src, $dest, $context, $use_prefix, $relative);
  1157. }
  1158. else
  1159. {
  1160. $this->setError(JText::_('JLIB_FILESYSTEM_ERROR_STREAMS_NOT_UPLOADED_FILE'));
  1161. return false;
  1162. }
  1163. }
  1164. /**
  1165. * Writes a chunk of data to a file.
  1166. *
  1167. * @param string $filename The file name.
  1168. * @param string &$buffer The data to write to the file.
  1169. *
  1170. * @return boolean
  1171. *
  1172. * @since 11.1
  1173. */
  1174. public function writeFile($filename, &$buffer)
  1175. {
  1176. if ($this->open($filename, 'w'))
  1177. {
  1178. $result = $this->write($buffer);
  1179. $this->chmod();
  1180. $this->close();
  1181. return $result;
  1182. }
  1183. return false;
  1184. }
  1185. /**
  1186. * Determine the appropriate 'filename' of a file
  1187. *
  1188. * @param string $filename Original filename of the file
  1189. * @param string $mode Mode string to retrieve the filename
  1190. * @param boolean $use_prefix Controls the use of a prefix
  1191. * @param boolean $relative Determines if the filename given is relative. Relative paths do not have JPATH_ROOT stripped.
  1192. *
  1193. * @return string
  1194. *
  1195. * @since 11.1
  1196. */
  1197. public function _getFilename($filename, $mode, $use_prefix, $relative)
  1198. {
  1199. if ($use_prefix)
  1200. {
  1201. // Get rid of binary or t, should be at the end of the string
  1202. $tmode = trim($mode, 'btf123456789');
  1203. // Check if it's a write mode then add the appropriate prefix
  1204. // Get rid of JPATH_ROOT (legacy compat) along the way
  1205. if (in_array($tmode, JFilesystemHelper::getWriteModes()))
  1206. {
  1207. if (!$relative && $this->writeprefix)
  1208. {
  1209. $filename = str_replace(JPATH_ROOT, '', $filename);
  1210. }
  1211. $filename = $this->writeprefix . $filename;
  1212. }
  1213. else
  1214. {
  1215. if (!$relative && $this->readprefix)
  1216. {
  1217. $filename = str_replace(JPATH_ROOT, '', $filename);
  1218. }
  1219. $filename = $this->readprefix . $filename;
  1220. }
  1221. }
  1222. return $filename;
  1223. }
  1224. /**
  1225. * Return the internal file handle
  1226. *
  1227. * @return File handler
  1228. *
  1229. * @since 11.1
  1230. */
  1231. public function getFileHandle()
  1232. {
  1233. return $this->fh;
  1234. }
  1235. }