Index: /branches/comu-ver2/data/class/pages/admin/basis/LC_Page_Admin_Basis_ZipInstall.php
===================================================================
--- /branches/comu-ver2/data/class/pages/admin/basis/LC_Page_Admin_Basis_ZipInstall.php	(revision 17954)
+++ /branches/comu-ver2/data/class/pages/admin/basis/LC_Page_Admin_Basis_ZipInstall.php	(revision 18317)
@@ -3,5 +3,5 @@
  * This file is part of EC-CUBE
  *
- * Copyright(c) 2000-2007 LOCKON CO.,LTD. All Rights Reserved.
+ * Copyright(c) 2000-2009 LOCKON CO.,LTD. All Rights Reserved.
  *
  * http://www.lockon.co.jp/
@@ -33,4 +33,7 @@
 /** 郵便番号CSV ファイルのパス */
 define("ZIP_CSV_FILE_PATH", DATA_PATH . "downloads/KEN_ALL.CSV");
+
+/** UTF-8 変換済みの郵便番号CSV ファイルのパス */
+define("ZIP_CSV_UTF8_FILE_PATH", DATA_PATH . "downloads/KEN_ALL_utf-8.CSV");
 
 /**
@@ -43,4 +46,12 @@
 class LC_Page_Admin_Basis_ZipInstall extends LC_Page {
 
+    /** CSVの行数 */
+    var $tpl_line = 0;
+    var $tpl_mode;
+    var $exec;
+    var $tpl_count_mtb_zip;
+    /** フォームパラメータの配列 */
+    var $objFormParam;
+
     // }}}
     // {{{ functions
@@ -53,4 +64,12 @@
     function init() {
         parent::init();
+        $this->tpl_mainpage = 'basis/zip_install.tpl';
+        $this->tpl_subnavi = 'basis/subnavi.tpl';
+        $this->tpl_subno = 'zip_install';
+        $this->tpl_subtitle = '郵便番号DB登録';
+        $this->tpl_mainno = 'basis';
+
+        $this->tpl_mode = $_GET['mode'];
+        $this->exec = (boolean)$_GET['exec'];
     }
 
@@ -62,4 +81,83 @@
     function process() {
         $objQuery = new SC_Query();
+
+        SC_Utils_Ex::sfIsSuccess(new SC_Session);
+
+        // パラメータ管理クラス
+        $this->objFormParam = new SC_FormParam();
+        // パラメータ情報の初期化
+        $this->lfInitParam();
+        // POST値の取得
+        $this->objFormParam->setParam($_GET);
+        $this->arrErr = $this->objFormParam->checkError();
+        $this->arrForm = $this->objFormParam->getHashArray();
+
+        if ($this->exec) {
+            if (!empty($this->arrErr)) {
+                SC_Utils_Ex::sfDispException();
+            }
+            switch ($this->tpl_mode) {
+                // 自動登録
+                case 'auto':
+                    $objQuery->begin();
+                    $objQuery->delete('mtb_zip');
+                    $this->insertMtbZip();
+                    $objQuery->commit();
+                    break;
+                // 手動登録
+                case 'manual':
+                    $this->insertMtbZip($this->arrForm['startRowNum']);
+                    break;
+            }
+            exit;
+        }
+
+        switch ($this->tpl_mode) {
+            // 手動削除
+            case 'delete':
+                $objQuery->delete('mtb_zip');
+
+                // 進捗・完了画面を表示しない
+                $this->tpl_mode = null;
+
+                break;
+        }
+
+        $this->tpl_line = $this->countZipCsv();
+        $this->tpl_count_mtb_zip = $this->countMtbZip();
+
+        $objView = new SC_AdminView();
+
+        $objView->assignobj($this);
+        $objView->display(MAIN_FRAME);
+    }
+
+    /**
+     * デストラクタ.
+     *
+     * @return void
+     */
+    function destroy() {
+        parent::destroy();
+    }
+
+    /**
+     * パラメータ情報の初期化
+     *
+     * @return void
+     */
+    function lfInitParam() {
+        if ($this->tpl_mode == 'manual') {
+            $this->objFormParam->addParam("開始行", "startRowNum", INT_LEN, "n", array("EXIST_CHECK", "MAX_LENGTH_CHECK", "NUM_CHECK"));
+        }
+    }
+
+    /**
+     * DB登録
+     *
+     * @return void
+     */
+    function insertMtbZip($start = 1) {
+        $objQuery = new SC_Query();
         $objSess = new SC_Session();
 
@@ -67,47 +165,45 @@
         SC_Utils_Ex::sfIsSuccess($objSess);
 
-        $fp = fopen(ZIP_CSV_FILE_PATH, "r");
-        $img_path = USER_URL . "packages/" . TEMPLATE_NAME . "/img/";
-
-        echo ('<html>');
-        echo ('<body bgcolor="#494E5F">');
+        $img_path = USER_URL . USER_PACKAGE_DIR . DEFAULT_TEMPLATE_NAME . "/img/";
+
+        ?>
+        <html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
+        <head>
+            <meta http-equiv="Content-Type" content="text/html; charset=<?php echo CHAR_CODE ?>" />
+        </head>
+        <body>
+        <p>進捗状況</p>
+        <div style="background-color: #494E5F;">
+        <?php
         // 一部のIEは256バイト以上受け取ってから表示を開始する。
         SC_Utils_Ex::sfFlush(true);
 
-#('http://www.post.japanpost.jp/zipcode/dl/kogaki/lzh/ken_all.lzh')
-        if(!$fp) {
-            SC_Utils_Ex::sfErrorHeader(">> " . ZIP_CSV_FILE_PATH . "の取得に失敗しました。");
-        } else {
-            print("<img src='". $img_path . "install/main_w.jpg'><br>");
-            SC_Utils_Ex::sfFlush();
-
-            // CSVの件数を数える
-            $line = 0;
-            while(!feof($fp)) {
-                fgets($fp, ZIP_CSV_LINE_MAX);
-                $line++;
-            }
-
-            print("<img src='". $img_path ."install/space_w.gif'>");
-            SC_Utils_Ex::sfFlush();
-
-            // ファイルポインタを戻す
-            fseek($fp, 0);
-
-            // 画像を一個表示する件数を求める。
-            $disp_line = intval($line / IMAGE_MAX);
-
-            $objQuery->begin();
-            $objQuery->delete('mtb_zip');
-            $cnt = 1;
-            $img_cnt = 0;
-            $safe_mode = (boolean)ini_get('safe_mode');
-            $max_execution_time
-                = is_numeric(ini_get('max_execution_time'))
-                ? intval(ini_get('max_execution_time'))
-                : intval(get_cfg_var('max_execution_time'))
-            ;
-            while (!feof($fp)) {
-                $arrCSV = fgetcsv($fp, ZIP_CSV_LINE_MAX);
+        echo "<img src='" . $img_path . "admin/basis/zip_install_progress.gif'><br />";
+        echo "<img src='" . $img_path . "install/space_w.gif'>";
+        SC_Utils_Ex::sfFlush();
+
+        // 画像を一個表示する件数を求める。
+        $line_all = $this->countZipCsv();
+        $disp_line = intval($line_all / IMAGE_MAX);
+
+        /** 現在行(CSV形式。空行は除く。) */
+        $cntCurrentLine = 0;
+        /** 挿入した行数 */
+        $cntInsert = 0;
+        $img_cnt = 0;
+        $safe_mode = (boolean)ini_get('safe_mode');
+        $max_execution_time
+            = is_numeric(ini_get('max_execution_time'))
+            ? intval(ini_get('max_execution_time'))
+            : intval(get_cfg_var('max_execution_time'))
+        ;
+
+        $fp = $this->openZipCsv();
+        while (!feof($fp)) {
+            $arrCSV = fgetcsv($fp, ZIP_CSV_LINE_MAX);
+            if (empty($arrCSV)) continue;
+            $cntCurrentLine++;
+            if ($cntCurrentLine >= $start) {
+                $sqlval = array();
                 // $sqlval['code'] = $arrCSV[0];
                 // $sqlval['old_zipcode'] = $arrCSV[1];
@@ -116,7 +212,7 @@
                 // $sqlval['city_kana'] = $arrCSV[4];
                 // $sqlval['town_kana'] = $arrCSV[5];
-                $sqlval['state'] = mb_convert_encoding($arrCSV[6], CHAR_CODE, 'sjis-win');
-                $sqlval['city'] = mb_convert_encoding($arrCSV[7], CHAR_CODE, 'sjis-win');
-                $sqlval['town'] = mb_convert_encoding($arrCSV[8], CHAR_CODE, 'sjis-win');
+                $sqlval['state'] = $arrCSV[6];
+                $sqlval['city'] = $arrCSV[7];
+                $sqlval['town'] = $arrCSV[8];
                 // $sqlval['flg1'] = $arrCSV[9];
                 // $sqlval['flg2'] = $arrCSV[10];
@@ -126,37 +222,100 @@
                 // $sqlval['flg6'] = $arrCSV[14];
                 $objQuery->insert("mtb_zip", $sqlval);
-                $cnt++;
-                // $disp_line件ごとに進捗表示する
-                if($cnt % $disp_line == 0 && $img_cnt < IMAGE_MAX) {
-                    print("<img src='". $img_path ."install/graph_1_w.gif'>");
-                    SC_Utils_Ex::sfFlush();
-                    $img_cnt++;
+                $cntInsert++;
+            }
+
+            // $disp_line件ごとに進捗表示する
+            if($cntCurrentLine % $disp_line == 0 && $img_cnt < IMAGE_MAX) {
+                print("<img src='". $img_path ."install/graph_1_w.gif'>");
+                SC_Utils_Ex::sfFlush();
+                $img_cnt++;
+            }
+            // 暴走スレッドが残留する確率を軽減したタイムアウト防止のロジック
+            // TODO 動作が安定していれば、SC_Utils 辺りに移動したい。
+            if (!$safe_mode) {
+                // タイムアウトをリセット
+                set_time_limit($max_execution_time);
+            }
+        }
+        fclose($fp);
+
+        echo "<img src='". $img_path ."install/space_w.gif'>";
+        echo "</div>\n";
+        
+        ?>
+        <script type="text/javascript" language="javascript">
+            <!--
+                // 完了画面
+                function complete() {
+                    document.open("text/html","replace");
+                    document.clear();
+                    document.write("<p>完了しました。<br />");
+                    document.write("<?php echo $cntInsert ?> 件を追加しました。</p>");
+                    document.write("<p><a href='?' target='_top'>戻る</a></p>");
+                    document.close();
                 }
-                // 暴走スレッドが残留する確率を軽減したタイムアウト防止のロジック
-                // TODO 動作が安定していれば、SC_Utils 辺りに移動したい。
-                if (!$safe_mode) {
-                    // タイムアウトをリセット
-                    set_time_limit($max_execution_time);
-                }
-            }
-            fclose($fp);
-            $objQuery->commit();
-
-            print("<img src='". $img_path ."install/space_w.gif'><br>\n");
-            print("<table width='700' height='50' border='0' cellpadding='0' cellspacing='0'>\n");
-            print("<tr>\n");
-            print("<td align='center'><a href='javascript:window.close()'><img src='". $img_path ."install/close.gif' alt='CLOSE' width='85' height='22' border='0' /></a></td>\n");
-            print("</tr>\n");
-            print("</table>\n");
-        }
-    }
-
-    /**
-     * デストラクタ.
-     *
-     * @return void
-     */
-    function destroy() {
-        parent::destroy();
+                // コンテンツを削除するため、タイムアウトで呼び出し。
+                setTimeout("complete()", 0);
+            // -->
+        </script>
+        </body>
+        </html>
+        <?php
+    }
+
+    function openZipCsv() {
+        // http://www.post.japanpost.jp/zipcode/dl/kogaki/lzh/ken_all.lzh
+        $this->convertZipCsv();
+        $fp = fopen(ZIP_CSV_UTF8_FILE_PATH, "r");
+        if (!$fp) {
+            SC_Utils_Ex::sfDispException(ZIP_CSV_UTF8_FILE_PATH . ' の読み込みに失敗しました。');
+        }
+        return $fp;
+    }
+
+    function convertZipCsv() {
+        if (file_exists(ZIP_CSV_UTF8_FILE_PATH)) return;
+
+        $fpr = fopen(ZIP_CSV_FILE_PATH, "r");
+        if (!$fpr) {
+            SC_Utils_Ex::sfDispException(ZIP_CSV_FILE_PATH . ' の読み込みに失敗しました。');
+        }
+
+        $fpw = fopen(ZIP_CSV_UTF8_FILE_PATH, "w");
+        if (!$fpw) {
+            SC_Utils_Ex::sfDispException(ZIP_CSV_UTF8_FILE_PATH . ' を開けません。');
+        }
+
+        while (!feof($fpr)) {
+            fwrite($fpw, mb_convert_encoding(fgets($fpr, ZIP_CSV_LINE_MAX), CHAR_CODE, 'sjis-win'));
+        }
+
+        fclose($fpw);
+        fclose($fpr);
+    }
+
+    function countMtbZip() {
+        $objQuery = new SC_Query();
+        return $objQuery->count('mtb_zip');
+    }
+
+    function countZipCsv() {
+        $line = 0;
+        $fp = $this->openZipCsv();
+
+        // CSVの行数を数える
+        while (!feof($fp)) {
+            /*
+            // 正確にカウントする
+            $tmp = fgetcsv($fp, ZIP_CSV_LINE_MAX);
+            */
+            // 推測でカウントする
+            $tmp = fgets($fp, ZIP_CSV_LINE_MAX);
+            if (empty($tmp)) continue;
+            $line++;
+        }
+        fclose($fp);
+
+        return $line;
     }
 }
Index: /branches/comu-ver2/data/Smarty/templates/default/admin/basis/subnavi.tpl
===================================================================
--- /branches/comu-ver2/data/Smarty/templates/default/admin/basis/subnavi.tpl	(revision 18254)
+++ /branches/comu-ver2/data/Smarty/templates/default/admin/basis/subnavi.tpl	(revision 18317)
@@ -31,5 +31,5 @@
 <li<!--{if $tpl_subno == 'seo'}--> class="on"<!--{/if}--> id="navi-basis-seo"><a href="<!--{$smarty.const.URL_DIR}-->admin/basis/seo.php"><span>SEO管理</span></a></li>
 <li<!--{if $tpl_subno == 'kiyaku'}--> class="on"<!--{/if}--> id="navi-basis-kiyaku"><a href="<!--{$smarty.const.URL_DIR}-->admin/basis/kiyaku.php"><span>会員規約設定</span></a></li>
-<li<!--{if $tpl_subno == 'zip_install'}--> class="on"<!--{/if}--> id="navi-basis-zip"><a href="#" onclick="win03('<!--{$smarty.const.URL_DIR}-->admin/basis/zip_install.php', 'install', '750', '350');"><span>郵便番号DB登録</span></a></li>
+<li<!--{if $tpl_subno == 'zip_install'}--> class="on"<!--{/if}--> id="navi-basis-zip"><a href="<!--{$smarty.const.URL_DIR}-->admin/basis/zip_install.php"><span>郵便番号DB登録</span></a></li>
 <li<!--{if $tpl_subno == 'control'}--> class="on"<!--{/if}--> id="navi-basis-control"><a href="<!--{$smarty.const.URL_DIR}-->admin/basis/control.php"><span>サイト管理設定</span></a></li>
 <li<!--{if $tpl_subno == 'holiday'}--> class="on"<!--{/if}--> id="navi-basis-holiday"><a href="<!--{$smarty.const.URL_DIR}-->admin/basis/holiday.php"><span>定休日管理</span></a></li>
Index: /branches/comu-ver2/data/Smarty/templates/default/admin/basis/zip_install.tpl
===================================================================
--- /branches/comu-ver2/data/Smarty/templates/default/admin/basis/zip_install.tpl	(revision 18317)
+++ /branches/comu-ver2/data/Smarty/templates/default/admin/basis/zip_install.tpl	(revision 18317)
@@ -0,0 +1,61 @@
+<!--{*
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2008 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+*}-->
+<!--{if $tpl_mode|strlen == 0 || $arrErr|count >= 1}-->
+    <style type="text/css">
+        .item {
+            margin-top: 1em;
+        }
+    </style>
+    <form name="form1" id="form1" method="get" action="?" onsubmit="return false;">
+        <input type="hidden" name="mode" value="">
+        <p>郵便番号CSVには <!--{$tpl_line|escape}--> 行のデータがあります。</p>
+        <p>郵便番号DBには <!--{$tpl_count_mtb_zip|escape}--> 行のデータがあります。</p>
+        <!--{if $tpl_count_mtb_zip == 0}-->
+            <p class="attention">登録を行なってください。</p>
+        <!--{elseif $tpl_line <> $tpl_count_mtb_zip}-->
+            <p class="attention">行数に差異があります。登録に異常がある恐れがあります。</p>
+        <!--{/if}-->
+
+        <div style="margin: 1em 0;">
+            <p>通常は、[自動登録] を利用してください。<br />
+                ただし、タイムアウトしてしまう環境では、タイムアウトした後に [手動登録] を正常に完了するまで繰り返してください。</p>
+        </div>
+
+        <div class="item">
+            <button type="button" onclick="fnModeSubmit('auto', '', '');">自動登録</button><br />
+            全ての郵便番号を削除してから、登録しなおします。タイムアウトした場合、元の状態に戻ります。
+        </div>
+        <div class="item">
+            <button type="button" onclick="fnModeSubmit('delete', '', '');">手動削除</button><br />
+            全ての郵便番号を削除します。再登録するまで、住所自動入力は機能しなくなります。
+        </div>
+        <div class="item">
+            <button type="button" onclick="fnModeSubmit('manual', '', '');">手動登録</button>
+            開始行: <input type="text" name="startRowNum" value="<!--{$arrForm.startRowNum|default:$tpl_count_mtb_zip+1|escape}-->" size="8"><span class="attention"><!--{$arrErr.startRowNum}--></span><br />
+            指定した行数から郵便番号を登録します。タイムアウトした場合、直前まで登録されます。
+        </div>
+    </form>
+<!--{else}-->
+    <iframe src="?mode=<!--{$tpl_mode|escape}-->&amp;exec=yes&amp;startRowNum=<!--{$arrForm.startRowNum|escape}-->" name="progress" height="200" width="750" frameborder="0"></iframe>
+<!--{/if}-->
