"Fossies" - the Fresh Open Source Software Archive 
Member "fogproject-1.5.9/packages/web/lib/fog/fogbase.class.php" (13 Sep 2020, 70601 Bytes) of package /linux/misc/fogproject-1.5.9.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
See also the latest
Fossies "Diffs" side-by-side code changes report for "fogbase.class.php":
1.5.8_vs_1.5.9.
1 <?php
2 /**
3 * FOGBase, the base class for pretty much all of fog.
4 *
5 * PHP version 5
6 *
7 * This gives all the rest of the classes a common frame to work from.
8 *
9 * @category FOGBase
10 * @package FOGProject
11 * @author Tom Elliott <tommygunsster@gmail.com>
12 * @license http://opensource.org/licenses/gpl-3.0 GPLv3
13 * @link https://fogproject.org
14 */
15 /**
16 * FOGBase, the base class for pretty much all of fog.
17 *
18 * @category FOGBase
19 * @package FOGProject
20 * @author Tom Elliott <tommygunsster@gmail.com>
21 * @license http://opensource.org/licenses/gpl-3.0 GPLv3
22 * @link https://fogproject.org
23 */
24 abstract class FOGBase
25 {
26 /**
27 * Locale
28 *
29 * @var string
30 */
31 public static $locale = '';
32 /**
33 * Ping is active?
34 *
35 * @var bool
36 */
37 public static $fogpingactive = false;
38 /**
39 * Delete auth is active?
40 *
41 * @var bool
42 */
43 public static $fogdeleteactive = false;
44 /**
45 * Export auth is active?
46 *
47 * @var bool
48 */
49 public static $fogexportactive = false;
50 /**
51 * The pending macs count.
52 *
53 * @var int
54 */
55 public static $pendingMACs = 0;
56 /**
57 * The pending hosts count.
58 *
59 * @var int
60 */
61 public static $pendingHosts = 0;
62 /**
63 * Default screen.
64 *
65 * @var string
66 */
67 public static $defaultscreen = '';
68 /**
69 * Plugins installed.
70 *
71 * @var array
72 */
73 public static $pluginsinstalled = array();
74 /**
75 * User agent string.
76 *
77 * @var string
78 */
79 public static $useragent;
80 /**
81 * Language variables brought in from text.php.
82 *
83 * @var array
84 */
85 public static $foglang;
86 /**
87 * Sets if the requesting call is ajax requested.
88 *
89 * @var bool
90 */
91 public static $ajax = false;
92 /**
93 * Sets if this is a form submit.
94 *
95 * @var bool
96 */
97 public static $post = false;
98 /**
99 * Tells whether or not its a fog/service request.
100 *
101 * @var bool
102 */
103 public static $service = false;
104 /**
105 * Tells if we are json or not
106 *
107 * @var bool
108 */
109 public static $json = false;
110 /**
111 * Tells if we are new service or not
112 *
113 * @var bool
114 */
115 public static $newService = false;
116 /**
117 * Tests/sets if a given key is loaded already.
118 *
119 * @var array
120 */
121 protected $isLoaded = array();
122 /**
123 * The length of a given string item.
124 *
125 * @var int
126 */
127 protected static $strlen;
128 /**
129 * Display debug information.
130 *
131 * @var bool
132 */
133 protected static $debug = false;
134 /**
135 * Display extra information about items.
136 *
137 * @var bool
138 */
139 protected static $info = false;
140 /**
141 * Select box creator function stored in variable.
142 *
143 * @var callable
144 */
145 protected static $buildSelectBox;
146 /**
147 * Sets what's selected for the select box.
148 *
149 * @var bool|int
150 */
151 protected static $selected;
152 /**
153 * The database handler.
154 *
155 * @var object
156 */
157 protected static $DB;
158 /**
159 * FTP Handler.
160 *
161 * @var object
162 */
163 protected static $FOGFTP;
164 /**
165 * Core usage elements as FOGBase is abstract.
166 *
167 * @var object
168 */
169 protected static $FOGCore;
170 /**
171 * Event handling.
172 *
173 * @var object
174 */
175 protected static $EventManager;
176 /**
177 * Hook handling.
178 *
179 * @var object
180 */
181 protected static $HookManager;
182 /**
183 * The default timezone for all of fog to use.
184 *
185 * @var object
186 */
187 protected static $TimeZone;
188 /**
189 * The logged in user.
190 *
191 * @var object
192 */
193 protected static $FOGUser;
194 /**
195 * View/Page Controller-Manager.
196 *
197 * @var object
198 */
199 protected static $FOGPageManager;
200 /**
201 * URL Manager | mainly for ajax, and externel getters.
202 *
203 * @var object
204 */
205 protected static $FOGURLRequests;
206 /**
207 * Side/Sub menu manager.
208 *
209 * @var object
210 */
211 protected static $FOGSubMenu;
212 /**
213 * Current requests script name.
214 *
215 * @var string
216 */
217 public static $scriptname;
218 /**
219 * Current requests query string.
220 *
221 * @var string
222 */
223 public static $querystring;
224 /**
225 * Current requests http requested with string.
226 *
227 * @var string
228 */
229 public static $httpreqwith;
230 /**
231 * Current request method.
232 *
233 * @var string
234 */
235 public static $reqmethod;
236 /**
237 * Current remote address.
238 *
239 * @var string
240 */
241 public static $remoteaddr;
242 /**
243 * Current http referer.
244 *
245 * @var string
246 */
247 public static $httpreferer;
248 /**
249 * The current server's IP information.
250 *
251 * @var array
252 */
253 protected static $ips = array();
254 /**
255 * The current server's Interface information.
256 *
257 * @var array
258 */
259 protected static $interface = array();
260 /**
261 * The current base pages requiring search functionality.
262 *
263 * @var array
264 */
265 protected static $searchPages = array(
266 'user',
267 'host',
268 'group',
269 'image',
270 //'storage',
271 'snapin',
272 'printer',
273 'task',
274 );
275 /**
276 * Is our current element already initialized?
277 *
278 * @var bool
279 */
280 private static $_initialized = false;
281 /**
282 * The current running schema information.
283 *
284 * @var int
285 */
286 public static $mySchema = 0;
287 /**
288 * Allows pages to include the main gui or not.
289 *
290 * @var bool
291 */
292 public static $showhtml = true;
293 /**
294 * HTTPS set or not store protocol to use.
295 *
296 * @var string
297 */
298 public static $httpproto = false;
299 /**
300 * HTTP_HOST variable.
301 *
302 * @var string
303 */
304 public static $httphost = '';
305 /**
306 * Hosts are what we work with.
307 * To help simplify changing elements using hosts,
308 * store as a static variable.
309 *
310 * @var Host
311 */
312 public static $Host = null;
313 /**
314 * Initializes the FOG System if needed.
315 *
316 * @return void
317 */
318 private static function _init()
319 {
320 if (self::$_initialized === true) {
321 return;
322 }
323 global $foglang;
324 global $FOGFTP;
325 global $FOGCore;
326 global $DB;
327 global $currentUser;
328 global $EventManager;
329 global $HookManager;
330 global $FOGURLRequests;
331 global $FOGPageManager;
332 global $TimeZone;
333 self::$foglang = &$foglang;
334 self::$FOGFTP = &$FOGFTP;
335 self::$FOGCore = &$FOGCore;
336 self::$DB = &$DB;
337 self::$EventManager = &$EventManager;
338 self::$HookManager = &$HookManager;
339 self::$FOGUser = &$currentUser;
340 global $sub;
341 $scriptPattern = 'service';
342 $queryPattern = 'sub=requestClientInfo';
343 self::$querystring = filter_input(INPUT_SERVER, 'QUERY_STRING');
344 self::$scriptname = filter_input(INPUT_SERVER, 'SCRIPT_NAME');
345 self::$httpreqwith = filter_input(INPUT_SERVER, 'HTTP_X_REQUESTED_WITH');
346 self::$reqmethod = filter_input(INPUT_SERVER, 'REQUEST_METHOD');
347 self::$remoteaddr = filter_input(INPUT_SERVER, 'REMOTE_ADDR');
348 self::$httpreferer = filter_input(INPUT_SERVER, 'HTTP_REFERER');
349 if (false !== stripos(self::$scriptname, $scriptPattern)) {
350 self::$service = true;
351 } elseif (false !== stripos(self::$querystring, $queryPattern)) {
352 self::$service = true;
353 }
354 self::$ajax = false !== stripos(self::$httpreqwith, 'xmlhttprequest');
355 self::$post = false !== stripos(self::$reqmethod, 'post');
356 self::$newService = isset($_POST['newService'])
357 || isset($_GET['newService'])
358 || $sub == 'requestClientInfo';
359 self::$json = isset($_POST['json'])
360 || isset($_GET['json'])
361 || self::$newService
362 || $sub == 'requestClientInfo';
363 self::$FOGURLRequests = &$FOGURLRequests;
364 self::$FOGPageManager = &$FOGPageManager;
365 self::$TimeZone = &$TimeZone;
366 /*
367 * Lambda function to allow building of select boxes.
368 *
369 * @param string $option the option to iterate
370 * @param bool|int $index the index to operate on if needed.
371 *
372 * @return void
373 */
374 self::$buildSelectBox = function ($option, $index = false) {
375 $value = $option;
376 if ($index) {
377 $value = $index;
378 }
379 printf(
380 '<option value="%s"%s>%s</option>',
381 $value,
382 (self::$selected == $value ? ' selected' : ''),
383 $option
384 );
385 };
386 /**
387 * Set proto and host.
388 */
389 self::$httpproto = 'http'
390 . (
391 filter_input(INPUT_SERVER, 'HTTPS') ?
392 's' :
393 ''
394 );
395 self::$httphost = filter_input(INPUT_SERVER, 'HTTP_HOST');
396 self::$_initialized = true;
397 }
398 /**
399 * Initiates the base class for FOG.
400 *
401 * @return this
402 */
403 public function __construct()
404 {
405 self::$useragent = self::_getUserAgent();
406 self::_init();
407
408 return $this;
409 }
410 /**
411 * Return the user agent.
412 *
413 * @return string
414 */
415 private static function _getUserAgent()
416 {
417 return filter_input(INPUT_SERVER, 'HTTP_USER_AGENT');
418 }
419 /**
420 * Defines string as class name.
421 *
422 * @return string
423 */
424 public function __toString()
425 {
426 return get_class($this);
427 }
428 /**
429 * Returns the class after verifying reflection of the class.
430 *
431 * @param string $class the name of the class to load
432 * @param mixed $data the data to load into the class
433 * @param bool $props return just properties or full object
434 *
435 * @throws Exception
436 *
437 * @return class Returns the instantiated class
438 */
439 public static function getClass($class, $data = '', $props = false)
440 {
441 if (!is_string($class)) {
442 throw new Exception(_('Class name must be a string'));
443 }
444 // Get all args, even unnamed args.
445 $args = func_get_args();
446 array_shift($args);
447
448 // Trim the class var
449 $class = trim($class);
450
451 // Test what the class is and return if it is Reflection.
452 $lClass = strtolower($class);
453 if ($lClass === 'reflectionclass') {
454 return new ReflectionClass(count($args) === 1 ? $args[0] : $args);
455 }
456
457 global $sub;
458 // If class is Storage, test if sub is group or node.
459 if ($class === 'Storage') {
460 $class = 'StorageNode';
461 if (preg_match('#storage[-|_]group#i', $sub)) {
462 $class = 'StorageGroup';
463 }
464 }
465
466 // Initiate Reflection item.
467 $obj = new ReflectionClass($class);
468
469 // If props is set to true return the properties of the class.
470 if ($props === true) {
471 return $obj->getDefaultProperties();
472 }
473
474 // Return the main object
475 if ($obj->getConstructor()) {
476 // If there's only one argument return the instance using it.
477 // Otherwise return with full call.
478 if (count($args) === 1) {
479 $class = $obj->newInstance($args[0]);
480 } else {
481 $class = $obj->newInstanceArgs($args);
482 }
483 } else {
484 $class = $obj->newInstanceWithoutConstructor();
485 }
486
487 return $class;
488 }
489 /**
490 * Get's the relevant host item.
491 *
492 * @param bool $service Is this a service request
493 * @param bool $encoded Is this data encoded
494 * @param bool $hostnotrequired Is the host return needed
495 * @param bool $returnmacs Only return macs?
496 * @param bool $override Perform an override of the items?
497 * @param bool $mac Mac Override?
498 *
499 * @throws Exception
500 *
501 * @return array|object Returns either th macs or the host
502 */
503 public static function getHostItem(
504 $service = true,
505 $encoded = false,
506 $hostnotrequired = false,
507 $returnmacs = false,
508 $override = false,
509 $mac = false
510 ) {
511 self::$Host = new Host(0);
512 // Store the mac
513 if (!$mac) {
514 $mac = filter_input(INPUT_POST, 'mac');
515 if (!$mac) {
516 $mac = filter_input(INPUT_GET, 'mac');
517 }
518 if (!$mac) {
519 parse_str(
520 file_get_contents('php://input'),
521 $vars
522 );
523 $mac = $vars['mac'];
524 }
525 }
526 // disabling sysuuid detection code for now as it is causing
527 // trouble with machines having the same UUID like we've seen
528 // on some MSI motherboards having FFFFFFFF-FFFF-FFFF-FFFF...
529 /* $sysuuid = filter_input(INPUT_POST, 'sysuuid');
530 if (!$sysuuid) {
531 $sysuuid = filter_input(INPUT_GET, 'sysuuid');
532 }
533 */
534 // If encoded decode and store value
535 if ($encoded === true) {
536 $mac = base64_decode($mac);
537 // $sysuuid = base64_decode($sysuuid);
538 }
539 // See if we can find the host by system uuid rather than by mac's first.
540 /* if ($sysuuid) {
541 $Inventory = self::getClass('Inventory')
542 ->set('sysuuid', $sysuuid)
543 ->load('sysuuid');
544 $Host = self::getClass('Inventory')
545 ->set('sysuuid', $sysuuid)
546 ->load('sysuuid')
547 ->getHost();
548 if ($Host->isValid() && !$returnmacs) {
549 self::$Host = $Host;
550 return;
551 }
552 }
553 */
554 // Trim the mac list.
555 $mac = trim($mac);
556 // Parsing the macs
557 $MACs = self::parseMacList(
558 $mac,
559 !$service,
560 $service
561 );
562 $macs = array();
563 foreach ((array) $MACs as &$mac) {
564 if (!$mac->isValid()) {
565 continue;
566 }
567 $macs[] = $mac->__toString();
568 unset($mac);
569 }
570 // Get the host element based on the mac address
571 self::getClass('HostManager')->getHostByMacAddresses($macs);
572 // If no macs are returned and the host is not required,
573 // throw message that it's an invalid mac.
574 if (count($macs) < 1 && $hostnotrequired === false) {
575 if ($service) {
576 $msg = '#!im';
577 } else {
578 $msg = sprintf(
579 '%s %s',
580 self::$foglang['InvalidMAC'],
581 $mac
582 );
583 }
584 throw new Exception($msg);
585 }
586
587 // If returnmacs parameter is true, return the macs as an array
588 if ($returnmacs) {
589 if (!is_array($macs)) {
590 $macs = (array) $macs;
591 }
592
593 return $macs;
594 }
595
596 if ($hostnotrequired === false && $override === false) {
597 if (self::$Host->get('pending')) {
598 self::$Host = new Host(0);
599 }
600 if (!self::$Host->isValid()) {
601 if ($service) {
602 $msg = '#!ih';
603 } else {
604 $msg = _('Invalid Host');
605 }
606 throw new Exception($msg);
607 }
608 }
609 return;
610 }
611 /**
612 * Get's blamed nodes for failures.
613 *
614 * @param Host $Host The host to work with.
615 *
616 * @return array
617 */
618 public static function getAllBlamedNodes($Host)
619 {
620 $DateInterval = self::niceDate()->modify('-5 minutes');
621 /**
622 * Returns the node id if still accurate
623 * or will clean up past time nodes.
624 *
625 * @param object $NodeFailure the node that is in failed state
626 *
627 * @return int|bool
628 */
629 $nodeFail = function ($NodeFailure) use ($DateInterval) {
630 if ($NodeFailure->isValid()) {
631 return false;
632 }
633 $DateTime = self::niceDate($NodeFailure->get('failureTime'));
634 if ($DateTime < $DateInterval) {
635 $NodeFailure->destroy();
636
637 return false;
638 }
639
640 return $NodeFailure->get('id');
641 };
642 $find = array(
643 'taskID' => self::$Host->get('task')->get('id'),
644 'hostID' => self::$Host->get('id'),
645 );
646 $nodeRet = array_map(
647 $nodeFail,
648 (array)self::getClass('NodeFailureManager')->find($find)
649 );
650 $nodeRet = array_filter($nodeRet);
651 $nodeRet = array_unique($nodeRet);
652 $nodeRet = array_values($nodeRet);
653
654 return $nodeRet;
655 }
656 /**
657 * Returns array of plugins installed.
658 *
659 * @return array
660 */
661 protected static function getActivePlugins()
662 {
663 $plugins = self::getSubObjectIDs(
664 'Plugin',
665 array(
666 'installed' => 1,
667 'state' => 1,
668 ),
669 'name'
670 );
671
672 return array_map('strtolower', (array) $plugins);
673 }
674 /**
675 * Converts our string if needed.
676 *
677 * @param string $txt the string to use
678 * @param array $data the data if txt is formatted string
679 *
680 * @return string
681 */
682 private static function _setString($txt, $data = array())
683 {
684 if (count($data)) {
685 $data = vsprintf($txt, $data);
686 } else {
687 $data = $txt;
688 }
689
690 return $data;
691 }
692 /**
693 * Prints fatal errors.
694 *
695 * @param string $txt the string to use
696 * @param array $data the data if txt is formatted string
697 *
698 * @return void
699 */
700 protected static function fatalError($txt, $data = array())
701 {
702 if (self::$service || self::$ajax) {
703 return;
704 }
705 $data = self::_setString($txt, $data);
706 $string = sprintf(
707 'FOG FATAL ERROR: %s: %s',
708 get_class($this),
709 $data
710 );
711 printf('<div class="debug debug-error">%s</div>', $string);
712 }
713 /**
714 * Prints error.
715 *
716 * @param string $txt the string to use
717 * @param array $data the data if txt is formatted string
718 *
719 * @return void
720 */
721 protected static function error($txt, $data = array())
722 {
723 if ((self::$service || self::$ajax) || !self::$debug) {
724 return;
725 }
726 $data = self::_setString($txt, $data);
727 $string = sprintf(
728 'FOG ERROR: %s: %s',
729 get_class($this),
730 $data
731 );
732 printf('<div class="debug debug-error">%s</div>', $string);
733 }
734 /**
735 * Prints debug.
736 *
737 * @param string $txt the string to use
738 * @param array $data the data if txt is formatted string
739 *
740 * @return void
741 */
742 protected static function debug($txt, $data = array())
743 {
744 if ((self::$service || self::$ajax) || !self::$debug) {
745 return;
746 }
747 $data = self::_setString($txt, $data);
748 $string = sprintf(
749 'FOG DEBUG: %s: %s',
750 get_class($this),
751 $data
752 );
753 printf('<div class="debug debug-error">%s</div>', $string);
754 }
755 /**
756 * Prints info.
757 *
758 * @param string $txt the string to use
759 * @param array $data the data if txt is formatted string
760 *
761 * @return void
762 */
763 protected static function info($txt, $data = array())
764 {
765 if (!self::$info || self::$service || self::$ajax) {
766 return;
767 }
768 $data = self::_setString($txt, $data);
769 $string = sprintf(
770 'FOG INFO: %s: %s',
771 get_class($this),
772 $data
773 );
774 printf('<div class="debug debug-info">%s</div>', $string);
775 }
776 /**
777 * Sets message banner at top of pages.
778 *
779 * @param string $txt the string to use
780 * @param array $data the data if txt is formatted string
781 *
782 * @return void
783 */
784 protected static function setMessage($txt, $data = array())
785 {
786 if (session_status() != PHP_SESSION_NONE) {
787 $_SESSION['FOG_MESSAGES'] = self::_setString($txt, $data);
788 }
789 }
790 /**
791 * Gets message banner and prepares to display it.
792 *
793 * @return string
794 */
795 protected static function getMessages()
796 {
797 if (session_status() == PHP_SESSION_NONE) {
798 return;
799 }
800 if (!isset($_SESSION['FOG_MESSAGES'])) {
801 $_SESSION['FOG_MESSAGES'] = array();
802 }
803 $messages = (array) $_SESSION['FOG_MESSAGES'];
804 unset($_SESSION['FOG_MESSAGES']);
805 // Create a hook in for messages
806 if (self::$HookManager instanceof HookManager) {
807 self::$HookManager->processEvent(
808 'MessageBox',
809 array('data' => &$messages)
810 );
811 }
812 /**
813 * Lambda that simply prints the messages as passed.
814 *
815 * @param string $message the message to print
816 */
817 $print_messages = function ($message) {
818 printf('<div class="fog-message-box">%s</div>', $message);
819 };
820 // Print the messages
821 array_map($print_messages, $messages);
822 unset($messages);
823 }
824 /**
825 * Redirect pages where/when necessary.
826 *
827 * @param string $url The url to redirect to
828 *
829 * @return void
830 */
831 protected static function redirect($url = '')
832 {
833 if (self::$service) {
834 return;
835 }
836 header('Strict-Transport-Security: "max-age=15768000"');
837 header('X-Content-Type-Options: nosniff');
838 header('X-XSS-Protection: 1; mode=block');
839 header('X-Robots-Tag: none');
840 header('X-Frame-Options: SAMEORIGIN');
841 header("Location: $url");
842 exit;
843 }
844 /**
845 * Insert before key in array.
846 *
847 * @param string $key the key to insert before
848 * @param array $array the array to modify
849 * @param string $new_key the new key to insert
850 * @param mixed $new_value the value to insert
851 *
852 * @throws Exception
853 * @return void
854 */
855 protected static function arrayInsertBefore(
856 $key,
857 array &$array,
858 $new_key,
859 $new_value
860 ) {
861 if (!is_string($key)) {
862 throw new Exception(_('Key must be a string or index'));
863 }
864 $new = array();
865 foreach ($array as $k => &$value) {
866 if ($k === $key) {
867 $new[$new_key] = $new_value;
868 }
869 $new[$k] = $value;
870 unset($k, $value);
871 }
872 $array = $new;
873 }
874 /**
875 * Insert after key in array.
876 *
877 * @param string $key the key to insert after
878 * @param array $array the array to modify
879 * @param string $new_key the new key to insert
880 * @param mixed $new_value the value to insert
881 *
882 * @throws Exception
883 * @return void
884 */
885 protected static function arrayInsertAfter(
886 $key,
887 array &$array,
888 $new_key,
889 $new_value
890 ) {
891 if (!is_string($key) && !is_numeric($key)) {
892 throw new Exception(_('Key must be a string or index'));
893 }
894 $new = array();
895 foreach ($array as $k => &$value) {
896 $new[$k] = $value;
897 if ($k === $key) {
898 $new[$new_key] = $new_value;
899 }
900 unset($k, $value);
901 }
902 $array = $new;
903 }
904 /**
905 * Remove value based on the key from array.
906 *
907 * @param string|array $key the key to remove
908 * @param array $array the array to work with
909 *
910 * @throws Exception
911 * @return void
912 */
913 protected static function arrayRemove($key, array &$array)
914 {
915 if (!(is_string($key) || is_array($key))) {
916 throw new Exception(_('Key must be an array of keys or a string.'));
917 }
918 if (is_array($key)) {
919 foreach ($key as &$k) {
920 self::arrayRemove($k, $array);
921 unset($k);
922 }
923 } else {
924 foreach ($array as &$value) {
925 if (is_array($value)) {
926 self::arrayRemove($key, $value);
927 } else {
928 unset($array[$key]);
929 }
930 unset($value);
931 }
932 }
933 }
934 /**
935 * Find the key of a needle within the haystack that is an array.
936 *
937 * @param mixed $needle the needle to find
938 * @param array $haystack the array to search in
939 * @param bool|mixed $ignorecase whether to care about case
940 *
941 * @return key or false
942 */
943 protected static function arrayFind(
944 $needle,
945 array $haystack,
946 $ignorecase = false
947 ) {
948 $key = array_search($needle, $haystack);
949 if (false !== $key) {
950 return $key;
951 }
952 $cmd = $ignorecase !== false ? 'stripos' : 'strpos';
953 foreach ($haystack as $key => &$value) {
954 if (false !== $cmd($value, $needle)) {
955 return $key;
956 }
957 unset($value);
958 }
959
960 return -1;
961 }
962 /**
963 * Check if isLoaded.
964 *
965 * @param string|int $key the key to see if loaded
966 *
967 * @return bool|string
968 */
969 protected function isLoaded($key)
970 {
971 $key = $this->key($key);
972 $result = isset($this->isLoaded[$key]) ? $this->isLoaded[$key] : 0;
973 $this->isLoaded[$key] = true;
974 ++$this->isLoaded[$key];
975
976 return $result ? $result : false;
977 }
978 /**
979 * Reset request variables.
980 *
981 * @return void
982 */
983 protected static function resetRequest()
984 {
985 if (session_status() == PHP_SESSION_NONE) {
986 return;
987 }
988 if (!isset($_SESSION['post_request_vals'])) {
989 $_SESSION['post_request_vals'] = array();
990 }
991 $sesVars = $_SESSION['post_request_vals'];
992 $setReq = function (&$val, &$key) {
993 $_POST[$key] = $val;
994 unset($val, $key);
995 };
996 if (count($sesVars) > 0) {
997 array_walk($sesVars, $setReq);
998 }
999 unset($_SESSION['post_request_vals'], $sesVars, $reqVars);
1000 }
1001 /**
1002 * Set request vars particularly for post failures really.
1003 *
1004 * @return void
1005 */
1006 protected function setRequest()
1007 {
1008 if (session_status() == PHP_SESSION_NONE) {
1009 return;
1010 }
1011 if (!isset($_SESSION['post_request_vals'])) {
1012 $_SESSION['post_request_vals'] = array();
1013 }
1014 if (!$_SESSION['post_request_vals'] && self::$post) {
1015 $_SESSION['post_request_vals'] = $_POST;
1016 }
1017 }
1018 /**
1019 * Return nicely formatted byte sizes.
1020 *
1021 * @param int|float $size the size to convert
1022 *
1023 * @return float
1024 */
1025 protected static function formatByteSize($size)
1026 {
1027 $units = array('iB', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB');
1028 $factor = floor((strlen($size) - 1) / 3);
1029
1030 return sprintf('%3.2f %s', $size / pow(1024, $factor), $units[$factor]);
1031 }
1032 /**
1033 * Gets the global module status.
1034 *
1035 * Can return just the shortnames or the long.
1036 *
1037 * @param bool $names if set will return the services as set
1038 * @param bool $keys will return just the shortnames if set
1039 *
1040 * @return array
1041 */
1042 protected static function getGlobalModuleStatus($names = false, $keys = false)
1043 {
1044 // The shortnames are on the left, the long names are on the right
1045 // If the right is true it means the short is accurate.
1046 // If the left is not the right caller in form of:
1047 // FOG_CLIENT_<name>_ENABLED in lowercase.
1048 $services = array(
1049 'autologout' => 'autologoff',
1050 'clientupdater' => true,
1051 'dircleanup' => 'directorycleaner',
1052 'displaymanager' => true,
1053 'greenfog' => true,
1054 'hostnamechanger' => true,
1055 'hostregister' => true,
1056 'powermanagement' => true,
1057 'printermanager' => true,
1058 'snapinclient' => 'snapin',
1059 'taskreboot' => true,
1060 'usercleanup' => true,
1061 'usertracker' => true,
1062 );
1063 // If keys is set, return just the keys.
1064 if ($keys) {
1065 $keys = array_keys($services);
1066 $keys = array_filter($keys);
1067 $keys = array_unique($keys);
1068
1069 return array_values($keys);
1070 }
1071 // Change the keys values
1072 foreach ($services as $short => &$value) {
1073 $tmp = $value === true ? $short : $value;
1074 $value = sprintf('FOG_CLIENT_%s_ENABLED', strtoupper($tmp));
1075 unset($value);
1076 }
1077 // If names is set, send back the short and long names together.
1078 if ($names) {
1079 return $services;
1080 }
1081 // Now lets get their status'
1082 $serviceEn = self::getSubObjectIDs(
1083 'Service',
1084 array(
1085 'name' => array_values($services),
1086 ),
1087 'value',
1088 false,
1089 'AND',
1090 'name',
1091 false,
1092 false
1093 );
1094
1095 return array_combine(array_keys($services), $serviceEn);
1096 }
1097 /**
1098 * Sets the date.
1099 *
1100 * @param mixed $date The date stamp, defaults to now if not set
1101 * @param bool $utc Whether to use utc timezone or not
1102 *
1103 * @return DateTime
1104 */
1105 public static function niceDate($date = 'now', $utc = false)
1106 {
1107 if ($utc || empty(self::$TimeZone)) {
1108 $tz = new DateTimeZone('UTC');
1109 } else {
1110 $tz = new DateTimeZone(self::$TimeZone);
1111 }
1112
1113 return new DateTime($date, $tz);
1114 }
1115 /**
1116 * Do formatting things.
1117 *
1118 * @param mixed $time The time to work from
1119 * @param mixed $format Specified format to return
1120 * @param bool $utc Use UTC Timezone?
1121 *
1122 * @return mixed
1123 */
1124 public static function formatTime($time, $format = false, $utc = false)
1125 {
1126 if (!$time instanceof DateTime) {
1127 $time = self::niceDate($time, $utc);
1128 }
1129 if ($format) {
1130 if (!self::validDate($time)) {
1131 return _('No Data');
1132 }
1133
1134 return $time->format($format);
1135 }
1136 $now = self::niceDate('now', $utc);
1137 // Get difference of the current to supplied.
1138 $diff = $now->format('U') - $time->format('U');
1139 $absolute = abs($diff);
1140 if (is_nan($diff)) {
1141 return _('Not a number');
1142 }
1143 if (!self::validDate($time)) {
1144 return _('No Data');
1145 }
1146 $date = $time->format('Y/m/d');
1147 if ($now->format('Y/m/d') == $date) {
1148 if (0 <= $diff && $absolute < 60) {
1149 return 'Moments ago';
1150 } elseif ($diff < 0 && $absolute < 60) {
1151 return 'Seconds from now';
1152 } elseif ($absolute < 3600) {
1153 return self::humanify($diff / 60, 'minute');
1154 } else {
1155 return self::humanify($diff / 3600, 'hour');
1156 }
1157 }
1158 $dayAgo = clone $now;
1159 $dayAgo->modify('-1 day');
1160 $dayAhead = clone $now;
1161 $dayAhead->modify('+1 day');
1162 if ($dayAgo->format('Y/m/d') == $date) {
1163 return 'Ran Yesterday at '.$time->format('H:i');
1164 } elseif ($dayAhead->format('Y/m/d') == $date) {
1165 return 'Runs today at '.$time->format('H:i');
1166 } elseif ($absolute / 86400 <= 7) {
1167 return self::humanify($diff / 86400, 'day');
1168 } elseif ($absolute / 604800 <= 5) {
1169 return self::humanify($diff / 604800, 'week');
1170 } elseif ($absolute / 2628000 < 12) {
1171 return self::humanify($diff / 2628000, 'month');
1172 }
1173
1174 return self::humanify($diff / 31536000, 'year');
1175 }
1176 /**
1177 * Checks if the time passed is valid or not.
1178 *
1179 * @param mixed $date the date to use
1180 * @param mixed $format the format to test
1181 *
1182 * @return object
1183 */
1184 protected static function validDate($date, $format = '')
1185 {
1186 if ($format == 'N') {
1187 if ($date instanceof DateTime) {
1188 return $date->format('N') >= 0;
1189 } else {
1190 return $date >= 0 && $date <= 7;
1191 }
1192 }
1193 if (!$date instanceof DateTime) {
1194 $date = self::niceDate($date);
1195 }
1196 if (!$format) {
1197 $format = 'm/d/Y';
1198 }
1199 if (empty(self::$TimeZone)) {
1200 $tz = new DateTimeZone('UTC');
1201 } else {
1202 $tz = new DateTimeZone(self::$TimeZone);
1203 }
1204
1205 return DateTime::createFromFormat(
1206 $format,
1207 $date->format($format),
1208 $tz
1209 );
1210 }
1211 /**
1212 * Simply returns if the item should be with an s or not.
1213 *
1214 * @param int $count The count of the element
1215 * @param string $text The string to append to
1216 * @param bool $space Use a space or not
1217 *
1218 * @throws Exception
1219 *
1220 * @return string
1221 */
1222 protected static function pluralize($count, $text, $space = false)
1223 {
1224 if (!is_bool($space)) {
1225 throw new Exception(_('Space variable must be boolean'));
1226 }
1227
1228 return sprintf(
1229 '%d %s%s%s',
1230 $count,
1231 $text,
1232 $count != 1 ? 's' : '',
1233 $space === true ? ' ' : ''
1234 );
1235 }
1236 /**
1237 * Returns the difference given from a start and end time.
1238 *
1239 * @param mixed $start the starting date
1240 * @param mixed $end the ending date
1241 * @param bool $ago Return immediate highest down
1242 *
1243 * @throws Exception
1244 *
1245 * @return DateTime
1246 */
1247 protected static function diff($start, $end, $ago = false)
1248 {
1249 if (!is_bool($ago)) {
1250 throw new Exception(_('Ago must be boolean'));
1251 }
1252 if (!$start instanceof DateTime) {
1253 $start = self::niceDate($start);
1254 }
1255 if (!$end instanceof DateTime) {
1256 $end = self::niceDate($end);
1257 }
1258 $Duration = $start->diff($end);
1259 $str = '';
1260 $suffix = '';
1261 if ($ago === true) {
1262 $str = '%s %s';
1263 if ($Duration->invert) {
1264 $suffix = 'ago';
1265 }
1266 if (($v = $Duration->y) > 0) {
1267 return sprintf(
1268 $str,
1269 self::pluralize($v, 'year'),
1270 $suffix
1271 );
1272 }
1273 if (($v = $Duration->m) > 0) {
1274 return sprintf(
1275 $str,
1276 self::pluralize($v, 'month'),
1277 $suffix
1278 );
1279 }
1280 if (($v = $Duration->d) > 0) {
1281 return sprintf(
1282 $str,
1283 self::pluralize($v, 'day'),
1284 $suffix
1285 );
1286 }
1287 if (($v = $Duration->h) > 0) {
1288 return sprintf(
1289 $str,
1290 self::pluralize($v, 'hour'),
1291 $suffix
1292 );
1293 }
1294 if (($v = $Duration->i) > 0) {
1295 return sprintf(
1296 $str,
1297 self::pluralize($v, 'minute'),
1298 $suffix
1299 );
1300 }
1301 if (($v = $Duration->s) > 0) {
1302 return sprintf(
1303 $str,
1304 self::pluralize($v, 'second'),
1305 $suffix
1306 );
1307 }
1308 }
1309 if (($v = $Duration->y) > 0) {
1310 $str .= self::pluralize($v, 'year', true);
1311 }
1312 if (($v = $Duration->m) > 0) {
1313 $str .= self::pluralize($v, 'month', true);
1314 }
1315 if (($v = $Duration->d) > 0) {
1316 $str .= self::pluralize($v, 'day', true);
1317 }
1318 if (($v = $Duration->h) > 0) {
1319 $str .= self::pluralize($v, 'hour', true);
1320 }
1321 if (($v = $Duration->i) > 0) {
1322 $str .= self::pluralize($v, 'minute', true);
1323 }
1324 if (($v = $Duration->s) > 0) {
1325 $str .= self::pluralize($v, 'second');
1326 }
1327
1328 return $str;
1329 }
1330 /**
1331 * Return more human friendly time.
1332 *
1333 * @param int $diff the difference passed
1334 * @param string $unit the unit of time (minute, hour, etc...)
1335 *
1336 * @throws Exception
1337 *
1338 * @return string
1339 */
1340 protected static function humanify($diff, $unit)
1341 {
1342 if (!is_numeric($diff)) {
1343 throw new Exception(_('Diff parameter must be numeric'));
1344 }
1345 if (!is_string($unit)) {
1346 throw new Exception(_('Unit of time must be a string'));
1347 }
1348 $before = $after = '';
1349 if ($diff < 0) {
1350 $before = sprintf('%s ', _('In'));
1351 }
1352 if ($diff < 0) {
1353 $after = sprintf(' %s', _('ago'));
1354 }
1355 $diff = floor(abs($diff));
1356 if ($diff != 1) {
1357 $unit .= 's';
1358 }
1359
1360 return sprintf(
1361 '%s%d %s%s',
1362 $before,
1363 $diff,
1364 $unit,
1365 $after
1366 );
1367 }
1368 /**
1369 * Changes the keys around as needed.
1370 *
1371 * @param array $array the array to change key for
1372 * @param string $old_key the original key
1373 * @param string $new_key the key to change to
1374 *
1375 * @throws Exception
1376 * @return void
1377 */
1378 protected static function arrayChangeKey(array &$array, $old_key, $new_key)
1379 {
1380 if (!is_string($old_key)) {
1381 throw new Exception(_('Old key must be a string'));
1382 }
1383 if (!is_string($new_key)) {
1384 throw new Exception(_('New key must be a string'));
1385 }
1386 $array[$old_key] = (
1387 is_string($array[$old_key]) ?
1388 trim($array[$old_key]) :
1389 $array[$old_key]
1390 );
1391 if (!self::$service && is_string($array[$old_key])) {
1392 $item = mb_convert_encoding(
1393 $array[$old_key],
1394 'utf-8'
1395 );
1396 $array[$new_key] = Initiator::sanitizeItems(
1397 $item
1398 );
1399 } else {
1400 $array[$new_key] = $array[$old_key];
1401 }
1402 if ($old_key != $new_key) {
1403 unset($array[$old_key]);
1404 }
1405 }
1406 /**
1407 * Converts to bits.
1408 *
1409 * @param int|float $kilobytes the bytes to convert
1410 *
1411 * @return float
1412 */
1413 protected static function byteconvert($kilobytes)
1414 {
1415 return ($kilobytes / 8) * 1024;
1416 }
1417 /**
1418 * Converts hex to binary equivalent.
1419 *
1420 * @param mixed $hex The hex to convert.
1421 *
1422 * @return string
1423 */
1424 protected static function hex2bin($hex)
1425 {
1426 if (function_exists('hex2bin')) {
1427 return hex2bin($hex);
1428 }
1429 $n = strlen($hex);
1430 $i = 0;
1431 $sbin = '';
1432 while ($i < $n) {
1433 $a = substr($hex, $i, 2);
1434 $sbin .= pack('H*', $a);
1435 $i += 2;
1436 }
1437
1438 return $sbin;
1439 }
1440 /**
1441 * Create security token.
1442 *
1443 * @return string
1444 */
1445 public static function createSecToken()
1446 {
1447 if (function_exists('random_bytes')) {
1448 $token = bin2hex(
1449 random_bytes(64)
1450 );
1451 } elseif (function_exists('openssl_random_pseudo_bytes')) {
1452 $token = bin2hex(
1453 openssl_random_pseudo_bytes(
1454 64
1455 )
1456 );
1457 }
1458 return $token;
1459 }
1460 /**
1461 * AES Encrypt function.
1462 *
1463 * @param mixed $data the item to encrypt
1464 * @param string $key the key to use if false will generate own
1465 * @param int $enctype the type of encryption to use
1466 *
1467 * @return string
1468 */
1469 public static function aesencrypt(
1470 $data,
1471 $key = false,
1472 $enctype = 'aes-256-cbc'
1473 ) {
1474 if (!$data) {
1475 echo json_encode(
1476 array(
1477 'error' => _('Data is blank')
1478 )
1479 );
1480 exit;
1481 }
1482 $iv_size = openssl_cipher_iv_length($enctype);
1483 $key = self::hex2bin($key);
1484 if (mb_strlen($key, '8bit') !== ($iv_size * 2)) {
1485 echo json_encode(
1486 array(
1487 'error' => _('Needs a 256-bit key')
1488 )
1489 );
1490 exit;
1491 }
1492 $iv = openssl_random_pseudo_bytes($iv_size, $cstrong);
1493
1494 // Pad the plaintext
1495 if (strlen($data) % $iv_size) {
1496 $data = str_pad(
1497 $data,
1498 ((strlen($data) + $iv_size) - (strlen($data) % $iv_size)),
1499 "\0"
1500 );
1501 }
1502
1503 $cipher = openssl_encrypt(
1504 $data,
1505 $enctype,
1506 $key,
1507 OPENSSL_RAW_DATA | OPENSSL_NO_PADDING,
1508 $iv
1509 );
1510 if (!$cipher) {
1511 echo json_encode(
1512 array(
1513 'error' => openssl_error_string()
1514 )
1515 );
1516 exit;
1517 }
1518 $iv = bin2hex($iv);
1519 $cipher = bin2hex($cipher);
1520 return sprintf(
1521 '%s|%s',
1522 $iv,
1523 $cipher
1524 );
1525 }
1526 /**
1527 * AES Decrypt function.
1528 *
1529 * @param mixed $encdata the item to decrypt
1530 * @param string $key the key to use
1531 * @param int $enctype the type of encryption to use
1532 * @param int $mode the mode of encryption
1533 *
1534 * @return string
1535 */
1536 public static function aesdecrypt(
1537 $encdata,
1538 $key = false,
1539 $enctype = 'aes-128-cbc'
1540 ) {
1541 $iv_size = openssl_cipher_iv_length($enctype) * 2;
1542 if (false === strpos($encdata, '|')) {
1543 return $encdata;
1544 }
1545 $data = explode('|', $encdata);
1546 if (strlen($data[0]) != $iv_size || strlen($data[1]) != $iv_size) {
1547 return $encdata;
1548 }
1549 // add error handler to catch warnings we might get from pack() with non-hex strings
1550 set_error_handler(
1551 function ($severity, $message, $file, $line) {
1552 throw new ErrorException($message, $severity, $severity, $file, $line);
1553 }
1554 );
1555 try {
1556 $iv = pack('H*', $data[0]);
1557 $encoded = pack('H*', $data[1]);
1558 if (!$key && isset($data[2]) && strlen($data[2]) == $iv_size) {
1559 $key = pack('H*', $data[2]);
1560 }
1561 } catch (Exception $e) {
1562 return $encdata;
1563 }
1564 restore_error_handler();
1565 if (empty($key)) {
1566 return '';
1567 }
1568 $decipher = openssl_decrypt(
1569 $encoded,
1570 $enctype,
1571 $key,
1572 OPENSSL_RAW_DATA | OPENSSL_NO_PADDING,
1573 $iv
1574 );
1575 if (!$decipher) {
1576 echo json_encode(
1577 array(
1578 'error' => openssl_error_string()
1579 )
1580 );
1581 exit;
1582 }
1583
1584 return trim($decipher);
1585 }
1586 /**
1587 * Encrypts the data using the host information.
1588 * Really just an alias to aesencrypt for now.
1589 *
1590 * @param mixed $data the data to encrypt
1591 *
1592 * @throws Exception
1593 *
1594 * @return string
1595 */
1596 protected static function certEncrypt($data)
1597 {
1598 if (!self::$Host->isValid()) {
1599 throw new Exception('#!ih');
1600 }
1601 if (!self::$Host->get('pub_key')) {
1602 throw new Exception('#!ihc');
1603 }
1604 return self::aesencrypt($data, self::$Host->get('pub_key'));
1605 }
1606 /**
1607 * Decrypts the information passed.
1608 *
1609 * @param mixed $dataArr the data to decrypt
1610 * @param bool $padding to use padding or not
1611 *
1612 * @throws Exception
1613 *
1614 * @return mixed
1615 */
1616 protected static function certDecrypt($dataArr, $padding = true)
1617 {
1618 if ($padding) {
1619 $padding = OPENSSL_PKCS1_PADDING;
1620 } else {
1621 $padding = OPENSSL_NO_PADDING;
1622 }
1623 $tmpssl = array();
1624 $sslfile = self::getSubObjectIDs('StorageNode', '', 'sslpath');
1625 foreach ($sslfile as &$path) {
1626 if (!file_exists($path) || !is_readable($path)) {
1627 continue;
1628 }
1629 $tmpssl[] = $path;
1630 unset($path);
1631 }
1632 if (count($tmpssl) < 1) {
1633 throw new Exception(_('Private key path not found'));
1634 }
1635 $sslfile = sprintf(
1636 '%s%s.srvprivate.key',
1637 str_replace(
1638 array('\\', '/'),
1639 array(
1640 DS,
1641 DS
1642 ),
1643 $tmpssl[0]
1644 ),
1645 DS
1646 );
1647 unset($tmpssl);
1648 if (!file_exists($sslfile)) {
1649 throw new Exception(_('Private key not found'));
1650 }
1651 if (!is_readable($sslfile)) {
1652 throw new Exception(_('Private key not readable'));
1653 }
1654 $sslfilecontents = file_get_contents($sslfile);
1655 $priv_key = openssl_pkey_get_private($sslfilecontents);
1656 if (!$priv_key) {
1657 throw new Exception(_('Private key failed'));
1658 }
1659 $a_key = openssl_pkey_get_details($priv_key);
1660 $chunkSize = ceil($a_key['bits'] / 8);
1661 $output = array();
1662 foreach ((array) $dataArr as &$data) {
1663 $dataun = '';
1664 while ($data) {
1665 $data = self::hex2bin($data);
1666 $chunk = substr($data, 0, $chunkSize);
1667 $data = substr($data, $chunkSize);
1668 $decrypt = '';
1669 $test = openssl_private_decrypt(
1670 $chunk,
1671 $decrypt,
1672 $priv_key,
1673 $padding
1674 );
1675 if (!$test) {
1676 throw new Exception(_('Failed to decrypt data on server'));
1677 }
1678 $dataun .= $decrypt;
1679 }
1680 unset($data);
1681 $output[] = $dataun;
1682 }
1683 openssl_free_key($priv_key);
1684
1685 return (array) $output;
1686 }
1687 /**
1688 * Cycle the macs and return valid.
1689 *
1690 * @param string|array $stringlist the macs to parse
1691 * @param bool $image check if image type ignored
1692 * @param bool $client check if client type ignored
1693 *
1694 * @return array
1695 */
1696 public static function parseMacList(
1697 $stringlist,
1698 $image = false,
1699 $client = false
1700 ) {
1701 $MAClist = array();
1702 $MACs = $stringlist;
1703 $lowerAndTrim = function ($element) {
1704 return strtolower(trim($element));
1705 };
1706 if (!is_array($stringlist)) {
1707 $MACs = array_map($lowerAndTrim, explode('|', $stringlist));
1708 } else {
1709 $MACs = array_map($lowerAndTrim, $stringlist);
1710 }
1711 $MACs = array_filter($MACs);
1712 $MACs = array_unique($MACs);
1713 $MACs = array_values($MACs);
1714 if (count($MACs) < 1) {
1715 return array();
1716 }
1717 $pending_filter = explode(
1718 ',',
1719 self::getSetting('FOG_QUICKREG_PENDING_MAC_FILTER')
1720 );
1721 $Ignore = array_map($lowerAndTrim, $pending_filter);
1722 $Ignore = array_filter($Ignore);
1723 if (count($Ignore) > 0) {
1724 $pattern = sprintf(
1725 '#%s#i',
1726 implode('|', (array) $Ignore)
1727 );
1728 $found_macs = preg_grep($pattern, $MACs);
1729 $MACs = array_diff($MACs, $found_macs);
1730 $MACs = array_filter($MACs);
1731 $MACs = array_unique($MACs);
1732 $MACs = array_values($MACs);
1733 }
1734 if (count($MACs) < 1) {
1735 return array();
1736 }
1737 $count = self::getClass('MACAddressAssociationManager')->count(
1738 array(
1739 'mac' => $MACs,
1740 'pending' => array(0, ''),
1741 )
1742 );
1743 if ($count > 0) {
1744 $existingMACs = self::getSubObjectIDs(
1745 'MACAddressAssociation',
1746 array(
1747 'mac' => $MACs,
1748 'pending' => array(0, ''),
1749 ),
1750 'mac'
1751 );
1752 $existingMACs = array_map($lowerAndTrim, $existingMACs);
1753 $existingMACs = array_filter($existingMACs);
1754 $existingMACs = array_unique($existingMACs);
1755 $existingMACs = array_values($existingMACs);
1756 $MACs = self::fastmerge((array) $MACs, (array) $existingMACs);
1757 $MACs = array_unique($MACs);
1758 }
1759 if ($client) {
1760 $clientIgnored = self::getSubObjectIDs(
1761 'MACAddressAssociation',
1762 array(
1763 'mac' => $MACs,
1764 'clientIgnore' => 1,
1765 ),
1766 'mac'
1767 );
1768 $clientIgnored = array_map($lowerAndTrim, $clientIgnored);
1769 $MACs = array_diff((array) $MACs, (array) $clientIgnored);
1770 unset($clientIgnored);
1771 }
1772 if ($image) {
1773 $imageIgnored = self::getSubObjectIDs(
1774 'MACAddressAssociation',
1775 array(
1776 'mac' => $MACs,
1777 'imageIgnore' => 1,
1778 ),
1779 'mac'
1780 );
1781 $imageIgnored = array_map($lowerAndTrim, (array) $imageIgnored);
1782 $MACs = array_diff((array) $MACs, (array) $imageIgnored);
1783 unset($imageIgnored);
1784 }
1785 $MACs = array_filter($MACs);
1786 $MACs = array_unique($MACs);
1787 $MACs = array_values($MACs);
1788 if (count($MACs) < 1) {
1789 return array();
1790 }
1791 $validMACs = array();
1792 foreach ($MACs as &$MAC) {
1793 $MAC = self::getClass('MACAddress', $MAC);
1794 if (!$MAC->isValid()) {
1795 continue;
1796 }
1797 $validMACs[] = $MAC;
1798 unset($MAC);
1799 }
1800 $validMACs = array_filter($validMACs);
1801
1802 return $validMACs;
1803 }
1804 /**
1805 * Prints the data encrypted as needed.
1806 *
1807 * @param string $datatosend the data to send
1808 * @param bool $service if not a service simpy return
1809 * @param array $array The non-encoded array data.
1810 *
1811 * @return string
1812 */
1813 protected function sendData(
1814 $datatosend,
1815 $service = true,
1816 $array = array()
1817 ) {
1818 global $sub;
1819 if (false === $service) {
1820 return;
1821 }
1822 try {
1823 if (!self::$Host->isValid()) {
1824 throw new Exception('#!ih');
1825 }
1826 $datatosend = trim($datatosend);
1827 $curdate = self::niceDate();
1828 $secdate = self::niceDate(self::$Host->get('sec_time'));
1829 if ($curdate >= $secdate) {
1830 self::$Host
1831 ->set('pub_key', '')
1832 ->save()
1833 ->load();
1834 if (self::$newService || self::$json) {
1835 throw new Exception('#!ihc');
1836 }
1837 }
1838 if (self::$newService) {
1839 printf(
1840 '#!enkey=%s',
1841 self::certEncrypt($datatosend)
1842 );
1843 exit;
1844 } else {
1845 echo $datatosend;
1846 exit;
1847 }
1848 } catch (Exception $e) {
1849 if (self::$json) {
1850 if ($e->getMessage() === '#!ihc') {
1851 echo $e->getMessage();
1852 exit;
1853 }
1854 $repData = str_replace('#!', '', $e->getMessage());
1855 $array['error'] = $repData;
1856 $data = array('error' => $repData);
1857 if ($sub === 'requestClientInfo') {
1858 echo json_encode($array);
1859 exit;
1860 } else {
1861 return $data;
1862 }
1863 }
1864 throw new Exception($e->getMessage());
1865 }
1866 }
1867 /**
1868 * Checks if an array of needles is found in the main array.
1869 *
1870 * @param array $haystack the array to search
1871 * @param array $needles the items to test for
1872 * @param bool $case whether to be case insensitive
1873 *
1874 * @return bool
1875 */
1876 protected static function arrayStrpos($haystack, $needles, $case = true)
1877 {
1878 $cmd = sprintf('str%spos', ($case ? 'i' : ''));
1879 $mapinfo = array();
1880 foreach ((array) $needles as &$needle) {
1881 $mapinfo[] = $cmd($haystack, $needle);
1882 unset($needle);
1883 }
1884 $mapinfo = array_filter($mapinfo);
1885
1886 return count($mapinfo) > 0;
1887 }
1888 /**
1889 * How to log this file.
1890 *
1891 * @param string $txt The text to log.
1892 * @param int $curlog The logLevel setting.
1893 * @param int $logfile The logToFile setting.
1894 * @param int $logbrow The logToBrowser setting.
1895 * @param object $obj The object.
1896 * @param int $level The basic log level.
1897 *
1898 * @return void
1899 */
1900 protected static function log(
1901 $txt,
1902 $curlog,
1903 $logfile,
1904 $logbrow,
1905 $obj,
1906 $level = 1
1907 ) {
1908 if (!is_string($txt)) {
1909 throw new Exception(_('Txt must be a string'));
1910 }
1911 if (!is_int($level)) {
1912 throw new Exception(_('Level must be an integer'));
1913 }
1914 if (self::$ajax) {
1915 return;
1916 }
1917 $findStr = array("\r", "\n", "\t", ' ,');
1918 $repStr = array('', ' ', ' ', ',');
1919 $txt = str_replace($findStr, $repStr, $txt);
1920 $txt = trim($txt);
1921 if (empty($txt)) {
1922 return;
1923 }
1924 $txt = sprintf('[%s] %s', self::niceDate()->format('Y-m-d H:i:s'), $txt);
1925 if ($curlog >= $level) {
1926 echo $txt;
1927 }
1928 self::logHistory($txt);
1929 }
1930 /**
1931 * Log to history table.
1932 *
1933 * @param string $string the string to store
1934 *
1935 * @return void
1936 */
1937 protected static function logHistory($string)
1938 {
1939 if (!is_string($string)) {
1940 throw new Exception(_('String must be a string'));
1941 }
1942 $string = sprintf(
1943 '[%s] %s',
1944 self::niceDate()->format('Y-m-d H:i:s'),
1945 $string
1946 );
1947 $string = trim($string);
1948 if (!$string) {
1949 return;
1950 }
1951 $name = (
1952 self::$FOGUser->isValid() ?
1953 self::$FOGUser->get('name') :
1954 'fog'
1955 );
1956 if (!self::$FOGUser->isValid()) {
1957 return;
1958 }
1959 if (self::$DB) {
1960 self::getClass('History')
1961 ->set('info', $string)
1962 ->set('ip', self::$remoteaddr)
1963 ->save();
1964 }
1965 }
1966 /**
1967 * Sets the order by element of sql.
1968 *
1969 * @param string $orderBy the string to order by
1970 *
1971 * @return void
1972 */
1973 public function orderBy(&$orderBy)
1974 {
1975 if (empty($orderBy)) {
1976 $orderBy = 'name';
1977 if (!array_key_exists($orderBy, $this->databaseFields)) {
1978 $orderBy = 'id';
1979 }
1980 } else {
1981 if (!is_array($orderBy)) {
1982 $orderBy = trim($orderBy);
1983 if (!array_key_exists($orderBy, $this->databaseFields)) {
1984 $orderBy = 'name';
1985 }
1986 if (!array_key_exists($orderBy, $this->databaseFields)) {
1987 $orderBy = 'id';
1988 }
1989 }
1990 }
1991 }
1992 /**
1993 * Gets the object ids only.
1994 *
1995 * @param string $object The object to use
1996 * @param array $findWhere How to find the elements we need
1997 * @param string $getField The field value to return
1998 * @param mixed $not DB to search with not or no not
1999 * @param string $operator How to join strings (And or Or)
2000 * @param mixed $orderBy Order the return by
2001 * @param mixed $groupBy Group the return by
2002 * @param string $filter How to filter the data returning
2003 *
2004 * @return array
2005 */
2006 public static function getSubObjectIDs(
2007 $object = 'Host',
2008 $findWhere = array(),
2009 $getField = 'id',
2010 $not = false,
2011 $operator = 'AND',
2012 $orderBy = 'name',
2013 $groupBy = false,
2014 $filter = 'array_unique'
2015 ) {
2016 if (empty($object)) {
2017 $object = 'Host';
2018 }
2019 if (empty($getField)) {
2020 $getField = 'id';
2021 }
2022 if (empty($operator)) {
2023 $operator = 'AND';
2024 }
2025 if (is_array($getField)) {
2026 foreach ((array)$getField as &$field) {
2027 $data[$field] = self::getSubObjectIDs(
2028 $object,
2029 $findWhere,
2030 $field,
2031 $not,
2032 $operator,
2033 $orderBy,
2034 $groupBy,
2035 $filter
2036 );
2037 unset($field);
2038 }
2039 return $data;
2040 }
2041 return self::getClass($object)->getManager()->find(
2042 $findWhere,
2043 $operator,
2044 $orderBy,
2045 '',
2046 '',
2047 $groupBy,
2048 $not,
2049 $getField,
2050 '',
2051 $filter
2052 );
2053 }
2054 /**
2055 * Get global setting value by key.
2056 *
2057 * @param string $key What to get
2058 *
2059 * @throws Exception
2060 *
2061 * @return string
2062 */
2063 public static function getSetting($key)
2064 {
2065 if (!is_string($key)) {
2066 throw new Exception(_('Key must be a string'));
2067 }
2068 $findStr = '\r\n';
2069 $repStr = "\n";
2070 $value = self::getClass('Service')
2071 ->set('name', $key)
2072 ->load('name')
2073 ->get('value');
2074
2075 return trim(
2076 str_replace(
2077 $findStr,
2078 $repStr,
2079 $value
2080 )
2081 );
2082 }
2083 /**
2084 * Set global setting value by key.
2085 *
2086 * @param string $key What to set
2087 * @param string $value Value to set
2088 *
2089 * @throws Exception
2090 *
2091 * @return this
2092 */
2093 public static function setSetting($key, $value)
2094 {
2095 self::getClass('ServiceManager')->update(
2096 array('name' => $key),
2097 '',
2098 array('value' => trim($value))
2099 );
2100 }
2101 /**
2102 * Gets queued state ids.
2103 *
2104 * @return array
2105 */
2106 public static function getQueuedStates()
2107 {
2108 return (array)TaskState::getQueuedStates();
2109 }
2110 /**
2111 * Get queued state main id.
2112 *
2113 * @return int
2114 */
2115 public static function getQueuedState()
2116 {
2117 return TaskState::getQueuedState();
2118 }
2119 /**
2120 * Get checked in state id.
2121 *
2122 * @return int
2123 */
2124 public static function getCheckedInState()
2125 {
2126 return TaskState::getCheckedInState();
2127 }
2128 /**
2129 * Get in progress state id.
2130 *
2131 * @return int
2132 */
2133 public static function getProgressState()
2134 {
2135 return TaskState::getProgressState();
2136 }
2137 /**
2138 * Get complete state id.
2139 *
2140 * @return int
2141 */
2142 public static function getCompleteState()
2143 {
2144 return TaskState::getCompleteState();
2145 }
2146 /**
2147 * Get cancelled state id.
2148 *
2149 * @return int
2150 */
2151 public static function getCancelledState()
2152 {
2153 return TaskState::getCancelledState();
2154 }
2155 /**
2156 * Put string between two strings.
2157 *
2158 * @param string $string the string to insert
2159 * @param string $start the string to place after
2160 * @param string $end the string to place before
2161 *
2162 * @return string
2163 */
2164 public static function stringBetween($string, $start, $end)
2165 {
2166 $string = " $string";
2167 $ini = strpos($string, $start);
2168 if ($ini == 0) {
2169 return '';
2170 }
2171 $ini += strlen($start);
2172 $len = strpos($string, $end, $ini) - $ini;
2173
2174 return substr($string, $ini, $len);
2175 }
2176 /**
2177 * Strips and decodes items.
2178 *
2179 * @param mixed $item the item to strip and decode
2180 *
2181 * @return mixed
2182 */
2183 public static function stripAndDecode(&$item)
2184 {
2185 foreach ((array) $item as $key => &$val) {
2186 $tmp = str_replace(' ', '+', $val);
2187 $tmp = base64_decode($tmp);
2188 $tmp = trim($tmp);
2189 if (mb_detect_encoding($tmp, 'utf-8', true)) {
2190 $val = $tmp;
2191 }
2192 unset($tmp);
2193 $item[$key] = trim($val);
2194 unset($val);
2195 }
2196
2197 return $item;
2198 }
2199 /**
2200 * Gets the master interface based on the ip found.
2201 *
2202 * @param string $ip_find the interface ip's to find
2203 *
2204 * @return string
2205 */
2206 public static function getMasterInterface($ip_find)
2207 {
2208 if (count(self::$interface) > 0) {
2209 return self::$interface;
2210 }
2211 self::getIPAddress();
2212 exec(
2213 "/sbin/ip route | grep '$ip_find' | awk -F'[ /]+' '/kernel.*src/ {print $4}'",
2214 $Interfaces,
2215 $retVal
2216 );
2217 $ip_find = trim($ip_find);
2218 if (!$ip_find) {
2219 return;
2220 }
2221 self::$interface = array();
2222 $index = 0;
2223 foreach ((array) self::$ips as &$ip) {
2224 $ip = trim($ip);
2225 if ($ip_find !== $ip) {
2226 continue;
2227 }
2228 self::$interface[] = $Interfaces[$index++];
2229 unset($ip);
2230 }
2231 if (count(self::$interface) < 1) {
2232 return false;
2233 }
2234
2235 return array_shift(self::$interface);
2236 }
2237 /**
2238 * Get IP Addresses of the server.
2239 *
2240 * @return array
2241 */
2242 protected static function getIPAddress($force = false)
2243 {
2244 if (!$force && count(self::$ips) > 0) {
2245 return self::$ips;
2246 }
2247 $output = array();
2248 exec(
2249 "/sbin/ip -4 addr | awk -F'[ /]+' '/global/ {print $3}'",
2250 $IPs,
2251 $retVal
2252 );
2253 if (!count($IPs)) {
2254 exec(
2255 "/sbin/ifconfig -a | awk -F'[ /:]+' '/(cast)/ {print $4}'",
2256 $IPs,
2257 $retVal
2258 );
2259 }
2260 natcasesort($IPs);
2261 $retIPs = function (&$IP) {
2262 $IP = trim($IP);
2263 if (!filter_var($IP, FILTER_VALIDATE_IP)) {
2264 $IP = gethostbyname($IP);
2265 }
2266 if (filter_var($IP, FILTER_VALIDATE_IP)) {
2267 return $IP;
2268 }
2269 };
2270 $retNames = function (&$IP) {
2271 $IP = trim($IP);
2272 if (filter_var($IP, FILTER_VALIDATE_IP)) {
2273 return gethostbyaddr($IP);
2274 }
2275
2276 return $IP;
2277 };
2278 $IPs = array_map($retIPs, (array) $IPs);
2279 $Names = array_map($retNames, (array) $IPs);
2280 $output = self::fastmerge(
2281 $IPs,
2282 $Names,
2283 array('127.0.0.1', '127.0.1.1')
2284 );
2285 unset($IPs, $Names);
2286 natcasesort($output);
2287 self::$ips = array_values(array_filter(array_unique((array) $output)));
2288
2289 return self::$ips;
2290 }
2291 /**
2292 * Returns the last error.
2293 *
2294 * @return string
2295 */
2296 public static function lasterror()
2297 {
2298 $error = error_get_last();
2299
2300 return sprintf(
2301 '%s: %s, %s: %s, %s: %s, %s: %s',
2302 _('Type'),
2303 $error['type'],
2304 _('File'),
2305 $error['file'],
2306 _('Line'),
2307 $error['line'],
2308 _('Message'),
2309 $error['message']
2310 );
2311 }
2312 /**
2313 * Gets the filesize in a non-arch dependent way.
2314 *
2315 * @param string $file the file to get size of
2316 *
2317 * @return string|int|float
2318 */
2319 public static function getFilesize($path)
2320 {
2321 $size = 0;
2322 if (is_dir($path)) {
2323 foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $file) {
2324 if ($file->getFilename() != ".") {
2325 $size += filesize($file);
2326 }
2327 }
2328 } else {
2329 $size = filesize($path);
2330 }
2331 return is_numeric($size) ? $size : 0;
2332 }
2333 /**
2334 * Perform enmass wake on lan.
2335 *
2336 * @param array $macs The macs to send
2337 *
2338 * @return void
2339 */
2340 public static function wakeUp($macs)
2341 {
2342 if (!is_array($macs)) {
2343 $macs = array($macs);
2344 }
2345 session_write_close();
2346 ignore_user_abort(true);
2347 set_time_limit(0);
2348 $macs = self::parseMacList($macs);
2349 if (count($macs) < 1) {
2350 return;
2351 }
2352 $macStr = implode(
2353 '|',
2354 $macs
2355 );
2356 $macStr = trim($macStr);
2357 if (empty($macStr)) {
2358 return;
2359 }
2360 $url = '%s://%s/fog/management/index.php?';
2361 $url .= 'node=client&sub=wakeEmUp';
2362 $nodeURLs = array();
2363 $macCount = count($macs);
2364 if ($macCount < 1) {
2365 return;
2366 }
2367 foreach ((array)self::getClass('StorageNodeManager')
2368 ->find(
2369 array('isEnabled' => 1)
2370 ) as &$Node
2371 ) {
2372 $ip = $Node->get('ip');
2373 $nodeURLs[] = sprintf(
2374 $url,
2375 self::$httpproto,
2376 $ip
2377 );
2378 unset($Node);
2379 }
2380 list(
2381 $gHost
2382 ) = self::getSubObjectIDs(
2383 'Service',
2384 array(
2385 'name' => array(
2386 'FOG_WEB_HOST'
2387 ),
2388 ),
2389 'value',
2390 false,
2391 'AND',
2392 'name',
2393 false,
2394 ''
2395 );
2396 $ip = $gHost;
2397 $nodeURLs[] = $ip;
2398 $ret = self::$FOGURLRequests->process(
2399 $nodeURLs,
2400 'POST',
2401 array('mac' => $macStr),
2402 false,
2403 false,
2404 false,
2405 false
2406 );
2407 }
2408 /**
2409 * Faster array merge operation.
2410 *
2411 * @param array $array1 The array to merge with.
2412 *
2413 * @return array
2414 */
2415 public static function fastmerge($array1)
2416 {
2417 $others = func_get_args();
2418 array_shift($others);
2419 foreach ((array)$others as &$other) {
2420 foreach ((array)$other as $key => &$oth) {
2421 if (is_numeric($key)) {
2422 $array1[] = $oth;
2423 continue;
2424 } elseif (isset($array1[$key])) {
2425 $array1[$key] = $oth;
2426 continue;
2427 }
2428 unset($oth);
2429 }
2430 $array1 += $other;
2431 unset($other);
2432 }
2433
2434 return $array1;
2435 }
2436 /**
2437 * Returns hash of passed file.
2438 *
2439 * @param string $file The file to get hash of.
2440 *
2441 * @return string
2442 */
2443 public static function getHash($file)
2444 {
2445 $filesize = self::getFilesize($file);
2446 $fp = fopen($file, 'r');
2447 if ($fp) {
2448 $data = fread($fp, 10485760);
2449 if ($filesize >= 20971520) {
2450 fseek($fp, -10485760, SEEK_END);
2451 $data .= fread($fp, 10485760);
2452 }
2453 fclose($fp);
2454 }
2455 return isset($data) ? hash('sha256', $data) : '';
2456 }
2457 /**
2458 * Attempts to login
2459 *
2460 * @param string $username the username to attempt
2461 * @param string $password the password to attempt
2462 *
2463 * @return object
2464 */
2465 public static function attemptLogin($username, $password)
2466 {
2467 return self::getClass('User')
2468 ->validatePw($username, $password);
2469 }
2470 /**
2471 * Clears the mac lookup table
2472 *
2473 * @return bool
2474 */
2475 public static function clearMACLookupTable()
2476 {
2477 $OUITable = self::getClass('OUI', '', true);
2478 $OUITable = $OUITable['databaseTable'];
2479 return self::$DB->query("TRUNCATE TABLE `$OUITable`");
2480 }
2481 /**
2482 * Returns the count of mac lookups
2483 *
2484 * @return int
2485 */
2486 public static function getMACLookupCount()
2487 {
2488 return self::getClass('OUIManager')->count();
2489 }
2490 /**
2491 * Resolves a hostname to its IP address
2492 *
2493 * @param string $host the item to test
2494 *
2495 * @return string
2496 */
2497 public static function resolveHostname($host)
2498 {
2499 $host = trim($host);
2500 if (filter_var($host, FILTER_VALIDATE_IP)) {
2501 return $host;
2502 }
2503 $host = gethostbyname($host);
2504 $host = trim($host);
2505 return $host;
2506 }
2507 /**
2508 * Gets the broadcast address of the server
2509 *
2510 * @return array
2511 */
2512 public static function getBroadcast()
2513 {
2514 $output = array();
2515 $cmd = sprintf(
2516 '%s | %s | %s',
2517 '/sbin/ip -4 addr',
2518 "awk -F'[ /]+' '/global/ {print $6}'",
2519 "grep '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'"
2520 );
2521 exec($cmd, $IPs, $retVal);
2522 if (!count($IPs)) {
2523 $cmd = sprintf(
2524 '%s | %s | %s | %s',
2525 '/sbin/ifconfig -a',
2526 "awk '/(cast)/ {print $3}'",
2527 "cut -d':' -f2",
2528 "grep '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'"
2529 );
2530 exec($cmd, $IPs, $retVal);
2531 }
2532 $IPs = array_map('trim', (array)$IPs);
2533 $IPs = array_filter($IPs);
2534 $IPs = array_values($IPs);
2535 return $IPs;
2536 }
2537 /**
2538 * Wait a random interval between 1/2 second to 2 seconds.
2539 *
2540 * @return void
2541 */
2542 public static function randWait()
2543 {
2544 usleep(
2545 rand(
2546 5000,
2547 2000000
2548 )
2549 );
2550 }
2551 }