Joomla! PHP Cross Reference Web Portals

Source: /libraries/joomla/filesystem/stream.php - 1423 lines - 31072 bytes - Summary - Text - Print

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

title

Description

title

Description

title

Description

title

title

Body