サイト管理人Blog

cloudfreeで「さぁ始めましょう♪」

phpのFTP関数でローカルファイルをサーバと同じにする処理を走らせる

2023-12-24 記載
概要 : phpのftp関数でローカルファイルをサーバと同じにする
関連記事:phpのFTP関数でローカルファイルをサーバと同じにする処理を走らせる
Keyword : FTP, php,

cloudfreeのサーバからphpの FTP関数 を使って、ほかのサーバへftpログインしてFTP操作できるのか?「と思いためしたところ、バッチリできました。
クライアントからの接続はもちろん大丈夫ですが、サーバ側からの接続はまた違うかもしれないので確認してみました。

FTP関数
https://www.php.net/manual/ja/ref.ftp.php

ftp_mlsd — ディレクトリに存在するファイルの一覧を返す

この命令が強力で、ローカルのファイル操作はphp+FTPがPowershellなんかよりも便利なのでは?と思うほどでした。

https://localhost/ftpjob.php?jobkey=cloudfree_mywordpress_local_update
でサーバーとローカルのファイル同期をとるphpコードは以下です。

  mb_language('Japanese');
  mb_internal_encoding('UTF-8');
  date_default_timezone_set("Asia/Tokyo");
  setlocale(LC_ALL, 'ja_JP.UTF-8');

  $sJobkey = $_GET['jobkey'] ?? 'nop';

  $cParam = array();
  $cParam['dryrun'] = 'no';

  if ($sJobkey === 'nop') {
  } elseif ($sJobkey === 'cloudfree_mywordpress_local_update') {
    $cParam['base_path_src'] = '/cfsid.cloudfree.jp/public_html/mywordpress/';
    $cParam['base_path_dest'] = 'c:/home/cfsid/cfsid.cloudfree.jp/public_html/mywordpress/';
    //ftp-cloudfree
    $ftp_cloudfree = getftp('svXX.cloudfree.ne.jp/cfsid_ftpuser@cfsid.cloudfree.jp/password');
    ftp_chdir($ftp_cloudfree, $cParam['base_path_src']);
    //ftp-local
    $ftp_local = getftp('localhost/ftpuser/password');
    ftp_chdir($ftp_local, '/cloudfree_home/cfsid/cfsid.cloudfree.jp/public_html/mywordpress/');

    echo '<hr>';
    $cParam['subfolder'] = 'yes';
    $cParam['delete_localonly'] = 'yes';
    GetFile_IfUpdate($ftp_cloudfree, $ftp_local, 'wp-content/uploads/2023/', $cParam);
    echo '<hr>';
    $cParam['subfolder'] = 'yes';
    $cParam['delete_localonly'] = 'yes';
    GetFile_IfUpdate($ftp_cloudfree, $ftp_local, 'wp-content/themes/', $cParam);
    
    ftp_close($ftp_cloudfree);
    ftp_close($ftp_local);
  }

  // === function ================================================================

  //DESTとSRCの両ファイルの更新日時を比較して、同じでなければSRCファイルをGetしてSRCタイムに書き換える
  //$cParam['subfolder']='yes'ならサブフォルダも対象とし再帰関数として作動する
  //$cParam['dryrun']='yes'「GetしてSRCタイムに書き換える」は行わない
  function GetFile_IfUpdate($ftp_src, $ftp_dest, $sFolder, $cParam) {
    echo 'search folder:'.$sFolder."<br>\n";

    $aList = ftp_mlsd($ftp_src, $sFolder);
    $aList_dest_mdtm = GetDic_mdtm(ftp_mlsd($ftp_dest, $sFolder));

    foreach($aList as $item) {
      if ($item['type'] == 'dir' && $cParam['subfolder'] == 'yes') {
        GetFile_IfUpdate($ftp_src, $ftp_dest, $sFolder.$item['name'].'/', $cParam);
      } else if ($item['type'] == 'file') {
        $fExist = key_exists($item['name'], $aList_dest_mdtm);
        $fDownload = false;
        if (!$fExist) {
          //ローカルにはないファイル
          echo '[NEW]'.$sFolder.$item['name']."<br>\n";
          $fDownload = true;
        } elseif ($aList_dest_mdtm[$item['name']] != $item['modify']) { 
          //更新日時が相違のファイル
          echo '[Diff]'.$sFolder.$item['name']."<br>\n";
          echo date_mdtm($item['modify']).'[svr] != [local]'.date_mdtm($aList_dest_mdtm[$item['name']])."<br>\n";
          $fDownload = true;
        } else {
          //更新日時が同一
        }
        //ダウンロード
        if ($fDownload) {
          $local_filename = $cParam['base_path_dest'].$sFolder.$item['name'];  
          $ftpDateTime = DateTime::createFromFormat('YmdHis', $item['modify'], new DateTimeZone('UTC'));
          $ftpDateTime->setTimezone(new DateTimeZone('Asia/Tokyo'));
          if ($cParam['dryrun'] != 'yes') {
            ftp_get($ftp_src, $local_filename, $cParam['base_path_src'].$sFolder.$item['name'], FTP_BINARY);
            touch($local_filename, $ftpDateTime->getTimestamp());
          }
          echo 'download '.$local_filename."<br>\n";
          echo 'modify set:'.$ftpDateTime->format('Y-m-d H:i:s')."<br>\n";
        }
        if ($fExist) {
          unset($aList_dest_mdtm[$item['name']]);
        }
      }
    }
    //ローカルのみに存在するファイルに対する操作
    if (($cParam['delete_localonly'] === 'yes') && (count($aList_dest_mdtm) > 0)) {
      echo "===[delete_localonly]===<br>\n";
      //MDTM問い合わせ時に削除しているので、残る要素はローカルにしかないファイル
      foreach(array_keys($aList_dest_mdtm) as $key) {
        echo $key."<br>\n";
        if ($cParam['dryrun'] != 'yes') {
          ftp_delete($ftp_dest, $sFolder.$key);
        }
      }
    }
  }
 
  //FTPサーバへの接続
  function getftp($sServerVal) {
    $asServerVal = explode('/', $sServerVal);
    $ftp = ftp_connect($asServerVal[0]) or die("Couldn't connect to $asServerVal[0]");
    ftp_login($ftp, $asServerVal[1], $asServerVal[2]) or die("Couldn't login");
    return $ftp;
  }

  // 最終更新日時を'Y-m-d H:i:s'文字列として取得
  // "20230401235900"->"2023-04-01 23:59:00"
  function date_mdtm($sYmdHis) {
    $sYmdHis = explode('.', $sYmdHis)[0];
    return DateTime::createFromFormat('YmdHis', $sYmdHis, new DateTimeZone('UTC'))->format('Y-m-d H:i:s');
  }

  //ローカルファイルの最終更新日時をファイル名をkeyに取得する連想配列を返す
  // echo Dic_mdtm['index.html']; // '20230401235900' 
  function GetDic_mdtm($aList_dest) {
    $ret = array();
    foreach($aList_dest as $item) {
      if ($item['type'] === 'file') {
        $ret[$item['name']] = $item['modify'];
      }
    }
    return $ret;
  }

投稿へのコメントは コチラ(掲示板) へお願いします。

サイト管理人Blog