PageRenderTime 41ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/mc/rt_missioncontrol_j15/lib/updater/libraries/joomla/filesystem/stream.php

https://github.com/bhar1red/anahita
PHP | 1004 lines | 666 code | 70 blank | 268 comment | 110 complexity | f7e173dbbb0b23774389fea144091808 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * Joomla! Stream Interface
  4. *
  5. * The Joomla! stream interface is designed to handle files as streams
  6. * where as the legacy JFile static class treated files in a rather
  7. * atomic manner.
  8. *
  9. * This class adheres to the stream wrapper operations:
  10. * http://www.php.net/manual/en/function.stream-get-wrappers.php
  11. *
  12. * PHP5
  13. *
  14. * Created on Sep 17, 2008
  15. *
  16. * @package Joomla!
  17. * @license GNU General Public License version 2 or later; see LICENSE.txt
  18. * @copyright 2008 OpenSourceMatters.org
  19. * @version SVN: $Id: stream.php 12276 2009-06-22 01:54:01Z pasamio $
  20. */
  21. // Check to ensure this file is within the rest of the framework
  22. defined('JPATH_BASE') or die();
  23. RokUpdater::import('joomla.filesystem.helper');
  24. RokUpdater::import('joomla.utilities.utility');
  25. /**
  26. * Joomla! Stream Class
  27. * @see http://au.php.net/manual/en/intro.stream.php PHP Stream Manual
  28. * @see http://au.php.net/manual/en/wrappers.php Stream Wrappers
  29. * @see http://au.php.net/manual/en/filters.php Stream Filters
  30. * @see http://au.php.net/manual/en/transports.php Socket Transports (used by some options, particularly HTTP proxy)
  31. */
  32. class JStream extends JObject
  33. {
  34. // Publicly settable vars (protected to let our parent read them)
  35. /** @var File Mode */
  36. protected $filemode = 0644;
  37. /** @var Directory Mode */
  38. protected $dirmode = 0755;
  39. /** @var Default Chunk Size */
  40. protected $chunksize = 8192;
  41. /** @var Filename */
  42. protected $filename;
  43. /** @var Prefix of the connection for writing */
  44. protected $writeprefix;
  45. /** @var Prefix of the connection for reading */
  46. protected $readprefix;
  47. /** @var Read Processing method: gz, bz, f
  48. * If a scheme is detected, fopen will be defaulted
  49. * To use compression with a network stream use a filter
  50. */
  51. protected $processingmethod = 'f';
  52. /** @var array Filters applied to the current stream */
  53. protected $filters = Array();
  54. // Private vars
  55. /** @var File Handle */
  56. private $_fh;
  57. /** @var File size */
  58. private $_filesize;
  59. /** @var Context to use when opening the connection */
  60. private $_context = null;
  61. /** @var Context options; used to rebuild the context */
  62. private $_contextOptions;
  63. /** @var The mode under which the file was opened */
  64. private $_openmode;
  65. /**
  66. * Constructor
  67. * @param string Prefix of the stream; Note: unlike the JPATH_*, this has a final path seperator!
  68. */
  69. function __construct($writeprefix='', $readprefix='', $context=Array())
  70. {
  71. $this->writeprefix = $writeprefix;
  72. $this->readprefix = $readprefix;
  73. $this->_contextOptions = $context;
  74. $this->_buildContext();
  75. }
  76. /**
  77. * Destructor
  78. */
  79. function __destruct() {
  80. // attempt to close on destruction if there is a file handle
  81. if($this->_fh) @$this->close();
  82. }
  83. // ----------------------------
  84. // Generic File Operations
  85. // ----------------------------
  86. /**
  87. * Open a stream with some lazy loading smarts
  88. * @param string Filename
  89. * @param string Mode string to use
  90. * @param bool Use the PHP include path
  91. * @param resource Context to use when opening
  92. * @param bool Use a prefix to open the file
  93. * @param bool Filename is a relative path (if false, strips JPATH_ROOT to make it relative)
  94. * @param bool Detect the processing method for the file and use the appropriate function to handle output automatically
  95. */
  96. function open($filename, $mode='r', $use_include_path=false, $context=null, $use_prefix=true, $relative=false, $detectprocessingmode=false)
  97. {
  98. $filename = $this->_getFilename($filename, $mode, $use_prefix, $relative);
  99. if(!$filename)
  100. {
  101. $this->setError(JText::_('No filename set'));
  102. return false;
  103. }
  104. $this->filename = $filename;
  105. $this->_openmode = $mode;
  106. $url = parse_url($filename);
  107. $retval = false;
  108. if(isset($url['scheme']))
  109. {
  110. // if we're dealing with a Joomla! stream, load it
  111. if(JFilesystemHelper::isJoomlaStream($url['scheme'])) {
  112. require_once(dirname(__FILE__).DS.'streams'.DS.$url['scheme'].'.php');
  113. }
  114. // we have a scheme! force the method to be f
  115. $this->processingmethod = 'f';
  116. }
  117. else if($detectprocessingmode)
  118. {
  119. $ext = strtolower(JFile::getExt($this->filename));
  120. switch ($ext)
  121. {
  122. case 'tgz' :
  123. case 'gz' :
  124. case 'gzip' :
  125. $this->processingmethod = 'gz';
  126. break;
  127. case 'tbz2' :
  128. case 'bz2' :
  129. case 'bzip2':
  130. $this->processingmethod = 'bz';
  131. break;
  132. default:
  133. $this->processingmethod = 'f';
  134. break;
  135. }
  136. }
  137. // Capture PHP errors
  138. $php_errormsg = 'Error Unknown whilst opening a file';
  139. $track_errors = ini_get('track_errors');
  140. ini_set('track_errors', true);
  141. // Decide which context to use:
  142. switch($this->processingmethod)
  143. {
  144. case 'gz': // gzip doesn't support contexts or streams
  145. $this->_fh = gzopen($filename, $mode, $use_include_path);
  146. break;
  147. case 'bz': // bzip2 is much like gzip except it doesn't use the include path
  148. $this->_fh = bzopen($filename, $mode);
  149. break;
  150. case 'f': // fopen can handle streams
  151. default:
  152. if($context) { // one supplied at open; overrides everything
  153. $this->_fh = fopen($filename, $mode, $use_include_path, $context);
  154. } else if ($this->_context) { // one provided at initialisation
  155. $this->_fh = fopen($filename, $mode, $use_include_path, $this->_context);
  156. } else { // no context; all defaults
  157. $this->_fh = fopen($filename, $mode, $use_include_path);
  158. }
  159. break;
  160. }
  161. if(!$this->_fh) {
  162. $this->setError($php_errormsg);
  163. } else {
  164. $retval = true;
  165. }
  166. // restore error tracking to what it was before
  167. ini_set('track_errors',$track_errors);
  168. // return the result
  169. return $retval;
  170. }
  171. /**
  172. * Attempt to close a file handle
  173. * Will return false if it failed and true on success
  174. * Note: if the file is not open the system will return true
  175. * Note: this function destroys the file handle as well
  176. */
  177. function close()
  178. {
  179. if(!$this->_fh)
  180. {
  181. $this->setError(JText::_('File not open'));
  182. return true;
  183. }
  184. $retval = false;
  185. // Capture PHP errors
  186. $php_errormsg = 'Error Unknown';
  187. $track_errors = ini_get('track_errors');
  188. ini_set('track_errors', true);
  189. switch($this->processingmethod)
  190. {
  191. case 'gz':
  192. $res = gzclose($this->_fh);
  193. break;
  194. case 'bz':
  195. $res = bzclose($this->_fh);
  196. break;
  197. case 'f':
  198. default:
  199. $res = fclose($this->_fh);
  200. break;
  201. }
  202. if(!$res) {
  203. $this->setError($php_errormsg);
  204. }
  205. else
  206. {
  207. $this->_fh = null; // reset this
  208. $retval = true;
  209. }
  210. // chmod the file after its closed if we wrote
  211. if($this->_openmode[0] == 'w') {
  212. $this->chmod();
  213. }
  214. // restore error tracking to what it was before
  215. ini_set('track_errors',$track_errors);
  216. // return the result
  217. return $retval;
  218. }
  219. /**
  220. * Work out if we're at the end of the file for a stream
  221. */
  222. function eof()
  223. {
  224. if(!$this->_fh)
  225. {
  226. $this->setError(JText::_('File not open'));
  227. return false;
  228. }
  229. $retval = false;
  230. // Capture PHP errors
  231. $php_errormsg = '';
  232. $track_errors = ini_get('track_errors');
  233. ini_set('track_errors', true);
  234. switch($this->processingmethod)
  235. {
  236. case 'gz':
  237. $res = gzeof($this->_fh);
  238. break;
  239. case 'bz':
  240. case 'f':
  241. default:
  242. $res = feof($this->_fh);
  243. break;
  244. }
  245. if($php_errormsg) {
  246. $this->setError($php_errormsg);
  247. }
  248. // restore error tracking to what it was before
  249. ini_set('track_errors',$track_errors);
  250. // return the result
  251. return $res;
  252. }
  253. /**
  254. * Retrieve the file size of the path
  255. */
  256. function filesize()
  257. {
  258. if(!$this->filename)
  259. {
  260. $this->setError(JText::_('File not open'));
  261. return false;
  262. }
  263. $retval = false;
  264. // Capture PHP errors
  265. $php_errormsg = '';
  266. $track_errors = ini_get('track_errors');
  267. ini_set('track_errors', true);
  268. $res = @filesize($this->filename);
  269. if(!$res)
  270. {
  271. $tmp_error = '';
  272. if($php_errormsg) { // some bad went wrong
  273. $tmp_error = $php_errormsg; // store the error in case we need it
  274. }
  275. $res = JFilesystemHelper::remotefsize($this->filename);
  276. if(!$res)
  277. {
  278. if($tmp_error) { // use the php_errormsg from before
  279. $this->setError($tmp_error);
  280. } else { // error but nothing from php? how strange! create our own
  281. $this->setError(JText::_('Failed to get file size. This may not work for all streams!'));
  282. }
  283. }
  284. else
  285. {
  286. $this->_filesize = $res;
  287. $retval = $res;
  288. }
  289. }
  290. else
  291. {
  292. $this->_filesize = $res;
  293. $retval = $res;
  294. }
  295. // restore error tracking to what it was before
  296. ini_set('track_errors',$track_errors);
  297. // return the result
  298. return $retval;
  299. }
  300. function gets($length=0)
  301. {
  302. if(!$this->_fh)
  303. {
  304. $this->setError(JText::_('File not open'));
  305. return false;
  306. }
  307. $retval = false;
  308. // Capture PHP errors
  309. $php_errormsg = 'Error Unknown';
  310. $track_errors = ini_get('track_errors');
  311. ini_set('track_errors', true);
  312. switch($this->processingmethod)
  313. {
  314. case 'gz':
  315. $res = $length ? gzgets($this->_fh, $length) : gzgets($this->_fh);
  316. break;
  317. case 'bz':
  318. case 'f':
  319. default:
  320. $res = $length ? fgets($this->_fh, $length) : fgets($this->_fh);
  321. break;
  322. }
  323. if(!$res) {
  324. $this->setError($php_errormsg);
  325. } else {
  326. $retval = $res;
  327. }
  328. // restore error tracking to what it was before
  329. ini_set('track_errors',$track_errors);
  330. // return the result
  331. return $retval;
  332. }
  333. /**
  334. * Read a file
  335. * Handles user space streams appropriately otherwise any read will return 8192
  336. * @param int length of data to read
  337. * @see http://www.php.net/manual/en/function.fread.php
  338. */
  339. function read($length=0)
  340. {
  341. if(!$this->_filesize && !$length)
  342. {
  343. $this->filesize(); // get the filesize
  344. if(!$this->_filesize) {
  345. $length = -1; // set it to the biggest and then wait until eof
  346. } else {
  347. $length = $this->_filesize;
  348. }
  349. }
  350. if(!$this->_fh)
  351. {
  352. $this->setError(JText::_('File not open'));
  353. return false;
  354. }
  355. $retval = false;
  356. // Capture PHP errors
  357. $php_errormsg = 'Error Unknown';
  358. $track_errors = ini_get('track_errors');
  359. ini_set('track_errors', true);
  360. $remaining = $length;
  361. do {
  362. // do chunked reads where relevant
  363. switch($this->processingmethod)
  364. {
  365. case 'bz':
  366. $res = ($remaining > 0) ? bzread($this->_fh, $remaining) : bzread($this->_fh, $this->chunksize);
  367. break;
  368. case 'gz':
  369. $res = ($remaining > 0) ? gzread($this->_fh, $remaining) : gzread($this->_fh, $this->chunksize);
  370. break;
  371. case 'f':
  372. default:
  373. $res = ($remaining > 0) ? fread($this->_fh, $remaining) : fread($this->_fh, $this->chunksize);
  374. break;
  375. }
  376. if(!$res)
  377. {
  378. $this->setError($php_errormsg);
  379. $remaining = 0; // jump from the loop
  380. } else
  381. {
  382. if(!$retval) $retval = '';
  383. $retval .= $res;
  384. if(!$this->eof())
  385. {
  386. $len = strlen($res);
  387. $remaining -= $len;
  388. }
  389. else
  390. {
  391. // if its the end of the file then we've nothing left to read; reset remaining and len
  392. $remaining = 0;
  393. $length = strlen($retval);
  394. }
  395. }
  396. } while($remaining || !$length);
  397. // restore error tracking to what it was before
  398. ini_set('track_errors',$track_errors);
  399. // return the result
  400. return $retval;
  401. }
  402. /**
  403. * Seek the file
  404. * Note: the return value is different to that of fseek
  405. * @param int Offset to use when seeking
  406. * @param int Seek mode to use
  407. * @return boolean True on success, false on failure
  408. * @see http://www.php.net/manual/en/function.fseek.php
  409. */
  410. function seek($offset, $whence=SEEK_SET)
  411. {
  412. if(!$this->_fh)
  413. {
  414. $this->setError(JText::_('File not open'));
  415. return false;
  416. }
  417. $retval = false;
  418. // Capture PHP errors
  419. $php_errormsg = '';
  420. $track_errors = ini_get('track_errors');
  421. ini_set('track_errors', true);
  422. switch($this->processingmethod)
  423. {
  424. case 'gz':
  425. $res = gzseek($this->_fh, $offset, $whence);
  426. break;
  427. case 'bz':
  428. case 'f':
  429. default:
  430. $res = fseek($this->_fh, $offset, $whence);
  431. break;
  432. }
  433. // seek, interestingly returns 0 on success or -1 on failure
  434. if($res == -1) {
  435. $this->setError($php_errormsg);
  436. } else {
  437. $retval = true;
  438. }
  439. // restore error tracking to what it was before
  440. ini_set('track_errors',$track_errors);
  441. // return the result
  442. return $retval;
  443. }
  444. function tell()
  445. {
  446. if(!$this->_fh)
  447. {
  448. $this->setError(JText::_('File not open'));
  449. return false;
  450. }
  451. $res = false;
  452. // Capture PHP errors
  453. $php_errormsg = '';
  454. $track_errors = ini_get('track_errors');
  455. ini_set('track_errors', true);
  456. switch($this->processingmethod)
  457. {
  458. case 'gz':
  459. $res = gztell($this->_fh);
  460. break;
  461. case 'bz':
  462. case 'f':
  463. default:
  464. $res = ftell($this->_fh);
  465. break;
  466. }
  467. // may return 0 so check its really false
  468. if($res === FALSE) {
  469. $this->setError($php_errormsg);
  470. }
  471. // restore error tracking to what it was before
  472. ini_set('track_errors',$track_errors);
  473. // return the result
  474. return $res;
  475. }
  476. /**
  477. * File write
  478. * Note: Whilst this function accepts a reference, the underlying fwrite
  479. * will do a copy! This will roughly double the memory allocation for
  480. * any write you do. Specifying chunked will get around this by only
  481. * writing in specific chunk sizes. This defaults to 8192 which is a
  482. * sane number to use most of the time (change the default with
  483. * JStream::set('chunksize', newsize);)
  484. * Note: This doesn't support gzip/bzip2 writing like reading does
  485. * @param string Reference to the string to write
  486. * @param int Length of the string to write
  487. * @param int Size of chunks to write in
  488. * @see http://www.php.net/manual/en/function.fwrite.php
  489. */
  490. function write(&$string, $length=0, $chunk=0)
  491. {
  492. if(!$this->_fh)
  493. {
  494. $this->setError(JText::_('File not open'));
  495. return false;
  496. }
  497. // if the length isn't set, set it to the length of the string
  498. if(!$length) $length = strlen($string);
  499. // if the chunk isn't set, set it to the default
  500. if(!$chunk) $chunk = $this->chunksize;
  501. $retval = true;
  502. // Capture PHP errors
  503. $php_errormsg = '';
  504. $track_errors = ini_get('track_errors');
  505. ini_set('track_errors', true);
  506. $remaining = $length;
  507. do {
  508. // if the amount remaining is greater than the chunk size, then use the chunk
  509. $amount = ($remaining > $chunk) ? $chunk : $remaining;
  510. $res = fwrite($this->_fh, $string, $amount);
  511. // returns false on error or the number of bytes written
  512. if($res === false)
  513. { // returned error
  514. $this->setError($php_errormsg);
  515. $retval = false;
  516. $remaining = 0;
  517. }
  518. else if($res === 0)
  519. { // wrote nothing?
  520. $remaining = 0;
  521. $this->setError('Warning: No data written');
  522. } else
  523. { // wrote something
  524. $remaining -= $res;
  525. }
  526. } while($remaining);
  527. // restore error tracking to what it was before
  528. ini_set('track_errors',$track_errors);
  529. // return the result
  530. return $retval;
  531. }
  532. /**
  533. * chmod wrapper
  534. * @param mixed Mode to use
  535. */
  536. function chmod($filename='', $mode=0)
  537. {
  538. if(!$filename)
  539. {
  540. if(!isset($this->filename) || !$this->filename) {
  541. $this->setError(JText::_('Filename not set'));
  542. return false;
  543. }
  544. $filename = $this->filename;
  545. }
  546. // if no mode is set use the default
  547. if(!$mode) $mode = $this->filemode;
  548. $retval = false;
  549. // Capture PHP errors
  550. $php_errormsg = '';
  551. $track_errors = ini_get('track_errors');
  552. ini_set('track_errors', true);
  553. $sch = parse_url($filename, PHP_URL_SCHEME);
  554. // scheme specific options; ftp's chmod support is fun
  555. switch($sch)
  556. {
  557. case 'ftp':
  558. case 'ftps':
  559. $res = JFilesystemHelper::ftpChmod($filename, $mode);
  560. break;
  561. default:
  562. //echo '<p>Chmodding '. $filename . ' with ' . decoct($mode) .'</p>';
  563. $res = chmod($filename, $mode);
  564. break;
  565. }
  566. // seek, interestingly returns 0 on success or -1 on failure
  567. if(!$res) {
  568. $this->setError($php_errormsg);
  569. } else {
  570. $retval = true;
  571. }
  572. // restore error tracking to what it was before
  573. ini_set('track_errors',$track_errors);
  574. // return the result
  575. return $retval;
  576. }
  577. /**
  578. * Get the stream metadata
  579. * @see http://au.php.net/manual/en/function.stream-get-meta-data.php
  580. * @return array header/metadata
  581. */
  582. function get_meta_data()
  583. {
  584. if(!$this->_fh)
  585. {
  586. $this->setError(JText::_('File not open'));
  587. return false;
  588. }
  589. return stream_get_meta_data($this->_fh);
  590. }
  591. // ----------------------------
  592. // Stream contexts
  593. // ----------------------------
  594. /**
  595. * Builds the context from the array
  596. */
  597. function _buildContext()
  598. {
  599. // according to the manual this always works!
  600. if(count($this->_contextOptions)) {
  601. $this->_context = @stream_context_create($this->_contextOptions);
  602. } else {
  603. $this->_context = null;
  604. }
  605. }
  606. /**
  607. * Updates the context to the array
  608. * Format is the same as the options for stream_context_create
  609. * @param Array Options to create the context with
  610. * @see http://www.php.net/stream_context_create
  611. */
  612. function setContextOptions($context)
  613. {
  614. $this->_contextOptions = $context;
  615. $this->_buildContext();
  616. }
  617. /**
  618. * Adds a particular options to the context
  619. * @param string The wrapper to use
  620. * @param string The option to set
  621. * @param string The value of the option
  622. * @see http://www.php.net/stream_context_create Stream Context Creation
  623. * @see http://au.php.net/manual/en/context.php Context Options for various streams
  624. */
  625. function addContextEntry($wrapper, $name, $value)
  626. {
  627. $this->_contextOptions[$wrapper][$name] = $value;
  628. $this->_buildContext();
  629. }
  630. /**
  631. * Deletes a particular setting from a context
  632. * @param string The wrapper to use
  633. * @param string The option to unset
  634. * @see http://www.php.net/stream_context_create
  635. */
  636. function deleteContextEntry($wrapper, $name)
  637. {
  638. // check the wrapper is set
  639. if(isset($this->_contextOptions[$wrapper]))
  640. {
  641. // check that entry is set for that wrapper
  642. if(isset($this->_contextOptions[$wrapper][$name]))
  643. {
  644. // unset the item
  645. unset($this->_contextOptions[$wrapper][$name]);
  646. // check that there are still items there
  647. if(!count($this->_contextOptions[$wrapper])) {
  648. // clean up an empty wrapper context option
  649. unset($this->_contextOptions[$wrapper]);
  650. }
  651. }
  652. }
  653. // rebuild the context and apply it to the stream
  654. $this->_buildContext();
  655. }
  656. /**
  657. * Applies the current context to the stream
  658. * Use this to change the values of the context after you've opened a stream
  659. */
  660. function applyContextToStream()
  661. {
  662. $retval = false;
  663. if($this->_fh)
  664. {
  665. // Capture PHP errors
  666. $php_errormsg = 'Unknown error setting context option';
  667. $track_errors = ini_get('track_errors');
  668. ini_set('track_errors', true);
  669. $retval = @stream_context_set_option($this->_fh, $this->_contextOptions);
  670. if(!$retval) {
  671. $this->setError($php_errormsg);
  672. }
  673. // restore error tracking to what it was before
  674. ini_set('track_errors',$track_errors);
  675. }
  676. return $retval;
  677. }
  678. // ----------------------------
  679. // Stream filters
  680. // ----------------------------
  681. /**
  682. * Append a filter to the chain
  683. * @param
  684. * @see http://www.php.net/manual/en/function.stream-filter-append.php
  685. */
  686. function &appendFilter($filtername, $read_write=STREAM_FILTER_READ, $params=Array() )
  687. {
  688. $res = false;
  689. if($this->_fh)
  690. {
  691. // Capture PHP errors
  692. $php_errormsg = '';
  693. $track_errors = ini_get('track_errors');
  694. ini_set('track_errors', true);
  695. $res = @stream_filter_append($this->_fh, $filtername, $read_write, $params);
  696. if(!$res && $php_errormsg) {
  697. $this->setError($php_errormsg);
  698. } else {
  699. $this->filters[] =& $res;
  700. }
  701. // restore error tracking to what it was before
  702. ini_set('track_errors',$track_errors);
  703. }
  704. return $res;
  705. }
  706. function &prependFilter($filtername, $read_write=STREAM_FILTER_READ, $params=Array() )
  707. {
  708. $res = false;
  709. if($this->_fh)
  710. {
  711. // Capture PHP errors
  712. $php_errormsg = '';
  713. $track_errors = ini_get('track_errors');
  714. ini_set('track_errors', true);
  715. $res = @stream_filter_prepend($this->_fh, $filername, $read_write, $params);
  716. if(!$res && $php_errormsg) $this->setError($php_errormsg); // set the error msg
  717. else JUtility::array_unshift_ref($res, $this->filters); // push the new resource onto the filter stack
  718. // restore error tracking to what it was before
  719. ini_set('track_errors',$track_errors);
  720. }
  721. return $res;
  722. }
  723. /**
  724. * Remove a filter, either by resource (handed out from the
  725. * append or prepend function alternatively via getting the
  726. * filter list)
  727. * @return bool Result of operation
  728. */
  729. function removeFilter(&$resource, $byindex=false)
  730. {
  731. $res = false;
  732. // Capture PHP errors
  733. $php_errormsg = '';
  734. $track_errors = ini_get('track_errors');
  735. ini_set('track_errors', true);
  736. if($byindex) {
  737. $res = stream_filter_remove($this->filters[$resource]);
  738. } else {
  739. $res = stream_filter_remove($resource);
  740. }
  741. if($res && $php_errormsg) {
  742. $this->setError($php_errormsg);
  743. }
  744. // restore error tracking to what it was before
  745. ini_set('track_errors',$track_errors);
  746. return $res;
  747. }
  748. // ----------------------------
  749. // Support operations (copy, move)
  750. // ----------------------------
  751. /**
  752. * Copy a file from src to dest
  753. */
  754. function copy($src, $dest, $context=null, $use_prefix=true, $relative=false)
  755. {
  756. $res = false;
  757. // Capture PHP errors
  758. $php_errormsg = '';
  759. $track_errors = ini_get('track_errors');
  760. ini_set('track_errors', true);
  761. $chmodDest = $this->_getFilename($dest, 'w', $use_prefix, $relative);
  762. $exists = file_exists($dest);
  763. $context_support = version_compare(PHP_VERSION, '5.3', '>='); // 5.3 provides context support
  764. if($exists && !$context_support)
  765. {
  766. // the file exists and there is no context support
  767. // this could cause a failure as we may need to overwrite the file
  768. // so we write our own copy function that will work with a stream
  769. // context; php 5.3 will fix this for us (yay!)
  770. // Note: since open processes the filename for us we won't worry about
  771. // calling _getFilename
  772. $res = $this->open($src);
  773. if($res) {
  774. $reader = $this->_fh;
  775. $res = $this->open($dest, 'w');
  776. if($res)
  777. {
  778. $res = stream_copy_to_stream($reader, $this->_fh);
  779. $tmperror = $php_errormsg; // save this in case fclose throws an error
  780. @fclose($reader);
  781. $php_errormsg = $tmperror; // restore after fclose
  782. }
  783. else
  784. {
  785. @fclose($reader); // close the reader off
  786. $php_errormsg = JText::_('Failed to open writer') .': '. $this->getError();
  787. }
  788. }
  789. else
  790. {
  791. if(!$php_errormsg) {
  792. $php_errormsg = JText::_('Failed to open reader') .': '. $this->getError();
  793. }
  794. }
  795. }
  796. else
  797. {
  798. // since we're going to open the file directly we need to get the filename
  799. // we need to use the same prefix so force everything to write
  800. $src = $this->_getFilename($src, 'w', $use_prefix, $relative);
  801. $dest = $this->_getFilename($dest, 'w', $use_prefix, $relative);
  802. if($context_support && $context) { // use the provided context
  803. $res = @copy($src, $dest, $context);
  804. } else if($context_support && $this->_context) { // use the objects context
  805. $res = @copy($src, $dest, $this->_context);
  806. } else { // don't use any context
  807. $res = @copy($src, $dest);
  808. }
  809. }
  810. if(!$res && $php_errormsg) {
  811. $this->setError($php_errormsg);
  812. } else {
  813. $this->chmod($chmodDest);
  814. }
  815. // restore error tracking to what it was before
  816. ini_set('track_errors',$track_errors);
  817. return $res;
  818. }
  819. /**
  820. * Moves a file
  821. */
  822. function move($src, $dest, $context=null, $use_prefix=true, $relative=false)
  823. {
  824. $res = false;
  825. // Capture PHP errors
  826. $php_errormsg = '';
  827. $track_errors = ini_get('track_errors');
  828. ini_set('track_errors', true);
  829. $src = $this->_getFilename($src, 'w', $use_prefix, $relative);
  830. $dest = $this->_getFilename($dest, 'w', $use_prefix, $relative);
  831. if($context) { // use the provided context
  832. $res = @rename($src, $dest, $context);
  833. } else if($this->_context) { // use the objects context
  834. $res = @rename($src, $dest, $this->_context);
  835. } else { // don't use any context
  836. $res = @rename($src, $dest);
  837. }
  838. if(!$res && $php_errormsg) {
  839. $this->setError($php_errormsg());
  840. }
  841. $this->chmod($dest);
  842. // restore error tracking to what it was before
  843. ini_set('track_errors',$track_errors);
  844. return $res;
  845. }
  846. /**
  847. * Delete a file
  848. */
  849. function delete($filename, $context=null, $use_prefix=true, $relative=false)
  850. {
  851. $res = false;
  852. // Capture PHP errors
  853. $php_errormsg = '';
  854. $track_errors = ini_get('track_errors');
  855. ini_set('track_errors', true);
  856. $filename = $this->_getFilename($filename, 'w', $use_prefix, $relative);
  857. if($context) { // use the provided context
  858. $res = @unlink($filename, $context);
  859. } else if($this->_context) { // use the objects context
  860. $res = @unlink($filename, $this->_context);
  861. } else { // don't use any context
  862. $res = @unlink($filename);
  863. }
  864. if(!$res && $php_errormsg) {
  865. $this->setError($php_errormsg());
  866. }
  867. // restore error tracking to what it was before
  868. ini_set('track_errors',$track_errors);
  869. return $res;
  870. }
  871. /**
  872. * Upload a file
  873. */
  874. function upload($src, $dest, $context=null, $use_prefix=true, $relative=false)
  875. {
  876. if(is_uploaded_file($src)) { // make sure its an uploaded file
  877. return $this->copy($src, $dest, $context, $use_prefix, $relative);
  878. } else {
  879. $this->setError(JText::_('Not an uploaded file!'));
  880. return false;
  881. }
  882. }
  883. // ----------------------------
  884. // All in one
  885. // ----------------------------
  886. /**
  887. * Writes a chunk of data to a file
  888. */
  889. function writeFile($filename, &$buffer)
  890. {
  891. if($this->open($filename, 'w'))
  892. {
  893. $result = $this->write($buffer);
  894. $this->chmod();
  895. $this->close();
  896. return $result;
  897. }
  898. return false;
  899. }
  900. /**
  901. * Determine the appropriate 'filename' of a file
  902. * @param string Original filename of the file
  903. * @param string Mode string to retrieve the filename
  904. * @param boolean Controls the use of a prefix
  905. * @param boolean Determines if the filename given is relative. Relative paths do not have JPATH_ROOT stripped.
  906. */
  907. function _getFilename($filename, $mode, $use_prefix, $relative)
  908. {
  909. if($use_prefix)
  910. {
  911. // get rid of binary or t, should be at the end of the string
  912. $tmode = trim($mode,'btf123456789');
  913. // check if its a write mode then add the appropriate prefix
  914. // get rid of JPATH_ROOT (legacy compat) along the way
  915. if(in_array($tmode, JFilesystemHelper::getWriteModes()))
  916. {
  917. if(!$relative && $this->writeprefix) $filename = str_replace(JPATH_ROOT, '', $filename);
  918. $filename = $this->writeprefix . $filename;
  919. }
  920. else
  921. {
  922. if(!$relative && $this->readprefix) $filename = str_replace(JPATH_ROOT, '', $filename);
  923. $filename = $this->readprefix . $filename;
  924. }
  925. }
  926. return $filename;
  927. }
  928. /**
  929. * Return the internal file handle
  930. */
  931. function getFileHandle() {
  932. return $this->_fh;
  933. }
  934. }