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

Revision 20960, 14.5 KB checked in by Seasoft, 13 years ago (diff)

#144 (郵便番号DB のアップデート)

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