source: branches/comu-ver2/data/class/helper/SC_Helper_Mobile.php @ 17605

Revision 17605, 16.4 KB checked in by Seasoft, 16 years ago (diff)

/index.php にリンクやリダイレクトしている箇所の「index.php」を定数化。

  • 定数「DIR_INDEX_FILE」… DirectoryIndex? の実ファイル名。現状の EC-CUBE は、「index.php」。/html/define.php で定義するが、定義が無い場合 SC_Initial::defineDirectoryIndex() で「index.php」と定義。本来は、プログラム中で実ファイルとしての index.php を指すときとは、この定数を使うのが良い気がするが、今回はそこまでは書き換えていない。
  • 定数「USE_FILENAME_DIR_INDEX」… DIR_INDEX_FILE にアクセスするときにファイル名を使用するか。/html/define.php で定義。
  • 定数「DIR_INDEX_URL」… /index.php にリンクやリダイレクトしている箇所の「index.php」部分を示す。この定数は SC_Initial::defineDirectoryIndex() で自動生成する。

・$_SERVERPHP_SELF? や自身をあらわすファイル名を利用している箇所を文字列「?」に書き換え。これにより、/ が自己URLにリンクするときに /index.php となることを防ぐ。RFC3986 を参考にする。モバイル端末がこのRFCに準拠しているのか確信が無いので、モバイルではこの変更は見送った。
・従来 / にリンクしていた箇所に、定数「DIR_INDEX_URL」を付加。漏れがあると予測される。

  • Property svn:keywords set to Id Revision Date
  • 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-2007 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_PATH . '../module/Net/URL.php');
26require_once(CLASS_PATH . "SC_DbConn.php");
27require_once(CLASS_PATH . 'SC_Query.php');
28
29/**
30 * モバイルのヘルパークラス.
31 *
32 * @package Helper
33 * @author LOCKON CO.,LTD.
34 * @version $Id$
35 */
36class SC_Helper_Mobile {
37
38    /**
39     * EC-CUBE がサポートする携帯端末かどうかをチェックする。
40     * 非対応端末の場合は /mobile/unsupported/ へリダイレクトする。
41     *
42     * @return void
43     */
44    function lfMobileCheckCompatibility() {
45        if (!SC_MobileUserAgent::isSupported()) {
46            header('Location: ' . URL_DIR . 'mobile/unsupported/' . DIR_INDEX_URL);
47            exit;
48        }
49    }
50
51    /**
52     * 入力データを内部エンコーディングに変換し、絵文字を除去する。
53     *
54     * @param string &$value 入力データへの参照
55     * @return void
56     */
57    function lfMobileConvertInputValue(&$value) {
58        // Shift JIS から内部エンコーディングに変換する。
59        // SoftBank 以外の絵文字は外字領域に含まれるため、この段階で除去される。
60        $value = mb_convert_encoding($value, CHAR_CODE, 'SJIS');
61
62        // SoftBank の絵文字を除去する。
63        $value = preg_replace('/\\x1b\\$[^\\x0f]*\\x0f/', '', $value);
64    }
65
66    /**
67     * モバイルサイト用の入力の初期処理を行う。
68     *
69     * @return void
70     */
71    function lfMobileInitInput() {
72        array_walk($_GET, array($this, 'lfMobileConvertInputValue'));
73        array_walk($_POST, array($this, 'lfMobileConvertInputValue'));
74        array_walk($_REQUEST, array($this, 'lfMobileConvertInputValue'));
75    }
76
77    /**
78     * dtb_mobile_ext_session_id テーブルを検索してセッションIDを取得する。
79     *
80     * @return string|null 取得したセッションIDを返す。
81     *                     取得できなかった場合は null を返す。
82     */
83    function lfMobileGetExtSessionId() {
84        if (!preg_match('|^' . URL_DIR . '(.*)$|', $_SERVER['SCRIPT_NAME'], $matches)) {
85            return null;
86        }
87
88        $url = $matches[1];
89        $time = date('Y-m-d H:i:s', time() - MOBILE_SESSION_LIFETIME);
90        $objQuery = new SC_Query;
91
92        foreach ($_REQUEST as $key => $value) {
93            $session_id = $objQuery->get('dtb_mobile_ext_session_id', 'session_id',
94                                         'param_key = ? AND param_value = ? AND url = ? AND create_date >= ?',
95                                         array($key, $value, $url, $time));
96            if (isset($session_id)) {
97                return $session_id;
98            }
99        }
100
101        return null;
102    }
103
104    /**
105     * パラメーターから有効なセッションIDを取得する。
106     *
107     * @return string|false 取得した有効なセッションIDを返す。
108     *                      取得できなかった場合は false を返す。
109     */
110    function lfMobileGetSessionId() {
111        // パラメーターからセッションIDを取得する。
112        $sessionId = @$_POST[session_name()];
113        if (!isset($sessionId)) {
114            $sessionId = @$_GET[session_name()];
115        }
116        if (!isset($sessionId)) {
117            $sessionId = $this->lfMobileGetExtSessionId();
118        }
119        if (!isset($sessionId)) {
120            return false;
121        }
122
123        // セッションIDの存在をチェックする。
124        $objSession = new SC_Helper_Session_Ex();
125        if ($objSession->sfSessRead($sessionId) === null) {
126            GC_Utils_Ex::gfPrintLog("Non-existent session id : sid=$sessionId");
127            return false;
128        }
129        return session_id($sessionId);
130    }
131
132    /**
133     * セッションデータが有効かどうかをチェックする。
134     *
135     * FIXME "@" でエラーを抑制するのは良くない
136     *
137     * @return boolean セッションデータが有効な場合は true、無効な場合は false を返す。
138     */
139    function lfMobileValidateSession() {
140        // 配列 mobile が登録されているかどうかをチェックする。
141        if (!is_array(@$_SESSION['mobile'])) {
142            return false;
143        }
144
145        // 有効期限を過ぎていないかどうかをチェックする。
146        if (intval(@$_SESSION['mobile']['expires']) < time()) {
147            GC_Utils_Ex::gfPrintLog("Session expired at " .
148                       date('Y/m/d H:i:s', @$_SESSION['mobile']['expires']) .
149                       ' : sid=' . session_id());
150
151            return false;
152        }
153
154        // 携帯端末の機種が一致するかどうかをチェックする。
155        $model = SC_MobileUserAgent::getModel();
156        if (@$_SESSION['mobile']['model'] != $model) {
157            GC_Utils_Ex::gfPrintLog("User agent model mismatch : " .
158                       "\"$model\" != \"" . @$_SESSION['mobile']['model'] .
159                       '" (expected), sid=' . session_id());
160            return false;
161        }
162
163        return true;
164    }
165
166    /**
167     * モバイルサイト用のセッション関連の初期処理を行う。
168     *
169     * @return void
170     */
171    function lfMobileInitSession() {
172        // セッションIDの受け渡しにクッキーを使用しない。
173        ini_set('session.use_cookies', '0');
174
175        // パラメーターから有効なセッションIDを取得する。
176        $sessionId = $this->lfMobileGetSessionId();
177
178        session_start();
179
180        // セッションIDまたはセッションデータが無効な場合は、セッションIDを再生成
181        // し、セッションデータを初期化する。
182        if ($sessionId === false || !$this->lfMobileValidateSession()) {
183            session_regenerate_id();
184            $_SESSION = array('mobile' => array('model'    => SC_MobileUserAgent::getModel(),
185                                                'phone_id' => SC_MobileUserAgent::getId(),
186                                                'expires'  => time() + MOBILE_SESSION_LIFETIME));
187
188            // 新しいセッションIDを付加してリダイレクトする。
189            if ($_SERVER['REQUEST_METHOD'] == 'GET') {
190                // GET の場合は同じページにリダイレクトする。
191                header('Location: ' . $this->gfAddSessionId());
192            } else {
193                // GET 以外の場合はトップページへリダイレクトする。
194                header('Location: ' . URL_SITE_TOP . '?' . SID);
195            }
196            exit;
197        }
198
199        // 携帯端末IDを取得できた場合はセッションデータに保存する。
200        $phoneId = SC_MobileUserAgent::getId();
201        if ($phoneId !== false) {
202            $_SESSION['mobile']['phone_id'] = $phoneId;
203        }
204
205        // セッションの有効期限を更新する。
206        $_SESSION['mobile']['expires'] = time() + MOBILE_SESSION_LIFETIME;
207    }
208
209    /**
210     * モバイルサイト用の出力の初期処理を行う。
211     *
212     * 出力の流れ
213     * 1. Smarty
214     * 2. 内部エンコーディングから Shift JIS に変換する。
215     * 3. 全角カタカナを半角カタカナに変換する。
216     * 4. 画像用のタグを調整する。
217     * 5. 絵文字タグを絵文字コードに変換する。
218     * 6. 出力
219     *
220     * @return void
221     */
222    function lfMobileInitOutput() {
223        // Smarty 用のディレクトリーを作成する。
224        @mkdir(COMPILE_DIR);
225
226        // 出力用のエンコーディングを Shift JIS に固定する。
227        mb_http_output('SJIS-win');
228
229        // 絵文字タグを絵文字コードに変換する。
230        ob_start(array('SC_MobileEmoji', 'handler'));
231
232        // 端末に合わせて画像サイズを変換する。
233        ob_start(array('SC_MobileImage', 'handler'));
234
235        // 全角カタカナを半角カタカナに変換する。
236        ob_start(create_function('$buffer', 'return mb_convert_kana($buffer, "k", "SJIS-win");'));
237
238        // 内部エンコーディングから Shift JIS に変換する。
239        ob_start('mb_output_handler');
240    }
241
242    /**
243     * モバイルサイト用の初期処理を行う。
244     *
245     * @return void
246     */
247    function sfMobileInit() {
248        $this->lfMobileInitInput();
249
250        if (basename(dirname($_SERVER['SCRIPT_NAME'])) != 'unsupported') {
251            $this->lfMobileCheckCompatibility();
252            /**
253             * 共有SSL対応のため、SC_SessionFactory_UseRequest::initSession()へ移行
254             * また、他のセッション関連メソッドもSC_SessionFactory_UseRequestのインスタンスから呼び出すこと
255             *
256             * @see data/class/session/sessionfactory/SC_SessionFactory_UseRequest.php
257             */
258            // $this->lfMobileInitSession();
259        }
260
261        $this->lfMobileInitOutput();
262    }
263
264    /**
265     * Location等でセッションIDを付加する必要があるURLにセッションIDを付加する。
266     *
267     * @return String
268     */
269    function gfAddSessionId($url = null) {
270        $objURL = new Net_URL($url);
271        $objURL->addQueryString(session_name(), session_id());
272        return $objURL->getURL();
273    }
274
275    /**
276     * セッション ID を付加した配列を返す.
277     *
278     * @param array $array 元となる配列
279     * @param array セッション ID を追加した配列
280     */
281    function sessionIdArray($array = array()) {
282        return array_merge($array, array(session_name() => session_id()));
283    }
284
285    /**
286     * 空メール用のトークンを生成する。
287     *
288     * @return string 生成したトークンを返す。
289     */
290    function lfGenerateKaraMailToken() {
291        $token_chars = '0123456789abcdefghijklmnopqrstuvwxyz';
292        $token_chars_length = strlen($token_chars);
293        $token_length = 10;
294        $token = '';
295
296        while ($token_length > 0) {
297            $token .= $token_chars{mt_rand(0, $token_chars_length - 1)};
298            --$token_length;
299        }
300
301        return $token;
302    }
303
304    /**
305     * 空メール管理テーブルに新規エントリーを登録し、トークンを返す。
306     *
307     * @param string $next_url 空メール受け付け後に遷移させるページ (モバイルサイトトップからの相対URL)
308     * @param string $session_id セッションID (省略した場合は現在のセッションID)
309     * @return string|false トークンを返す。エラーが発生した場合はfalseを返す。
310     */
311    function gfPrepareKaraMail($next_url, $session_id = null) {
312        if (!isset($session_id)) {
313            $session_id = session_id();
314        }
315
316        $objQuery = new SC_Query;
317
318        // GC
319        $time = date('Y-m-d H:i:s', time() - MOBILE_SESSION_LIFETIME);
320        $objQuery->delete('dtb_mobile_kara_mail', 'email IS NULL AND create_date < ?', array($time));
321
322        $objQuery->delete('dtb_mobile_kara_mail', 'session_id = ?', array($session_id));
323
324        $arrValues = array('session_id' => $session_id,
325                           'next_url'   => $next_url);
326
327        $try = 10;
328
329        while ($try > 0) {
330            $arrValues['token'] = $token = $this->lfGenerateKaraMailToken();
331
332            $objQuery->insert('dtb_mobile_kara_mail', $arrValues);
333            $count = $objQuery->count('dtb_mobile_kara_mail', 'token = ?', array($token));
334
335            if ($count == 1) {
336                break;
337            }
338
339            $objQuery->delete('dtb_mobile_kara_mail', 'session_id = ?', array($session_id));
340            $token = false;
341            --$try;
342        }
343
344        return $token;
345    }
346
347    /**
348     * 空メールから取得したメールアドレスを空メール管理テーブルに登録する。
349     *
350     * @param string $token トークン
351     * @param string $email メールアドレス
352     * @return boolean 成功した場合はtrue、失敗した場合はfalseを返す。
353     */
354    function gfRegisterKaraMail($token, $email) {
355        $objQuery = new SC_Query;
356
357        // GC
358        $time = date('Y-m-d H:i:s', time() - MOBILE_SESSION_LIFETIME);
359        $objQuery->delete('dtb_mobile_kara_mail',
360                          '(email IS NULL AND create_date < ?) OR (email IS NOT NULL AND receive_date < ?)',
361                          array($time, $time));
362
363        $kara_mail_id = $objQuery->get('dtb_mobile_kara_mail', 'kara_mail_id', 'token = ?', array($token));
364        if (!isset($kara_mail_id)) {
365            return false;
366        }
367
368        $arrValues = array('email' => $email);
369        $arrRawValues = array('receive_date' => 'now()');
370        $objQuery->update('dtb_mobile_kara_mail', $arrValues, 'kara_mail_id = ?', array($kara_mail_id), $arrRawValues);
371
372        return true;
373    }
374
375    /**
376     * 空メール管理テーブルからトークンが一致する行を削除し、
377     * 次に遷移させるページのURLを返す。 
378     *
379     * メールアドレスは $_SESSION['mobile']['kara_mail_from'] に登録される。
380     *
381     * @param string $token トークン
382     * @return string|false URLを返す。エラーが発生した場合はfalseを返す。
383     */
384    function gfFinishKaraMail($token) {
385        $objQuery = new SC_Query;
386
387        $arrRow = $objQuery->getrow('dtb_mobile_kara_mail', 'session_id, next_url, email',
388                                    'token = ? AND email IS NOT NULL AND receive_date >= ?',
389                                    array($token, date('Y-m-d H:i:s', time() - MOBILE_SESSION_LIFETIME)));
390        if (!isset($arrRow)) {
391            return false;
392        }
393
394        $objQuery->delete('dtb_mobile_kara_mail', 'token = ?', array($token));
395
396        list($session_id, $next_url, $email) = $arrRow;
397        $objURL = new Net_URL(MOBILE_SITE_URL . $next_url);
398        $objURL->addQueryString(session_name(), $session_id);
399        $url = $objURL->getURL();
400
401        session_id($session_id);
402        session_start();
403        $_SESSION['mobile']['kara_mail_from'] = $email;
404        session_write_close();
405
406        return $url;
407    }
408
409    /**
410     * 外部サイト連携用にセッションIDとパラメーターの組み合わせを保存する。
411     *
412     * @param string $param_key パラメーター名
413     * @param string $param_value パラメーター値
414     * @param string $url URL
415     * @return void
416     */
417    function sfMobileSetExtSessionId($param_key, $param_value, $url) {
418        $objQuery = new SC_Query;
419
420        // GC
421        $time = date('Y-m-d H:i:s', time() - MOBILE_SESSION_LIFETIME);
422        $objQuery->delete('dtb_mobile_ext_session_id', 'create_date < ?', array($time));
423
424        $arrValues = array('session_id'  => session_id(),
425                           'param_key'   => $param_key,
426                           'param_value' => $param_value,
427                           'url'         => $url);
428
429        $objQuery->insert('dtb_mobile_ext_session_id', $arrValues);
430    }
431
432    /**
433     * メールアドレスが携帯のものかどうかを判別する。
434     *
435     * @param string $address メールアドレス
436     * @return boolean 携帯のメールアドレスの場合はtrue、それ以外の場合はfalseを返す。
437     */
438    function gfIsMobileMailAddress($address) {
439        $masterData = new SC_DB_MasterData_Ex();
440        $arrMobileMailDomains = $masterData->getMasterData("mtb_mobile_domain");
441
442        if (defined('MOBILE_ADDITIONAL_MAIL_DOMAINS')) {
443            $arrMobileMailDomains = array_merge($arrMobileMailDomains, split('[ ,]+', MOBILE_ADDITIONAL_MAIL_DOMAINS));
444        }
445
446        foreach ($arrMobileMailDomains as $domain) {
447            $domain = str_replace('.', '\\.', $domain);
448            if (preg_match("/@([^@]+\\.)?$domain\$/", $address)) {
449                return true;
450            }
451        }
452
453        return false;
454    }
455}
456?>
Note: See TracBrowser for help on using the repository browser.