再帰的な関数処理でディレクトリ内の.svnディレクトリを削除する方法

このQ&Aのポイント
  • 以下のPHPコードを使用して、再帰的な関数処理で指定されたディレクトリ内のすべての.svnディレクトリを削除することができます。
  • コマンドラインからPHPを実行し、ディレクトリ内のすべての.svnディレクトリを再帰的に削除します。
  • コード内のDirectoryIteratorを使用して、ディレクトリ内のすべてのファイルとディレクトリにアクセスし、.svnディレクトリが見つかった場合に削除します。
回答を見る
  • ベストアンサー

フォルダへの再帰的な関数処理方を教えてください

すみませんがPHPのコードについて質問させてください。 PHP : 5.3.5 OS : WindowsXP コマンドラインにてPHPを作動させ、各ディレクトリ内にある.svnディレクトリを再帰的に全て削除しようと思って以下のコードを書きました。 <?php error_reporting(E_ALL | E_STRICT); define('DS', DIRECTORY_SEPARATOR); define('PS', PATH_SEPARATOR); require_once('Zend' . DS . 'Debug.php'); function e ($message) { echo $message . PHP_EOL; } function d ($var, $label = null) { Zend_Debug::dump($var, $label); } $date = date('Y/m/d H:i:s'); e("====== START(" . $date . ") ======"); $arg1 = realpath($argv[1]); if (!is_dir($arg1)) { e($arg1 . "はディレクトリじゃないよ?"); } else { function removeSVN ($dirname) { $parentDir = new DirectoryIterator($dirname); foreach ($parentDir as $key => $childDir) { $realChild = realpath($childDir); if ($childDir->isDir() && !$childDir->isDot()) { if ($childDir == ".svn") { e("Delete : " . $childDir->getFilename()); //ココでrealpath()化するか、chdir()をしないと //$childDirではエラーになります rmdir($realChild); } else { e("Insert : " . realpath($childDir->getFilename())); //以下の一文を抜けばエラーにはならず、".\CLI\centurion"内 //の.SVNは削除されますが、勿論再帰的には作動しません。 call_user_func('removeSVN', $childDir); } } } } //ココでrealpath()化するか、chdir()をしないと$argv[1]ではエラーになります removeSVN($arg1); } e("============ END ============"); で、 C:\php> php.exe .\CLI\removeSVN.php .\CLI\centurion と実行すると、 ====== START(2011/10/02 22:00:34) ====== Insert : Fatal error: Uncaught exception 'UnexpectedValueException' with message 'DirectoryIterator::__construct(application,application): 指定されたファイルが見つかりません。 (code: 2)' in C:\php\CLI\removeSVN.php on line 32 UnexpectedValueException: DirectoryIterator::__construct(application,application): 指定されたファイルが見つかりません。 (code: 2) in C:\php\CLI\removeSVN.php on line 32 Call Stack: 0.0030 381536 1. {main}() C:\php\CLI\removeSVN.php:0 0.0067 396576 2. removeSVN() C:\php\CLI\removeSVN.php:54 0.0092 397784 3. call_user_func() C:\php\CLI\removeSVN.php:49 0.0093 397800 4. removeSVN() C:\php\CLI\removeSVN.php:49 0.0093 398336 5. DirectoryIterator->__construct() C:\php\CLI\removeSVN.php:32 とエラーが出ます。 エラー内にある32行目とは$parentDir = new DirectoryIterator($dirname);の事です。 自分は、call_user_func()にて$childDirディレクトリ内に入り、また再帰的に.svnフォルダを見つけて削除しようと考えたのですが、ダメでした。 自分の力では分かりませんのでアドバイスをいただけないでしょうか? ディレクトリの最後まで行き、ファイルのみになった場合に帰れるように、continue文を入れないといけないのかな、とも思ったのですが、良く分かりませんでした。

  • PHP
  • 回答数1
  • ありがとう数0

質問者が選んだベストアンサー

  • ベストアンサー
  • ida_rdt
  • ベストアンサー率75% (3/4)
回答No.1

再帰的に処理する場合は、自分自身(function)を再帰的に呼び出すことで、非常にシンプルになります。 $sourceDir = '/var/www/html'; // 対象フォルダ(例) $targetDir = '.svn'; // 処理するフォルダ名 procDir( $sourceDir, $targetDir ); function procDir( $sourceDir, $targetDir ) {  // ディレクトリを開く  if ( $handle = opendir( $sourceDir ) )  {   while ( false !== ( $file = readdir( $handle ) ) )   {    // エラーチェック    if ( $file == '.' || $file == '..' ) { continue; }    $path = $sourceDir . '/' . $file;    if ( is_dir( $path ) )    {     // 対象フォルダの処理     if ( $file == $targetDir )     {      /**       * [ $path ] にターゲットのフルパスが格納される。       * 削除を実行する前に、echo 等で書き出して確認することを       * お勧めします。下記例だと、シェルコマンドの rm を使用して       * いますが、unlink + rmdir の組み合わせの方がPHPっぽい       * かもしれません。       *       */      //system( 'rm -dfvr ' . $path );      //echo $path . "\n";      continue;     }     // 再帰的に処理     procDir( $path, $targetDir );    }   }   closedir( $handle );  } }

関連するQ&A

  • エラーが起きた位置の特定

    例えば下記のようなコードで、この(↓)エラーが出たとします。 Warning: somefunc1(): The argument should be an array in /path/to/test.php on line 5 このエラーが、 A) 18行目→test_func1()→somefunc1() の経路で発生したエラーなのか、 B) 19行目→test_func2()→test_func1($arg1)→somefunc1() の経路なのか、 C) 19行目→test_func2()→test_func1($arg2)→somefunc1() の経路なのか、 それを効率よく判断する方法はありませんか? この位簡単なコードではデバッグも簡単なんですが、大規模なアプリケーションになってくると、どの時点で起きたエラーなのか(どの手順で呼び出された時なのか、ループの何回目なのか等)の判断ができなくなってきてしまいます。 ==== test.php ==== 01: <?php 02: 03: function test_func1($arg) 04: { 05:   somefunc1($arg); // PHP組み込み関数 06: } 07: 08: function test_func2($arg) 09: { 10:   $arg1 = somefunc2($arg); // PHP組み込み関数 11:   $arg2 = somefunc3($arg); // PHP組み込み関数 12:   test_func1($arg1); 13:   test_func1($arg2); 14: } 15: 16: $val = /* ...処理... */ ; 17: 18: test_func1($val); 19: test_func2($val); 20: 21: ?> よろしくお願いいたします。

    • ベストアンサー
    • PHP
  • 再帰関数のサポートについて

    http://ja.phptherightway.com/pages/Functional-Programming.html 上記ページにありますようにPHPは再帰関数をサポートとあります。 関数プログラミングなるものはこの再帰関数を使ってループをつくったりすると ききました。 たとえば function roop($i){ print($i); $n = $i + 1; if($n < 100){ roop($n); } } roop(1); というようなコードでしょうか。 これは1~99までのループですよね。 これはPHPがインタープリターといえど、一度 PHP専用のバイトコードに変換して からPHPエンジンがバイトコードを実行するため再帰が可能という解釈でもんだいないですかね? もしほんとうに逐次解釈なインタープリターなら解釈途中に、その関数自体の定義をインタープリターが認識? し終わる前に未定義状態の関数が出現してしまうってことですよね? undefined な関数があるといようなエラーがでてくのでしょうか? 生Cのソースみればわかるのでしょうけれども、私はCがわからないので・・・。 概要でよいのでご教授ください。

    • ベストアンサー
    • PHP
  • 呼び出し先にさらに呼び出しがある場合について

    PHPバージョン5.2.4を使っています。 index.phpからdir1ディレクトリにあるfile1.phpをrequireして使いたいのですが、 file1.phpもdir1ディレクトリにあるfile2.phpをrequireしているので 次のような呼び出し方ならうまく作動するのですが、 [index.php] define('DIR', realpath(dirname(__FILE__))); require_once 'dir1/file1.php'; [dir1/file1.php] require_once DIR.'/file1.php'; [dir1/file2.php] print "file2表示"; 次のようにindex.phpをdir1ディレクトリに移動させて実行すると file1.phpのrequireでエラーが出てしまいます。 [dir1/index.php] define('DIR', realpath(dirname(__FILE__))); require_once 'dir1/file1.php'; このような呼び出し先の中にさらに別の呼び出しがある場合は どのように記述すればindex.php(実行するファイル)を 別のどんな場所に移動させても作動させることができるのでしょうか?

    • ベストアンサー
    • PHP
  • map関数についての質問です

    お世話になります、連続の質問になりますが宜しくお願いします $arg_[0]<>$arg_[1]<>$arg_[2]<>$arg_[3] という具合な配列をmap関数を使って open(OUT,">>$logfile") || &error("Write Error : $logfile"); print OUT join('<>',(map{$arg_.[$_]} (0..3)),); close(OUT); として、ファイルに書き込むと 事前にセットした変数値ではなく ARRAY(0x81e4c10)<>ARRAY(0x81e4c4c)<>ARRAY(0x81e4c88)<>ARRAY(0x81e4cc4)<> こういう具合になってしまいます、正しく $arg_[0]<>$arg_[1]<>$arg_[2]<>$arg_[3] にセットした値を書き込むコードを教えて頂けませんでしょうか。

    • ベストアンサー
    • Perl
  • include_pathについて。

    PHP 5.2以上のバージョンの話として質問をさせて頂きます。 (ローカルではWindows版XAMPPを使用。リモートはLinuxサーバー。) ----- <ファイルの位置関係> imgディレクトリ --- C.jpg (画像ファイル) mainディレクトリ --- A.php sub ディレクトリ --- funcディレクトリ --- B.php (img、main、subディレクトリは3つとも同階層) //------- (A.phpの記述) require_once '../sub/func/B.php'; //------- (B.phpの記述) echo '<img src="C.jpgのパス">'; // ←■画像Cを表示したい■ //★どう表示されるかテスト★ echo dirname(__FILE__) ;   //----- このような状況で、 A.phpにアクセスすると、★テスト★の所は、 ~/sub/func   //←のように表示される。 // つまりこれは、__FILE__ は、 // A.phpではなく、B.phpを指している。(?) と、このような時、B.phpの中で、 C画像の相対パスは、どう書いたらよろしいのでしょうか? A.phpから見た、C画像の相対パスで書いたらいい? それとも、B.phpから見たソレでしょうか? phpinfo()でinclude_pathの項目を調べると、 .:/usr/local/lib/php/~ のように書かれています。(デフォルトのままです。)

    • ベストアンサー
    • PHP
  • bccでエラー:メンバー関数は呼び出すかそのアドレスを~

    クラスのメンバ関数を、ある関数(実は qsort)の引数として渡したい と思っています。環境は OS:Windows XP コンパイラ:C++Builder6 に付属の bcc32.exe です。 下記のコード(t.cpp)をコマンドプロンプトで bcc32 t としてコンパイルすると「※1」の行で下のエラーになります。 「エラー E2235 t.cpp 29: メンバー関数は呼び出すか  そのアドレスをとらなければならない(関数 main() )」 どのように直せば良いでしょうか? -------------------------------------------------------- #include <stdio.h> #include <stdlib.h> class Aclass { public: void f(int); }; void Aclass::f(int x) { printf("classfunc %d\n", x); } void sub1(int x) { printf("sub-1 %d\n", x); } void call_func(void(*func)(int), int x) { func(2*x + 1); } void main(void) { call_func((void(*)(int))sub1, 11); Aclass *a = new Aclass; call_func((void(*)(int))a->f, -7); //※1 delete a; } -------------------------------------------------------- この掲示板、行頭の空白が削除されてしまいますねー。

  • PHPのセグメンテーション違反に対する例外処理について

    PHPのセグメンテーション違反に対する例外処理について 再帰呼び出しのプログラム(error_seg.php)を作成し、Linuxのシェルで  $ php error_seg.php と実行しました。 実行環境: PHPのバージョン:5.2.10 Linuxのバージョン:2.6.18-164.15.1.el5 (mockbuild@builder16.centos.org) (gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)) #1 SMP Wed Mar 17 11:37:14 EDT 2010 プログラムは下記の通りです。 <?php $cnt=0; function func(){ global $cnt; $cnt++; print $cnt . "回目の呼び出し\n"; func(); } try{ func(); }catch(Exception $e){ echo "例外発生:" . $e->getMessage()."\n"; } ?> ※このプログラムは、   http://d.hatena.ne.jp/syonbori_tech/20090414/1239717538  のサイトを参考にして作りました。 この結果、  1回目の呼び出し  2回目の呼び出し  ・・・  26187回目の呼び出し  26188回目の呼び出し  セグメンテーション違反です と表示され、セグメンテーション違反を再現させました。 ※何回目でセグメンテーション違反が発生するかは、  その都度異なります。 プログラム中で、try-catchの例外処理を入れたのですが、 例外処理されないようです。セグメンテーション違反に対して 例外処理をすることはできないのでしょうか。 できるとすれば、どのように記述をすればよいでしょうか。

    • ベストアンサー
    • PHP
  • Apacheの設定で、別ドライブの設定方法は?

    httpd.confの設定で、C:ドライブにWeb関係の設定をし、E:ドライブにSVNのフォルダーを作って行いたいと思っています。 同じCドライブでは、SVNのテストは上手くいきました。 それを、Eドライブにすると、Apacheが落ちてしまいます。 httpd.confの設定で、別ドライブを認識させる方法は、どこにありますか? WindowsのApacheでは、別ドライブの設定をすることは出来ないのでしょうか? Apacheは、Cドライブにインストールしています。 設定の抜粋は以下のとおり <Directory "E:/svn"> AllowOverride All #Options Indexes SymLinksIfOwnerMatch IncludesNoExec </Directory>    : <Location /svn> DAV svn SVNListParentPath on SVNParentPath E:\svn </Location>

  • FTPの再帰について

    ファイル及びディクレトリを削除する関数を作成しているのですが、 再帰した時に、FindFileでディレクトリが取得できなくなってしまいます。 エラー情報を取得すると、Error12110が出ていました。 12110 ERROR_FTP_TRANSFER_IN_PROGRESS The requested operation cannot be made on the FTP session handle because an operation is already in progress. 以下、ソースもつけます。 ご指摘いただければうれしいです。 よろしくお願いします。 try { CFtpFileFind finder (m_ftpConP); BOOL bWorking = FALSE; CString strFilePath; if ((bWorking = finder.FindFile(pIstrFilePath + "/*")) != 0) { while( bWorking != 0 ) { bWorking = finder.FindNextFile(); if( finder.IsDots() != 0 ) continue; strFilePath = pIstrFilePath + "/"; strFilePath += finder.GetFileName(); if( finder.IsDirectory() != 0 ) { intRet = Remove( strFilePath ); } else { // ファイル if(m_ftpConP->Remove(strFilePath) == 0) { intRet = -1; } } } finder.Close(); if (!m_ftpConP->RemoveDirectory(pIstrFilePath)) { intRet = -1; } } } catch (CInternetException* pEx) { TCHAR sz[1024]; pEx->GetErrorMessage(sz, 1024); AfxMessageBox(sz); pEx->Delete(); }

  • scandir関数取得結果の文字化け

    PHPスクリプトでローカルのディレクトリ名を 取得するプログラムを下記のとおり作成しました。 <?php $list = scandir($rootdir); foreach($list as $dirname){ print($dirname."<br>"); } ?> 取得結果は下記のとおりで 日本語が文字化けてしまいます。 010_�^�C_�ߋ��̗� 020_�^�C_�ߋ��̗��Q mb_convert_encoding($dirname, "UTF-8", "auto"); を行えば文字化けせずに出力できるのですが、 他にwindows環境でこの文字化けに対する回避方法はないのでしょうか? ご教授願います。 [環境] WindwosXP Pro SP3 PHP Version 5.2.9-2 [表示ページの文字コード] <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> [php.iniのmbstring設定] mbstring.language = Japanese mbstring.internal_encoding = UTF-8 mbstring.http_input = pass mbstring.http_output = pass mbstring.encoding_translation = Off mbstring.detect_order = SJIS,EUC-JP,JIS,UTF-8,ASCII mbstring.substitute_character = none; mbstring.func_overload = 0 以上よろしくお願いします。

    • 締切済み
    • PHP

専門家に質問してみよう