| [ Index ] |
|
Code source de b2evolution 2.1.0-beta |
1 <?php 2 /** 3 * This file implements the Filelist class. 4 * 5 * This file is part of the evoCore framework - {@link http://evocore.net/} 6 * See also {@link http://sourceforge.net/projects/evocms/}. 7 * 8 * @copyright (c)2003-2007 by Francois PLANQUE - {@link http://fplanque.net/} 9 * Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}. 10 * 11 * {@internal License choice 12 * - If you have received this file as part of a package, please find the license.txt file in 13 * the same folder or the closest folder above for complete license terms. 14 * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/) 15 * then you must choose one of the following licenses before using the file: 16 * - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php 17 * - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php 18 * }} 19 * 20 * {@internal Open Source relicensing agreement: 21 * Daniel HAHLER grants Francois PLANQUE the right to license 22 * Daniel HAHLER's contributions to this file and the b2evolution project 23 * under any OSI approved OSS license (http://www.opensource.org/licenses/). 24 * }} 25 * 26 * @package evocore 27 * 28 * {@internal Below is a list of authors who have contributed to design/coding of this file: }} 29 * @author blueyed: Daniel HAHLER 30 * @author fplanque: Francois PLANQUE 31 * 32 * @version $Id: _filelist.class.php,v 1.1 2007/06/25 10:59:55 fplanque Exp $ 33 */ 34 if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' ); 35 36 37 load_class('files/model/_file.class.php'); 38 39 40 /** 41 * Holds a list of File objects. 42 * 43 * Can hold an arbitrary list of Files. 44 * Can list files in a directory by itself. 45 * Can walk recursively down a directory tree to list in "flat mode". 46 * Can sort file list. 47 * Can iterate through list. 48 * Cannot hold files with different root type/ID. 49 * 50 * @see File 51 * @package evocore 52 */ 53 class Filelist 54 { 55 /** 56 * Flat mode? (all files recursive without dirs) 57 * @param boolean 58 */ 59 var $flatmode; 60 61 /** 62 * Do we want to include directories? (This gets used by {@link load()}). 63 * @var boolean 64 */ 65 var $include_dirs = true; 66 67 /** 68 * Do we want to include files? (This gets used by {@link load()}). 69 * @var boolean 70 */ 71 var $include_files = true; 72 73 /** 74 * The root of the file list. 75 * 76 * All files in this list MUST have that same FileRoot. Adding will fail otherwise. 77 * 78 * @var FileRoot 79 */ 80 var $_FileRoot; 81 82 /** 83 * Path to list with trailing slash. 84 * 85 * false if we are constructing an arbitrary list (i-e not tied to a single directory) 86 * fp> should use NULL instead of false 87 * 88 * @var string 89 * @access protected 90 */ 91 var $_ads_list_path = false; 92 93 /** 94 * Path to list reltive to root, with trailing slash 95 * 96 * false if we are constructing an arbitrary list (i-e not tied to a single directory) 97 * fp> should use NULL instead of false 98 * 99 * @param string 100 * @access protected 101 */ 102 var $_rds_list_path = false; 103 104 /** 105 * Filename filter pattern 106 * 107 * Will be matched against the filename part (not the path) 108 * NULL if disabled 109 * 110 * Can be a regular expression (see {@link Filelist::$_filter_is_regexp}), internally with delimiters/modifiers! 111 * 112 * Use {@link set_filter()} to set it. 113 * 114 * @var string 115 * @access protected 116 */ 117 var $_filter = NULL; 118 119 /** 120 * Is the filter a regular expression? NULL if unknown 121 * 122 * Use {@link set_filter()} to set it. 123 * 124 * @see Filelist::$_filter 125 * @var boolean 126 * @access protected 127 */ 128 var $_filter_is_regexp = NULL; 129 130 /** 131 * The list of Files. 132 * @var array 133 * @access protected 134 */ 135 var $_entries = array(); 136 137 /** 138 * Index on File IDs (id => {@link $_entries} key). 139 * 140 * Note: fplanque>> what's the purpose of the md5 IDs?? 141 * 142 * @todo make these direct links to &File objects 143 * @var array 144 * @access protected 145 */ 146 var $_md5_ID_index = array(); 147 148 /** 149 * Index on full paths (path => {@link $_entries} key). 150 * @todo make these direct links to &File objects 151 * @var array 152 * @access protected 153 */ 154 var $_full_path_index = array(); 155 156 /** 157 * Index on (r)elative (s)lash terminated (f)ile/(d)irectory paths (rdfs_path => key into {@link $_entries}). 158 * 159 * @todo make these direct links to &File objects 160 * 161 * @var array 162 * @access protected 163 */ 164 var $_rdfs_rel_path_index = array(); 165 166 /** 167 * Index on sort order (order # => {@link $_entries} key). 168 * @todo make these direct links to &File objects 169 * @var array 170 * @access protected 171 */ 172 var $_order_index = array(); 173 174 /** 175 * Number of entries in the {@link $_entries} array 176 * 177 * Note: $_total_entries = $_total_dirs + $_total_files 178 * 179 * @var integer 180 * @access protected 181 */ 182 var $_total_entries = 0; 183 184 /** 185 * Number of directories 186 * @var integer 187 * @access protected 188 */ 189 var $_total_dirs = 0; 190 191 /** 192 * Number of files 193 * @var integer 194 * @access protected 195 */ 196 var $_total_files = 0; 197 198 /** 199 * Number of bytes 200 * @var integer 201 * @access protected 202 */ 203 var $_total_bytes = 0; 204 205 /** 206 * Index of the current iterator position. 207 * 208 * This is the key of {@link $_order_index} 209 * 210 * @var integer 211 * @access protected 212 */ 213 var $_current_idx = -1; 214 215 /** 216 * What column is the list ordered on? 217 * 218 * Possible values are: 'name', 'path', 'type', 'size', 'lastmod', 'perms' 219 * 220 * @var string 221 * @access protected 222 */ 223 var $_order = NULL; 224 225 /** 226 * Are we sorting ascending (or descending)? 227 * 228 * NULL is default and means ascending for 'name', descending for the rest 229 * 230 * @var boolean 231 * @access protected 232 */ 233 var $_order_asc = NULL; 234 235 /** 236 * User preference: Sort dirs not at top 237 * 238 * @var boolean 239 */ 240 var $_dirs_not_at_top = false; 241 242 /** 243 * User preference: Load and show hidden files? 244 * 245 * "Hidden files" are prefixed with a dot . 246 * 247 * @var boolean 248 */ 249 var $_show_hidden_files = false; 250 251 /** 252 * User preference: recursive size of dirs? 253 * 254 * The load() & sort() methods use this. 255 * 256 * @var boolean 257 * @access protected 258 */ 259 var $_use_recursive_dirsize = false; 260 261 262 /** 263 * Constructor 264 * 265 * @param FileRoot See FileRootCache::get_by_type_and_ID() 266 * @param boolean|string Default path for the files, false if you want to create an arbitrary list; NULL for the Fileroot's ads_path. 267 * @param integer ID of the user, the group or the collection the file belongs to... 268 */ 269 function Filelist( $FileRoot, $path = NULL ) 270 { 271 global $AdminUI; 272 273 if( ! is_object($FileRoot) ) 274 { 275 debug_die( 'Fatal: $FileRoot is no object!' ); 276 } 277 278 if( is_null($path) ) 279 { 280 $path = $FileRoot->ads_path; 281 } 282 $this->_ads_list_path = $path; 283 $this->_FileRoot = & $FileRoot; 284 285 if( ! empty($this->_ads_list_path) ) 286 { 287 // Get the subpath relative to root 288 $this->_rds_list_path = $this->rdfs_relto_root_from_adfs( $this->_ads_list_path ); 289 } 290 } 291 292 293 /** 294 * Loads or reloads the filelist entries. 295 * 296 * NOTE: this does not work for arbitrary lists! 297 * 298 * @todo flatmode always shows hidden files, even if we don't want them :/ 299 * 300 * @uses $flatmode 301 * @return boolean True on sucess, false on failure (not accessible) 302 */ 303 function load() 304 { 305 global $Messages; 306 307 if( !$this->_ads_list_path ) 308 { // We have no path to load from: (happens when FM finds no available root OR we have an arbitrary) 309 // echo 'Cannot load a filelist with no list path' ; 310 return false; 311 } 312 313 // Clears the list (for RE-loads): 314 $this->_total_entries = 0; 315 $this->_total_bytes = 0; 316 $this->_total_files = 0; 317 $this->_total_dirs = 0; 318 $this->_entries = array(); 319 $this->_md5_ID_index = array(); 320 $this->_full_path_index = array(); 321 $this->_rdfs_rel_path_index = array(); 322 $this->_order_index = array(); 323 324 // Attempt list files for requested directory: (recursively if flat mode): 325 if( ($filepath_array = get_filenames( $this->_ads_list_path, $this->include_files, $this->include_dirs, true, $this->flatmode )) === false ) 326 { 327 $Messages->add( sprintf( T_('Cannot open directory «%s»!'), $this->_ads_list_path ), 'fl_error' ); 328 return false; 329 } 330 331 // Loop through file list: 332 foreach( $filepath_array as $adfp_path ) 333 { 334 // Extract the filename from the full path 335 $name = basename( $adfp_path ); 336 337 // Check for hidden status... 338 if( ( ! $this->_show_hidden_files) && (substr($name, 0, 1) == '.') ) 339 { // Do not load & show hidden files (prefixed with .) 340 continue; 341 } 342 343 // Check filter... 344 if( $this->_filter !== NULL ) 345 { // Filter: must match filename 346 if( $this->_filter_is_regexp ) 347 { // Filter is a reg exp: 348 if( ! preg_match( $this->_filter, $name ) ) 349 { // does not match the regexp filter 350 continue; 351 } 352 } 353 else 354 { // Filter is NOT a regexp: 355 if( ! fnmatch( $this->_filter, $name ) ) 356 { 357 continue; 358 } 359 } 360 } 361 362 // Extract the file's relative path to the root 363 $rdfp_path_relto_root = $this->rdfs_relto_root_from_adfs( $adfp_path ); 364 // echo '<br>'.$rdfp_rel_path; 365 366 // Add the file into current list: 367 $this->add_by_subpath( $rdfp_path_relto_root, true ); 368 } 369 370 return true; 371 } 372 373 374 /** 375 * Add a File object to the list (by reference). 376 * 377 * @param File File object (by reference) 378 * @param boolean Has the file to exist to get added? 379 * @return boolean true on success, false on failure 380 */ 381 function add( & $File, $mustExist = false ) 382 { 383 if( !is_a( $File, 'file' ) ) 384 { // Passed object is not a File!! :( 385 return false; 386 } 387 388 // Integrity check: 389 if( $File->_FileRoot->ID != $this->_FileRoot->ID ) 390 { 391 debug_die( 'Adding file '.$File->_FileRoot->ID.':'.$File->get_rdfs_rel_path().' to filelist '.$this->_FileRoot->ID.' : root mismatch!' ); 392 } 393 394 if( $mustExist && ! $File->exists() ) 395 { // File does not exist.. 396 return false; 397 } 398 399 400 $this->_entries[$this->_total_entries] = & $File; 401 $this->_md5_ID_index[$File->get_md5_ID()] = $this->_total_entries; 402 $this->_full_path_index[$File->get_full_path()] = $this->_total_entries; 403 $this->_rdfs_rel_path_index[$File->get_rdfs_rel_path()] = $this->_total_entries; 404 // add file to the end of current list: 405 $this->_order_index[$this->_total_entries] = $this->_total_entries; 406 407 // Count 1 more entry (file or dir) 408 $this->_total_entries++; 409 410 if( $File->is_dir() ) 411 { // Count 1 more directory 412 $this->_total_dirs++; 413 414 // fplanque>> TODO: get this outta here?? 415 // blueyed>> Where does it belong instead? 416 if( $this->_use_recursive_dirsize ) 417 { // We want to use recursive directory sizes 418 // won't be done in the File constructor 419 $File->setSize( get_dirsize_recursive( $File->get_full_path() ) ); 420 } 421 } 422 else 423 { // Count 1 more file 424 $this->_total_files++; 425 } 426 427 // Count total bytes in this dir 428 $this->_total_bytes += $File->get_size(); 429 430 return true; 431 } 432 433 434 /** 435 * Update the name dependent caches 436 * 437 * This is especially useful after a name change of one of the files in the list 438 */ 439 function update_caches() 440 { 441 $this->_md5_ID_index = array(); 442 $this->_full_path_index = array(); 443 $this->_rdfs_rel_path_index = array(); 444 445 $count = 0; 446 foreach( $this->_entries as $loop_File ) 447 { 448 $this->_md5_ID_index[$loop_File->get_md5_ID()] = $count; 449 $this->_full_path_index[$loop_File->get_full_path()] = $count; 450 $this->_rdfs_rel_path_index[$loop_File->get_rdfs_rel_path()] = $count; 451 $count++; 452 } 453 } 454 455 456 /** 457 * Add a file to the list, by filename. 458 * 459 * This is a stub for {@link Filelist::add()}. 460 * 461 * @param string Subpath for this file/folder, relative the associated root, including trailing slash (if directory) 462 * @param boolean Has the file to exist to get added? 463 * @return boolean true on success, false on failure (path not allowed, 464 * file does not exist) 465 */ 466 function add_by_subpath( $rel_path, $mustExist = false ) 467 { 468 $FileCache = & get_Cache( 'FileCache' ); 469 $NewFile = & $FileCache->get_by_root_and_path( $this->_FileRoot->type, $this->_FileRoot->in_type_ID, $rel_path ); 470 471 return $this->add( $NewFile, $mustExist ); 472 } 473 474 475 /** 476 * Sort the entries by sorting the internal {@link $_order_index} array. 477 * 478 * @param string The order to use ('name', 'type', 'lastmod', .. ) 479 * @param boolean Ascending (true) or descending 480 * @param boolean Sort directories at top? 481 */ 482 function sort( $order = NULL, $orderasc = NULL, $dirsattop = NULL ) 483 { 484 if( ! $this->_total_entries ) 485 { 486 return false; 487 } 488 489 if( $order !== NULL ) 490 { // New order 491 $this->_order = $order; 492 } 493 elseif( $this->_order === NULL ) 494 { // Init 495 $this->_order = 'name'; 496 } 497 498 if( $orderasc !== NULL ) 499 { // New ascending/descending setting 500 $this->_order_asc = $orderasc; 501 } 502 elseif( $this->_order_asc === NULL ) 503 { // Init: ascending for 'name' and 'path', else descending 504 $this->_order_asc = ( ( $this->_order == 'name' || $this->_order == 'path' ) ? 1 : 0 ); 505 } 506 507 if( $dirsattop !== NULL ) 508 { 509 $this->_dirs_not_at_top = ! $dirsattop; 510 } 511 512 usort( $this->_order_index, array( $this, '_sort_callback' ) ); 513 514 // Reset the iterator: 515 $this->restart(); 516 } 517 518 519 /** 520 * usort callback function for {@link Filelist::sort()} 521 * 522 * @access protected 523 * @return integer 524 */ 525 function _sort_callback( $a, $b ) 526 { 527 $FileA = & $this->_entries[$a]; 528 $FileB = & $this->_entries[$b]; 529 530 // What colmun are we sorting on? 531 switch( $this->_order ) 532 { 533 case 'size': 534 if( $this->_use_recursive_dirsize ) 535 { // We are using recursive directory sizes: 536 $r = $FileA->get_size() - $FileB->get_size(); 537 } 538 else 539 { 540 $r = $FileA->is_dir() && $FileB->is_dir() ? 541 strcasecmp( $FileA->get_name(), $FileB->get_name() ) : 542 ( $FileA->get_size() - $FileB->get_size() ); 543 } 544 break; 545 546 case 'path': // group by dir 547 $r = strcasecmp( $FileA->get_dir(), $FileB->get_dir() ); 548 if( $r == 0 ) 549 { 550 $r = strcasecmp( $FileA->get_name(), $FileB->get_name() ); 551 } 552 break; 553 554 case 'lastmod': 555 $r = $FileB->get_lastmod_ts() - $FileA->get_lastmod_ts(); 556 break; 557 558 case 'perms': 559 // This will use literal representation ( 'r', 'r+w' / octal ) 560 $r = strcasecmp( $FileA->get_perms(), $FileB->get_perms() ); 561 break; 562 563 case 'fsowner': 564 $r = strcasecmp( $FileA->get_fsowner_name(), $FileB->get_fsowner_name() ); 565 break; 566 567 case 'fsgroup': 568 $r = strcasecmp( $FileA->get_fsgroup_name(), $FileB->get_fsgroup_name() ); 569 break; 570 571 case 'type': 572 if( $r = strcasecmp( $FileA->get_type(), $FileB->get_type() ) ) 573 { 574 break; 575 } 576 // same type: continue to name: 577 default: 578 case 'name': 579 $r = strcasecmp( $FileA->get_name(), $FileB->get_name() ); 580 if( $r == 0 ) 581 { // same name: look at path 582 $r = strcasecmp( $FileA->get_dir(), $FileB->get_dir() ); 583 } 584 break; 585 } 586 587 if( ! $this->_order_asc ) 588 { // We want descending order: switch order 589 $r = - $r; 590 } 591 592 if( ! $this->_dirs_not_at_top ) 593 { // We want dirs to be on top, always: 594 if( $FileA->is_dir() && !$FileB->is_dir() ) 595 { 596 $r = -1; 597 } 598 elseif( $FileB->is_dir() && !$FileA->is_dir() ) 599 { 600 $r = 1; 601 } 602 } 603 604 return $r; 605 } 606 607 608 /** 609 * Get the used order. 610 * 611 * @return string 612 */ 613 function get_sort_order() 614 { 615 return $this->translate_order( $this->_order ); 616 } 617 618 619 /** 620 * Get the link to sort by a column. Handle current order and appends an 621 * icon to reflect the current state (ascending/descending), if the column 622 * is the same we're sorting by. 623 * 624 * @todo get this outta here. This is NOT a displayable object. 625 * We might want to have a "FileListResults" object that derives from Widget/Results/FilteredResults (the more the better) 626 * This object is what the SQL or the ItemQuery object is to Results or to ItemList2. The model and the display should not be mixed. 627 * IF NOT doing the clean objects, move this at least to file.funcs. 628 * 629 * @param string The type (name, path, size, ..) 630 * @param string The text for the anchor. 631 * @return string 632 */ 633 function get_sort_link( $type, $atext ) 634 { 635 global $AdminUI; 636 637 $newAsc = $this->_order == $type ? (1 - $this->is_sorting_asc()) : 1; 638 639 $r = '<a href="'.regenerate_url( 'fm_order,fm_orderasc', 'fm_order='.$type.'&fm_orderasc='.$newAsc ).'" title="'.T_('Change Order').'"'; 640 641 /** 642 * @todo get this outta here. This is NOT a displayable object. 643 * We might want to have a "FileListResults" object that derives from Widget/Results/FilteredResults (the more the better) 644 * This object is what the SQL or the ItemQuery object is to Results or to ItemList2. The model and the display should not be mixed. 645 * IF NOT doing the clean objects, move this at least to file.funcs. 646 */ 647 $result_params = $AdminUI->get_template('Results'); 648 649 650 // Sorting icon: 651 if( $this->_order != $type ) 652 { // Not sorted on this column: 653 $r .= ' class="basic_sort_link">'.$result_params['basic_sort_off']; 654 } 655 elseif( $this->is_sorting_asc($type) ) 656 { // We are sorting on this column , in ascneding order: 657 $r .= ' class="basic_current">'.$result_params['basic_sort_asc']; 658 } 659 else 660 { // Descending order: 661 $r .= ' class="basic_current">'.$result_params['basic_sort_desc']; 662 } 663 664 $r .= ' '.$atext; 665 666 667 return $r.'</a>'; 668 } 669 670 671 /** 672 * Reset the iterator 673 */ 674 function restart() 675 { 676 $this->_current_idx = -1; 677 } 678 679 680 /** 681 * Are we sorting ascending? 682 * 683 * @param string The type (empty for current order type) 684 * @return integer 1 for ascending sorting, 0 for descending 685 */ 686 function is_sorting_asc( $col = '' ) 687 { 688 if( $this->_order_asc === NULL ) 689 { // We have not specified a sort order by now, use default: 690 if( empty($col) ) 691 { 692 $col = $this->_order; 693 } 694 return ( $col == 'name' || $col == 'path' ) ? 1 : 0; 695 } 696 else 697 { // Use previsously specified sort order: 698 return ( $this->_order_asc ) ? 1 : 0; 699 } 700 } 701 702 703 /** 704 * Set the filter. 705 * 706 * @param string Filter string (for regular expressions, if no delimiter/modifiers are included, we try magically adding them) 707 * @param boolean Is the filter a regular expression? (it's a glob pattern otherwise) 708 */ 709 function set_filter( $filter_string, $filter_is_regexp ) 710 { 711 global $Messages; 712 713 $this->_filter_is_regexp = $filter_is_regexp; 714 715 if( $this->_filter_is_regexp && ! empty($filter_string) ) 716 { 717 if( ! is_regexp( $filter_string, true ) ) 718 { 719 // Try with adding delimiters: 720 $filter_string_delim = '~'.str_replace( '~', '\~', $filter_string ).'~'; 721 if( is_regexp( $filter_string_delim, true ) ) 722 { 723 $filter_string = $filter_string_delim; 724 } 725 else 726 { 727 $Messages->add( sprintf( T_('The filter «%s» is not a regular expression.'), $filter_string ), 'fl_error' ); 728 $filter_string = '~.*~'; 729 } 730 } 731 } 732 733 $this->_filter = empty($filter_string) ? NULL : $filter_string; 734 } 735 736 737 /** 738 * Is a filter active? 739 * 740 * @return boolean 741 */ 742 function is_filtering() 743 { 744 return ($this->_filter !== NULL); 745 } 746 747 748 /** 749 * Does the list contain a specific File? 750 * 751 * @param File the File object to look for 752 * @return boolean 753 */ 754 function contains( & $File ) 755 { 756 return isset( $this->_md5_ID_index[ $File->get_md5_ID() ] ); 757 } 758 759 760 /** 761 * Return the current filter 762 * 763 * @param boolean add a note when it's a regexp or no filter? 764 * @return string the filter 765 */ 766 function get_filter( $verbose = true ) 767 { 768 if( $this->_filter === NULL ) 769 { // Filtering is not active 770 return $verbose ? T_('No filter') : ''; 771 } 772 else 773 { // Filtering is active 774 return $this->_filter 775 .( $verbose && $this->_filter_is_regexp ? ' ('.T_('regular expression').')' : '' ); 776 } 777 } 778 779 780 /** 781 * Is the current Filter a regexp? 782 * 783 * @return NULL|boolean true if regexp, NULL if no filter set 784 */ 785 function is_filter_regexp() 786 { 787 return $this->_filter_is_regexp; 788 } 789 790 791 /** 792 * Get the total number of entries in the list. 793 * 794 * @return integer 795 */ 796 function count() 797 { 798 return $this->_total_entries; 799 } 800 801 802 /** 803 * Get the total number of directories in the list 804 * 805 * @return integer 806 */ 807 function count_dirs() 808 { 809 return $this->_total_dirs; 810 } 811 812 813 /** 814 * Get the total number of files in the list 815 * 816 * @return integer 817 */ 818 function count_files() 819 { 820 return $this->_total_files; 821 } 822 823 824 /** 825 * Get the total number of bytes of all files in the list 826 * 827 * @return integer 828 */ 829 function count_bytes() 830 { 831 return $this->_total_bytes; 832 } 833 834 835 /** 836 * Get the next entry and increment internal counter. 837 * 838 * @param string can be used to query only 'file's or 'dir's. 839 * @return File object (by reference) on success, false on end of list 840 */ 841 function & get_next( $type = '' ) 842 { 843 /* 844 * DEBUG: return the same file 10 times, useful for profiling 845 static $debugMakeLonger = 0; 846 if( $debugMakeLonger-- == 0 ) 847 { 848 $this->_current_idx++; 849 $debugMakeLonger = 9; 850 } 851 */ 852 853 if( !isset($this->_order_index[$this->_current_idx + 1]) ) 854 { // End of list: 855 $r = false; 856 return $r; 857 } 858 $this->_current_idx++; 859 860 $index = $this->_order_index[$this->_current_idx]; 861 862 if( $type != '' ) 863 { 864 if( $type == 'dir' && !$this->_entries[ $index ]->is_dir() ) 865 { // we want a dir 866 $r = & $this->get_next( 'dir' ); 867 return $r; 868 } 869 elseif( $type == 'file' && $this->_entries[ $index ]->is_dir() ) 870 { // we want a file 871 $r = & $this->get_next( 'file' ); 872 return $r; 873 } 874 } 875 876 return $this->_entries[ $index ]; 877 } 878 879 880 /** 881 * Get a file by its relative (to root) path. 882 * 883 * @param string the RELATIVE path (with ending slash for directories) 884 * @return mixed File object (by reference) on success, false on failure. 885 */ 886 function & get_by_rdfs_path( $rdfs_path ) 887 { 888 $path = str_replace( '\\', '/', $rdfs_path ); 889 890 if( isset( $this->_rdfs_rel_path_index[ $rdfs_path ] ) ) 891 { 892 return $this->_entries[ $this->_rdfs_rel_path_index[ $rdfs_path ] ]; 893 } 894 else 895 { 896 $r = false; 897 return $r; 898 } 899 } 900 901 902 /** 903 * Get a file by its full path. 904 * 905 * @param string the full/absolute path (with ending slash for directories) 906 * @return mixed File object (by reference) on success, false on failure. 907 */ 908 function & get_by_full_path( $adfs_path ) 909 { 910 $path = str_replace( '\\', '/', $adfs_path ); 911 912 if( isset( $this->_full_path_index[ $adfs_path ] ) ) 913 { 914 return $this->_entries[ $this->_full_path_index[ $adfs_path ] ]; 915 } 916 else 917 { 918 $r = false; 919 return $r; 920 } 921 } 922 923 924 /** 925 * Get a file by it's ID. 926 * 927 * @param string the ID (MD5 of path and name) 928 * @return mixed File object (by reference) on success, false on failure. 929 */ 930 function & get_by_md5_ID( $md5id ) 931 { 932 if( isset( $this->_md5_ID_index[ $md5id ] ) ) 933 { 934 return $this->_entries[ $this->_md5_ID_index[ $md5id ] ]; 935 } 936 else 937 { 938 $r = false; 939 return $r; 940 } 941 } 942 943 944 /** 945 * Get a file by index. 946 * 947 * @param integer Index of the entries (starting with 0) 948 * @param boolean added by fp (set to false when it's a problem) 949 * @return File 950 */ 951 function & get_by_idx( $index, $halt_on_error = true ) 952 { 953 if( isset( $this->_order_index[ $index ] ) ) 954 { 955 return $this->_entries[ $this->_order_index[ $index ] ]; 956 } 957 elseif( !$halt_on_error ) 958 { 959 $r = false; 960 return $r; 961 } 962 963 debug_die( 'Requested file does not exist!' ); 964 } 965 966 967 /** 968 * Get the FileLists FileRoot 969 * 970 * @return FileRoot 971 */ 972 function & get_FileRoot() 973 { 974 return $this->_FileRoot; 975 } 976 977 978 /** 979 * Get the FileLists root type. 980 * 981 * @return string 982 */ 983 function get_root_type() 984 { 985 return $this->_FileRoot->type; 986 } 987 988 989 /** 990 * Get the FileLists root ID (in_type_ID). 991 * 992 * @return FileRoot 993 */ 994 function get_root_ID() 995 { 996 return $this->_FileRoot->in_type_ID; 997 } 998 999 1000 /** 1001 * Get absolute path to list. 1002 */ 1003 function get_ads_list_path() 1004 { 1005 return $this->_ads_list_path; 1006 } 1007 1008 /** 1009 * Get path to list relative to root. 1010 */ 1011 function get_rds_list_path() 1012 { 1013 return $this->_rds_list_path; 1014 } 1015 1016 1017 /** 1018 * Get the path (and name) of a {@link File} relative to the {@link Filelist::$_FileRoot::$ads_path}. 1019 * 1020 * @param string 1021 * @return string 1022 */ 1023 function rdfs_relto_root_from_adfs( $adfs_path ) 1024 { 1025 // Check that the file is inside root: 1026 if( substr( $adfs_path, 0, strlen($this->_FileRoot->ads_path) ) != $this->_FileRoot->ads_path ) 1027 { 1028 debug_die( 'rdfs_relto_root_from_adfs: Path is NOT inside of root!' ); 1029 } 1030 1031 // Return only the relative part: 1032 return substr( $adfs_path, strlen($this->_FileRoot->ads_path) ); 1033 } 1034 1035 1036 /** 1037 * Removes a {@link File} from the entries list. 1038 * 1039 * This handles indexes and number of total entries, bytes, files/dirs. 1040 * 1041 * @return boolean true on success, false if not found in list. 1042 */ 1043 function remove( & $File ) 1044 { 1045 if( isset( $this->_md5_ID_index[ $File->get_md5_ID() ] ) ) 1046 { 1047 $this->_total_entries--; 1048 $this->_total_bytes -= $File->get_size(); 1049 1050 if( $File->is_dir() ) 1051 { 1052 $this->_total_dirs--; 1053 } 1054 else 1055 { 1056 $this->_total_files--; 1057 } 1058 1059 // unset from indexes 1060 $index = $this->_full_path_index[ $File->get_full_path() ]; // current index 1061 unset( $this->_entries[ $this->_md5_ID_index[ $File->get_md5_ID() ] ] ); 1062 unset( $this->_md5_ID_index[ $File->get_md5_ID() ] ); 1063 unset( $this->_full_path_index[ $File->get_full_path() ] ); 1064 unset( $this->_rdfs_rel_path_index[ $File->get_rdfs_rel_path() ] ); 1065 1066 // get the ordered index right: move all next files downwards 1067 $order_key = array_search( $index, $this->_order_index ); 1068 unset( $this->_order_index[$order_key] ); 1069 $this->_order_index = array_values( $this->_order_index ); 1070 1071 if( $this->_current_idx > -1 && $this->_current_idx >= $order_key ) 1072 { // We have removed a file before or at the $order_key'th position 1073 $this->_current_idx--; 1074 } 1075 return true; 1076 } 1077 return false; 1078 } 1079 1080 1081 /** 1082 * Get the list of File entries. 1083 * 1084 * You can use a method on each object to get this as result instead of the object 1085 * itself. 1086 * 1087 * @param string Use this method on every File and put the result into the list. 1088 * @return array The array with the File objects or method results 1089 */ 1090 function get_array( $method = NULL ) 1091 { 1092 $r = array(); 1093 1094 if( is_string($method) ) 1095 { 1096 foreach( $this->_order_index as $index ) 1097 { 1098 $r[] = $this->_entries[ $index ]->$method(); 1099 } 1100 } 1101 else 1102 { 1103 foreach( $this->_order_index as $index ) 1104 { 1105 $r[] = & $this->_entries[ $index ]; 1106 } 1107 } 1108 1109 return $r; 1110 } 1111 1112 1113 /** 1114 * Get a MD5 checksum over the entries. 1115 * Used to identify a unique filelist. 1116 * 1117 * @return string md5 hash 1118 */ 1119 function md5_checksum() 1120 { 1121 return md5( serialize( $this->_entries ) ); 1122 } 1123 1124 1125 /** 1126 * Attempt to load meta data for all files in the list. 1127 * 1128 * Will attempt only once per file and cache the result. 1129 */ 1130 function load_meta() 1131 { 1132 global $DB, $Debuglog; 1133 1134 $to_load = array(); 1135 1136 for( $i=0; $i<count($this->_entries); $i++ ) 1137 { // For each file: 1138 $loop_File = & $this->_entries[$i]; 1139 // echo '<br>'.$loop_File->get_full_path(); 1140 1141 if( $loop_File->meta != 'unknown' ) 1142 { // We have already loaded meta data: 1143 continue; 1144 } 1145 1146 $to_load[] = $DB->quote( $loop_File->get_rdfp_rel_path() ); 1147 } 1148 1149 if( count( $to_load ) ) 1150 { // We have something to load... 1151 /** 1152 * @var FileCache 1153 */ 1154 $FileCache = & get_Cache( 'FileCache' ); 1155 1156 $rows = $DB->get_results( " 1157 SELECT * 1158 FROM T_files 1159 WHERE file_root_type = '".$this->_FileRoot->type."' 1160 AND file_root_ID = ".$this->_FileRoot->in_type_ID." 1161 AND file_path IN (".implode( ',', $to_load ).")", 1162 OBJECT, 'Load FileList meta data' ); 1163 1164 if( count($rows) ) 1165 { // Go through rows of loaded meta data... 1166 foreach( $rows as $row ) 1167 { 1168 // Retrieve matching File object: 1169 /** 1170 * @var File 1171 */ 1172 $loop_File = & $FileCache->get_by_root_and_path( $row->file_root_type, $row->file_root_ID, $row->file_path ); 1173 1174 // Associate meta data to File object: 1175 $loop_File->load_meta( false, $row ); 1176 } 1177 } 1178 } 1179 1180 // For all Files that still have no meta data, memorize that we could not find any meta data 1181 for( $i=0; $i<count($this->_entries); $i++ ) 1182 { // For each file: 1183 $loop_File = & $this->_entries[$i]; 1184 1185 if( $loop_File->meta == 'unknown' ) 1186 { 1187 $loop_File->meta = 'notfound'; 1188 } 1189 } 1190 1191 // Has sth been loaded? 1192 return count( $to_load ) && count($rows); 1193 } 1194 1195 1196 /** 1197 * Returns cwd, where the accessible directories (below root) are clickable 1198 * 1199 * @return string cwd as clickable html 1200 */ 1201 function get_cwd_clickable( $clickableOnly = true ) 1202 { 1203 if( empty($this->_ads_list_path) ) 1204 { 1205 return ' -- '.T_('No directory.').' -- '; 1206 } 1207 1208 // Get the part of the path which is not clickable: 1209 $r = substr( $this->_FileRoot->ads_path, 0, strrpos( substr($this->_FileRoot->ads_path, 0, -1), '/' )+1 ); 1210 1211 // get the part that is clickable 1212 $clickabledirs = explode( '/', substr( $this->_ads_list_path, strlen($r) ) ); 1213 1214 if( $clickableOnly ) 1215 { 1216 $r = ''; 1217 } 1218 1219 $cd = ''; 1220 foreach( $clickabledirs as $nr => $dir ) 1221 { 1222 if( empty($dir) ) 1223 { 1224 break; 1225 } 1226 if( $nr ) 1227 { 1228 $cd .= $dir.'/'; 1229 } 1230 $r .= '<a href="'.regenerate_url( 'path', 'path='.$cd ) 1231 .'" title="'.T_('Change to this directory').'">'.$dir.'</a>/'; 1232 } 1233 1234 return $r; 1235 } 1236 1237 } 1238 1239 /* 1240 * $Log: _filelist.class.php,v $ 1241 * Revision 1.1 2007/06/25 10:59:55 fplanque 1242 * MODULES (refactored MVC) 1243 * 1244 * Revision 1.28 2007/06/19 23:15:08 blueyed 1245 * doc fixes 1246 * 1247 * Revision 1.27 2007/04/26 00:11:10 fplanque 1248 * (c) 2007 1249 * 1250 * Revision 1.26 2007/02/10 18:01:58 waltercruz 1251 * Changing double quotes to single quotes 1252 * 1253 * Revision 1.25 2007/01/24 13:28:38 fplanque 1254 * todo 1255 * 1256 * Revision 1.24 2007/01/24 13:26:56 fplanque 1257 * fixed sort by type 1258 * 1259 * Revision 1.23 2007/01/24 12:18:25 blueyed 1260 * Fixed PHP-fnmatch() implementation (for Windows) 1261 * 1262 * Revision 1.22 2006/12/24 00:52:56 fplanque 1263 * Make posts with images - Proof of concept 1264 * 1265 * Revision 1.21 2006/12/07 23:13:10 fplanque 1266 * @var needs to have only one argument: the variable type 1267 * Otherwise, I can't code! 1268 * 1269 * Revision 1.20 2006/12/07 20:03:32 fplanque 1270 * Woohoo! File editing... means all skin editing. 1271 * 1272 * Revision 1.19 2006/11/24 18:27:24 blueyed 1273 * Fixed link to b2evo CVS browsing interface in file docblocks 1274 */ 1275 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Thu Nov 29 23:58:50 2007 | par Balluche grâce à PHPXref 0.7 |
|