2024-07-08 00:54:28 -04:00
< ? php
2024-07-08 07:05:49 -04:00
declare ( strict_types = 1 );
2024-07-08 00:54:28 -04:00
/**
2024-07-08 01:12:25 -04:00
* SPDX - FileCopyrightText : 2017 - 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX - FileCopyrightText : 2016 ownCloud , Inc .
* SPDX - License - Identifier : AGPL - 3.0 - only
2024-07-08 00:54:28 -04:00
*/
namespace OCA\Files\Command ;
use OC\Core\Command\Base ;
use OC\Core\Command\InterruptedException ;
2024-07-08 07:05:49 -04:00
use OC\Files\Node\Node ;
2024-07-08 00:54:28 -04:00
use OC\FilesMetadata\FilesMetadataManager ;
use OC\ForbiddenException ;
use OCP\EventDispatcher\IEventDispatcher ;
use OCP\Files\File ;
use OCP\Files\FileInfo ;
use OCP\Files\Folder ;
use OCP\Files\IRootFolder ;
use OCP\Files\NotFoundException ;
use OCP\IUserManager ;
use Psr\Log\LoggerInterface ;
use Symfony\Component\Console\Helper\Table ;
use Symfony\Component\Console\Input\InputArgument ;
use Symfony\Component\Console\Input\InputInterface ;
use Symfony\Component\Console\Output\OutputInterface ;
class ListFiles extends Base {
protected array $fileInfo = [];
protected array $dirInfo = [];
public function __construct (
private IUserManager $userManager ,
private IRootFolder $rootFolder ,
private FilesMetadataManager $filesMetadataManager ,
private IEventDispatcher $eventDispatcher ,
private LoggerInterface $logger
) {
parent :: __construct ();
}
protected function configure () : void {
parent :: configure ();
$this -> setName ( " files:list " )
-> setDescription ( " List filesystem in the path mentioned in path argument " )
-> addArgument (
" path " ,
InputArgument :: REQUIRED ,
'List all the files and folder mentioned in this path, eg occ files:list path="/alice/files/Music", the path being a required argument to determine the user'
)
-> addOption ( " type " , " " , InputArgument :: OPTIONAL , " Filter by type like application, image, video etc " )
-> addOption (
" minSize " ,
2024-07-08 07:20:49 -04:00
" 0 " ,
2024-07-08 00:54:28 -04:00
InputArgument :: OPTIONAL ,
" Filter by min size "
)
-> addOption (
" maxSize " ,
2024-07-08 07:20:49 -04:00
" 0 " ,
2024-07-08 00:54:28 -04:00
InputArgument :: OPTIONAL ,
" Filter by max size "
)
-> addOption (
" sort " ,
" name " ,
InputArgument :: OPTIONAL ,
" Sort by name, path, size, owner, type, perm, created-at "
)
-> addOption ( " order " , " ASC " , InputArgument :: OPTIONAL , " Order is either ASC or DESC " );
}
2024-07-08 07:05:49 -04:00
private function getNodeInfo ( Node $node ) : array {
2024-07-08 00:54:28 -04:00
$nodeInfo = [
" name " => $node -> getName (),
" size " => $node -> getSize () . " bytes " ,
" perm " => $node -> getPermissions (),
2024-07-08 01:12:25 -04:00
" owner " => $node -> getOwner () ? -> getDisplayName (),
2024-07-08 00:54:28 -04:00
" created-at " => $node -> getCreationTime (),
" type " => $node -> getMimePart (),
];
if ( $node -> getMimetype () == FileInfo :: MIMETYPE_FOLDER ) {
$nodeInfo [ 'type' ] = 'directory' ;
}
return $nodeInfo ;
}
protected function listFiles (
string $user ,
string $path ,
OutputInterface $output ,
? string $type = " " ,
? int $minSize = 0 ,
? int $maxSize = 0
) : void {
try {
/** @var Folder $userFolder **/
$userFolder = $this -> rootFolder -> get ( $path );
$files = $userFolder -> getDirectoryListing ();
foreach ( $files as $file ) {
2024-07-08 07:05:49 -04:00
/** @var Node $fileNode */
$fileNode = $file ;
2024-07-08 00:54:28 -04:00
$includeType = $includeMin = $includeMax = true ;
2024-07-08 07:05:49 -04:00
$nodeInfo = $this -> getNodeInfo ( $fileNode );
if ( $type !== " " && $type !== $nodeInfo [ 'type' ]) {
2024-07-08 00:54:28 -04:00
$includeType = false ;
}
if ( $minSize > 0 ) {
$includeMin = $file -> getSize () >= $minSize ;
}
if ( $maxSize > 0 ) {
$includeMax = $file -> getSize () <= $maxSize ;
}
if ( $file instanceof File ) {
if ( $includeType && $includeMin && $includeMax ) {
$this -> fileInfo [] = $nodeInfo ;
}
} elseif ( $file instanceof Folder ) {
if ( $includeType && $includeMin && $includeMax ) {
$this -> dirInfo [] = $nodeInfo ;
}
}
}
} catch ( ForbiddenException $e ) {
$output -> writeln (
" <error>Home storage for user $user not writable or 'files' subdirectory missing</error> "
);
$output -> writeln ( " " . $e -> getMessage ());
$output -> writeln (
'Make sure you\'re running the list command only as the user the web server runs as'
);
} catch ( InterruptedException $e ) {
# exit the function if ctrl-c has been pressed
$output -> writeln ( " Interrupted by user " );
} catch ( NotFoundException $e ) {
$output -> writeln (
" <error>Path not found: " . $e -> getMessage () . " </error> "
);
} catch ( \Exception $e ) {
$output -> writeln (
" <error>Exception during list: " . $e -> getMessage () . " </error> "
);
$output -> writeln ( " <error> " . $e -> getTraceAsString () . " </error> " );
}
}
protected function execute (
InputInterface $input ,
OutputInterface $output
) : int {
$inputPath = $input -> getArgument ( " path " );
2024-07-08 07:05:49 -04:00
$user = '' ;
2024-07-08 00:54:28 -04:00
if ( $inputPath ) {
$inputPath = ltrim ( $inputPath , " path= " );
[, $user ] = explode ( " / " , rtrim ( $inputPath , " / " ) . '/' , 4 );
}
$this -> initTools ( $output );
$path = $inputPath ? : " / " . $user ;
if ( $this -> userManager -> userExists ( $user )) {
$output -> writeln (
" Starting list for user ( $user ) "
);
$this -> listFiles (
$user ,
$path ,
$output ,
$input -> getOption ( " type " ),
2024-07-08 07:05:49 -04:00
( int ) $input -> getOption ( " minSize " ),
( int ) $input -> getOption ( " maxSize " )
2024-07-08 00:54:28 -04:00
);
} else {
$output -> writeln (
" <error>Unknown user $user </error> "
);
$output -> writeln ( " " , OutputInterface :: VERBOSITY_VERBOSE );
return self :: FAILURE ;
}
$this -> presentStats ( $input , $output );
return self :: SUCCESS ;
}
/**
* Initialises some useful tools for the Command
*/
protected function initTools ( OutputInterface $output ) : void {
// Convert PHP errors to exceptions
set_error_handler (
fn (
int $severity ,
string $message ,
string $file ,
int $line
) : bool => $this -> exceptionErrorHandler (
$output ,
$severity ,
$message ,
$file ,
$line
),
E_ALL
);
}
/**
* Processes PHP errors in order to be able to show them in the output
*
* @ see https :// www . php . net / manual / en / function . set - error - handler . php
*
* @ param int $severity the level of the error raised
* @ param string $message
* @ param string $file the filename that the error was raised in
* @ param int $line the line number the error was raised
*/
public function exceptionErrorHandler (
OutputInterface $output ,
int $severity ,
string $message ,
string $file ,
int $line
) : bool {
if ( $severity === E_DEPRECATED || $severity === E_USER_DEPRECATED ) {
// Do not show deprecation warnings
return false ;
}
$e = new \ErrorException ( $message , 0 , $severity , $file , $line );
$output -> writeln (
" <error>Error during list: " . $e -> getMessage () . " </error> "
);
$output -> writeln (
" <error> " . $e -> getTraceAsString () . " </error> " ,
OutputInterface :: VERBOSITY_VERY_VERBOSE
);
return true ;
}
protected function presentStats (
InputInterface $input ,
OutputInterface $output
) : void {
$headers = [
" Permission " ,
" Size " ,
" Owner " ,
" Created at " ,
" Filename " ,
" Type " ,
];
$rows = [];
$fileInfo = $this -> fileInfo [ 0 ] ? ? [];
$sortKey = array_key_exists ( $input -> getOption ( " sort " ), $fileInfo )
? $input -> getOption ( " sort " )
: " name " ;
$order = $input -> getOption ( " order " ) == " ASC " ? SORT_ASC : SORT_DESC ;
$fileArr = array_column ( $this -> fileInfo , $sortKey );
$dirArr = array_column ( $this -> dirInfo , $sortKey );
array_multisort (
$fileArr ,
$order ,
$this -> fileInfo
);
array_multisort (
$dirArr ,
$order ,
$this -> dirInfo
);
foreach ( $this -> fileInfo as $k => $item ) {
$rows [ $k ] = [
$item [ " perm " ],
$item [ " size " ],
$item [ " owner " ],
$item [ " created-at " ],
$item [ " name " ],
$item [ " type " ],
];
}
foreach ( $this -> dirInfo as $k => $item ) {
$rows [] = [
$item [ " perm " ],
$item [ " size " ],
$item [ " owner " ],
$item [ " created-at " ],
$item [ " name " ],
$item [ " type " ],
];
}
$table = new Table ( $output );
$table -> setHeaders ( $headers ) -> setRows ( $rows );
$table -> render ();
}
}