source: branches/version-2_13-dev/data/class/util/SC_Utils.php @ 22926

Revision 22926, 62.2 KB checked in by Seasoft, 11 years ago (diff)

#2287 (環境によりデストラクタが正しく動作しないケースがある)
#2288 (リクエスト単位で実行されるべきログ出力がブロックにも適用されている)
#2043 (typo修正・ソース整形・ソースコメントの改善 for 2.13.0)

  • 不明確な仕様にコメントを残した。
  • 親デストラクタを呼ぶだけの記述は可読性が悪くなると考え削除した。(上述のチケットで OS の仕様に依存したデストラクタとなるため、敢えてアプリケーション側で記述しておく意義は薄れたという認識のもと。)
  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • 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
24/**
25 * 各種ユーティリティクラス.
26 *
27 * 主に static 参照するユーティリティ系の関数群
28 *
29 * :XXX: 内部でインスタンスを生成している関数は, Helper クラスへ移動するべき...
30 *
31 * @package Util
32 * @author LOCKON CO.,LTD.
33 * @version $Id:SC_Utils.php 15532 2007-08-31 14:39:46Z nanasess $
34 */
35class SC_Utils
36{
37    // インストール初期処理
38    function sfInitInstall()
39    {
40        // インストール済みが定義されていない。
41        if (!defined('ECCUBE_INSTALL')) {
42            $phpself = $_SERVER['SCRIPT_NAME'];
43            if (strpos('/install/', $phpself) === false) {
44                $path = substr($phpself, 0, strpos($phpself, basename($phpself)));
45                $install_url = SC_Utils_Ex::searchInstallerPath($path);
46                header('Location: ' . $install_url);
47                exit;
48            }
49        }
50        $path = HTML_REALDIR . 'install/' . DIR_INDEX_FILE;
51        if (file_exists($path)) {
52            SC_Utils_Ex::sfErrorHeader('&gt;&gt; /install/' . DIR_INDEX_FILE . ' は、インストール完了後にファイルを削除してください。');
53        }
54    }
55
56    /**
57     * インストーラのパスを検索し, URL を返す.
58     *
59     * $path と同階層に install/index.php があるか検索する.
60     * 存在しない場合は上位階層を再帰的に検索する.
61     * インストーラのパスが見つかった場合は, その URL を返す.
62     * DocumentRoot まで検索しても見つからない場合は /install/index.php を返す.
63     *
64     * @param string $path 検索対象のパス
65     * @return string インストーラの URL
66     */
67    function searchInstallerPath($path)
68    {
69        $installer = 'install/' . DIR_INDEX_PATH;
70
71        if (SC_Utils_Ex::sfIsHTTPS()) {
72            $proto = 'https://';
73        } else {
74            $proto = 'http://';
75        }
76        $host = $proto . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'];
77        if ($path == '/') {
78            return $host . $path . $installer;
79        }
80        if (substr($path, -1, 1) != '/') {
81            $path .= $path . '/';
82        }
83        $installer_url = $host . $path . $installer;
84        $resources = fopen(SC_Utils_Ex::getRealURL($installer_url), 'r');
85        if ($resources === false) {
86            $installer_url = SC_Utils_Ex::searchInstallerPath($path . '../');
87        }
88
89        return $installer_url;
90    }
91
92    /**
93     * 相対パスで記述された URL から絶対パスの URL を取得する.
94     *
95     * この関数は, http(s):// から始まる URL を解析し, 相対パスで記述されていた
96     * 場合, 絶対パスに変換して返す
97     *
98     * 例)
99     * http://www.example.jp/aaa/../index.php
100     * ↓
101     * http://www.example.jp/index.php
102     *
103     * @param string $url http(s):// から始まる URL
104     * @return string $url を絶対パスに変換した URL
105     */
106    function getRealURL($url)
107    {
108        $parse = parse_url($url);
109        $tmp = explode('/', $parse['path']);
110        $results = array();
111        foreach ($tmp as $v) {
112            if ($v == '' || $v == '.') {
113                // queit.
114            } elseif ($v == '..') {
115                array_pop($results);
116            } else {
117                array_push($results, $v);
118            }
119        }
120
121        $path = join('/', $results);
122
123        return $parse['scheme'] . '://' . $parse['host'] . ':' . $parse['port'] .'/' . $path;
124    }
125
126    // 装飾付きエラーメッセージの表示
127    function sfErrorHeader($mess, $print = false)
128    {
129        global $GLOBAL_ERR;
130        $GLOBAL_ERR.= '<div id="errorHeader">';
131        $GLOBAL_ERR.= $mess;
132        $GLOBAL_ERR.= '</div>';
133        if ($print) {
134            echo $GLOBAL_ERR;
135        }
136    }
137
138    /* エラーページの表示 */
139    function sfDispError($type)
140    {
141        require_once CLASS_EX_REALDIR . 'page_extends/error/LC_Page_Error_DispError_Ex.php';
142
143        $objPage = new LC_Page_Error_DispError_Ex();
144        $objPage->init();
145        $objPage->type = $type;
146        $objPage->process();
147        exit;
148    }
149
150    /* サイトエラーページの表示 */
151    function sfDispSiteError($type, $objSiteSess = '', $return_top = false, $err_msg = '')
152    {
153        require_once CLASS_EX_REALDIR . 'page_extends/error/LC_Page_Error_Ex.php';
154
155        $objPage = new LC_Page_Error_Ex();
156        $objPage->init();
157        $objPage->type = $type;
158        $objPage->objSiteSess = $objSiteSess;
159        $objPage->return_top = $return_top;
160        $objPage->err_msg = $err_msg;
161        $objPage->is_mobile = SC_Display_Ex::detectDevice() == DEVICE_TYPE_MOBILE;
162        $objPage->process();
163        exit;
164    }
165
166    /**
167     * 前方互換用
168     *
169     * @deprecated 2.12.0 trigger_error($debugMsg, E_USER_ERROR) を使用すること
170     */
171    function sfDispException($debugMsg = null)
172    {
173        trigger_error('前方互換用メソッドが使用されました。', E_USER_WARNING);
174        trigger_error($debugMsg, E_USER_ERROR);
175    }
176
177    /* 認証の可否判定 */
178    function sfIsSuccess($objSess, $disp_error = true)
179    {
180        $ret = $objSess->IsSuccess();
181        if ($ret != SUCCESS) {
182            if ($disp_error) {
183                // エラーページの表示
184                SC_Utils_Ex::sfDispError($ret);
185            }
186            return false;
187        }
188        // リファラーチェック(CSRFの暫定的な対策)
189        // 「リファラ無」 の場合はスルー
190        // 「リファラ有」 かつ 「管理画面からの遷移でない」 場合にエラー画面を表示する
191        if (empty($_SERVER['HTTP_REFERER'])) {
192            // TODO 警告表示させる?
193            // sfErrorHeader('>> referrerが無効になっています。');
194        } else {
195            $domain  = SC_Utils_Ex::sfIsHTTPS() ? HTTPS_URL : HTTP_URL;
196            $pattern = sprintf('|^%s.*|', $domain);
197            $referer = $_SERVER['HTTP_REFERER'];
198
199            // 管理画面から以外の遷移の場合はエラー画面を表示
200            if (!preg_match($pattern, $referer)) {
201                if ($disp_error) SC_Utils_Ex::sfDispError(INVALID_MOVE_ERRORR);
202                return false;
203            }
204        }
205
206        return true;
207    }
208
209    /**
210     * 文字列をアスタリスクへ変換する.
211     *
212     * @param string $passlen 変換する文字列
213     * @return string アスタリスクへ変換した文字列
214     */
215    function sfPassLen($passlen)
216    {
217        $ret = '';
218        for ($i=0;$i<$passlen;true) {
219            $ret.='*';
220            $i++;
221        }
222
223        return $ret;
224    }
225
226    /**
227     * HTTPSかどうかを判定
228     *
229     * @return bool
230     */
231    function sfIsHTTPS()
232    {
233        // HTTPS時には$_SERVER['HTTPS']には空でない値が入る
234        // $_SERVER['HTTPS'] != 'off' はIIS用
235        if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
236            return true;
237        } else {
238            return false;
239        }
240    }
241
242    /**
243     *  正規の遷移がされているかを判定
244     *  前画面でuniqidを埋め込んでおく必要がある
245     *  @param  obj  SC_Session, SC_SiteSession
246     *  @return bool
247     */
248    function sfIsValidTransition($objSess)
249    {
250        // 前画面からPOSTされるuniqidが正しいものかどうかをチェック
251        $uniqid = $objSess->getUniqId();
252        if (!empty($_POST['uniqid']) && ($_POST['uniqid'] === $uniqid)) {
253            return true;
254        } else {
255            return false;
256        }
257    }
258
259    /* DB用日付文字列取得 */
260    function sfGetTimestamp($year, $month, $day, $last = false)
261    {
262        if ($year != '' && $month != '' && $day != '') {
263            if ($last) {
264                $time = '23:59:59';
265            } else {
266                $time = '00:00:00';
267            }
268            $date = $year.'-'.$month.'-'.$day.' '.$time;
269        } else {
270            $date = '';
271        }
272
273        return $date;
274    }
275
276    /* DB用日付日時文字列取得 */
277    function sfGetTimestampistime($year, $month, $day, $hour, $minutes, $last = false)
278    {
279        if ($year != '' && $month != '' && $day != '' && $hour != '' && $minutes != '') {
280            if ($last) {
281                $time = $hour.':'.$minutes.':59';
282            } else {
283                $time = $hour.':'.$minutes.':00';
284            }
285            $date = $year.'-'.$month.'-'.$day.' '.$time;
286        } else {
287            $date = '';
288        }
289
290        return $date;
291    }
292
293    /**
294     *  INT型の数値チェック
295     *  ・FIXME: マイナス値の扱いが不明確
296     *  ・XXX: INT_LENには収まるが、INT型の範囲を超えるケースに対応できないのでは?
297     *
298     *  @param mixed $value
299     *  @return bool
300     */
301    //
302    function sfIsInt($value)
303    {
304        if (strlen($value) >= 1 && strlen($value) <= INT_LEN && is_numeric($value)) {
305            return true;
306        }
307
308        return false;
309    }
310
311    /*
312     * 桁が0で埋められているかを判定する
313     *
314     * @param string $value 検査対象
315     * @return boolean 0で埋められている
316     */
317    function sfIsZeroFilling($value)
318    {
319        if (strlen($value) > 1 && $value{0} === '0')
320            return true;
321
322        return false;
323    }
324
325    function sfGetCSVData($data, $prefix = '')
326    {
327        if ($prefix == '') {
328            $dir_name = SC_Utils_Ex::sfUpDirName();
329            $file_name = $dir_name . date('ymdHis') .'.csv';
330        } else {
331            $file_name = $prefix . date('ymdHis') .'.csv';
332        }
333
334        if (mb_internal_encoding() == CHAR_CODE) {
335            $data = mb_convert_encoding($data,'SJIS-Win',CHAR_CODE);
336        }
337
338        /* データを出力 */
339        return array($file_name, $data);
340    }
341
342    /* 1階層上のディレクトリ名を取得する */
343    function sfUpDirName()
344    {
345        $path = $_SERVER['SCRIPT_NAME'];
346        $arrVal = explode('/', $path);
347        $cnt = count($arrVal);
348
349        return $arrVal[($cnt - 2)];
350    }
351
352    // チェックボックスの値をマージ
353    /**
354     * @deprecated
355     */
356    function sfMergeCBValue($keyname, $max)
357    {
358        $conv = '';
359        $cnt = 1;
360        for ($cnt = 1; $cnt <= $max; $cnt++) {
361            if ($_POST[$keyname . $cnt] == '1') {
362                $conv.= '1';
363            } else {
364                $conv.= '0';
365            }
366        }
367
368        return $conv;
369    }
370
371    // html_checkboxesの値をマージして2進数形式に変更する。
372    /**
373     * @deprecated
374     */
375    function sfMergeCheckBoxes($array, $max)
376    {
377        $ret = '';
378        $arrTmp = array();
379        if (is_array($array)) {
380            foreach ($array as $val) {
381                $arrTmp[$val] = '1';
382            }
383        }
384        for ($i = 1; $i <= $max; $i++) {
385            if (isset($arrTmp[$i]) && $arrTmp[$i] == '1') {
386                $ret.= '1';
387            } else {
388                $ret.= '0';
389            }
390        }
391
392        return $ret;
393    }
394
395    // html_checkboxesの値をマージして「-」でつなげる。
396    /**
397     * @deprecated
398     */
399    function sfMergeParamCheckBoxes($array)
400    {
401        $ret = '';
402        if (is_array($array)) {
403            foreach ($array as $val) {
404                if ($ret != '') {
405                    $ret.= "-$val";
406                } else {
407                    $ret = $val;
408                }
409            }
410        } else {
411            $ret = $array;
412        }
413
414        return $ret;
415    }
416
417    // html_checkboxesの値をマージしてSQL検索用に変更する。
418    /**
419     * @deprecated
420     */
421    function sfSearchCheckBoxes($array)
422    {
423        $max = max($array);
424        $ret = '';
425        for ($i = 1; $i <= $max; $i++) {
426            $ret .= in_array($i, $array) ? '1' : '_';
427        }
428        if (strlen($ret) != 0) {
429            $ret .= '%';
430        }
431
432        return $ret;
433    }
434
435    // 2進数形式の値をhtml_checkboxes対応の値に切り替える
436    /**
437     * @deprecated
438     */
439    function sfSplitCheckBoxes($val)
440    {
441        $arrRet = array();
442        $len = strlen($val);
443        for ($i = 0; $i < $len; $i++) {
444            if (substr($val, $i, 1) == '1') {
445                $arrRet[] = ($i + 1);
446            }
447        }
448
449        return $arrRet;
450    }
451
452    // チェックボックスの値をマージ
453    /**
454     * @deprecated
455     */
456    function sfMergeCBSearchValue($keyname, $max)
457    {
458        $conv = '';
459        $cnt = 1;
460        for ($cnt = 1; $cnt <= $max; $cnt++) {
461            if ($_POST[$keyname . $cnt] == '1') {
462                $conv.= '1';
463            } else {
464                $conv.= '_';
465            }
466        }
467
468        return $conv;
469    }
470
471    // チェックボックスの値を分解
472    /**
473     * @deprecated
474     */
475    function sfSplitCBValue($val, $keyname = '')
476    {
477        $arr = array();
478        $len = strlen($val);
479        $no = 1;
480        for ($cnt = 0; $cnt < $len; $cnt++) {
481            if ($keyname != '') {
482                $arr[$keyname . $no] = substr($val, $cnt, 1);
483            } else {
484                $arr[] = substr($val, $cnt, 1);
485            }
486            $no++;
487        }
488
489        return $arr;
490    }
491
492    // キーと値をセットした配列を取得
493    function sfArrKeyValue($arrList, $keyname, $valname, $len_max = '', $keysize = '')
494    {
495        $arrRet = array();
496        $max = count($arrList);
497
498        if ($len_max != '' && $max > $len_max) {
499            $max = $len_max;
500        }
501
502        for ($cnt = 0; $cnt < $max; $cnt++) {
503            if ($keysize != '') {
504                $key = SC_Utils_Ex::sfCutString($arrList[$cnt][$keyname], $keysize);
505            } else {
506                $key = $arrList[$cnt][$keyname];
507            }
508            $val = $arrList[$cnt][$valname];
509
510            if (!isset($arrRet[$key])) {
511                $arrRet[$key] = $val;
512            }
513
514        }
515
516        return $arrRet;
517    }
518
519    // キーと値をセットした配列を取得(値が複数の場合)
520    function sfArrKeyValues($arrList, $keyname, $valname, $len_max = '', $keysize = '', $connect = '')
521    {
522        $max = count($arrList);
523
524        if ($len_max != '' && $max > $len_max) {
525            $max = $len_max;
526        }
527
528        $keyValues = array();
529        for ($cnt = 0; $cnt < $max; $cnt++) {
530            if ($keysize != '') {
531                $key = SC_Utils_Ex::sfCutString($arrList[$cnt][$keyname], $keysize);
532            } else {
533                $key = $arrList[$cnt][$keyname];
534            }
535            $val = $arrList[$cnt][$valname];
536
537            if ($connect != '') {
538                $keyValues[$key].= "$val".$connect;
539            } else {
540                $keyValues[$key][] = $val;
541            }
542        }
543
544        return $keyValues;
545    }
546
547    // 配列の値をカンマ区切りで返す。
548    function sfGetCommaList($array, $space=true, $arrPop = array())
549    {
550        if (count($array) > 0) {
551            $line = '';
552            foreach ($array as $val) {
553                if (!in_array($val, $arrPop)) {
554                    if ($space) {
555                        $line .= $val . ', ';
556                    } else {
557                        $line .= $val . ',';
558                    }
559                }
560            }
561            if ($space) {
562                $line = preg_replace("/, $/", '', $line);
563            } else {
564                $line = preg_replace("/,$/", '', $line);
565            }
566            return $line;
567        } else {
568            return false;
569        }
570
571    }
572
573    /* 配列の要素をCSVフォーマットで出力する。*/
574    function sfGetCSVList($array)
575    {
576        $line = '';
577        if (count($array) > 0) {
578            foreach ($array as $val) {
579                $val = mb_convert_encoding($val, CHAR_CODE, CHAR_CODE);
580                $line .= '"' .$val. '",';
581            }
582            $line = preg_replace("/,$/", "\r\n", $line);
583        } else {
584            return false;
585        }
586
587        return $line;
588    }
589
590    /*-----------------------------------------------------------------*/
591    /*    check_set_term
592    /*    年月日に別れた2つの期間の妥当性をチェックし、整合性と期間を返す
593    /* 引数 (開始年,開始月,開始日,終了年,終了月,終了日)
594    /* 戻値 array(1,2,3)
595    /*          1.開始年月日 (YYYY/MM/DD 000000)
596    /*            2.終了年月日 (YYYY/MM/DD 235959)
597    /*            3.エラー (0 = OK, 1 = NG)
598    /*-----------------------------------------------------------------*/
599    function sfCheckSetTerm($start_year, $start_month, $start_day, $end_year, $end_month, $end_day)
600    {
601        // 期間指定
602        $error = 0;
603        if ($start_month || $start_day || $start_year) {
604            if (! checkdate($start_month, $start_day , $start_year)) $error = 1;
605        } else {
606            $error = 1;
607        }
608        if ($end_month || $end_day || $end_year) {
609            if (! checkdate($end_month ,$end_day ,$end_year)) $error = 2;
610        }
611        if (! $error) {
612            $date1 = $start_year .'/'.sprintf('%02d',$start_month) .'/'.sprintf('%02d',$start_day) .' 000000';
613            $date2 = $end_year   .'/'.sprintf('%02d',$end_month)   .'/'.sprintf('%02d',$end_day)   .' 235959';
614            if ($date1 > $date2) $error = 3;
615        } else {
616            $error = 1;
617        }
618
619        return array($date1, $date2, $error);
620    }
621
622    // エラー箇所の背景色を変更するためのfunction SC_Viewで読み込む
623    function sfSetErrorStyle()
624    {
625        return 'style="background-color:'.ERR_COLOR.'"';
626    }
627
628    // 一致した値のキー名を取得
629    function sfSearchKey($array, $word, $default)
630    {
631        foreach ($array as $key => $val) {
632            if ($val == $word) {
633                return $key;
634            }
635        }
636
637        return $default;
638    }
639
640    function sfGetErrorColor($val)
641    {
642        if ($val != '') {
643            return 'background-color:' . ERR_COLOR;
644        }
645
646        return '';
647    }
648
649    function sfGetEnabled($val)
650    {
651        if (! $val) {
652            return ' disabled="disabled"';
653        }
654
655        return '';
656    }
657
658    function sfGetChecked($param, $value)
659    {
660        if ((string)$param === (string)$value) {
661            return 'checked="checked"';
662        }
663
664        return '';
665    }
666
667    function sfTrim($str)
668    {
669        $ret = preg_replace("/^[  \n\r]*/u", '', $str);
670        $ret = preg_replace("/[  \n\r]*$/u", '', $ret);
671        return $ret;
672    }
673
674    /**
675     * 税金額を返す
676     *
677     * ・店舗基本情報に基づいた計算は SC_Helper_DB::sfTax() を使用する
678     *
679     * @param integer $price 計算対象の金額
680     * @param integer $tax 税率(%単位)
681     *     XXX integer のみか不明
682     * @param integer $tax_rule 端数処理
683     * @return integer 税金額
684     */
685    function sfTax($price, $tax, $tax_rule)
686    {
687        $real_tax = $tax / 100;
688        $ret = $price * $real_tax;
689        switch ($tax_rule) {
690            // 四捨五入
691            case 1:
692                $ret = round($ret);
693                break;
694            // 切り捨て
695            case 2:
696                $ret = floor($ret);
697                break;
698            // 切り上げ
699            case 3:
700                $ret = ceil($ret);
701                break;
702            // デフォルト:切り上げ
703            default:
704                $ret = ceil($ret);
705                break;
706        }
707
708        return $ret;
709    }
710
711    /**
712     * 税金付与した金額を返す
713     *
714     * ・店舗基本情報に基づいた計算は SC_Helper_DB::sfTax() を使用する
715     *
716     * @param integer $price 計算対象の金額
717     * @param integer $tax 税率(%単位)
718     *     XXX integer のみか不明
719     * @param integer $tax_rule 端数処理
720     * @return integer 税金付与した金額
721     */
722    function sfCalcIncTax($price, $tax, $tax_rule)
723    {
724        return $price + SC_Utils_Ex::sfTax($price, $tax, $tax_rule);
725    }
726
727    // 桁数を指定して四捨五入
728    function sfRound($value, $pow = 0)
729    {
730        $adjust = pow(10 ,$pow-1);
731
732        // 整数且つ0出なければ桁数指定を行う
733        if (SC_Utils_Ex::sfIsInt($adjust) and $pow > 1) {
734            $ret = (round($value * $adjust)/$adjust);
735        }
736
737        $ret = round($ret);
738
739        return $ret;
740    }
741
742    /**
743     * ポイント付与
744     * $product_id が使われていない。
745     * @param int $price
746     * @param float $point_rate
747     * @param int $rule
748     * @param int $product_id
749     * @return int
750     */
751    function sfPrePoint($price, $point_rate, $rule = POINT_RULE, $product_id = '')
752    {
753        $real_point = $point_rate / 100;
754        $ret = $price * $real_point;
755        switch ($rule) {
756            // 四捨五入
757            case 1:
758                $ret = round($ret);
759                break;
760            // 切り捨て
761            case 2:
762                $ret = floor($ret);
763                break;
764            // 切り上げ
765            case 3:
766                $ret = ceil($ret);
767                break;
768            // デフォルト:切り上げ
769            default:
770                $ret = ceil($ret);
771                break;
772        }
773
774        return $ret;
775    }
776
777    /* 規格分類の件数取得 */
778    function sfGetClassCatCount()
779    {
780        $sql = 'select count(dtb_class.class_id) as count, dtb_class.class_id ';
781        $sql.= 'from dtb_class inner join dtb_classcategory on dtb_class.class_id = dtb_classcategory.class_id ';
782        $sql.= 'where dtb_class.del_flg = 0 AND dtb_classcategory.del_flg = 0 ';
783        $sql.= 'group by dtb_class.class_id, dtb_class.name';
784        $objQuery =& SC_Query_Ex::getSingletonInstance();
785        $arrList = $objQuery->getAll($sql);
786        // キーと値をセットした配列を取得
787        $arrRet = SC_Utils_Ex::sfArrKeyValue($arrList, 'class_id', 'count');
788
789        return $arrRet;
790    }
791
792    /**
793     * 商品IDとカテゴリIDから商品規格IDを取得する
794     * @param int $product_id
795     * @param int $classcategory_id1 デフォルト値0
796     * @param int $classcategory_id2 デフォルト値0
797     * @return int
798     */
799    function sfGetProductClassId($product_id, $classcategory_id1=0, $classcategory_id2=0)
800    {
801        $where = 'product_id = ? AND classcategory_id1 = ? AND classcategory_id2 = ?';
802        if (!$classcategory_id1) { //NULLが入ってきた場合への対策
803          $classcategory_id1 = 0;
804        }
805        if (!$classcategory_id2) {
806          $classcategory_id2 = 0;
807        }
808        $objQuery =& SC_Query_Ex::getSingletonInstance();
809        $ret = $objQuery->get('product_class_id', 'dtb_products_class', $where, Array($product_id, $classcategory_id1, $classcategory_id2));
810
811        return $ret;
812    }
813
814    /* 文末の「/」をなくす */
815    function sfTrimURL($url)
816    {
817        $ret = rtrim($url, '/');
818
819        return $ret;
820    }
821
822    /* DBから取り出した日付の文字列を調整する。*/
823    function sfDispDBDate($dbdate, $time = true)
824    {
825        list($y, $m, $d, $H, $M) = preg_split('/[- :]/', $dbdate);
826
827        if (strlen($y) > 0 && strlen($m) > 0 && strlen($d) > 0) {
828            if ($time) {
829                $str = sprintf('%04d/%02d/%02d %02d:%02d', $y, $m, $d, $H, $M);
830            } else {
831                $str = sprintf('%04d/%02d/%02d', $y, $m, $d, $H, $M);
832            }
833        } else {
834            $str = '';
835        }
836
837        return $str;
838    }
839
840    /* 配列をキー名ごとの配列に変更する */
841    function sfSwapArray($array, $isColumnName = true)
842    {
843        $arrRet = array();
844        foreach ($array as $key1 => $arr1) {
845            if (!is_array($arr1)) continue 1;
846            $index = 0;
847            foreach ($arr1 as $key2 => $val) {
848                if ($isColumnName) {
849                    $arrRet[$key2][$key1] = $val;
850                } else {
851                    $arrRet[$index++][$key1] = $val;
852                }
853            }
854        }
855
856        return $arrRet;
857    }
858
859    /**
860     * 連想配列から新たな配列を生成して返す.
861     *
862     * $requires が指定された場合, $requires に含まれるキーの値のみを返す.
863     *
864     * @param array 連想配列
865     * @param array 必須キーの配列
866     * @return array 連想配列の値のみの配列
867     */
868    function getHash2Array($hash, $requires = array())
869    {
870        $array = array();
871        $i = 0;
872        foreach ($hash as $key => $val) {
873            if (!empty($requires)) {
874                if (in_array($key, $requires)) {
875                    $array[$i] = $val;
876                    $i++;
877                }
878            } else {
879                $array[$i] = $val;
880                $i++;
881            }
882        }
883
884        return $array;
885    }
886
887    /* かけ算をする(Smarty用) */
888    function sfMultiply($num1, $num2)
889    {
890        return $num1 * $num2;
891    }
892
893    /**
894     * 加算ポイントの計算
895     *
896     * ・店舗基本情報に基づいた計算は SC_Helper_DB::sfGetAddPoint() を使用する
897     *
898     * @param integer $totalpoint
899     * @param integer $use_point
900     * @param integer $point_rate
901     * @return integer 加算ポイント
902     */
903    function sfGetAddPoint($totalpoint, $use_point, $point_rate)
904    {
905        // 購入商品の合計ポイントから利用したポイントのポイント換算価値を引く方式
906        $add_point = $totalpoint - intval($use_point * ($point_rate / 100));
907
908        if ($add_point < 0) {
909            $add_point = '0';
910        }
911
912        return $add_point;
913    }
914
915    /* 一意かつ予測されにくいID */
916    function sfGetUniqRandomId($head = '')
917    {
918        // 予測されないようにランダム文字列を付与する。
919        $random = GC_Utils_Ex::gfMakePassword(8);
920        // 同一ホスト内で一意なIDを生成
921        $id = uniqid($head);
922
923        return $id . $random;
924    }
925
926    // 二回以上繰り返されているスラッシュ[/]を一つに変換する。
927    function sfRmDupSlash($istr)
928    {
929        if (preg_match('|^http://|', $istr)) {
930            $str = substr($istr, 7);
931            $head = 'http://';
932        } else if (preg_match('|^https://|', $istr)) {
933            $str = substr($istr, 8);
934            $head = 'https://';
935        } else {
936            $str = $istr;
937        }
938        $str = preg_replace('|[/]+|', '/', $str);
939        $ret = $head . $str;
940
941        return $ret;
942    }
943
944    /**
945     * テキストファイルの文字エンコーディングを変換する.
946     *
947     * $filepath に存在するテキストファイルの文字エンコーディングを変換する.
948     * 変換前の文字エンコーディングは, mb_detect_order で設定した順序で自動検出する.
949     * 変換後は, 変換前のファイル名に「enc_」というプレフィクスを付与し,
950     * $out_dir で指定したディレクトリへ出力する
951     *
952     * TODO $filepath のファイルがバイナリだった場合の扱い
953     * TODO fwrite などでのエラーハンドリング
954     *
955     * @access public
956     * @param string $filepath 変換するテキストファイルのパス
957     * @param string $enc_type 変換後のファイルエンコーディングの種類を表す文字列
958     * @param string $out_dir 変換後のファイルを出力するディレクトリを表す文字列
959     * @return string 変換後のテキストファイルのパス
960     */
961    function sfEncodeFile($filepath, $enc_type, $out_dir)
962    {
963        $ifp = fopen($filepath, 'r');
964
965        // 正常にファイルオープンした場合
966        if ($ifp !== false) {
967            $basename = basename($filepath);
968            $outpath = $out_dir . 'enc_' . $basename;
969
970            $ofp = fopen($outpath, 'w+');
971
972            while (!feof($ifp)) {
973                $line = fgets($ifp);
974                $line = mb_convert_encoding($line, $enc_type, 'auto');
975                fwrite($ofp,  $line);
976            }
977
978            fclose($ofp);
979            fclose($ifp);
980        }
981        // ファイルが開けなかった場合はエラーページを表示
982        else {
983            SC_Utils_Ex::sfDispError('');
984            exit;
985        }
986
987        return $outpath;
988    }
989
990    function sfCutString($str, $len, $byte = true, $commadisp = true)
991    {
992        if ($byte) {
993            if (strlen($str) > ($len + 2)) {
994                $ret =substr($str, 0, $len);
995                $cut = substr($str, $len);
996            } else {
997                $ret = $str;
998                $commadisp = false;
999            }
1000        } else {
1001            if (mb_strlen($str) > ($len + 1)) {
1002                $ret = mb_substr($str, 0, $len);
1003                $cut = mb_substr($str, $len);
1004            } else {
1005                $ret = $str;
1006                $commadisp = false;
1007            }
1008        }
1009
1010        // 絵文字タグの途中で分断されないようにする。
1011        if (isset($cut)) {
1012            // 分割位置より前の最後の [ 以降を取得する。
1013            $head = strrchr($ret, '[');
1014
1015            // 分割位置より後の最初の ] 以前を取得する。
1016            $tail_pos = strpos($cut, ']');
1017            if ($tail_pos !== false) {
1018                $tail = substr($cut, 0, $tail_pos + 1);
1019            }
1020
1021            // 分割位置より前に [、後に ] が見つかった場合は、[ から ] までを
1022            // 接続して絵文字タグ1個分になるかどうかをチェックする。
1023            if ($head !== false && $tail_pos !== false) {
1024                $subject = $head . $tail;
1025                if (preg_match('/^\[emoji:e?\d+\]$/', $subject)) {
1026                    // 絵文字タグが見つかったので削除する。
1027                    $ret = substr($ret, 0, -strlen($head));
1028                }
1029            }
1030        }
1031
1032        if ($commadisp) {
1033            $ret = $ret . '...';
1034        }
1035
1036        return $ret;
1037    }
1038
1039    // 年、月、締め日から、先月の締め日+1、今月の締め日を求める。
1040    function sfTermMonth($year, $month, $close_day)
1041    {
1042        $end_year = $year;
1043        $end_month = $month;
1044
1045        // 該当月の末日を求める。
1046        $end_last_day = date('d', mktime(0, 0, 0, $month + 1, 0, $year));
1047
1048        // 月の末日が締め日より少ない場合
1049        if ($end_last_day < $close_day) {
1050            // 締め日を月末日に合わせる
1051            $end_day = $end_last_day;
1052        } else {
1053            $end_day = $close_day;
1054        }
1055
1056        // 前月の取得
1057        $tmp_year = date('Y', mktime(0, 0, 0, $month, 0, $year));
1058        $tmp_month = date('m', mktime(0, 0, 0, $month, 0, $year));
1059        // 前月の末日を求める。
1060        $start_last_day = date('d', mktime(0, 0, 0, $month, 0, $year));
1061
1062        // 前月の末日が締め日より少ない場合
1063        if ($start_last_day < $close_day) {
1064            // 月末日に合わせる
1065            $tmp_day = $start_last_day;
1066        } else {
1067            $tmp_day = $close_day;
1068        }
1069
1070        // 先月の末日の翌日を取得する
1071        $start_year = date('Y', mktime(0, 0, 0, $tmp_month, $tmp_day + 1, $tmp_year));
1072        $start_month = date('m', mktime(0, 0, 0, $tmp_month, $tmp_day + 1, $tmp_year));
1073        $start_day = date('d', mktime(0, 0, 0, $tmp_month, $tmp_day + 1, $tmp_year));
1074
1075        // 日付の作成
1076        $start_date = sprintf('%d/%d/%d', $start_year, $start_month, $start_day);
1077        $end_date = sprintf('%d/%d/%d 23:59:59', $end_year, $end_month, $end_day);
1078
1079        return array($start_date, $end_date);
1080    }
1081
1082    // 再帰的に多段配列を検索して一次元配列(Hidden引渡し用配列)に変換する。
1083    function sfMakeHiddenArray($arrSrc, $arrDst = array(), $parent_key = '')
1084    {
1085        if (is_array($arrSrc)) {
1086            foreach ($arrSrc as $key => $val) {
1087                if ($parent_key != '') {
1088                    $keyname = $parent_key . '['. $key . ']';
1089                } else {
1090                    $keyname = $key;
1091                }
1092                if (is_array($val)) {
1093                    $arrDst = SC_Utils_Ex::sfMakeHiddenArray($val, $arrDst, $keyname);
1094                } else {
1095                    $arrDst[$keyname] = $val;
1096                }
1097            }
1098        }
1099
1100        return $arrDst;
1101    }
1102
1103    // DB取得日時をタイムに変換
1104    function sfDBDatetoTime($db_date)
1105    {
1106        $date = preg_replace("|\..*$|",'',$db_date);
1107        $time = strtotime($date);
1108
1109        return $time;
1110    }
1111
1112    /**
1113     * PHPのmb_convert_encoding関数をSmartyでも使えるようにする
1114     *
1115     * XXX この関数を使っている箇所は、ほぼ設計誤りと思われる。変数にフェッチするか、出力時のエンコーディングで対応すべきと見受ける。
1116     */
1117    function sfMbConvertEncoding($str, $encode = CHAR_CODE)
1118    {
1119        return mb_convert_encoding($str, $encode);
1120    }
1121
1122    // 2つの配列を用いて連想配列を作成する
1123    function sfArrCombine($arrKeys, $arrValues)
1124    {
1125        if (count($arrKeys) <= 0 and count($arrValues) <= 0) return array();
1126
1127        $keys = array_values($arrKeys);
1128        $vals = array_values($arrValues);
1129
1130        $max = max( count($keys), count($vals));
1131        $combine_ary = array();
1132        for ($i=0; $i<$max; $i++) {
1133            $combine_ary[$keys[$i]] = $vals[$i];
1134        }
1135        if (is_array($combine_ary)) return $combine_ary;
1136
1137        return false;
1138    }
1139
1140    /* 階層構造のテーブルから与えられたIDの直属の子を取得する */
1141    function sfGetUnderChildrenArray($arrData, $pid_name, $id_name, $parent)
1142    {
1143        $max = count($arrData);
1144
1145        $arrChildren = array();
1146        // 子IDを検索する
1147        for ($i = 0; $i < $max; $i++) {
1148            if ($arrData[$i][$pid_name] == $parent) {
1149                $arrChildren[] = $arrData[$i][$id_name];
1150            }
1151        }
1152
1153        return $arrChildren;
1154    }
1155
1156    /**
1157     * SQLシングルクォート対応
1158     * @deprecated SC_Query::quote() を使用すること
1159     */
1160    function sfQuoteSmart($in)
1161    {
1162        if (is_int($in) || is_double($in)) {
1163            return $in;
1164        } elseif (is_bool($in)) {
1165            return $in ? 1 : 0;
1166        } elseif (is_null($in)) {
1167            return 'NULL';
1168        } else {
1169            return "'" . str_replace("'", "''", $in) . "'";
1170        }
1171    }
1172
1173    // ディレクトリを再帰的に生成する
1174    function sfMakeDir($path)
1175    {
1176        static $count = 0;
1177        $count++;  // 無限ループ回避
1178        $dir = dirname($path);
1179        if (preg_match("|^[/]$|", $dir) || preg_match("|^[A-Z]:[\\]$|", $dir) || $count > 256) {
1180            // ルートディレクトリで終了
1181            return;
1182        } else {
1183            if (is_writable(dirname($dir))) {
1184                if (!file_exists($dir)) {
1185                    mkdir($dir);
1186                    GC_Utils_Ex::gfPrintLog("mkdir $dir");
1187                }
1188            } else {
1189                SC_Utils_Ex::sfMakeDir($dir);
1190                if (is_writable(dirname($dir))) {
1191                    if (!file_exists($dir)) {
1192                        mkdir($dir);
1193                        GC_Utils_Ex::gfPrintLog("mkdir $dir");
1194                    }
1195                }
1196            }
1197        }
1198
1199        return;
1200    }
1201
1202    // ディレクトリ以下のファイルを再帰的にコピー
1203    function sfCopyDir($src, $des, $mess = '', $override = false)
1204    {
1205        if (!is_dir($src)) {
1206            return false;
1207        }
1208
1209        $oldmask = umask(0);
1210        $mod= stat($src);
1211
1212        // ディレクトリがなければ作成する
1213        if (!file_exists($des)) {
1214            if (!mkdir($des, $mod[2])) {
1215                echo 'path:' . $des;
1216            }
1217        }
1218
1219        $fileArray=glob($src.'*');
1220        if (is_array($fileArray)) {
1221            foreach ($fileArray as $data_) {
1222                // CVS管理ファイルはコピーしない
1223                if (strpos($data_, '/CVS/Entries') !== false) {
1224                    break;
1225                }
1226                if (strpos($data_, '/CVS/Repository') !== false) {
1227                    break;
1228                }
1229                if (strpos($data_, '/CVS/Root') !== false) {
1230                    break;
1231                }
1232
1233                mb_ereg("^(.*[\/])(.*)",$data_, $matches);
1234                $data=$matches[2];
1235                if (is_dir($data_)) {
1236                    $mess = SC_Utils_Ex::sfCopyDir($data_.'/', $des.$data.'/', $mess);
1237                } else {
1238                    if (!$override && file_exists($des.$data)) {
1239                        $mess.= $des.$data . ":ファイルが存在します\n";
1240                    } else {
1241                        if (@copy($data_, $des.$data)) {
1242                            $mess.= $des.$data . ":コピー成功\n";
1243                        } else {
1244                            $mess.= $des.$data . ":コピー失敗\n";
1245                        }
1246                    }
1247                    $mod=stat($data_);
1248                }
1249            }
1250        }
1251        umask($oldmask);
1252
1253        return $mess;
1254    }
1255
1256    /**
1257     * ブラウザに強制的に送出する
1258     *
1259     * @param boolean|string $output 半角スペース256文字+改行を出力するか。または、送信する文字列を指定。
1260     * @return void
1261     */
1262    function sfFlush($output = false, $sleep = 0)
1263    {
1264        // 出力をバッファリングしない(==日本語自動変換もしない)
1265        while (@ob_end_flush());
1266
1267        if ($output === true) {
1268            // IEのために半角スペース256文字+改行を出力
1269            //echo str_repeat(' ', 256) . "\n";
1270            echo str_pad('', 256) . "\n";
1271        } else if ($output !== false) {
1272            echo $output;
1273        }
1274
1275        // 出力をフラッシュする
1276        flush();
1277
1278        ob_start();
1279
1280        // 時間のかかる処理
1281        sleep($sleep);
1282    }
1283
1284    // @versionの記載があるファイルからバージョンを取得する。
1285    function sfGetFileVersion($path)
1286    {
1287        if (file_exists($path)) {
1288            $src_fp = fopen($path, 'rb');
1289            if ($src_fp) {
1290                while (!feof($src_fp)) {
1291                    $line = fgets($src_fp);
1292                    if (strpos($line, '@version') !== false) {
1293                        $arrLine = explode(' ', $line);
1294                        $version = $arrLine[5];
1295                    }
1296                }
1297                fclose($src_fp);
1298            }
1299        }
1300
1301        return $version;
1302    }
1303
1304    /**
1305     * $array の要素を $arrConvList で指定した方式で mb_convert_kana を適用する.
1306     *
1307     * @param array $array 変換する文字列の配列
1308     * @param array $arrConvList mb_convert_kana の適用ルール
1309     * @return array 変換後の配列
1310     * @see mb_convert_kana
1311     */
1312    function mbConvertKanaWithArray($array, $arrConvList)
1313    {
1314        foreach ($arrConvList as $key => $val) {
1315            if (isset($array[$key])) {
1316                $array[$key] = mb_convert_kana($array[$key] ,$val);
1317            }
1318        }
1319
1320        return $array;
1321    }
1322
1323    /**
1324     * 配列の添字が未定義の場合は空文字を代入して定義する.
1325     *
1326     * @param array $array 添字をチェックする配列
1327     * @param array $defineIndexes チェックする添字
1328     * @return array 添字を定義した配列
1329     */
1330    function arrayDefineIndexes($array, $defineIndexes)
1331    {
1332        foreach ($defineIndexes as $key) {
1333            if (!isset($array[$key])) $array[$key] = '';
1334        }
1335
1336        return $array;
1337    }
1338
1339    /**
1340     * $arrSrc のうち、キーが $arrKey に含まれるものを返す
1341     *
1342     * $arrSrc に含まない要素は返されない。
1343     *
1344     * @param array $arrSrc
1345     * @param array $arrKey
1346     * @return array
1347     */
1348    function sfArrayIntersectKeys($arrSrc, $arrKey)
1349    {
1350        $arrRet = array();
1351        foreach ($arrKey as $key) {
1352            if (isset($arrSrc[$key])) $arrRet[$key] = $arrSrc[$key];
1353        }
1354
1355        return $arrRet;
1356    }
1357
1358    /**
1359     * 前方互換用
1360     *
1361     * @deprecated 2.12.0 GC_Utils_Ex::printXMLDeclaration を使用すること
1362     */
1363    function printXMLDeclaration()
1364    {
1365        trigger_error('前方互換用メソッドが使用されました。', E_USER_WARNING);
1366        GC_Utils_Ex::printXMLDeclaration();
1367    }
1368
1369    /**
1370     * 配列をテーブルタグで出力する。
1371     *
1372     * @return string
1373     */
1374    function getTableTag($array)
1375    {
1376        $html = '<table>';
1377        $html.= '<tr>';
1378        foreach ($array[0] as $key => $val) {
1379            $html.="<th>$key</th>";
1380        }
1381        $html.= '</tr>';
1382
1383        $cnt = count($array);
1384
1385        for ($i = 0; $i < $cnt; $i++) {
1386            $html.= '<tr>';
1387            foreach ($array[$i] as $val) {
1388                $html.="<td>$val</td>";
1389            }
1390            $html.= '</tr>';
1391        }
1392
1393        return $html;
1394    }
1395
1396    /**
1397     * 一覧-メイン画像のファイル指定がない場合、専用の画像ファイルに書き換える。
1398     *
1399     * @param string &$filename ファイル名
1400     * @return string
1401     */
1402    function sfNoImageMainList($filename = '')
1403    {
1404        if (strlen($filename) == 0 || substr($filename, -1, 1) == '/') {
1405            $filename .= 'noimage_main_list.jpg';
1406        }
1407
1408        return $filename;
1409    }
1410
1411    /**
1412     * 詳細-メイン画像のファイル指定がない場合、専用の画像ファイルに書き換える。
1413     *
1414     * @param string &$filename ファイル名
1415     * @return string
1416     */
1417    function sfNoImageMain($filename = '')
1418    {
1419        if (strlen($filename) == 0 || substr($filename, -1, 1) == '/') {
1420            $filename .= 'noimage_main.png';
1421        }
1422
1423        return $filename;
1424    }
1425
1426    /* デバッグ用 ------------------------------------------------------------------------------------------------*/
1427    function sfPrintR($obj)
1428    {
1429        echo '<div style="font-size: 12px;color: #00FF00;">' . "\n";
1430        echo '<strong>**デバッグ中**</strong><br />' . "\n";
1431        echo '<pre>' . "\n";
1432        var_dump($obj);
1433        echo '</pre>' . "\n";
1434        echo '<strong>**デバッグ中**</strong></div>' . "\n";
1435    }
1436
1437    /**
1438     * ランダムな文字列を取得する
1439     *
1440     * @param integer $length 文字数
1441     * @return string ランダムな文字列
1442     */
1443    function sfGetRandomString($length = 1)
1444    {
1445        return Text_Password::create($length);
1446    }
1447
1448    /**
1449     * 前方互換用
1450     *
1451     * @deprecated 2.12.0 GC_Utils_Ex::getUrl を使用すること
1452     */
1453    function sfGetUrl()
1454    {
1455        trigger_error('前方互換用メソッドが使用されました。', E_USER_WARNING);
1456
1457        return GC_Utils_Ex::getUrl();
1458    }
1459
1460    /**
1461     * 前方互換用
1462     *
1463     * @deprecated 2.12.0 GC_Utils_Ex::toStringBacktrace を使用すること
1464     */
1465    function sfBacktraceToString($arrBacktrace)
1466    {
1467        trigger_error('前方互換用メソッドが使用されました。', E_USER_WARNING);
1468
1469        return GC_Utils_Ex::toStringBacktrace($arrBacktrace);
1470    }
1471
1472    /**
1473     * 前方互換用
1474     *
1475     * @deprecated 2.12.0 GC_Utils_Ex::isAdminFunction を使用すること
1476     */
1477    function sfIsAdminFunction()
1478    {
1479        trigger_error('前方互換用メソッドが使用されました。', E_USER_WARNING);
1480
1481        return GC_Utils_Ex::isAdminFunction();
1482    }
1483
1484    /**
1485     * 前方互換用
1486     *
1487     * @deprecated 2.12.0 GC_Utils_Ex::isFrontFunction を使用すること
1488     */
1489    function sfIsFrontFunction()
1490    {
1491        trigger_error('前方互換用メソッドが使用されました。', E_USER_WARNING);
1492
1493        return GC_Utils_Ex::isFrontFunction();
1494    }
1495
1496    /**
1497     * 前方互換用
1498     *
1499     * @deprecated 2.12.0 GC_Utils_Ex::isInstallFunction を使用すること
1500     */
1501    function sfIsInstallFunction()
1502    {
1503        trigger_error('前方互換用メソッドが使用されました。', E_USER_WARNING);
1504
1505        return GC_Utils_Ex::isInstallFunction();
1506    }
1507
1508    // 郵便番号から住所の取得
1509    function sfGetAddress($zipcode)
1510    {
1511        $objQuery =& SC_Query_Ex::getSingletonInstance();
1512
1513        $masterData = new SC_DB_MasterData_Ex();
1514        $arrPref = $masterData->getMasterData('mtb_pref');
1515        // インデックスと値を反転させる。
1516        $arrREV_PREF = array_flip($arrPref);
1517
1518        // 郵便番号検索文作成
1519        $zipcode = mb_convert_kana($zipcode ,'n');
1520        $sqlse = 'SELECT state, city, town FROM mtb_zip WHERE zipcode = ?';
1521
1522        $data_list = $objQuery->getAll($sqlse, array($zipcode));
1523        if (empty($data_list)) return array();
1524
1525        // $zip_cntが1より大きければtownを消す
1526        //(複数行HITしているので、どれに該当するか不明の為)
1527        $zip_cnt = count($data_list);
1528        if ($zip_cnt > 1) {
1529            $data_list[0]['town'] = '';
1530        }
1531        unset($zip_cnt);
1532
1533        /*
1534         * 総務省からダウンロードしたデータをそのままインポートすると
1535         * 以下のような文字列が入っているので 対策する。
1536         * ・(1・19丁目)
1537         * ・以下に掲載がない場合
1538         * ・●●の次に番地が来る場合
1539         */
1540        $town =  $data_list[0]['town'];
1541        $town = preg_replace("/(.*)$/",'',$town);
1542        $town = preg_replace('/以下に掲載がない場合/','',$town);
1543        $town = preg_replace('/(.*?)の次に番地がくる場合/','',$town);
1544        $data_list[0]['town'] = $town;
1545        $data_list[0]['state'] = $arrREV_PREF[$data_list[0]['state']];
1546
1547        return $data_list;
1548    }
1549
1550    /**
1551     * 前方互換用
1552     *
1553     * @deprecated 2.12.0 microtime(true) を使用する。
1554     */
1555    function sfMicrotimeFloat()
1556    {
1557        trigger_error('前方互換用メソッドが使用されました。', E_USER_WARNING);
1558
1559        return microtime(true);
1560    }
1561
1562    /**
1563     * 変数が空白かどうかをチェックする.
1564     *
1565     * 引数 $val が空白かどうかをチェックする. 空白の場合は true.
1566     * 以下の文字は空白と判断する.
1567     * - ' ' (ASCII 32 (0x20)), 通常の空白
1568     * - "\t" (ASCII 9 (0x09)), タブ
1569     * - "\n" (ASCII 10 (0x0A)), リターン
1570     * - "\r" (ASCII 13 (0x0D)), 改行
1571     * - "\0" (ASCII 0 (0x00)), NULバイト
1572     * - "\x0B" (ASCII 11 (0x0B)), 垂直タブ
1573     *
1574     * 引数 $val が配列の場合は, 空の配列の場合 true を返す.
1575     *
1576     * 引数 $greedy が true の場合は, 全角スペース, ネストした空の配列も
1577     * 空白と判断する.
1578     *
1579     * @param mixed $val チェック対象の変数
1580     * @param boolean $greedy '貧欲'にチェックを行う場合 true
1581     * @return boolean $val が空白と判断された場合 true
1582     */
1583    function isBlank($val, $greedy = true)
1584    {
1585        if (is_array($val)) {
1586            if ($greedy) {
1587                if (empty($val)) {
1588                    return true;
1589                }
1590                $array_result = true;
1591                foreach ($val as $in) {
1592                    /*
1593                     * SC_Utils_Ex への再帰は無限ループやメモリリークの懸念
1594                     * 自クラスへ再帰する.
1595                     */
1596                    $array_result = SC_Utils::isBlank($in, $greedy);
1597                    if (!$array_result) {
1598                        return false;
1599                    }
1600                }
1601                return $array_result;
1602            } else {
1603                return empty($val);
1604            }
1605        }
1606
1607        if ($greedy) {
1608            $val = preg_replace('/ /', '', $val);
1609        }
1610
1611        $val = trim($val);
1612        if (strlen($val) > 0) {
1613            return false;
1614        }
1615
1616        return true;
1617    }
1618
1619    /**
1620     * 指定されたURLのドメインが一致するかを返す
1621     *
1622     * 戻り値:一致(true) 不一致(false)
1623     *
1624     * @param string $url
1625     * @return boolean
1626     */
1627    function sfIsInternalDomain($url)
1628    {
1629        $netURL = new Net_URL(HTTP_URL);
1630        $host = $netURL->host;
1631        if (!$host) return false;
1632        $host = preg_quote($host, '#');
1633        if (!preg_match("#^(http|https)://{$host}#i", $url)) return false;
1634
1635        return true;
1636    }
1637
1638    /**
1639     * パスワードのハッシュ化
1640     *
1641     * @param string $str 暗号化したい文言
1642     * @param string $salt salt
1643     * @return string ハッシュ暗号化された文字列
1644     */
1645    function sfGetHashString($str, $salt)
1646    {
1647        $res = '';
1648        if ($salt == '') {
1649            $salt = AUTH_MAGIC;
1650        }
1651        if (AUTH_TYPE == 'PLAIN') {
1652            $res = $str;
1653        } else {
1654            $res = hash_hmac(PASSWORD_HASH_ALGOS, $str . ':' . AUTH_MAGIC, $salt);
1655        }
1656
1657        return $res;
1658    }
1659
1660    /**
1661     * パスワード文字列のハッシュ一致判定
1662     *
1663     * @param string $pass 確認したいパスワード文字列
1664     * @param string $hashpass 確認したいパスワードハッシュ文字列
1665     * @param string $salt salt
1666     * @return boolean 一致判定
1667     */
1668    function sfIsMatchHashPassword($pass, $hashpass, $salt)
1669    {
1670        $res = false;
1671        if ($hashpass != '') {
1672            if (AUTH_TYPE == 'PLAIN') {
1673                if ($pass === $hashpass) {
1674                    $res = true;
1675                }
1676            } else {
1677                if (empty($salt)) {
1678                    // 旧バージョン(2.11未満)からの移行を考慮
1679                    $hash = sha1($pass . ':' . AUTH_MAGIC);
1680                } else {
1681                    $hash = SC_Utils_Ex::sfGetHashString($pass, $salt);
1682                }
1683                if ($hash === $hashpass) {
1684                    $res = true;
1685                }
1686            }
1687        }
1688
1689        return $res;
1690    }
1691
1692    /**
1693     * 検索結果の1ページあたりの最大表示件数を取得する
1694     *
1695     * フォームの入力値から最大表示件数を取得する
1696     * 取得できなかった場合は, 定数 SEARCH_PMAX の値を返す
1697     *
1698     * @param string $search_page_max 表示件数の選択値
1699     * @return integer 1ページあたりの最大表示件数
1700     */
1701    function sfGetSearchPageMax($search_page_max)
1702    {
1703        if (SC_Utils_Ex::sfIsInt($search_page_max) && $search_page_max > 0) {
1704            $page_max = intval($search_page_max);
1705        } else {
1706            $page_max = SEARCH_PMAX;
1707        }
1708
1709        return $page_max;
1710    }
1711
1712    /**
1713     * 値を JSON 形式にして返す.
1714     *
1715     * この関数は, json_encode() 又は Services_JSON::encode() のラッパーです.
1716     * json_encode() 関数が使用可能な場合は json_encode() 関数を使用する.
1717     * 使用できない場合は, Services_JSON::encode() 関数を使用する.
1718     *
1719     * @param mixed $value JSON 形式にエンコードする値
1720     * @return string JSON 形式にした文字列
1721     * @see json_encode()
1722     * @see Services_JSON::encode()
1723     */
1724    function jsonEncode($value)
1725    {
1726        if (function_exists('json_encode')) {
1727            return json_encode($value);
1728        } else {
1729            GC_Utils_Ex::gfPrintLog(' *use Services_JSON::encode(). faster than using the json_encode!');
1730            $objJson = new Services_JSON();
1731            return $objJson->encode($value);
1732        }
1733    }
1734
1735    /**
1736     * JSON 文字列をデコードする.
1737     *
1738     * この関数は, json_decode() 又は Services_JSON::decode() のラッパーです.
1739     * json_decode() 関数が使用可能な場合は json_decode() 関数を使用する.
1740     * 使用できない場合は, Services_JSON::decode() 関数を使用する.
1741     *
1742     * @param string $json JSON 形式にエンコードされた文字列
1743     * @return mixed デコードされた PHP の型
1744     * @see json_decode()
1745     * @see Services_JSON::decode()
1746     */
1747    function jsonDecode($json)
1748    {
1749        if (function_exists('json_decode')) {
1750            return json_decode($json);
1751        } else {
1752            GC_Utils_Ex::gfPrintLog(' *use Services_JSON::decode(). faster than using the json_decode!');
1753            $objJson = new Services_JSON();
1754            return $objJson->decode($json);
1755        }
1756    }
1757
1758    /**
1759     * パスが絶対パスかどうかをチェックする.
1760     *
1761     * 引数のパスが絶対パスの場合は true を返す.
1762     * この関数は, パスの存在チェックを行なわないため注意すること.
1763     *
1764     * @param string チェック対象のパス
1765     * @return boolean 絶対パスの場合 true
1766     */
1767    function isAbsoluteRealPath($realpath)
1768    {
1769        if (strpos(PHP_OS, 'WIN') === false) {
1770            return substr($realpath, 0, 1) == '/';
1771        } else {
1772            return preg_match('/^[a-zA-Z]:(\\\|\/)/', $realpath) ? true : false;
1773        }
1774    }
1775
1776    /**
1777     * ディレクトリを再帰的に作成する.
1778     *
1779     * mkdir 関数の $recursive パラメーターを PHP4 でサポートする.
1780     *
1781     * @param string $pathname ディレクトリのパス
1782     * @param integer $mode 作成するディレクトリのパーミッション
1783     * @return boolean 作成に成功した場合 true; 失敗した場合 false
1784     * @see http://jp.php.net/mkdir
1785     */
1786    function recursiveMkdir($pathname, $mode = 0777)
1787    {
1788        /*
1789         * SC_Utils_Ex への再帰は無限ループやメモリリークの懸念
1790         * 自クラスへ再帰する.
1791         */
1792        is_dir(dirname($pathname)) || SC_Utils::recursiveMkdir(dirname($pathname), $mode);
1793
1794        return is_dir($pathname) || @mkdir($pathname, $mode);
1795    }
1796
1797    function isAppInnerUrl($url)
1798    {
1799        $pattern = '/^(' . preg_quote(HTTP_URL, '/') . '|' . preg_quote(HTTPS_URL, '/') . ')/';
1800
1801        return preg_match($pattern, $url) >= 1;
1802    }
1803
1804    /**
1805     * PHP のタイムアウトを延長する
1806     *
1807     * ループの中で呼び出すことを意図している。
1808     * 暴走スレッドが残留する確率を軽減するため、set_time_limit(0) とはしていない。
1809     * @param integer $seconds 最大実行時間を延長する秒数。
1810     * @return boolean 成功=true, 失敗=false
1811     */
1812    function extendTimeOut($seconds = null)
1813    {
1814        $safe_mode = (boolean)ini_get('safe_mode');
1815        if ($safe_mode) return false;
1816
1817        if (is_null($seconds)) {
1818            $seconds
1819                = is_numeric(ini_get('max_execution_time'))
1820                ? intval(ini_get('max_execution_time'))
1821                : intval(get_cfg_var('max_execution_time'))
1822            ;
1823        }
1824
1825        // タイムアウトをリセット
1826        set_time_limit($seconds);
1827
1828        return true;
1829    }
1830
1831   /**
1832     * コンパイルファイルを削除します.
1833     * @return void
1834     */
1835    function clearCompliedTemplate()
1836    {
1837        // コンパイルファイルの削除処理
1838        SC_Helper_FileManager_Ex::deleteFile(COMPILE_REALDIR, false);
1839        SC_Helper_FileManager_Ex::deleteFile(COMPILE_ADMIN_REALDIR, false);
1840        SC_Helper_FileManager_Ex::deleteFile(SMARTPHONE_COMPILE_REALDIR, false);
1841        SC_Helper_FileManager_Ex::deleteFile(MOBILE_COMPILE_REALDIR, false);
1842    }
1843
1844    /**
1845     * 指定されたパスの配下を再帰的にコピーします.
1846     * @param string $imageDir コピー元ディレクトリのパス
1847     * @param string $destDir コピー先ディレクトリのパス
1848     * @return void
1849     */
1850    function copyDirectory($source_path, $dest_path)
1851    {
1852        $handle=opendir($source_path);
1853        while ($filename = readdir($handle)) {
1854            if ($filename === '.' || $filename === '..') continue;
1855            $cur_path = $source_path . $filename;
1856            $dest_file_path = $dest_path . $filename;
1857            if (is_dir($cur_path)) {
1858                // ディレクトリの場合
1859                // コピー先に無いディレクトリの場合、ディレクトリ作成.
1860                if (!empty($filename) && !file_exists($dest_file_path)) mkdir($dest_file_path);
1861                SC_Utils_Ex::copyDirectory($cur_path . '/', $dest_file_path . '/');
1862            } else {
1863                if (file_exists($dest_file_path)) unlink($dest_file_path);
1864                copy($cur_path, $dest_file_path);
1865            }
1866        }
1867    }
1868
1869    /**
1870     * 文字列を区切り文字を挟み反復する
1871     * @param string $input 繰り返す文字列。
1872     * @param string $multiplier input を繰り返す回数。
1873     * @param string $separator 区切り文字
1874     * @return string
1875     */
1876    function repeatStrWithSeparator($input, $multiplier, $separator = ',')
1877    {
1878        return implode($separator, array_fill(0, $multiplier, $input));
1879    }
1880
1881    /**
1882     * RFC3986に準拠したURIエンコード
1883     * MEMO: PHP5.3.0未満では、~のエンコードをしてしまうための処理
1884     *
1885     * @param string $str 文字列
1886     * @return string RFC3986エンコード文字列
1887     */
1888    function encodeRFC3986($str)
1889    {
1890        return str_replace('%7E', '~', rawurlencode($str));
1891    }
1892
1893    /**
1894     * マルチバイト対応の trim
1895     *
1896     * @param string $str 入力文字列
1897     * @param string $charlist 削除する文字を指定
1898     * @return string 変更後の文字列
1899     */
1900    static function trim($str, $charlist = null)
1901    {
1902        $re = SC_Utils_Ex::getTrimPregPattern($charlist);
1903
1904        return preg_replace('/(^' . $re . ')|(' . $re . '$)/us', '', $str);
1905    }
1906
1907    /**
1908     * マルチバイト対応の ltrim
1909     *
1910     * @param string $str 入力文字列
1911     * @param string $charlist 削除する文字を指定
1912     * @return string 変更後の文字列
1913     */
1914    static function ltrim($str, $charlist = null)
1915    {
1916        $re = SC_Utils_Ex::getTrimPregPattern($charlist);
1917
1918        return preg_replace('/^' . $re . '/us', '', $str);
1919    }
1920
1921    /**
1922     * マルチバイト対応の rtrim
1923     *
1924     * @param string $str 入力文字列
1925     * @param string $charlist 削除する文字を指定
1926     * @return string 変更後の文字列
1927     */
1928    static function rtrim($str, $charlist = null)
1929    {
1930        $re = SC_Utils_Ex::getTrimPregPattern($charlist);
1931
1932        return preg_replace('/' . $re . '$/us', '', $str);
1933    }
1934
1935    /**
1936     * 文字列のトリム処理で使用する PCRE のパターン
1937     *
1938     * @param string $charlist 削除する文字を指定
1939     * @return string パターン
1940     */
1941    static function getTrimPregPattern($charlist = null)
1942    {
1943        if (is_null($charlist)) {
1944            return '\s+';
1945        } else {
1946            return '[' . preg_quote($charlist, '/') . ']+';
1947        }
1948    }
1949
1950    /**
1951     * データ量の単位を付与する
1952     *
1953     * @param int $data
1954     * @return string
1955     */
1956    function getUnitDataSize($data)
1957    {
1958        if($data < 1000){
1959            $return = $data . "KB";
1960        }elseif($data < 1000000){
1961            $return = $data/1000 . "MB";
1962        }else{
1963            $return = $data/1000000 . "GB";
1964        }
1965
1966        return $return;
1967    }
1968
1969    /**
1970     * カテゴリーツリー状の配列を作成.
1971     *
1972     * @param string $primary_key
1973     * @param string $glue_key
1974     * @param integer $max_depth
1975     * @param array $correction
1976     * @param integer $root_id
1977     * @return array ツリーの配列
1978     */
1979    public static function buildTree($primary_key, $glue_key, $max_depth, $correction = array(), $root_id = 0)
1980    {
1981        $children = array();
1982        foreach ($correction as $child) {
1983            $children[$child[$glue_key]][] = $child;
1984        }
1985        $arrTree = $children[$root_id];
1986        foreach ($arrTree as &$child) {
1987            SC_Utils_Ex::addChild($child, $primary_key, 1, $max_depth, $children);
1988        }
1989
1990        return $arrTree;
1991    }
1992
1993    /**
1994     * ツリーの親子をつなげるルーチン.
1995     *
1996     * @param array $target 親
1997     * @param string $primary_key 主キーの識別子
1998     * @param integer $level 親の階層
1999     * @param integer $max_depth 階層の深さの最大値
2000     * @param array $children 子の配列(キーが親ID)
2001     * @return void
2002     */
2003    public static function addChild(&$target, $primary_key, $level, $max_depth, &$children = array())
2004    {
2005        if (isset($children[$target[$primary_key]])) {
2006            $target['children'] = $children[$target[$primary_key]];
2007            if ($level + 1 < $max_depth) {
2008                foreach ($target['children'] as &$child) {
2009                    SC_Utils_Ex::addChild($child, $primary_key, $level++, $max_depth, $children);
2010                }
2011            }
2012        }
2013    }
2014
2015    /**
2016     * 配列のキーをIDにした配列を作成.
2017     *
2018     * @param string $ID_name IDが格納されているキー名
2019     * @param array $correction 元の配列
2020     * @return array
2021     */
2022    public static function makeArrayIDToKey($ID_name, $correction = array())
2023    {
2024        $arrTmp = array();
2025        foreach ($correction as $item) {
2026            $arrTmp[$item[$ID_name]] = $item;
2027        }
2028        $return =& $arrTmp;
2029        unset($arrTmp);
2030
2031        return $return;
2032    }
2033
2034    /**
2035     * 階層情報が含まれている配列から親ID配列を取得する.
2036     *
2037     * @param integer $start_id 取得起点
2038     * @param string $primary_key 主キー名
2039     * @param string $glue_key 親IDキー名
2040     * @param array $correction 階層構造が含まれている配列
2041     * @param boolean $cid_is_key キーがIDの配列の場合はtrue
2042     * @param integer $root_id ルートID
2043     * @param boolean $id_only IDだけの配列を返す場合はtrue
2044     * @return array 親ID配列
2045     */
2046    public static function getTreeTrail($start_id, $primary_key, $glue_key, $correction = array(), $cid_is_key = FALSE, $root_id = 0, $id_only = TRUE)
2047    {
2048        if ($cid_is_key) {
2049            $arrIDToKay = $correction;
2050        } else {
2051            $arrIDToKay = SC_Utils_Ex::makeArrayIDToKey($primary_key, $correction);
2052        }
2053        $id = $start_id;
2054        $arrTrail = array();
2055        while ($id != $root_id && !SC_Utils_Ex::isBlank($id)) {
2056            if ($id_only) {
2057                $arrTrail[] = $id;
2058            } else {
2059                $arrTrail[] = $arrIDToKay[$id];
2060            }
2061            if (isset($arrIDToKay[$id][$glue_key])) {
2062                $id = $arrIDToKay[$id][$glue_key];
2063            } else {
2064                $id = $root_id;
2065            }
2066        }
2067
2068        return array_reverse($arrTrail);
2069    }
2070}
Note: See TracBrowser for help on using the repository browser.