[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/src/Filesystem/ -> Stream.php (source)

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


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer