zhensolid 1 năm trước cách đây
mục cha
commit
3c0aa3aaf7
41 tập tin đã thay đổi với 3219 bổ sung0 xóa
  1. 1 0
      .htaccess
  2. 1 0
      .user.ini
  3. 7 0
      404.html
  4. 341 0
      COPYING
  5. 51 0
      README
  6. BIN
      VeraBd.ttf
  7. 88 0
      config.php
  8. 43 0
      css/custom.css
  9. 311 0
      graph.php
  10. 410 0
      graph_svg.php
  11. 39 0
      index.html
  12. 220 0
      index.php
  13. 20 0
      js/custom.js
  14. 81 0
      json.php
  15. 39 0
      lang/br.php
  16. 40 0
      lang/cn.php
  17. 39 0
      lang/cs.php
  18. 40 0
      lang/de.php
  19. 39 0
      lang/en.php
  20. 41 0
      lang/es.php
  21. 39 0
      lang/fi.php
  22. 39 0
      lang/fr.php
  23. 39 0
      lang/hr.php
  24. 39 0
      lang/hu.php
  25. 39 0
      lang/it.php
  26. 40 0
      lang/nl.php
  27. 39 0
      lang/no.php
  28. 39 0
      lang/pl.php
  29. 39 0
      lang/ru.php
  30. 39 0
      lang/sk.php
  31. 15 0
      localize.php
  32. 21 0
      themes/dark/style.css
  33. 16 0
      themes/dark/theme.php
  34. 170 0
      themes/espresso/style.css
  35. 17 0
      themes/espresso/theme.php
  36. 183 0
      themes/light/style.css
  37. 15 0
      themes/light/theme.php
  38. 170 0
      themes/red/style.css
  39. 16 0
      themes/red/theme.php
  40. 124 0
      vera_copyright.txt
  41. 230 0
      vnstat.php

+ 1 - 0
.htaccess

@@ -0,0 +1 @@
+ 

+ 1 - 0
.user.ini

@@ -0,0 +1 @@
+open_basedir=/home/www/vnstat2-php-frontend-master/:/tmp/

+ 7 - 0
404.html

@@ -0,0 +1,7 @@
+<html>
+<head><title>404 Not Found</title></head>
+<body>
+<center><h1>404 Not Found</h1></center>
+<hr><center>nginx</center>
+</body>
+</html>

+ 341 - 0
COPYING

@@ -0,0 +1,341 @@
+GNU GENERAL PUBLIC LICENSE
+               Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+            GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+             END OF TERMS AND CONDITIONS
+
+        How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+

+ 51 - 0
README

@@ -0,0 +1,51 @@
+0. WHAT IS IT?
+
+This is a PHP frontend end to vnstat, a network traffic logger.
+Since vnstat is console mode only I created this script to
+make a 'nice' report of the data collected by vnstat.
+For more information about vnstat check out http://humdi.net/vnstat/
+For updates to this script check http://www.sqweek.com
+
+
+1. REQUIREMENTS 
+
+- vnstat setup and collecting data
+- webserver with PHP
+- php-gd extension installed for PNG graphs
+
+
+2. INSTALL
+
+Installation should be really straightforward:
+
+Put the files from this package somewhere inside the webroot of
+your webserver. Then edit the few configuration options in config.php
+to suit your situation and your good to go. The various options are
+explained in config.php.
+
+
+3. LICENSE
+
+vnstat PHP frontend 2.0.0
+Copyright (c)2006-2011  Bjorge Dijkstra (bjd@jooz.net)
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+NOTE:
+  The Truetype font file VeraBd.ttf is copyright by Bitstream Inc. 
+  See vera_copyright.txt for more information.
+
+

BIN
VeraBd.ttf


+ 88 - 0
config.php

@@ -0,0 +1,88 @@
+<?php
+    //
+    // vnStat PHP frontend (c)2006-2010 Bjorge Dijkstra (bjd@jooz.net)
+    //
+    // This program is free software; you can redistribute it and/or modify
+    // it under the terms of the GNU General Public License as published by
+    // the Free Software Foundation; either version 2 of the License, or
+    // (at your option) any later version.
+    //
+    // This program is distributed in the hope that it will be useful,
+    // but WITHOUT ANY WARRANTY; without even the implied warranty of
+    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    // GNU General Public License for more details.
+    //
+    // You should have received a copy of the GNU General Public License
+    // along with this program; if not, write to the Free Software
+    // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+    //
+    //
+    // see file COPYING or at http://www.gnu.org/licenses/gpl.html
+    // for more information.
+    //
+    error_reporting(E_ALL | E_NOTICE);
+
+    //
+    // configuration parameters
+    //
+    // edit these to reflect your particular situation
+    //
+    $locale = 'zh_CN.utf8';
+    $language = 'cn';
+
+
+    // Set local timezone
+    date_default_timezone_set("Asia/Shanghai");
+
+    // list of network interfaces monitored by vnStat
+    // $iface_list = array('enp06s', 'sixxs');
+    $iface_list = array('enp0s6','docker0');
+
+    //
+    // optional names for interfaces
+    // if there's no name set for an interface then the interface identifier
+    // will be displayed instead
+    //
+    $iface_title['enp0s6'] = '内部网络';
+    $iface_title['docker0'] = 'Docker';
+
+    //
+    // There are two possible sources for vnstat data. If the $vnstat_bin
+    // variable is set then vnstat is called directly from the PHP script
+    // to get the interface data.
+    //
+    // The other option is to periodically dump the vnstat interface data to
+    // a file (e.g. by a cronjob). In that case the $vnstat_bin variable
+    // must be cleared and set $data_dir to the location where the dumps
+    // are stored. Dumps must be named 'vnstat_dump_$iface'.
+    //
+    // You can generate vnstat dumps with the command:
+    //   vnstat --json -i $iface > /path/to/data_dir/vnstat_dump_$iface
+    //
+    $vnstat_bin = '/usr/bin/vnstat';
+    $data_dir = './dumps';
+
+    // graphics format to use: svg or png
+    $graph_format='svg';
+
+    // preferred byte notation. null auto chooses. otherwise use one of
+    // 'TB','GB','MB','KB'
+    $byte_notation = null;
+
+    // Font to use for PNG graphs
+    define('GRAPH_FONT',dirname(__FILE__).'/VeraBd.ttf');
+
+    // Font to use for SVG graphs
+    define('SVG_FONT', 'Verdana');
+
+    // Default theme
+    define('DEFAULT_COLORSCHEME', 'light');
+    
+    // SVG Depth scaling factor
+    define('SVG_DEPTH_SCALING', 1);
+
+    // 添加新的主题支持
+    define('ENABLE_DARK_MODE', true);
+    define('ENABLE_ANIMATIONS', true);
+
+?>

+ 43 - 0
css/custom.css

@@ -0,0 +1,43 @@
+/* 现代化卡片样式 */
+.traffic-card {
+    background: white;
+    border-radius: 10px;
+    box-shadow: 0 2px 15px rgba(0,0,0,0.1);
+    padding: 20px;
+    margin: 15px 0;
+    transition: transform 0.3s ease;
+}
+
+.traffic-card:hover {
+    transform: translateY(-5px);
+}
+
+/* 响应式表格 */
+.traffic-table {
+    width: 100%;
+    border-collapse: separate;
+    border-spacing: 0;
+    background: white;
+    border-radius: 8px;
+    overflow: hidden;
+}
+
+/* 图表容器美化 */
+.chart-container {
+    background: white;
+    padding: 15px;
+    border-radius: 10px;
+    box-shadow: 0 2px 10px rgba(0,0,0,0.05);
+}
+
+/* 深色模式支持 */
+@media (prefers-color-scheme: dark) {
+    body {
+        background-color: #1a1a1a;
+        color: #ffffff;
+    }
+    
+    .traffic-card {
+        background: #2d2d2d;
+    }
+} 

+ 311 - 0
graph.php

@@ -0,0 +1,311 @@
+<?php
+    //
+    // vnStat PHP frontend (c)2006-2010 Bjorge Dijkstra (bjd@jooz.net)
+    //
+    // This program is free software; you can redistribute it and/or modify
+    // it under the terms of the GNU General Public License as published by
+    // the Free Software Foundation; either version 2 of the License, or
+    // (at your option) any later version.
+    //
+    // This program is distributed in the hope that it will be useful,
+    // but WITHOUT ANY WARRANTY; without even the implied warranty of
+    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    // GNU General Public License for more details.
+    //
+    // You should have received a copy of the GNU General Public License
+    // along with this program; if not, write to the Free Software
+    // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+    //
+    //
+    // see file COPYING or at http://www.gnu.org/licenses/gpl.html
+    // for more information.
+    //
+    require 'config.php';
+    require 'localize.php';
+    require 'vnstat.php';
+
+    validate_input();
+
+    require "./themes/$style/theme.php";
+
+    function allocate_color($im, $colors)
+    {
+	return imagecolorallocatealpha($im, $colors[0], $colors[1], $colors[2], $colors[3]);
+    }
+
+    function init_image()
+    {
+        global $im, $xlm, $xrm, $ytm, $ybm, $iw, $ih,$graph, $cl, $iface, $colorscheme, $style;
+
+        if ($graph == 'none')
+            return;
+
+        //
+        // image object
+        //
+        $xlm = 70;
+        $xrm = 20;
+        $ytm = 35;
+        $ybm = 60;
+        if ($graph == 'small')
+        {
+            $iw = 300 + $xrm + $xlm;
+            $ih = 100 + $ytm + $ybm;
+        }
+        else
+        {
+            $iw = 600 + $xrm + $xlm;
+            $ih = 200 + $ytm + $ybm;
+        }
+
+        $im = imagecreatetruecolor($iw,$ih);
+
+        //
+        // colors
+        //
+	$cs = $colorscheme;
+	$cl['image_background'] = allocate_color($im, $cs['image_background']);
+	$cl['background'] = allocate_color($im, $cs['graph_background']);
+	$cl['background_2'] = allocate_color($im, $cs['graph_background_2']);
+        $cl['grid_stipple_1'] = allocate_color($im, $cs['grid_stipple_1']);
+        $cl['grid_stipple_2'] = allocate_color($im, $cs['grid_stipple_2']);
+        $cl['text'] = allocate_color($im, $cs['text']);
+        $cl['border'] = allocate_color($im, $cs['border']);
+        $cl['rx'] = allocate_color($im, $cs['rx']);
+        $cl['rx_border'] = allocate_color($im, $cs['rx_border']);
+        $cl['tx'] = allocate_color($im, $cs['tx']);
+        $cl['tx_border'] = allocate_color($im, $cs['tx_border']);
+
+        imagefilledrectangle($im,0,0,$iw,$ih,$cl['image_background']);
+	imagefilledrectangle($im,$xlm,$ytm,$iw-$xrm,$ih-$ybm, $cl['background']);
+
+	$x_step = ($iw - $xlm - $xrm) / 12;
+	$depth = ($x_step / 8) + 4;
+	imagefilledpolygon($im, array($xlm, $ytm, $xlm, $ih - $ybm, $xlm - $depth, $ih - $ybm + $depth, $xlm - $depth, $ytm + $depth), 4, $cl['background_2']);
+	imagefilledpolygon($im, array($xlm, $ih - $ybm, $xlm - $depth, $ih - $ybm + $depth, $iw - $xrm - $depth, $ih - $ybm  + $depth, $iw - $xrm, $ih - $ybm), 4, $cl['background_2']);
+
+	// draw title
+	$text = T('Traffic data for')." $iface";
+ 	$bbox = imagettfbbox(10, 0, GRAPH_FONT, $text);
+	$textwidth = $bbox[2] - $bbox[0];
+	imagettftext($im, 10, 0, ($iw-$textwidth)/2, ($ytm/2), $cl['text'], GRAPH_FONT, $text);
+
+    }
+
+    function draw_border()
+    {
+        global $im,$cl,$iw,$ih;
+
+        imageline($im,     0,    0,$iw-1,    0, $cl['border']);
+        imageline($im,     0,$ih-1,$iw-1,$ih-1, $cl['border']);
+        imageline($im,     0,    0,    0,$ih-1, $cl['border']);
+        imageline($im, $iw-1,    0,$iw-1,$ih-1, $cl['border']);
+    }
+
+    function draw_grid($x_ticks, $y_ticks)
+    {
+        global $im, $cl, $iw, $ih, $xlm, $xrm, $ytm, $ybm;
+        $x_step = ($iw - $xlm - $xrm) / ($x_ticks ?: 1);
+        $y_step = ($ih - $ytm - $ybm) / $y_ticks;
+
+	$depth = 10;//($x_step / 8) + 4;
+
+        $ls = array($cl['grid_stipple_1'],$cl['grid_stipple_2']);
+        imagesetstyle($im, $ls);
+        for ($i=$xlm;$i<=($iw-$xrm); $i += $x_step)
+        {
+            imageline($im, $i, $ytm, $i, $ih - $ybm, IMG_COLOR_STYLED);
+	    imageline($im, $i, $ih - $ybm, $i - $depth, $ih - $ybm + $depth, IMG_COLOR_STYLED);
+        }
+        for ($i=$ytm;$i<=($ih-$ybm); $i += $y_step)
+        {
+            imageline($im, $xlm, $i, $iw - $xrm, $i, IMG_COLOR_STYLED);
+	    imageline($im, $xlm, $i, $xlm - $depth, $i + $depth, IMG_COLOR_STYLED);
+        }
+        imageline($im, $xlm, $ytm, $xlm, $ih - $ybm, $cl['border']);
+        imageline($im, $xlm, $ih - $ybm, $iw - $xrm, $ih - $ybm, $cl['border']);
+    }
+
+    function draw_data($data)
+    {
+        global $im,$cl,$iw,$ih,$xlm,$xrm,$ytm,$ybm;
+
+        sort($data);
+
+        $x_ticks = count($data);
+        $y_ticks = 10;
+        $y_scale = 1;
+        $prescale = 1;
+        $unit = 'K';
+        $offset = 0;
+        $gr_h = $ih - $ytm - $ybm;
+        $x_step = ($iw - $xlm - $xrm) / ($x_ticks ?: 1);
+        $y_step = ($ih - $ytm - $ybm) / $y_ticks;
+        $bar_w = ($x_step / 2);
+
+        // 找出最大值
+        $low = 99999999999;
+        $high = 0;
+        for ($i=0; $i<$x_ticks; $i++)
+        {
+            if ($data[$i]['rx'] < $low)
+                $low = $data[$i]['rx'];
+            if ($data[$i]['tx'] < $low)
+                $low = $data[$i]['tx'];
+            if ($data[$i]['rx'] > $high)
+                $high = $data[$i]['rx'];
+            if ($data[$i]['tx'] > $high)
+                $high = $data[$i]['tx'];
+        }
+
+        // 修改这里的单位转换逻辑
+        $high = $high * 1.2; // 增加20%余量
+        
+        if ($high < 1024) {
+            $unit = 'K';
+        } else if ($high < 1048576) { // 1024 * 1024
+            $unit = 'M';
+            $prescale = 1024;
+            $high = $high / 1024;
+        } else if ($high < 1073741824) { // 1024 * 1024 * 1024
+            $unit = 'G';
+            $prescale = 1048576;
+            $high = $high / 1048576;
+        } else {
+            $unit = 'T';
+            $prescale = 1073741824;
+            $high = $high / 1073741824;
+        }
+
+        // 计算合适的刻度
+        $y_scale = ceil($high / $y_ticks);
+        
+        // 确保最小刻度
+        if ($y_scale < 1) {
+            $y_scale = 1;
+        }
+
+        draw_grid($x_ticks, $y_ticks);
+
+        //
+        // graph scale factor (per pixel)
+        //
+	imagesetthickness($im, 1);
+        $sf = ($prescale * $y_scale * $y_ticks) / $gr_h;
+
+        if (count($data) == 0)
+        {
+            $text = T('no data available');
+	    $bbox = imagettfbbox(10, 0, GRAPH_FONT, $text);
+	    $textwidth = $bbox[2] - $bbox[0];
+	    imagettftext($im, 10, 0, ($iw-$textwidth)/2, $ytm + 80, $cl['text'], GRAPH_FONT, $text);
+        }
+        else
+        {
+            //
+            // draw bars
+            //
+            for ($i=0; $i<$x_ticks; $i++)
+            {
+        	$x = $xlm + ($i * $x_step);
+        	$y = $ytm + ($ih - $ytm - $ybm) - (($data[$i]['rx'] - $offset) / $sf);
+
+		$depth = $x_step / 8;
+		$space = 0;
+
+		$x1 = $x;
+		$y1 = $y;
+		$x2 = $x + $bar_w - $space;
+		$y2 = $ih - $ybm;
+
+        	imagefilledrectangle($im, $x1, $y1, $x2, $y2, $cl['rx']);
+		imagerectangle($im, $x1, $y1, $x2, $y2, $cl['rx_border']);
+
+		imagefilledrectangle($im, $x1 - $depth, $y1 + $depth, $x2 -$depth, $y2 + $depth, $cl['rx']);
+		imagerectangle($im, $x1 - $depth, $y1 + $depth, $x2 - $depth, $y2 + $depth, $cl['rx_border']);
+
+		imagefilledpolygon($im, array($x1, $y1, $x2, $y1, $x2 - $depth, $y1 + $depth, $x1 - $depth, $y1 + $depth), 4, $cl['rx']);
+		imagepolygon($im, array($x1, $y1, $x2, $y1, $x2 - $depth, $y1 + $depth, $x1 - $depth, $y1 + $depth), 4, $cl['rx_border']);
+		imagefilledpolygon($im, array($x2, $y1, $x2, $y2, $x2 - $depth, $y2 + $depth, $x2 - $depth, $y1 + $depth), 4, $cl['rx']);
+		imagepolygon($im, array($x2, $y1, $x2, $y2, $x2 - $depth, $y2 + $depth, $x2 - $depth, $y1 + $depth), 4, $cl['rx_border']);
+
+        	$y1 = $ytm + ($ih - $ytm - $ybm) - (($data[$i]['tx'] - $offset) / $sf);
+		$x1 = $x1 + $bar_w;
+		$x2 = $x2 + $bar_w;
+
+        	imagefilledrectangle($im, $x1, $y1, $x2, $y2, $cl['tx']);
+		imagerectangle($im, $x1, $y1, $x2, $y2, $cl['tx_border']);
+
+        	imagefilledrectangle($im, $x1 - $depth, $y1 + $depth, $x2 - $depth, $y2 + $depth, $cl['tx']);
+		imagerectangle($im, $x1 - $depth, $y1 + $depth, $x2 - $depth, $y2 + $depth, $cl['tx_border']);
+
+		imagefilledpolygon($im, array($x1, $y1, $x2, $y1, $x2 - $depth, $y1 + $depth, $x1 - $depth, $y1 + $depth), 4, $cl['tx']);
+		imagepolygon($im, array($x1, $y1, $x2, $y1, $x2 - $depth, $y1 + $depth, $x1 - $depth, $y1 + $depth), 4, $cl['tx_border']);
+		imagefilledpolygon($im, array($x2, $y1, $x2, $y2, $x2 - $depth, $y2 + $depth, $x2 - $depth, $y1 + $depth), 4, $cl['tx']);
+		imagepolygon($im, array($x2, $y1, $x2, $y2, $x2 - $depth, $y2 + $depth, $x2 - $depth, $y1 + $depth), 4, $cl['tx_border']);
+            }
+
+            //
+            // axis labels
+            //
+            for ($i=0; $i<=$y_ticks; $i++)
+            {
+                $label = ($i * $y_scale).$unit;
+		$bbox = imagettfbbox(8, 0, GRAPH_FONT, $label);
+		$textwidth = $bbox[2] - $bbox[0];
+		imagettftext($im, 8, 0, $xlm - $textwidth - 16, ($ih - $ybm) - ($i * $y_step) + 8 + $depth, $cl['text'], GRAPH_FONT, $label);
+            }
+
+            for ($i=0; $i<$x_ticks; $i++)
+            {
+                $label = $data[$i]['img_label'];
+		$bbox = imagettfbbox(9, 0, GRAPH_FONT, $label);
+		$textwidth = $bbox[2] - $bbox[0];
+		imagettftext($im, 9, 0, $xlm + ($i * $x_step) + ($x_step / 2) - ($textwidth / 2) - $depth - 4, $ih - $ybm + 20 + $depth, $cl['text'], GRAPH_FONT, $label);
+            }
+        }
+
+        draw_border();
+
+
+        //
+        // legend
+        //
+        imagefilledrectangle($im, $xlm, $ih-$ybm+39, $xlm+8,$ih-$ybm+47,$cl['rx']);
+        imagerectangle($im, $xlm, $ih-$ybm+39, $xlm+8,$ih-$ybm+47,$cl['text']);
+	imagettftext($im, 8,0, $xlm+14, $ih-$ybm+48,$cl['text'], GRAPH_FONT,T('bytes in'));
+
+        imagefilledrectangle($im, $xlm+120 , $ih-$ybm+39, $xlm+128,$ih-$ybm+47,$cl['tx']);
+        imagerectangle($im, $xlm+120, $ih-$ybm+39, $xlm+128,$ih-$ybm+47,$cl['text']);
+	imagettftext($im, 8,0, $xlm+134, $ih-$ybm+48,$cl['text'], GRAPH_FONT,T('bytes out'));
+    }
+
+    function output_image()
+    {
+        global $page,$hour,$day,$month,$im,$iface;
+
+        if ($page == 'summary')
+            return;
+
+        init_image();
+
+        if ($page == 'h')
+        {
+            draw_data($hour);
+        }
+        else if ($page == 'd')
+        {
+            draw_data($day);
+        }
+        else if ($page == 'm')
+        {
+            draw_data($month);
+        }
+
+        header('Content-type: image/png');
+        imagepng($im);
+    }
+
+    get_vnstat_data();
+    output_image();
+?>

+ 410 - 0
graph_svg.php

@@ -0,0 +1,410 @@
+<?php
+    //
+    // vnStat PHP frontend (c)2006-2010 Bjorge Dijkstra (bjd@jooz.net)
+    //
+    // This program is free software; you can redistribute it and/or modify
+    // it under the terms of the GNU General Public License as published by
+    // the Free Software Foundation; either version 2 of the License, or
+    // (at your option) any later version.
+    //
+    // This program is distributed in the hope that it will be useful,
+    // but WITHOUT ANY WARRANTY; without even the implied warranty of
+    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    // GNU General Public License for more details.
+    //
+    // You should have received a copy of the GNU General Public License
+    // along with this program; if not, write to the Free Software
+    // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+    //
+    //
+    // see file COPYING or at http://www.gnu.org/licenses/gpl.html
+    // for more information.
+    //
+    require 'config.php';
+    require 'localize.php';
+    require 'vnstat.php';
+
+    validate_input();
+
+    require "./themes/$style/theme.php";
+
+    function svg_create($width, $height)
+    {
+	header('Content-type: image/svg+xml');
+	print "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
+	print "<svg width=\"$width\" height=\"$height\" version=\"1.2\" baseProfile=\"tiny\" xmlns=\"http://www.w3.org/2000/svg\">\n";
+	print "<g style=\"shape-rendering: crispEdges\">\n";
+    }
+
+    function svg_end()
+    {
+	print "</g>\n";
+	print "</svg>\n";
+    }
+
+    function svg_options($options)
+    {
+	foreach ($options as $key => $value) {
+	    print "$key=\"$value\" ";
+	}
+    }
+
+    function svg_group($options)
+    {
+	print "<g ";
+	svg_options($options);
+	print ">\n";
+    }
+
+    function svg_group_end()
+    {
+	print "</g>\n";
+    }
+
+    function svg_text($x, $y, $text, $options = array())
+    {
+	printf("<text x=\"%F\" y=\"%F\" ", $x, $y);
+	svg_options($options);
+	print ">$text</text>\n";
+    }
+
+    function svg_line($x1, $y1, $x2, $y2, $options = array())
+    {
+	printf("<line x1=\"%F\" y1=\"%F\" x2=\"%F\" y2=\"%F\" ", $x1, $y1, $x2, $y2);
+	svg_options($options);
+	print "/>\n";
+    }
+
+    function svg_rect($x, $y, $w, $h, $options = array())
+    {
+	printf("<rect x=\"%F\" y=\"%F\" width=\"%F\" height=\"%F\" ", $x, $y, $w, $h);
+	svg_options($options);
+	print "/>\n";
+    }
+
+    function svg_poly($points, $options = array())
+    {
+       print "<polygon points=\"";
+       for ($p = 0; $p < count($points); $p += 2) {
+	  printf("%F,%F ", $points[$p], $points[$p+1]);
+       }
+       svg_options($options);
+       print "\"/>\n";
+    }
+
+    function allocate_color($colors)
+    {
+	$col['rgb'] = sprintf("#%02X%02X%02X", $colors[0], $colors[1], $colors[2]);
+	$col['opacity'] = sprintf("%F", (127 - $colors[3]) / 127);
+	return $col;
+    }
+
+    function init_image()
+    {
+        global $xlm, $xrm, $ytm, $ybm, $iw, $ih,$graph, $cl, $iface, $colorscheme, $style;
+
+        if ($graph == 'none')
+            return;
+
+        //
+        // image object
+        //
+        $xlm = 70;
+        $xrm = 20;
+        $ytm = 35;
+        $ybm = 60;
+        if ($graph == 'small')
+        {
+            $iw = 300 + $xrm + $xlm;
+            $ih = 100 + $ytm + $ybm;
+        }
+        else
+        {
+            $iw = 600 + $xrm + $xlm;
+            $ih = 200 + $ytm + $ybm;
+        }
+
+	svg_create($iw, $ih);
+
+        //
+        // colors
+        //
+	$cs = $colorscheme;
+	$cl['image_background'] = allocate_color($cs['image_background']);
+	$cl['background'] = allocate_color($cs['graph_background']);
+	$cl['background_2'] = allocate_color($cs['graph_background_2']);
+        $cl['grid_stipple_1'] = allocate_color($cs['grid_stipple_1']);
+        $cl['grid_stipple_2'] = allocate_color($cs['grid_stipple_2']);
+        $cl['text'] = allocate_color($cs['text']);
+        $cl['border'] = allocate_color($cs['border']);
+        $cl['rx'] = allocate_color($cs['rx']);
+        $cl['rx_border'] = allocate_color($cs['rx_border']);
+        $cl['tx'] = allocate_color($cs['tx']);
+        $cl['tx_border'] = allocate_color($cs['tx_border']);
+
+        svg_rect(0, 0, $iw, $ih, array( 'stroke' => 'none', 'stroke-width' => 0, 'fill' => $cl['image_background']['rgb']) );
+	svg_rect($xlm, $ytm, $iw-$xrm-$xlm, $ih-$ybm-$ytm, array( 'stroke' => 'none', 'stroke-width' => 0, 'fill' => $cl['background']['rgb']) );
+
+	$depth = 12*SVG_DEPTH_SCALING;
+	svg_group( array( 'stroke' => 'none', 'stroke-width' => 0, 'fill' => $cl['background_2']['rgb'], 'fill-opacity' => $cl['background_2']['opacity']) );
+	svg_poly(array($xlm, $ytm, $xlm, $ih - $ybm, $xlm - $depth, $ih - $ybm + $depth, $xlm - $depth, $ytm + $depth));
+	svg_poly(array($xlm, $ih - $ybm, $xlm - $depth, $ih - $ybm + $depth, $iw - $xrm - $depth, $ih - $ybm  + $depth, $iw - $xrm, $ih - $ybm));
+	svg_group_end();
+
+	// draw title
+	$text = T('Traffic data for')." $iface";
+	svg_text($iw / 2, ($ytm / 2), $text, array( 'stroke' => 'none', 'fill' => $cl['text']['rgb'],'stroke-width' => 0, 'font-family' => SVG_FONT, 'font-weight' => 'bold', 'text-anchor' => 'middle' ));
+    }
+
+    function draw_border()
+    {
+        global $cl, $iw, $ih;
+	svg_rect(1, 1, $iw-2, $ih-2, array( 'stroke' => $cl['border']['rgb'], 'stroke-opacity' => $cl['border']['opacity'], 'stroke-width' => 1, 'fill' => 'none') );
+    }
+
+    function draw_grid($x_ticks, $y_ticks)
+    {
+        global $cl, $iw, $ih, $xlm, $xrm, $ytm, $ybm;
+        $x_step = ($iw - $xlm - $xrm) / ($x_ticks ?: 1);
+        $y_step = ($ih - $ytm - $ybm) / $y_ticks;
+
+	$depth = 12*SVG_DEPTH_SCALING;
+
+	svg_group( array( 'stroke' => $cl['grid_stipple_1']['rgb'], 'stroke-opacity' => $cl['grid_stipple_1']['opacity'], 'stroke-width' => '1px', 'stroke-dasharray' => '1,1' ) );
+        for ($i = $xlm; $i <= ($iw - $xrm); $i += $x_step)
+        {
+	    svg_line($i, $ytm, $i, $ih-$ybm);
+            svg_line($i, $ih-$ybm, $i-$depth, $ih-$ybm+$depth);
+        }
+        for ($i = $ytm; $i <= ($ih - $ybm); $i += $y_step)
+        {
+            svg_line($xlm, $i, $iw - $xrm, $i);
+	    svg_line($xlm, $i, $xlm - $depth, $i + $depth);
+        }
+	svg_group_end();
+
+	svg_group( array( 'stroke' => $cl['border']['rgb'], 'stroke-width' => '1px', 'stroke-opacity' => $cl['border']['opacity'] ) );
+        svg_line($xlm, $ytm, $xlm, $ih - $ybm);
+        svg_line($xlm, $ih - $ybm, $iw - $xrm, $ih - $ybm);
+	svg_group_end();
+    }
+
+
+    function draw_data($data)
+    {
+        global $cl,$iw,$ih,$xlm,$xrm,$ytm,$ybm;
+
+        sort($data);
+
+        $x_ticks = count($data);
+        $y_ticks = 10;
+        $y_scale = 1;
+        $prescale = 1;
+        $unit = 'K';
+        $offset = 0;
+        $gr_h = $ih - $ytm - $ybm;
+        $x_step = ($iw - $xlm - $xrm) / ($x_ticks ?: 1);
+        $y_step = ($ih - $ytm - $ybm) / $y_ticks;
+        $bar_w = ($x_step / 2);
+
+        // 找出最大值
+        $low = 99999999999;
+        $high = 0;
+        for ($i=0; $i<$x_ticks; $i++)
+        {
+            if ($data[$i]['rx'] < $low)
+                $low = $data[$i]['rx'];
+            if ($data[$i]['tx'] < $low)
+                $low = $data[$i]['tx'];
+            if ($data[$i]['rx'] > $high)
+                $high = $data[$i]['rx'];
+            if ($data[$i]['tx'] > $high)
+                $high = $data[$i]['tx'];
+        }
+
+        // 新的单位转换逻辑
+        $high = $high * 1.2; // 增加20%余量,避免数据触顶
+        
+        // 自动选择合适的单位
+        if ($high < 1024) {
+            $unit = 'K';
+        } else if ($high < 1048576) { // 1024 * 1024
+            $unit = 'M';
+            $prescale = 1024;
+            $high = $high / 1024;
+        } else if ($high < 1073741824) { // 1024 * 1024 * 1024
+            $unit = 'G';
+            $prescale = 1048576;
+            $high = $high / 1048576;
+        } else {
+            $unit = 'T';
+            $prescale = 1073741824;
+            $high = $high / 1073741824;
+        }
+
+        // 计算合适的刻度
+        $y_scale = ceil($high / $y_ticks);
+        
+        // 确保最小刻度
+        if ($y_scale < 1) {
+            $y_scale = 1;
+        }
+
+        draw_grid($x_ticks, $y_ticks);
+
+        // 图表缩放因子(每像素)
+        $sf = ($prescale * $y_scale * $y_ticks) / $gr_h;
+
+        if (count($data) == 0)
+        {
+            $text = T('no data available');
+            svg_text($iw/2, $ytm + 80, $text, array(
+                'stroke' => 'none',
+                'fill' => $cl['text']['rgb'],
+                'stroke-width' => 0,
+                'font-family' => SVG_FONT,
+                'font-size' => '16pt',
+                'text-anchor' => 'middle'
+            ));
+        }
+        else
+        {
+            // 绘制柱状图
+            for ($i=0; $i<$x_ticks; $i++)
+            {
+                $x = $xlm + ($i * $x_step);
+                $y = $ytm + ($ih - $ytm - $ybm) - (($data[$i]['rx'] - $offset) / $sf);
+
+                $depth = ($x_ticks < 20) ? 8*SVG_DEPTH_SCALING : 6*SVG_DEPTH_SCALING;
+                $space = 0;
+
+                $x1 = (int)$x;
+                $y1 = (int)$y;
+                $w = (int)($bar_w - $space);
+                $h = (int)($ih - $ybm - $y);
+                $x2 = (int)($x + $bar_w - $space);
+                $y2 = (int)($ih - $ybm);
+
+                svg_group( array( 'stroke' => $cl['rx_border']['rgb'], 'stroke-opacity' => $cl['rx_border']['opacity'], 
+                                  'stroke-width' => 1, 'stroke-linejoin' => 'round',
+                                  'fill' => $cl['rx']['rgb'], 'fill-opacity' => $cl['rx']['opacity'] ) );
+                svg_rect($x1, $y1, $w, $h);
+                svg_rect($x1 - $depth, $y1 + $depth, $w, $h);
+                svg_poly(array($x1, $y1, $x2, $y1, $x2 - $depth, $y1 + $depth, $x1 - $depth, $y1 + $depth));
+                svg_poly(array($x2, $y1, $x2, $y2, $x2 - $depth, $y2 + $depth, $x2 - $depth, $y1 + $depth));
+                svg_group_end();
+
+                $y1 = (int)($ytm + ($ih - $ytm - $ybm) - (($data[$i]['tx'] - $offset) / $sf));
+                $x1 = (int)($x1 + $bar_w);
+                $x2 = (int)($x2 + $bar_w);
+                $w = (int)($bar_w - $space);
+                $h = (int)($ih - $ybm - $y1 - 1);
+
+                svg_group( array( 'stroke' => $cl['tx_border']['rgb'], 'stroke-opacity' => $cl['tx_border']['opacity'],
+                                  'stroke-width' => 1, 'stroke-linejoin' => 'round',
+                                  'fill' => $cl['tx']['rgb'], 'fill-opacity' => $cl['tx']['opacity'] ) );
+                svg_rect($x1, $y1, $w, $h);
+                svg_rect($x1 - $depth, $y1 + $depth, $w, $h);
+                svg_poly(array($x1, $y1, $x2, $y1, $x2 - $depth, $y1 + $depth, $x1 - $depth, $y1 + $depth));
+                svg_poly(array($x2, $y1, $x2, $y2, $x2 - $depth, $y2 + $depth, $x2 - $depth, $y1 + $depth));
+                svg_group_end();
+            }
+
+            // 绘制坐标轴标签
+            svg_group(array(
+                'fill' => $cl['text']['rgb'],
+                'fill-opacity' => $cl['text']['opacity'],
+                'stroke-width' => '0',
+                'font-family' => SVG_FONT,
+                'font-size' => '10pt',
+                'text-anchor' => 'end'
+            ));
+            
+            // Y轴刻度标签
+            for ($i=0; $i<=$y_ticks; $i++)
+            {
+                $label = ($i * $y_scale).$unit;
+                $tx = $xlm - 16;
+                $ty = ($ih - $ybm) - ($i * $y_step) + 8;
+                svg_text($tx, $ty, $label);
+            }
+            svg_group_end();
+
+            // X轴标签
+            svg_group(array(
+                'fill' => $cl['text']['rgb'],
+                'fill-opacity' => $cl['text']['opacity'],
+                'stroke-width' => '0',
+                'font-family' => SVG_FONT,
+                'font-size' => '10pt',
+                'text-anchor' => 'middle'
+            ));
+            
+            for ($i=0; $i<$x_ticks; $i++)
+            {
+                $label = $data[$i]['img_label'];
+                svg_text(
+                    $xlm + ($i * $x_step) + ($x_step / 2),
+                    $ih - $ybm + 20,
+                    $label
+                );
+            }
+            svg_group_end();
+        }
+
+        draw_border();
+
+        // 图例
+        svg_rect($xlm, $ih-$ybm+39, 8, 8, array(
+            'stroke' => $cl['text']['rgb'],
+            'stroke-width' => 1,
+            'fill' => $cl['rx']['rgb']
+        ));
+        svg_text($xlm+14, $ih-$ybm+48, T('bytes in'), array(
+            'fill' => $cl['text']['rgb'],
+            'stroke-width' => 0,
+            'font-family' => SVG_FONT,
+            'font-size' => '8pt'
+        ));
+
+        svg_rect($xlm+120, $ih-$ybm+39, 8, 8, array(
+            'stroke' => $cl['text']['rgb'],
+            'stroke-width' => 1,
+            'fill' => $cl['tx']['rgb']
+        ));
+        svg_text($xlm+134, $ih-$ybm+48, T('bytes out'), array(
+            'fill' => $cl['text']['rgb'],
+            'stroke-width' => 0,
+            'font-family' => SVG_FONT,
+            'font-size' => '8pt'
+        ));
+    }
+
+    function output_image()
+    {
+        global $page,$hour,$day,$month,$iface;
+
+        if ($page == 'summary')
+            return;
+
+        init_image();
+
+        if ($page == 'h')
+        {
+            draw_data($hour);
+        }
+        else if ($page == 'd')
+        {
+            draw_data($day);
+        }
+        else if ($page == 'm')
+        {
+            draw_data($month);
+        }
+
+	svg_end();
+    }
+
+    get_vnstat_data();
+    output_image();
+?>

+ 39 - 0
index.html

@@ -0,0 +1,39 @@
+<!doctype html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <title>恭喜,站点创建成功!</title>
+    <style>
+        .container {
+            width: 60%;
+            margin: 10% auto 0;
+            background-color: #f0f0f0;
+            padding: 2% 5%;
+            border-radius: 10px
+        }
+
+        ul {
+            padding-left: 20px;
+        }
+
+            ul li {
+                line-height: 2.3
+            }
+
+        a {
+            color: #20a53a
+        }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <h1>恭喜, 站点创建成功!</h1>
+        <h3>这是默认index.html,本页面由系统自动生成</h3>
+        <ul>
+            <li>本页面在FTP根目录下的index.html</li>
+            <li>您可以修改、删除或覆盖本页面</li>
+            <li>FTP相关信息,请到“面板系统后台 > FTP” 查看</li>
+        </ul>
+    </div>
+</body>
+</html>

+ 220 - 0
index.php

@@ -0,0 +1,220 @@
+<?php
+    //
+    // vnStat PHP frontend (c)2006-2010 Bjorge Dijkstra (bjd@jooz.net)
+    //
+    // This program is free software; you can redistribute it and/or modify
+    // it under the terms of the GNU General Public License as published by
+    // the Free Software Foundation; either version 2 of the License, or
+    // (at your option) any later version.
+    //
+    // This program is distributed in the hope that it will be useful,
+    // but WITHOUT ANY WARRANTY; without even the implied warranty of
+    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    // GNU General Public License for more details.
+    //
+    // You should have received a copy of the GNU General Public License
+    // along with this program; if not, write to the Free Software
+    // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+    //
+    //
+    // see file COPYING or at http://www.gnu.org/licenses/gpl.html
+    // for more information.
+    //
+    require 'config.php';
+    require 'localize.php';
+    require 'vnstat.php';
+
+    validate_input();
+
+    require "./themes/$style/theme.php";
+
+    function write_side_bar()
+    {
+        global $iface, $page, $graph, $script, $style;
+        global $iface_list, $iface_title;
+        global $page_list, $page_title;
+
+        $p = "&amp;graph=$graph&amp;style=$style";
+
+        print "<ul class=\"iface\">\n";
+        foreach ($iface_list as $if)
+        {
+            if ($iface == $if) {
+                print "<li class=\"iface active\">";
+            } else {
+                print "<li class=\"iface\">";
+            }
+            print "<a href=\"$script?if=$if$p\">";
+            if (isset($iface_title[$if]))
+            {
+                print $iface_title[$if];
+            }
+            else
+            {
+                print $if;
+            }
+            print "</a>";
+            print "<ul class=\"page\">\n";
+            foreach ($page_list as $pg)
+            {
+                print "<li class=\"page\"><a href=\"$script?if=$if$p&amp;page=$pg\">".$page_title[$pg]."</a></li>\n";
+            }
+            print "</ul></li>\n";
+        }
+        print "</ul>\n";
+    }
+
+
+    function kbytes_to_string($kb)
+    {
+
+        global $byte_notation;
+
+        $units = array('TiB','GiB','MiB','KiB');
+        $scale = 1024*1024*1024;
+        $ui = 0;
+
+        $custom_size = isset($byte_notation) && in_array($byte_notation, $units);
+
+        while ((($kb < $scale) && ($scale > 1)) || $custom_size)
+        {
+            $ui++;
+            $scale = $scale / 1024;
+
+            if ($custom_size && $units[$ui] == $byte_notation) {
+                break;
+            }
+        }
+
+        return sprintf("%0.2f %s", ($kb/$scale),$units[$ui]);
+    }
+
+    function write_summary()
+    {
+        global $summary,$top,$day,$hour,$month;
+
+        $trx = $summary['totalrx']*1024+$summary['totalrxk'];
+        $ttx = $summary['totaltx']*1024+$summary['totaltxk'];
+
+        //
+        // build array for write_data_table
+        //
+
+        $sum = array();
+
+        if (count($day) > 0 && count($hour) > 0 && count($month) > 0) {
+            $sum[0]['act'] = 1;
+            $sum[0]['label'] = T('This hour');
+            $sum[0]['rx'] = $hour[0]['rx'];
+            $sum[0]['tx'] = $hour[0]['tx'];
+
+            $sum[1]['act'] = 1;
+            $sum[1]['label'] = T('This day');
+            $sum[1]['rx'] = $day[0]['rx'];
+            $sum[1]['tx'] = $day[0]['tx'];
+
+            $sum[2]['act'] = 1;
+            $sum[2]['label'] = T('This month');
+            $sum[2]['rx'] = $month[0]['rx'];
+            $sum[2]['tx'] = $month[0]['tx'];
+
+            $sum[3]['act'] = 1;
+            $sum[3]['label'] = T('All time');
+            $sum[3]['rx'] = $trx;
+            $sum[3]['tx'] = $ttx;
+        }
+
+        write_data_table(T('Summary'), $sum);
+        print "<br/>\n";
+        write_data_table(T('Top 10 days'), $top);
+    }
+
+
+    function write_data_table($caption, $tab)
+    {
+        print "<table width=\"100%\" cellspacing=\"0\">\n";
+        print "<caption>$caption</caption>\n";
+        print "<tr>";
+        print "<th class=\"label\" style=\"width:120px;\">&nbsp;</th>";
+        print "<th class=\"label\">".T('In')."</th>";
+        print "<th class=\"label\">".T('Out')."</th>";
+        print "<th class=\"label\">".T('Total')."</th>";
+        print "</tr>\n";
+
+        for ($i=0; $i<count($tab); $i++)
+        {
+            if ($tab[$i]['act'] == 1)
+            {
+                $t = $tab[$i]['label'];
+                $rx = kbytes_to_string($tab[$i]['rx']);
+                $tx = kbytes_to_string($tab[$i]['tx']);
+                $total = kbytes_to_string($tab[$i]['rx']+$tab[$i]['tx']);
+                $id = ($i & 1) ? 'odd' : 'even';
+                print "<tr>";
+                print "<td class=\"label_$id\">$t</td>";
+                print "<td class=\"numeric_$id\">$rx</td>";
+                print "<td class=\"numeric_$id\">$tx</td>";
+                print "<td class=\"numeric_$id\">$total</td>";
+                print "</tr>\n";
+             }
+        }
+        print "</table>\n";
+    }
+
+    get_vnstat_data();
+
+    //
+    // html start
+    //
+    header('Content-type: text/html; charset=utf-8');
+    print '<?xml version="1.0"?>';
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+  <title>vnStat - PHP frontend</title>
+  <link rel="stylesheet" type="text/css" href="themes/<?php echo $style ?>/style.css"/>
+  <!-- 添加 Bootstrap 5 -->
+  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
+  <!-- 添加一些现代图标 -->
+  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
+</head>
+<body>
+
+<div id="wrap">
+  <div id="sidebar"><?php write_side_bar(); ?></div>
+   <div id="content">
+    <div id="header"><?php print T('Traffic data for').(isset($iface_title[$iface]) ? $iface_title[$iface] : '')." ($iface)";?></div>
+    <div id="main">
+    <?php
+    $graph_params = "if=$iface&amp;page=$page&amp;style=$style";
+    if ($page != 's')
+        if ($graph_format == 'svg') {
+	     print "<object type=\"image/svg+xml\" width=\"692\" height=\"297\" data=\"graph_svg.php?$graph_params\"></object>\n";
+        } else {
+	     print "<img src=\"graph.php?$graph_params\" alt=\"graph\"/>\n";
+        }
+
+    if ($page == 's')
+    {
+        write_summary();
+    }
+    else if ($page == 'h')
+    {
+        write_data_table(T('Last 24 hours'), $hour);
+    }
+    else if ($page == 'd')
+    {
+        write_data_table(T('Last 30 days'), $day);
+    }
+    else if ($page == 'm')
+    {
+        write_data_table(T('Last 12 months'), $month);
+    }
+    ?>
+    </div>
+    <div id="footer"><a href="http://www.sqweek.com/">vnStat PHP frontend</a> 2.0.0 - &copy;2006-2024 Bjorge Dijkstra (bjd _at_ jooz.net)</div>
+  </div>
+</div>
+
+</body></html>

+ 20 - 0
js/custom.js

@@ -0,0 +1,20 @@
+// 添加图表动画
+document.addEventListener('DOMContentLoaded', function() {
+    // 为所有数据卡片添加渐入效果
+    const cards = document.querySelectorAll('.traffic-card');
+    cards.forEach(card => {
+        card.style.opacity = '0';
+        card.style.transform = 'translateY(20px)';
+        
+        setTimeout(() => {
+            card.style.transition = 'opacity 0.5s ease, transform 0.5s ease';
+            card.style.opacity = '1';
+            card.style.transform = 'translateY(0)';
+        }, 100);
+    });
+});
+
+// 添加数据刷新功能
+function refreshData() {
+    // 实现自动刷新逻辑
+} 

+ 81 - 0
json.php

@@ -0,0 +1,81 @@
+<?php
+    //
+    // vnStat PHP frontend (c)2006-2010 Bjorge Dijkstra (bjd@jooz.net)
+    //
+    // This program is free software; you can redistribute it and/or modify
+    // it under the terms of the GNU General Public License as published by
+    // the Free Software Foundation; either version 2 of the License, or
+    // (at your option) any later version.
+    //
+    // This program is distributed in the hope that it will be useful,
+    // but WITHOUT ANY WARRANTY; without even the implied warranty of
+    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    // GNU General Public License for more details.
+    //
+    // You should have received a copy of the GNU General Public License
+    // along with this program; if not, write to the Free Software
+    // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+    //
+    //
+    // see file COPYING or at http://www.gnu.org/licenses/gpl.html
+    // for more information.
+    //
+    require 'config.php';
+    require 'localize.php';
+    require 'vnstat.php';
+
+    validate_input();
+
+    require "./themes/$style/theme.php";
+
+    function write_summary()
+    {
+        global $summary,$top,$day,$hour,$month;
+
+        $trx = $summary['totalrx']*1024+$summary['totalrxk'];
+        $ttx = $summary['totaltx']*1024+$summary['totaltxk'];
+
+        //
+        // build array for write_data_table
+        //
+        $sum['hour']['act'] = 1;
+        $sum['hour']['rx'] = $hour[0]['rx'];
+        $sum['hour']['tx'] = $hour[0]['tx'];
+
+        $sum['day']['act'] = 1;
+        $sum['day']['rx'] = $day[0]['rx'];
+        $sum['day']['tx'] = $day[0]['tx'];
+
+        $sum['month']['act'] = 1;
+        $sum['month']['rx'] = $month[0]['rx'];
+        $sum['month']['tx'] = $month[0]['tx'];
+
+        $sum['total']['act'] = 1;
+        $sum['total']['rx'] = $trx;
+        $sum['total']['tx'] = $ttx;
+
+        print json_encode($sum);
+    }
+
+
+    get_vnstat_data(false);
+
+    header('Content-type: application/json; charset=utf-8');
+    $graph_params = "if=$iface&amp;page=$page&amp;style=$style";
+    if ($page == 's')
+    {
+        write_summary();
+    }
+    else if ($page == 'h')
+    {
+      print json_encode(array('hours' => $hour));
+    }
+    else if ($page == 'd')
+    {
+      print json_encode(array('days' => $day));
+    }
+    else if ($page == 'm')
+    {
+      print json_encode(array('months' => $month));
+    }
+    ?>

+ 39 - 0
lang/br.php

@@ -0,0 +1,39 @@
+<?php
+
+// sidebar labels
+$L['summary'] = 'sumario';
+$L['hours'] = 'horas';
+$L['days'] = 'dias';
+$L['months'] = 'meses';
+
+// main table headers
+$L['Summary'] = 'Sumario';
+$L['Top 10 days'] = 'Top 10 - dias';
+$L['Last 24 hours'] = 'Ultimas 24 horas';
+$L['Last 30 days'] = 'Ultimos 30 dias';
+$L['Last 12 months'] = 'Ultimos 12 meses';
+
+// traffic table columns
+$L['In'] = 'Entrada';
+$L['Out'] = 'Saida';
+$L['Total'] = 'Total';
+
+// summary rows
+$L['This hour'] = 'Esta hora';
+$L['This day'] = 'Este dia';
+$L['This month'] = 'Este mes';
+$L['All time'] = 'Todos os tempos';
+
+// graph text
+$L['Traffic data for'] = 'Trafego da';
+$L['bytes in'] = 'bytes entrada';
+$L['bytes out'] = 'bytes saida';
+
+// date formats
+$L['datefmt_days'] = '%d %B';
+$L['datefmt_days_img'] = '%d';
+$L['datefmt_months'] = '%B %Y';
+$L['datefmt_months_img'] = '%b';
+$L['datefmt_hours'] = '%l%p';
+$L['datefmt_hours_img'] = '%l';
+$L['datefmt_top'] = '%d %B %Y';

+ 40 - 0
lang/cn.php

@@ -0,0 +1,40 @@
+<?php
+
+// sidebar labels
+$L['summary'] = '总计';
+$L['hours'] = '每时';
+$L['days'] = '每天';
+$L['months'] = '每月';
+
+// main table headers
+$L['Summary'] = '概览';
+$L['Top 10 days'] = '最高流量的10天';
+$L['Last 24 hours'] = '过去24小时';
+$L['Last 30 days'] = '过去30天';
+$L['Last 12 months'] = '过去12个月';
+
+// traffic table columns
+$L['In'] = '流入';
+$L['Out'] = '流出';
+$L['Total'] = '总流量';
+
+// summary rows
+$L['This hour'] = '本小时';
+$L['This day'] = '本日';
+$L['This month'] = '本月';
+$L['All time'] = '总计';
+
+// graph text
+$L['Traffic data for'] = '统计的网络:';
+$L['bytes in'] = '流入bytes';
+$L['bytes out'] = '流出bytes';
+
+// date formats
+$L['datefmt_days'] = '%B%d日';
+$L['datefmt_days_img'] = '%d';
+$L['datefmt_months'] = '%Y年%B';
+$L['datefmt_months_img'] = '%b';
+$L['datefmt_hours'] = '%H:00';
+$L['datefmt_hours_img'] = '%H';
+$L['datefmt_top'] = '%Y年%m月%d日';
+

+ 39 - 0
lang/cs.php

@@ -0,0 +1,39 @@
+<?php
+
+// sidebar labels
+$L['summary'] = 'shrnutí';
+$L['hours'] = 'hodiny';
+$L['days'] = 'dny';
+$L['months'] = 'měsíce';
+
+// main table headers
+$L['Summary'] = 'Shrnutí';
+$L['Top 10 days'] = 'Nej 10 dní';
+$L['Last 24 hours'] = 'Posledních 24 hodin';
+$L['Last 30 days'] = 'Posledních 30 dní';
+$L['Last 12 months'] = 'Posledních 12 měsíců';
+
+// traffic table columns
+$L['In'] = 'Stahování';
+$L['Out'] = 'Odesílání';
+$L['Total'] = 'Celkem';
+
+// summary rows
+$L['This hour'] = 'Tato hodina';
+$L['This day'] = 'Tento den';
+$L['This month'] = 'Tento měsíc';
+$L['All time'] = 'Za celou dobu';
+
+// graph text
+$L['Traffic data for'] = 'Přehled pro';
+$L['bytes in'] = 'bytů staženo';
+$L['bytes out'] = 'bytů odesláno';
+
+// date formats
+$L['datefmt_days'] = '%d. %B';
+$L['datefmt_days_img'] = '%d';
+$L['datefmt_months'] = '%B %Y';
+$L['datefmt_months_img'] = '%b';
+$L['datefmt_hours'] = '%k%p';
+$L['datefmt_hours_img'] = '%k';
+$L['datefmt_top'] = '%d. %B %Y';

+ 40 - 0
lang/de.php

@@ -0,0 +1,40 @@
+<?php
+
+// sidebar labels
+$L['summary'] = 'Übersicht';
+$L['hours'] = 'Stunden';
+$L['days'] = 'Tage';
+$L['months'] = 'Monate';
+
+// main table headers
+$L['Summary'] = 'Übersicht';
+$L['Top 10 days'] = 'Top 10 nach Tagen';
+$L['Last 24 hours'] = 'Letzte 24 Stunden';
+$L['Last 30 days'] = 'Letzte 30 Tage';
+$L['Last 12 months'] = 'Letzte 12 Monate';
+
+// traffic table columns
+$L['In'] = 'Rein';
+$L['Out'] = 'Raus';
+$L['Total'] = 'Total';
+
+// summary rows
+$L['This hour'] = 'Diese Stunde';
+$L['This day'] = 'Dieser Tag';
+$L['This month'] = 'Dieser Monat';
+$L['All time'] = 'Alles';
+
+// graph text
+$L['Traffic data for'] = 'Trafficdaten für';
+$L['bytes in'] = 'Bytes rein';
+$L['bytes out'] = 'Bytes raus';
+
+// date formats
+$L['datefmt_days'] = '%d.%B';
+$L['datefmt_days_img'] = '%d';
+$L['datefmt_months'] = '%B.%Y';
+$L['datefmt_months_img'] = '%b';
+$L['datefmt_hours'] = '%H:%M';
+$L['datefmt_hours_img'] = '%H';
+$L['datefmt_top'] = '%d.%B.%Y';
+

+ 39 - 0
lang/en.php

@@ -0,0 +1,39 @@
+<?php
+
+// sidebar labels
+$L['summary'] = 'summary';
+$L['hours'] = 'hours';
+$L['days'] = 'days';
+$L['months'] = 'months';
+
+// main table headers
+$L['Summary'] = 'Summary';
+$L['Top 10 days'] = 'Top 10 days';
+$L['Last 24 hours'] = 'Last 24 hours';
+$L['Last 30 days'] = 'Last 30 days';
+$L['Last 12 months'] = 'Last 12 months';
+
+// traffic table columns
+$L['In'] = 'In';
+$L['Out'] = 'Out';
+$L['Total'] = 'Total';
+
+// summary rows
+$L['This hour'] = 'This hour';
+$L['This day'] = 'This day';
+$L['This month'] = 'This month';
+$L['All time'] = 'All time';
+
+// graph text
+$L['Traffic data for'] = 'Traffic data for';
+$L['bytes in'] = 'bytes in';
+$L['bytes out'] = 'bytes out';
+
+// date formats
+$L['datefmt_days'] = '%d %B';
+$L['datefmt_days_img'] = '%d';
+$L['datefmt_months'] = '%B %Y';
+$L['datefmt_months_img'] = '%b';
+$L['datefmt_hours'] = '%l%p';
+$L['datefmt_hours_img'] = '%l';
+$L['datefmt_top'] = '%d %B %Y';

+ 41 - 0
lang/es.php

@@ -0,0 +1,41 @@
+<?php
+
+// sidebar labels
+$L['summary'] = 'sumario';
+$L['hours'] = 'horas';
+$L['days'] = 'días';
+$L['months'] = 'meses';
+
+// main table headers
+$L['Summary'] = 'Sumario';
+$L['Top 10 days'] = 'Últimos 10 días';
+$L['Last 24 hours'] = 'Últimas 24 horas';
+$L['Last 30 days'] = 'Últimos 30 días';
+$L['Last 12 months'] = 'Últimos 12 meses';
+
+// traffic table columns
+$L['In'] = 'Entrada';
+$L['Out'] = 'Salida';
+$L['Total'] = 'Total';
+
+// summary rows
+$L['This hour'] = 'Esta hora';
+$L['This day'] = 'Este día';
+$L['This month'] = 'Este mes';
+$L['All time'] = 'Todo el tiempo';
+
+// graph text
+$L['Traffic data for'] = 'Trafico de datos para';
+$L['bytes in'] = 'entrada de bytes';
+$L['bytes out'] = 'salida de bytes';
+
+// date formats
+$L['datefmt_days'] = '%d %B';
+$L['datefmt_days_img'] = '%d';
+$L['datefmt_months'] = '%B %Y';
+$L['datefmt_months_img'] = '%b';
+$L['datefmt_hours'] = '%H:%M';
+$L['datefmt_hours_img'] = '%H';
+$L['datefmt_top'] = '%d %B %Y';
+
+// spanish version by Carlos Troetsch

+ 39 - 0
lang/fi.php

@@ -0,0 +1,39 @@
+<?php
+
+// sidebar labels
+$L['summary'] = 'yhteenveto';
+$L['hours'] = 'tunnit';
+$L['days'] = 'päivät';
+$L['months'] = 'kuukaudet';
+
+// main table headers
+$L['Summary'] = 'Yhteenveto';
+$L['Top 10 days'] = 'Top 10 päivää';
+$L['Last 24 hours'] = 'Viimeiset 24 tuntia';
+$L['Last 30 days'] = 'Viimeiset 30 päivää';
+$L['Last 12 months'] = 'Viimeiset 12 kuukautta';
+
+// traffic table columns
+$L['In'] = 'Sisään';
+$L['Out'] = 'Ulos';
+$L['Total'] = 'Yhteensä';
+
+// summary rows
+$L['This hour'] = 'Viimeisin tunti';
+$L['This day'] = 'Viimeisin päivä';
+$L['This month'] = 'Viimeisin kuukausi';
+$L['All time'] = 'Kaikkiaan';
+
+// graph text
+$L['Traffic data for'] = 'Liikennemäärä';
+$L['bytes in'] = 'tavua sisään';
+$L['bytes out'] = 'tavua ulos';
+
+// date formats
+$L['datefmt_days'] = '%d. %B';
+$L['datefmt_days_img'] = '%d';
+$L['datefmt_months'] = '%B %Y';
+$L['datefmt_months_img'] = '%b';
+$L['datefmt_hours'] = '%H';
+$L['datefmt_hours_img'] = '%H';
+$L['datefmt_top'] = '%a %d. %b %Y';

+ 39 - 0
lang/fr.php

@@ -0,0 +1,39 @@
+<?php
+
+// sidebar labels
+$L['summary'] = 'Sommaire';
+$L['hours'] = 'Heures';
+$L['days'] = 'Jours';
+$L['months'] = 'Mois';
+
+// main table headers
+$L['Summary'] = 'Sommaire';
+$L['Top 10 days'] = 'Les 10 meilleurs jours';
+$L['Last 24 hours'] = 'Dernières 24 heures';
+$L['Last 30 days'] = 'Derniers 30 jours';
+$L['Last 12 months'] = 'Les 12 derniers mois';
+
+// traffic table columns
+$L['In'] = 'Entrant';
+$L['Out'] = 'Sortant';
+$L['Total'] = 'Total';
+
+// summary rows
+$L['This hour'] = 'Cette heure';
+$L['This day'] = 'Aujourd\' hui';
+$L['This month'] = 'Ce mois';
+$L['All time'] = 'Tout temps';
+
+// graph text
+$L['Traffic data for'] = 'Traffic de donnée pour :';
+$L['bytes in'] = 'bytes entrants';
+$L['bytes out'] = 'bytes sortants';
+
+// date formats
+$L['datefmt_days'] = '%d %B';
+$L['datefmt_days_img'] = '%d';
+$L['datefmt_months'] = '%B %Y';
+$L['datefmt_months_img'] = '%b';
+$L['datefmt_hours'] = '%Hh%M';
+$L['datefmt_hours_img'] = '%H';
+$L['datefmt_top'] = '%d %B %Y';

+ 39 - 0
lang/hr.php

@@ -0,0 +1,39 @@
+<?php
+
+// sidebar labels
+$L['summary'] = 'sažetak';  // summary
+$L['hours'] = 'sati';
+$L['days'] = 'dani';
+$L['months'] = 'mjeseci';
+
+// main table headers
+$L['Summary'] = 'Sažetak';
+$L['Top 10 days'] = '10 naprometnijih dana'; 
+$L['Last 24 hours'] = 'Zadnja 24 sata';
+$L['Last 30 days'] = 'Zadnjih 30 dana';
+$L['Last 12 months'] = 'Zadnjih 12 mjeseci';
+
+// traffic table columns
+$L['In'] = 'Primljeno';  
+$L['Out'] = 'Poslano'; 
+$L['Total'] = 'Ukupno'; // Total
+
+// summary rows
+$L['This hour'] = 'Tekući sat';
+$L['This day'] = 'Danas';
+$L['This month'] = 'Tekući mjesec';
+$L['All time'] = 'Sveukupno'; 
+
+// graph text
+$L['Traffic data for'] = 'Promet za';
+$L['bytes in'] = 'bajta primljeno';
+$L['bytes out'] = 'bajta poslano';
+
+// date formats
+$L['datefmt_days'] = '%d. %m'; 
+$L['datefmt_days_img'] = '%d';
+$L['datefmt_months'] = '%m.%Y'; 
+$L['datefmt_months_img'] = '%b';
+$L['datefmt_hours'] = '%H';  // %k
+$L['datefmt_hours_img'] = '%H';
+$L['datefmt_top'] = '%d.%m.%Y';

+ 39 - 0
lang/hu.php

@@ -0,0 +1,39 @@
+<?php
+
+// sidebar labels
+$L['summary'] = 'Összegzés';
+$L['hours'] = 'órák';
+$L['days'] = 'napok';
+$L['months'] = 'hónapok';
+
+// main table headers
+$L['Summary'] = 'Öszegzés';
+$L['Top 10 days'] = 'Legjobb 10 nap';
+$L['Last 24 hours'] = 'Utolsó 24 óra';
+$L['Last 30 days'] = 'Utolsó 30 nap';
+$L['Last 12 months'] = 'Utolsó 12 hónap';
+
+// traffic table columns
+$L['In'] = 'Bejövő';
+$L['Out'] = 'Kimenő';
+$L['Total'] = 'Összesen';
+
+// summary rows
+$L['This hour'] = 'Ebben az órában';
+$L['This day'] = 'Ezen a napon';
+$L['This month'] = 'Ebben a hónapban';
+$L['All time'] = 'Összesen';
+
+// graph text
+$L['Traffic data for'] = 'Forgalmi adatok: ';
+$L['bytes in'] = 'bejövő bájtok';
+$L['bytes out'] = 'kimenő bájtok';
+
+// date formats
+$L['datefmt_days'] = '%d %B';
+$L['datefmt_days_img'] = '%d';
+$L['datefmt_months'] = '%B %Y';
+$L['datefmt_months_img'] = '%b';
+$L['datefmt_hours'] = '%l%p';
+$L['datefmt_hours_img'] = '%l';
+$L['datefmt_top'] = '%d %B %Y';

+ 39 - 0
lang/it.php

@@ -0,0 +1,39 @@
+<?php
+
+// sidebar labels
+$L['summary'] = 'Riepilogo';
+$L['hours'] = 'Ore';
+$L['days'] = 'Giorni';
+$L['months'] = 'Mesi';
+
+// main table headers
+$L['Summary'] = 'Riepilogo';
+$L['Top 10 days'] = '10 giorni piu intensivi';
+$L['Last 24 hours'] = 'Ultime 24 ore';
+$L['Last 30 days'] = 'Ultimi 30 giorni';
+$L['Last 12 months'] = 'Ultimi 12 mesi';
+
+// traffic table columns
+$L['In'] = 'Entrata';
+$L['Out'] = 'Uscita';
+$L['Total'] = 'Totale';
+
+// summary rows
+$L['This hour'] = 'Quest ora';
+$L['This day'] = 'Oggi';
+$L['This month'] = 'Questo mese';
+$L['All time'] = 'Sempre';
+
+// graph text
+$L['Traffic data for'] = 'Dati per';
+$L['bytes in'] = 'bytes entrati';
+$L['bytes out'] = 'bytes usciti';
+
+// date formats
+$L['datefmt_days'] = '%d %B';
+$L['datefmt_days_img'] = '%d';
+$L['datefmt_months'] = '%B %Y';
+$L['datefmt_months_img'] = '%b';
+$L['datefmt_hours'] = '%l%p';
+$L['datefmt_hours_img'] = '%l';
+$L['datefmt_top'] = '%d %B %Y';

+ 40 - 0
lang/nl.php

@@ -0,0 +1,40 @@
+<?php
+
+// sidebar labels
+$L['summary'] = 'samenvatting';
+$L['hours'] = 'uren';
+$L['days'] = 'dagen';
+$L['months'] = 'maanden';
+
+// main table headers
+$L['Summary'] = 'Samenvatting';
+$L['Top 10 days'] = 'Top 10 dagen';
+$L['Last 24 hours'] = 'Afgelopen 24 uur';
+$L['Last 30 days'] = 'Afgelopen 30 dagen';
+$L['Last 12 months'] = 'Afgelopen 12 maanden';
+
+// traffic table columns
+$L['In'] = 'In';
+$L['Out'] = 'Uit';
+$L['Total'] = 'Totaal';
+
+// summary rows
+$L['This hour'] = 'Dit uur';
+$L['This day'] = 'Deze dag';
+$L['This month'] = 'Deze maand';
+$L['All time'] = 'Altijd';
+
+// graph text
+$L['Traffic data for'] = 'Data verkeer voor';
+$L['bytes in'] = 'bytes in';
+$L['bytes out'] = 'bytes uit';
+
+// date formats
+$L['datefmt_days'] = '%d %B';
+$L['datefmt_days_img'] = '%d';
+$L['datefmt_months'] = '%B %Y';
+$L['datefmt_months_img'] = '%b';
+$L['datefmt_hours'] = '%H:%M';
+$L['datefmt_hours_img'] = '%H';
+$L['datefmt_top'] = '%d %B %Y';
+

+ 39 - 0
lang/no.php

@@ -0,0 +1,39 @@
+<?php
+
+// sidebar labels
+$L['summary'] = 'Sammendrag';
+$L['hours'] = 'Timer';
+$L['days'] = 'Dager';
+$L['months'] = 'Måneder';
+
+// main table headers
+$L['Summary'] = 'Sammendrag';
+$L['Top 10 days'] = 'Topp 10 dager';
+$L['Last 24 hours'] = 'Siste 24 timer';
+$L['Last 30 days'] = 'Siste 30 dager';
+$L['Last 12 months'] = 'Siste 12 måneder';
+
+// traffic table columns
+$L['In'] = 'Inn';
+$L['Out'] = 'Ut';
+$L['Total'] = 'Totalt';
+
+// summary rows
+$L['This hour'] = 'Denne time';
+$L['This day'] = 'Idag';
+$L['This month'] = 'Denne måneden';
+$L['All time'] = 'Totalt';
+
+// graph text
+$L['Traffic data for'] = 'Trafikkdata for';
+$L['bytes in'] = 'bytes inn';
+$L['bytes out'] = 'bytes ut';
+
+// date formats
+$L['datefmt_days'] = '%d %B';
+$L['datefmt_days_img'] = '%d';
+$L['datefmt_months'] = '%B %Y';
+$L['datefmt_months_img'] = '%b';
+$L['datefmt_hours'] = '%H:%M';
+$L['datefmt_hours_img'] = '%H';
+$L['datefmt_top'] = '%d %B %Y';

+ 39 - 0
lang/pl.php

@@ -0,0 +1,39 @@
+<?php
+
+// sidebar labels
+$L['summary'] = 'podsumowanie';
+$L['hours'] = 'godziny';
+$L['days'] = 'dni';
+$L['months'] = 'miesiące';
+
+// main table headers
+$L['Summary'] = 'Podsumowanie';
+$L['Top 10 days'] = 'Top 10 dni';
+$L['Last 24 hours'] = 'Ostatnie 24 godziny';
+$L['Last 30 days'] = 'Ostatnie 30 dni';
+$L['Last 12 months'] = 'Ostatnie 12 miesięcy';
+
+// traffic table columns
+$L['In'] = 'Wyjście';
+$L['Out'] = 'Wejście';
+$L['Total'] = 'Suma';
+
+// summary rows
+$L['This hour'] = 'Ta godzina';
+$L['This day'] = 'Ten dzień';
+$L['This month'] = 'Ten miesiąc';
+$L['All time'] = 'Całość';
+
+// graph text
+$L['Traffic data for'] = 'Transfer dla';
+$L['bytes in'] = 'Wysłane';
+$L['bytes out'] = 'Odebrane';
+
+// date formats
+$L['datefmt_days'] = '%d %B';
+$L['datefmt_days_img'] = '%d';
+$L['datefmt_months'] = '%B %Y';
+$L['datefmt_months_img'] = '%b';
+$L['datefmt_hours'] = '%l%p';
+$L['datefmt_hours_img'] = '%l';
+$L['datefmt_top'] = '%d %B %Y';

+ 39 - 0
lang/ru.php

@@ -0,0 +1,39 @@
+<?php
+
+// sidebar labels
+$L['summary'] = 'сводка';
+$L['hours'] = 'по часам';
+$L['days'] = 'по дням';
+$L['months'] = 'по месяцам';
+
+// main table headers
+$L['Summary'] = 'Сводка';
+$L['Top 10 days'] = 'Топ 10 дней';
+$L['Last 24 hours'] = 'Последние 24 часа';
+$L['Last 30 days'] = 'Последние 30 дней';
+$L['Last 12 months'] = 'Последние 12 месяцев';
+
+// traffic table columns
+$L['In'] = 'Входящий';
+$L['Out'] = 'Исходящий';
+$L['Total'] = 'Общий';
+
+// summary rows
+$L['This hour'] = 'Текущий час';
+$L['This day'] = 'Текущий день';
+$L['This month'] = 'Текущий месяц';
+$L['All time'] = 'За все время';
+
+// graph text
+$L['Traffic data for'] = 'Статистика трафика для';
+$L['bytes in'] = 'получено';
+$L['bytes out'] = 'передано';
+
+// date formats
+$L['datefmt_days'] = '%d %B';
+$L['datefmt_days_img'] = '%d';
+$L['datefmt_months'] = '%B %Y';
+$L['datefmt_months_img'] = '%b';
+$L['datefmt_hours'] = '%H:%M';
+$L['datefmt_hours_img'] = '%H';
+$L['datefmt_top'] = '%d %B %Y';

+ 39 - 0
lang/sk.php

@@ -0,0 +1,39 @@
+<?php
+
+// sidebar labels
+$L['summary'] = 'zhrnutie';
+$L['hours'] = 'hodiny';
+$L['days'] = 'dni';
+$L['months'] = 'mesiace';
+
+// main table headers
+$L['Summary'] = 'Zhrnutie';
+$L['Top 10 days'] = 'Naj 10 dni';
+$L['Last 24 hours'] = 'Posledných 24 hodin';
+$L['Last 30 days'] = 'Posledných 30 dni';
+$L['Last 12 months'] = 'Posledných 12 mesiacov';
+
+// traffic table columns
+$L['In'] = 'Sťahovanie';
+$L['Out'] = 'Posielanie';
+$L['Total'] = 'Celkom';
+
+// summary rows
+$L['This hour'] = 'Túto hodinu';
+$L['This day'] = 'Tento deň';
+$L['This month'] = 'Tento mesiac';
+$L['All time'] = 'Celkom';
+
+// graph text
+$L['Traffic data for'] = 'Prehlad pre';
+$L['bytes in'] = 'bajtov stiahnuté';
+$L['bytes out'] = 'bajtov poslané';
+
+// date formats
+$L['datefmt_days'] = '%d %B';
+$L['datefmt_days_img'] = '%d';
+$L['datefmt_months'] = '%B %Y';
+$L['datefmt_months_img'] = '%b';
+$L['datefmt_hours'] = '%l%p';
+$L['datefmt_hours_img'] = '%l';
+$L['datefmt_top'] = '%d %B %Y';

+ 15 - 0
localize.php

@@ -0,0 +1,15 @@
+<?php
+    // setup locale and translation
+    setlocale(LC_ALL, $locale);
+    require "lang/$language.php";
+
+    function T($str)
+    {
+        global $L;
+        if (isset($L[$str]))
+            return $L[$str];
+        else
+            return $str;
+    }
+
+?>

+ 21 - 0
themes/dark/style.css

@@ -0,0 +1,21 @@
+* {margin:0; padding:0;}
+body {background:#2f2f2f; font-family:Verdana; font-size:12px;}
+#wrap {width: 960px; background:#242424; padding:10px; margin:0 auto; border:1px solid #474747;}
+#sidebar {width: 160px; float: left; padding: 3px 4px; color: #fff; background-color: #2F2F2F; border:1px solid #474747; -moz-border-radius:8px;}
+#sidebar ul.iface {}
+#sidebar li.iface {list-style-type:none; color:#08BB08; text-transform:uppercase; padding-bottom:10px; text-align:center;}
+#sidebar a{color:#aaa;}
+#sidebar ul.page {}
+#sidebar li.page {list-style-type:none; text-transform:none;}
+#content {margin-left: 180px; width: 780px;}
+#header {padding: 3px; color: #fff; background-color: #2F2F2F; text-align: center; border:1px solid #474747; font-size:14px; font-weight:bold; -moz-border-radius:8px;}
+#footer {padding: 3px; color: #fff; background-color: #2F2F2F; text-align: center; border:1px solid #474747; font-size:11px; -moz-border-radius:8px; clear:both; margin-top:10px;}
+#footer a {color:#fff;}
+#main {padding: 10px 10px 10px 10px; color: #fff; background-color: #2F2F2F; text-align: center; border:1px solid #474747; -moz-border-radius:8px; margin-top:10px;}
+#main td {padding:1px 0;}
+#main td.numeric_odd {text-align: right; color: #fff; background:#474747;}
+#main td.numeric_even {text-align: right; color: #fff; background:#242424;}
+#main td.label_odd {color: #fff; background:#474747;}
+#main td.label_even {color: #fff; background:#242424;}
+#main th.label {color: #fff; padding:2px 0; border-bottom:1px solid #fff;}
+#main caption {padding: 3px 0 4px 0; color:#08BB08; text-transform:uppercase;}

+ 16 - 0
themes/dark/theme.php

@@ -0,0 +1,16 @@
+<?php
+    // A dark colorscheme based on a contribution by Mart Visser
+    $colorscheme = array(
+       'image_background'   => array(  36,  36,  36,   0 ),
+       'graph_background'   => array( 220, 220, 230,   0 ),
+       'graph_background_2' => array( 205, 205, 220,   0 ),
+       'grid_stipple_1'     => array( 140, 140, 140,   0 ),
+       'grid_stipple_2'     => array( 200, 200, 200,   0 ),
+       'border'             => array(  71,  71,  71,   0 ),
+       'text'               => array(  255,  255,  255,   0 ),
+       'rx'                 => array(  10, 180,  10,  50 ),
+       'rx_border'          => array(  0, 120,  0,  90 ),
+       'tx'                  => array( 130, 130, 130,  50 ),
+       'tx_border'          => array(  60,  60,  60,  90 )
+     );
+?>

+ 170 - 0
themes/espresso/style.css

@@ -0,0 +1,170 @@
+body
+{
+	background-color: #363330;
+	margin: 8px;
+	padding: 0;
+}
+
+#content
+{
+    width: 898px;
+}
+
+#sidebar
+{
+    position: absolute;
+    left: 8px;
+    top: 8px;
+    width: 160px;
+    border-right: 1px solid #D3CAAA;
+    border-collapse: collapse;
+    float: left;
+}
+
+#sidebar ul.iface
+{
+    margin: 0px;
+    padding: 0px;
+    border-top: 1px dashed #D3CAAA;
+    background-color: #363330;
+    color: #D3CAAA;
+}
+
+#sidebar li.iface
+{
+    list-style-type: none;
+    margin: 0px;
+    padding: 0px;
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 1em;
+    font-weight: bold;
+    border-bottom: 1px dashed #D3CAAA;
+}
+
+#sidebar a
+{
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 1em;
+    font-weight: bold;
+}
+
+#sidebar ul.page
+{
+    margin: 0px;
+    padding: 0px;
+    border-top: 1px dashed #D3CAAA;
+}
+
+#sidebar li.page
+{
+    list-style-type: none;
+    margin: 0px;
+    padding: 4px;
+    border: none;
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 0.75em;
+    font-weight: normal;
+    text-align: right;
+    background-color: #413D39;
+    color: #D3CAAA;
+}
+
+
+#header
+{
+    width: 720px;
+    margin-left: 160px;
+    padding: 0px 8px 0px 8px;
+    border-width: 1px 1px 1px 1px;
+    border-style: dashed solid dashed solid;
+    border-color: #D3CAAA;
+    border-collapse: collapse;
+    background-color: #363330;
+    color: #D3CAAA;
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 1em;
+    font-weight: bold;
+    text-align: center;
+}
+
+#footer
+{
+    width: 720px;
+    margin-left: 160px;
+    padding: 2px 8px 2px 8px;
+    border-width: 1px 1px 1px 1px;
+    border-style: solid;
+    border-color: #D3CAAA;
+    border-collapse: collapse;
+    background-color: #363330;
+    color: #D3CAAA;
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 0.70em;
+    text-align: center;
+}
+
+#main
+{
+    width: 720px;
+    margin-left: 160px;
+    padding: 8px 8px 8px 8px;
+    border-left: 1px solid #D3CAAA;
+    border-right: 1px solid #D3CAAA;
+    border-collapse: collapse;
+}
+
+#main td
+{
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 0.8em;
+}
+
+#main td.numeric_odd
+{
+    text-align: right;
+    background-color: #756F68;
+    color: #D3CAAA;
+}
+
+#main td.numeric_even
+{
+    text-align: right;
+    background-color: #544C4A;
+    color: #D3CAAA;
+}
+
+#main td.label_odd
+{
+    background-color: #413D39;
+    color: #D3CAAA;
+}
+
+#main td.label_even
+{
+    background-color: #5A514F;
+    color: #D3CAAA;
+}
+
+#main th.label
+{
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 1em;
+    font-weight: bold;
+    background-color: #413D39;
+    color: #D3CAAA;
+}
+
+#main caption
+{
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 1.25em;
+    font-weight: bold;
+    padding: 4px;
+    color: #D3CAAA;
+}
+
+a
+{
+    text-decoration: none;
+    color: #D3CAAA;
+}

+ 17 - 0
themes/espresso/theme.php

@@ -0,0 +1,17 @@
+<?php
+    // A dark colorscheme based on a contribution by Márcio Bremm
+    // It is based also on Espresso (gtkrc theme) by Jesse L. Kay
+    $colorscheme = array(
+         'image_background'   => array( 065, 061, 057,   0 ),
+	 'graph_background'   => array( 117, 111, 104,  30 ),
+	 'graph_background_2' => array( 128, 122, 102,  30 ),
+	 'grid_stipple_1'     => array( 140, 140, 140,   0 ),
+         'grid_stipple_2'     => array( 200, 200, 200,   0 ),
+	 'border'             => array( 211, 202, 170,   0 ),
+	 'text'               => array( 211, 202, 170,   0 ),
+	 'rx'                 => array( 211, 202, 170,  50 ),
+	 'rx_border'	      => array(  80,  40,  40,  90 ),
+	 'tx'	              => array( 163, 156, 131,  50 ),
+	 'tx_border'          => array(  60,  60,  60,  90 )
+     );
+?>

+ 183 - 0
themes/light/style.css

@@ -0,0 +1,183 @@
+body 
+{
+    margin: 0;
+    padding: 0;
+}
+
+a[href]:link,
+a[href]:visited {
+    color: #00f;
+    text-decoration: none;
+}
+a[href]:hover,
+a[href]:active,
+a[href]:focus {
+    color: #c00;
+    text-decoration: none;
+}
+
+#wrap
+{
+   xwidth: 868px;
+}
+
+#sidebar
+{
+    width: 160px;
+    border-right: 1px solid #99b;
+    border-collapse: collapse;
+    float: left;
+}
+
+#sidebar ul.iface
+{
+    margin: 0;
+    padding: 0;
+    border-top: 1px solid #99b;    
+    color: #000;
+    background-color: #eef;
+}
+
+#sidebar li.iface ul
+{
+    display: none;
+}
+#sidebar li.iface.active ul
+{
+    display: block;
+}
+#sidebar li.iface:hover ul
+{
+    display: block;
+}
+#sidebar li.iface
+{
+    margin: 2px;
+    padding: 0;
+    list-style-type: none;
+    font-size: 12px;
+    font-weight: bold;
+    xborder-top: 1px solid #99b;
+    border-bottom: 1px solid #99b;
+}
+
+#sidebar a
+{
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 1em;
+    font-weight: bold;
+}
+
+#sidebar ul.page
+{
+    margin: 0;
+    padding: 0;
+    border-top: 1px solid #99b;
+}
+
+#sidebar li.page 
+{
+    margin: 0;
+    padding: 4px;
+    border: none;
+    list-style-type: none;
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 0.75em;
+    font-weight: normal;
+    text-align: right;
+    color: #000;    
+    background-color: #fff;
+}
+
+#content
+{
+    margin-left: 160px;
+    width: 720px;
+}
+
+
+#header
+{
+    padding: 0px 8px 0px 8px;
+    border-width: 1px;
+    border-style: solid solid solid solid;
+    border-color: #99b;
+    border-collapse: collapse;
+    color: #000;    
+    background-color: #eef;
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 1em;
+    font-weight: bold;    
+    text-align: center;
+}
+
+#footer
+{
+    padding: 2px 8px 2px 8px;
+    border: 1px solid #99b;
+    border-collapse: collapse;
+    color: #000;    
+    background-color: #eef;
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 0.65em;
+    font-weight: bold;    
+    text-align: center;
+}
+
+#main
+{
+    padding: 8px;
+    border-left: 1px solid #99b;
+    border-right: 1px solid #99b;
+    border-bottom: 1px solid #99b;
+    border-collapse: collapse;
+}
+
+#main td
+{
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 0.8em;
+}
+
+#main td.numeric_odd
+{
+    text-align: right;
+    color: #000;
+    background-color: #eef;
+}
+
+#main td.numeric_even
+{
+    text-align: right;
+    color: #000;    
+    background-color: #fff;
+}
+
+#main td.label_odd
+{
+    color: #000;
+    background-color: #dde;
+}
+
+#main td.label_even
+{
+    color: #000;
+    background-color: #eee;
+}
+
+#main th.label
+{
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 1em;
+    font-weight: bold;
+    color: #000;    
+    background-color: #dde;
+}
+
+#main caption
+{
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 1.25em;
+    font-weight: bold;
+    padding: 4px;
+}

+ 15 - 0
themes/light/theme.php

@@ -0,0 +1,15 @@
+<?php
+    $colorscheme = array(
+         'image_background'   => array( 255, 255, 255,   0 ),
+	 'graph_background'   => array( 220, 220, 230,   0 ),
+	 'graph_background_2' => array( 205, 205, 220,   0 ),
+	 'grid_stipple_1'     => array( 140, 140, 140,   0 ),
+         'grid_stipple_2'     => array( 200, 200, 200,   0 ),
+	 'border'             => array(   0,   0,   0,   0 ),
+	 'text'               => array(   0,   0,   0,   0 ),
+	 'rx'                 => array( 190, 190,  20,  50 ),
+	 'rx_border'	      => array(  40,  80,  40,  90 ),
+	 'tx'	              => array( 130, 160, 100,  50 ),
+	 'tx_border'          => array(  80,  40,  40,  90 )
+     );
+?>

+ 170 - 0
themes/red/style.css

@@ -0,0 +1,170 @@
+body
+{
+	background-color: #D2D2D2;
+	margin: 8px;
+	padding: 0;
+}
+
+#content
+{
+    width: 898px;
+}
+
+#sidebar
+{
+    position: absolute;
+    left: 8px;
+    top: 8px;
+    width: 160px;
+    border-right: 1px solid #82001D;
+    border-collapse: collapse;
+    float: left;
+}
+
+#sidebar ul.iface
+{
+    margin: 0px;
+    padding: 0px;
+    border-top: 1px dashed #82001D;
+    background-color: #D2D2D2;
+    color: #82001D;
+}
+
+#sidebar li.iface
+{
+    list-style-type: none;
+    margin: 0px;
+    padding: 0px;
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 1em;
+    font-weight: bold;
+    border-bottom: 1px dashed #82001D;
+}
+
+#sidebar a
+{
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 1em;
+    font-weight: bold;
+}
+
+#sidebar ul.page
+{
+    margin: 0px;
+    padding: 0px;
+    border-top: 1px dashed #82001D;
+}
+
+#sidebar li.page
+{
+    list-style-type: none;
+    margin: 0px;
+    padding: 4px;
+    border: none;
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 0.75em;
+    font-weight: normal;
+    text-align: right;
+    background-color: #C1C1C1;
+    color: #82001D;
+}
+
+
+#header
+{
+    width: 720px;
+    margin-left: 160px;
+    padding: 0px 8px 0px 8px;
+    border-width: 1px 1px 1px 1px;
+    border-style: dashed solid dashed solid;
+    border-color: #82001D;
+    border-collapse: collapse;
+    background-color: #D2D2D2;
+    color: #82001D;
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 1em;
+    font-weight: bold;
+    text-align: center;
+}
+
+#footer
+{
+    width: 720px;
+    margin-left: 160px;
+    padding: 2px 8px 2px 8px;
+    border-width: 1px 1px 1px 1px;
+    border-style: solid;
+    border-color: #82001D;
+    border-collapse: collapse;
+    background-color: #D2D2D2;
+    color: #82001D;
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 0.70em;
+    text-align: center;
+}
+
+#main
+{
+    width: 720px;
+    margin-left: 160px;
+    padding: 8px 8px 8px 8px;
+    border-left: 1px solid #82001D;
+    border-right: 1px solid #82001D;
+    border-collapse: collapse;
+}
+
+#main td
+{
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 0.8em;
+}
+
+#main td.numeric_odd
+{
+    text-align: right;
+    background-color: #C9C9C9;
+    color: #82001D;
+}
+
+#main td.numeric_even
+{
+    text-align: right;
+    background-color: #CFCFCF;
+    color: #82001D;
+}
+
+#main td.label_odd
+{
+    background-color: #A6A6A6;
+    color: #82001D;
+}
+
+#main td.label_even
+{
+    background-color: #C1C1C1;
+    color: #82001D;
+}
+
+#main th.label
+{
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 1em;
+    font-weight: bold;
+    background-color: #A6A6A6;
+    color: #82001D;
+}
+
+#main caption
+{
+    font-family: 'Trebuchet MS', Verdana, sans-serif;
+    font-size: 1.25em;
+    font-weight: bold;
+    padding: 4px;
+    color: #82001D;
+}
+
+a
+{
+    text-decoration: none;
+    color: #A80022;
+}

+ 16 - 0
themes/red/theme.php

@@ -0,0 +1,16 @@
+<?php
+    // A red colorscheme based on a contribution by Enrico Tröger
+    $colorscheme = array(
+         'image_background'   => array( 225, 225, 225,   0 ),
+	 'graph_background'   => array( 220, 220, 230,   0 ),
+	 'graph_background_2' => array( 205, 205, 220,   0 ),
+	 'grid_stipple_1'     => array( 140, 140, 140,   0 ),
+         'grid_stipple_2'     => array( 200, 200, 200,   0 ),
+	 'border'             => array(   0,   0,   0,   0 ),
+	 'text'               => array(   0,   0,   0,   0 ),
+	 'rx'                 => array( 190,  20,  20,  50 ),
+	 'rx_border'	      => array(  80,  40,  40,  90 ),
+	 'tx'	              => array( 130, 130, 130,  50 ),
+	 'tx_border'          => array(  60,  60,  60,  90 )
+     );
+?>

+ 124 - 0
vera_copyright.txt

@@ -0,0 +1,124 @@
+Bitstream Vera Fonts Copyright
+
+The fonts have a generous copyright, allowing derivative works (as
+long as "Bitstream" or "Vera" are not in the names), and full
+redistribution (so long as they are not *sold* by themselves). They
+can be be bundled, redistributed and sold with any software.
+
+The fonts are distributed under the following copyright:
+
+Copyright
+=========
+
+Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream
+Vera is a trademark of Bitstream, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the fonts accompanying this license ("Fonts") and associated
+documentation files (the "Font Software"), to reproduce and distribute
+the Font Software, including without limitation the rights to use,
+copy, merge, publish, distribute, and/or sell copies of the Font
+Software, and to permit persons to whom the Font Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright and trademark notices and this permission notice
+shall be included in all copies of one or more of the Font Software
+typefaces.
+
+The Font Software may be modified, altered, or added to, and in
+particular the designs of glyphs or characters in the Fonts may be
+modified and additional glyphs or characters may be added to the
+Fonts, only if the fonts are renamed to names not containing either
+the words "Bitstream" or the word "Vera".
+
+This License becomes null and void to the extent applicable to Fonts
+or Font Software that has been modified and is distributed under the
+"Bitstream Vera" names.
+
+The Font Software may be sold as part of a larger software package but
+no copy of one or more of the Font Software typefaces may be sold by
+itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
+BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL,
+OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT
+SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
+
+Except as contained in this notice, the names of Gnome, the Gnome
+Foundation, and Bitstream Inc., shall not be used in advertising or
+otherwise to promote the sale, use or other dealings in this Font
+Software without prior written authorization from the Gnome Foundation
+or Bitstream Inc., respectively. For further information, contact:
+fonts at gnome dot org.
+
+Copyright FAQ
+=============
+
+   1. I don't understand the resale restriction... What gives?
+
+      Bitstream is giving away these fonts, but wishes to ensure its
+      competitors can't just drop the fonts as is into a font sale system
+      and sell them as is. It seems fair that if Bitstream can't make money
+      from the Bitstream Vera fonts, their competitors should not be able to
+      do so either. You can sell the fonts as part of any software package,
+      however.
+
+   2. I want to package these fonts separately for distribution and
+      sale as part of a larger software package or system.  Can I do so?
+
+      Yes. A RPM or Debian package is a "larger software package" to begin 
+      with, and you aren't selling them independently by themselves. 
+      See 1. above.
+
+   3. Are derivative works allowed?
+      Yes!
+
+   4. Can I change or add to the font(s)?
+      Yes, but you must change the name(s) of the font(s).
+
+   5. Under what terms are derivative works allowed?
+
+      You must change the name(s) of the fonts. This is to ensure the
+      quality of the fonts, both to protect Bitstream and Gnome. We want to
+      ensure that if an application has opened a font specifically of these
+      names, it gets what it expects (though of course, using fontconfig,
+      substitutions could still could have occurred during font
+      opening). You must include the Bitstream copyright. Additional
+      copyrights can be added, as per copyright law. Happy Font Hacking!
+
+   6. If I have improvements for Bitstream Vera, is it possible they might get 
+       adopted in future versions?
+
+      Yes. The contract between the Gnome Foundation and Bitstream has
+      provisions for working with Bitstream to ensure quality additions to
+      the Bitstream Vera font family. Please contact us if you have such
+      additions. Note, that in general, we will want such additions for the
+      entire family, not just a single font, and that you'll have to keep
+      both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add
+      glyphs to the font, they must be stylistically in keeping with Vera's
+      design. Vera cannot become a "ransom note" font. Jim Lyles will be
+      providing a document describing the design elements used in Vera, as a
+      guide and aid for people interested in contributing to Vera.
+
+   7. I want to sell a software package that uses these fonts: Can I do so?
+
+      Sure. Bundle the fonts with your software and sell your software
+      with the fonts. That is the intent of the copyright.
+
+   8. If applications have built the names "Bitstream Vera" into them, 
+      can I override this somehow to use fonts of my choosing?
+
+      This depends on exact details of the software. Most open source
+      systems and software (e.g., Gnome, KDE, etc.) are now converting to
+      use fontconfig (see www.fontconfig.org) to handle font configuration,
+      selection and substitution; it has provisions for overriding font
+      names and subsituting alternatives. An example is provided by the
+      supplied local.conf file, which chooses the family Bitstream Vera for
+      "sans", "serif" and "monospace".  Other software (e.g., the XFree86
+      core server) has other mechanisms for font substitution.
+

+ 230 - 0
vnstat.php

@@ -0,0 +1,230 @@
+<?php
+    //
+    // vnStat PHP frontend (c)2006-2010 Bjorge Dijkstra (bjd@jooz.net)
+    //
+    // This program is free software; you can redistribute it and/or modify
+    // it under the terms of the GNU General Public License as published by
+    // the Free Software Foundation; either version 2 of the License, or
+    // (at your option) any later version.
+    //
+    // This program is distributed in the hope that it will be useful,
+    // but WITHOUT ANY WARRANTY; without even the implied warranty of
+    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    // GNU General Public License for more details.
+    //
+    // You should have received a copy of the GNU General Public License
+    // along with this program; if not, write to the Free Software
+    // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+    //
+    //
+    // see file COPYING or at http://www.gnu.org/licenses/gpl.html
+    // for more information.
+    //
+
+    //
+    // Valid values for other parameters you can pass to the script.
+    // Input parameters will always be limited to one of the values listed here.
+    // If a parameter is not provided or invalid it will revert to the default,
+    // the first parameter in the list.
+    //
+    if (isset($_SERVER['PHP_SELF']))
+    {
+        $script = $_SERVER['PHP_SELF'];
+    }
+    elseif (isset($_SERVER['SCRIPT_NAME']))
+    {
+        $script = $_SERVER['SCRIPT_NAME'];
+    }
+    else
+    {
+        die('can\'t determine script name!');
+    }
+
+    $page_list  = array('s','h','d','m');
+
+    $graph_list = array('large','small','none');
+
+    $page_title['s'] = T('summary');
+    $page_title['h'] = T('hours');
+    $page_title['d'] = T('days');
+    $page_title['m'] = T('months');
+
+
+    //
+    // functions
+    //
+    function validate_input()
+    {
+        global $page,  $page_list;
+        global $iface, $iface_list;
+        global $graph, $graph_list;
+        global $colorscheme, $style;
+        //
+        // get interface data
+        //
+        $page = isset($_GET['page']) ? $_GET['page'] : '';
+        $iface = isset($_GET['if']) ? $_GET['if'] : '';
+        $graph = isset($_GET['graph']) ? $_GET['graph'] : '';
+        $style = isset($_GET['style']) ? $_GET['style'] : '';
+
+        if (!in_array($page, $page_list))
+        {
+            $page = $page_list[0];
+        }
+
+        if (!in_array($iface, $iface_list))
+        {
+            $iface = $iface_list[0];
+        }
+
+        if (!in_array($graph, $graph_list))
+        {
+            $graph = $graph_list[0];
+        }
+
+        $tp = "./themes/$style";
+        if (!is_dir($tp) || !file_exists("$tp/theme.php") || !preg_match('/^[a-z0-9-_]+$/i', $style))
+        {
+            $style = DEFAULT_COLORSCHEME;
+        }
+    }
+
+
+    function get_vnstat_data($use_label=true)
+    {
+        global $iface, $vnstat_bin, $data_dir;
+        global $hour,$day,$month,$top,$summary;
+
+        $vnstat_data = array();
+        if (!isset($vnstat_bin) || $vnstat_bin == '')
+        {
+            if (file_exists("$data_dir/vnstat_dump_$iface"))
+            {
+                $file_data = file_get_contents("$data_dir/vnstat_dump_$iface");
+                $vnstat_data = json_decode($file_data, TRUE);
+            }
+        }
+        else
+        {
+            // FIXME: use mode and limit parameter to reduce data that needs to be parsed
+            $fd = popen("$vnstat_bin --json -i $iface", "r");
+            if (is_resource($fd))
+            {
+                $buffer = '';
+                while (!feof($fd)) {
+                    $buffer .= fgets($fd);
+                }
+                pclose($fd);
+                $vnstat_data = json_decode($buffer, TRUE);
+            }
+        }
+
+        $day = array();
+        $hour = array();
+        $month = array();
+        $top = array();
+
+        if (!isset($vnstat_data) || !isset($vnstat_data['vnstatversion'])) {
+            return;
+        }
+
+        $iface_data = $vnstat_data['interfaces'][0];
+        $traffic_data = $iface_data['traffic'];
+        // data are grouped for hour, day, month, ... and a data entry looks like this:
+        // [0] => Array
+        //   (
+        //     [id] => 48032
+        //     [date] => Array
+        //       (
+        //         [year] => 2020
+        //         [month] => 8
+        //         [day] => 23
+        //       )
+        //     [time] => Array
+        //       (
+        //         [hour] => 16
+        //         [minute] => 0
+        //       )
+        //     [rx] => 2538730
+        //     [tx] => 2175640
+        //   )
+
+        // per-day data
+        // FIXME: instead of using array_reverse, sorting by date/time keys would be more reliable
+        $day_data = array_reverse($traffic_data['day']);
+        for($i = 0; $i < min(30, count($day_data)); $i++) {
+            $d = $day_data[$i];
+            $ts = mktime(0, 0, 0, $d['date']['month'], $d['date']['day'], $d['date']['year']);
+
+            $day[$i]['time'] = $ts;
+            $day[$i]['rx'] = $d['rx'] / 1024;
+            $day[$i]['tx'] = $d['tx'] / 1024;
+            $day[$i]['act'] = 1;
+
+            if($use_label) {
+                $day[$i]['label'] = strftime(T('datefmt_days'), $ts);
+                $day[$i]['img_label'] = strftime(T('datefmt_days_img'), $ts);
+            }
+        }
+
+        // per-month data
+        $month_data = array_reverse($traffic_data['month']);
+        for($i = 0; $i < min(12, count($month_data)); $i++) {
+            $d = $month_data[$i];
+            $ts = mktime(0, 0, 0, $d['date']['month']+1, 0, $d['date']['year']);
+
+            $month[$i]['time'] = $ts;
+            $month[$i]['rx'] = $d['rx'] / 1024;
+            $month[$i]['tx'] = $d['tx'] / 1024;
+            $month[$i]['act'] = 1;
+
+            if($use_label) {
+                $month[$i]['label'] = strftime(T('datefmt_months'), $ts);
+                $month[$i]['img_label'] = strftime(T('datefmt_months_img'), $ts);
+            }
+        }
+
+        // per-hour data
+        $hour_data = array_reverse($traffic_data['hour']);
+        for($i = 0; $i < min(24, count($hour_data)); $i++) {
+            $d = $hour_data[$i];
+            $ts = mktime($d['time']['hour'], $d['time']['minute'], 0, $d['date']['month'], $d['date']['day'], $d['date']['year']);
+
+            $hour[$i]['time'] = $ts;
+            $hour[$i]['rx'] = $d['rx'] / 1024;
+            $hour[$i]['tx'] = $d['tx'] / 1024;
+            $hour[$i]['act'] = 1;
+
+            if($use_label) {
+                $hour[$i]['label'] = strftime(T('datefmt_hours'), $ts);
+                $hour[$i]['img_label'] = strftime(T('datefmt_hours_img'), $ts);
+            }
+        }
+
+        // top10 days data
+        $top10_data = $traffic_data['top'];
+        for($i = 0; $i < min(10, count($top10_data)); $i++) {
+            $d = $top10_data[$i];
+            $ts = mktime(0, 0, 0, $d['date']['month'], $d['date']['day'], $d['date']['year']);
+
+            $top[$i]['time'] = $ts;
+            $top[$i]['rx'] = $d['rx'] / 1024;
+            $top[$i]['tx'] = $d['tx'] / 1024;
+            $top[$i]['act'] = 1;
+
+            if($use_label) {
+                $top[$i]['label'] = strftime(T('datefmt_top'), $ts);
+                $top[$i]['img_label'] = '';
+            }
+        }
+
+        // summary data from old dumpdb command
+        // all time total received/transmitted MB
+        $summary['totalrx'] = $traffic_data['total']['rx'] / 1024 / 1024;
+        $summary['totaltx'] = $traffic_data['total']['tx'] / 1024 / 1024;
+        // FIXME: used to be "total rx kB counter" from dumpdb, no idea how to get those
+        $summary['totalrxk'] = 0;
+        $summary['totaltxk'] = 0;
+        $summary['interface'] = $iface_data['name'];
+    }
+?>