Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

functions_download.php

Zuletzt modifiziert: 02.04.2025, 15:01 - Dateigröße: 19.39 KiB


001  <?php
002  /**
003  *
004  * This file is part of the phpBB Forum Software package.
005  *
006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
007  * @license GNU General Public License, version 2 (GPL-2.0)
008  *
009  * For full copyright and license information, please see
010  * the docs/CREDITS.txt file.
011  *
012  */
013   
014  /**
015  * @ignore
016  */
017  if (!defined('IN_PHPBB'))
018  {
019      exit;
020  }
021   
022  /**
023  * A simplified function to deliver avatars
024  * The argument needs to be checked before calling this function.
025  */
026  function send_avatar_to_browser($file, $browser)
027  {
028      global $config, $phpbb_root_path;
029   
030      $prefix = $config['avatar_salt'] . '_';
031      $image_dir = $config['avatar_path'];
032   
033      // Adjust image_dir path (no trailing slash)
034      if (substr($image_dir, -1, 1) == '/' || substr($image_dir, -1, 1) == '\\')
035      {
036          $image_dir = substr($image_dir, 0, -1) . '/';
037      }
038      $image_dir = str_replace(array('../', '..\\', './', '.\\'), '', $image_dir);
039   
040      if ($image_dir && ($image_dir[0] == '/' || $image_dir[0] == '\\'))
041      {
042          $image_dir = '';
043      }
044      $file_path = $phpbb_root_path . $image_dir . '/' . $prefix . $file;
045   
046      if ((@file_exists($file_path) && @is_readable($file_path)) && !headers_sent())
047      {
048          header('Cache-Control: public');
049   
050          $image_data = @getimagesize($file_path);
051          header('Content-Type: ' . image_type_to_mime_type($image_data[2]));
052   
053          if ((strpos(strtolower($browser), 'msie') !== false) && !phpbb_is_greater_ie_version($browser, 7))
054          {
055              header('Content-Disposition: attachment; ' . header_filename($file));
056   
057              if (strpos(strtolower($browser), 'msie 6.0') !== false)
058              {
059                  header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
060              }
061              else
062              {
063                  header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT');
064              }
065          }
066          else
067          {
068              header('Content-Disposition: inline; ' . header_filename($file));
069              header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT');
070          }
071   
072          $size = @filesize($file_path);
073          if ($size)
074          {
075              header("Content-Length: $size");
076          }
077   
078          if (@readfile($file_path) == false)
079          {
080              $fp = @fopen($file_path, 'rb');
081   
082              if ($fp !== false)
083              {
084                  while (!feof($fp))
085                  {
086                      echo fread($fp, 8192);
087                  }
088                  fclose($fp);
089              }
090          }
091   
092          flush();
093      }
094      else
095      {
096          header('HTTP/1.0 404 Not Found');
097      }
098  }
099   
100  /**
101  * Wraps an url into a simple html page. Used to display attachments in IE.
102  * this is a workaround for now; might be moved to template system later
103  * direct any complaints to 1 Microsoft Way, Redmond
104  */
105  function wrap_img_in_html($src, $title)
106  {
107      echo '<!DOCTYPE html>';
108      echo '<html>';
109      echo '<head>';
110      echo '<meta charset="utf-8">';
111      echo '<meta http-equiv="X-UA-Compatible" content="IE=edge">';
112      echo '<title>' . $title . '</title>';
113      echo '</head>';
114      echo '<body>';
115      echo '<div>';
116      echo '<img src="' . $src . '" alt="' . $title . '" />';
117      echo '</div>';
118      echo '</body>';
119      echo '</html>';
120  }
121   
122  /**
123  * Send file to browser
124  */
125  function send_file_to_browser($attachment, $upload_dir, $category)
126  {
127      global $user, $db, $phpbb_dispatcher, $phpbb_root_path, $request;
128   
129      $filename = $phpbb_root_path . $upload_dir . '/' . $attachment['physical_filename'];
130   
131      if (!@file_exists($filename))
132      {
133          send_status_line(404, 'Not Found');
134          trigger_error('ERROR_NO_ATTACHMENT');
135      }
136   
137      // Correct the mime type - we force application/octetstream for all files, except images
138      // Please do not change this, it is a security precaution
139      if ($category != ATTACHMENT_CATEGORY_IMAGE || strpos($attachment['mimetype'], 'image') !== 0)
140      {
141          $attachment['mimetype'] = (strpos(strtolower($user->browser), 'msie') !== false || strpos(strtolower($user->browser), 'opera') !== false) ? 'application/octetstream' : 'application/octet-stream';
142      }
143   
144      if (@ob_get_length())
145      {
146          @ob_end_clean();
147      }
148   
149      // Now send the File Contents to the Browser
150      $size = @filesize($filename);
151   
152      /**
153      * Event to alter attachment before it is sent to browser.
154      *
155      * @event core.send_file_to_browser_before
156      * @var    array    attachment    Attachment data
157      * @var    string    upload_dir    Relative path of upload directory
158      * @var    int        category    Attachment category
159      * @var    string    filename    Path to file, including filename
160      * @var    int        size        File size
161      * @since 3.1.11-RC1
162      */
163      $vars = array(
164          'attachment',
165          'upload_dir',
166          'category',
167          'filename',
168          'size',
169      );
170      extract($phpbb_dispatcher->trigger_event('core.send_file_to_browser_before', compact($vars)));
171   
172      // To correctly display further errors we need to make sure we are using the correct headers for both (unsetting content-length may not work)
173   
174      // Check if headers already sent or not able to get the file contents.
175      if (headers_sent() || !@file_exists($filename) || !@is_readable($filename))
176      {
177          // PHP track_errors setting On?
178          if (!empty($php_errormsg))
179          {
180              send_status_line(500, 'Internal Server Error');
181              trigger_error($user->lang['UNABLE_TO_DELIVER_FILE'] . '<br />' . sprintf($user->lang['TRACKED_PHP_ERROR'], $php_errormsg));
182          }
183   
184          send_status_line(500, 'Internal Server Error');
185          trigger_error('UNABLE_TO_DELIVER_FILE');
186      }
187   
188      // Make sure the database record for the filesize is correct
189      if ($size > 0 && $size != $attachment['filesize'] && strpos($attachment['physical_filename'], 'thumb_') === false)
190      {
191          // Update database record
192          $sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
193              SET filesize = ' . (int) $size . '
194              WHERE attach_id = ' . (int) $attachment['attach_id'];
195          $db->sql_query($sql);
196      }
197   
198      // Now the tricky part... let's dance
199      header('Cache-Control: private');
200   
201      // Send out the Headers. Do not set Content-Disposition to inline please, it is a security measure for users using the Internet Explorer.
202      header('Content-Type: ' . $attachment['mimetype']);
203   
204      if (phpbb_is_greater_ie_version($user->browser, 7))
205      {
206          header('X-Content-Type-Options: nosniff');
207      }
208   
209      if (empty($user->browser) || ((strpos(strtolower($user->browser), 'msie') !== false) && !phpbb_is_greater_ie_version($user->browser, 7)))
210      {
211          header('Content-Disposition: attachment; ' . header_filename(html_entity_decode($attachment['real_filename'], ENT_COMPAT)));
212          if (empty($user->browser) || (strpos(strtolower($user->browser), 'msie 6.0') !== false))
213          {
214              header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
215          }
216      }
217      else
218      {
219          header('Content-Disposition: ' . ((strpos($attachment['mimetype'], 'image') === 0) ? 'inline' : 'attachment') . '; ' . header_filename(html_entity_decode($attachment['real_filename'], ENT_COMPAT)));
220          if (phpbb_is_greater_ie_version($user->browser, 7) && (strpos($attachment['mimetype'], 'image') !== 0))
221          {
222              header('X-Download-Options: noopen');
223          }
224      }
225   
226      // Close the db connection before sending the file etc.
227      file_gc(false);
228   
229      if (!set_modified_headers($attachment['filetime'], $user->browser))
230      {
231          // We make sure those have to be enabled manually by defining a constant
232          // because of the potential disclosure of full attachment path
233          // in case support for features is absent in the webserver software.
234          if (defined('PHPBB_ENABLE_X_ACCEL_REDIRECT') && PHPBB_ENABLE_X_ACCEL_REDIRECT)
235          {
236              // X-Accel-Redirect - http://wiki.nginx.org/XSendfile
237              header('X-Accel-Redirect: ' . $user->page['root_script_path'] . $upload_dir . '/' . $attachment['physical_filename']);
238              exit;
239          }
240          else if (defined('PHPBB_ENABLE_X_SENDFILE') && PHPBB_ENABLE_X_SENDFILE && !phpbb_http_byte_range($size))
241          {
242              // X-Sendfile - http://blog.lighttpd.net/articles/2006/07/02/x-sendfile
243              // Lighttpd's X-Sendfile does not support range requests as of 1.4.26
244              // and always requires an absolute path.
245              header('X-Sendfile: ' . __DIR__ . "/../$upload_dir/{$attachment['physical_filename']}");
246              exit;
247          }
248   
249          if ($size)
250          {
251              header("Content-Length: $size");
252          }
253   
254          // Try to deliver in chunks
255          @set_time_limit(0);
256   
257          $fp = @fopen($filename, 'rb');
258   
259          if ($fp !== false)
260          {
261              // Deliver file partially if requested
262              if ($range = phpbb_http_byte_range($size))
263              {
264                  fseek($fp, $range['byte_pos_start']);
265   
266                  send_status_line(206, 'Partial Content');
267                  header('Content-Range: bytes ' . $range['byte_pos_start'] . '-' . $range['byte_pos_end'] . '/' . $range['bytes_total']);
268                  header('Content-Length: ' . $range['bytes_requested']);
269   
270                  // First read chunks
271                  while (!feof($fp) && ftell($fp) < $range['byte_pos_end'] - 8192)
272                  {
273                      echo fread($fp, 8192);
274                  }
275                  // Then, read the remainder
276                  echo fread($fp, $range['bytes_requested'] % 8192);
277              }
278              else
279              {
280                  while (!feof($fp))
281                  {
282                      echo fread($fp, 8192);
283                  }
284              }
285              fclose($fp);
286          }
287          else
288          {
289              @readfile($filename);
290          }
291   
292          flush();
293      }
294   
295      exit;
296  }
297   
298  /**
299  * Get a browser friendly UTF-8 encoded filename
300  */
301  function header_filename($file)
302  {
303      global $request;
304   
305      $user_agent = $request->header('User-Agent');
306   
307      // There be dragons here.
308      // Not many follows the RFC...
309      if (strpos($user_agent, 'MSIE') !== false || strpos($user_agent, 'Konqueror') !== false)
310      {
311          return "filename=" . rawurlencode($file);
312      }
313   
314      // follow the RFC for extended filename for the rest
315      return "filename*=UTF-8''" . rawurlencode($file);
316  }
317   
318  /**
319  * Check if downloading item is allowed
320  */
321  function download_allowed()
322  {
323      global $config, $user, $db, $request;
324   
325      if (!$config['secure_downloads'])
326      {
327          return true;
328      }
329   
330      $url = html_entity_decode($request->header('Referer'), ENT_COMPAT);
331   
332      if (!$url)
333      {
334          return ($config['secure_allow_empty_referer']) ? true : false;
335      }
336   
337      // Split URL into domain and script part
338      $url = @parse_url($url);
339   
340      if ($url === false)
341      {
342          return ($config['secure_allow_empty_referer']) ? true : false;
343      }
344   
345      $hostname = $url['host'];
346      unset($url);
347   
348      $allowed = ($config['secure_allow_deny']) ? false : true;
349      $iplist = array();
350   
351      if (($ip_ary = @gethostbynamel($hostname)) !== false)
352      {
353          foreach ($ip_ary as $ip)
354          {
355              if ($ip)
356              {
357                  $iplist[] = $ip;
358              }
359          }
360      }
361   
362      // Check for own server...
363      $server_name = $user->host;
364   
365      // Forcing server vars is the only way to specify/override the protocol
366      if ($config['force_server_vars'] || !$server_name)
367      {
368          $server_name = $config['server_name'];
369      }
370   
371      if (preg_match('#^.*?' . preg_quote($server_name, '#') . '.*?$#i', $hostname))
372      {
373          $allowed = true;
374      }
375   
376      // Get IP's and Hostnames
377      if (!$allowed)
378      {
379          $sql = 'SELECT site_ip, site_hostname, ip_exclude
380              FROM ' . SITELIST_TABLE;
381          $result = $db->sql_query($sql);
382   
383          while ($row = $db->sql_fetchrow($result))
384          {
385              $site_ip = trim($row['site_ip']);
386              $site_hostname = trim($row['site_hostname']);
387   
388              if ($site_ip)
389              {
390                  foreach ($iplist as $ip)
391                  {
392                      if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($site_ip, '#')) . '$#i', $ip))
393                      {
394                          if ($row['ip_exclude'])
395                          {
396                              $allowed = ($config['secure_allow_deny']) ? false : true;
397                              break 2;
398                          }
399                          else
400                          {
401                              $allowed = ($config['secure_allow_deny']) ? true : false;
402                          }
403                      }
404                  }
405              }
406   
407              if ($site_hostname)
408              {
409                  if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($site_hostname, '#')) . '$#i', $hostname))
410                  {
411                      if ($row['ip_exclude'])
412                      {
413                          $allowed = ($config['secure_allow_deny']) ? false : true;
414                          break;
415                      }
416                      else
417                      {
418                          $allowed = ($config['secure_allow_deny']) ? true : false;
419                      }
420                  }
421              }
422          }
423          $db->sql_freeresult($result);
424      }
425   
426      return $allowed;
427  }
428   
429  /**
430  * Check if the browser has the file already and set the appropriate headers-
431  * @returns false if a resend is in order.
432  */
433  function set_modified_headers($stamp, $browser)
434  {
435      global $request;
436   
437      // let's see if we have to send the file at all
438      $last_load     =  $request->header('If-Modified-Since') ? strtotime(trim($request->header('If-Modified-Since'))) : false;
439   
440      if (strpos(strtolower($browser), 'msie 6.0') === false && !phpbb_is_greater_ie_version($browser, 7))
441      {
442          if ($last_load !== false && $last_load >= $stamp)
443          {
444              send_status_line(304, 'Not Modified');
445              // seems that we need those too ... browsers
446              header('Cache-Control: private');
447              header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT');
448              return true;
449          }
450          else
451          {
452              header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $stamp) . ' GMT');
453          }
454      }
455      return false;
456  }
457   
458  /**
459  * Garbage Collection
460  *
461  * @param bool $exit        Whether to die or not.
462  *
463  * @return null
464  */
465  function file_gc($exit = true)
466  {
467      global $cache, $db;
468   
469      if (!empty($cache))
470      {
471          $cache->unload();
472      }
473   
474      $db->sql_close();
475   
476      if ($exit)
477      {
478          exit;
479      }
480  }
481   
482  /**
483  * HTTP range support (RFC 2616 Section 14.35)
484  *
485  * Allows browsers to request partial file content
486  * in case a download has been interrupted.
487  *
488  * @param int $filesize        the size of the file in bytes we are about to deliver
489  *
490  * @return mixed        false if the whole file has to be delivered
491  *                    associative array on success
492  */
493  function phpbb_http_byte_range($filesize)
494  {
495      // Only call find_range_request() once.
496      static $request_array;
497   
498      if (!$filesize)
499      {
500          return false;
501      }
502   
503      if (!isset($request_array))
504      {
505          $request_array = phpbb_find_range_request();
506      }
507   
508      return (empty($request_array)) ? false : phpbb_parse_range_request($request_array, $filesize);
509  }
510   
511  /**
512  * Searches for HTTP range request in request headers.
513  *
514  * @return mixed        false if no request found
515  *                    array of strings containing the requested ranges otherwise
516  *                    e.g. array(0 => '0-0', 1 => '123-125')
517  */
518  function phpbb_find_range_request()
519  {
520      global $request;
521   
522      $value = $request->header('Range');
523   
524      // Make sure range request starts with "bytes="
525      if (strpos($value, 'bytes=') === 0)
526      {
527          // Strip leading 'bytes='
528          // Multiple ranges can be separated by a comma
529          return explode(',', substr($value, 6));
530      }
531   
532      return false;
533  }
534   
535  /**
536  * Analyses a range request array.
537  *
538  * A range request can contain multiple ranges,
539  * we however only handle the first request and
540  * only support requests from a given byte to the end of the file.
541  *
542  * @param array    $request_array    array of strings containing the requested ranges
543  * @param int    $filesize        the full size of the file in bytes that has been requested
544  *
545  * @return mixed        false if the whole file has to be delivered
546  *                    associative array on success
547  *                        byte_pos_start        the first byte position, can be passed to fseek()
548  *                        byte_pos_end        the last byte position
549  *                        bytes_requested        the number of bytes requested
550  *                        bytes_total            the full size of the file
551  */
552  function phpbb_parse_range_request($request_array, $filesize)
553  {
554      $first_byte_pos    = -1;
555      $last_byte_pos    = -1;
556   
557      // Go through all ranges
558      foreach ($request_array as $range_string)
559      {
560          $range = explode('-', trim($range_string));
561   
562          // "-" is invalid, "0-0" however is valid and means the very first byte.
563          if (count($range) != 2 || $range[0] === '' && $range[1] === '')
564          {
565              continue;
566          }
567   
568          // Substitute defaults
569          if ($range[0] === '')
570          {
571              $range[0] = 0;
572          }
573   
574          if ($range[1] === '')
575          {
576              $range[1] = $filesize - 1;
577          }
578   
579          if ($last_byte_pos >= 0 && $last_byte_pos + 1 != $range[0])
580          {
581              // We only support contiguous ranges, no multipart stuff :(
582              return false;
583          }
584   
585          if ($range[1] && $range[1] < $range[0])
586          {
587              // The requested range contains 0 bytes.
588              continue;
589          }
590   
591          // Return bytes from $range[0] to $range[1]
592          if ($first_byte_pos < 0)
593          {
594              $first_byte_pos    = (int) $range[0];
595          }
596   
597          $last_byte_pos    = (int) $range[1];
598   
599          if ($first_byte_pos >= $filesize)
600          {
601              // Requested range not satisfiable
602              return false;
603          }
604   
605          // Adjust last-byte-pos if it is absent or greater than the content.
606          if ($range[1] === '' || $last_byte_pos >= $filesize)
607          {
608              $last_byte_pos = $filesize - 1;
609          }
610      }
611   
612      if ($first_byte_pos < 0 || $last_byte_pos < 0)
613      {
614          return false;
615      }
616   
617      return array(
618          'byte_pos_start'    => $first_byte_pos,
619          'byte_pos_end'        => $last_byte_pos,
620          'bytes_requested'    => $last_byte_pos - $first_byte_pos + 1,
621          'bytes_total'        => $filesize,
622      );
623  }
624   
625  /**
626  * Increments the download count of all provided attachments
627  *
628  * @param \phpbb\db\driver\driver_interface $db The database object
629  * @param array|int $ids The attach_id of each attachment
630  *
631  * @return null
632  */
633  function phpbb_increment_downloads($db, $ids)
634  {
635      if (!is_array($ids))
636      {
637          $ids = array($ids);
638      }
639   
640      $sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
641          SET download_count = download_count + 1
642          WHERE ' . $db->sql_in_set('attach_id', $ids);
643      $db->sql_query($sql);
644  }
645   
646  /**
647  * Handles authentication when downloading attachments from a post or topic
648  *
649  * @param \phpbb\db\driver\driver_interface $db The database object
650  * @param \phpbb\auth\auth $auth The authentication object
651  * @param int $topic_id The id of the topic that we are downloading from
652  *
653  * @return null
654  */
655  function phpbb_download_handle_forum_auth($db, $auth, $topic_id)
656  {
657      global $phpbb_container;
658   
659      $sql_array = [
660          'SELECT'    => 't.forum_id, t.topic_poster, t.topic_visibility, f.forum_name, f.forum_password, f.parent_id',
661          'FROM'        => [
662              TOPICS_TABLE => 't',
663              FORUMS_TABLE => 'f',
664          ],
665          'WHERE'        => 't.topic_id = ' . (int) $topic_id . '
666              AND t.forum_id = f.forum_id',
667      ];
668   
669      $sql = $db->sql_build_query('SELECT', $sql_array);
670      $result = $db->sql_query($sql);
671      $row = $db->sql_fetchrow($result);
672      $db->sql_freeresult($result);
673   
674      $phpbb_content_visibility = $phpbb_container->get('content.visibility');
675   
676      if ($row && !$phpbb_content_visibility->is_visible('topic', $row['forum_id'], $row))
677      {
678          send_status_line(404, 'Not Found');
679          trigger_error('ERROR_NO_ATTACHMENT');
680      }
681      else if ($row && $auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id']))
682      {
683          if ($row['forum_password'])
684          {
685              // Do something else ... ?
686              login_forum_box($row);
687          }
688      }
689      else
690      {
691          send_status_line(403, 'Forbidden');
692          trigger_error('SORRY_AUTH_VIEW_ATTACH');
693      }
694  }
695   
696  /**
697  * Handles authentication when downloading attachments from PMs
698  *
699  * @param \phpbb\db\driver\driver_interface $db The database object
700  * @param \phpbb\auth\auth $auth The authentication object
701  * @param int $user_id The user id
702  * @param int $msg_id The id of the PM that we are downloading from
703  *
704  * @return null
705  */
706  function phpbb_download_handle_pm_auth($db, $auth, $user_id, $msg_id)
707  {
708      global $phpbb_dispatcher;
709   
710      if (!$auth->acl_get('u_pm_download'))
711      {
712          send_status_line(403, 'Forbidden');
713          trigger_error('SORRY_AUTH_VIEW_ATTACH');
714      }
715   
716      $allowed = phpbb_download_check_pm_auth($db, $user_id, $msg_id);
717   
718      /**
719      * Event to modify PM attachments download auth
720      *
721      * @event core.modify_pm_attach_download_auth
722      * @var    bool    allowed        Whether the user is allowed to download from that PM or not
723      * @var    int        msg_id        The id of the PM to download from
724      * @var    int        user_id        The user id for auth check
725      * @since 3.1.11-RC1
726      */
727      $vars = array('allowed', 'msg_id', 'user_id');
728      extract($phpbb_dispatcher->trigger_event('core.modify_pm_attach_download_auth', compact($vars)));
729   
730      if (!$allowed)
731      {
732          send_status_line(403, 'Forbidden');
733          trigger_error('ERROR_NO_ATTACHMENT');
734      }
735  }
736   
737  /**
738  * Checks whether a user can download from a particular PM
739  *
740  * @param \phpbb\db\driver\driver_interface $db The database object
741  * @param int $user_id The user id
742  * @param int $msg_id The id of the PM that we are downloading from
743  *
744  * @return bool Whether the user is allowed to download from that PM or not
745  */
746  function phpbb_download_check_pm_auth($db, $user_id, $msg_id)
747  {
748      // Check if the attachment is within the users scope...
749      $sql = 'SELECT msg_id
750          FROM ' . PRIVMSGS_TO_TABLE . '
751          WHERE msg_id = ' . (int) $msg_id . '
752              AND (
753                  user_id = ' . (int) $user_id . '
754                  OR author_id = ' . (int) $user_id . '
755              )';
756      $result = $db->sql_query_limit($sql, 1);
757      $allowed = (bool) $db->sql_fetchfield('msg_id');
758      $db->sql_freeresult($result);
759   
760      return $allowed;
761  }
762   
763  /**
764  * Check if the browser is internet explorer version 7+
765  *
766  * @param string $user_agent    User agent HTTP header
767  * @param int $version IE version to check against
768  *
769  * @return bool true if internet explorer version is greater than $version
770  */
771  function phpbb_is_greater_ie_version($user_agent, $version)
772  {
773      if (preg_match('/msie (\d+)/', strtolower($user_agent), $matches))
774      {
775          $ie_version = (int) $matches[1];
776          return ($ie_version > $version);
777      }
778      else
779      {
780          return false;
781      }
782  }
783