PageRenderTime 173ms CodeModel.GetById 54ms app.highlight 74ms RepoModel.GetById 32ms app.codeStats 1ms

/lib/Zend/Http/UserAgent/AbstractDevice.php

https://bitbucket.org/claudiu_marginean/magento-hg-mirror
PHP | 974 lines | 578 code | 94 blank | 302 comment | 141 complexity | 6b900aeab41e3f6c4226181fd747fea8 MD5 | raw file
  1<?php
  2/**
  3 * Zend Framework
  4 *
  5 * LICENSE
  6 *
  7 * This source file is subject to the new BSD license that is bundled
  8 * with this package in the file LICENSE.txt.
  9 * It is also available through the world-wide-web at this URL:
 10 * http://framework.zend.com/license/new-bsd
 11 * If you did not receive a copy of the license and are unable to
 12 * obtain it through the world-wide-web, please send an email
 13 * to license@zend.com so we can send you a copy immediately.
 14 *
 15 * @category   Zend
 16 * @package    Zend_Http
 17 * @subpackage UserAgent
 18 * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
 19 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 20 */
 21
 22#require_once 'Zend/Http/UserAgent/Device.php';
 23
 24/**
 25 * Abstract Class to define a browser device.
 26 *
 27 * @category   Zend
 28 * @package    Zend_Http
 29 * @subpackage UserAgent
 30 * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
 31 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 32 */
 33abstract class Zend_Http_UserAgent_AbstractDevice
 34    implements Zend_Http_UserAgent_Device
 35{
 36    /**
 37     * Browser signature
 38     *
 39     * @var string
 40     */
 41    protected $_browser = '';
 42
 43    /**
 44     * Browser version
 45     *
 46     * @var string
 47     */
 48    protected $_browserVersion = '';
 49
 50    /**
 51     * Configuration
 52     * 
 53     * @var array
 54     */
 55    protected $_config;
 56
 57    /**
 58     * User Agent chain
 59     *
 60     * @var string
 61     */
 62    protected $_userAgent;
 63
 64    /**
 65     * Server variable
 66     * 
 67     * @var array
 68     */
 69    protected $_server;
 70
 71    /**
 72     * Image types
 73     * 
 74     * @var array
 75     */
 76    protected $_images = array(
 77        'jpeg', 
 78        'gif', 
 79        'png', 
 80        'pjpeg', 
 81        'x-png', 
 82        'bmp',
 83    );
 84
 85    /**
 86     * Browser/Device features
 87     *
 88     * @var array
 89     */
 90    protected $_aFeatures = array();
 91
 92    /**
 93     * Browser/Device features groups
 94     *
 95     * @var array
 96     */
 97    protected $_aGroup = array();
 98
 99    /**
100     * Constructor
101     *
102     * @param  null|string|array $userAgent If array, restores from serialized version
103     * @param  array $server 
104     * @param  array $config 
105     * @return void
106     */
107    public function __construct($userAgent = null, array $server = array(), array $config = array())
108    {
109        if (is_array($userAgent)) {
110            // Restoring from serialized array
111            $this->_restoreFromArray($userAgent);
112        } else {
113            // Constructing new object
114            $this->setUserAgent($userAgent);
115            $this->_server    = $server;
116            $this->_config    = $config;
117            $this->_getDefaultFeatures();
118            $this->_defineFeatures();
119        }
120    }
121
122    /**
123     * Serialize object
124     * 
125     * @return string
126     */
127    public function serialize()
128    {
129        $spec = array(
130            '_aFeatures'      => $this->_aFeatures,
131            '_aGroup'         => $this->_aGroup,
132            '_browser'        => $this->_browser,
133            '_browserVersion' => $this->_browserVersion,
134            '_userAgent'      => $this->_userAgent,
135            '_images'         => $this->_images,
136        );
137        return serialize($spec);
138    }
139
140    /**
141     * Unserialize
142     * 
143     * @param  string $serialized 
144     * @return void
145     */
146    public function unserialize($serialized)
147    {
148        $spec = unserialize($serialized);
149        $this->_restoreFromArray($spec);
150    }
151
152    /**
153     * Restore object state from array
154     * 
155     * @param  array $spec 
156     * @return void
157     */
158    protected function _restoreFromArray(array $spec)
159    {
160        foreach ($spec as $key => $value) {
161            if (property_exists($this, $key)) {
162                $this->{$key} = $value;
163            }
164        }
165    }
166
167    /**
168     * Look for features
169     *
170     * @return array|null
171     */
172    protected function _defineFeatures()
173    {
174        $features = $this->_loadFeaturesAdapter();
175
176        if (is_array($features)) {
177            $this->_aFeatures = array_merge($this->_aFeatures, $features);
178        }
179        
180        return $this->_aFeatures;
181    }
182
183    /**
184     * Gets the browser type identifier
185     *
186     * @return string
187     */
188    abstract public function getType();
189
190    /**
191     * Check a feature for the current browser/device.
192     *
193     * @param  string $feature The feature to check.
194     * @return bool
195     */
196    public function hasFeature($feature)
197    {
198        return (!empty($this->_aFeatures[$feature]));
199    }
200
201    /**
202     * Gets the value of the current browser/device feature
203     *
204     * @param  string $feature Feature to search
205     * @return string|null
206     */
207    public function getFeature($feature)
208    {
209        if ($this->hasFeature($feature)) {
210            return $this->_aFeatures[$feature];
211        }
212    }
213
214    /**
215     * Set a feature for the current browser/device.
216     *
217     * @param  string $feature The feature to set.
218     * @param  string $value (option) feature value.
219     * @param  string $group (option) Group to associate with the feature
220     * @return Zend_Http_UserAgent_AbstractDevice
221     */
222    public function setFeature($feature, $value = false, $group = '')
223    {
224        $this->_aFeatures[$feature] = $value;
225        if (!empty($group)) {
226            $this->setGroup($group, $feature);
227        }
228        return $this;
229    }
230
231    /**
232     * Affects a feature to a group
233     *
234     * @param  string $group Group name
235     * @param  string $feature Feature name
236     * @return Zend_Http_UserAgent_AbstractDevice
237     */
238    public function setGroup($group, $feature)
239    {
240        if (!isset($this->_aGroup[$group])) {
241            $this->_aGroup[$group] = array();
242        }
243        if (!in_array($feature, $this->_aGroup[$group])) {
244            $this->_aGroup[$group][] = $feature;
245        }
246        return $this;
247    }
248
249    /**
250     * Gets an array of features associated to a group
251     *
252     * @param  string $group Group param
253     * @return array
254     */
255    public function getGroup($group)
256    {
257        return $this->_aGroup[$group];
258    }
259
260    /**
261     * Gets all the browser/device features
262     *
263     * @return array
264     */
265    public function getAllFeatures()
266    {
267        return $this->_aFeatures;
268    }
269
270    /**
271     * Gets all the browser/device features' groups
272     *
273     * @return array
274     */
275    public function getAllGroups()
276    {
277        return $this->_aGroup;
278    }
279
280    /**
281     * Sets all the standard features extracted from the User Agent chain and $this->_server
282     * vars
283     *
284     * @return void
285     */
286    protected function _getDefaultFeatures()
287    {
288        $server = array();
289        
290        // gets info from user agent chain 
291        $uaExtract = $this->extractFromUserAgent($this->getUserAgent());
292        
293        if (is_array($uaExtract)) {
294            foreach ($uaExtract as $key => $info) {
295                $this->setFeature($key, $info, 'product_info');
296            }
297        }
298        
299        if (isset($uaExtract['browser_name'])) {
300            $this->_browser = $uaExtract['browser_name'];
301        }
302        if (isset($uaExtract['browser_version'])) {
303            $this->_browserVersion = $uaExtract['browser_version'];
304        }
305        if (isset($uaExtract['device_os'])) {
306            $this->device_os = $uaExtract['device_os_name'];
307        }
308        
309        /* browser & device info */
310        $this->setFeature('is_wireless_device', false, 'product_info');
311        $this->setFeature('is_mobile', false, 'product_info');
312        $this->setFeature('is_desktop', false, 'product_info');
313        $this->setFeature('is_tablet', false, 'product_info');
314        $this->setFeature('is_bot', false, 'product_info');
315        $this->setFeature('is_email', false, 'product_info');
316        $this->setFeature('is_text', false, 'product_info');
317        $this->setFeature('device_claims_web_support', false, 'product_info');
318        
319        $this->setFeature('is_' . strtolower($this->getType()), true, 'product_info');
320        
321        /* sets the browser name */
322        if (isset($this->list) && empty($this->_browser)) {
323            $lowerUserAgent = strtolower($this->getUserAgent());
324            foreach ($this->list as $browser_signature) {
325                if (strpos($lowerUserAgent, $browser_signature) !== false) {
326                    $this->_browser = strtolower($browser_signature);
327                    $this->setFeature('browser_name', $this->_browser, 'product_info');
328                }
329            }
330        }
331        
332        /* sets the client IP */
333        if (isset($this->_server['remote_addr'])) {
334            $this->setFeature('client_ip', $this->_server['remote_addr'], 'product_info');
335        } elseif (isset($this->_server['http_x_forwarded_for'])) {
336            $this->setFeature('client_ip', $this->_server['http_x_forwarded_for'], 'product_info');
337        } elseif (isset($this->_server['http_client_ip'])) {
338            $this->setFeature('client_ip', $this->_server['http_client_ip'], 'product_info');
339        }
340        
341        /* sets the server infos */
342        if (isset($this->_server['server_software'])) {
343            if (strpos($this->_server['server_software'], 'Apache') !== false || strpos($this->_server['server_software'], 'LiteSpeed') !== false) {
344                $server['version'] = 1;
345                if (strpos($this->_server['server_software'], 'Apache/2') !== false) {
346                    $server['version'] = 2;
347                }
348                $server['server'] = 'apache';
349            }
350            
351            if (strpos($this->_server['server_software'], 'Microsoft-IIS') !== false) {
352                $server['server'] = 'iis';
353            }
354            
355            if (strpos($this->_server['server_software'], 'Unix') !== false) {
356                $server['os'] = 'unix';
357                if (isset($_ENV['MACHTYPE'])) {
358                    if (strpos($_ENV['MACHTYPE'], 'linux') !== false) {
359                        $server['os'] = 'linux';
360                    }
361                }
362            } elseif (strpos($this->_server['server_software'], 'Win') !== false) {
363                $server['os'] = 'windows';
364            }
365            
366            if (preg_match('/Apache\/([0-9\.]*)/', $this->_server['server_software'], $arr)) {
367                if ($arr[1]) {
368                    $server['version'] = $arr[1];
369                    $server['server']  = 'apache';
370                }
371            }
372        }
373        
374        $this->setFeature('php_version', phpversion(), 'server_info');
375        if (isset($server['server'])) {
376            $this->setFeature('server_os', $server['server'], 'server_info');
377        }
378        if (isset($server['version'])) {
379            $this->setFeature('server_os_version', $server['version'], 'server_info');
380        }
381        if (isset($this->_server['http_accept'])) {
382            $this->setFeature('server_http_accept', $this->_server['http_accept'], 'server_info');
383        }
384        if (isset($this->_server['http_accept_language'])) {
385            $this->setFeature('server_http_accept_language', $this->_server['http_accept_language'], 'server_info');
386        }
387        if (isset($this->_server['server_addr'])) {
388            $this->setFeature('server_ip', $this->_server['server_addr'], 'server_info');
389        }
390        if (isset($this->_server['server_name'])) {
391            $this->setFeature('server_name', $this->_server['server_name'], 'server_info');
392        }
393    }
394
395    /**
396     * Extract and sets informations from the User Agent chain
397     *
398     * @param  string $userAgent User Agent chain
399     * @return array
400     */
401    public static function extractFromUserAgent($userAgent)
402    {
403        $userAgent = trim($userAgent);
404        
405        /**
406         * @see http://www.texsoft.it/index.php?c=software&m=sw.php.useragent&l=it
407         */
408        $pattern =  "(([^/\s]*)(/(\S*))?)(\s*\[[a-zA-Z][a-zA-Z]\])?\s*(\\((([^()]|(\\([^()]*\\)))*)\\))?\s*";
409        preg_match("#^$pattern#", $userAgent, $match);
410
411        $comment = array();
412        if (isset($match[7])) {
413            $comment = explode(';', $match[7]);
414        }
415        
416        // second part if exists
417        $end = substr($userAgent, strlen($match[0]));
418        if (!empty($end)) {
419            $result['others']['full'] = $end;
420        }
421        
422        $match2 = array();
423        if (isset($result['others'])) {
424            preg_match_all('/(([^\/\s]*)(\/)?([^\/\(\)\s]*)?)(\s\((([^\)]*)*)\))?/i', $result['others']['full'], $match2);
425        }
426        $result['user_agent']   = trim($match[1]);
427        $result['product_name'] = isset($match[2]) ? trim($match[2]) : '';
428        $result['browser_name'] = $result['product_name'];
429        if (isset($match[4]) && trim($match[4])) {
430            $result['product_version'] = trim($match[4]);
431            $result['browser_version'] = trim($match[4]);
432        }
433        if (count($comment) && !empty($comment[0])) {
434            $result['comment']['full']     = trim($match[7]);
435            $result['comment']['detail']   = $comment;
436            $result['compatibility_flag']  = trim($comment[0]);
437            if (isset($comment[1])) {
438                $result['browser_token']   = trim($comment[1]);
439            }
440            if (isset($comment[2])) {
441                $result['device_os_token'] = trim($comment[2]);
442            }
443        }
444        if (empty($result['device_os_token']) && !empty($result['compatibility_flag'])) {
445            // some browsers do not have a platform token
446            $result['device_os_token'] = $result['compatibility_flag'];
447        }
448        if ($match2) {
449            $i = 0;
450            $max = count($match2[0]);
451            for ($i = 0; $i < $max; $i ++) {
452                if (!empty($match2[0][$i])) {
453                    $result['others']['detail'][] = array(
454                        $match2[0][$i], 
455                        $match2[2][$i], 
456                        $match2[4][$i],
457                    );
458                }
459            }
460        }
461        
462        /** Security level */
463        $security = array(
464            'N' => 'no security', 
465            'U' => 'strong security', 
466            'I' => 'weak security',
467        );
468        if (!empty($result['browser_token'])) {
469            if (isset($security[$result['browser_token']])) {
470                $result['security_level'] = $security[$result['browser_token']];
471                unset($result['browser_token']);
472            }
473        }
474        
475        $product = strtolower($result['browser_name']);
476        
477        // Mozilla : true && false
478        $compatibleOrIe = false;
479        if (isset($result['compatibility_flag']) && isset($result['comment'])) {
480            $compatibleOrIe = ($result['compatibility_flag'] == 'compatible' || strpos($result['comment']['full'], "MSIE") !== false);
481        }
482        if ($product == 'mozilla' && $compatibleOrIe) {
483            if (!empty($result['browser_token'])) {
484                // Classic Mozilla chain
485                preg_match_all('/([^\/\s].*)(\/|\s)(.*)/i', $result['browser_token'], $real);
486            } else {
487                // MSIE specific chain with 'Windows' compatibility flag
488                foreach ($result['comment']['detail'] as $v) {
489                    if (strpos($v, 'MSIE') !== false) {
490                        $real[0][1]               = trim($v);
491                        $result['browser_engine'] = "MSIE";
492                        $real[1][0]               = "Internet Explorer";
493                        $temp                     = explode(' ', trim($v));
494                        $real[3][0]               = $temp[1];
495                    
496                    }
497                    if (strpos($v, 'Win') !== false) {
498                        $result['device_os_token'] = trim($v);
499                    }
500                }
501            }
502            
503            if (!empty($real[0])) {
504                $result['browser_name']    = $real[1][0];
505                $result['browser_version'] = $real[3][0];
506            } else {
507                $result['browser_name']    = $result['browser_token'];
508                $result['browser_version'] = '??';
509            }
510        } elseif ($product == 'mozilla' && $result['browser_version'] < 5.0) {
511            // handles the real Mozilla (or old Netscape if version < 5.0)
512            $result['browser_name'] = 'Netscape';
513        }
514        
515        /** windows */
516        if ($result['browser_name'] == 'MSIE') {
517            $result['browser_engine'] = 'MSIE';
518            $result['browser_name']   = 'Internet Explorer';
519        }
520        if (isset($result['device_os_token'])) {
521            if (strpos($result['device_os_token'], 'Win') !== false) {
522                
523                $windows = array(
524                    'Windows NT 6.1'          => 'Windows 7', 
525                    'Windows NT 6.0'          => 'Windows Vista', 
526                    'Windows NT 5.2'          => 'Windows Server 2003', 
527                    'Windows NT 5.1'          => 'Windows XP', 
528                    'Windows NT 5.01'         => 'Windows 2000 SP1', 
529                    'Windows NT 5.0'          => 'Windows 2000', 
530                    'Windows NT 4.0'          => 'Microsoft Windows NT 4.0', 
531                    'WinNT'                   => 'Microsoft Windows NT 4.0', 
532                    'Windows 98; Win 9x 4.90' => 'Windows Me', 
533                    'Windows 98'              => 'Windows 98', 
534                    'Win98'                   => 'Windows 98', 
535                    'Windows 95'              => 'Windows 95', 
536                    'Win95'                   => 'Windows 95', 
537                    'Windows CE'              => 'Windows CE',
538                );
539                if (isset($windows[$result['device_os_token']])) {
540                    $result['device_os_name'] = $windows[$result['device_os_token']];
541                } else {
542                    $result['device_os_name'] = $result['device_os_token'];
543                }
544            }
545        }
546        
547        // iphone 
548        $apple_device = array(
549            'iPhone', 
550            'iPod', 
551            'iPad',
552        );
553        if (isset($result['compatibility_flag'])) {
554            if (in_array($result['compatibility_flag'], $apple_device)) {
555                $result['device']           = strtolower($result['compatibility_flag']);
556                $result['device_os_token']  = 'iPhone OS';
557                $result['browser_language'] = trim($comment[3]);
558                $result['browser_version']  = $result['others']['detail'][1][2];
559                if (!empty($result['others']['detail'][2])) {
560                    $result['firmware'] = $result['others']['detail'][2][2];
561                }
562                if (!empty($result['others']['detail'][3])) {
563                    $result['browser_name']  = $result['others']['detail'][3][1];
564                    $result['browser_build'] = $result['others']['detail'][3][2];
565                }
566            }
567        }
568        
569        // Safari
570        if (isset($result['others'])) {
571            if ($result['others']['detail'][0][1] == 'AppleWebKit') {
572                $result['browser_engine'] = 'AppleWebKit';
573                if ($result['others']['detail'][1][1] == 'Version') {
574                    $result['browser_version'] = $result['others']['detail'][1][2];
575                } else {
576                    $result['browser_version'] = $result['others']['detail'][count($result['others']['detail']) - 1][2];
577                }
578                if (isset($comment[3])) {
579                     $result['browser_language'] = trim($comment[3]);
580                }
581                
582                $last = $result['others']['detail'][count($result['others']['detail']) - 1][1];
583                
584                if (empty($result['others']['detail'][2][1]) || $result['others']['detail'][2][1] == 'Safari') {
585                    $result['browser_name']    = ($result['others']['detail'][1][1] && $result['others']['detail'][1][1] != 'Version' ? $result['others']['detail'][1][1] : 'Safari');
586                    $result['browser_version'] = ($result['others']['detail'][1][2] ? $result['others']['detail'][1][2] : $result['others']['detail'][0][2]);
587                } else {
588                    $result['browser_name']    = $result['others']['detail'][2][1];
589                    $result['browser_version'] = $result['others']['detail'][2][2];
590                    
591                    // mobile version
592                    if ($result['browser_name'] == 'Mobile') {
593                        $result['browser_name'] = 'Safari ' . $result['browser_name'];
594                        if ($result['others']['detail'][1][1] == 'Version') {
595                            $result['browser_version'] = $result['others']['detail'][1][2];
596                        }
597                    }
598                }
599                
600                // For Safari < 2.2, AppleWebKit version gives the Safari version
601                if (strpos($result['browser_version'], '.') > 2 || (int) $result['browser_version'] > 20) {
602                    $temp = explode('.', $result['browser_version']);
603                    $build = (int) $temp[0];
604                    $awkVersion = array(
605                        48  => '0.8', 
606                        73  => '0.9', 
607                        85  => '1.0', 
608                        103 => '1.1', 
609                        124 => '1.2', 
610                        300 => '1.3', 
611                        400 => '2.0',
612                    );
613                    foreach ($awkVersion as $k => $v) {
614                        if ($build >= $k) {
615                            $result['browser_version'] = $v;
616                        }
617                    }
618                }
619            }
620            
621            // Gecko (Firefox or compatible)
622            if ($result['others']['detail'][0][1] == 'Gecko') {
623                $searchRV = true;
624                if (!empty($result['others']['detail'][1][1]) && !empty($result['others']['detail'][count($result['others']['detail']) - 1][2]) || strpos(strtolower($result['others']['full']), 'opera') !== false) {
625                    $searchRV = false;
626                    $result['browser_engine'] = $result['others']['detail'][0][1];
627                    
628                    // the name of the application is at the end indepenently 
629                    // of quantity of information in $result['others']['detail']
630                    $last = count($result['others']['detail']) - 1;
631                    
632                    // exception : if the version of the last information is 
633                    // empty we take the previous one
634                    if (empty($result['others']['detail'][$last][2])) {
635                        $last --;
636                    }
637                    
638                    // exception : if the last one is 'Red Hat' or 'Debian' => 
639                    // use rv: to find browser_version */
640                    if (in_array($result['others']['detail'][$last][1], array(
641                        'Debian', 
642                        'Hat',
643                    ))) {
644                        $searchRV = true;
645                    }
646                    $result['browser_name']    = $result['others']['detail'][$last][1];
647                    $result['browser_version'] = $result['others']['detail'][$last][2];
648                    if (isset($comment[4])) {
649                        $result['browser_build'] = trim($comment[4]);
650                    }
651                    $result['browser_language'] = trim($comment[3]);
652                    
653                    // Netscape
654                    if ($result['browser_name'] == 'Navigator' || $result['browser_name'] == 'Netscape6') {
655                        $result['browser_name'] = 'Netscape';
656                    }
657                }
658                if ($searchRV) {
659                    // Mozilla alone : the version is identified by rv:
660                    $result['browser_name'] = 'Mozilla';
661                    if (isset($result['comment']['detail'])) {
662                        foreach ($result['comment']['detail'] as $rv) {
663                            if (strpos($rv, 'rv:') !== false) {
664                                $result['browser_version'] = trim(str_replace('rv:', '', $rv));
665                            }
666                        }
667                    }
668                }
669            }
670            
671            // Netscape
672            if ($result['others']['detail'][0][1] == 'Netscape') {
673                $result['browser_name']    = 'Netscape';
674                $result['browser_version'] = $result['others']['detail'][0][2];
675            }
676            
677            // Opera 
678            // Opera: engine Presto
679            if ($result['others']['detail'][0][1] == 'Presto') {
680                $result['browser_engine'] = 'Presto';
681                if (!empty($result['others']['detail'][1][2])) {
682                    $result['browser_version'] = $result['others']['detail'][1][2];
683                }
684            }
685            
686            // UA ends with 'Opera X.XX'
687            if ($result['others']['detail'][0][1] == 'Opera') {
688                $result['browser_name']    = $result['others']['detail'][0][1];
689                $result['browser_version'] = $result['others']['detail'][1][1];
690            }
691            
692            // Opera Mini
693            if (isset($result["browser_token"])) {
694                if (strpos($result["browser_token"], 'Opera Mini') !== false) {
695                    $result['browser_name'] = 'Opera Mini';
696                }
697            }
698            
699            // Symbian
700            if ($result['others']['detail'][0][1] == 'SymbianOS') {
701                $result['device_os_token'] = 'SymbianOS';
702            }
703        }
704        
705        // UA ends with 'Opera X.XX'
706        if (isset($result['browser_name']) && isset($result['browser_engine'])) {
707            if ($result['browser_name'] == 'Opera' && $result['browser_engine'] == 'Gecko' && empty($result['browser_version'])) {
708                $result['browser_version'] = $result['others']['detail'][count($result['others']['detail']) - 1][1];
709            }
710        }
711        
712        // cleanup
713        if (isset($result['browser_version']) && isset($result['browser_build'])) {
714            if ($result['browser_version'] == $result['browser_build']) {
715                unset($result['browser_build']);
716            }
717        }
718        
719        // compatibility
720        $compatibility['AppleWebKit'] = 'Safari';
721        $compatibility['Gecko']       = 'Firefox';
722        $compatibility['MSIE']        = 'Internet Explorer';
723        $compatibility['Presto']      = 'Opera';
724        if (!empty($result['browser_engine'])) {
725            if (isset($compatibility[$result['browser_engine']])) {
726                $result['browser_compatibility'] = $compatibility[$result['browser_engine']];
727            }
728        }
729        
730        ksort($result);
731        return $result;
732    }
733
734    /**
735     * Loads the Features Adapter if it's defined in the $config array
736     * Otherwise, nothing is done
737     *
738     * @param  string $browserType Browser type
739     * @return array
740     */
741    protected function _loadFeaturesAdapter()
742    {
743        $config      = $this->_config;
744        $browserType = $this->getType();
745        if (!isset($config[$browserType]) || !isset($config[$browserType]['features'])) {
746            return array();
747        }
748        $config = $config[$browserType]['features'];
749
750        if (empty($config['classname'])) {
751            #require_once 'Zend/Http/UserAgent/Exception.php';
752            throw new Zend_Http_UserAgent_Exception('The ' . $this->getType() . ' features adapter must have a "classname" config parameter defined');
753        }
754
755        $className = $config['classname'];
756        if (!class_exists($className)) {
757            if (isset($config['path'])) {
758                $path = $config['path'];
759            } else {
760                #require_once 'Zend/Http/UserAgent/Exception.php';
761                throw new Zend_Http_UserAgent_Exception('The ' . $this->getType() . ' features adapter must have a "path" config parameter defined');
762            }
763            
764            if (false === include_once ($path)) {
765                #require_once 'Zend/Http/UserAgent/Exception.php';
766                throw new Zend_Http_UserAgent_Exception('The ' . $this->getType() . ' features adapter path that does not exist');
767            }
768        }
769        
770        return call_user_func(array($className, 'getFromRequest'), $this->_server, $this->_config);
771    }
772
773    /**
774     * Retrieve image format support
775     *
776     * @return array
777     */
778    public function getImageFormatSupport()
779    {
780        return $this->_images;
781    }
782
783    /**
784     * Get maximum image height supported by this device
785     *
786     * @return int
787     */
788    public function getMaxImageHeight()
789    {
790        return null;
791    }
792
793    /**
794     * Get maximum image width supported by this device
795     *
796     * @return int
797     */
798    public function getMaxImageWidth()
799    {
800        return null;
801    }
802
803    /**
804     * Get physical screen height of this device
805     *
806     * @return int
807     */
808    public function getPhysicalScreenHeight()
809    {
810        return null;
811    }
812
813    /**
814     * Get physical screen width of this device
815     *
816     * @return int
817     */
818    public function getPhysicalScreenWidth()
819    {
820        return null;
821    }
822
823    /**
824     * Get preferred markup type
825     *
826     * @return string
827     */
828    public function getPreferredMarkup()
829    {
830        return 'xhtml';
831    }
832
833    /**
834     * Get supported X/HTML version
835     *
836     * @return int
837     */
838    public function getXhtmlSupportLevel()
839    {
840        return 4;
841    }
842
843    /**
844     * Does the device support Flash?
845     *
846     * @return bool
847     */
848    public function hasFlashSupport()
849    {
850        return true;
851    }
852
853    /**
854     * Does the device support PDF?
855     *
856     * @return bool
857     */
858    public function hasPdfSupport()
859    {
860        return true;
861    }
862
863    /**
864     * Does the device have a phone number associated with it?
865     *
866     * @return bool
867     */
868    public function hasPhoneNumber()
869    {
870        return false;
871    }
872
873    /**
874     * Does the device support HTTPS?
875     *
876     * @return bool
877     */
878    public function httpsSupport()
879    {
880        return true;
881    }
882
883    /**
884     * Get the browser type
885     *
886     * @return string
887     */
888    public function getBrowser()
889    {
890        return $this->_browser;
891    }
892
893    /**
894     * Get the browser version
895     *
896     * @return string
897     */
898    public function getBrowserVersion()
899    {
900        return $this->_browserVersion;
901    }
902
903    /**
904     * Get the user agent string
905     *
906     * @return string
907     */
908    public function getUserAgent()
909    {
910        return $this->_userAgent;
911    }
912
913    /**
914     * @return the $_images
915     */
916    public function getImages()
917    {
918        return $this->_images;
919    }
920
921    /**
922     * @param string $browser
923     */
924    public function setBrowser($browser)
925    {
926        $this->_browser = $browser;
927    }
928
929    /**
930     * @param string $browserVersion
931     */
932    public function setBrowserVersion($browserVersion)
933    {
934        $this->_browserVersion = $browserVersion;
935    }
936
937    /**
938     * @param string $userAgent
939     */
940    public function setUserAgent($userAgent)
941    {
942        $this->_userAgent = $userAgent;
943        return $this;
944    }
945
946    /**
947     * @param array $_images
948     */
949    public function setImages($_images)
950    {
951        $this->_images = $_images;
952    }
953
954    /**
955     * Match a user agent string against a list of signatures
956     * 
957     * @param  string $userAgent 
958     * @param  array $signatures 
959     * @return bool
960     */
961    protected static function _matchAgentAgainstSignatures($userAgent, $signatures)
962    {
963        $userAgent = strtolower($userAgent);
964        foreach ($signatures as $signature) {
965            if (!empty($signature)) {
966                if (strpos($userAgent, $signature) !== false) {
967                    // Browser signature was found in user agent string
968                    return true;
969                }
970            }
971        }
972        return false;
973    }
974}