Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

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: 09.10.2024, 12:51 - Dateigröße: 19.60 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: public');
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 ($category == ATTACHMENT_CATEGORY_FLASH && $request->variable('view', 0) === 1)
210      {
211          // We use content-disposition: inline for flash files and view=1 to let it correctly play with flash player 10 - any other disposition will fail to play inline
212          header('Content-Disposition: inline');
213      }
214      else
215      {
216          if (empty($user->browser) || ((strpos(strtolower($user->browser), 'msie') !== false) && !phpbb_is_greater_ie_version($user->browser, 7)))
217          {
218              header('Content-Disposition: attachment; ' . header_filename(htmlspecialchars_decode($attachment['real_filename'])));
219              if (empty($user->browser) || (strpos(strtolower($user->browser), 'msie 6.0') !== false))
220              {
221                  header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
222              }
223          }
224          else
225          {
226              header('Content-Disposition: ' . ((strpos($attachment['mimetype'], 'image') === 0) ? 'inline' : 'attachment') . '; ' . header_filename(htmlspecialchars_decode($attachment['real_filename'])));
227              if (phpbb_is_greater_ie_version($user->browser, 7) && (strpos($attachment['mimetype'], 'image') !== 0))
228              {
229                  header('X-Download-Options: noopen');
230              }
231          }
232      }
233   
234      // Close the db connection before sending the file etc.
235      file_gc(false);
236   
237      if (!set_modified_headers($attachment['filetime'], $user->browser))
238      {
239          // We make sure those have to be enabled manually by defining a constant
240          // because of the potential disclosure of full attachment path
241          // in case support for features is absent in the webserver software.
242          if (defined('PHPBB_ENABLE_X_ACCEL_REDIRECT') && PHPBB_ENABLE_X_ACCEL_REDIRECT)
243          {
244              // X-Accel-Redirect - http://wiki.nginx.org/XSendfile
245              header('X-Accel-Redirect: ' . $user->page['root_script_path'] . $upload_dir . '/' . $attachment['physical_filename']);
246              exit;
247          }
248          else if (defined('PHPBB_ENABLE_X_SENDFILE') && PHPBB_ENABLE_X_SENDFILE && !phpbb_http_byte_range($size))
249          {
250              // X-Sendfile - http://blog.lighttpd.net/articles/2006/07/02/x-sendfile
251              // Lighttpd's X-Sendfile does not support range requests as of 1.4.26
252              // and always requires an absolute path.
253              header('X-Sendfile: ' . dirname(__FILE__) . "/../$upload_dir/{$attachment['physical_filename']}");
254              exit;
255          }
256   
257          if ($size)
258          {
259              header("Content-Length: $size");
260          }
261   
262          // Try to deliver in chunks
263          @set_time_limit(0);
264   
265          $fp = @fopen($filename, 'rb');
266   
267          if ($fp !== false)
268          {
269              // Deliver file partially if requested
270              if ($range = phpbb_http_byte_range($size))
271              {
272                  fseek($fp, $range['byte_pos_start']);
273   
274                  send_status_line(206, 'Partial Content');
275                  header('Content-Range: bytes ' . $range['byte_pos_start'] . '-' . $range['byte_pos_end'] . '/' . $range['bytes_total']);
276                  header('Content-Length: ' . $range['bytes_requested']);
277   
278                  // First read chunks
279                  while (!feof($fp) && ftell($fp) < $range['byte_pos_end'] - 8192)
280                  {
281                      echo fread($fp, 8192);
282                  }
283                  // Then, read the remainder
284                  echo fread($fp, $range['bytes_requested'] % 8192);
285              }
286              else
287              {
288                  while (!feof($fp))
289                  {
290                      echo fread($fp, 8192);
291                  }
292              }
293              fclose($fp);
294          }
295          else
296          {
297              @readfile($filename);
298          }
299   
300          flush();
301      }
302   
303      exit;
304  }
305   
306  /**
307  * Get a browser friendly UTF-8 encoded filename
308  */
309  function header_filename($file)
310  {
311      global $request;
312   
313      $user_agent = $request->header('User-Agent');
314   
315      // There be dragons here.
316      // Not many follows the RFC...
317      if (strpos($user_agent, 'MSIE') !== false || strpos($user_agent, 'Konqueror') !== false)
318      {
319          return "filename=" . rawurlencode($file);
320      }
321   
322      // follow the RFC for extended filename for the rest
323      return "filename*=UTF-8''" . rawurlencode($file);
324  }
325   
326  /**
327  * Check if downloading item is allowed
328  */
329  function download_allowed()
330  {
331      global $config, $user, $db, $request;
332   
333      if (!$config['secure_downloads'])
334      {
335          return true;
336      }
337   
338      $url = htmlspecialchars_decode($request->header('Referer'));
339   
340      if (!$url)
341      {
342          return ($config['secure_allow_empty_referer']) ? true : false;
343      }
344   
345      // Split URL into domain and script part
346      $url = @parse_url($url);
347   
348      if ($url === false)
349      {
350          return ($config['secure_allow_empty_referer']) ? true : false;
351      }
352   
353      $hostname = $url['host'];
354      unset($url);
355   
356      $allowed = ($config['secure_allow_deny']) ? false : true;
357      $iplist = array();
358   
359      if (($ip_ary = @gethostbynamel($hostname)) !== false)
360      {
361          foreach ($ip_ary as $ip)
362          {
363              if ($ip)
364              {
365                  $iplist[] = $ip;
366              }
367          }
368      }
369   
370      // Check for own server...
371      $server_name = $user->host;
372   
373      // Forcing server vars is the only way to specify/override the protocol
374      if ($config['force_server_vars'] || !$server_name)
375      {
376          $server_name = $config['server_name'];
377      }
378   
379      if (preg_match('#^.*?' . preg_quote($server_name, '#') . '.*?$#i', $hostname))
380      {
381          $allowed = true;
382      }
383   
384      // Get IP's and Hostnames
385      if (!$allowed)
386      {
387          $sql = 'SELECT site_ip, site_hostname, ip_exclude
388              FROM ' . SITELIST_TABLE;
389          $result = $db->sql_query($sql);
390   
391          while ($row = $db->sql_fetchrow($result))
392          {
393              $site_ip = trim($row['site_ip']);
394              $site_hostname = trim($row['site_hostname']);
395   
396              if ($site_ip)
397              {
398                  foreach ($iplist as $ip)
399                  {
400                      if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($site_ip, '#')) . '$#i', $ip))
401                      {
402                          if ($row['ip_exclude'])
403                          {
404                              $allowed = ($config['secure_allow_deny']) ? false : true;
405                              break 2;
406                          }
407                          else
408                          {
409                              $allowed = ($config['secure_allow_deny']) ? true : false;
410                          }
411                      }
412                  }
413              }
414   
415              if ($site_hostname)
416              {
417                  if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($site_hostname, '#')) . '$#i', $hostname))
418                  {
419                      if ($row['ip_exclude'])
420                      {
421                          $allowed = ($config['secure_allow_deny']) ? false : true;
422                          break;
423                      }
424                      else
425                      {
426                          $allowed = ($config['secure_allow_deny']) ? true : false;
427                      }
428                  }
429              }
430          }
431          $db->sql_freeresult($result);
432      }
433   
434      return $allowed;
435  }
436   
437  /**
438  * Check if the browser has the file already and set the appropriate headers-
439  * @returns false if a resend is in order.
440  */
441  function set_modified_headers($stamp, $browser)
442  {
443      global $request;
444   
445      // let's see if we have to send the file at all
446      $last_load     =  $request->header('If-Modified-Since') ? strtotime(trim($request->header('If-Modified-Since'))) : false;
447   
448      if (strpos(strtolower($browser), 'msie 6.0') === false && !phpbb_is_greater_ie_version($browser, 7))
449      {
450          if ($last_load !== false && $last_load >= $stamp)
451          {
452              send_status_line(304, 'Not Modified');
453              // seems that we need those too ... browsers
454              header('Cache-Control: public');
455              header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT');
456              return true;
457          }
458          else
459          {
460              header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $stamp) . ' GMT');
461          }
462      }
463      return false;
464  }
465   
466  /**
467  * Garbage Collection
468  *
469  * @param bool $exit        Whether to die or not.
470  *
471  * @return null
472  */
473  function file_gc($exit = true)
474  {
475      global $cache, $db;
476   
477      if (!empty($cache))
478      {
479          $cache->unload();
480      }
481   
482      $db->sql_close();
483   
484      if ($exit)
485      {
486          exit;
487      }
488  }
489   
490  /**
491  * HTTP range support (RFC 2616 Section 14.35)
492  *
493  * Allows browsers to request partial file content
494  * in case a download has been interrupted.
495  *
496  * @param int $filesize        the size of the file in bytes we are about to deliver
497  *
498  * @return mixed        false if the whole file has to be delivered
499  *                    associative array on success
500  */
501  function phpbb_http_byte_range($filesize)
502  {
503      // Only call find_range_request() once.
504      static $request_array;
505   
506      if (!$filesize)
507      {
508          return false;
509      }
510   
511      if (!isset($request_array))
512      {
513          $request_array = phpbb_find_range_request();
514      }
515   
516      return (empty($request_array)) ? false : phpbb_parse_range_request($request_array, $filesize);
517  }
518   
519  /**
520  * Searches for HTTP range request in request headers.
521  *
522  * @return mixed        false if no request found
523  *                    array of strings containing the requested ranges otherwise
524  *                    e.g. array(0 => '0-0', 1 => '123-125')
525  */
526  function phpbb_find_range_request()
527  {
528      global $request;
529   
530      $value = $request->header('Range');
531   
532      // Make sure range request starts with "bytes="
533      if (strpos($value, 'bytes=') === 0)
534      {
535          // Strip leading 'bytes='
536          // Multiple ranges can be separated by a comma
537          return explode(',', substr($value, 6));
538      }
539   
540      return false;
541  }
542   
543  /**
544  * Analyses a range request array.
545  *
546  * A range request can contain multiple ranges,
547  * we however only handle the first request and
548  * only support requests from a given byte to the end of the file.
549  *
550  * @param array    $request_array    array of strings containing the requested ranges
551  * @param int    $filesize        the full size of the file in bytes that has been requested
552  *
553  * @return mixed        false if the whole file has to be delivered
554  *                    associative array on success
555  *                        byte_pos_start        the first byte position, can be passed to fseek()
556  *                        byte_pos_end        the last byte position
557  *                        bytes_requested        the number of bytes requested
558  *                        bytes_total            the full size of the file
559  */
560  function phpbb_parse_range_request($request_array, $filesize)
561  {
562      $first_byte_pos    = -1;
563      $last_byte_pos    = -1;
564   
565      // Go through all ranges
566      foreach ($request_array as $range_string)
567      {
568          $range = explode('-', trim($range_string));
569   
570          // "-" is invalid, "0-0" however is valid and means the very first byte.
571          if (sizeof($range) != 2 || $range[0] === '' && $range[1] === '')
572          {
573              continue;
574          }
575   
576          // Substitute defaults
577          if ($range[0] === '')
578          {
579              $range[0] = 0;
580          }
581   
582          if ($range[1] === '')
583          {
584              $range[1] = $filesize - 1;
585          }
586   
587          if ($last_byte_pos >= 0 && $last_byte_pos + 1 != $range[0])
588          {
589              // We only support contiguous ranges, no multipart stuff :(
590              return false;
591          }
592   
593          if ($range[1] && $range[1] < $range[0])
594          {
595              // The requested range contains 0 bytes.
596              continue;
597          }
598   
599          // Return bytes from $range[0] to $range[1]
600          if ($first_byte_pos < 0)
601          {
602              $first_byte_pos    = (int) $range[0];
603          }
604   
605          $last_byte_pos    = (int) $range[1];
606   
607          if ($first_byte_pos >= $filesize)
608          {
609              // Requested range not satisfiable
610              return false;
611          }
612   
613          // Adjust last-byte-pos if it is absent or greater than the content.
614          if ($range[1] === '' || $last_byte_pos >= $filesize)
615          {
616              $last_byte_pos = $filesize - 1;
617          }
618      }
619   
620      if ($first_byte_pos < 0 || $last_byte_pos < 0)
621      {
622          return false;
623      }
624   
625      return array(
626          'byte_pos_start'    => $first_byte_pos,
627          'byte_pos_end'        => $last_byte_pos,
628          'bytes_requested'    => $last_byte_pos - $first_byte_pos + 1,
629          'bytes_total'        => $filesize,
630      );
631  }
632   
633  /**
634  * Increments the download count of all provided attachments
635  *
636  * @param \phpbb\db\driver\driver_interface $db The database object
637  * @param array|int $ids The attach_id of each attachment
638  *
639  * @return null
640  */
641  function phpbb_increment_downloads($db, $ids)
642  {
643      if (!is_array($ids))
644      {
645          $ids = array($ids);
646      }
647   
648      $sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
649          SET download_count = download_count + 1
650          WHERE ' . $db->sql_in_set('attach_id', $ids);
651      $db->sql_query($sql);
652  }
653   
654  /**
655  * Handles authentication when downloading attachments from a post or topic
656  *
657  * @param \phpbb\db\driver\driver_interface $db The database object
658  * @param \phpbb\auth\auth $auth The authentication object
659  * @param int $topic_id The id of the topic that we are downloading from
660  *
661  * @return null
662  */
663  function phpbb_download_handle_forum_auth($db, $auth, $topic_id)
664  {
665      $sql_array = array(
666          'SELECT'    => 't.topic_visibility, t.forum_id, f.forum_name, f.forum_password, f.parent_id',
667          'FROM'        => array(
668              TOPICS_TABLE => 't',
669              FORUMS_TABLE => 'f',
670          ),
671          'WHERE'    => 't.topic_id = ' . (int) $topic_id . '
672              AND t.forum_id = f.forum_id',
673      );
674   
675      $sql = $db->sql_build_query('SELECT', $sql_array);
676      $result = $db->sql_query($sql);
677      $row = $db->sql_fetchrow($result);
678      $db->sql_freeresult($result);
679   
680      if ($row && $row['topic_visibility'] != ITEM_APPROVED && !$auth->acl_get('m_approve', $row['forum_id']))
681      {
682          send_status_line(404, 'Not Found');
683          trigger_error('ERROR_NO_ATTACHMENT');
684      }
685      else if ($row && $auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id']))
686      {
687          if ($row['forum_password'])
688          {
689              // Do something else ... ?
690              login_forum_box($row);
691          }
692      }
693      else
694      {
695          send_status_line(403, 'Forbidden');
696          trigger_error('SORRY_AUTH_VIEW_ATTACH');
697      }
698  }
699   
700  /**
701  * Handles authentication when downloading attachments from PMs
702  *
703  * @param \phpbb\db\driver\driver_interface $db The database object
704  * @param \phpbb\auth\auth $auth The authentication object
705  * @param int $user_id The user id
706  * @param int $msg_id The id of the PM that we are downloading from
707  *
708  * @return null
709  */
710  function phpbb_download_handle_pm_auth($db, $auth, $user_id, $msg_id)
711  {
712      global $phpbb_dispatcher;
713   
714      if (!$auth->acl_get('u_pm_download'))
715      {
716          send_status_line(403, 'Forbidden');
717          trigger_error('SORRY_AUTH_VIEW_ATTACH');
718      }
719   
720      $allowed = phpbb_download_check_pm_auth($db, $user_id, $msg_id);
721   
722      /**
723      * Event to modify PM attachments download auth
724      *
725      * @event core.modify_pm_attach_download_auth
726      * @var    bool    allowed        Whether the user is allowed to download from that PM or not
727      * @var    int        msg_id        The id of the PM to download from
728      * @var    int        user_id        The user id for auth check
729      * @since 3.1.11-RC1
730      */
731      $vars = array('allowed', 'msg_id', 'user_id');
732      extract($phpbb_dispatcher->trigger_event('core.modify_pm_attach_download_auth', compact($vars)));
733   
734      if (!$allowed)
735      {
736          send_status_line(403, 'Forbidden');
737          trigger_error('ERROR_NO_ATTACHMENT');
738      }
739  }
740   
741  /**
742  * Checks whether a user can download from a particular PM
743  *
744  * @param \phpbb\db\driver\driver_interface $db The database object
745  * @param int $user_id The user id
746  * @param int $msg_id The id of the PM that we are downloading from
747  *
748  * @return bool Whether the user is allowed to download from that PM or not
749  */
750  function phpbb_download_check_pm_auth($db, $user_id, $msg_id)
751  {
752      // Check if the attachment is within the users scope...
753      $sql = 'SELECT msg_id
754          FROM ' . PRIVMSGS_TO_TABLE . '
755          WHERE msg_id = ' . (int) $msg_id . '
756              AND (
757                  user_id = ' . (int) $user_id . '
758                  OR author_id = ' . (int) $user_id . '
759              )';
760      $result = $db->sql_query_limit($sql, 1);
761      $allowed = (bool) $db->sql_fetchfield('msg_id');
762      $db->sql_freeresult($result);
763   
764      return $allowed;
765  }
766   
767  /**
768  * Check if the browser is internet explorer version 7+
769  *
770  * @param string $user_agent    User agent HTTP header
771  * @param int $version IE version to check against
772  *
773  * @return bool true if internet explorer version is greater than $version
774  */
775  function phpbb_is_greater_ie_version($user_agent, $version)
776  {
777      if (preg_match('/msie (\d+)/', strtolower($user_agent), $matches))
778      {
779          $ie_version = (int) $matches[1];
780          return ($ie_version > $version);
781      }
782      else
783      {
784          return false;
785      }
786  }
787