source: branches/version-2_11-dev/data/class/pages/admin/basis/LC_Page_Admin_Basis_ZipInstall.php @ 20945

Revision 20945, 13.8 KB checked in by Seasoft, 13 years ago (diff)

#144 (郵便番号DB のアップデート)
#1317 (郵便番号DB登録 [自動登録]と[削除]のタイミングで、KEN_ALL_utf-8.CSV も削除)

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-httpd-php; charset=UTF-8
Line 
1<?php
2/*
3 * This file is part of EC-CUBE
4 *
5 * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
6 *
7 * http://www.lockon.co.jp/
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22 */
23
24// {{{ requires
25require_once CLASS_EX_REALDIR . 'page_extends/admin/LC_Page_Admin_Ex.php';
26
27/** CSV ファイルの最大行数 */
28define("ZIP_CSV_LINE_MAX", 8192);
29
30/** 画像の表示数量 */
31define("IMAGE_MAX", 680);
32
33/** 郵便番号CSV ファイルのパス */
34define("ZIP_CSV_REALFILE", DATA_REALDIR . "downloads/KEN_ALL.CSV");
35
36/** UTF-8 変換済みの郵便番号CSV ファイルのパス */
37define("ZIP_CSV_UTF8_REALFILE", DATA_REALDIR . "downloads/KEN_ALL_utf-8.CSV");
38
39/**
40 * 郵便番号DB登録 のページクラス.
41 *
42 * @package Page
43 * @author LOCKON CO.,LTD.
44 * @version $Id:LC_Page_Admin_Basis_ZipInstall.php 16741 2007-11-08 00:43:24Z adachi $
45 */
46class LC_Page_Admin_Basis_ZipInstall extends LC_Page_Admin_Ex {
47
48    /** CSVの行数 */
49    var $tpl_line = 0;
50    var $tpl_mode;
51    var $exec;
52    var $tpl_count_mtb_zip;
53
54    /** CSV の更新日時 */
55    var $tpl_csv_datetime;
56
57    /** ZIP アーカイブファイルの取得元 */
58    var $zip_download_url = 'http://www.post.japanpost.jp/zipcode/dl/kogaki/zip/ken_all.zip';
59
60    /** 日本郵便から取得した ZIP アーカイブファイルの保管パス */
61    var $zip_csv_temp_realfile;
62
63    // }}}
64    // {{{ functions
65
66    /**
67     * Page を初期化する.
68     *
69     * @return void
70     */
71    function init() {
72        parent::init();
73        $this->tpl_mainpage = 'basis/zip_install.tpl';
74        $this->tpl_subno = 'zip_install';
75        $this->tpl_maintitle = '基本情報管理';
76        $this->tpl_subtitle = '郵便番号DB登録';
77        $this->tpl_mainno = 'basis';
78
79        $this->tpl_mode = $this->getMode();
80        $this->exec = (boolean)$_GET['exec'];
81        $this->zip_csv_temp_realfile = DATA_REALDIR . 'downloads/tmp/ken_all.zip';
82    }
83
84    /**
85     * Page のプロセス.
86     *
87     * @return void
88     */
89    function process() {
90        $this->action();
91        $this->sendResponse();
92    }
93
94    /**
95     * Page のアクション.
96     *
97     * @return void
98     */
99    function action() {
100        // パラメータ管理クラス
101        $objFormParam = new SC_FormParam_Ex();
102        // パラメータ情報の初期化
103        $this->lfInitParam($this->tpl_mode, $objFormParam);
104        $objFormParam->setParam($_GET);
105        $this->arrErr = $objFormParam->checkError();
106        $this->arrForm = $objFormParam->getHashArray();
107
108        if ($this->exec) {
109            if (!empty($this->arrErr)) {
110                SC_Utils_Ex::sfDispException();
111            }
112            switch ($this->tpl_mode) {
113                // 自動登録
114                case 'auto':
115                    $this->lfAutoCommitZip();
116                    break;
117                // DB手動登録
118                case 'manual':
119                    $this->insertMtbZip($this->arrForm['startRowNum']);
120                    break;
121            }
122            exit;
123        }
124
125        switch ($this->tpl_mode) {
126            // 削除
127            case 'delete':
128                $this->lfDeleteZip();
129
130                // 進捗・完了画面を表示しない
131                $this->tpl_mode = null;
132                break;
133
134            // 郵便番号CSV更新
135            case 'update_csv';
136                $this->lfDownloadZipFileFromJp();
137                $this->lfExtractZipFile();
138
139                // 進捗・完了画面を表示しない
140                $this->tpl_mode = null;
141                break;
142        }
143
144        $this->tpl_line = $this->countZipCsv();
145        $this->tpl_count_mtb_zip = $this->countMtbZip();
146        $this->tpl_csv_datetime = $this->lfGetCsvDatetime();
147        // XXX PHP4 を切捨てたら、ダウンロードの必要性チェックなども行いたい
148        // $arrHeader = get_headers($this->zip_download_url, 1);
149    }
150
151    /**
152     * デストラクタ.
153     *
154     * @return void
155     */
156    function destroy() {
157        parent::destroy();
158    }
159
160    function lfAutoCommitZip() {
161        $objQuery =& SC_Query_Ex::getSingletonInstance();
162
163        $this->lfDownloadZipFileFromJp();
164        $this->lfExtractZipFile();
165
166        $objQuery->begin();
167        $this->lfDeleteZip();
168        $this->insertMtbZip();
169        $objQuery->commit();
170    }
171
172    /**
173     * テーブルデータと UTF-8 変換済みの郵便番号 CSV を削除
174     *
175     * @return void
176     */
177    function lfDeleteZip() {
178        $objQuery =& SC_Query_Ex::getSingletonInstance();
179
180        // DB
181        $objQuery->delete('mtb_zip');
182
183        // UTF-8 変換済みの郵便番号 CSV
184        unlink(ZIP_CSV_UTF8_REALFILE);
185    }
186
187    /**
188     * パラメータ情報の初期化
189     *
190     * @return void
191     */
192    function lfInitParam($tpl_mode, &$objFormParam) {
193        if ($tpl_mode == 'manual') {
194            $objFormParam->addParam("開始行", 'startRowNum', INT_LEN, 'n', array("EXIST_CHECK", "MAX_LENGTH_CHECK", "NUM_CHECK"));
195        }
196    }
197
198    /**
199     * DB登録
200     *
201     * @return void
202     */
203    function insertMtbZip($start = 1) {
204        $objQuery =& SC_Query_Ex::getSingletonInstance();
205
206        $img_path = USER_URL . USER_PACKAGE_DIR . "admin/img/basis/"; // 画像パスは admin 固定
207
208        ?>
209        <html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja">
210        <head>
211            <meta http-equiv="Content-Type" content="text/html; charset=<?php echo CHAR_CODE ?>" />
212        </head>
213        <body>
214        <p>DB 登録進捗状況</p>
215        <div style="background-color: #494E5F;">
216        <?php
217        // 一部のIEは256バイト以上受け取ってから表示を開始する。
218        SC_Utils_Ex::sfFlush(true);
219
220        echo '<img src="' . $img_path . 'zip_install_progress.gif"><br />';
221        echo '<img src="' . $img_path . 'space_w.gif">';
222        SC_Utils_Ex::sfFlush();
223
224        // 画像を一個表示する件数を求める。
225        $line_all = $this->countZipCsv();
226        $disp_line = intval($line_all / IMAGE_MAX);
227
228        /** 現在行(CSV形式。空行は除く。) */
229        $cntCurrentLine = 0;
230        /** 挿入した行数 */
231        $cntInsert = 0;
232        $img_cnt = 0;
233        $safe_mode = (boolean)ini_get('safe_mode');
234        $max_execution_time
235            = is_numeric(ini_get('max_execution_time'))
236            ? intval(ini_get('max_execution_time'))
237            : intval(get_cfg_var('max_execution_time'))
238        ;
239
240        $fp = $this->openZipCsv();
241        while (!feof($fp)) {
242            $arrCSV = fgetcsv($fp, ZIP_CSV_LINE_MAX);
243            if (empty($arrCSV)) continue;
244            $cntCurrentLine++;
245            if ($cntCurrentLine >= $start) {
246                $sqlval = array();
247                // $sqlval['code'] = $arrCSV[0];
248                // $sqlval['old_zipcode'] = $arrCSV[1];
249                $sqlval['zipcode'] = $arrCSV[2];
250                // $sqlval['state_kana'] = $arrCSV[3];
251                // $sqlval['city_kana'] = $arrCSV[4];
252                // $sqlval['town_kana'] = $arrCSV[5];
253                $sqlval['state'] = $arrCSV[6];
254                $sqlval['city'] = $arrCSV[7];
255                $sqlval['town'] = $arrCSV[8];
256                // $sqlval['flg1'] = $arrCSV[9];
257                // $sqlval['flg2'] = $arrCSV[10];
258                // $sqlval['flg3'] = $arrCSV[11];
259                // $sqlval['flg4'] = $arrCSV[12];
260                // $sqlval['flg5'] = $arrCSV[13];
261                // $sqlval['flg6'] = $arrCSV[14];
262                $objQuery->insert("mtb_zip", $sqlval);
263                $cntInsert++;
264            }
265
266            // $disp_line件ごとに進捗表示する
267            if($cntCurrentLine % $disp_line == 0 && $img_cnt < IMAGE_MAX) {
268                echo '<img src="' . $img_path . 'graph_1_w.gif">';
269                SC_Utils_Ex::sfFlush();
270                $img_cnt++;
271            }
272            // 暴走スレッドが残留する確率を軽減したタイムアウト防止のロジック
273            // TODO 動作が安定していれば、SC_Utils 辺りに移動したい。
274            if (!$safe_mode) {
275                // タイムアウトをリセット
276                set_time_limit($max_execution_time);
277            }
278        }
279        fclose($fp);
280
281        echo '<img src="' . $img_path . 'space_w.gif">';
282        echo '</div>' . "\n";
283
284        ?>
285        <script type="text/javascript" language="javascript">
286            <!--
287                // 完了画面
288                function complete() {
289                    document.open("text/html","replace");
290                    document.clear();
291                    document.write("<p>完了しました。<br />");
292                    document.write("<?php echo $cntInsert ?> 件を追加しました。</p>");
293                    document.write("<p><a href='?' target='_top'>戻る</a></p>");
294                    document.close();
295                }
296                // コンテンツを削除するため、タイムアウトで呼び出し。
297                setTimeout("complete()", 0);
298            // -->
299        </script>
300        </body>
301        </html>
302        <?php
303    }
304
305    function openZipCsv() {
306        $this->convertZipCsv();
307        $fp = fopen(ZIP_CSV_UTF8_REALFILE, 'r');
308        if (!$fp) {
309            SC_Utils_Ex::sfDispException(ZIP_CSV_UTF8_REALFILE . ' の読み込みに失敗しました。');
310        }
311        return $fp;
312    }
313
314    function convertZipCsv() {
315        if (file_exists(ZIP_CSV_UTF8_REALFILE)) return;
316
317        $fpr = fopen(ZIP_CSV_REALFILE, 'r');
318        if (!$fpr) {
319            SC_Utils_Ex::sfDispException(ZIP_CSV_REALFILE . ' の読み込みに失敗しました。');
320        }
321
322        $fpw = fopen(ZIP_CSV_UTF8_REALFILE, 'w');
323        if (!$fpw) {
324            SC_Utils_Ex::sfDispException(ZIP_CSV_UTF8_REALFILE . ' を開けません。');
325        }
326
327        while (!feof($fpr)) {
328            fwrite($fpw, mb_convert_encoding(fgets($fpr, ZIP_CSV_LINE_MAX), CHAR_CODE, 'sjis-win'));
329        }
330
331        fclose($fpw);
332        fclose($fpr);
333    }
334
335    function countMtbZip() {
336        $objQuery =& SC_Query_Ex::getSingletonInstance();
337        return $objQuery->count('mtb_zip');
338    }
339
340    function countZipCsv() {
341        $line = 0;
342        $fp = $this->openZipCsv();
343
344        // CSVの行数を数える
345        while (!feof($fp)) {
346            /*
347            // 正確にカウントする
348            $tmp = fgetcsv($fp, ZIP_CSV_LINE_MAX);
349            */
350            // 推測でカウントする
351            $tmp = fgets($fp, ZIP_CSV_LINE_MAX);
352            if (empty($tmp)) continue;
353            $line++;
354        }
355        fclose($fp);
356
357        return $line;
358    }
359
360    /**
361     * 日本郵便から郵便番号 CSV の ZIP アーカイブファイルを取得
362     *
363     * @return void
364     */
365    function lfDownloadZipFileFromJp() {
366        $res = copy($this->zip_download_url, $this->zip_csv_temp_realfile);
367        if (!$res) {
368            SC_Utils_Ex::sfDispException($this->zip_download_url . ' の取得または ' . $this->zip_csv_temp_realfile . ' への書き込みに失敗しました。');
369        }
370    }
371
372    /**
373     * ZIP アーカイブファイルを展開して、郵便番号 CSV を上書き
374     *
375     * @return void
376     */
377    function lfExtractZipFile() {
378        if (!function_exists('zip_open')) {
379            SC_Utils_Ex::sfDispException('PHP 拡張モジュール「zip」を有効にしてください。');
380        }
381
382        $zip = zip_open($this->zip_csv_temp_realfile);
383        if (!is_resource($zip)) {
384            SC_Utils_Ex::sfDispException($this->zip_csv_temp_realfile . ' をオープンできません。');
385        }
386
387        do {
388            $entry = zip_read($zip);
389        } while ($entry && zip_entry_name($entry) != 'KEN_ALL.CSV');
390
391        if (!$entry) {
392            SC_Utils_Ex::sfDispException($this->zip_csv_temp_realfile . ' に対象ファイルが見つかりません。');
393        }
394
395        // 展開時の破損を考慮し、別名で一旦展開する。
396        $tmp_csv_realfile = ZIP_CSV_REALFILE . '.tmp';
397
398        $res = zip_entry_open($zip, $entry, 'rb');
399        if (!$res) {
400            SC_Utils_Ex::sfDispException($this->zip_csv_temp_realfile . ' の展開に失敗しました。');
401        }
402
403        $fp = fopen($tmp_csv_realfile, 'w');
404        if (!$fp) {
405            SC_Utils_Ex::sfDispException($tmp_csv_realfile . ' を開けません。');
406        }
407
408        $res = fwrite($fp, zip_entry_read($entry, zip_entry_filesize($entry)));
409        if ($res === FALSE) {
410            SC_Utils_Ex::sfDispException($tmp_csv_realfile . ' の書き込みに失敗しました。');
411        }
412
413        fclose($fp);
414        zip_close($zip);
415
416        // CSV 削除
417        $res = unlink(ZIP_CSV_REALFILE);
418        if (!$res) {
419            SC_Utils_Ex::sfDispException(ZIP_CSV_REALFILE . ' を削除できません。');
420        }
421
422        // CSV ファイル名変更
423        $res = rename($tmp_csv_realfile, ZIP_CSV_REALFILE);
424        if (!$res) {
425            SC_Utils_Ex::sfDispException('ファイル名を変更できません。: ' . $tmp_csv_realfile . ' -> ' . ZIP_CSV_REALFILE);
426        }
427    }
428
429    /**
430     * CSV の更新日時を取得
431     *
432     * @return string CSV の更新日時 (整形済みテキスト)
433     */
434    function lfGetCsvDatetime() {
435        return date('Y/m/d H:i:s', filemtime(ZIP_CSV_REALFILE));
436    }
437}
438?>
Note: See TracBrowser for help on using the repository browser.