Browser.php Revision 1.118 (4 years, 6 months ago)

Location: [ Horde ] / horde / lib / Browser.php Annotate | Download

Log Message

Browser:: is now a framework package.

Checkout

  1. <?php
  2.  
  3. require_once HORDE_LIBS . 'Horde/String.php';
  4.  
  5. /**
  6. * The Browser:: class provides capability information for the current
  7. * web client. Browser identification is performed by examining the
  8. * HTTP_USER_AGENT environmental variable provide by the web server.
  9. *
  10. * $Horde: horde/lib/Browser.php,v 1.117 2004/02/12 20:04:55 chuck Exp $
  11. *
  12. * Copyright 1999-2004 Chuck Hagenbuch <chuck@horde.org>
  13. * Copyright 1999-2004 Jon Parise <jon@horde.org>
  14. *
  15. * See the enclosed file COPYING for license information (LGPL). If you
  16. * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
  17. *
  18. * @author Chuck Hagenbuch <chuck@horde.org>
  19. * @author Jon Parise <jon@horde.org>
  20. * @version $Revision: 1.118 $
  21. * @since Horde 1.3
  22. * @package Horde_Browser
  23. */
  24. class Browser {
  25.  
  26. /**
  27. * Major version number.
  28. *
  29. * @var integer $_majorVersion
  30. */
  31. var $_majorVersion = 0;
  32.  
  33. /**
  34. * Minor version number.
  35. *
  36. * @var integer $_minorVersion
  37. */
  38. var $_minorVersion = 0;
  39.  
  40. /**
  41. * Browser name.
  42. *
  43. * @var string $_browser
  44. */
  45. var $_browser = '';
  46.  
  47. /**
  48. * Full user agent
  49. *
  50. * @var string $_agent
  51. */
  52. var $_agent = '';
  53.  
  54. /**
  55. * HTTP_ACCEPT string
  56. *
  57. * @var string $_accept
  58. */
  59. var $_accept = '';
  60.  
  61. /**
  62. * Platform the browser is running on.
  63. *
  64. * @var string $_platform
  65. */
  66. var $_platform = '';
  67.  
  68. /**
  69. * Known robots.
  70. *
  71. * @var array $_robots
  72. */
  73. var $_robots = array(
  74. 'ZyBorg', 'Googlebot', 'Scooter/', 'Slurp.so', 'MuscatFerret',
  75. 'ArchitextSpider', 'Arachnoidea', 'ExtractorPro', 'ia_archiver',
  76. 'webbandit', 'Gulliver/', 'Slurp/cat', 'geckobot', 'KIT-Fireball',
  77. 'InfoSeek', 'Lycos_Spider', 'fido/', 'LEIA/', 'polybot'
  78. );
  79.  
  80. /**
  81. * Is this a mobile browser?
  82. *
  83. * @var boolean $_mobile
  84. */
  85. var $_mobile = false;
  86.  
  87. /**
  88. * Features.
  89. *
  90. * @var array $_features
  91. */
  92. var $_features = array(
  93. 'html' => true,
  94. 'hdml' => false,
  95. 'wml' => false,
  96. 'images' => true,
  97. 'iframes' => false,
  98. 'frames' => true,
  99. 'tables' => true,
  100. 'java' => true,
  101. 'javascript' => true,
  102. 'dom' => false,
  103. 'utf' => false,
  104. 'rte' => false,
  105. 'homepage' => false
  106. );
  107.  
  108. /**
  109. * Quirks
  110. *
  111. * @var array $_quirks
  112. */
  113. var $_quirks = array(
  114. 'must_cache_forms' => false,
  115. 'avoid_popup_windows' => false,
  116. 'cache_ssl_downloads' => false,
  117. 'break_disposition_header' => false,
  118. 'break_disposition_filename' => false,
  119. 'empty_file_input_value' => false,
  120. 'scrollbar_in_way' => false,
  121. 'cache_same_url' => false,
  122. 'ow_gui_1.3' => false,
  123. 'scroll_tds' => false,
  124. 'no_filename_spaces' => false,
  125. 'broken_multipart_form' => false,
  126. 'double_linebreak_textarea' => false,
  127. 'buggy_compression' => false
  128. );
  129.  
  130. /**
  131. * List of viewable image MIME subtypes.
  132. * This list of viewable images works for IE and Netscape/Mozilla.
  133. *
  134. * @var array $_images
  135. */
  136. var $_images = array('jpeg', 'gif', 'png', 'pjpeg', 'x-png', 'bmp', 'tiff');
  137.  
  138. /**
  139.  
  140. /**
  141. * Returns a reference to the global Browser object, only creating it
  142. * if it doesn't already exist.
  143. *
  144. * This method must be invoked as:
  145. * $browser = &Browser::singleton([$userAgent[, $accept]]);
  146. *
  147. * @access public
  148. *
  149. * @param optional string $userAgent The browser string to parse.
  150. * @param optional string $accept The HTTP_ACCEPT settings to use.
  151. *
  152. * @return object Browser The Browser object.
  153. */
  154. function &singleton($userAgent = null, $accept = null)
  155. {
  156. static $instances;
  157.  
  158. if (!isset($instances)) {
  159. $instances = array();
  160. }
  161.  
  162. $signature = serialize(array($userAgent, $accept));
  163. if (!array_key_exists($signature, $instances)) {
  164. $instances[$signature] = new Browser($userAgent, $accept);
  165. }
  166.  
  167. return $instances[$signature];
  168. }
  169.  
  170. /**
  171. * Create a browser instance (Constructor).
  172. *
  173. * @access public
  174. *
  175. * @param optional string $userAgent The browser string to parse.
  176. * @param optional string $accept The HTTP_ACCEPT settings to use.
  177. */
  178. function Browser($userAgent = null, $accept = null)
  179. {
  180. $this->match($userAgent, $accept);
  181. }
  182.  
  183. /**
  184. * Parses the user agent string and inititializes the object with
  185. * all the known features and quirks for the given browser.
  186. *
  187. * @access public
  188. *
  189. * @param optional string $userAgent The browser string to parse.
  190. * @param optional string $accept The HTTP_ACCEPT settings to use.
  191. */
  192. function match($userAgent = null, $accept = null)
  193. {
  194. // Set our agent string.
  195. if (is_null($userAgent)) {
  196. if (array_key_exists('HTTP_USER_AGENT', $_SERVER)) {
  197. $this->_agent = trim($_SERVER['HTTP_USER_AGENT']);
  198. }
  199. } else {
  200. $this->_agent = $userAgent;
  201. }
  202.  
  203. // Set our accept string.
  204. if (is_null($accept)) {
  205. if (array_key_exists('HTTP_ACCEPT', $_SERVER)) {
  206. $this->_accept = String::lower(trim($_SERVER['HTTP_ACCEPT']));
  207. }
  208. } else {
  209. $this->_accept = String::lower($accept);
  210. }
  211.  
  212. // Check for UTF support.
  213. if (array_key_exists('HTTP_ACCEPT_CHARSET', $_SERVER)) {
  214. $this->setFeature('utf', strstr(String::lower($_SERVER['HTTP_ACCEPT_CHARSET']), 'utf'));
  215. }
  216.  
  217. if (!empty($this->_agent)) {
  218. $this->_setPlatform();
  219.  
  220. if (preg_match('|Opera[/ ]([0-9.]+)|', $this->_agent, $version)) {
  221. $this->setBrowser('opera');
  222. list($this->_majorVersion, $this->_minorVersion) = explode('.', $version[1]);
  223. $this->setFeature('javascript', true);
  224. $this->setQuirk('no_filename_spaces');
  225.  
  226. switch ($this->_majorVersion) {
  227. case 7:
  228. $this->setFeature('dom');
  229. $this->setFeature('iframes');
  230. $this->setQuirk('double_linebreak_textarea');
  231. break;
  232. }
  233. } elseif ((preg_match('|MSIE ([0-9.]+)|', $this->_agent, $version)) ||
  234. (preg_match('|Internet Explorer/([0-9.]+)|', $this->_agent, $version))) {
  235.  
  236. $this->setBrowser('msie');
  237. $this->setQuirk('cache_ssl_downloads');
  238. $this->setQuirk('cache_same_url');
  239. $this->setQuirk('break_disposition_filename');
  240.  
  241. if (strstr($version[1], '.')) {
  242. list($this->_majorVersion, $this->_minorVersion) = explode('.', $version[1]);
  243. } else {
  244. $this->_majorVersion = $version[1];
  245. $this->_minorVersion = 0;
  246. }
  247.  
  248. /* Some IE 6's have buggy compression:
  249. http://lists.horde.org/archives/imp/Week-of-Mon-20030407/031952.html
  250. */
  251. if (preg_match('|Mozilla/4.0 \(compatible; MSIE 6.0; Windows NT 5.|', $this->_agent)) {
  252. $this->setQuirk('buggy_compression');
  253. }
  254.  
  255. switch ($this->_majorVersion) {
  256. case 6:
  257. $this->setFeature('javascript', 1.4);
  258. $this->setFeature('dom');
  259. $this->setFeature('iframes');
  260. $this->setFeature('utf');
  261. $this->setFeature('rte');
  262. $this->setFeature('homepage');
  263. $this->setQuirk('scrollbar_in_way');
  264. $this->setQuirk('broken_multipart_form');
  265. break;
  266.  
  267. case 5:
  268. if ($this->getPlatform() == 'mac') {
  269. $this->setFeature('javascript', 1.2);
  270. } else {
  271. // MSIE 5 for Windows.
  272. $this->setFeature('javascript', 1.4);
  273. $this->setFeature('dom');
  274. }
  275. $this->setFeature('iframes');
  276. $this->setFeature('utf');
  277. $this->setFeature('homepage');
  278. if ($this->_minorVersion == 5) {
  279. $this->setQuirk('break_disposition_header');
  280. $this->setQuirk('broken_multipart_form');
  281. }
  282. if ($this->_minorVersion >= 5) {
  283. $this->setFeature('rte');
  284. }
  285. break;
  286.  
  287. case 4:
  288. $this->setFeature('javascript', 1.2);
  289. if ($this->_minorVersion > 0) {
  290. $this->setFeature('utf');
  291. }
  292. break;
  293.  
  294. case 3:
  295. $this->setFeature('javascript', 1.1);
  296. $this->setQuirk('avoid_popup_windows');
  297. break;
  298. }
  299. } elseif (preg_match('|Elaine/([0-9]+)|', $this->_agent, $version) ||
  300. preg_match('|Digital Paths|', $this->_agent, $version)) {
  301. $this->setBrowser('palm');
  302. $this->setFeature('images', false);
  303. $this->setFeature('frames', false);
  304. $this->setFeature('javascript', false);
  305. $this->setQuirk('avoid_popup_windows');
  306. $this->_mobile = true;
  307. } elseif (preg_match('|ANTFresco/([0-9]+)|', $this->_agent, $version)) {
  308. $this->setBrowser('fresco');
  309. $this->setFeature('javascript', 1.1);
  310. $this->setQuirk('avoid_popup_windows');
  311. } elseif (preg_match('|Konqueror/([0-9]+)|', $this->_agent, $version) ||
  312. preg_match('|Safari/([0-9]+)|', $this->_agent, $version)) {
  313. // Konqueror and Apple's Safari both use the KHTML
  314. // rendering engine.
  315. $this->setBrowser('konqueror');
  316. $this->setQuirk('empty_file_input_value');
  317. $this->_majorVersion = $version[1];
  318.  
  319. if (strpos($this->_agent, 'Safari') !== false &&
  320. // Safari
  321. $this->_majorVersion >= 60) {
  322. $this->setFeature('javascript', 1.4);
  323. $this->setFeature('dom');
  324. $this->setFeature('iframes');
  325. } else {
  326. // Konqueror.
  327. $this->setBrowser('konqueror');
  328. $this->setFeature('javascript', 1.1);
  329. switch ($this->_majorVersion) {
  330. case 3:
  331. $this->setFeature('dom');
  332. $this->setFeature('iframes');
  333. break;
  334. }
  335. }
  336. } elseif (preg_match('|Mozilla/([0-9.]+)|', $this->_agent, $version)) {
  337. $this->setBrowser('mozilla');
  338. $this->setQuirk('must_cache_forms');
  339.  
  340. list($this->_majorVersion, $this->_minorVersion) = explode('.', $version[1]);
  341. switch ($this->_majorVersion) {
  342. case 5:
  343. if ($this->getPlatform() == 'win') {
  344. $this->setQuirk('break_disposition_filename');
  345. }
  346. $this->setFeature('javascript', 1.4);
  347. $this->setFeature('dom');
  348. $this->setFeature('rte');
  349. if (preg_match('|rv:(.*)\)|', $this->_agent, $revision)) {
  350. if ($revision[1] >= 1) {
  351. $this->setFeature('iframes');
  352. }
  353. }
  354. break;
  355.  
  356. case 4:
  357. $this->setFeature('javascript', 1.3);
  358. $this->setFeature('rte');
  359. $this->setQuirk('buggy_compression');
  360. break;
  361.  
  362. case 3:
  363. default:
  364. $this->setFeature('javascript', 1);
  365. $this->setQuirk('buggy_compression');
  366. break;
  367. }
  368. } elseif (preg_match('|Lynx/([0-9]+)|', $this->_agent, $version)) {
  369. $this->setBrowser('lynx');
  370. $this->setFeature('images', false);
  371. $this->setFeature('frames', false);
  372. $this->setFeature('javascript', false);
  373. $this->setQuirk('avoid_popup_windows');
  374. } elseif (preg_match('|Links \(([0-9]+)|', $this->_agent, $version)) {
  375. $this->setBrowser('links');
  376. $this->setFeature('images', false);
  377. $this->setFeature('frames', false);
  378. $this->setFeature('javascript', false);
  379. $this->setQuirk('avoid_popup_windows');
  380. } elseif (preg_match('|HotJava/([0-9]+)|', $this->_agent, $version)) {
  381. $this->setBrowser('hotjava');
  382. $this->setFeature('javascript', false);
  383. } elseif (strstr($this->_agent, 'UP/') ||
  384. strstr($this->_agent, 'UP.B')) {
  385. $this->setBrowser('up');
  386. $this->setFeature('html', false);
  387. $this->setFeature('javascript', false);
  388. $this->setFeature('hdml');
  389. $this->setFeature('wml');
  390.  
  391. if (strstr($this->_agent, 'GUI') &&
  392. strstr($this->_agent, 'UP.Link')) {
  393. /* The device accepts Openwave GUI extensions for
  394. WML 1.3. Non-UP.Link gateways sometimes have
  395. problems, so exclude them. */
  396. $this->setQuirk('ow_gui_1.3');
  397. }
  398. $this->_mobile = true;
  399. } elseif (strstr($this->_agent, 'Xiino/') ) {
  400. $this->setBrowser('xiino');
  401. $this->setFeature('hdml');
  402. $this->setFeature('wml');
  403. $this->_mobile = true;
  404. } elseif (strstr($this->_agent, 'Palmscape/') ) {
  405. $this->setBrowser('palmscape');
  406. $this->setFeature('javascript', false);
  407. $this->setFeature('hdml');
  408. $this->setFeature('wml');
  409. $this->_mobile = true;
  410. } elseif (strstr($this->_agent, 'Nokia')) {
  411. $this->setBrowser('nokia');
  412. $this->setFeature('html', false);
  413. $this->setFeature('wml');
  414. $this->setFeature('xhtml');
  415. $this->_mobile = true;
  416. } elseif (strstr($this->_agent, 'Ericsson')) {
  417. $this->setBrowser('ericsson');
  418. $this->setFeature('html', false);
  419. $this->setFeature('wml');
  420. $this->_mobile = true;
  421. } elseif (stristr($this->_agent, 'Wap')) {
  422. $this->setBrowser('wap');
  423. $this->setFeature('html', false);
  424. $this->setFeature('javascript', false);
  425. $this->setFeature('hdml');
  426. $this->setFeature('wml');
  427. $this->_mobile = true;
  428. } elseif (strstr(String::lower($this->_agent), 'docomo') ||
  429. strstr(String::lower($this->_agent), 'portalmmm')) {
  430. $this->setBrowser('imode');
  431. $this->setFeature('images', false);
  432. $this->_mobile = true;
  433. } elseif (strstr(String::lower($this->_agent), 'avantgo')) {
  434. $this->setBrower('avantgo');
  435. $this->_mobile = true;
  436. } elseif (strstr(String::lower($this->_agent), 'j-')) {
  437. $this->setBrowser('mml');
  438. $this->_mobile = true;
  439. }
  440. }
  441. }
  442.  
  443. /**
  444. * Match the platform of the browser.
  445. *
  446. * This is a pretty simplistic implementation, but it's intended
  447. * to let us tell what line breaks to send, so it's good enough
  448. * for its purpose.
  449. *
  450. * @access public
  451. *
  452. * @since Horde 2.2
  453. */
  454. function _setPlatform()
  455. {
  456. if (stristr($this->_agent, 'wind')) {
  457. $this->_platform = 'win';
  458. } elseif (stristr($this->_agent, 'mac')) {
  459. $this->_platform = 'mac';
  460. } else {
  461. $this->_platform = 'unix';
  462. }
  463. }
  464.  
  465. /**
  466. * Return the currently matched platform.
  467. *
  468. * @return string The user's platform.
  469. *
  470. * @since Horde 2.2
  471. */
  472. function getPlatform()
  473. {
  474. return $this->_platform;
  475. }
  476.  
  477. /**
  478. * Sets the current browser.
  479. *
  480. * @access public
  481. *
  482. * @param string $browser The browser to set as current.
  483. */
  484. function setBrowser($browser)
  485. {
  486. $this->_browser = $browser;
  487. }
  488.  
  489. /**
  490. * Determine if the given browser is the same as the current.
  491. *
  492. * @access public
  493. *
  494. * @param string $browser The browser to check.
  495. *
  496. * @return boolean Is the given browser the same as the current?
  497. */
  498. function isBrowser($browser)
  499. {
  500. return ($this->_browser === $browser);
  501. }
  502.  
  503. /**
  504. * Do we consider the current browser to be a mobile device?
  505. *
  506. * @return boolean True if we do, false if we don't.
  507. */
  508. function isMobile()
  509. {
  510. return $this->_mobile;
  511. }
  512.  
  513. /**
  514. * Retrieve the current browser.
  515. *
  516. * @access public
  517. *
  518. * @return string The current browser.
  519. */
  520. function getBrowser()
  521. {
  522. return $this->_browser;
  523. }
  524.  
  525. /**
  526. * Retrieve the current browser's major version.
  527. *
  528. * @access public
  529. *
  530. * @return int The current browser's major version.
  531. */
  532. function getMajor()
  533. {
  534. return $this->_majorVersion;
  535. }
  536.  
  537. /**
  538. * Retrieve the current browser's minor version.
  539. *
  540. * @access public
  541. *
  542. * @return int The current browser's minor version.
  543. */
  544. function getMinor()
  545. {
  546. return $this->_minorVersion;
  547. }
  548.  
  549. /**
  550. * Retrieve the current browser's version.
  551. *
  552. * @access public
  553. *
  554. * @return string The current browser's version.
  555. */
  556. function getVersion()
  557. {
  558. return $this->_majorVersion . '.' . $this->_minorVersion;
  559. }
  560.  
  561. /**
  562. * Set unique behavior for the current browser.
  563. *
  564. * @access public
  565. *
  566. * @param string $quirk The behavior to set.
  567. * @param optional string $value Special behavior parameter.
  568. */
  569. function setQuirk($quirk, $value = true)
  570. {
  571. $this->_quirks[$quirk] = $value;
  572. }
  573.  
  574. /**
  575. * Check unique behavior for the current browser.
  576. *
  577. * @access public
  578. *
  579. * @param string $quirk The behavior to check.
  580. *
  581. * @return boolean Does the browser have the behavior set?
  582. */
  583. function hasQuirk($quirk)
  584. {
  585. return !empty($this->_quirks[$quirk]);
  586. }
  587.  
  588. /**
  589. * Retreive unique behavior for the current browser.
  590. *
  591. * @access public
  592. *
  593. * @param string $quirk The behavior to retreive.
  594. *
  595. * @return string The value for the requested behavior.
  596. */
  597. function getQuirk($quirk)
  598. {
  599. return array_key_exists($quirk, $this->_quirks)
  600. ? $this->_quirks[$quirk]
  601. : null;
  602. }
  603.  
  604. /**
  605. * Set capabilities for the current browser.
  606. *
  607. * @access public
  608. *
  609. * @param string $feature The capability to set.
  610. * @param optional string $value Special capability parameter.
  611. */
  612. function setFeature($feature, $value = true)
  613. {
  614. $this->_features[$feature] = $value;
  615. }
  616.  
  617. /**
  618. * Check the current browser capabilities.
  619. *
  620. * @access public
  621. *
  622. * @param string $feature The capability to check.
  623. *
  624. * @return boolean Does the browser have the capability set?
  625. */
  626. function hasFeature($feature)
  627. {
  628. return !empty($this->_features[$feature]);
  629. }
  630.  
  631. /**
  632. * Retreive the current browser capability.
  633. *
  634. * @access public
  635. *
  636. * @param string $feature The capability to retreive.
  637. *
  638. * @return string The value of the requested capability.
  639. */
  640. function getFeature($feature)
  641. {
  642. return array_key_exists($feature, $this->_features)
  643. ? $this->_features[$feature]
  644. : null;
  645. }
  646.  
  647. /**
  648. * Returns the headers for a browser download.
  649. *
  650. * @access public
  651. *
  652. * @param optional string $filename The filename of the download.
  653. * @param optional string $cType The content-type description of the
  654. * file.
  655. * @param optional boolean $inline True if inline, false if attachment.
  656. * @param optional string $cLength The content-length of this file.
  657. *
  658. * @since Horde 2.2
  659. */
  660. function downloadHeaders($filename = 'unknown', $cType = null,
  661. $inline = false, $cLength = null)
  662. {
  663. /* Some browsers don't like spaces in the filename. */
  664. if ($this->hasQuirk('no_filename_spaces')) {
  665. $filename = strtr($filename, ' ', '_');
  666. }
  667.  
  668. /* MSIE doesn't like multiple periods in the file name. Convert
  669. all periods (except the last one) to underscores. */
  670. if ($this->isBrowser('msie')) {
  671. if (($pos = strrpos($filename, '.'))) {
  672. $filename = strtr(substr($filename, 0, $pos), '.', '_') . substr($filename, $pos);
  673. }
  674. }
  675.  
  676. /* Content-Type/Content-Disposition Header. */
  677. if ($inline) {
  678. if (!is_null($cType)) {
  679. header('Content-Type: ' . trim($cType));
  680. } elseif ($this->isBrowser('msie')) {
  681. header('Content-Type: application/x-msdownload');
  682. } else {
  683. header('Content-Type: application/octet-stream');
  684. }
  685. header('Content-Disposition: inline; filename="' . $filename . '"');
  686. } else {
  687. if ($this->isBrowser('msie')) {
  688. header('Content-Type: application/x-msdownload');
  689. } elseif (!is_null($cType)) {
  690. header('Content-Type: ' . trim($cType));
  691. } else {
  692. header('Content-Type: application/octet-stream');
  693. }
  694.  
  695. if ($this->hasQuirk('break_disposition_header')) {
  696. header('Content-Disposition: filename="' . $filename . '"');
  697. } else {
  698. header('Content-Disposition: attachment; filename="' . $filename . '"');
  699. }
  700. }
  701.  
  702. /* Content-Length Header. Don't send Content-Length for HTTP/1.1
  703. servers. */
  704. include_once HORDE_BASE . '/lib/Server.php';
  705. if ((Server::HTTPProtocol() != '1.1') && !is_null($cLength)) {
  706. header('Content-Length: ' . $cLength);
  707. }
  708.  
  709. /* Overwrite Pragma: and other caching headers for IE. */
  710. if ($this->hasQuirk('cache_ssl_downloads')) {
  711. header('Expires: 0');
  712. header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
  713. header('Pragma: public');
  714. }
  715. }
  716.  
  717. /**
  718. * Determines if the browser is a robot or not.
  719. *
  720. * @access public
  721. *
  722. * @return boolean True if browser is a known robot.
  723. */
  724. function isRobot()
  725. {
  726. if (in_array($this->_agent, $this->_robots)) {
  727. return true;
  728. } else {
  729. return false;
  730. }
  731. }
  732.  
  733. /**
  734. * Determines if a browser can display a given MIME type.
  735. *
  736. * @access public
  737. *
  738. * @param string $mimetype The MIME type to check.
  739. *
  740. * @return boolean True if the browser can display the MIME type.
  741. */
  742. function isViewable($mimetype)
  743. {
  744. if (!empty($this->_accept)) {
  745. return $this->_acceptMIMEType($mimetype);
  746. } else {
  747. if (!$this->hasFeature('images')) {
  748. return false;
  749. }
  750.  
  751. list($type, $subtype) = explode('/', String::lower($mimetype));
  752. if ($type != 'image') {
  753. return false;
  754. }
  755.  
  756. if (in_array($subtype, $this->_images)) {
  757. return true;
  758. } else {
  759. return false;
  760. }
  761. }
  762. }
  763.  
  764. /**
  765. * Determines if a browser accepts a given MIME type.
  766. *
  767. * @access private
  768. *
  769. * @param string $mimetype The MIME type to check.
  770. *
  771. * @return boolean True if the browser accepts the MIME type.
  772. */
  773. function _acceptMIMEType($mimetype)
  774. {
  775. if (strstr('*/*', $this->_accept)) {
  776. return true;
  777. }
  778.  
  779. if (strstr($this->_accept, String::lower($mimetype))) {
  780. return true;
  781. }
  782.  
  783. /* image/jpeg and image/pjpeg *appear* to be the same entity, but
  784. mozilla don't seem to want to accept the latter. For our
  785. purposes, we will treat them the same. */
  786. if ($this->isBrowser('mozilla') &&
  787. (String::lower($mimetype) == 'image/pjpeg') &&
  788. strstr($this->_accept, 'image/jpeg')) {
  789. return true;
  790. }
  791.  
  792. return false;
  793. }
  794.  
  795. /**
  796. * Escape characters in javascript code if the browser requires it.
  797. * %23, %26, and %2B (for IE) and %27 need to be escaped or else
  798. * jscript will interpret it as a single quote, pound sign, or
  799. * ampersand and refuse to work.
  800. *
  801. * @access public
  802. *
  803. * @param string $code The JS code to escape.
  804. *
  805. * @return string The escaped code.
  806. */
  807. function escapeJSCode($code)
  808. {
  809. $from = $to = array();
  810.  
  811. if ($this->isBrowser('msie') ||
  812. ($this->isBrowser('mozilla') && (</