root/trunk/wifidog-auth/wifidog/classes/MainUI.php @ 1128

Revision 1128, 20.6 KB (checked in by benoitg, 7 years ago)
  • File.php: Clickthrough weren't logged, DOH!
  • User.php: Error message on validation expired didn't properly

output the validation grace time.

  • Statistics.php: Fix #271: Getting statistics for a single MAC

address was broken.

  • NodeListXML.php: Small patch by Josephus to add the number of

online users

  • Improve CPU usage of the content manager
  • AbstractDb?: Fix query time not being displayed in debug mode

if profiling was turned off.

Add total execution time

statistics.

  • Fix logging of content clickthrough and display. Unique users

and node data is reliable for existing data.

Number of prints is underestimated (repeat prints for

the same user, same content at same node didn't get counted)

for data before this patch.

Same with number of clickthrough for File content types

and derivatives (picture, etc.).

options yet, but still very usefull).

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1<?php
2
3
4/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
5
6// +-------------------------------------------------------------------+
7// | WiFiDog Authentication Server                                     |
8// | =============================                                     |
9// |                                                                   |
10// | The WiFiDog Authentication Server is part of the WiFiDog captive  |
11// | portal suite.                                                     |
12// +-------------------------------------------------------------------+
13// | PHP version 5 required.                                           |
14// +-------------------------------------------------------------------+
15// | Homepage:     http://www.wifidog.org/                             |
16// | Source Forge: http://sourceforge.net/projects/wifidog/            |
17// +-------------------------------------------------------------------+
18// | This program is free software; you can redistribute it and/or     |
19// | modify it under the terms of the GNU General Public License as    |
20// | published by the Free Software Foundation; either version 2 of    |
21// | the License, or (at your option) any later version.               |
22// |                                                                   |
23// | This program is distributed in the hope that it will be useful,   |
24// | but WITHOUT ANY WARRANTY; without even the implied warranty of    |
25// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     |
26// | GNU General Public License for more details.                      |
27// |                                                                   |
28// | You should have received a copy of the GNU General Public License |
29// | along with this program; if not, contact:                         |
30// |                                                                   |
31// | Free Software Foundation           Voice:  +1-617-542-5942        |
32// | 59 Temple Place - Suite 330        Fax:    +1-617-542-2652        |
33// | Boston, MA  02111-1307,  USA       gnu@gnu.org                    |
34// |                                                                   |
35// +-------------------------------------------------------------------+
36
37/**
38 * @package    WiFiDogAuthServer
39 * @author     Benoit Grégoire <bock@step.polymtl.ca>
40 * @copyright  2005-2006 Benoit Grégoire, Technologies Coeus inc.
41 * @version    Subversion $Id$
42 * @link       http://www.wifidog.org/
43 */
44
45/**
46 * @internal We put a call to validate_schema() here so it systematically called
47 * from any UI page, but not from any machine readable pages
48 */
49require_once ('include/schema_validate.php');
50validate_schema();
51
52/**
53 * If the database doesn't get cleaned up by a cron job, we'll do now
54 */
55if (CONF_USE_CRON_FOR_DB_CLEANUP == false)
56{
57        garbage_collect();
58}
59
60/**
61 * Load required file
62 */
63require_once ('include/common_interface.php');
64
65/**
66 * Singleton class for managing headers, footers, stylesheet, etc.
67 *
68 * @package    WiFiDogAuthServer
69 * @author     Benoit Grégoire <bock@step.polymtl.ca>
70 * @copyright  2005-2006 Benoit Grégoire, Technologies Coeus inc.
71 */
72class MainUI
73{
74/** holder for the singleton */
75        private static $object;
76
77        /**
78        * Content to be displayed the page
79        *
80        * @var array
81        * @access private
82        */
83        private $_contentDisplayArray;
84
85        /**
86        * Content to be displayed on the page, before ordering
87        *
88        * @var array
89        * @access private
90        */
91        private $_contentArray;
92
93        /**
94         * Object for Smarty class
95         *
96         * @var object
97         * @access private
98         */
99        private $smarty;
100
101        /**
102         * Title of HTML page
103         *
104         * @var string
105         * @access private
106         */
107        private $title;
108        /**
109         * Additional class of the <body> of the HTML page
110         */
111        private $_pageName;
112
113        /** list of URLs to stylesheet to be included */
114        private $stylesheetUrlArray=array();
115
116        /**
117         * Headers of HTML page
118         *
119         * @var private
120         * @access private
121         */
122        private $_htmlHeaders;
123
124        /**
125         * Defines if tool section of HTML page is enabled or not
126         *
127         * @var bool
128         * @access private
129         */
130        private $_toolSectionEnabled = true;
131
132        /**
133         * Scripts for the footer
134         *
135         * @var array
136         * @access private
137         */
138        private $_footerScripts = array ();
139
140        private $_shrinkLeftArea = false;
141    /**
142     * Get the MainUI object
143     * @return object The MainUI object
144     */
145    public static function getObject() {
146        if (self::$object==null)
147        {
148                self::$object=new self();
149        }
150        return self::$object;
151    }
152        /**
153         * Contructor
154         *
155         * @return void
156         *
157         * @access public
158         */
159        private function __construct()
160        {
161                $db = AbstractDb::getObject();
162                // Init Smarty
163                $this->smarty = SmartyWifidog::getObject();
164
165                // Set default title
166                $this->title = Network :: getCurrentNetwork()->getName() . ' ' . _("authentication server");
167                // Init the content array
168                $current_content_sql = "SELECT display_area FROM content_available_display_areas\n";
169                $rows = array ();
170                $db->execSql($current_content_sql, $rows, false);
171                foreach ($rows as $row)
172                {
173                        $this->_contentDisplayArray[$row['display_area']] = '';
174                }
175        }
176
177        /**
178         * Add content to a structural area of the page
179         *
180         * @param string $display_area Structural area where content is to be
181         * placed.  Must be one of the display aread defined in the
182         * content_available_display_areas table
183         *
184         * @param string $content Either a Content object (recommended) or raw HTML content to be added to the area
185         *
186         * @param integer $display_order_index The order in which the content should
187         * be displayed
188         *
189         * @return void
190         */
191        public function addContent($displayArea, $content, $displayOrderIndex = 1)
192        {
193                //echo "MainUI::addContent(): Debug: displayArea: $displayArea, displayOrderIndex: $displayOrderIndex, content: $content<br/>";
194                if (!isset ($this->_contentDisplayArray[$displayArea]))
195                {
196                        throw new exception(sprintf(_('%s is not a valid structural display area'), $displayArea));
197                }
198                $this->_contentArray[] = array (
199                        'display_area' => $displayArea,
200                        'display_order' => $displayOrderIndex,
201                        'content' => $content
202                );
203        }
204
205        /** Private compare function for sorting the _contentArray() */
206        private static function _contentArrayCmp($a, $b)
207        {
208                if ($a['display_order'] == $b['display_order'])
209                {
210                        return 0;
211                }
212                return ($a['display_order'] < $b['display_order']) ? -1 : 1;
213        }
214
215        /** Main processing function do generate the final content.
216         * It will successively call prepareGetUserUI() on all content objects,
217         * and then getUserUI() on all objects.  Note that the point of calling
218         * prepareGetUserUI is to allow that function to call methods of MainUI
219         * (such ans changing headers, etc.).  However, please note that you should not
220         * call MainUI::addContent() from prepareGetUserUI, as prepareGetUserUI() wouldn't
221         * in turn get called on objects added this way.
222         * Orders the content and put it in the _contentDisplayArray array
223         *
224         * @return void
225         */
226        private function generateDisplayContent()
227        {
228                //pretty_print_r($this->_contentArray);
229                usort($this->_contentArray, array (
230                        $this,
231                        "_contentArrayCmp"
232                ));
233               
234                //Fist pass (preparation pass)
235                foreach ($this->_contentArray as $content_fragment)
236                {
237                        $content=$content_fragment['content'];
238
239                if (is_object($content))
240                {
241                if ($content instanceof Content)
242                        {
243                            //echo "<h1>prepareGetUserUI on ".$content->getId()."</h1>";
244                                $content->prepareGetUserUI();
245                        }
246                        else
247                        {
248                        throw new exception ("Object must be a subclass of Content");
249                        }
250                }
251
252                }
253                foreach ($this->_contentArray as $content_fragment)
254                {
255                    $content=$content_fragment['content'];
256                        if (is_object($content))
257                {
258                        if ($content instanceof Content)
259                        {
260                                $this->_contentDisplayArray[$content_fragment['display_area']] .= $content->getUserUI();
261                        }
262                        else
263                        {
264                        throw new exception ("Object must be a subclass of Content");
265                        }
266                }
267                else
268                {
269                    $this->_contentDisplayArray[$content_fragment['display_area']] .= $content;
270                }
271                }
272
273        }
274
275        /**
276         * Add the content marked "everywhere" from both the current node and the
277         * current network.
278         *
279         * @return void
280         */
281        private function addEverywhereContent()
282        {
283                $db = AbstractDb::getObject();
284                // Get all network content and node "everywhere" content
285                $content_rows = null;
286                $network_id = $db->escapeString(Network :: getCurrentNetwork()->getId());
287                $sql_network = "(SELECT content_id, display_area, display_order, subscribe_timestamp FROM network_has_content WHERE network_id='$network_id'  AND display_page='everywhere') ";
288                $node = Node :: getCurrentNode();
289                $sql_node = null;
290                if ($node)
291                {
292                        // Get all node content
293                        $node_id = $db->escapeString($node->getId());
294                        $sql_node = "UNION (SELECT content_id, display_area, display_order, subscribe_timestamp FROM node_has_content WHERE node_id='$node_id'  AND display_page='everywhere')";
295                }
296                $sql = "SELECT * FROM ($sql_network $sql_node) AS content_everywhere ORDER BY display_area, display_order, subscribe_timestamp DESC";
297
298                $db->execSql($sql, $content_rows, false);
299                if ($content_rows)
300                {
301                        foreach ($content_rows as $content_row)
302                        {
303                                $content = Content :: getObject($content_row['content_id']);
304                                if ($content->isDisplayableAt($node))
305                                {
306                                        $this->addContent($content_row['display_area'], $content, $content_row['display_order']);
307                                }
308                        }
309                }
310
311        }
312
313        /**
314        * Check if the tool section is enabled
315        *
316        * @return bool True or false
317        *
318        * @access public
319        */
320        public function isToolSectionEnabled()
321        {
322                return $this->_toolSectionEnabled;
323        }
324
325        /**
326         * Check if the tool section is enabled
327         *
328         * @return bool True or false
329         *
330         * @access public
331         */
332        public function setToolSectionEnabled($status)
333        {
334                $this->_toolSectionEnabled = $status;
335        }
336
337        /**
338         * Set the title of the HTML page
339         *
340         * @param string $title_string Title of the HTML page
341         *
342         * @return void
343         *
344         * @access public
345         */
346        public function setTitle($title_string)
347        {
348                $this->title = $title_string;
349        }
350
351        public function shrinkLeftArea()
352        {
353                $this->_shrinkLeftArea = true;
354        }
355
356        /**
357         * Set the class name of the <body> of the resulting page.
358         *
359         * @param string $page_name_string The page name of the resulting page.  Must have no spaces.  ex:  portal, login, userprofile, etc.)
360         *
361         * @return void
362         *
363         * @access public
364         */
365        public function setPageName($page_name_string)
366        {
367                $this->_pageName = $page_name_string;
368        }
369
370        /**
371        * Add content at the very end of the <body>.
372        *
373        * This is NOT meant to add footers or other display content, it is meant
374        * to add <script></script> tag pairs that have to be executed only once
375        * the page is loaded.
376        *
377        * @param string $script A piece of script surrounded by
378        *                       <script></script> tags.
379        *
380        * @return void
381        *
382        * @access public
383        */
384        public function addFooterScript($script)
385        {
386                $this->_footerScripts[] = $script;
387        }
388
389        /**
390         * Set the HTML page headers
391         *
392         * @param string $headers_string HTML page headers
393         *
394         * @return void
395         *
396         * @access public
397         */
398        public function setHtmlHeader($headers_string)
399        {
400                $this->_htmlHeaders = $headers_string;
401        }
402       
403        /**
404         * Add a stylesheet URL to the main page
405         *
406         * @param string Stylesheet URL
407         *
408         * @return void
409         *
410         * @access public
411         */
412        public function appendStylesheetURL($stylesheet_url)
413        {
414            //Note:  using the URL as value AND key will remove duplicate while keeping the stylesheet inclusion order, because of the way foreach is implemented in PHP
415                $this->stylesheetUrlArray[$stylesheet_url] = $stylesheet_url;
416        }
417        /**
418         * Set the section to be displayed in the tool pane
419         *
420         * @param string $section Section to be displayed:
421         *                          + ADMIN for administration tool pane
422         *
423         * @return string HTML code of tool pane
424         *
425         * @access public
426         */
427        public function setToolSection($section)
428        {
429                // Init ALL smarty SWITCH values
430                $this->smarty->assign('sectionADMIN', false);
431
432                switch ($section)
433                {
434                        case "ADMIN" :
435                                // Set section of Smarty template
436                                $this->smarty->assign('sectionADMIN', true);
437
438                                // Get information about user
439                                $_currentUser = User :: getCurrentUser();
440
441                                        // Init values
442                                        $_sqlAdditionalWhere = "";
443
444                                        // Init ALL smarty values
445                                        User :: assignSmartyValues($this->smarty, $_currentUser);
446                                        $this->smarty->assign('formAction', "");
447                                        $this->smarty->assign('nodeUI', "");
448                                        $this->smarty->assign('networkUI', "");
449
450                                        /*
451                                         * If the user is super admin OR owner of at least one node
452                                         * show the node menu
453                                         */
454                                        if ($_currentUser && ($_currentUser->isSuperAdmin() || $_currentUser->isOwner()))
455                                        {
456                                                // Assign the action URL for the form
457                                                $this->smarty->assign('formAction', GENERIC_OBJECT_ADMIN_ABS_HREF);
458
459                                                /*
460                                                 * If current user is a owner the SQL query must be changed
461                                                 * to return his nodes only
462                                                 */
463                                                if (!$_currentUser->isSuperAdmin())
464                                                {
465                                                        $_sqlAdditionalWhere = "AND node_id IN (SELECT node_id from node_stakeholders WHERE is_owner = true AND user_id='" . $_currentUser->getId() . "')";
466                                                }
467
468                                                // Provide node select control to the template
469                                                $this->smarty->assign('nodeUI', Node :: getSelectNodeUI('object_id', $_sqlAdditionalWhere));
470                                        }
471
472                                        // If the user is network admin show the network menu
473                                        if ($_currentUser && $_currentUser->isSuperAdmin())
474                                        {
475                                                // Provide network select control to the template
476                                                $this->smarty->assign('networkUI', Network :: getSelectNetworkUI('object_id'));
477                                        }
478
479                                        // Compile HTML code
480                                        $_html = $this->smarty->fetch("templates/classes/MainUI_ToolSection.tpl");
481                                break;
482
483                        default :
484                                $_html = _("Unknown section:") . $section;
485                                break;
486                }
487
488                $this->addContent('left_area_middle', $_html);
489        }
490
491        /**
492         * Get the content to be displayed in the tool pane
493         *
494         * @return string HTML markup
495         *
496         * @access private
497         */
498        private function getToolContent()
499        {
500               
501                $session = Session::getObject();
502                global $AVAIL_LOCALE_ARRAY;
503
504                // Init values
505                $_html = "";
506                $_gwId = null;
507                $_gwAddress = null;
508                $_gwPort = null;
509                $_selected = "";
510                $_languageChooser = array ();
511
512                // Init ALL smarty SWITCH values
513                $this->smarty->assign('sectionSTART', false);
514                $this->smarty->assign('sectionLOGIN', false);
515
516                // Set section of Smarty template
517                $this->smarty->assign('sectionSTART', true);
518
519                // Get information about user
520                $_currentUser = User :: getCurrentUser();
521
522                User :: assignSmartyValues($this->smarty, $_currentUser);
523
524                $this->smarty->assign('logoutParameters', "");
525                $this->smarty->assign('loginParameters', "");
526                $this->smarty->assign('formAction', "");
527                $this->smarty->assign('toolContent', "");
528                $this->smarty->assign('accountInformation', "");
529                $this->smarty->assign('techSupportInformation', "");
530                $this->smarty->assign('shrinkLeftArea', $this->_shrinkLeftArea);
531
532                // Provide Smarty with information about the network
533                Network :: assignSmartyValues($this->smarty);
534
535                /*
536                 * Provide Smarty information about the user's login/logout status
537                 */
538
539                if ($_currentUser != null)
540                {
541                        // User is logged in
542
543                        // Detect gateway information
544                        $_gwId = $session->get(SESS_GW_ID_VAR);
545                        $_gwAddress = $session->get(SESS_GW_ADDRESS_VAR);
546                        $_gwPort = $session->get(SESS_GW_PORT_VAR);
547
548                        // If gateway information could be detected tell them Smarty
549                        if ($_gwId && $_gwAddress && $_gwPort)
550                        {
551                                $this->smarty->assign('logoutParameters', "&amp;gw_id=" . $_gwId . "&amp;gw_address=" . $_gwAddress . "&amp;gw_port=" . $_gwPort);
552                        }
553                }
554                else
555                {
556                        // Detect gateway information
557                        $_gwId = !empty ($_REQUEST['gw_id']) ? $_REQUEST['gw_id'] : $session->get(SESS_GW_ID_VAR);
558                        $_gwAddress = !empty ($_REQUEST['gw_address']) ? $_REQUEST['gw_address'] : $session->get(SESS_GW_ADDRESS_VAR);
559                        $_gwPort = !empty ($_REQUEST['gw_port']) ? $_REQUEST['gw_port'] : $session->get(SESS_GW_PORT_VAR);
560
561                        // If gateway information could be detected tell them Smarty
562                        if (!empty ($_gwId) && !empty ($_gwAddress) && !empty ($_gwPort))
563                        {
564                                $this->smarty->assign('loginParameters', "?gw_id=" . $_gwId . "&amp;gw_address=" . $_gwAddress . "&amp;gw_port=" . $_gwPort);
565                        }
566                }
567
568                /*
569                 * Provide Smarty information for the language chooser
570                 */
571
572                // Assign the action URL for the form
573                $this->smarty->assign('formAction', $_SERVER['REQUEST_URI']);
574
575                foreach ($AVAIL_LOCALE_ARRAY as $_langIds => $_langNames)
576                {
577                        if (Locale :: getCurrentLocale()->getId() == $_langIds)
578                        {
579                                $_selected = ' selected="selected"';
580                        }
581                        else
582                        {
583                                $_selected = "";
584                        }
585
586                        $_languageChooser[] = '<option label="' . $_langNames . '" value="' . $_langIds . '"' . $_selected . '>' . $_langNames . '</option>';
587                }
588
589                // Provide Smarty all available languages
590                $this->smarty->assign('languageChooser', $_languageChooser);
591
592                // Compile HTML code
593                $_html = $this->smarty->fetch("templates/classes/MainUI_ToolContent.tpl");
594
595                return $_html;
596        }
597
598        /**
599         * Display the main page
600         *
601         * @return void
602         *
603         * @access public
604         * @internal Uses a few request parameters to display debug information.
605         * If $_REQUEST['debug_request'] is present, it will print out the
606         * $_REQUEST array at the top of the page.
607         */
608        public function display()
609        {
610        $db=AbstractDb::getObject();
611                // Init values
612                // Asign base CSS and theme pack CSS stylesheet
613                $this->appendStylesheetURL(BASE_THEME_URL . STYLESHEET_NAME);
614                $networkThemePack = Network :: getCurrentNetwork()->getThemePack();
615                if ($networkThemePack) {
616                                $this->appendStylesheetURL($networkThemePack->getStylesheetUrl());
617                }
618               
619                //Handle content (must be done before headers and anything else is handled)
620                /*
621                 * Build tool pane if it has been enabled
622                 */
623                if ($this->isToolSectionEnabled())
624                {
625                        $this->addContent('left_area_top', $this->getToolContent());
626                }
627                $this->addEverywhereContent();
628                $this->generateDisplayContent();
629
630                // Init ALL smarty values
631                $this->smarty->assign('htmlHeaders', "");
632                // $this->smarty->assign('isSuperAdmin', false);
633                // $this->smarty->assign('isOwner', false);
634                $this->smarty->assign('debugRequested', false);
635                $this->smarty->assign('debugOutput', "");
636                $this->smarty->assign('footerScripts', array ());
637
638                // Add HTML headers
639                $this->smarty->assign('htmlHeaders', $this->_htmlHeaders);
640
641                // Asign title
642                $this->smarty->assign('title', $this->title);
643
644                // Asign CSS class for body
645                $this->smarty->assign('page_name', $this->_pageName);
646               
647                $this->smarty->assign('stylesheetUrlArray', $this->stylesheetUrlArray);
648
649                /*
650                 * Allow super admin to display debug output if requested by using
651                 * $_REQUEST['debug_request']
652                 */
653
654                // Get information about user
655                User :: assignSmartyValues($this->smarty);
656
657                // Provide footer scripts to Smarty
658                $this->smarty->assign('footerScripts', $this->_footerScripts);
659
660        // Add SQL queries log (must be done manually here at the very end to catch everything)
661        if(defined("LOG_SQL_QUERIES") && LOG_SQL_QUERIES == true)
662            $this->_contentDisplayArray['page_footer'] .= $db->getSqlQueriesLog();
663       
664        // Provide the content array to Smarty
665        $this->smarty->assign('contentDisplayArray', $this->_contentDisplayArray);
666           
667                // Compile HTML code and output it
668                $this->smarty->display("templates/classes/MainUI_Display.tpl");
669        }
670
671        /**
672         * Display a generic error message
673         *
674         * @param string $errmsg                  The error message to be displayed
675         * @param bool   $show_tech_support_email Defines wether to show the link of
676         *                                        the tech-support
677         *
678         * @return void
679         *
680         * @access public
681         */
682        function displayError($errmsg, $show_tech_support_email = true)
683        {
684                // Init ALL smarty values
685                $this->smarty->assign("error", "");
686                $this->smarty->assign("show_tech_support_email", false);
687                $this->smarty->assign("tech_support_email", "");
688
689                // Define needed error content
690                $this->smarty->assign("error", $errmsg);
691
692                if ($show_tech_support_email)
693                {
694                        $this->smarty->assign("show_tech_support_email", true);
695                        $this->smarty->assign("tech_support_email", Network :: getCurrentNetwork()->getTechSupportEmail());
696                }
697
698                /*
699                 * Output the error message
700                 */
701                $_html = $this->smarty->fetch("templates/sites/error.tpl");
702
703                $this->addContent('page_header', $_html);
704                $this->display();
705        }
706
707        static public function redirect($redirect_url, $redirect_to_title = null, $timeout = 60)
708        {
709                if (!$redirect_to_title)
710                {
711                        $network = Network :: getCurrentNetwork();
712                        $redirect_to_title = $network ? sprintf(_("%s Login"), $network->getName()) : _("Login");
713                }
714
715                header("Location: $redirect_url");
716                echo "<html>\n" . "<head><meta http-equiv='Refresh' content='$timeout; URL=$redirect_url'/></head>\n" . "<body>\n" . "<noscript>\n" . "<span style='display:none;'>\n" . "<h1>" . $redirect_to_title . "</h1>\n" . sprintf(_("Click <a href='%s'>here</a> to continue"), $redirect_url) . "<br/>\n" . _("The transfer from secure login back to regular http may cause a warning.") . "\n" . "</span>\n" . "</noscript>\n" . "</body>\n" . "</html>\n";
717                exit;
718        }
719}
720
721/*
722 * Local variables:
723 * tab-width: 4
724 * c-basic-offset: 4
725 * c-hanging-comment-ender-p: nil
726 * End:
727 */
Note: See TracBrowser for help on using the browser.