暇人の寝室
技術系の記事や読書・アニメの感想などを投稿します。
プログラミング
前回の続き。
前回、複数ディレクトリ表示と-aオプションを作った。
今回は-aと同じくらいよく使用-lオプションを実装しようと思う。
尚、PHPの練習という目的でlsコマンドを作成しているので、一旦この辺で開発は停止する予定。(気まぐれに再開することもあるかも?)
サイズのパディングにはstr_pad関数を使用した。
サイズの最大桁数は、ファイル情報を取得したあと、サイズカラムのみを取り出した配列を作成してmax関数で最大値を取った。
// Print result of scandir
if(array_key_exists('l',$options)){
$file_stats = [];
foreach($scan_dirs as $dir){
$path = $target_dir . '/' . $dir;
$file_stats[] = getFileInfo($path);
}
$max_size = strlen(max(array_column($file_stats,'4')));
$file_stats = array_map(function($value)use($max_size){
$value[4] = str_pad($value[4],$max_size," ",STR_PAD_LEFT);
$value = implode(' ',$value);
return $value;
},$file_stats);
foreach($file_stats as $file_stat){
printf($file_stat . "\n");
}
}else{
printf(implode(' ',$scan_dirs));
}
ファイルの情報はstat()やposix_getpwuid()、posix_getgrgid()を駆使して取得し、配列で返す関数を作成した。
function getFileInfo($path){
$stat = stat($path);
$perms = getPerms(fileperms($path));
$owner = posix_getpwuid($stat['uid'])['name'];
$group = posix_getgrgid($stat['gid'])['name'];
$size = $stat['size'];
$timestamp = date('n月 d H:i',$stat['atime']);
return [
// ファイルタイプ
// パーミション
$perms,
// ハードリンクの数
$stat['nlink'],
// オーナー名
$owner,
// グループ名
$group,
// バイトサイズ
$size,
// タイムスタンプ
$timestamp,
// ファイル名
basename($path),
];
}
パーミッションをlsコマンドのようなフォーマットにする関数は、
https://www.php.net/manual/ja/function.fileperms.php
の「例2 完全なパーミッションの表示」にあるものを参考にした。
function getPerms($perms){
switch ($perms & 0xF000) {
case 0xC000: // ソケット
$info = 's';
break;
case 0xA000: // シンボリックリンク
$info = 'l';
break;
case 0x8000: // 通常のファイル
$info = '-';
break;
case 0x6000: // ブロックスペシャルファイル
$info = 'b';
break;
case 0x4000: // ディレクトリ
$info = 'd';
break;
case 0x2000: // キャラクタスペシャルファイル
$info = 'c';
break;
case 0x1000: // FIFO パイプ
$info = 'p';
break;
default: // 不明
$info = 'u';
}
// 所有者
$info .= (($perms & 0x0100) ? 'r' : '-');
$info .= (($perms & 0x0080) ? 'w' : '-');
$info .= (($perms & 0x0040) ?
(($perms & 0x0800) ? 's' : 'x' ) :
(($perms & 0x0800) ? 'S' : '-'));
// グループ
$info .= (($perms & 0x0020) ? 'r' : '-');
$info .= (($perms & 0x0010) ? 'w' : '-');
$info .= (($perms & 0x0008) ?
(($perms & 0x0400) ? 's' : 'x' ) :
(($perms & 0x0400) ? 'S' : '-'));
// 全体
$info .= (($perms & 0x0004) ? 'r' : '-');
$info .= (($perms & 0x0002) ? 'w' : '-');
$info .= (($perms & 0x0001) ?
(($perms & 0x0200) ? 't' : 'x' ) :
(($perms & 0x0200) ? 'T' : '-'));
return $info;
}
最後の列のファイル名をパスから正規表現で切り出そうなどと考えていたが、PHPにはbasename関数があるので無駄な試みだった。
> cd test_dir
> php ../ls.php -l .
-rw-rw-r-- 1 ylafaro ylafaro 0 9月 21 21:52 test3
-rw-rw-r-- 1 ylafaro ylafaro 0 9月 21 21:52 test4
~/prog/php-ls/test_dir
> php ../ls.php -l ..
-rw-rw-r-- 1 ylafaro ylafaro 73 9月 21 21:30 README.md
-rw-rw-r-- 1 ylafaro ylafaro 3340 9月 23 23:12 ls.php
-rw-rw-r-- 1 ylafaro ylafaro 0 9月 20 20:39 test1
-rw-rw-r-- 1 ylafaro ylafaro 0 9月 20 20:39 test2
drwxrwxr-x 2 ylafaro ylafaro 4096 9月 23 21:39 test_dir
~/prog/php-ls/test_dir
> php ../ls.php -l . ..
.:
-rw-rw-r-- 1 ylafaro ylafaro 0 9月 21 21:52 test3
-rw-rw-r-- 1 ylafaro ylafaro 0 9月 21 21:52 test4
..:
-rw-rw-r-- 1 ylafaro ylafaro 73 9月 21 21:30 README.md
-rw-rw-r-- 1 ylafaro ylafaro 3340 9月 23 23:12 ls.php
-rw-rw-r-- 1 ylafaro ylafaro 0 9月 20 20:39 test1
-rw-rw-r-- 1 ylafaro ylafaro 0 9月 20 20:39 test2
drwxrwxr-x 2 ylafaro ylafaro 4096 9月 23 21:39 test_dir
※スクリプトはこちらに公開している。