<?php // 4
/**
* This class gets information inside a folder and its subfolders.
* With few steps you can read:
* - total size of folder [ ->getSize() ]
* - folder and subfolders info [ ->getDetails() or ->getTree() ]
* - all files info [ ->getDetails() or ->getTree() ]
* - a valid W3C XML rappresentation of the folder and its subfolder
* with files informations [ ->getXML() ]
* - a Flash optimized XML rappresentation of the folder and its subfolder
* with files informations [ ->getFlashXML() ]
* - size of a file [ self::readableSize ]
* - file or folder permissions [ self::getPerms ]
* ______________________________________________________________
* EXAMPLE:
* $FS = &new FolderStats('./');
* var_dump( $FS->getSize() );
* --------------------------------------------------------------
* @Compatibility >= PHP 4
* @Author Andrea Giammarchi
* @Site http://www.devpro.it/
* @Mail andrea [ at ] 3site [ dot ] it
* @Date 03/03/2005
* @LastModified 12/07/2005 10:50
* @Version 1.0 tested
*/
class FolderStats {
/**
* 'Private' variables:
* __size:Array Integer size and readable size of the folder
* __stats:Array Files and folders informations container
* __folder:String Folder to parse
* __XML:String Valid W3C XML or Flash optimized XML rappresentation
*/
var $__size;
var $__stats;
var $__folder;
var $__XML;
/**
* Public constructor:
* Initializes private variables and start loop inside folder.
* new FolderStats( $folder:String )
* @Param String folder to parse recoursively
* [ DEFAULT: current directory ]
*/
function FolderStats( $folder = './' ) {
if(substr($folder, -1) !== '/' && substr($folder, -1) !== '\\')
$folder .= '/';
$this->__folder = &$folder;
$this->__stats = Array();
$this->__XML = Array();
$this->__stats['files'] = Array();
$this->__stats['folders'] = Array();
$this->__size = &$this->__folderInfo( $this->__folder );
}
/**
* Public method:
* returns an anrray with 2 keys and 2 values
* this->getSize():Array
* @Return Array An array with 2 keys;
* 'size' => (int) integer size
* 'rsize' => (string) readable size (i.e. '156.40 Kb')
*/
function getSize() {
return Array(
'size'=>$this->__size,
'rsize'=>FolderStats::readableSize( $this->__size )
);
}
/**
* Public method:
* returns an anrray with all information for each file and each folder
* this->getDetails():Array
* @Return Array An array with all details
*/
function getDetails() {
return $this->__stats;
}
/**
* Public method:
* returns a string with an optimized and Flash dedicated rappresentation
* of the folder and its files or subfolders.
* this->getFlashXML():String
* @Return String formatted XML string
*/
function getFlashXML() {
$XML = $this->__xmlFlashLooper( $this->__XML );
return str_replace( 'name', 'label', $XML );
}
/**
* Public method:
* returns a string with a valid W3C XML rappresentation
* of the folder and its files or subfolders.
* this->getXML():String
* @Return String formatted XML string
*/
function getXML() {
$XML = "<?xml version=\"1.0\"?>
<!DOCTYPE directory [
<!ELEMENT directory (name,(directory|file)*)>
<!ELEMENT file (name,size,rsize,cdate,mdate,perms)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT size (#PCDATA)>
<!ELEMENT rsize (#PCDATA)>
<!ELEMENT cdate (#PCDATA)>
<!ELEMENT mdate (#PCDATA)>
<!ELEMENT perms (#PCDATA)>
]>".$this->__xmlLooper( $this->__XML );
return $XML;
}
/**
* Public method:
* returns an array with indented informations folder by folder
* this->getTree():Array
* @Return Array An array with indented informations of eah subfolder and its files
*/
function getTree() {
$__tree = Array();
$__folder = preg_replace( "/^([^\a]+?)(\/)?$/i", "\\1", $this->__folder );
$__tree[$__folder] = $this->__findFileInFolder( $__folder );
for( $a = 0, $b = &count( $this->__stats['folders'] ); $a < $b; $a++ )
$__tree[$this->__stats['folders'][$a]['name']] =
$this->__findFileInFolder( $this->__stats['folders'][$a]['name'] );
return $__tree;
}
/**
* 'Static' Public method:
* returns a readable rappresentation of an integer size
* FolderStats::readableSize($size:Integer, $decimals:Integer):String
* @Param Integer Integer size to convert in readable size
* @Param Integer how many number as decimal values ( something like %.N for float numbers )
* [Default: 2]
* @Return String A readable rappresentation of this size
*/
function readableSize( $size, $dec = 2 ) {
// Original function name: fSize [ www.devpro.it ]
// Converts filesize in Kb, Mb, Gb or Tb [ Zb as incredible size ! ]
// andr3a [ www.3site.it ] 23 / 10 / 2004
// EXAMPLE:
// echo FolderStats::readableSize( 87983598 );
// // will print 83.91 Mb
$toEval = '';
$type = Array( 'bytes', 'Kb', 'Mb', 'Gb', 'Tb', 'Zb' );
$nsize = ( $size = (int) $size );
$times = 0;
while( $nsize >= 1024 ) {
$nsize = $nsize / 1024;
$toEval .= ' / 1024';
$times++;
}
if( $times === 0 )
$fSize = $size.' '.$type[$times];
else {
eval( '$size = ( $size'.$toEval.' );' );
$fSize = number_format( $size, $dec, '.', '' ).' '.$type[$times];
}
return $fSize;
}
/**
* 'Static' Public method:
* returns a readable rappresentation of a file or folder permissions
* FolderStats::getPerms($perms:fileperms()):String
* @Param fileperms() fileperms returned value for a file or folder [i.e. fileperms('./folder')]
* @Return String A readable rappresentation of this permissions
*/
function getPerms( $perms ) {
// Original code from WWW.PHP.NET
// [ http://uk.php.net/manual/en/function.fileperms.php ]
// Checks filepermissions and returns a readable rappresentation
// EXAMPLE:
// echo FolderStats::getPerms( fileperms( './FOLDER' ) );
// // will print for example "drwxrwxrwx" if has a chomd 777
if( ( $perms & 0xC000 ) == 0xC000 )
$info = 's'; // Socket
elseif( ( $perms & 0xA000 ) == 0xA000 )
$info = 'l'; // Symbolic Link
elseif( ( $perms & 0x8000 ) == 0x8000 )
$info = '-'; // Regular
elseif( ( $perms & 0x6000 ) == 0x6000 )
$info = 'b'; // Block special
elseif( ( $perms & 0x4000 ) == 0x4000 )
$info = 'd'; // Directory
elseif( ( $perms & 0x2000 ) == 0x2000 )
$info = 'c'; // Character special
elseif( ( $perms & 0x1000 ) == 0x1000 )
$info = 'p'; // FIFO pipe
else
$info = 'u'; // Unknown
// Owner
$info .= ( ( $perms & 0x0100 ) ? 'r' : '-' );
$info .= ( ( $perms & 0x0080 ) ? 'w' : '-' );
$info .= ( ( $perms & 0x0040 ) ?
( ( $perms & 0x0800 ) ? 's' : 'x' ) : ( ( $perms & 0x0800 ) ? 'S' : '-' ) );
// Group
$info .= ( ( $perms & 0x0020 ) ? 'r' : '-' );
$info .= ( ( $perms & 0x0010 ) ? 'w' : '-' );
$info .= ( ( $perms & 0x0008 ) ?
( ( $perms & 0x0400 ) ? 's' : 'x' ) : ( ( $perms & 0x0400 ) ? 'S' : '-' ) );
// World
$info .= ( ( $perms & 0x0004 ) ? 'r' : '-' );
$info .= ( ( $perms & 0x0002 ) ? 'w' : '-' );
$info .= ( ( $perms & 0x0001 ) ?
( ( $perms & 0x0200 ) ? 't' : 'x' ) : ( ( $perms & 0x0200 ) ? 'T' : '-' ) );
return $info;
}
/**
* 'Private' methods
*/
function __findFileInFolder( $folder ) {
$__f = Array();
for( $a = 0, $b = &count( $this->__stats['files'] ); $a < $b; $a++ ) {
$__g = explode( '/', $this->__stats['files'][$a]['name'] );
if( ( $c = ( count( $__g ) - 1 ) ) > 0 ) {
$__l = $__g[$c];
unset( $__g[$c] );
}
$__g = implode( '/', $__g );
if( $__g == $folder )
array_push( $__f, Array(
'name'=>$__l,
'size'=>$this->__stats['files'][$a]['size'],
'rsize'=>$this->__stats['files'][$a]['rsize'],
'cdate'=>$this->__stats['files'][$a]['cdate'],
'mdate'=>$this->__stats['files'][$a]['mdate'],
'perms'=>$this->__stats['files'][$a]['perms']
)
);
}
return $__f;
}
function __xmlFlashLooper( $ar, $level = 0 ) {
$__XML = "";
while( list( $k, ) = each( $ar ) ) {
if( is_int( $k ) ) {
$__XML .= "\n".str_repeat( "\t", $level )."<node ";
foreach( $ar[$k] as $kk => $vv )
$__XML .= "{$kk}=\"{$vv}\" ";
$__XML .= "/>";
}
else {
if( $k != '' && $k != '.' ) {
$__XML .= "\n".str_repeat( "\t", $level )."<node label=\"{$k}\">";
$__XML .= $this->__xmlFlashLooper( $ar[$k], ( $level + 1 ) );
$__XML .= "\n".str_repeat( "\t", $level )."</node>";
}
else
$__XML .= $this->__xmlFlashLooper( $ar[$k], $level );
}
}
return $__XML;
}
function __xmlLooper( $ar, $level = 0 ) {
$__XML = "";
while( list( $k, ) = each( $ar ) ) {
if( is_int( $k ) ) {
$__XML .= "\n".str_repeat( "\t", $level )."<file>";
foreach( $ar[$k] as $kk => $vv )
$__XML .= "\n".str_repeat( "\t", $level + 1 )."<{$kk}>{$vv}</{$kk}>";
$__XML .= "\n".str_repeat( "\t", $level )."</file>";
}
else {
if( $k != '' && $k != '.' ) {
$__XML .= "\n".str_repeat( "\t", $level )."<directory>";
$__XML .= "\n".str_repeat( "\t", $level + 1 )."<name>{$k}</name>";
$__XML .= $this->__xmlLooper( $ar[$k], ( $level + 1 ) );
$__XML .= "\n".str_repeat( "\t", $level )."</directory>";
}
else {
$__XML .= $this->__xmlLooper( $ar[$k], $level );
}
}
}
return $__XML;
}
final private function __folderInfo( $folder ) {
$totalbytes = 0;
if( $handle = opendir( $folder ) ) {
while( false !== ( $file = readdir( $handle ) ) ) {
if( $file != '.' && $file != '..' && is_dir( $folder.$file ) == false ) {
$__ns = filesize( $folder.$file );
$information = Array(
'name'=>$folder.$file,
'size'=>$__ns,
'rsize'=>self::readableSize( $__ns ),
'cdate'=>date( 'Y-m-d H:i:s', @filectime( $folder.$file ) ),
'mdate'=>date( 'Y-m-d H:i:s', @filemtime( $folder.$file ) ),
'perms'=>self::getPerms( fileperms( $folder.$file ) )
);
array_push( $this->__stats['files'], $information );
$__toXML = explode( '/', $folder );
$__indexXML = '';
for( $a = 0, $b = ( count( $__toXML ) - 1 ); $a < $b; $a++ )
$__indexXML .= '[\''.$__toXML[$a].'\']';
$information['name'] = basename( $information['name'] );
eval( 'if( isSet( $this->__XML'.$__indexXML.' ) == false ) { $this->__XML'.$__indexXML.' = Array(); }' );
eval( 'array_push( $this->__XML'.$__indexXML.', $information );' );
$totalbytes += $__ns;
}
elseif( $file != '.' && $file != '..' && is_dir( $folder.$file ) == true ) {
$__toXML = explode( '/', $folder.$file );
$__indexXML = '';
for( $a = 0, $b = &count( $__toXML ); $a < $b; $a++ )
$__indexXML .= '[\''.$__toXML[$a].'\']';
eval( '$this->__XML'.$__indexXML.' = Array();' );
array_push( $this->__stats['folders'], Array(
'name'=>$folder.$file,
'cdate'=>date( 'Y-m-d H:i:s', @filectime( $folder.$file ) ),
'mdate'=>date( 'Y-m-d H:i:s', @filemtime( $folder.$file ) ),
'perms'=>self::getPerms( fileperms( $folder.$file ) )
)
);
$totalbytes += $this->__folderInfo( $folder.$file.'/' );
}
}
closedir( $handle );
}
return $totalbytes;
}
}
?>