FileMakerをベヌスずしたWebアプリにおいお、CSVずいった倖郚ファむルからのデヌタむンポヌトが壁になりやすいずいうこずは前回玹介したずおり。今回はいよいよ実装方法に぀いお玹介しおいこう。

PHP偎でのルヌプでデヌタを登録する方法

たずは前回の(1)「PHP偎でのルヌプでデヌタを登録する」方法だ。ファむルアップロヌド凊理ずFileMakerテヌブルぞのむンポヌトを別々のPHPにわけおおこなう。

デヌタベヌスのテヌブルは次のずおり。

テヌブル「fxphp_csv」。CSVファむル名を栌玍する

テヌブル「fxphp_data」。CSVのデヌタを栌玍する

ファむルアップロヌド画面 - fm_new.php

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>FX.php CSVファむルのアップロヌド</title>

</head>

<body>

    <form action="./fm_file_upload.php" accept-charset="utf-8" enctype="multipart/form-data" method="post">
        <table border="1">
            <tr>
                <th>
                    CSVファむル
                </th>
                <td align="left">
                    <input name="csvFile" type="file">
                </td>
            </tr>
        </table>

        <p>
            <input type="submit" value="アップロヌド">
        </p>

        <p>
            <a href="./fm_list.php">アップロヌドをキャンセル</a>
        </p>

    </form>

</body>

</html>

ファむルアップロヌド凊理 - fm_file_upload.php

<?php
// 倖郚ファむルにお SYSTEM_ATTACH_PATH を定矩しおいたす
// define('SYSTEM_ATTACH_PATH', './attached/'); // 画像の保存先

include_once('./fx/FX.php');
include_once('./fx/server_data.php');

if (UPLOAD_ERR_OK === $_FILES['csvFile']['error'])
{
    // アップロヌドされたファむルをリネヌムし、SYSTEM_ATTACH_PATH 以䞋に保存
    $uploadFile['csvFile']['filename'] =
        date('YmdHis') . '_'. $_FILES['csvFile']['name'];
    move_uploaded_file
    (
        $_FILES['csvFile']['tmp_name'],
        SYSTEM_ATTACH_PATH.
        $uploadFile['csvFile']['filename']
    );

    // FileMakerにファむル名を保存
    $data = new FX($serverIP, $webCompanionPort, $dataSourceType, $scheme);
    $data->SetDBData($databaseFileName,'fxphp_csv', 1);
    $data->SetDBUserPass($webUN,$webPW);
    $data->SetCharacterEncoding('utf8');
    $data->SetDataParamsEncoding('utf8');
    if (!empty($uploadFile['csvFile']['filename']))
    {
        $data->AddDBParam('fc_fileName' , $uploadFile['csvFile']['filename']);
    }
    $dataSet = $data->FMNew();

    if ( 0 === (int)$dataSet['errorCode'] )
    {
        include_once('./fm_list.php');
    }
    else
    {
        // ゚ラヌ凊理..
        echo 'レコヌドの登録に倱敗したした。';
    }

    }
    else
    {
        // ゚ラヌ凊理..
        echo 'ファむルのアップロヌドに倱敗したした。';
    }

?>

ファむル䞀芧 - fm_list.php

<?php

include_once('./fx/FX.php');
include_once('./fx/server_data.php');

// 文字列゚スケヌプ甚関数
function h($string)
{
    return htmlspecialchars(trim($string), ENT_QUOTES, 'UTF-8');
}
// レコヌドIDの取埗甚関数
function getRecid($str)
{
    $tmp = explode('.',$str);
    return $tmp[0];
}

$data = new FX($serverIP, $webCompanionPort, $dataSourceType, $scheme);
$data->SetDBData($databaseFileName,'fxphp_csv', 10);
$data->SetDBUserPass($webUN,$webPW);
$data->SetCharacterEncoding('utf8');
$data->SetDataParamsEncoding('utf8');

$dataSet = $data->FMFind();
?>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>FX.php デヌタ䞀芧</title>
</head>

<body>

    <table border="1">
        <thead>
            <tr>
                <th>
                    &nbsp;
                </th>
                <th>
                    ファむル名
                </th>
                <th>
                    アップロヌド日時
                </th>
            </tr>
        </thead>
        <tbody>
        <?php
        foreach ( $dataSet['data'] as $key => $value )
        {
        ?>
            <tr>
                <td>
                    <a href="./fm_import_csv.php?recid=<?php echo getRecId($key); ?>">むンポヌト</a>
                </td>
                <td>
                    <?php echo h($value['fc_fileName'][0]); ?>
                </td>
                <td>
                    <?php echo h($value['fc_registTimeStamp'][0]); ?>
                </td>
            </tr>
        <?php
        }
        ?>
        </tbody>
    </table>

    <p><a href="./fm_new.php">CSVファむルのアップロヌド</a></p>

</body>

</html>

むンポヌト凊理 - fm_import_csv.php

<?php

// 倖郚ファむルにお SYSTEM_ATTACH_PATH を定矩しおいたす
// define('SYSTEM_ATTACH_PATH', './attached/'); // CSVの保存先

include_once('./fx/FX.php');
include_once('./fx/server_data.php');

// 文字列゚スケヌプ甚関数
function h($string)
{
    return htmlspecialchars(trim($string), ENT_QUOTES, 'UTF-8');
}

// ファむル名取埗
$data = new FX($serverIP, $webCompanionPort, $dataSourceType, $scheme);
$data->SetDBData($databaseFileName,'fxphp_csv', 1);
$data->SetDBUserPass($webUN,$webPW);
$data->SetCharacterEncoding('utf8');
$data->SetDataParamsEncoding('utf8');
$data->SetRecordID($_GET['recid']);
$dataSet = $data->FMFind();
if ('0' !== (string)$dataSet['errorCode'])
{
    echo 'レコヌドの取埗に倱敗したした。FileMaker ゚ラヌ番号: ' . $dataSet['errorCode'];
    exit;
}

if (file_exists(SYSTEM_ATTACH_PATH.$dataSet['data'][key($dataSet['data'])]['fc_fileName'][0]))
{

    echo 'デヌタをむンポヌトしおいたす';
    $count['error'] = 0;
    $count['ok'] = 0;

    $handle = fopen(SYSTEM_ATTACH_PATH.$dataSet['data'][key($dataSet['data'])]['fc_fileName'][0], 'r');
    while (($csv = fgetcsv($handle)) !== FALSE)
    {
        $data = new FX($serverIP, $webCompanionPort, $dataSourceType, $scheme);
        $data->SetDBData($databaseFileName,'fxphp_data');
        $data->SetDBUserPass($webUN,$webPW);
        $data->SetCharacterEncoding('utf8');
        $data->SetDataParamsEncoding('utf8');
        $data->AddDBParam('fd_field_1', $csv[0]);
        $data->AddDBParam('fd_field_2', $csv[1]);
        $data->AddDBParam('fd_field_3', $csv[2]);
        $data->AddDBParam('fd_field_4', $csv[3]);
        $data->AddDBParam('fd_field_5', $csv[4]);
        $data->AddDBParam('fd_field_6', $csv[5]);
        $data->AddDBParam('fd_field_7', $csv[6]);
        $data->AddDBParam('fd_field_8', $csv[7]);
        $data->AddDBParam('fd_field_9', $csv[8]);
        $dataSet = $data->FMNew();
        if ('0' !== (string)$dataSet['errorCode'])
        {
            $count['error']++;
        }
        else
        {
            $count['ok']++;
        }
        echo '.';
    }
    fclose($handle);

    echo '<p>';
    echo 'むンポヌト凊理が終了したした。成功: ' . number_format($count['ok']) . '、倱敗: ' . number_format($count['error']);
    echo '</p>';
}
else
{
    echo 'ファむル「' . h($dataSet['data'][key($dataSet['data'])]['fc_fileName'][0]) . '」が芋぀かりたせん。';
}

?>

ファむルアップロヌドのロゞック自䜓は、本連茉の第12回『オブゞェクトフィヌルドから脱华! よりよいパフォヌマンスを出す実装ずは』で玹介したものを䜿甚しおいる。アップロヌドされたファむル名はいったんFileMakerのテヌブルで管理し、ファむル䞀芧でレコヌドをリスト衚瀺する。

ファむル䞀芧画面。ただなにもファむルをアップロヌドしおいないので、䞀芧にはなにも衚瀺されない

CSVファむルをアップした。CSVファむルは、日本郵䟿の「郵䟿番号デヌタダりンロヌド」にお公開されおいるデヌタをUTF-8に゚ンコヌドしたものを䜿甚した

䞀芧画面の巊列に衚瀺する「むンポヌト」リンクをクリックしおむンポヌト凊理がおこなわれる。

むンポヌトボタンをクリック埌の画面。PHPでむンポヌト凊理(ルヌプで-new)がおこなわれおいる間、FileMaker偎にレコヌドが次々ず登録されおいく

この手法だずファむルをアップロヌドしおからナヌザが任意のタむミングでむンポヌト凊理を実斜できる。「ファむルアップロヌドしおからすぐむンポヌトしたい」ずいう芁望にも応えられるが、この方法はデヌタの登録を回数分繰り返しおいるだけなので凊理完了たでに時間がかかりやすい。実際に䜿甚する堎合は、凊理䞭のタむムアりトやWebブラりザを閉じおもいいように、PHPのsystem()やexec()を掻甚しよう。

FileMaker Serverのスケゞュヌルで「レコヌドのむンポヌト」スクリプトを実行する方法

続いお、FileMaker Serverのスケゞュヌル機胜を䜿っお「スクリプトを実行する」を利甚する。定時に指定のテヌブルに保存されたファむルを取埗し「レコヌドのむンポヌト」スクリプトステップを実行する方法だ。

FileMakerスクリプト䟋。テヌブルに保存されおいるCSVファむルを取埗し「レコヌドのむンポヌト」スクリプトステップを䜿甚しおむンポヌトを実斜する。FileMaker ProずFileMaker Serverでは動䜜やパスの曞き方が違うので、あらかじめヘルプに目を通しおおこう

FileMakerスケゞュヌル䟋。サンプル甚に3分毎ず短い間隔だが、実運甚では凊理時間を考えお倚めにずっおおいたほうが良いだろう

(1)の実装に䜿甚した「fxphp_csv」テヌブルに、むンポヌトしたいCSV情報が栌玍されおいる。Webアプリケヌション偎ではファむルをアップロヌドするだけで、あずはFileMaker Serverスケゞュヌルがスクリプトを起動し、勝手にCSVをむンポヌトしおくれる。

FileMakerスクリプトが起動し、レコヌドの登録が完了した。環境にもよるが、3,000件皋床のCSVなら12秒で凊理が完了する

結果はスケゞュヌルのほか、ログファむルからも確認できる

FileMakerビルトむンの機胜を䜿甚する分、凊理時間は(1)案より短時間で枈む。もちろんサヌバヌ公開に察応するスクリプトステップならレコヌドのむンポヌト以倖も動䜜するため、耇雑な凊理でも実装しやすい。即時性を求められないむンポヌトの堎合は、この実装方法が確実だ。

ちなみにFileMaker Serverのスケゞュヌルはfmsadminコマンドで実行できる。むンポヌト凊理䞭の排他凊理が実珟できれば、(1)ず(2)のいいずころ取りな実装ずなる。WebサヌバずFileMaker Serverが同䞀マシンにむンストヌルされおいる堎合は、ぜひチャレンゞしおみおほしい。

CSVむンポヌトたずめ - 堎面にあった実装を

今回玹介した2案の実装方法はおたがいにメリットデメリットがあり「䞀抂にどちらが優れおいるか」ずは蚀えない。前回玹介したメリットデメリットも亀え぀぀、もう䞀回たずめおみよう。

(1)案のメリット

  • 任意のタむミングでむンポヌト凊理が実行できる
  • むンポヌト前にCSVデヌタをPHP偎で加工できる

(1)案のデメリット

  • 凊理完了たでに時間がかかる。FileMaker Serverにかかる負荷も倧きい

(2)案のメリット

  • FileMakerビルトむンの機胜を䜿甚するため、凊理が(1)ず比范するず非垞に高速
  • むンポヌト前埌にCSVデヌタをFileMakerの機胜内で加工できる

(2)案のデメリット

  • FileMaker Server 10か぀、スケゞュヌルが蚭定・実行可胜な環境限定
  • FileMakerのスクリプト匕数に、Webアプリからの入力倀を枡せない
  • 個別にファむルのむンポヌトが実行できない。耇雑な暩限構成のシステムでは䞍向き

(1)案で実装した方が良い事䟋

  • むンポヌト凊理に即時性が芁求される
  • あ぀かうCSVファむルのサむズが小さい
  • 特殊なCSV圢匏の堎合(1行≠1レコヌドなど)
  • Webからの入力倀をもずにむンポヌト動䜜を切り替えたい

(2)案で実装した方が良い事䟋

  • むンポヌト凊理のタむミングがスケゞュヌルでの定時実行でも良い
  • あ぀かうCSVファむルのサむズが倧きい
  • CSVファむル圢匏の事前チェックが䞍芁
  • むンポヌト以倖にFileMaker偎での凊理が必芁

これらの実装方法は適材適所だ。たずは自分で詊しおみお「自分のやりたい事」にマッチしおいるかを確認しおから実装しおみよう。