Файл: admin/sources/classes/useragents/userAgentFunctions.php
Строк: 658
<?php
/**
 * <pre>
 * Invision Power Services
 * IP.Board v3.3.3
 * Skin Functions
 * Last Updated: $Date: 2012-05-10 16:10:13 -0400 (Thu, 10 May 2012) $
 * </pre>
 *
 * Owner: Matt
 * @author         $Author: bfarber $
 * @copyright    (c) 2001 - 2009 Invision Power Services, Inc.
 * @license        http://www.invisionpower.com/company/standards.php#license
 * @package        IP.Board
 * @link        http://www.invisionpower.com
 * @since        9th March 2005 11:03
 * @version        $Revision: 10721 $
 *
 */
if ( ! defined( 'IN_IPB' ) )
{
    print "<h1>Incorrect access</h1>You cannot access this file directly. If you have recently upgraded, make sure you upgraded all the relevant files.";
    exit();
}
class userAgentFunctions
{
    /**#@+
     * Registry object
     *
     * @access    protected
     * @var        object
     */    
    protected $registry;
    protected $DB;
    protected $settings;
    protected $request;
    protected $lang;
    protected $member;
    protected $memberData;
    protected $cache;
    protected $caches;
    /**#@-*/
        
    /**
     * Error handle
     *
     * @access    protected
     * @var        array
     */
    protected $_errorMsgs = array();
    
    /**
     * Message handle
     *
     * @access    protected
     * @var        array
     */
    protected $_generalMsgs = array();
    
    /**
     * Constructor
     *
     * @access    public
     * @param    object        Registry object
     * @return    @e void
     */
    public function __construct( ipsRegistry $registry )
    {
        //-----------------------------------------
        // Make object
        //-----------------------------------------
        
        $this->registry   =  $registry;
        $this->DB          =  $this->registry->DB();
        $this->settings   =& $this->registry->fetchSettings();
        $this->request    =& $this->registry->fetchRequest();
        $this->member     =  $this->registry->member();
        $this->cache      =  $this->registry->cache();
    }
    
    /**
     * Reset error handle
     *
     * @access    protected
     * @return    @e void
     */
    final protected function _resetErrorHandle()
    {
        $this->_errorMsgs = array();
    }
    
    /**
     * Add an error message
     *
     * @access    protected
     * @param    string        Error message to add
     * @return    @e void
     */
    final protected function _addErrorMessage( $error )
    {
        $this->_errorMsgs[] = $error;
    }
    
    /**
     * Fetch error messages
     *
     * @access    public
     * @return    array    Array of messages or FALSE
     */
    public function fetchErrorMessages()
    {
        return ( count( $this->_errorMsgs ) ) ? $this->_errorMsgs : FALSE;
    }
    
    /**
     * Reset error handle
     *
     * @access    protected
     * @return    @e void
     */
    final protected function _resetMessageHandle()
    {
        $this->_generalMsgs = array();
    }
    
    /**
     * Add an error message
     *
     * @access    protected
     * @param    string        Error message to add
     * @return    @e void
     */
    final protected function _addMessage( $error )
    {
        $this->_generalMsgs[] = $error;
    }
    
    /**
     * Fetch error messages
     *
     * @access    public
     * @return    array    Array of messages or FALSE
     */
    public function fetchMessages()
    {
        return ( count( $this->_generalMsgs ) ) ? $this->_generalMsgs : FALSE;
    }
    
    /**
     * Returns the default mobile user agents for the mobile skin
     *
     */
    public function getMobileSkinUserAgents()
    {
        require( IPS_ROOT_PATH . 'extensions/userAgents.php' );/*noLibHook*/
        
        return ( is_array( $MOBILESKIN ) ) ? $MOBILESKIN : array();
    }
    
    /**
     * Rebuilds the master user agents
     *
     * @access    public
     * @return    bool    true
     */
    public function rebuildMasterUserAgents()
    {
        //-----------------------------------------
        // INIT
        //-----------------------------------------
        
        $userAgents = array();
        $names      = array();
        $count      = 0;
        
        //-----------------------------------------
        // Get file...
        //-----------------------------------------
        $BROWSERS = array();
        $ENGINES  = array();
        require_once( IPS_ROOT_PATH . 'extensions/userAgents.php' );/*noLibHook*/
        
        //-----------------------------------------
        // Build names
        //-----------------------------------------
        
        if ( is_array($BROWSERS) && count($BROWSERS) )
        {
            foreach( $BROWSERS as $key => $data )
            {
                $names[ $key ] = "'" . $key . "'";
            }
        }
        
        if ( is_array($ENGINES) && count($ENGINES) )
        {
            foreach( $ENGINES as $key => $data )
            {
                $names[ $key ] = "'" . $key . "'";
            }
        }
        
        //-----------------------------------------
        // Delete old 'uns
        //-----------------------------------------
        
        $doNotReplace = array();
        $this->DB->build( array( 'select' => '*', 'from' => 'core_uagents', 'where' => 'uagent_regex<>uagent_default_regex' ) );
        $e = $this->DB->execute();
        while ( $row = $this->DB->fetch( $e ) )
        {
            unset( $names[ $row['uagent_key'] ] );
            
            if ( $row['uagent_type'] == 'search' )
            {
                foreach ( $ENGINES[ $row['uagent_key'] ]['b_regex'] as $k => $v )
                {
                    $this->DB->update( 'core_uagents', array( 'uagent_default_regex' => $k ), "uagent_id={$row['uagent_id']}" );
                }
                
                unset( $ENGINES[ $row['uagent_key'] ] );
            }
            elseif ( $row['uagent_type'] == 'browser' )
            {
                foreach ( $BROWSERS[ $row['uagent_key'] ]['b_regex'] as $k => $v )
                {
                    $this->DB->update( 'core_uagents', array( 'uagent_default_regex' => $k ), "uagent_id={$row['uagent_id']}" );
                }
                
                unset( $BROWSERS[ $row['uagent_key'] ] );
            }
        }
        
        $this->DB->delete( 'core_uagents', 'uagent_key IN (' . implode( ",", $names ) . ")" );
        
        //-----------------------------------------
        // Add new 'uns
        //-----------------------------------------
        
        foreach( $ENGINES as $key => $data )
        {
            foreach( $data['b_regex'] as $k => $d )
            {
                $_regex   = $k;
                $_capture = $d;
            }
            
            $this->DB->insert( 'core_uagents', array( 'uagent_name'          => $data['b_title'],
                                                         'uagent_key'            => $key,
                                                         'uagent_regex'         => $_regex,
                                                         'uagent_default_regex'    => $_regex,
                                                         'uagent_regex_capture' => intval( $_capture ),
                                                         'uagent_position'      => $count,
                                                         'uagent_type'          => 'search' ) );
                                                        
            $count++;
        }
        
        /* Reset count */
        $count = 1000;
        
        foreach( $BROWSERS as $key => $data )
        {
            foreach( $data['b_regex'] as $k => $d )
            {
                $_regex   = $k;
                $_capture = $d;
            }
            
            if ( $data['b_position'] )
            {
                $count = $data['b_position'];
            }
            
            $this->DB->insert( 'core_uagents', array( 'uagent_name'          => $data['b_title'],
                                                         'uagent_key'            => $key,
                                                         'uagent_regex'         => $_regex,
                                                         'uagent_regex_capture' => intval( $_capture ),
                                                         'uagent_position'      => $count,
                                                         'uagent_type'          => 'browser' ) );
            $count++;
        }
        
        $this->rebuildUserAgentCaches();
        
        return TRUE;
    }
    
    /**
     * Saves a user agent group
     *
     * @access    public
     * @param    string         Group Title
     * @param    array         Array of raw useragent data (array( key => array( 'uagent_id', ..etc ) )
     * @param    int            [Optional: Group ID. If passed, we update, if not, we add]
     * @return    int         User group id
     */
    public function saveUserAgentGroup( $ugroup_title, $ugroupData, $ugroup_id=0 )
    {
        //-----------------------------------------
        // INIT
        //-----------------------------------------
        
        $data = array();
        
        //-----------------------------------------
        // Fix up data
        //-----------------------------------------
        
        if ( is_array( $ugroupData ) )
        {
            foreach( $ugroupData as $key => $array )
            {
                $data[ $key ] = array( 'uagent_id'       => $array['uagent_id'],
                                       'uagent_key'      => $array['uagent_key'],
                                       'uagent_type'     => $array['uagent_type'],
                                       'uagent_versions' => $array['uagent_versions'] );
            }
        }
        
        //-----------------------------------------
        // Updating or what?
        //-----------------------------------------
        
        if ( $ugroup_id )
        {
            $this->DB->update( 'core_uagent_groups', array( 'ugroup_title' => $ugroup_title,
                                                               'ugroup_array' => serialize( $data ) ), 'ugroup_id=' . $ugroup_id );
        }
        else
        {
            $this->DB->insert( 'core_uagent_groups', array( 'ugroup_title' => $ugroup_title,
                                                               'ugroup_array' => serialize( $data ) ) );
                                                            
            $ugroup_id = $this->DB->getInsertId();
        }
        
        $this->rebuildUserAgentGroupCaches();
        
        return $ugroup_id;
    }
    
    /**
     * Fetch all agent groups
     *
     * @access    public
     * @return    array         Array of data
     */
    public function fetchGroups()
    {
        //-----------------------------------------
        // Try and get the skin from the cache
        //-----------------------------------------
        
        $userAgentGroups = array();
        
        //-----------------------------------------
        // Get em!!
        //-----------------------------------------
        
        $this->DB->build( array( 'select' => '*',
                                       'from'   => 'core_uagent_groups',
                                       'order'  => 'ugroup_title ASC'
                              )      );
                            
        $this->DB->execute();
    
        while( $row = $this->DB->fetch() )
        {
            /* Unpack data */
            $row['_groupArray'] = ( $row['ugroup_array'] ) ? unserialize( $row['ugroup_array'] ) : $row['_groupArray'];
            $row['_arrayCount'] = count( $row['_groupArray'] );
            
            $userAgentGroups[ $row['ugroup_id'] ] = $row;
        }
        
        
        return $userAgentGroups;
    }
    
    /**
     * Fetch agents from the DB
     *
     * @access    public
     * @param    int            [Optional: Group ID of agents to return]
     * @return    array         Array of agents
     */
    public function fetchAgents( $groupID=0 )
    {
        //-----------------------------------------
        // INIT
        //-----------------------------------------
        
        $userAgents = array();
        
        //-----------------------------------------
        // Get em!!
        //-----------------------------------------
        
        if ( ! $groupID )
        {
            $this->DB->build( array( 'select' => '*',
                                     'from'   => 'core_uagents',
                                     'order'  => 'uagent_position ASC, uagent_key ASC'
                                  )      );
                                
            $this->DB->execute();
        
            while( $row = $this->DB->fetch() )
            {
                $userAgents[ $row['uagent_id'] ] = $row;
            }
        }
        else
        {
            $uGroup = $this->DB->buildAndFetch( array( 'select' => '*',
                                                       'from'   => 'core_uagent_groups',
                                                       'where'  => 'ugroup_id=' . intval( $groupID ) ) );
            
            $userAgents = ( $uGroup['ugroup_array'] ) ? unserialize( $uGroup['ugroup_array'] ) : array();
        }
        
        return $userAgents;
    }
    
    /**
     * Recaches the user-agents where-ever it needs recaching!
     *
     * @access    public
     * @return    @e void
     */
    public function rebuildUserAgentCaches()
    {
        //-----------------------------------------
        // INIT
        //-----------------------------------------
        
        $cache = array();
        
        //-----------------------------------------
        // Get rows...
        //-----------------------------------------
        
        $this->DB->build( array( 'select' => '*',
                                       'from'   => 'core_uagents',
                                       'order'  => 'uagent_position ASC, uagent_key ASC'
                              )      );
                            
        $this->DB->execute();
    
        while( $row = $this->DB->fetch() )
        {
            $cache[ $row['uagent_key'] ] = $row;
        }
        
        $this->cache->setCache( 'useragents', $cache, array( 'array' => 1 ) );
        
        //-----------------------------------------
        // Now rebuild groups
        //-----------------------------------------
        
        $this->rebuildUserAgentGroupCaches();
    }
    
    /**
     * Recaches the user-agents where-ever it needs recaching!
     *
     * @access    public
     * @return    @e void
     */
    public function rebuildUserAgentGroupCaches()
    {
        //-----------------------------------------
        // INIT
        //-----------------------------------------
        
        $cache = array();
        
        //-----------------------------------------
        // Get rows...
        //-----------------------------------------
        
        $this->DB->build( array( 'select' => '*',
                                       'from'   => 'core_uagent_groups',
                                       'order'  => 'ugroup_id ASC'
                              )      );
                            
        $this->DB->execute();
    
        while( $row = $this->DB->fetch() )
        {
            $cache[ $row['ugroup_id'] ] = $row;
        }
        
        $this->cache->setCache( 'useragentgroups', $cache, array( 'array' => 1 ) );
        
        //-----------------------------------------
        // Rebuild Skin Map
        //-----------------------------------------
        
        $this->rebuildUserAgentSkinMap();
    }
    
    /**
     * Recaches user agent to skin set map
     * NOT CURRENTLY USED
     *
     * @access    public
     * @return    @e void
     */
    public function rebuildUserAgentSkinMap()
    {
        
    }
    
    /**
     * Removes a user agent group
     *
     * @access    public
     * @param    int        UA Group ID
     * @return    @e void
     */
    public function removeUserAgentGroup( $ugroup_id )
    {
        //-----------------------------------------
        // Remove it
        //-----------------------------------------
        
        $this->DB->delete( 'core_uagent_groups', 'ugroup_id=' . intval( $ugroup_id ) );
        
        //-----------------------------------------
        // Recache
        //-----------------------------------------
        
        $this->rebuildUserAgentGroupCaches();
    }
    
    /**
     * Save user agents after edit
     *
     * @access    public
     * @param    int            User Agent ID
     * @param    string        User Agent "Key"
     * @param    string        User Agent Name (Human title)
     * @param    string        User Agent Regex
     * @param    int            User Agent Regex Capture parenthesis #
     * @param    string        User Agent Type (browser, search engine, other)
     * @param    int            User Agent Position
     * @return    array         ..of data
     * <code>
     * Exception Codes:
     * NO_SUCH_UAGENT:        Could not locate user agent
     * UAGENT_EXISTS:         Could not rename user agent key
     * MISSING_DATA:        Fields are missing
     * REGEX_INCORRECT:     The regex is incorrect
     * </code>
     */
    public function saveUserAgentFromEdit( $uagent_id, $uagent_key, $uagent_name, $uagent_regex, $uagent_regex_capture, $uagent_type, $uagent_position )
    {
        //-----------------------------------------
        // INIT
        //-----------------------------------------
        
        $uagent_id                = intval( $uagent_id );
        $uagent_key                = strtolower( IPSText::alphanumericalClean( $uagent_key ) );
        $uagent_name            = trim( $uagent_name );
        $uagent_regex            = trim( $uagent_regex );
        $uagent_regex_capture    = intval( $uagent_regex_capture );
        $uagent_type            = IPSText::alphanumericalClean( $uagent_type );
        $uagent_position        = intval( $uagent_position );
        
        if ( ! $uagent_id OR ! $uagent_key OR ! $uagent_name OR ! $uagent_regex OR ! $uagent_type )
        {
            throw new Exception( 'MISSING_DATA' );
        }
    
        //-----------------------------------------
        // Fetch user agent data
        //-----------------------------------------
        
        $useragent = $this->DB->buildAndFetch( array( 'select' => '*',
                                                                'from'   => 'core_uagents',
                                                                'where'  => 'uagent_id=' . $uagent_id ) );
                                                            
        if ( ! $useragent['uagent_id'] )
        {
            throw new Exception( 'NO_SUCH_UAGENT' );
        }
        
        //-----------------------------------------
        // Did we change the key?
        //-----------------------------------------
        
        if ( $useragent['uagent_key'] != $uagent_key )
        {
            $useragentTest = $this->DB->buildAndFetch( array( 'select' => '*',
                                                                        'from'   => 'core_uagents',
                                                                     'where'  => 'uagent_key='' . $uagent_key . ''' ) );
                                                        
            if ( $useragentTest['uagent_id'] )
            {
                throw new Exception( "UAGENT_EXISTS" );
            }
        }
        
        //-----------------------------------------
        // Test syntax
        //-----------------------------------------
        
        if ( $this->testRegex( $uagent_regex ) !== TRUE )
        {
            throw new Exception( "REGEX_INCORRECT" );
        }
        
        //-----------------------------------------
        // Update
        //-----------------------------------------
        
        $this->DB->update( 'core_uagents', array( 'uagent_key'           => $uagent_key,
                                                     'uagent_name'          => $uagent_name,
                                                     'uagent_regex'         => $uagent_regex,
                                                     'uagent_regex_capture' => $uagent_regex_capture,
                                                     'uagent_position'        => $uagent_position,
                                                     'uagent_type'            => $uagent_type ), 'uagent_id=' . $uagent_id );
                                                        
        //-----------------------------------------
        // Recache
        //-----------------------------------------
        
        $this->rebuildUserAgentCaches();
        
        //-----------------------------------------
        // Return
        //-----------------------------------------
        
        return $uagent_id;
    }
    
    /**
     * Save replacement after add
     *
     * @access    public
     * @param    string        User Agent "Key"
     * @param    string        User Agent Name (Human title)
     * @param    string        User Agent Regex
     * @param    int            User Agent Regex Capture parenthesis #
     * @param    string        User Agent Type (browser, search engine, other)
     * @param    int            User Agent Position
     * @return    array         ..of data
     * <code>
     * Exception Codes:
     * UAGENT_EXISTS:         Could not rename user agent key
     * MISSING_DATA:        Fields are missing
     * </code>
     */
    public function saveUserAgentFromAdd( $uagent_key, $uagent_name, $uagent_regex, $uagent_regex_capture, $uagent_type, $uagent_position )
    {
        //-----------------------------------------
        // INIT
        //-----------------------------------------
        
        $uagent_key                = strtolower( IPSText::alphanumericalClean( $uagent_key ) );
        $uagent_name            = trim($uagent_name);
        $uagent_regex            = trim($uagent_regex);
        $uagent_regex_capture    = intval( $uagent_regex_capture );
        $uagent_type            = IPSText::alphanumericalClean( $uagent_type );
        $uagent_position        = intval( $uagent_position );
        
        if ( ! $uagent_key OR ! $uagent_name OR ! $uagent_regex OR ! $uagent_type )
        {
            throw new Exception( 'MISSING_DATA' );
        }
    
        //-----------------------------------------
        // Check for an existing user agent
        //-----------------------------------------
        
        $useragentTest = $this->DB->buildAndFetch( array( 'select' => '*',
                                                                    'from'   => 'core_uagents',
                                                                 'where'  => 'uagent_key='' . $uagent_key . ''' ) );
                                                    
        if ( $useragentTest['uagent_id'] )
        {
            throw new Exception( "UAGENT_EXISTS" );
        }
        
        
        //-----------------------------------------
        // Update
        //-----------------------------------------
        
        $this->DB->insert( 'core_uagents', array( 'uagent_key'           => $uagent_key,
                                                     'uagent_name'          => $uagent_name,
                                                     'uagent_regex'         => $uagent_regex,
                                                     'uagent_regex_capture' => $uagent_regex_capture,
                                                     'uagent_position'        => $uagent_position,
                                                     'uagent_type'            => $uagent_type ) );
        
        $uagent_id = $this->DB->getInsertId();
        
        //-----------------------------------------
        // Recache
        //-----------------------------------------
        
        $this->rebuildUserAgentCaches();
        
        //-----------------------------------------
        // Return
        //-----------------------------------------
        
        return $uagent_id;
    }
    
    /**
     * Reverts / Removes Replacement
     *
     * @access    public
     * @param    int            User Agent ID
     * @return    array         All user agents for this skin set
     * <code>
     * Exception Codes:
     * NO_SUCH_UAGENT:        Could not locate user agent
     * </code>
     */
    public function removeUserAgent( $uagent_id )
    {
        //-----------------------------------------
        // INIT
        //-----------------------------------------
        $uagent_id = intval( $uagent_id );
        //-----------------------------------------
        // Fetch replacement data
        //-----------------------------------------
        
        $useragentTest = $this->DB->buildAndFetch( array( 'select' => '*',
                                                                    'from'   => 'core_uagents',
                                                                 'where'  => 'uagent_id=' . $uagent_id ) );
                                                    
        if ( ! $useragentTest['uagent_id'] )
        {
            throw new Exception( "NO_SUCH_UAGENT" );
        }
        
        //-----------------------------------------
        // Remove it...
        //-----------------------------------------
        
        $this->DB->delete( 'core_uagents', 'uagent_id=' . $uagent_id );
        
        //-----------------------------------------
        // Recache
        //-----------------------------------------
        
        $this->rebuildUserAgentCaches();
        
        //-----------------------------------------
        // Grab the adjusted user agents
        //-----------------------------------------
        
        $useragents = $this->fetchAgents();
        
        //-----------------------------------------
        // Reeee-turn
        //-----------------------------------------
        
        return $useragents;
    }
    
    /**
     * Test the user's user-agent for a match in the database
     *
     * @access        public
     * @param        string        [Optional: user agent raw string]
     * @return        array         array[ 'uagent_id' => int, 'uagent_key' => string, 'uagent_name' => string, 'uagent_version' => int ]
     */
    public function findUserAgentID( $userAgent='' )
    {
        //-----------------------------------------
        // INIT
        //-----------------------------------------
        
        $userAgent    = ( $userAgent ) ? $userAgent : $this->member->user_agent;
        $uagentReturn = array( 'uagent_id'      => 0,
                                'uagent_key'     => NULL,
                               'uagent_name'    => NULL,
                               'uagent_type'    => NULL,
                               'uagent_version' => 0 );
        /* Hardcoded to prevent admin tampering - legacy app is selected in publicSessions */
        if ( stristr( $userAgent, 'ip.ios' ) )
        {
            preg_match( '#^ip.ioss+?v([d.]+?),#i', $userAgent, $matches );
            
            if ( $matches[0] )
            {
                return array(  'uagent_id'      => -1,
                                'uagent_key'     => 'ipsMobileApple',
                               'uagent_name'    => 'IPS Mobile Apple',
                               'uagent_type'    => 'mobileApp',
                               'uagent_version' => intval( $matches[1] ) );
            }
        }
        else if ( stristr( $userAgent, 'ip.android' ) )
        {
            preg_match( '#^ip.androids+?v([d.]+?),#i', $userAgent, $matches );
            
            if ( $matches[0] )
            {
                return array(  'uagent_id'      => -1,
                                'uagent_key'     => 'ipsMobileAndroid',
                               'uagent_name'    => 'IPS Mobile Android',
                               'uagent_type'    => 'mobileApp',
                               'uagent_version' => intval( $matches[1] ) );
            }
        }
        
        //-----------------------------------------
        // Test in the DB
        //-----------------------------------------
        $userAgentCache = $this->cache->getCache('useragents');
        foreach( $userAgentCache as $key => $data )
        {
            $regex = str_replace( '#', '\#', $data['uagent_regex'] );
            if ( ! preg_match( "#{$regex}#i", $userAgent, $matches ) )
            {
                continue;
            }
            else
            {
                //-----------------------------------------
                // Okay, we got a match - finalize
                //-----------------------------------------
                
                if ( $data['uagent_regex_capture'] )
                {
                     $version = $matches[ $data['uagent_regex_capture'] ];
                }
                else
                {
                    $version = 0;
                }
                
                $uagentReturn = array( 'uagent_id'      => $data['uagent_id'],
                                       'uagent_key'     => $data['uagent_key'],
                                       'uagent_name'    => $data['uagent_name'],
                                       'uagent_type'    => $data['uagent_type'],
                                       'uagent_version' => intval( $version ) );
                                    
                break;
            }
        }
        
        return $uagentReturn;
    }
            
    /**
     * Test regex for errors
     *
     * @access        public
     * @param        string        Regex
     * @return        boolean        (True is OK)
     */
    public function testRegex( $regex )
    {
        //-----------------------------------------
        // INIT
        //-----------------------------------------
        
        $return = '';
        $regex  = str_replace( '#', '\#', $regex );
        $this->_resetMessageHandle();
        
        //-----------------------------------------
        // Test...
        //-----------------------------------------
        
        ob_start();
        eval( "preg_match( '#" . $regex . "#', 'this is just a test' );" );
        $return = ob_get_contents();
        ob_end_clean();
        
        //-----------------------------------------
        // More data...
        //-----------------------------------------
        
        $this->_addMessage( $return );
    
        //-----------------------------------------
        // Return
        //-----------------------------------------
        
        return $return ? FALSE : TRUE;
    }
}