| Joomla! | PHP Cross Reference | Web Portals |
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
Body
title
Description
Body
title
Description
Body
title
Body
title