<?php
// 例えば、クエリーが b=k なら isK() がtrueとなるので、携帯向け表示にしたりする
// conf_system.inc.php でcookieにb指定をセットしている。

// {{{ このクラスでのみ利用するグローバル変数（_UA_*）
// over PHP5に限定できるならプライベートなクラス変数にしたいところのもの

// @see getQueryKey()
$GLOBALS['_UA_query_key'] = 'b';

// @see setPCQuery() // b=pc
$GLOBALS['_UA_PC_query'] = 'pc';

// @see setMobileQuery() // b=k
$GLOBALS['_UA_mobile_query'] = 'k';

// @see setIPhoneGroupQuery() // b=i
$GLOBALS['_UA_iphonegroup_query'] = 'i';

$GLOBALS['_UA_force_mode'] = null; // 12/11/03現在、利用していない

// }}}

// [todo] enableJS() や enableAjax() も欲しいかも

/**
 * staticメソッドで利用する
 */
class UA
{
    /**
     * 強制的にモード（pc, k）を指定する。UA無指定時に有効。
     * （クエリーをセットするわけではない）
     */
    function setForceMode($v)
    {
        $GLOBALS['_UA_force_mode'] = $v;
    }
    
    /**
     * UAがPC（非モバイル）ならtrueを返す
     * iPhoneも含んでいるが、いずれ含まなくなる可能性があることに注意。
     * 現在、iPhoneはsetForceMode()でisMobileByQuery()扱いしている。（効力弱めで）
     *
     * @static
     * @access  public
     * @return  boolean
     */
    function isPC($ua = null)
    {
        // 現状、モバイル以外全て、b=XXでもtrueになってしまう
        return !UA::isMobile($ua);
    }
    
    /**
     * isMobile() のエイリアスになっている
     *
     * [plan] 携帯isK()と、モバイルisMobile()は、別のものとして区別した方がいいかな。（isMobile()はisK()を含むものとして）
     * 携帯：画面が小さい。ページの表示容量に制限がある。数字のアクセスキーを使う。
     * モバイル：携帯と同じく画面が小さめだが、フルブラウザで、JavaScriptが使える。
     */
    function isK($ua = null)
    {
        return UA::isMobile($ua);
    }
    
    /**
     * UAが携帯表示対象ならtrueを返す
     * isK()と意味を区別する予定があるので、それまでの間は使わないでおく（現時点、使っていない）
     * （isMobileByQuery()などは使われているが）
     * isM()にしたい気も。
     *
     * @static
     * @access  public
     * @params  string  $ua  UAを指定するなら
     * @return  boolean
     */
    function isMobile($ua = null)
    {
        static $cache_ = null;

        // UA無指定で、強制指定があれば
        if (!$ua && isset($GLOBALS['_UA_force_mode'])) {
            // ここはキャッシュしない
            return ($GLOBALS['_UA_force_mode'] == $GLOBALS['_UA_mobile_query']);
        }
        
        // 引数のUAが無指定なら、クエリー指定を参照
        if (is_null($ua)) {
            if (UA::getQueryValue()) {
                return UA::isMobileByQuery();
            }
        }
        
        // 引数のUAが無指定なら、キャッシュ有効
        if (is_null($ua) and !is_null($cache_)) {
            return $cache_;
        }
        
        $isMobile = false;
        if ($nuam = &UA::getNet_UserAgent_Mobile($ua)) {
            if (!$nuam->isNonMobile()) {
                $isMobile = true;
            }
        }
        
        /*
        // NetFront系（含むPSP）もモバイルに
        if (!$isMobile) {
            $isMobile = UA::isNetFront($ua);
        }
        */
        
        // Nintendo DSもモバイルに
        if (!$isMobile) {
            $isMobile = UA::isNintendoDS($ua);
        }
        
        // 引数のUAが無指定なら、キャッシュ保存
        if (is_null($ua)) {
            $cache_ = $isMobile;
        }
        
        return $isMobile;
    }
    
    /**
     * UAがiPhone, iPod touchならtrueを返す。（※iPadを含めている）
     *
     * @static
     * @access  public
     * @param   string   $aua  UAを指定するなら
     * @return  boolean
     */
    function isIPhoneGroup($aua = null)
    {
        static $cache_ = null;
        
        $ua = $aua;
        
        // UA無指定で、強制指定があればチェック
        if (!$ua && isset($GLOBALS['_UA_force_mode'])) {
            // 移行の便宜上、効力を弱めている
            // return ($GLOBALS['_UA_force_mode'] == $GLOBALS['_UA_iphonegroup_query']);
            if ($GLOBALS['_UA_force_mode'] == $GLOBALS['_UA_iphonegroup_query']) {
                return true;
            }
        }
        
        // UAの引数が無指定なら、
        if (is_null($ua)) {
            // クエリー指定を参照
            if (UA::getQueryValue()) {
                //// 後方互換上、b=kでもiPhoneとみなすことを許す。
                //if (!UA::isMobileByQuery()) {
                    return UA::isIPhoneGroupByQuery();
                //}
            }
            
            // （キャッシュするほどではないかも）
            // 引数のUAが無指定なら、キャッシュ有効
            if (!is_null($cache_)) {
                return $cache_;
            }
            
            // クライアントのUAで判別
            if (isset($_SERVER['HTTP_USER_AGENT'])) {
                $ua = $_SERVER['HTTP_USER_AGENT'];
            }
        }
        
        $isiPhoneGroup = false;
        
        // iPhone
        // Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3

        // iPod touch
        // Mozilla/5.0 (iPod; U; CPU like Mac OS X; ja-jp) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/3A110a Safari/419.3
        if (preg_match('/(iPhone|iPod);/', $ua)) {// || UA::isAndroidWebKit($ua)) { // androidを含めていないのはなんでだっけ？
            $isiPhoneGroup = true;
        
        // iPad 2010/5/29
        // Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; ja-jp) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B367 Safari/531.21.10
        } elseif (preg_match('/iPad;/', $ua)) {
            $isiPhoneGroup = true;
        }
        
        // UAの引数が無指定なら、キャッシュ保存
        if (is_null($aua)) {
            $cache_ = $isiPhoneGroup;
        }
        return $isiPhoneGroup;
    }
    
    /**
     * クエリーがPCを指定しているならtrueを返す
     *
     * @static
     * @access  private
     * @return  boolean
     */
    function isPCByQuery()
    {
        $qv = UA::getQueryValue();
        if (isset($qv) && $qv == UA::getPCQuery()) {
            return true;
        }
        return false;
    }
    
    /**
     * クエリーが携帯を指定しているならtrueを返す
     *
     * @static
     * @access  private
     * @return  boolean
     */
    function isMobileByQuery()
    {
        $qv = UA::getQueryValue();
        if (isset($qv) && $qv == UA::getMobileQuery()) {
            return true;
        }
        return false;
    }
    
    /**
     * クエリーがIPhoneGroupを指定しているならtrueを返す
     *
     * @static
     * @access  private
     * @return  boolean
     */
    function isIPhoneGroupByQuery()
    {
        $qv = UA::getQueryValue();
        if (isset($qv) && $qv == UA::getIPhoneGroupQuery()) {
            return true;
        }
        return false;
    }
    
    /**
     * 表示モード指定用のクエリー値を取得する
     *
     * @static
     * @access  public
     * @return  string|null
     */
    function getQueryValue($key = null)
    {
        if (is_null($key)) {
            if (!$key = UA::getQueryKey()) {
                return null;
            }
        }
        
        $value = null;
        if (isset($_POST[$key])) {
            $value = $_POST[$key];
        } elseif (isset($_GET[$key])) {
            $value = $_GET[$key];
        } elseif (isset($_COOKIE[$key])) {
            $value = $_COOKIE[$key];
        }
        $r = null;
        if ($value) {
            if (preg_match('/^\\w+$/', $value)) {
                $r = $value;
            }
        }
        return $r;
    }
    
    /**
     * @static
     * @access  public
     * @return  string
     */
    function getQueryKey()
    {
        return $GLOBALS['_UA_query_key'];
    }
    
    /**
     * @static
     * @access  public
     * @param   string  $pc  default is 'pc'
     * @return  void
     */
    function setPCQuery($pc)
    {
        $GLOBALS['_UA_PC_query'] = $pc;
    }
    
    /**
     * @static
     * @access  public
     * @return  string
     */
    function getPCQuery()
    {
        return $GLOBALS['_UA_PC_query'];
    }
    
    /**
     * @static
     * @access  public
     * @param   string  $k  default is 'k'
     * @return  void
     */
    function setMobileQuery($k)
    {
        $GLOBALS['_UA_mobile_query'] = $k;
    }
    
    /**
     * @static
     * @access  public
     * @return  string
     */
    function getMobileQuery()
    {
        return $GLOBALS['_UA_mobile_query'];
    }
    
    /**
     * @static
     * @access  public
     * @param   string  $i  default is 'i'
     * @return  void
     */
    function setIPhoneGroupQuery($i)
    {
        $GLOBALS['_UA_iphonegroup_query'] = $i;
    }
    
    /**
     * @static
     * @access  public
     * @return  string
     */
    function getIPhoneGroupQuery()
    {
        return $GLOBALS['_UA_iphonegroup_query'];
    }
    
    /**
     * Net_UserAgent_Mobile::singleton() の結果を取得する。
     * REAR Error は false に変換される。
     *
     * @static
     * @access  public
     * @param   string  $ua
     * @return  Net_UserAgent_Mobile|false
     */
    function getNet_UserAgent_Mobile($ua = null)
    {
        static $cache_ = null;
        
        if (is_null($ua) and !is_null($cache_)) {
            return $cache_;
        }
        
        require_once 'Net/UserAgent/Mobile.php';
        
        if (!is_null($ua)) {
            $nuam = &Net_UserAgent_Mobile::factory($ua);
        } else {
            $nuam = &Net_UserAgent_Mobile::singleton();
        }
        
        if (PEAR::isError($nuam)) {
            trigger_error($nuam->toString, E_USER_WARNING);
            $return = false;
            
        } elseif (!$nuam) {
            $return = false; // null
        
        } else {
            $return = $nuam;
        }
        
        if (is_null($ua)) {
            $cache_ = $return;
        }
        
        return $return;
    }
    
    /**
     * UAがdocomoならtrueを返す
     *
     * @static
     * @access  public
     * @param   string   $ua  UAを指定するなら
     * @return  boolean
     */
    function isDoCoMo($ua = null)
    {
        if ($nuam = &UA::getNet_UserAgent_Mobile($ua)) {
            return $nuam->isDoCoMo();
        }
        return false;
    }
    
    /**
     * UAがEZweb(au)ならtrueを返す
     *
     * @static
     * @access  public
     * @param   string   $ua  UAを指定するなら
     * @return  boolean
     */
    function isEZweb($ua = null)
    {
        if ($nuam = &UA::getNet_UserAgent_Mobile($ua)) {
            return $nuam->isEZweb();
        }
        return false;
    }
    
    /**
     * UAがisSoftBankならtrueを返す
     *
     * @static
     * @access  public
     * @param   string   $ua  UAを指定するなら
     * @return  boolean
     */
    function isSoftBank($ua = null)
    {
        if ($nuam = &UA::getNet_UserAgent_Mobile($ua)) {
            return $nuam->isSoftBank();
        }
        return false;
    }
    
    /**
     * UAがNetFront（携帯、PDA、PSP）ならtrueを返す
     *
     * @static
     * @access  public
     * @param   string   $ua  UAを指定するなら
     * @return  boolean
     */
    function isNetFront($ua = null)
    {
        if (is_null($ua) and isset($_SERVER['HTTP_USER_AGENT'])) {
            $ua = $_SERVER['HTTP_USER_AGENT'];
        }
        
        if (preg_match('/(NetFront|AVEFront\/|AVE-Front\/)/', $ua)) {
            return true;
        }
        if (UA::isPSP()) {
            return true;
        }
        return false;
    }
    
    /**
     * UAがPSPならtrueを返す。NetFront系らしい。
     *
     * @static
     * @access  public
     * @param   string   $ua  UAを指定するなら
     * @return  boolean
     */
    function isPSP($ua = null)
    {
        if (is_null($ua) and isset($_SERVER['HTTP_USER_AGENT'])) {
            $ua = $_SERVER['HTTP_USER_AGENT'];
        }
        
        // Mozilla/4.0 (PSP (PlayStation Portable); 2.00) 
        if (preg_match('/PlayStation Portable/', $ua)) {
            return true;
        }
        return false;
    }
    
    /**
     * UAがNintendo DS系ならtrueを返す。
     *
     * @static
     * @access  public
     * @param   string   $ua  UAを指定するなら
     * @return  boolean
     */
    function isNintendoDS($ua = null)
    {
        if (is_null($ua) and isset($_SERVER['HTTP_USER_AGENT'])) {
            $ua = $_SERVER['HTTP_USER_AGENT'];
        }
        
        // (Wii) Opera/9.30 (Nintendo Wii; U; ; 3642; ja)
        // (DS) Mozilla/4.0 (compatible; MSIE 6.0; Nitro) Opera 8.5 [ja]
        // (DSi) Opera/9.50 (Nintendo DSi; Opera/507; U; ja)
        // (3DS) Mozilla/5.0 (Nintendo 3DS; U; ; ja) Version/1.7455.JP
        if (preg_match('/(?: Nitro|Nintendo DSi;)/', $ua) || UA::isNintendo3DS($ua)) {
            return true;
        }
        return false;
    }
    
    /**
     * UAがNintendo 3DSならtrueを返す。
     *
     * @static
     * @access  public
     * @param   string   $ua  UAを指定するなら
     * @return  boolean
     */
    function isNintendo3DS($ua = null)
    {
        if (is_null($ua) and isset($_SERVER['HTTP_USER_AGENT'])) {
            $ua = $_SERVER['HTTP_USER_AGENT'];
        }
        
        // ニンテンドーDSiブラウザーではローカルIPのクッキーを記憶したが、3DSでは記憶せず、クッキーエラーになるらしい。
        if (preg_match('/Nintendo 3DS;/', $ua)) {
            return true;
        }
        return false;
    }
    
    
    /**
     * UAがAndroid（でWebkit）ならtrueを返す。
     *
     * @static
     * @access  public
     * @param   string   $ua  UAを指定するなら
     * @return  boolean
     */
    function isAndroidWebKit($ua = null)
    {
        if (is_null($ua) and isset($_SERVER['HTTP_USER_AGENT'])) {
            $ua = $_SERVER['HTTP_USER_AGENT'];
        }
        if (!$ua) {
            return false;
        }
        // シミュレータ
        // Mozilla/5.0 (Linux; U; Android 1.0; en-us; generic) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2
        // T-mobile G1
        // Mozilla/5.0 (Linux; U; Android 1.0; en-us; dream) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2
        // genericとdreamが異なる
        if (false !== strpos($ua, 'Android') && false !== strpos($ua, 'WebKit')) {
            return true;
        }
        return false;
    }
    
    /**
     * UAがSafari系なら true を返す
     *
     * @static
     * @access  public
     * @param   string   $ua  UAを指定するなら
     * @return  boolean
     */
    function isSafariGroup($ua = null)
    {
        if (is_null($ua) and isset($_SERVER['HTTP_USER_AGENT'])) {
            $ua = $_SERVER['HTTP_USER_AGENT'];
        }
        
        return (boolean)preg_match('/Safari|AppleWebKit|Konqueror/', $ua);
    }

    /**
     * UAがWindows PhoneのIE Mobileなら true を返す
     *
     * @static
     * @access  public
     * @param   string   $ua  UAを指定するなら
     * @return  boolean
     */
    function isWindowsPhoneIEMobile($ua = null)
    {
        if (is_null($ua) and isset($_SERVER['HTTP_USER_AGENT'])) {
            $ua = $_SERVER['HTTP_USER_AGENT'];
        }
        
        if (false !== strpos($ua, 'Windows Phone OS') && false !== strpos($ua, 'IEMobile')) {
            return true;
        }
        return false;
    }
}

/*
 * Local Variables:
 * mode: php
 * coding: cp932
 * tab-width: 4
 * c-basic-offset: 4
 * indent-tabs-mode: nil
 * End:
 */
// vim: set syn=php fenc=cp932 ai et ts=4 sw=4 sts=4 fdm=marker:
