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

Revision 17676, 16.5 KB checked in by Seasoft, 12 years ago (diff)

merge 17654,17656,17657,17659,17660,17666,17669

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