root/trunk/wifidog-auth/wifidog/classes/NodeLists/NodeListPDF.php @ 1249

Revision 1249, 34.1 KB (checked in by benoitg, 6 years ago)

-This is a behemoth "the road to 1.0" commit. I've been working on this for 6 months,
and it's reached the point where others can help. Those are very far reaching changes, please
notify me if anything isn't working right (and im sure I can't have caught everything).

Mostly complete. Missing parts are Content stakeholders, system roles and "su" functionnality.
I need help replacing all the DEPRECATED* methods. Please read the wiki page above for instructions.

  • generic_object_admin.php: More work towards making it generic once again.
  • GenericDataObject?: New class. Eventually, most classes should extend this, instead of directly implementing GenericObject?
  • Menu.php: Finally a uniform Menuing system to replace the mismatch of links that made wifidog impossible to navigate. It's not very sophisticated yet, but it IS permission aware Loosely inspired from Drupal's menuing system. HTML is slightly modified "Son of suckerfish", so will be easy to style (althouh I haven't had time yet). Actual menus are added in the hook_menu methods of each class.
  • VirtualHost.php: Finally properly split off Virtual Hosts, and make Server a singleton.
  • install.php: Do the bare minimum changes so it's still possible to setup a wifidog auth server. However, install.php still needs 1- A good overhaull, 2- A way to install sample databases instead of the minimal one. -Other changes
  • Unbreak signup link for non-javascript enabled devices
  • AbstractDb?: Improve debuging features
  • *:getObject(): Hopefully improve performance of class caching by making sure that we do not manipulate different objects. Otherwise copies would be generated as soon as we change properties, wasting much memory.
    • Add dependency check for XSL module for hotspot_status.php.
    • Some work towards respecting the coding style: http://dev.wifidog.org/wiki/doc/developer/CodingStandard
    • wifidog/admin/index.php: Delete admin page. There is no longuer a concept of a separate admin section. Menu will depend on your access level.
Line 
1<?php
2
3/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5// +-------------------------------------------------------------------+
6// | WiFiDog Authentication Server                                     |
7// | =============================                                     |
8// |                                                                   |
9// | The WiFiDog Authentication Server is part of the WiFiDog captive  |
10// | portal suite.                                                     |
11// +-------------------------------------------------------------------+
12// | PHP version 5 required.                                           |
13// +-------------------------------------------------------------------+
14// | Homepage:     http://www.wifidog.org/                             |
15// | Source Forge: http://sourceforge.net/projects/wifidog/            |
16// +-------------------------------------------------------------------+
17// | This program is free software; you can redistribute it and/or     |
18// | modify it under the terms of the GNU General Public License as    |
19// | published by the Free Software Foundation; either version 2 of    |
20// | the License, or (at your option) any later version.               |
21// |                                                                   |
22// | This program is distributed in the hope that it will be useful,   |
23// | but WITHOUT ANY WARRANTY; without even the implied warranty of    |
24// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     |
25// | GNU General Public License for more details.                      |
26// |                                                                   |
27// | You should have received a copy of the GNU General Public License |
28// | along with this program; if not, contact:                         |
29// |                                                                   |
30// | Free Software Foundation           Voice:  +1-617-542-5942        |
31// | 59 Temple Place - Suite 330        Fax:    +1-617-542-2652        |
32// | Boston, MA  02111-1307,  USA       gnu@gnu.org                    |
33// |                                                                   |
34// +-------------------------------------------------------------------+
35
36/**
37 * @package    WiFiDogAuthServer
38 * @subpackage NodeLists
39 * @author     Max Horváth <max.horvath@freenet.de>
40 * @copyright  2006 Max Horváth, Horvath Web Consulting
41 * @version    Subversion $Id: Content.php 974 2006-02-25 15:08:12Z max-horvath $
42 * @link       http://www.wifidog.org/
43 */
44
45/**
46 * Load required classes
47 */
48require_once('classes/Dependency.php');
49require_once('classes/MainUI.php');
50require_once('classes/Network.php');
51require_once('classes/Node.php');
52require_once('classes/User.php');
53
54// Check for FPDF library
55if (Dependency::check("FPDF")) {
56    // Start server load check
57    $_serverBusy = false;
58
59    if (PHP_OS != "Windows" && PHP_OS != "Darwin" && @file_exists('/proc/loadavg') && $_loadavgFile = @file_get_contents('/proc/loadavg')) {
60        $_loadavg = explode(' ', $_loadavgFile);
61
62        if (trim($_loadavg[0]) > 5) {
63                $_serverBusy = true;
64        }
65    }
66
67    if (!$_serverBusy) {
68        // Load FPDF library
69        require_once("lib/fpdf/fpdf.php");
70
71        /**
72         * PDF class of WiFiDog, extends FPDF library
73         *
74         * Extended private functions don't use the "private" construct used to
75         * declare the function as the parent class is written in PHP4-style. Every
76         * function in a PHP4-style-class is public. A child class cannot change the
77         * visibility of a parents function.
78         *
79         * @package    WiFiDogAuthServer
80         * @author     Max Horváth <max.horvath@freenet.de>
81         * @copyright  2006 Max Horváth, Horvath Web Consulting
82         */
83        class PdfWiFiDog extends FPDF
84        {
85            /**
86             * Is document is protected?
87             *
88             * @var bool
89
90             */
91            private $_encrypted;
92
93            /**
94             * U entry in pdf document
95             *
96             * @var string
97
98             */
99            private $_uValue;
100
101            /**
102             * O entry in pdf document
103             *
104             * @var string
105
106             */
107            private $_oValue;
108
109            /**
110             * P entry in pdf document
111             *
112             * @var string
113
114             */
115            private $_pValue;
116
117            /**
118             * Encryption object id
119             *
120             * @var string
121
122             */
123            private $_encObjectId;
124
125            /**
126             * Last encrypted RC4 key (cached for optimization)
127             *
128             * @var string
129
130             */
131            private $_lastRC4Key;
132
133            /**
134             * Last computed RC4 key
135             *
136             * @var string
137
138             */
139            private $_lastRC4KeyC;
140
141            /**
142             * Array of column widths
143             *
144             * @var array
145
146             */
147            private $_widths;
148
149            /**
150             * Array of column alignments
151             *
152             * @var array
153
154             */
155            private $_aligns;
156
157            /**
158             * Constructor
159             *
160             * @param string $orientation Oriantation of generated page
161             *                              - P for portrait
162             *                              - L for landscape
163             * @param string $unit        In which unit shall this class compute?
164             *                              - pt
165             *                              - mm
166             *                              - cm
167             *                              - in
168             * @param string $format      Format of generated page
169             *                              - letter
170             *                              - legal
171             *                              - a3
172             *                              - a4
173             *                              - a5
174             *
175             * @return void
176             */
177            public function __construct($orientation = 'L', $unit = 'mm', $format = 'letter')
178            {
179                // Call parent constructor
180                parent::FPDF($orientation, $unit, $format);
181
182                $this->_encrypted = false;
183                $this->_lastRC4Key = '';
184                $this->padding = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08" .
185                                 "\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A";
186            }
187
188            /**
189             * Function to set permissions as well as user and owner passwords
190             *
191             * @param array  $permissions Array with values taken from the
192             *                            following list:
193             *                              - copy
194             *                              - print
195             *                              - modify
196             *                              - annot-forms
197             *                            If a value is present it means that the
198             *                            permission is granted.
199             * @param string $userPass    If an user password is set, the user will
200             *                            be prompted for it before the document
201             *                            will be opened
202             * @param string $ownerPass   If an owner password is set, the document
203             *                            can be opened in privilege mode with no
204             *                            restrictions if that password is entered
205             *
206             * @return void
207             */
208            public function SetProtection($permissions = array(), $userPass = '', $ownerPass = null)
209            {
210                // Init values
211                $_options = array("print" => 4, "modify" => 8, "copy" => 16, "annot-forms" => 32);
212                $_protection = 192;
213
214                // Set permissions
215                foreach ($permissions as $_permission) {
216                    if (!isset($_options[$_permission])) {
217                        $this->Error("Incorrect permission: " . $_permission);
218                    }
219
220                    // Update protection of document
221                    $_protection += $_options[$_permission];
222                }
223
224                // If no owner password has been defined generate a random one
225                if ($ownerPass === null) {
226                    $ownerPass = uniqid(rand());
227                }
228
229                $this->_encrypted = true;
230
231                $this->_generateencryptionkey($userPass, $ownerPass, $_protection);
232            }
233
234            /**
235             * Set the array of column widths
236             *
237             * @param array $w Array of column widths
238             *
239             * @return void
240             */
241            public function SetWidths($w)
242            {
243                $this->_widths = $w;
244            }
245
246            /**
247             * Set the array of column alignments
248             *
249             * @param array $a Array of column alignments
250             *
251             * @return void
252             */
253            function SetAligns($a)
254            {
255                $this->_aligns = $a;
256            }
257
258            /**
259             * Generates a table with containing the nodes data
260             *
261             * @param array $header Header of table
262             * @param array $data   Data of table
263             *
264             * @return void
265             */
266            public function nodeList($header, $data)
267            {
268                // Calculate the height of the row
269                $_nb = 0;
270
271                for ($_i = 0; $_i < count($header); $_i++) {
272                    $_nb = max($_nb, $this->_nbLines($this->_widths[$_i], $header[$_i]));
273                }
274
275                $_h = 5 * $_nb;
276
277                // Issue a page break first if needed
278                $this->_checkPageBreak($_h);
279
280                // Draw the Header
281                for ($_i = 0; $_i < count($header); $_i++) {
282                    $_w = $this->_widths[$_i];
283                    $_a = $this->_aligns[$_i];
284
285                    // Save the current position
286                    $_x = $this->GetX();
287                    $_y = $this->GetY();
288
289                    // Draw the border
290                    $this->Rect($_x, $_y, $_w, $_h);
291
292                    // Enable bold text
293                    $this->SetFont("", "B");
294
295                    // Print the text
296                    $this->MultiCell($_w, 5, utf8_decode($header[$_i]), 0, "C");
297
298                    // Disable bold text
299                    $this->SetFont("");
300
301                    // Put the position to the right of the cell
302                    $this->SetXY($_x + $_w, $_y);
303                }
304
305                // Go to the next line
306                $this->Ln($_h);
307
308                // Draw the Data
309                foreach ($data as $_row) {
310                    // Calculate the height of the row
311                    $_nb = 0;
312
313                    for ($_i = 0; $_i < 8; $_i++) {
314                        // Define which array data to use
315                        switch ($_i) {
316                        case 0:
317                            $_dataPart = $_row['name'];
318                            break;
319
320                        case 1:
321                            $_dataPart = $_row['civic_number'] . " " . $_row['street_name'];
322                            break;
323                        case 2:
324                            $_dataPart = $_row['postal_code'];
325                            break;
326
327                        case 3:
328                            $_dataPart = $_row['city'];
329                            break;
330
331                        case 4:
332                            $_dataPart = $_row['province'];
333                            break;
334
335                        case 5:
336                            $_dataPart = $_row['public_phone_number'];
337                            break;
338
339                        case 6:
340                            $_dataPart = $_row['public_email'];
341                            break;
342
343                        case 7:
344                            $_dataPart = str_replace(array("http://", "https://"), "", $_row['home_page_url']);
345                            break;
346
347                        default:
348                            throw new Exception("Error: PdfWifidog::nodeList(): Fatal error while defining which array data to use.");
349                            break;
350                        }
351
352                        $_nb = max($_nb, $this->_nbLines($this->_widths[$_i], $_dataPart));
353                    }
354
355                    $_h = 5 * $_nb;
356
357                    // Issue a page break first if needed
358                    $this->_checkPageBreak($_h);
359
360                    // Draw the data
361                    for ($_i = 0; $_i < 8; $_i++) {
362                        // Define which array data to use
363                        switch ($_i) {
364                        case 0:
365                            $_dataPart = $_row['name'];
366                            break;
367
368                        case 1:
369                            if (defined("ORDER_CIVIC_NUMBER") && ORDER_CIVIC_NUMBER == "street_name_first") {
370                                $_dataPart = $_row['street_name'] . " " . $_row['civic_number'];
371                            } else {
372                                $_dataPart = $_row['civic_number'] . " " . $_row['street_name'];
373                            }
374                            break;
375                        case 2:
376                            $_dataPart = $_row['postal_code'];
377                            break;
378
379                        case 3:
380                            $_dataPart = $_row['city'];
381                            break;
382
383                        case 4:
384                            $_dataPart = $_row['province'];
385                            break;
386
387                        case 5:
388                            $_dataPart = $_row['public_phone_number'];
389                            break;
390
391                        case 6:
392                            $_dataPart = $_row['public_email'];
393                            break;
394
395                        case 7:
396                            $_dataPart = str_replace(array("http://", "https://"), "", $_row['home_page_url']);
397                            break;
398
399                        default:
400                            throw new Exception("Error: PdfWifidog::nodeList(): Fatal error while defining which array data to use.");
401                            break;
402                        }
403
404                        // Get styles
405                        $_w = $this->_widths[$_i];
406                        $_a = $this->_aligns[$_i];
407
408                        // Save the current position
409                        $_x = $this->GetX();
410                        $_y = $this->GetY();
411
412                        // Draw the border
413                        $this->Rect($_x, $_y, $_w, $_h);
414
415                        // Print the text
416                        $this->MultiCell($_w, 5, utf8_decode($_dataPart), 0, $_a);
417
418                        // Put the position to the right of the cell
419                        $this->SetXY($_x + $_w, $_y);
420                    }
421
422                    // Go to the next line
423                    $this->Ln($_h);
424                }
425            }
426
427            /**
428             * Defines basic values of the PDF file
429             *
430             * @return void
431
432             */
433            function _putinfo()
434            {
435                        if (defined("WIFIDOG_NAME")) {
436                        $this->_out('/Producer ' . $this->_textstring(WIFIDOG_NAME));
437                        } else {
438                        $this->_out('/Producer ' . $this->_textstring('WiFiDog Authentication Server'));
439                        }
440
441                if (!empty($this->title)) {
442                        $this->_out('/Title ' . $this->_textstring($this->title));
443                }
444
445                if (!empty($this->subject)) {
446                        $this->_out('/Subject ' . $this->_textstring($this->subject));
447                }
448
449                if (!empty($this->author)) {
450                        $this->_out('/Author ' . $this->_textstring($this->author));
451                }
452
453                if (!empty($this->keywords)) {
454                        $this->_out('/Keywords ' . $this->_textstring($this->keywords));
455                }
456
457                if (!empty($this->creator)) {
458                        $this->_out('/Creator ' . $this->_textstring($this->creator));
459                }
460
461                $this->_out('/CreationDate ' . $this->_textstring('D:' . date('YmdHis')));
462            }
463
464            /**
465             * Extends parent _putstream function with encryption
466             *
467             * @param string $s String to be processed
468             *
469             * @return void
470
471             */
472            function _putstream($s)
473            {
474                if ($this->_encrypted) {
475                    $s = $this->_RC4($this->_objectkey($this->n), $s);
476                }
477
478                parent::_putstream($s);
479            }
480
481            /**
482             * Extends parent _textstream function with encryption
483             *
484             * @param string $s String to be processed
485             *
486             * @return string Processed string
487
488             */
489            function _textstring($s)
490            {
491                if ($this->_encrypted) {
492                    $s = $this->_RC4($this->_objectkey($this->n), $s);
493                }
494
495                return parent::_textstring($s);
496            }
497
498            /**
499             * Compute key depending on object number where the encrypted data is
500             * stored
501             *
502             * @param int $n Number of object
503             *
504             * @return Computed key
505
506             */
507            private function _objectkey($n)
508            {
509                return substr($this->_md5_16($this->encryption_key.pack('VXxx', $n)), 0, 10);
510            }
511
512            /**
513             * Escape special characters (extends parent function)
514             *
515             * @param string $s String to be processed
516             *
517             * @return Processed string
518
519             */
520            function _escape($s)
521            {
522                $s = str_replace('\\', '\\\\', $s);
523                $s = str_replace(')', '\\)', $s);
524                $s = str_replace('(', '\\(', $s);
525                $s = str_replace("\r", '\\r', $s);
526
527                return $s;
528            }
529
530            /**
531             * Helper function for parent _put-functions to be extended with
532             * encryption
533             *
534             * @return void
535
536             */
537            private function _putencryption()
538            {
539                $this->_out('/Filter /Standard');
540                $this->_out('/V 1');
541                $this->_out('/R 2');
542                $this->_out('/O (' . $this->_escape($this->_oValue) . ')');
543                $this->_out('/U (' . $this->_escape($this->_uValue) . ')');
544                $this->_out('/P ' . $this->_pValue);
545            }
546
547            /**
548             * Extends parent _putresources function with encryption
549             *
550             * @return void
551
552             */
553            function _putresources()
554            {
555                parent::_putresources();
556
557                if ($this->_encrypted) {
558                    $this->_newobj();
559                    $this->_encObjectId = $this->n;
560                    $this->_out('<<');
561                    $this->_putencryption();
562                    $this->_out('>>');
563                    $this->_out('endobj');
564                }
565            }
566
567            /**
568             * Extends parent _puttrailer function with encryption
569             *
570             * @return void
571
572             */
573            function _puttrailer()
574            {
575                parent::_puttrailer();
576
577                if ($this->_encrypted) {
578                    $this->_out('/Encrypt ' . $this->_encObjectId . ' 0 R');
579                    $this->_out('/ID [()()]');
580                }
581            }
582
583            /**
584             * RC4 encryption algorithm to be used in PDF format
585             *
586             * @param string $key  Key to be used for encryption
587             * @param string $text String to be encrypted
588             *
589             * @return Encrypted string
590
591             */
592            private function _RC4($key, $text)
593            {
594                if ($this->_lastRC4Key != $key) {
595                    $k = str_repeat($key, 256/strlen($key) + 1);
596                    $rc4 = range(0, 255);
597                    $j = 0;
598
599                    for ($i = 0; $i < 256; $i++) {
600                        $t = $rc4[$i];
601                        $j = ($j + $t + ord($k{$i})) % 256;
602                        $rc4[$i] = $rc4[$j];
603                        $rc4[$j] = $t;
604                    }
605
606                    $this->_lastRC4Key = $key;
607                    $this->_lastRC4KeyC = $rc4;
608                } else {
609                    $rc4 = $this->_lastRC4KeyC;
610                }
611
612                $len = strlen($text);
613                $a = 0;
614                $b = 0;
615                $out = '';
616
617                for ($i = 0; $i < $len; $i++) {
618                    $a = ($a + 1) % 256;
619                    $t= $rc4[$a];
620                    $b = ($b + $t) % 256;
621                    $rc4[$a] = $rc4[$b];
622                    $rc4[$b] = $t;
623                    $k = $rc4[($rc4[$a] + $rc4[$b]) % 256];
624                    $out .= chr(ord($text{$i}) ^ $k);
625                }
626
627                return $out;
628            }
629
630            /**
631             * Get MD5 as binary string
632             *
633             * @param string $string String to be converted
634             *
635             * @return Converted string
636
637             */
638            private function _md5_16($string)
639            {
640                return pack('H*', md5($string));
641            }
642
643            /**
644             * Compute O value
645             *
646             * @param string $userPass  User password to be used
647             * @param string $ownerPass Owner password to be used
648             *
649             * @return Computed O value
650
651             */
652            private function _GenOvalue($userPass, $ownerPass)
653            {
654                $tmp = $this->_md5_16($ownerPass);
655                $owner_RC4_key = substr($tmp, 0, 5);
656
657                return $this->_RC4($owner_RC4_key, $userPass);
658            }
659
660            /**
661             * Compute U value
662             *
663             * @return Computed U value
664
665             */
666            private function _GenUvalue()
667            {
668                return $this->_RC4($this->encryption_key, $this->padding);
669            }
670
671            /**
672             * Compute encryption key
673             *
674             * @param string $userPass   User password to be used
675             * @param string $ownerPass  Owner password to be used
676             * @param int    $protection Protection to be used
677             *
678             * @return Generated encryption key
679
680             */
681            private function _generateencryptionkey($userPass, $ownerPass, $protection)
682            {
683                // Pad passwords
684                $userPass = substr($userPass . $this->padding, 0, 32);
685                $ownerPass = substr($ownerPass . $this->padding, 0, 32);
686
687                // Compute O value
688                $this->_oValue = $this->_GenOvalue($userPass, $ownerPass);
689
690                // Compute encyption key
691                $tmp = $this->_md5_16($userPass . $this->_oValue . chr($protection) . "\xFF\xFF\xFF");
692                $this->encryption_key = substr($tmp, 0, 5);
693
694                // Compute U value
695                $this->_uValue = $this->_GenUvalue();
696
697                // Compute P value
698                $this->_pValue = -(($protection ^ 255) + 1);
699            }
700
701            /**
702             * Check if we need to add a page break
703             *
704             * @param int $h Height of page
705             *
706             * @return void
707
708             */
709            private function _checkPageBreak($h)
710            {
711                // If the height h would cause an overflow, add a new page immediately
712                if ($this->GetY() + $h > $this->PageBreakTrigger) {
713                    $this->AddPage($this->CurOrientation);
714                }
715            }
716
717            /**
718             * Computes the number of lines a MultiCell of width w will take
719             *
720             * @param int    $w   Width of cell
721             * @param string $txt Text to be calculated
722             *
723             * @return Number of lines
724
725             */
726            private function _nbLines($w, $txt)
727            {
728                $cw = &$this->CurrentFont['cw'];
729
730                if ($w == 0) {
731                    $w = $this->w - $this->rMargin - $this->x;
732                }
733
734                $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
735                $s = str_replace("\r", '', $txt);
736                $nb = strlen($s);
737
738                if ($nb > 0 && $s[$nb - 1] == "\n") {
739                    $nb--;
740                }
741
742                $sep = -1;
743                $i = 0;
744                $j = 0;
745                $l = 0;
746                $nl = 1;
747
748                while ($i < $nb) {
749                    $c = $s[$i];
750
751                    if ($c == "\n") {
752                        $i++;
753                        $sep = -1;
754                        $j = $i;
755                        $l = 0;
756                        $nl++;
757
758                        continue;
759                    }
760
761                    if ($c == ' ') {
762                        $sep = $i;
763                    }
764
765                    $l += $cw[$c];
766
767                    if ($l > $wmax) {
768                        if ($sep == -1) {
769                            if ($i == $j) {
770                                $i++;
771                            }
772                        } else {
773                            $i = $sep + 1;
774                        }
775
776                        $sep = -1;
777                        $j = $i;
778                        $l = 0;
779                        $nl++;
780                    } else {
781                        $i++;
782                    }
783                }
784
785                return $nl;
786            }
787        }
788    } else {
789        $ui = MainUI::getObject();
790
791        $errmsg = _("To protect the server the PDF file has not been created, because the server is too busy right now!");
792        $ui->displayError($errmsg);
793
794        exit();
795    }
796} else {
797    $ui = MainUI::getObject();
798
799    $errmsg = _("PDF file cannot be created because the FPDF library is not installed!");
800    $ui->displayError($errmsg);
801
802    exit();
803}
804
805/**
806 * Defines the HTML type of node list
807 *
808 * @package    WiFiDogAuthServer
809 * @subpackage NodeLists
810 * @author     Max Horváth <max.horvath@freenet.de>
811 * @copyright  2006 Max Horváth, Horvath Web Consulting
812 */
813class NodeListPDF
814{
815    /**
816     * Is FPDF available?
817     *
818     * @var bool
819
820     */
821    private $_pdfAvailable = false;
822
823    /**
824     * PdfWifidog object
825     *
826     * @var object
827
828     */
829    private $_pdf;
830
831    /**
832     * Format of page
833     *
834     * @var string
835
836     */
837    private $_pdfFormat = "letter";
838
839    /**
840     * Sort list by?
841     *
842     * @var string
843
844     */
845    private $_pdfSort = "name";
846
847    /**
848     * Format of date
849     *
850     * @var string
851
852     */
853    private $_pdfDate = "m/d/Y";
854
855    /**
856     * Path of logo
857     *
858     * @var string
859
860     */
861    private $_pdfImage = "media/base_theme/images/wifidog_logo.jpg";
862
863    /**
864     * Network to generate the list from
865     *
866     * @var object
867
868     */
869    private $_network;
870
871    /**
872     * Nodes to generate the list from
873     *
874     * @var array
875
876     */
877    private $_nodes;
878
879    /**
880     * Object of current user
881     *
882     * @var object
883
884     */
885    private $_currentUser;
886
887    /**
888     * Constructor
889     *
890     * @return void
891     */
892    public function __construct(&$network)
893    {
894       
895        $db = AbstractDb::getObject();
896
897        // Init network
898        $this->_network = $network;
899
900        // Init PdfWifidog and check if FDPF is available
901        if (Dependency::check("FPDF")) {
902            // Set PDF availability switch
903            $this->_pdfAvailable = true;
904
905            // Try to load customization file
906            if (file_exists(WIFIDOG_ABS_FILE_PATH . "templates/NodeLists/NodeListPDF.php")) {
907                require_once("templates/NodeLists/NodeListPDF.php");
908            }
909
910            /*
911             * Process customizations
912             */
913
914            // Page format
915            if (defined("PDF_FORMAT") && PDF_FORMAT == "a4") {
916                $this->_pdfFormat = PDF_FORMAT;
917            }
918
919            // Sort by?
920            if (defined("PDF_SORT")) {
921                switch (PDF_SORT) {
922                case "street_name":
923                case "postal_code":
924                case "city":
925                    $this->_pdfSort = PDF_SORT;
926                    break;
927
928                default:
929                    $this->_pdfSort = "name";
930                    break;
931
932                }
933            }
934
935            // Format of date
936            if (defined("PDF_DATE")) {
937                $this->_pdfDate = PDF_DATE;
938            }
939
940            // Path of logo
941            if (defined("PDF_IMAGE")) {
942                $this->_pdfImage = PDF_IMAGE;
943            }
944
945            /*
946             * Customizations processed
947             */
948
949            // Init PDF class
950            $this->_pdf = new PdfWiFiDog("L", "mm", $this->_pdfFormat);
951
952            // Define document values
953            $this->_pdf->SetTitle($this->_network->getName() . " " . _("Hotspots"));
954            $this->_pdf->SetSubject($this->_network->getName() . " " . _("Hotspots"));
955            $this->_pdf->SetAuthor($this->_network->getName());
956            $this->_pdf->SetKeywords($this->_network->getName() . ", " . _("Hotspots"));
957
958                if (defined("WIFIDOG_NAME")) {
959                $this->_pdf->SetCreator(WIFIDOG_NAME);
960                }
961
962            // Define styles
963            $this->_pdf->SetAligns(array("L", "L", "C", "L", "L", "L", "L", "L"));
964
965            // Set width according to page format
966            if ($this->_pdfFormat == "letter") {
967                $this->_pdf->SetWidths(array(35, 35, 15, 35, 35, 35, 35, 35));
968            } else {
969                $this->_pdf->SetWidths(array(36, 36, 15, 36, 36, 36, 36, 45));
970            }
971
972            // Apply protection
973            $this->_pdf->SetProtection(array('print'));
974        }
975
976        // Init user
977        $this->_currentUser = User::getCurrentUser();
978
979        // Query the database, sorting by node name
980        $db->execSql("SELECT *, (CURRENT_TIMESTAMP-last_heartbeat_timestamp) AS since_last_heartbeat, EXTRACT(epoch FROM creation_date) as creation_date_epoch, CASE WHEN ((CURRENT_TIMESTAMP-last_heartbeat_timestamp) < interval '5 minutes') THEN true ELSE false END AS is_up FROM nodes WHERE network_id = '" . $db->escapeString($this->_network->getId()) . "' AND (node_deployment_status = 'DEPLOYED' OR node_deployment_status = 'NON_WIFIDOG_NODE') ORDER BY lower(" . $this->_pdfSort . ")", $this->_nodes, false);
981    }
982
983    /**
984     * Sets header of output
985     *
986     * @return void
987     */
988    public function setHeader()
989    {
990        if (Dependency::check("FPDF")) {
991            header("Cache-control: private, no-cache, must-revalidate, post-check=0, pre-check=0");
992            header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); # Past date
993            header("Pragma: no-cache");
994            header("Content-Transfer-Encoding: binary");
995            header("Content-Type: application/pdf");
996            header("Content-Disposition: inline; filename=" . $this->_network->getId() . "_hotspot_status.pdf");
997        }
998    }
999
1000    /**
1001     * Retreives the output of this object.
1002     *
1003     * @param bool $return_object This parameter doesn't have any effect in
1004     *                            the class
1005     *
1006     * @return string The PDF file
1007     */
1008    public function getOutput($return_object = false)
1009    {
1010        // Init values
1011        $_nodeDetails = array();
1012
1013        // Check for FPDF support
1014        if ($this->_pdfAvailable) {
1015            // Init PDF
1016            $this->_pdf->AddPage();
1017
1018            // Analyze logo
1019            $_imageSize = GetImageSize(WIFIDOG_ABS_FILE_PATH . $this->_pdfImage);
1020
1021            // Calculate position of logo
1022            if ($this->_pdfFormat == "letter") {
1023                $_imageLeft = 270;
1024            } else {
1025                $_imageLeft = 286;
1026            }
1027
1028            $_imageWidth = 27 * ($_imageSize[0] / (72 / 25.4)) / ($_imageSize[1] / (72 / 25.4));
1029            $_imageLeft = $_imageLeft - $_imageWidth;
1030
1031            // Place logo
1032            $this->_pdf->Image(WIFIDOG_ABS_FILE_PATH . $this->_pdfImage, $_imageLeft, 12, 0, 27);
1033
1034            // Define font size for Header
1035            $this->_pdf->SetFont('Arial', '', 36);
1036
1037            $this->_pdf->Write(15, utf8_decode($this->_network->getName() . " " . _("Hotspots")));
1038            $this->_pdf->Ln();
1039
1040            // Define font size for the description and the node list
1041            $this->_pdf->SetFont('Arial', '', 8);
1042
1043            // Check sorting
1044            switch ($this->_pdfSort) {
1045                case "street_name":
1046                    $_sortBy = _("street name");
1047                    break;
1048
1049                case "postal_code":
1050                    $_sortBy = _("postal code");
1051                    break;
1052
1053                case "city":
1054                    $_sortBy = _("city");
1055                    break;
1056
1057                default:
1058                    $_sortBy = _("name");
1059                    break;
1060
1061                }
1062
1063            $this->_pdf->Write(10, utf8_decode(sprintf(_("This list contains all Hotspots of %s sorted by %s."), $this->_network->getName(), $_sortBy)));
1064            $this->_pdf->Ln(4);
1065
1066            $this->_pdf->Write(10, utf8_decode(sprintf(_("Number of Hotspots: %d"), count($this->_nodes))));
1067            $this->_pdf->Ln(4);
1068
1069            $this->_pdf->Write(10, utf8_decode(sprintf(_("Last updated on: %s"), date($this->_pdfDate))));
1070            $this->_pdf->Ln(12);
1071
1072            // Node details
1073            if ($this->_nodes) {
1074                foreach ($this->_nodes as $_nodeData) {
1075                    $_node = Node::getObject($_nodeData['node_id']);
1076                    $_nodeData['num_online_users'] = $_node->getNumOnlineUsers();
1077                    $_nodeDetails[] = $_nodeData;
1078                }
1079            }
1080
1081            $_header = array(_("Hotspot"), _("Address"), _("Postal code"), _("City"), _("Province / State"), _("Telephone"), _("Email"), _("Homepage URL"));
1082
1083            $this->_pdf->nodeList($_header, $_nodeDetails);
1084
1085            // Compile PDF file
1086            $this->_pdf->Output();
1087        }
1088    }
1089
1090}
1091
1092/*
1093 * Local variables:
1094 * tab-width: 4
1095 * c-basic-offset: 4
1096 * c-hanging-comment-ender-p: nil
1097 * End:
1098 */
1099
1100?>
Note: See TracBrowser for help on using the browser.