source: branches/version-2_13_0/data/class/pages/admin/basis/LC_Page_Admin_Basis_ZipInstall.php @ 23143

Revision 23143, 13.7 KB checked in by m_uehara, 7 years ago (diff)

#2348 r23140 をマージ

  • 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-2013 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
24require_once CLASS_EX_REALDIR . 'page_extends/admin/LC_Page_Admin_Ex.php';
25
26/** CSV ファイルの最大行数 */
27define('ZIP_CSV_LINE_MAX', 8192);
28
29/** 画像の表示数量 */
30define('IMAGE_MAX', 680);
31
32/** 郵便番号CSV ファイルのパス */
33define('ZIP_CSV_REALFILE', DATA_REALDIR . 'downloads/KEN_ALL.CSV');
34
35/** UTF-8 変換済みの郵便番号CSV ファイルのパス */
36define('ZIP_CSV_UTF8_REALFILE', DATA_REALDIR . 'downloads/KEN_ALL_utf-8.CSV');
37
38/**
39 * 郵便番号DB登録 のページクラス.
40 *
41 * @package Page
42 * @author LOCKON CO.,LTD.
43 * @version $Id:LC_Page_Admin_Basis_ZipInstall.php 16741 2007-11-08 00:43:24Z adachi $
44 */
45class LC_Page_Admin_Basis_ZipInstall extends LC_Page_Admin_Ex
46{
47    /** CSVの行数 */
48    public $tpl_line = 0;
49    public $tpl_mode;
50    public $exec;
51    public $tpl_count_mtb_zip;
52
53    /** CSV の更新日時 */
54    public $tpl_csv_datetime;
55
56    /** 日本郵便から取得した ZIP アーカイブファイルの保管パス */
57    public $zip_csv_temp_realfile;
58
59    /**
60     * Page を初期化する.
61     *
62     * @return void
63     */
64    public function init()
65    {
66        parent::init();
67        $this->tpl_mainpage = 'basis/zip_install.tpl';
68        $this->tpl_subno = 'zip_install';
69        $this->tpl_maintitle = '基本情報管理';
70        $this->tpl_subtitle = '郵便番号DB登録';
71        $this->tpl_mainno = 'basis';
72
73        $this->tpl_mode = $this->getMode();
74        $this->exec = (boolean) $_GET['exec'];
75        $this->zip_csv_temp_realfile = DATA_REALDIR . 'downloads/tmp/ken_all.zip';
76    }
77
78    /**
79     * Page のプロセス.
80     *
81     * @return void
82     */
83    public function process()
84    {
85        $this->action();
86        $this->sendResponse();
87    }
88
89    /**
90     * Page のアクション.
91     *
92     * @return void
93     */
94    public function action()
95    {
96        // パラメーター管理クラス
97        $objFormParam = new SC_FormParam_Ex();
98        // パラメーター情報の初期化
99        $this->lfInitParam($this->tpl_mode, $objFormParam);
100        $objFormParam->setParam($_GET);
101        $this->arrErr = $objFormParam->checkError();
102        $this->arrForm = $objFormParam->getHashArray();
103        $this->tpl_zip_download_url_empty = !defined('ZIP_DOWNLOAD_URL') || strlen(ZIP_DOWNLOAD_URL) === 0 || ZIP_DOWNLOAD_URL === false;
104        $this->tpl_zip_function_not_exists = !function_exists('zip_open');
105        $this->tpl_skip_update_csv = $this->tpl_zip_download_url_empty || $this->tpl_zip_function_not_exists;
106
107        if ($this->exec) {
108            if (!empty($this->arrErr)) {
109                trigger_error('', E_USER_ERROR);
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            SC_Response_Ex::actionExit();
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            // 自動登録時の郵便番号CSV更新
143            // XXX iframe内にエラー表示しない様、ここでlfDownloadZipFileFromJp()を呼ぶ。
144            case 'auto';
145                if (!$this->tpl_skip_update_csv) {
146                    $this->lfDownloadZipFileFromJp();
147                    $this->lfExtractZipFile();
148                }
149                break;
150        }
151
152        $this->tpl_line = $this->countZipCsv();
153        $this->tpl_count_mtb_zip = $this->countMtbZip();
154        $this->tpl_csv_datetime = $this->lfGetCsvDatetime();
155        // XXX PHP4 を切捨てたら、ダウンロードの必要性チェックなども行いたい
156        // $arrHeader = get_headers(ZIP_DOWNLOAD_URL, 1);
157    }
158
159    public function lfAutoCommitZip()
160    {
161        $objQuery =& SC_Query_Ex::getSingletonInstance();
162
163        // DB更新
164        $objQuery->begin();
165        $this->lfDeleteZip();
166        $this->insertMtbZip();
167        $objQuery->commit();
168    }
169
170    /**
171     * テーブルデータと UTF-8 変換済みの郵便番号 CSV を削除
172     *
173     * @return void
174     */
175    public function lfDeleteZip()
176    {
177        $objQuery =& SC_Query_Ex::getSingletonInstance();
178
179        // DB
180        $objQuery->delete('mtb_zip');
181
182        // UTF-8 変換済みの郵便番号 CSV
183        unlink(ZIP_CSV_UTF8_REALFILE);
184    }
185
186    /**
187     * パラメーター情報の初期化
188     *
189     * @return void
190     */
191    public function lfInitParam($tpl_mode, &$objFormParam)
192    {
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    public function insertMtbZip($start = 1)
204    {
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
235        $fp = $this->openZipCsv();
236        while (!feof($fp)) {
237            $arrCSV = fgetcsv($fp, ZIP_CSV_LINE_MAX);
238            if (empty($arrCSV)) continue;
239            $cntCurrentLine++;
240            if ($cntCurrentLine >= $start) {
241                $sqlval = array();
242                $sqlval['zip_id'] = $cntCurrentLine;
243                $sqlval['zipcode'] = $arrCSV[2];
244                $sqlval['state'] = $arrCSV[6];
245                $sqlval['city'] = $arrCSV[7];
246                $sqlval['town'] = $arrCSV[8];
247                $objQuery->insert('mtb_zip', $sqlval);
248                $cntInsert++;
249            }
250
251            // $disp_line件ごとに進捗表示する
252            if ($cntCurrentLine % $disp_line == 0 && $img_cnt < IMAGE_MAX) {
253                echo '<img src="' . $img_path . 'graph_1_w.gif">';
254                SC_Utils_Ex::sfFlush();
255                $img_cnt++;
256            }
257            SC_Utils_Ex::extendTimeOut();
258        }
259        fclose($fp);
260
261        echo '<img src="' . $img_path . 'space_w.gif">';
262
263        ?>
264        </div>
265        <script type='text/javascript' language='javascript'>
266            <!--
267                // 完了画面
268                function complete()
269                {
270                    document.open('text/html','replace');
271                    document.clear();
272                    document.write('<p>完了しました。<br />');
273                    document.write("<?php echo $cntInsert ?> 件を追加しました。</p>");
274                    document.write("<p><a href='?' target='_top'>戻る</a></p>");
275                    document.close();
276                }
277                // コンテンツを削除するため、タイムアウトで呼び出し。
278                setTimeout('complete()', 0);
279            // -->
280        </script>
281        </body>
282        </html>
283        <?php
284    }
285
286    public function openZipCsv()
287    {
288        $this->convertZipCsv();
289        $fp = fopen(ZIP_CSV_UTF8_REALFILE, 'r');
290        if (!$fp) {
291            trigger_error(ZIP_CSV_UTF8_REALFILE . ' の読み込みに失敗しました。', E_USER_ERROR);
292        }
293
294        return $fp;
295    }
296
297    public function convertZipCsv()
298    {
299        if (file_exists(ZIP_CSV_UTF8_REALFILE)) return;
300
301        $fpr = fopen(ZIP_CSV_REALFILE, 'r');
302        if (!$fpr) {
303            trigger_error(ZIP_CSV_REALFILE . ' の読み込みに失敗しました。', E_USER_ERROR);
304        }
305
306        $fpw = fopen(ZIP_CSV_UTF8_REALFILE, 'w');
307        if (!$fpw) {
308            trigger_error(ZIP_CSV_UTF8_REALFILE . ' を開けません。', E_USER_ERROR);
309        }
310
311        while (!feof($fpr)) {
312            fwrite($fpw, mb_convert_encoding(fgets($fpr, ZIP_CSV_LINE_MAX), CHAR_CODE, 'sjis-win'));
313        }
314
315        fclose($fpw);
316        fclose($fpr);
317    }
318
319    public function countMtbZip()
320    {
321        $objQuery =& SC_Query_Ex::getSingletonInstance();
322
323        return $objQuery->count('mtb_zip');
324    }
325
326    public function countZipCsv()
327    {
328        $line = 0;
329        $fp = $this->openZipCsv();
330
331        // CSVの行数を数える
332        while (!feof($fp)) {
333            /*
334            // 正確にカウントする
335            $tmp = fgetcsv($fp, ZIP_CSV_LINE_MAX);
336            */
337            // 推測でカウントする
338            $tmp = fgets($fp, ZIP_CSV_LINE_MAX);
339            if (empty($tmp)) continue;
340            $line++;
341        }
342        fclose($fp);
343
344        return $line;
345    }
346
347    /**
348     * 日本郵便から郵便番号 CSV の ZIP アーカイブファイルを取得
349     *
350     * @return void
351     */
352    public function lfDownloadZipFileFromJp()
353    {
354        // Proxy経由を可能とする。
355        // TODO Proxyの設定は「data/module/HTTP/Request.php」内の「function HTTP_Request」へ記述する。いずれは、外部設定としたい。
356        $req = new HTTP_Request();
357
358        $req->setURL(ZIP_DOWNLOAD_URL);
359
360        // 郵便番号CSVをdownloadする。
361        $res = $req->sendRequest();
362        if (!$res || strlen($res) > 1) {
363            trigger_error(ZIP_DOWNLOAD_URL . ' の取得に失敗しました。', E_USER_ERROR);
364        }
365
366        // 郵便番号CSV(zip file)を保存する。
367        $fp = fopen($this->zip_csv_temp_realfile, 'w');
368        if (!$fp) {
369            trigger_error($this->zip_csv_temp_realfile . ' を開けません。', E_USER_ERROR);
370        }
371        $res = fwrite($fp, $req->getResponseBody());
372        if (!$res) {
373            trigger_error($this->zip_csv_temp_realfile . ' への書き込みに失敗しました。', E_USER_ERROR);
374        }
375    }
376
377    /**
378     * ZIP アーカイブファイルを展開して、郵便番号 CSV を上書き
379     *
380     * @return void
381     */
382    public function lfExtractZipFile()
383    {
384        $zip = zip_open($this->zip_csv_temp_realfile);
385        if (!is_resource($zip)) {
386            trigger_error($this->zip_csv_temp_realfile . ' をオープンできません。', E_USER_ERROR);
387        }
388
389        do {
390            $entry = zip_read($zip);
391        } while ($entry && zip_entry_name($entry) != 'KEN_ALL.CSV');
392
393        if (!$entry) {
394            trigger_error($this->zip_csv_temp_realfile . ' に対象ファイルが見つかりません。', E_USER_ERROR);
395        }
396
397        // 展開時の破損を考慮し、別名で一旦展開する。
398        $tmp_csv_realfile = ZIP_CSV_REALFILE . '.tmp';
399
400        $res = zip_entry_open($zip, $entry, 'rb');
401        if (!$res) {
402            trigger_error($this->zip_csv_temp_realfile . ' の展開に失敗しました。', E_USER_ERROR);
403        }
404
405        $fp = fopen($tmp_csv_realfile, 'w');
406        if (!$fp) {
407            trigger_error($tmp_csv_realfile . ' を開けません。', E_USER_ERROR);
408        }
409
410        $res = fwrite($fp, zip_entry_read($entry, zip_entry_filesize($entry)));
411        if ($res === FALSE) {
412            trigger_error($tmp_csv_realfile . ' の書き込みに失敗しました。', E_USER_ERROR);
413        }
414
415        fclose($fp);
416        zip_close($zip);
417
418        // CSV 削除
419        $res = unlink(ZIP_CSV_REALFILE);
420        if (!$res) {
421            trigger_error(ZIP_CSV_REALFILE . ' を削除できません。', E_USER_ERROR);
422        }
423
424        // CSV ファイル名変更
425        $res = rename($tmp_csv_realfile, ZIP_CSV_REALFILE);
426        if (!$res) {
427            trigger_error('ファイル名を変更できません。: ' . $tmp_csv_realfile . ' -> ' . ZIP_CSV_REALFILE, E_USER_ERROR);
428        }
429    }
430
431    /**
432     * CSV の更新日時を取得
433     *
434     * @return string CSV の更新日時 (整形済みテキスト)
435     */
436    public function lfGetCsvDatetime()
437    {
438        return date('Y/m/d H:i:s', filemtime(ZIP_CSV_REALFILE));
439    }
440}
Note: See TracBrowser for help on using the repository browser.