PHP
CSV

PHPでcsvをもとにファイル名を変更&移動する

個人的に必要だったので、メモ。

事情

  • 勤務先で、商品の画像を整理する必要があった
  • 手作業でやるかコードを書くか聞かれた。7000件以上画像があったので、もちろんコード書きます。
  • フォルダ/商品グループ/型番.jpg という感じでファイルは保存されている。グループは数千件。
  • その写真を、フォルダ/OK/JANコード.jpgという感じにしたい
  • 同じJANコードでいくつも写真がある場合は、janコードの後ろに「_数字」としたい
  • ルールに沿わないファイルについては、OKフォルダに入れない
  • フォルダ構成↓
PIC
|--category1
|  |--ABC15.jpg
|  |--ABF15.jpg.jpg
|
|--category2
|  |--ABC15.jpg
|  |--ABF15.jpg.jpg
|
・・・

こんな感じ

 データをどう変更したいか

  • 124515.jpg → 1111111111111.jpg
  • 123123.jpg → 2222222222222.jpg
  • 234566-A.jpg → 3333333333333_1.jpg
  • 234566-B.jpg → 3333333333333_2.jpg

みたいな感じ

Let's Try!

*データのバックアップを取っておきましょう。ファイルの名前を変更すると元に戻すのは難しいと思います。
*ファイル名変えるだけなら、いらない処理も書いてあります。

1.ファイルを移動させる

現状だと、写真がカテゴリごとに分かれていて、なんだか見にくいのでとりあえず同じ階層に移動させます。
ここがいろいろ書いてあって大変ありがたい。
この3番に書いてあるSPLを参考に書きます。

 <?php
$folderDir = <写真のカテゴリフォルダへのパス>;
$newFileDir = <写真の移動先へのパス>;

$fileList = getFileList($folderDir);

foreach($fileList as $file){
    $newFilePath = $newFileDir."\\".$file[1];
    $result = rename($file[0],$newFilePath);
    //確認のため
    var_dump($result);
}

//↓リンク先からほぼ引用
function getFileList($dir) {
    $iterator = new RecursiveDirectoryIterator($dir);
    $iterator = new RecursiveIteratorIterator($iterator);

    $list = array();
    foreach ($iterator as $fileinfo) {
        if ($fileinfo->isFile()) {
            $list[] = array( $fileinfo->getPathname() ,$fileinfo->getFilename() );
        }
    }

    return $list;
}

?>

こいつを起動すると、コンソールにtrueを返しながらファイルを移動してくれました。これで、一つのフォルダ直下にすべての画像達が集合してくれました。

2.ルールを作って仕分ける

正規表現で検索して、OKフォルダに移動したいと思います。
移動先のフォルダを先に作らないとエラーが出ます、、、

<?php 
$fileDir = <写真があるフォルダへのパス>;

$fileList = getFileList($fileDir);

foreach($fileList as $file){
    preg_match('/^\d+_m*\d*.jpg/', $file[1], $m);
    if($m){
        $result = rename($file[0],$fileDir.'\OK\\'.$file[1]);
        var_dump($result);
    }
}

function getFileList($dir) {
    $iterator = new RecursiveDirectoryIterator($dir);
    $iterator = new RecursiveIteratorIterator($iterator);

    $list = array();
    foreach ($iterator as $fileinfo) {
        if ($fileinfo->isFile()) {
            $list[] = array( $fileinfo->getPathname() ,$fileinfo->getFilename() );
        }
    }

    return $list;
}

?>

これを実行すれば正規表現にマッチしたファイルだけ移動してくれます。

正規表現の部分は適宜自分で変えましょう。

3 csvを読み込んで、それに従いファイルの名前を変更する

2カラムで、型番とJANが書かれているcsvファイルを読み込んで、ファイルの型番をJANコードに書き換えます。

 <?php 
$csvList  = array();
$csvFile = <csvファイルへのパス>;
$fp   = fopen($csvFile, "r");

while (($data = fgetcsv($fp, 0, ",")) !== FALSE) {
  $csvList[] = $data;
}
fclose($fp);

$picFileDir = <写真があるフォルダへのパス>;

$fileList = getFileList($picFileDir);

foreach($fileList as $file){
    preg_match('/^\d+/', $file[1], $fileCode);
    foreach ($csvList as $csv) {
        if ($csv[0] === $fileCode[0]) {
            $newFilePath = str_replace($csv[0],$csv[1],$file[0]);
            $result = rename($file[0],$newFilePath);
            var_dump($result);
        }
    }
}

function getFileList($dir) {
    $iterator = new RecursiveDirectoryIterator($dir);
    $iterator = new RecursiveIteratorIterator($iterator);

    $list = array();
    foreach ($iterator as $fileinfo) {
        if ($fileinfo->isFile()) {
            $list[] = array( $fileinfo->getPathname() ,$fileinfo->getFilename() );
        }
    }

    return $list;
}

?>

これを実行すると、型番がJANコードに書き換わります。
2番目の手順でまとめたほうがよさそうな気もしますが、気にしません。

ここでも、正規表現の部分は適宜書き換えましょう。

4.同じJANコードの画像に連番をつける

3の手順でJANコードがファイル名に含まれているので、
それを検索して、順番にファイル名を整頓します。

$csvList  = array();
$csvFile = <csvファイルへのパス>;
$fp   = fopen($file, "r");

while (($data = fgetcsv($fp, 0, ",")) !== FALSE) {
  $csvList[] = $data;
}
fclose($fp);

$picFileDir = <写真があるフォルダへのパス>;
foreach ($csvList as $csv) {
   $file_num = 0;
   foreach(glob($picFileDir."/".$csv[1]."*.jpg") as $file) {
        $finalPath = $picFileDir."/".$csv[1]. ".jpg";

        if($file_num > 0){
            $finalPath = $picFileDir."/".$csv[1] ."_".$file_num. ".jpg";
        }
        $result = rename($file,$finalPath);
        var_dump($result);

        $file_num++;
    }
}

このような形です。glob内を適宜書き換えたり、$finalPathを適宜書き換えましょう。

これにて、一応やりたいことはできた。

所感

  • 動くものはかけたが冗長な気がする
  • 調べる&コード書く&この記事を書くと、同時進行で2~3時間かかった。もっと素早く実装したい・・・。
  • 変数名きたねえんだよ!
  • 一つのファイルにまとめて実行したほうがええやんか!