1<?php 2 3/** 4 * phpIPAM class with common functions, used in all other classes 5 * 6 * @author: Miha Petkovsek <miha.petkovsek@gmail.com> 7 */ 8class Common_functions { 9 10 /** 11 * from api flag 12 * 13 * (default value: false) 14 * 15 * @var bool 16 */ 17 public $api = false; 18 19 /** 20 * settings 21 * 22 * (default value: null) 23 * 24 * @var mixed 25 * @access public 26 */ 27 public $settings = null; 28 29 /** 30 * If Jdon validation error occurs it will be saved here 31 * 32 * (default value: false) 33 * 34 * @var bool 35 * @access public 36 */ 37 public $json_error = false; 38 39 /** 40 * Default font 41 * 42 * (default value: "<font face='Helvetica, Verdana, Arial, sans-serif' style='font-size:12px) 43 * 44 * @var string 45 * @access public 46 */ 47 public $mail_font_style = "<font face='Helvetica, Verdana, Arial, sans-serif' style='font-size:12px;color:#333;'>"; 48 49 /** 50 * Default font 51 * 52 * (default value: "<font face='Helvetica, Verdana, Arial, sans-serif' style='font-size:12px) 53 * 54 * @var string 55 * @access public 56 */ 57 public $mail_font_style_light = "<font face='Helvetica, Verdana, Arial, sans-serif' style='font-size:11px;color:#777;'>"; 58 59 /** 60 * Default font for links 61 * 62 * (default value: "<font face='Helvetica, Verdana, Arial, sans-serif' style='font-size:12px) 63 * 64 * @var string 65 * @access public 66 */ 67 public $mail_font_style_href = "<font face='Helvetica, Verdana, Arial, sans-serif' style='font-size:12px;color:#a0ce4e;'>"; 68 69 /** 70 * Database 71 * 72 * @var mixed 73 * @access protected 74 */ 75 protected $Database; 76 77 /** 78 * Result 79 * 80 * @var mixed 81 * @access public 82 */ 83 public $Result; 84 85 /** 86 * Log 87 * 88 * @var mixed 89 * @access public 90 */ 91 public $Log; 92 93 /** 94 * Net_IPv4 95 * 96 * @var mixed 97 * @access protected 98 */ 99 protected $Net_IPv4; 100 101 /** 102 * Net_IPv6 103 * 104 * @var mixed 105 * @access protected 106 */ 107 protected $Net_IPv6; 108 109 /** 110 * NET_DNS object 111 * 112 * @var mixed 113 * @access protected 114 */ 115 protected $DNS2; 116 117 /** 118 * debugging flag 119 * 120 * @var mixed 121 * @access protected 122 */ 123 protected $debugging; 124 125 /** 126 * Cache mac vendor objects 127 * @var array|null 128 */ 129 private $mac_address_vendors = null; 130 131 132 133 /** 134 * __construct function 135 * 136 * @access public 137 */ 138 public function __construct () { 139 # debugging 140 $this->set_debugging( Config::get('debugging') ); 141 } 142 143 /** 144 * @version handling 145 * -------------------------------- 146 */ 147 148 /** 149 * Compare dotted version numbers 1.21.0 <=> 1.4.10 150 * 151 * @access public 152 * @param string $verA 153 * @param mixed $verB 154 * @return int 155 */ 156 public function cmp_version_strings($verA, $verB) { 157 $a = explode('.', $verA); 158 $b = explode('.', $verB); 159 160 if ($a[0] != $b[0]) return $a[0] < $b[0] ? -1 : 1; // 1.x.y is less than 2.x.y 161 if (strcmp($a[1], $b[1]) != 0) return strcmp($a[1], $b[1]); // 1.21.y is less than 1.3.y 162 if ($a[2] != $b[2]) return $a[2] < $b[2] ? -1 : 1; // 1.4.9 is less than 1.4.10 163 return 0; 164 } 165 166 167 168 169 170 171 172 173 /** 174 * @general fetch methods 175 * -------------------------------- 176 */ 177 178 179 /** 180 * Fetch all objects from specified table in database 181 * 182 * @access public 183 * @param mixed $table 184 * @param mixed $sortField (default:id) 185 * @param mixed bool (default:true) 186 * @return false|array 187 */ 188 public function fetch_all_objects ($table=null, $sortField="id", $sortAsc=true) { 189 # null table 190 if(is_null($table)||strlen($table)==0) return false; 191 192 $cached_item = $this->cache_check("fetch_all_objects", "t=$table f=$sortField o=$sortAsc"); 193 if(is_object($cached_item)) return $cached_item->result; 194 195 # fetch 196 try { $res = $this->Database->getObjects($table, $sortField, $sortAsc); } 197 catch (Exception $e) { 198 $this->Result->show("danger", _("Error: ").$e->getMessage()); 199 return false; 200 } 201 # save 202 if (is_array($res)) { 203 foreach ($res as $r) { 204 $this->cache_write ($table, $r); 205 } 206 } 207 # result 208 $result = (is_array($res) && sizeof($res)>0) ? $res : false; 209 $this->cache_write ("fetch_all_objects", (object) ["id"=>"t=$table f=$sortField o=$sortAsc", "result" => $result]); 210 return $result; 211 } 212 213 /** 214 * Fetches specified object specified table in database 215 * 216 * @access public 217 * @param mixed $table 218 * @param mixed $method (default: null) 219 * @param mixed $value 220 * @return false|object 221 */ 222 public function fetch_object ($table=null, $method=null, $value) { 223 // checks 224 if(!is_string($table)) return false; 225 if(strlen($table)==0) return false; 226 if(is_null($method)) return false; 227 if(is_null($value)) return false; 228 if($value===0) return false; 229 230 # check cache 231 $cached_item = $this->cache_check($table, $value); 232 if(is_object($cached_item)) 233 return $cached_item; 234 235 # null method 236 $method = is_null($method) ? "id" : $this->Database->escape($method); 237 238 try { $res = $this->Database->getObjectQuery("SELECT * from `$table` where `$method` = ? limit 1;", array($value)); } 239 catch (Exception $e) { 240 $this->Result->show("danger", _("Error: ").$e->getMessage()); 241 return false; 242 } 243 244 # save to cache array 245 $this->cache_write ($table, $res); 246 247 return is_object($res) ? $res : false; 248 } 249 250 /** 251 * Fetches multiple objects in specified table in database 252 * 253 * doesnt cache 254 * 255 * @access public 256 * @param mixed $table 257 * @param mixed $field 258 * @param mixed $value 259 * @param string $sortField (default: 'id') 260 * @param bool $sortAsc (default: true) 261 * @param bool $like (default: false) 262 * @param array|mixed $result_fields (default: *) 263 * @return bool|array 264 */ 265 public function fetch_multiple_objects ($table, $field, $value, $sortField = 'id', $sortAsc = true, $like = false, $result_fields = "*") { 266 # null table 267 if(is_null($table)||strlen($table)==0) return false; 268 else { 269 try { $res = $this->Database->findObjects($table, $field, $value, $sortField, $sortAsc, $like, false, $result_fields); } 270 catch (Exception $e) { 271 $this->Result->show("danger", _("Error: ").$e->getMessage()); 272 return false; 273 } 274 # save to cache 275 if ($result_fields==="*" && is_array($res)) { // Only cache objects containing all fields 276 foreach ($res as $r) { 277 $this->cache_write ($table, $r); 278 } 279 } 280 # result 281 return (is_array($res) && sizeof($res)>0) ? $res : false; 282 } 283 } 284 285 /** 286 * Count objects in database. 287 * 288 * @access public 289 * @param mixed $table 290 * @param mixed $field 291 * @param mixed $val (default: null) 292 * @param bool $like (default: false) 293 * @return int 294 */ 295 public function count_database_objects ($table, $field, $val=null, $like = false) { 296 # if null 297 try { $cnt = $this->Database->numObjectsFilter($table, $field, $val, $like); } 298 catch (Exception $e) { 299 $this->Result->show("danger", _("Error: ").$e->getMessage()); 300 return false; 301 } 302 return $cnt; 303 } 304 305 /** 306 * Count all objects in database. 307 * 308 * @param string $table 309 * @param string $field 310 * @return array|false 311 */ 312 public function count_all_database_objects ($table, $field) { 313 try { $cnt = $this->Database->getGroupBy($table, $field); } 314 catch (Exception $e) { 315 $this->Result->show("danger", _("Error: ").$e->getMessage()); 316 return false; 317 } 318 return $cnt; 319 } 320 321 /** 322 * Returns table schema information 323 * 324 * @param string $tableName 325 * @return array 326 */ 327 public function getTableSchemaByField($tableName) { 328 $results = []; 329 330 if (!is_string($tableName)) return $results; 331 332 $tableName = $this->Database->escape($tableName); 333 334 $cached_item = $this->cache_check("getTableSchemaByField", "t=$tableName"); 335 if(is_object($cached_item)) return $cached_item->result; 336 337 try { 338 $query = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?;"; 339 $schema = $this->Database->getObjectsQuery($query, [$this->Database->dbname, $tableName]); 340 } catch (\Exception $e) { 341 $this->Result->show("danger", _("Error: ").$e->getMessage()); 342 return $results; 343 } 344 345 if (is_array($schema)) { 346 foreach ($schema as $col) { 347 $results[$col->COLUMN_NAME] = $col; 348 } 349 } 350 $this->cache_write("getTableSchemaByField", (object) ["id"=>"t=$tableName", "result" => $results]); 351 return $results; 352 } 353 354 /** 355 * Get all admins that are set to receive changelog 356 * 357 * @access public 358 * @param bool|mixed $subnetId 359 * @return bool|array 360 */ 361 public function changelog_mail_get_recipients ($subnetId = false) { 362 // fetch all users with mailNotify 363 $notification_users = $this->fetch_multiple_objects ("users", "mailChangelog", "Yes", "id", true); 364 // recipients array 365 $recipients = array(); 366 // any ? 367 if (is_array($notification_users)) { 368 if(sizeof($notification_users)>0) { 369 // if subnetId is set check who has permissions 370 if (isset($subnetId)) { 371 foreach ($notification_users as $u) { 372 // inti object 373 $Subnets = new Subnets ($this->Database); 374 //check permissions 375 $subnet_permission = $Subnets->check_permission($u, $subnetId); 376 // if 3 than add 377 if ($subnet_permission==3) { 378 $recipients[] = $u; 379 } 380 } 381 } 382 else { 383 foreach ($notification_users as $u) { 384 if($u->role=="Administrator") { 385 $recipients[] = $u; 386 } 387 } 388 } 389 } 390 return sizeof($recipients)>0 ? $recipients : false; 391 } 392 else { 393 return false; 394 } 395 } 396 397 398 399 400 /** 401 * fetches settings from database 402 * 403 * @access private 404 * @return mixed 405 */ 406 public function get_settings () { 407 if (is_object($this->settings)) 408 return $this->settings; 409 410 // fetch_object results are cached in $Database->cache. 411 $settings = $this->fetch_object("settings", "id", 1); 412 413 if (!is_object($settings)) 414 return false; 415 416 #save 417 $this->settings = $settings; 418 419 return $this->settings; 420 } 421 422 423 /** 424 * Write result to cache. 425 * 426 * @access protected 427 * @param string $table 428 * @param mixed $object 429 * @return void 430 */ 431 protected function cache_write ($table, $object) { 432 if (!is_object($object)) 433 return; 434 435 // Exclude exceptions from caching 436 if ($this->cache_check_exceptions($table)) 437 return; 438 439 // get and check id property 440 $identifier = $this->cache_set_identifier ($table); 441 442 if (!property_exists($object, $identifier)) 443 return; 444 445 $id = $object->{$identifier}; 446 447 // already set 448 if (isset($this->Database->cache[$table][$identifier][$id])) 449 return; 450 451 // add ip ? 452 $ip_check = $this->cache_check_add_ip($table); 453 if ($ip_check!==false) { 454 $object->ip = $this->transform_address ($object->{$ip_check}, "dotted"); 455 } 456 457 // save 458 $this->Database->cache[$table][$identifier][$id] = clone $object; 459 } 460 461 /** 462 * Check if caching is not needed 463 * 464 * @access protected 465 * @param mixed $table 466 * @return bool 467 */ 468 protected function cache_check_exceptions ($table) { 469 $exceptions = [ 470 "firewallZoneSubnet"=>1, 471 "circuitsLogicalMapping" =>1, 472 "php_sessions"=>1]; 473 474 // check 475 return isset($exceptions[$table]) ? true : false; 476 } 477 478 /** 479 * Check if ip is to be added to result 480 * 481 * @access protected 482 * @param mixed $table 483 * @return bool|mixed 484 */ 485 protected function cache_check_add_ip ($table) { 486 $ip_tables = ["subnets"=>"subnet", "ipaddresses"=>"ip_addr"]; 487 488 // check 489 return array_key_exists ($table, $ip_tables) ? $ip_tables[$table] : false; 490 } 491 492 /** 493 * Set identifier for table - exceptions. 494 * 495 * @access protected 496 * @param string $table 497 * @return string 498 */ 499 protected function cache_set_identifier ($table) { 500 // Tables with different primary keys 501 $mapings = [ 502 'userGroups'=>'g_id', 503 'lang'=>'l_id', 504 'vlans'=>'vlanId', 505 'vrf'=>'vrfId', 506 'changelog'=>'cid', 507 'widgets'=>'wid', 508 'deviceTypes'=>'tid']; 509 510 return isset($mapings[$table]) ? $mapings[$table] : 'id'; 511 } 512 513 /** 514 * Checks if object alreay exists in cache.. 515 * 516 * @access protected 517 * @param mixed $table 518 * @param mixed $id 519 * @return bool|array 520 */ 521 protected function cache_check ($table, $id) { 522 // get identifier 523 $identifier = $this->cache_set_identifier ($table); 524 525 // check if cache is already set, otherwise return false 526 if (isset($this->Database->cache[$table][$identifier][$id])) 527 return clone $this->Database->cache[$table][$identifier][$id]; 528 529 return false; 530 } 531 532 /** 533 * Sets debugging 534 * 535 * @access public 536 * @param bool $debug (default: false) 537 * @return void 538 */ 539 public function set_debugging ($debug = false) { 540 $this->debugging = $debug==true ? true : false; 541 } 542 543 /** 544 * Gets debugging 545 * 546 * @access public 547 * @return bool 548 */ 549 public function get_debugging () { 550 return $this->debugging; 551 } 552 553 /** 554 * Initializes PEAR Net IPv4 object 555 * 556 * @access public 557 * @return void 558 */ 559 public function initialize_pear_net_IPv4 () { 560 //initialize NET object 561 if(!is_object($this->Net_IPv4)) { 562 require_once( dirname(__FILE__) . '/../../functions/PEAR/Net/IPv4.php' ); 563 //initialize object 564 $this->Net_IPv4 = new Net_IPv4(); 565 } 566 } 567 568 /** 569 * Initializes PEAR Net IPv6 object 570 * 571 * @access public 572 * @return void 573 */ 574 public function initialize_pear_net_IPv6 () { 575 //initialize NET object 576 if(!is_object($this->Net_IPv6)) { 577 require_once( dirname(__FILE__) . '/../../functions/PEAR/Net/IPv6.php' ); 578 //initialize object 579 $this->Net_IPv6 = new Net_IPv6(); 580 } 581 } 582 583 /** 584 * Initializes PEAR Net IPv6 object 585 * 586 * @access public 587 * @return void 588 */ 589 public function initialize_pear_net_DNS2 () { 590 //initialize NET object 591 if(!is_object($this->DNS2)) { 592 require_once( dirname(__FILE__) . '/../../functions/PEAR/Net/DNS2.php' ); 593 //initialize object 594 $this->DNS2 = new Net_DNS2_Resolver(array("timeout"=>2)); 595 } 596 } 597 598 /** 599 * Strip tags from array or field to protect from XSS 600 * 601 * @access public 602 * @param array|string $input 603 * @return array|string 604 */ 605 public function strip_input_tags ($input) { 606 if(is_array($input)) { 607 foreach($input as $k=>$v) { 608 if(is_array($v)) { 609 $input[$k] = $this->strip_input_tags($v); 610 continue; 611 } 612 $input[$k] = is_null($v) ? NULL : strip_tags($v); 613 } 614 # stripped array 615 return $input; 616 } 617 618 // not array 619 return is_null($input) ? NULL : strip_tags($input); 620 } 621 622 /** 623 * Remove <script>, <iframe> and JS HTML event attributes from HTML to protect from XSS 624 * 625 * @param string $html 626 * @return string 627 */ 628 public function noxss_html($html) { 629 if (!is_string($html) || strlen($html)==0) 630 return ""; 631 632 // Convert encoding to UTF-8 633 $html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'); 634 635 // Throw loadHTML() parsing errors 636 $err_mode = libxml_use_internal_errors(false); 637 638 try { 639 $dom = new \DOMDocument(); 640 641 if ($dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NOBLANKS | LIBXML_NOWARNING | LIBXML_NOERROR) === false) 642 return ""; 643 644 $banned_elements = ['script', 'iframe', 'embed']; 645 $remove_elements = []; 646 647 $elements = $dom->getElementsByTagName('*'); 648 649 if (is_object($elements) && $elements->length>0) { 650 foreach($elements as $e) { 651 if (in_array($e->nodeName, $banned_elements)) { 652 $remove_elements[] = $e; 653 continue; 654 } 655 656 if (!$e->hasAttributes()) 657 continue; 658 659 // remove on* HTML event attributes 660 foreach ($e->attributes as $attr) { 661 if (substr($attr->nodeName,0,2) == "on") 662 $e->removeAttribute($attr->nodeName); 663 } 664 } 665 666 // Remove banned elements 667 foreach($remove_elements as $e) 668 $e->parentNode->removeChild($e); 669 670 // Return sanitised HTML 671 $html = $dom->saveHTML(); 672 } 673 } catch (Exception $e) { 674 $html = ""; 675 } 676 677 // restore error mode 678 libxml_use_internal_errors($err_mode); 679 680 return is_string($html) ? $html : ""; 681 } 682 683 /** 684 * Changes empty array fields to specified character 685 * 686 * @access public 687 * @param array|object $fields 688 * @param string $char (default: "/") 689 * @return array 690 */ 691 public function reformat_empty_array_fields ($fields, $char = "/") { 692 $out = array(); 693 // loop 694 foreach($fields as $k=>$v) { 695 if(is_array($v)) { 696 $out[$k] = $v; 697 } 698 else { 699 if(is_null($v) || strlen($v)==0) { 700 $out[$k] = $char; 701 } else { 702 $out[$k] = $v; 703 } 704 } 705 } 706 # result 707 return $out; 708 } 709 710 /** 711 * Removes empty array fields 712 * 713 * @access public 714 * @param array $fields 715 * @return array 716 */ 717 public function remove_empty_array_fields ($fields) { 718 // init 719 $out = array(); 720 // loop 721 if(is_array($fields)) { 722 foreach($fields as $k=>$v) { 723 if(is_null($v) || strlen($v)==0) { 724 } 725 else { 726 $out[$k] = $v; 727 } 728 } 729 } 730 # result 731 return $out; 732 } 733 734 /** 735 * Trim whitespace form array objects 736 * 737 * @method trim_array_objects 738 * @param string|array $fields 739 * @return string|array 740 */ 741 public function trim_array_objects ($fields) { 742 if(is_array($fields)) { 743 // init 744 $out = array(); 745 // loop 746 foreach($fields as $k=>$v) { 747 $out[$k] = trim($v); 748 } 749 } 750 else { 751 $out = trim($fields); 752 } 753 # result 754 return $out; 755 } 756 757 /** 758 * Strip XSS on value print 759 * 760 * @method strip_xss 761 * 762 * @param string $input 763 * 764 * @return string 765 */ 766 public function strip_xss ($input) { 767 return htmlspecialchars($input, ENT_QUOTES, 'UTF-8'); 768 } 769 770 /** 771 * Detect the encoding used for a string and convert to UTF-8 772 * 773 * @method convert_encoding_to_UTF8 774 * @param string $string 775 * @return string 776 */ 777 public function convert_encoding_to_UTF8($string) { 778 //convert encoding if necessary 779 return mb_convert_encoding($string, 'UTF-8', mb_detect_encoding($string, 'ASCII, UTF-8, ISO-8859-1, auto', true)); 780 } 781 782 /** 783 * Function to verify checkbox if 0 length 784 * 785 * @access public 786 * @param mixed $field 787 * @return int|mixed 788 */ 789 public function verify_checkbox ($field) { 790 return (!isset($field) || strlen($field)==0) ? 0 : escape_input($field); 791 } 792 793 /** 794 * identify ip address type - ipv4 or ipv6 795 * 796 * @access public 797 * @param mixed $address 798 * @return mixed IP version 799 */ 800 public function identify_address ($address) { 801 # dotted representation 802 if (strpos($address, ':') !== false) return 'IPv6'; 803 if (strpos($address, '.') !== false) return 'IPv4'; 804 # numeric representation 805 if (is_numeric($address)) { 806 if($address <= 4294967295) return 'IPv4'; // 4294967295 = '255.255.255.255' 807 return 'IPv6'; 808 } else { 809 # decimal representation 810 if(strlen($address) < 12) return 'IPv4'; 811 return 'IPv6'; 812 } 813 } 814 815 /** 816 * Alias of identify_address_format function 817 * 818 * @access public 819 * @param mixed $address 820 * @return mixed 821 */ 822 public function get_ip_version ($address) { 823 return $this->identify_address ($address); 824 } 825 826 /** 827 * Transforms array to log format 828 * 829 * @access public 830 * @param mixed $logs 831 * @param bool $changelog 832 * @return mixed 833 */ 834 public function array_to_log ($logs, $changelog = false) { 835 $result = ""; 836 837 if(!is_array($logs)) 838 return $result; 839 840 foreach($logs as $key=>$req) { 841 # ignore __ and PHPSESSID 842 if( substr($key,0,2)=='__' || substr($key,0,9)=='PHPSESSID' || substr($key,0,4)=='pass' || $key=='plainpass' ) 843 continue; 844 845 // NOTE The colon character ":" is reserved as it used in array_to_log for implode/explode. 846 // Replace colon (U+003A) with alternative characters. 847 // Using JSON encode/decode would be more appropiate but we need to maintain backwards compatibility with historical changelog/logs data in the database. 848 if ($req == "mac") 849 $req = strtr($req, ':', '-'); # Mac-addresses, replace Colon U+003A with hyphen U+002D 850 851 if (strpos($req, ':')!==false) 852 $req = strtr($req, ':', '.'); # Default, replace Colon U+003A with Full Stop U+002E. 853 854 $result .= ($changelog===true) ? "[$key]: $req<br>" : " ". $key . ": " . $req . "<br>"; 855 } 856 return $result; 857 } 858 859 /** 860 * Transforms seconds to hms 861 * 862 * @access public 863 * @param mixed $sec 864 * @param bool $padHours (default: false) 865 * @return mixed 866 */ 867 public function sec2hms($sec, $padHours = false) { 868 // holds formatted string 869 $hms = ""; 870 871 // get the number of hours 872 $hours = intval(intval($sec) / 3600); 873 874 // add to $hms, with a leading 0 if asked for 875 $hms .= ($padHours) 876 ? str_pad($hours, 2, "0", STR_PAD_LEFT). ':' 877 : $hours. ':'; 878 879 // get the seconds 880 $minutes = intval(($sec / 60) % 60); 881 882 // then add to $hms (with a leading 0 if needed) 883 $hms .= str_pad($minutes, 2, "0", STR_PAD_LEFT). ':'; 884 885 // seconds 886 $seconds = intval($sec % 60); 887 888 // add to $hms, again with a leading 0 if needed 889 $hms .= str_pad($seconds, 2, "0", STR_PAD_LEFT); 890 891 // return hms 892 return $hms; 893 } 894 895 /** 896 * Shortens text to max chars 897 * 898 * @access public 899 * @param mixed $text 900 * @param int $chars (default: 25) 901 * @return mixed 902 */ 903 public function shorten_text($text, $chars = 25) { 904 // minimum length = 8 905 if ($chars < 8) $chars = 8; 906 // count input text size 907 $origLen = mb_strlen($text); 908 // cut unwanted chars 909 if ($origLen > $chars) { 910 $text = mb_substr($text, 0, $chars-3) . '...'; 911 } 912 return $text; 913 } 914 915 /** 916 * Reformats MAC address to requested format 917 * 918 * @access public 919 * @param mixed $mac 920 * @param string $format (default: 1) 921 * 1 : 00:66:23:33:55:66 922 * 2 : 00-66-23-33-55-66 923 * 3 : 0066.2333.5566 924 * 4 : 006623335566 925 * @return mixed 926 */ 927 public function reformat_mac_address ($mac, $format = 1) { 928 // strip al tags first 929 $mac = strtolower(str_replace(array(":",".","-"), "", $mac)); 930 // format 4 931 if ($format==4) { 932 return $mac; 933 } 934 // format 3 935 if ($format==3) { 936 $mac = str_split($mac, 4); 937 $mac = implode(".", $mac); 938 } 939 // format 2 940 elseif ($format==2) { 941 $mac = str_split($mac, 2); 942 $mac = implode("-", $mac); 943 } 944 // format 1 945 else { 946 $mac = str_split($mac, 2); 947 $mac = implode(":", $mac); 948 } 949 // return 950 return $mac; 951 } 952 953 /** 954 * Returns true if site is accessed with https 955 * 956 * @access public 957 * @return bool 958 */ 959 public function isHttps() { 960 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') { 961 return true; 962 } 963 if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') { 964 return true; 965 } 966 if (!empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') { 967 return true; 968 } 969 return false; 970 } 971 972 /** 973 * Create URL for base 974 * 975 * @access public 976 * @return mixed 977 */ 978 public function createURL () { 979 // SSL on standard port 980 if(($_SERVER['HTTPS'] == 'on') || ($_SERVER['SERVER_PORT'] == 443)) { 981 $url = "https://".$_SERVER['HTTP_HOST']; 982 } 983 // reverse proxy doing SSL offloading 984 elseif(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') { 985 if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) { 986 $url = "https://".$_SERVER['HTTP_X_FORWARDED_HOST']; 987 } 988 else { 989 $url = "https://".$_SERVER['HTTP_HOST']; 990 } 991 } 992 elseif(isset($_SERVER['HTTP_X_SECURE_REQUEST']) && $_SERVER['HTTP_X_SECURE_REQUEST'] == 'true') { 993 $url = "https://".$_SERVER['SERVER_NAME']; 994 } 995 // custom port 996 elseif($_SERVER['SERVER_PORT']!="80" && (isset($_SERVER['HTTP_X_FORWARDED_PORT']) && $_SERVER['HTTP_X_FORWARDED_PORT']!="80")) { 997 $url = "http://".$_SERVER['SERVER_NAME'].":".$_SERVER['SERVER_PORT']; 998 } 999 // normal http 1000 else { 1001 $url = "http://".$_SERVER['HTTP_HOST']; 1002 } 1003 1004 //result 1005 return $url; 1006 } 1007 1008 /** 1009 * Creates links from text fields if link is present 1010 * 1011 * source: https://css-tricks.com/snippets/php/find-urls-in-text-make-links/ 1012 * 1013 * @access public 1014 * @param mixed $field_type 1015 * @param mixed $text 1016 * @return mixed 1017 */ 1018 public function create_links ($text, $field_type = "varchar") { 1019 // create links only for varchar fields 1020 if (strpos($field_type, "varchar")!==false) { 1021 // regular expression 1022 $reg_exUrl = "#((http|https|ftp|ftps|telnet|ssh)://\S+[^\s.,>)\];'\"!?])#"; 1023 1024 // Check if there is a url in the text, make the urls hyper links 1025 $text = preg_replace($reg_exUrl, "<a href='$0' target='_blank'>$0</a>", $text); 1026 } 1027 // return text 1028 return $text; 1029 } 1030 1031 /** 1032 * Sets valid actions 1033 * 1034 * @access private 1035 * @return string[] 1036 */ 1037 private function get_valid_actions () { 1038 return array( 1039 "add", 1040 "all-add", 1041 "edit", 1042 "all-edit", 1043 "delete", 1044 "truncate", 1045 "split", 1046 "resize", 1047 "move", 1048 "remove", 1049 "assign" 1050 ); 1051 } 1052 1053 /** 1054 * Validate posted action on scripts 1055 * 1056 * @access public 1057 * @param mixed $action 1058 * @param bool $popup 1059 * @return mixed|bool 1060 */ 1061 public function validate_action ($action, $popup = false) { 1062 # get valid actions 1063 $valid_actions = $this->get_valid_actions (); 1064 # check 1065 in_array($action, $valid_actions) ?: $this->Result->show("danger", _("Invalid action!"), true, $popup); 1066 } 1067 1068 /** 1069 * Validates email address. 1070 * 1071 * @access public 1072 * @param mixed $email 1073 * @return bool 1074 */ 1075 public function validate_email($email) { 1076 return filter_var($email, FILTER_VALIDATE_EMAIL); 1077 } 1078 1079 /** 1080 * Validate hostname 1081 * 1082 * @access public 1083 * @param mixed $hostname 1084 * @param bool $permit_root_domain 1085 * @return bool|mixed 1086 */ 1087 public function validate_hostname($hostname, $permit_root_domain=true) { 1088 // first validate hostname 1089 $valid = (preg_match("/^([a-z_\d](-*[a-z_\d])*)(\.([a-z_\d](-*[a-z_\d])*))*$/i", $hostname) //valid chars check 1090 && preg_match("/^.{1,253}$/", $hostname) //overall length check 1091 && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $hostname) ); //length of each label 1092 // if it fails return immediately 1093 if (!$valid) { 1094 return $valid; 1095 } 1096 // than validate root_domain if requested 1097 elseif ($permit_root_domain) { 1098 return $valid; 1099 } 1100 else { 1101 if(strpos($hostname, ".")!==false) { return $valid; } 1102 else { return false; } 1103 } 1104 } 1105 1106 /** 1107 * Validates IP address 1108 * 1109 * @access public 1110 * @param mixed $ip 1111 * @return bool 1112 */ 1113 public function validate_ip ($ip) { 1114 if(filter_var($ip, FILTER_VALIDATE_IP)===false) { return false; } 1115 else { return true; } 1116 } 1117 1118 /** 1119 * Validates MAC address 1120 * 1121 * @access public 1122 * @param mixed $mac 1123 * @return bool 1124 */ 1125 public function validate_mac ($mac) { 1126 // first put it to common format (1) 1127 $mac = $this->reformat_mac_address ($mac); 1128 // we permit empty 1129 if (strlen($mac)==0) { return true; } 1130 elseif (preg_match('/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/', $mac) != 1) { return false; } 1131 else { return true; } 1132 } 1133 1134 /** 1135 * Validates json from provided string. 1136 * 1137 * @access public 1138 * @param mixed $string 1139 * @return mixed 1140 */ 1141 public function validate_json_string($string) { 1142 // try to decode 1143 json_decode($string); 1144 // check for error 1145 $parse_result = json_last_error_msg(); 1146 // save possible error 1147 if($parse_result!=="No error") { 1148 $this->json_error = $parse_result; 1149 } 1150 // return true / false 1151 return (json_last_error() == JSON_ERROR_NONE); 1152 } 1153 1154 /** 1155 * Transforms ipv6 to nt 1156 * 1157 * @access public 1158 * @param mixed $ipv6 1159 * @return mixed 1160 */ 1161 public function ip2long6 ($ipv6) { 1162 if($ipv6 == ".255.255.255") { 1163 return false; 1164 } 1165 $ip_n = inet_pton($ipv6); 1166 $bits = 15; // 16 x 8 bit = 128bit 1167 $ipv6long = ""; 1168 1169 while ($bits >= 0) 1170 { 1171 $bin = sprintf("%08b",(ord($ip_n[$bits]))); 1172 $ipv6long = $bin.$ipv6long; 1173 $bits--; 1174 } 1175 return gmp_strval(gmp_init($ipv6long,2),10); 1176 } 1177 1178 /** 1179 * Transforms int to ipv4 1180 * 1181 * @access public 1182 * @param mixed $ipv4long 1183 * @return mixed 1184 */ 1185 public function long2ip4($ipv4long) { 1186 if (PHP_INT_SIZE==4) { 1187 // As of php7.1 long2ip() no longer accepts strings. 1188 // Convert unsigned int IPv4 to signed integer. 1189 $ipv4long = (int) ($ipv4long + 0); 1190 } 1191 return long2ip($ipv4long); 1192 } 1193 1194 /** 1195 * Transforms int to ipv6 1196 * 1197 * @access public 1198 * @param mixed $ipv6long 1199 * @return mixed 1200 */ 1201 public function long2ip6($ipv6long) { 1202 $hex = sprintf('%032s', gmp_strval(gmp_init($ipv6long, 10), 16)); 1203 $ipv6 = implode(':', str_split($hex, 4)); 1204 // compress result 1205 return inet_ntop(inet_pton($ipv6)); 1206 } 1207 1208 /** 1209 * Identifies IP address format 1210 * 1211 * 0 = decimal 1212 * 1 = dotted 1213 * 1214 * @access public 1215 * @param mixed $address 1216 * @return mixed decimal or dotted 1217 */ 1218 public function identify_address_format ($address) { 1219 return is_numeric($address) ? "decimal" : "dotted"; 1220 } 1221 1222 /** 1223 * Transforms IP address to required format 1224 * 1225 * format can be decimal (1678323323) or dotted (10.10.0.0) 1226 * 1227 * @access public 1228 * @param mixed $address 1229 * @param string $format (default: "dotted") 1230 * @return mixed requested format 1231 */ 1232 public function transform_address ($address, $format = "dotted") { 1233 # no change 1234 if($this->identify_address_format ($address) == $format) { return $address; } 1235 else { 1236 if($this->identify_address_format ($address) == "dotted") { return $this->transform_to_decimal ($address); } 1237 else { return $this->transform_to_dotted ($address); } 1238 } 1239 } 1240 1241 /** 1242 * Transform IP address from decimal to dotted (167903488 -> 10.2.1.0) 1243 * 1244 * @access public 1245 * @param mixed $address 1246 * @return mixed dotted format 1247 */ 1248 public function transform_to_dotted ($address) { 1249 if ($this->identify_address ($address) == "IPv4" ) { return($this->long2ip4($address)); } 1250 else { return($this->long2ip6($address)); } 1251 } 1252 1253 /** 1254 * Transform IP address from dotted to decimal (10.2.1.0 -> 167903488) 1255 * 1256 * @access public 1257 * @param mixed $address 1258 * @return int IP address 1259 */ 1260 public function transform_to_decimal ($address) { 1261 if ($this->identify_address ($address) == "IPv4" ) { return( sprintf("%u", ip2long($address)) ); } 1262 else { return($this->ip2long6($address)); } 1263 } 1264 1265 /** 1266 * Returns text representation of json errors 1267 * 1268 * @access public 1269 * @param mixed $error_int 1270 * @return mixed 1271 */ 1272 public function json_error_decode ($error_int) { 1273 // init 1274 $error = array(); 1275 // error definitions 1276 $error[0] = "JSON_ERROR_NONE"; 1277 $error[1] = "JSON_ERROR_DEPTH"; 1278 $error[2] = "JSON_ERROR_STATE_MISMATCH"; 1279 $error[3] = "JSON_ERROR_CTRL_CHAR"; 1280 $error[4] = "JSON_ERROR_SYNTAX"; 1281 $error[5] = "JSON_ERROR_UTF8"; 1282 $error[6] = "JSON_ERROR_RECURSION"; 1283 $error[7] = "JSON_ERROR_INF_OR_NAN"; 1284 $error[8] = "JSON_ERROR_UNSUPPORTED_TYPE"; 1285 $error[9] = "JSON_ERROR_INVALID_PROPERTY_NAME"; 1286 $error[10] = "JSON_ERROR_UTF16"; 1287 // return def 1288 if (isset($error[$error_int])) { return $error[$error_int]; } 1289 else { return "JSON_ERROR_UNKNOWN"; } 1290 } 1291 1292 /** 1293 * Download URL via CURL 1294 * @param string $url 1295 * @param array|boolean $headers (default:false) 1296 * @param integer $timeout (default:30) 1297 */ 1298 public function curl_fetch_url($url, $headers=false, $timeout=30) { 1299 $result = ['result'=>false, 'result_code'=>503, 'error_msg'=>'']; 1300 1301 try { 1302 $curl = curl_init(); 1303 curl_setopt($curl, CURLOPT_URL, $url); 1304 curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); 1305 curl_setopt($curl, CURLOPT_MAXREDIRS, 4); 1306 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 1307 curl_setopt($curl, CURLOPT_FAILONERROR, true); 1308 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true); 1309 curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $timeout); 1310 if (is_array($headers)) 1311 curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); 1312 1313 // configure proxy settings 1314 if (Config::get('proxy_enabled') == true) { 1315 curl_setopt($curl, CURLOPT_PROXY, Config::get('proxy_server')); 1316 curl_setopt($curl, CURLOPT_PROXYPORT, Config::get('proxy_port')); 1317 if (Config::get('proxy_use_auth') == true) { 1318 curl_setopt($curl, CURLOPT_PROXYUSERPWD, Config::get('proxy_user').':'.Config::get('proxy_pass')); 1319 } 1320 } 1321 1322 $result['result'] = curl_exec($curl); 1323 $result['result_code'] = curl_getinfo($curl, CURLINFO_HTTP_CODE); 1324 $result['error_msg'] = curl_error($curl); 1325 1326 // close 1327 curl_close ($curl); 1328 1329 } catch (Exception $e) { 1330 } 1331 1332 return $result; 1333 } 1334 1335 /** 1336 * Fetches latlng from googlemaps by provided address 1337 * 1338 * @access public 1339 * @param mixed $address 1340 * @return array 1341 */ 1342 public function get_latlng_from_address ($address) { 1343 $results = array('lat' => null, 'lng' => null, 'error' => null); 1344 1345 // get geocode API key 1346 $gmaps_api_geocode_key = Config::get('gmaps_api_geocode_key'); 1347 1348 if(empty($gmaps_api_geocode_key)) { 1349 $results['info'] = _("Geocode API key not set"); 1350 return $results; 1351 } 1352 1353 # Geocode address 1354 $curl = $this->curl_fetch_url('https://maps.google.com/maps/api/geocode/json?address='.rawurlencode($address).'&sensor=false&key='.rawurlencode($gmaps_api_geocode_key), ["Accept: application/json"]); 1355 1356 if ($curl['result'] === false) { 1357 $results['error'] = _("Geocode lookup failed. Check Internet connectivity."); 1358 return $results; 1359 } 1360 1361 $output= json_decode($curl['result']); 1362 1363 if (isset($output->results[0]->geometry->location->lat)) 1364 $results['lat'] = str_replace(",", ".", $output->results[0]->geometry->location->lat); 1365 1366 if (isset($output->results[0]->geometry->location->lng)) 1367 $results['lng'] = str_replace(",", ".", $output->results[0]->geometry->location->lng); 1368 1369 if (isset($output->error_message)) 1370 $results['error'] = $output->error_message; 1371 1372 return $results; 1373 } 1374 1375 /** 1376 * Updates location to latlng from address 1377 * 1378 * @access public 1379 * @param mixed $id 1380 * @param mixed $lat 1381 * @param mixed $lng 1382 * @return bool 1383 */ 1384 public function update_latlng ($id, $lat, $lng) { 1385 # execute 1386 try { $this->Database->updateObject("locations", array("id"=>$id, "lat"=>$lat, "long"=>$lng), "id"); } 1387 catch (Exception $e) { 1388 return false; 1389 } 1390 return true; 1391 } 1392 1393 /** 1394 * Creates form input field for custom fields. 1395 * 1396 * @access public 1397 * @param mixed $field 1398 * @param mixed $object 1399 * @param string $action 1400 * @param mixed $timepicker_index 1401 * @param bool $disabled 1402 * @param string $set_delimiter 1403 * @return array 1404 */ 1405 public function create_custom_field_input ($field, $object, $action, $timepicker_index, $disabled = false, $set_delimiter = "") { 1406 # make sure it is array 1407 $field = (array) $field; 1408 $object = (object) $object; 1409 1410 // disabled 1411 $disabled_text = $disabled ? "readonly" : ""; 1412 // replace spaces with | 1413 $field['nameNew'] = str_replace(" ", "___", $field['name']); 1414 // required 1415 $required = $field['Null']=="NO" ? "*" : ""; 1416 // set default value if adding new object 1417 if ($action=="add") { $object->{$field['name']} = $field['Default']; } 1418 1419 //set, enum 1420 if(substr($field['type'], 0,3) == "set" || substr($field['type'], 0,4) == "enum") { 1421 $html = $this->create_custom_field_input_set_enum ($field, $object, $disabled_text, $set_delimiter); 1422 } 1423 //date and time picker 1424 elseif($field['type'] == "date" || $field['type'] == "datetime") { 1425 $res = $this->create_custom_field_input_date ($field, $object, $timepicker_index, $disabled_text); 1426 $timepicker_index = $res['timepicker_index']; 1427 $html = $res ['html']; 1428 } 1429 //boolean 1430 elseif($field['type'] == "tinyint(1)") { 1431 $html = $this->create_custom_field_input_boolean ($field, $object, $disabled_text); 1432 } 1433 //text 1434 elseif($field['type'] == "text") { 1435 $html = $this->create_custom_field_input_textarea ($field, $object, $disabled_text); 1436 } 1437 //default - input field 1438 else { 1439 $html = $this->create_custom_field_input_input ($field, $object, $disabled_text); 1440 } 1441 1442 # result 1443 return array( 1444 "required" => $required, 1445 "field" => implode("\n", $html), 1446 "timepicker_index" => $timepicker_index 1447 ); 1448 } 1449 1450 /** 1451 * Creates form input field for set and enum values 1452 * 1453 * @access public 1454 * @param mixed $field 1455 * @param mixed $object 1456 * @param string $disabled_text 1457 * @param string $set_delimiter 1458 * @return array 1459 */ 1460 public function create_custom_field_input_set_enum ($field, $object, $disabled_text, $set_delimiter = "") { 1461 $html = array(); 1462 //parse values 1463 $field['type'] = trim(substr($field['type'],0,-1)); 1464 $tmp = substr($field['type'], 0,3)=="set" ? explode(",", str_replace(array("set(", "'"), "", $field['type'])) : explode(",", str_replace(array("enum(", "'"), "", $field['type'])); 1465 //null 1466 if($field['Null']!="NO") { array_unshift($tmp, ""); } 1467 1468 $html[] = "<select name='$field[nameNew]' class='form-control input-sm input-w-auto' rel='tooltip' data-placement='right' title='$field[Comment]' $disabled_text>"; 1469 foreach($tmp as $v) { 1470 // set selected 1471 $selected = $v==$object->{$field['name']} ? "selected='selected'" : ""; 1472 // parse delimiter 1473 if(strlen($set_delimiter)==0) { 1474 // save 1475 $html[] = "<option value='$v' $selected>$v</option>"; 1476 } 1477 else { 1478 // explode by delimiter 1479 $tmp2 = explode ($set_delimiter, $v); 1480 // reset selected 1481 $selected = $tmp2[0]==$object->{$field['name']} ? "selected='selected'" : ""; 1482 // save 1483 $html[] = "<option value='$tmp2[0]' $selected>$tmp2[1]</option>"; 1484 } 1485 1486 } 1487 $html[] = "</select>"; 1488 1489 // result 1490 return $html; 1491 } 1492 1493 /** 1494 * Creates form input field for date fields. 1495 * 1496 * @access public 1497 * @param mixed $field 1498 * @param mixed $object 1499 * @param mixed $timepicker_index 1500 * @param string $disabled_text 1501 * @return array 1502 */ 1503 public function create_custom_field_input_date ($field, $object, $timepicker_index, $disabled_text) { 1504 $html = array (); 1505 // just for first 1506 if($timepicker_index==0) { 1507 $html[] = '<link rel="stylesheet" type="text/css" href="css/bootstrap/bootstrap-datetimepicker.min.css?v='.SCRIPT_PREFIX.'">'; 1508 $html[] = '<script src="js/bootstrap-datetimepicker.min.js?v='.SCRIPT_PREFIX.'"></script>'; 1509 $html[] = '<script>'; 1510 $html[] = '$(document).ready(function() {'; 1511 //date only 1512 $html[] = ' $(".datepicker").datetimepicker( {pickDate: true, pickTime: false, pickSeconds: false });'; 1513 //date + time 1514 $html[] = ' $(".datetimepicker").datetimepicker( { pickDate: true, pickTime: true } );'; 1515 $html[] = '})'; 1516 $html[] = '</script>'; 1517 } 1518 $timepicker_index++; 1519 1520 //set size 1521 if($field['type'] == "date") { $size = 10; $class='datepicker'; $format = "yyyy-MM-dd"; } 1522 else { $size = 19; $class='datetimepicker'; $format = "yyyy-MM-dd"; } 1523 1524 //field 1525 if(!isset($object->{$field['name']})) { $html[] = ' <input type="text" class="'.$class.' form-control input-sm input-w-auto" data-format="'.$format.'" name="'. $field['nameNew'] .'" maxlength="'.$size.'" rel="tooltip" data-placement="right" title="'.$field['Comment'].'" '.$disabled_text.'>'. "\n"; } 1526 else { $html[] = ' <input type="text" class="'.$class.' form-control input-sm input-w-auto" data-format="'.$format.'" name="'. $field['nameNew'] .'" maxlength="'.$size.'" value="'. $this->strip_xss($object->{$field['name']}). '" rel="tooltip" data-placement="right" title="'.$field['Comment'].'" '.$disabled_text.'>'. "\n"; } 1527 1528 // result 1529 return array ( 1530 "html" => $html, 1531 "timepicker_index" => $timepicker_index 1532 ); 1533 } 1534 1535 /** 1536 * Creates form input field for boolean fields. 1537 * 1538 * @access public 1539 * @param mixed $field 1540 * @param mixed $object 1541 * @param string $disabled_text 1542 * @return array 1543 */ 1544 public function create_custom_field_input_boolean ($field, $object, $disabled_text) { 1545 $html = array (); 1546 $html[] = "<select name='$field[nameNew]' class='form-control input-sm input-w-auto' rel='tooltip' data-placement='right' title='$field[Comment]' $disabled_text>"; 1547 $tmp = array(0=>"No",1=>"Yes"); 1548 //null 1549 if($field['Null']!="NO") { $tmp[2] = ""; } 1550 1551 foreach($tmp as $k=>$v) { 1552 if(strlen($object->{$field['name']})==0 && $k==2) { $html[] = "<option value='$k' selected='selected'>"._($v)."</option>"; } 1553 elseif($k==$object->{$field['name']}) { $html[] = "<option value='$k' selected='selected'>"._($v)."</option>"; } 1554 else { $html[] = "<option value='$k'>"._($v)."</option>"; } 1555 } 1556 $html[] = "</select>"; 1557 // result 1558 return $html; 1559 } 1560 1561 /** 1562 * Creates form input field for text fields. 1563 * 1564 * @access public 1565 * @param mixed $field 1566 * @param mixed $object 1567 * @param string $disabled_text 1568 * @return array 1569 */ 1570 public function create_custom_field_input_textarea ($field, $object, $disabled_text) { 1571 $html = array (); 1572 $html[] = ' <textarea class="form-control input-sm" name="'. $field['nameNew'] .'" placeholder="'. $this->print_custom_field_name ($field['name']) .'" rowspan=3 rel="tooltip" data-placement="right" title="'.$field['Comment'].'" '.$disabled_text.'>'. $object->{$field['name']}. '</textarea>'. "\n"; 1573 // result 1574 return $html; 1575 } 1576 1577 /** 1578 * Creates form input field for date fields. 1579 * 1580 * @access public 1581 * @param mixed $field 1582 * @param mixed $object 1583 * @param string $disabled_text 1584 * @return array 1585 */ 1586 public function create_custom_field_input_input ($field, $object, $disabled_text) { 1587 $html = array (); 1588 // max length 1589 $maxlength = 100; 1590 if(strpos($field['type'],"varchar")!==false) { 1591 $maxlength = str_replace(array("varchar","(",")"),"", $field['type']); 1592 } 1593 if(strpos($field['type'],"int")!==false) { 1594 $maxlength = str_replace(array("int","(",")"),"", $field['type']); 1595 } 1596 // print 1597 $html[] = ' <input type="text" class="ip_addr form-control input-sm" name="'. $field['nameNew'] .'" placeholder="'. $this->print_custom_field_name ($field['name']) .'" value="'. $this->strip_xss($object->{$field['name']}). '" size="30" rel="tooltip" data-placement="right" maxlength="'.$maxlength.'" title="'.$field['Comment'].'" '.$disabled_text.'>'. "\n"; 1598 // result 1599 return $html; 1600 } 1601 1602 /** 1603 * Prints custom field 1604 * 1605 * @method print_custom_field 1606 * 1607 * @param string $type 1608 * @param string $value 1609 * 1610 * @return void 1611 */ 1612 public function print_custom_field ($type, $value) { 1613 // escape 1614 $value = str_replace("'", "'", $value); 1615 // create links 1616 $value = $this->create_links ($value, $type); 1617 1618 //booleans 1619 if($type=="tinyint(1)") { 1620 if($value == "1") { print _("Yes"); } 1621 elseif(strlen($value)==0) { print "/"; } 1622 else { print _("No"); } 1623 } 1624 //text 1625 elseif($type=="text") { 1626 if(strlen($value)>0) { print "<i class='fa fa-gray fa-comment' rel='tooltip' data-container='body' data-html='true' title='".str_replace("\n", "<br>", $value)."'>"; } 1627 else { print ""; } 1628 } 1629 else { 1630 print $value; 1631 } 1632 } 1633 1634 /** 1635 * Print custom field name, strip out custom_ prefix 1636 * 1637 * @method print_custom_field_name 1638 * 1639 * @param string $name 1640 * 1641 * @return string 1642 */ 1643 public function print_custom_field_name ($name, $return = true) { 1644 return strpos($name, "custom_")===0 ? substr($name, 7) : $name; 1645 } 1646 1647 /** 1648 * Creates image link to rack. 1649 * 1650 * @method create_rack_link 1651 * 1652 * @param bool|int $rackId 1653 * @param bool|int $deviceId 1654 * @param bool $is_back 1655 * 1656 * @return [type] 1657 */ 1658 public function create_rack_link ($rackId = false, $deviceId = false, $is_back = false) { 1659 if($rackId===false) { 1660 return false; 1661 } 1662 else { 1663 //device ? 1664 if ($deviceId!==false) { 1665 return $this->createURL ().BASE."app/tools/racks/draw_rack.php?rackId=$rackId&deviceId=$deviceId&is_back=$is_back"; 1666 } 1667 else { 1668 return $this->createURL ().BASE."app/tools/racks/draw_rack.php?rackId=$rackId&is_back=$is_back"; 1669 } 1670 } 1671 } 1672 1673 /** 1674 * Get MAC address vendor details 1675 * 1676 * https://www.macvendorlookup.com/vendormacs-xml-download 1677 * 1678 * @method get_mac_address_vendor 1679 * @param mixed $mac 1680 * @return string 1681 */ 1682 public function get_mac_address_vendor_details ($mac) { 1683 // set default arrays 1684 $matches = array(); 1685 // validate mac 1686 if(strlen($mac)<4) { return ""; } 1687 if(!$this->validate_mac ($mac)) { return ""; } 1688 // reformat mac address 1689 $mac = strtoupper($this->reformat_mac_address ($mac, 1)); 1690 $mac_partial = explode(":", $mac); 1691 // get mac XML database 1692 1693 if (is_null($this->mac_address_vendors)) { 1694 //populate mac vendors array 1695 $this->mac_address_vendors = array(); 1696 1697 $data = file_get_contents(dirname(__FILE__)."/../vendormacs.xml"); 1698 1699 if (preg_match_all('/\<VendorMapping\smac_prefix="([0-9a-fA-F]{2})[:-]([0-9a-fA-F]{2})[:-]([0-9a-fA-F]{2})"\svendor_name="(.*)"\/\>/', $data, $matches, PREG_SET_ORDER)) { 1700 if (is_array($matches)) { 1701 foreach ($matches as $match) { 1702 $mac_vendor = strtoupper($match[1] . ':' . $match[2] . ':' . $match[3]); 1703 $this->mac_address_vendors[$mac_vendor] = $match[4]; 1704 } 1705 } 1706 } 1707 } 1708 1709 $mac_vendor = strtoupper($mac_partial[0] . ':' . $mac_partial[1] . ':' . $mac_partial[2]); 1710 1711 if (isset($this->mac_address_vendors[$mac_vendor])) { 1712 return $this->mac_address_vendors[$mac_vendor]; 1713 } else { 1714 return ""; 1715 } 1716 } 1717 1718 /** 1719 * Read user supplied permissions ($_POST) and calculate deltas from old_permissions 1720 * 1721 * @access public 1722 * @param array $post_permissions 1723 * @param array $old_permissions 1724 * @return array 1725 */ 1726 public function get_permission_changes ($post_permissions, $old_permissions) { 1727 $new_permissions = array(); 1728 $removed_permissions = array(); 1729 $changed_permissions = array(); 1730 1731 # set new posted permissions 1732 foreach($post_permissions as $key=>$val) { 1733 if(substr($key, 0,5) == "group") { 1734 if($val != "0") $new_permissions[substr($key,5)] = $val; 1735 } 1736 } 1737 1738 // calculate diff 1739 if(is_array($old_permissions)) { 1740 foreach ($old_permissions as $k1=>$p1) { 1741 // if there is not permisison in new that remove old 1742 // if change than save 1743 if (!array_key_exists($k1, $new_permissions)) { 1744 $removed_permissions[$k1] = 0; 1745 } elseif ($old_permissions[$k1]!==$new_permissions[$k1]) { 1746 $changed_permissions[$k1] = $new_permissions[$k1]; 1747 } 1748 } 1749 } else { 1750 $old_permissions = array(); // fix for adding 1751 } 1752 // add also new groups if available 1753 if(is_array($new_permissions)) { 1754 foreach ($new_permissions as $k1=>$p1) { 1755 if(!array_key_exists($k1, $old_permissions)) { 1756 $changed_permissions[$k1] = $new_permissions[$k1]; 1757 } 1758 } 1759 } 1760 1761 return array($removed_permissions, $changed_permissions, $new_permissions); 1762 } 1763 1764 /** 1765 * Parse subnet permissions to user readable format 1766 * 1767 * @access public 1768 * @param mixed $permissions 1769 * @return string 1770 */ 1771 public function parse_permissions ($permissions) { 1772 switch($permissions) { 1773 case 0: $r = _("No access"); break; 1774 case 1: $r = _("Read"); break; 1775 case 2: $r = _("Write"); break; 1776 case 3: $r = _("Admin"); break; 1777 default: $r = _("error"); 1778 } 1779 return $r; 1780 } 1781 1782 1783 1784 1785 1786 1787 /** 1788 * @breadcrumbs functions 1789 * ------------------------ 1790 */ 1791 1792 /** 1793 * print_breadcrumbs function. 1794 * 1795 * @access public 1796 * @param mixed $Section 1797 * @param mixed $Subnet 1798 * @param mixed $req 1799 * @param mixed $Address (default: null) 1800 * @return void 1801 */ 1802 public function print_breadcrumbs ($Section, $Subnet, $req, $Address=null) { 1803 # subnets 1804 if($req['page'] == "subnets") { $this->print_subnet_breadcrumbs ($Subnet, $req, $Address); } 1805 # folders 1806 elseif($req['page'] == "folder") { $this->print_folder_breadcrumbs ($Section, $Subnet, $req); } 1807 # tools 1808 elseif ($req['page'] == "tools") { $this->print_tools_breadcrumbs ($req); } 1809 } 1810 1811 /** 1812 * Print address breadcrumbs 1813 * 1814 * @access private 1815 * @param mixed $Subnet 1816 * @param mixed $req 1817 * @param mixed $Address 1818 * @return void 1819 */ 1820 private function print_subnet_breadcrumbs ($Subnet, $req, $Address) { 1821 if(isset($req['subnetId'])) { 1822 # get all parents 1823 $parents = $Subnet->fetch_parents_recursive ($req['subnetId']); 1824 1825 print "<ul class='breadcrumb'>"; 1826 # remove root - 0 1827 //array_shift($parents); 1828 1829 # section details 1830 $section = (array) $this->fetch_object ("sections", "id", $req['section']); 1831 1832 # section name 1833 print " <li><a href='".create_link("subnets",$section['id'])."'>$section[name]</a> <span class='divider'></span></li>"; 1834 1835 # all parents 1836 foreach($parents as $parent) { 1837 $subnet = (array) $Subnet->fetch_subnet("id",$parent); 1838 if($subnet['isFolder']==1) { 1839 print " <li><a href='".create_link("folder",$section['id'],$parent)."'><i class='icon-folder-open icon-gray'></i> $subnet[description]</a> <span class='divider'></span></li>"; 1840 } else { 1841 print " <li><a href='".create_link("subnets",$section['id'],$parent)."'>$subnet[description] ($subnet[ip]/$subnet[mask])</a> <span class='divider'></span></li>"; 1842 } 1843 } 1844 # parent subnet 1845 $subnet = (array) $Subnet->fetch_subnet("id",$req['subnetId']); 1846 # ip set 1847 if(isset($req['ipaddrid'])) { 1848 $ip = (array) $Address->fetch_address ("id", $req['ipaddrid']); 1849 print " <li><a href='".create_link("subnets",$section['id'],$subnet['id'])."'>$subnet[description] ($subnet[ip]/$subnet[mask])</a> <span class='divider'></span></li>"; 1850 print " <li class='active'>$ip[ip]</li>"; //IP address 1851 } 1852 else { 1853 print " <li class='active'>$subnet[description] ($subnet[ip]/$subnet[mask])</li>"; //active subnet 1854 1855 } 1856 print "</ul>"; 1857 } 1858 } 1859 1860 /** 1861 * Print folder breadcrumbs 1862 * 1863 * @access private 1864 * @param obj $Section 1865 * @param obj $Subnet 1866 * @param mixed $req 1867 * @return void 1868 */ 1869 private function print_folder_breadcrumbs ($Section, $Subnet, $req) { 1870 if(isset($req['subnetId'])) { 1871 # get all parents 1872 $parents = $Subnet->fetch_parents_recursive ($req['subnetId']); 1873 print "<ul class='breadcrumb'>"; 1874 # remove root - 0 1875 array_shift($parents); 1876 1877 # section details 1878 $section = (array) $Section->fetch_section(null, $req['section']); 1879 1880 # section name 1881 print " <li><a href='".create_link("subnets",$section['id'])."'>$section[name]</a> <span class='divider'></span></li>"; 1882 1883 # all parents 1884 foreach($parents as $parent) { 1885 $parent = (array) $parent; 1886 $subnet = (array) $Subnet->fetch_subnet(null,$parent[0]); 1887 if ($subnet['isFolder']=="1") 1888 print " <li><a href='".create_link("folder",$section['id'],$parent[0])."'><i class='icon-folder-open icon-gray'></i> $subnet[description]</a> <span class='divider'></span></li>"; 1889 else 1890 print " <li><a href='".create_link("subnets",$section['id'],$parent[0])."'><i class='icon-folder-open icon-gray'></i> $subnet[description]</a> <span class='divider'></span></li>"; 1891 } 1892 # parent subnet 1893 $subnet = (array) $Subnet->fetch_subnet(null,$req['subnetId']); 1894 print " <li>$subnet[description]</li>"; # active subnet 1895 print "</ul>"; 1896 } 1897 } 1898 1899 /** 1900 * Prints tools breadcrumbs 1901 * 1902 * @access public 1903 * @param mixed $req 1904 * @return void 1905 */ 1906 private function print_tools_breadcrumbs ($req) { 1907 print "<ul class='breadcrumb'>"; 1908 print " <li><a href='".create_link("tools")."'>"._('Tools')."</a> <span class='divider'></span></li>"; 1909 if(!isset($req['subnetId'])) { 1910 print " <li class='active'>$req[section]</li>"; 1911 } 1912 else { 1913 print " <li class='active'><a href='".create_link("tools", $req['section'])."'>$req[section]</a> <span class='divider'></span></li>"; 1914 1915 # pstn 1916 if ($_GET['section']=="pstn-prefixes") { 1917 # get all parents 1918 $Tools = new Tools ($this->Database); 1919 $parents = $Tools->fetch_prefix_parents_recursive ($req['subnetId']); 1920 # all parents 1921 foreach($parents as $parent) { 1922 $prefix = $this->fetch_object("pstnPrefixes", "id", $parent[0]); 1923 print " <li><a href='".create_link("tools",$req['section'],$parent[0])."'><i class='icon-folder-open icon-gray'></i> $prefix->name</a> <span class='divider'></span></li>"; 1924 } 1925 1926 } 1927 $prefix = $this->fetch_object("pstnPrefixes", "id", $req['subnetId']); 1928 print " <li class='active'>$prefix->name</li>"; 1929 } 1930 print "</ul>"; 1931 } 1932 1933 /** 1934 * Prints site title 1935 * 1936 * @access public 1937 * @param mixed $get 1938 * @return void 1939 */ 1940 public function get_site_title ($get) { 1941 // remove html tags 1942 $get = $this->strip_input_tags ($get); 1943 // init 1944 $title = array (); 1945 $title[] = $this->settings->siteTitle; 1946 1947 // page 1948 if (isset($get['page'])) { 1949 // dashboard 1950 if ($get['page']=="dashboard") { 1951 return $this->settings->siteTitle." Dashboard"; 1952 } 1953 // install, upgrade 1954 elseif ($get['page']=="temp_share" || $get['page']=="request_ip" || $get['page']=="opensearch") { 1955 $title[] = ucwords(escape_input($get['page'])); 1956 } 1957 // sections, subnets 1958 elseif ($get['page']=="subnets" || $get['page']=="folder") { 1959 // subnets 1960 $title[] = _("Subnets"); 1961 1962 // section 1963 if (isset($get['section'])) { 1964 $se = $this->fetch_object ("sections", "id", escape_input($get['section'])); 1965 if($se!==false) { 1966 $title[] = $se->name; 1967 } 1968 } 1969 // subnet 1970 if (isset($get['subnetId'])) { 1971 $sn = $this->fetch_object ("subnets", "id", escape_input($get['subnetId'])); 1972 if($sn!==false) { 1973 if($sn->isFolder) { 1974 $title[] = $sn->description; 1975 } 1976 else { 1977 $sn->description = strlen($sn->description)>0 ? " (".$sn->description.")" : ""; 1978 $title[] = $this->transform_address($sn->subnet, "dotted")."/".$sn->mask.$sn->description; 1979 } 1980 } 1981 } 1982 // ip address 1983 if (isset($get['ipaddrid'])) { 1984 $ip = $this->fetch_object ("ipaddresses", "id", escape_input($get['ipaddrid'])); 1985 if($ip!==false) { 1986 $title[] = $this->transform_address($ip->ip_addr, "dotted"); 1987 } 1988 } 1989 } 1990 // tools, admin 1991 elseif ($get['page']=="tools" || $get['page']=="administration") { 1992 $title[] = ucwords(escape_input($get['page'])); 1993 // subpage 1994 if (isset($get['section'])) { 1995 $title[] = ucwords(escape_input($get['section'])); 1996 } 1997 if (isset($get['subnetId'])) { 1998 // vland domain 1999 if($get['section']=="vlan") { 2000 $se = $this->fetch_object ("vlanDomains", "id", escape_input($get['subnetId'])); 2001 if($se!==false) { 2002 $title[] = $se->name." domain"; 2003 } 2004 } 2005 else { 2006 $title[] = ucwords(escape_input($get['subnetId'])); 2007 } 2008 } 2009 } 2010 else { 2011 $title[] = ucwords(escape_input($get['page'])); 2012 } 2013 } 2014 // return title 2015 return implode(" / ", $title); 2016 } 2017 2018 2019 2020 2021 /** 2022 * Print action wrapper 2023 * 2024 * Provided items can have following items: 2025 * type: link, divider, header 2026 * text: text to print 2027 * href: '' 2028 * class: classes to be added to item 2029 * dataparams: params to be added (e.g. data-deviceid='0') 2030 * icon: name for icon 2031 * visible: where it should be visible 2032 * 2033 * 2034 * @method print_actions 2035 * @param string $type 2036 * @param array $items [array of items] 2037 * @param bool $left_align 2038 * @param bool $print_text 2039 * @return [type] 2040 */ 2041 public function print_actions ($compress = "1", $items = [], $left_align = false, $print_text = false) { 2042 if (sizeof($items)>0) { 2043 return $compress=="1" ? $this->print_actions_dropdown($items, $left_align, $print_text) : $this->print_actions_buttons ($items); 2044 } 2045 else { 2046 return ""; 2047 } 2048 } 2049 2050 /** 2051 * Prints action dropdown 2052 * 2053 * @method print_actions_buttons 2054 * @param array $items [array of items] 2055 * @param bool $left_align 2056 * @param bool $print_text 2057 * @return string 2058 */ 2059 private function print_actions_dropdown ($items = [], $left_align = false, $print_text = false) { 2060 // init 2061 $html = []; 2062 // alignment 2063 $alignment = $left_align ? "dropdown-menu-left" : "dropdown-menu-right"; 2064 // text 2065 $action_text = $print_text ? " <i class='fa fa-cogs'></i> Actions " : " <i class='fa fa-cogs'></i> "; 2066 2067 $html[] = "<div class='dropdown'>"; 2068 $html[] = " <button class='btn btn-xs btn-default dropdown-toggle ' type='button' id='dropdownMenu' data-toggle='dropdown' aria-haspopup='true' aria-expanded='true' rel='tooltip' title='"._("Actions")."'> "._($action_text)." <span class='caret'></span></button>"; 2069 $html[] = " <ul class='dropdown-menu $alignment' aria-labelledby='dropdownMenu'>"; 2070 2071 // loop items 2072 foreach ($items as $i) { 2073 // visible 2074 if (isset($i['visible'])) { 2075 if ($i['visible']!="dropdown") { 2076 continue; 2077 } 2078 } 2079 // title 2080 if ($i['type']=="header") { 2081 $html[] = " <li class='dropdown-header'>".($i['text'])."</li>"; 2082 2083 } 2084 // separator 2085 elseif ($i['type']=="divider") { 2086 $html[] = " <li role='separator' class='divider'></li>"; 2087 } 2088 // item 2089 else { 2090 $html[] = " <li><a class='$i[class]' href='$i[href]' $i[dataparams]><i class='fa fa-$i[icon]'></i> "._($i['text'])."</a></li>"; 2091 } 2092 } 2093 // remove last divider if present 2094 if (strpos(end($html),"divider")!==false) { 2095 array_pop($html); 2096 } 2097 // end 2098 $html[] = " </ul>"; 2099 $html[] = "</div>"; 2100 // result 2101 return implode("\n", $html); 2102 } 2103 2104 2105 /** 2106 * Prints icons btn-group 2107 * 2108 * @method print_actions_buttons 2109 * @param array $items [array of items] 2110 * @return string 2111 */ 2112 private function print_actions_buttons ($items = []) { 2113 // init 2114 $html = []; 2115 // structure 2116 $html[] = " <div class='btn-group'>"; 2117 // irems 2118 foreach ($items as $i) { 2119 // visible 2120 if (isset($i['visible'])) { 2121 if ($i['visible']!="buttons") { 2122 continue; 2123 } 2124 } 2125 // save only links 2126 if($i['type']=="link") { 2127 $html[] = " <a href='$i[href]' class='btn btn-xs btn-default $i[class]' $i[dataparams] rel='tooltip' title='"._($i['text'])."'><i class='fa fa-$i[icon]'></i></a>"; 2128 } 2129 } 2130 // end 2131 $html[] = " </div>"; 2132 // result 2133 return implode("\n", $html); 2134 } 2135}