PageRenderTime 28ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/zabbix-2.0.1/frontends/php/api/classes/CMap.php

#
PHP | 1052 lines | 749 code | 160 blank | 143 comment | 190 complexity | 93c07db5800d3ccb5ee812ef06b55929 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
  1. <?php
  2. /*
  3. ** Zabbix
  4. ** Copyright (C) 2000-2011 Zabbix SIA
  5. **
  6. ** This program is free software; you can redistribute it and/or modify
  7. ** it under the terms of the GNU General Public License as published by
  8. ** the Free Software Foundation; either version 2 of the License, or
  9. ** (at your option) any later version.
  10. **
  11. ** This program is distributed in the hope that it will be useful,
  12. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ** GNU General Public License for more details.
  15. **
  16. ** You should have received a copy of the GNU General Public License
  17. ** along with this program; if not, write to the Free Software
  18. ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. **/
  20. ?>
  21. <?php
  22. /**
  23. * @package API
  24. */
  25. /**
  26. * Class containing methods for operations with Maps
  27. */
  28. class CMap extends CMapElement {
  29. protected $tableName = 'sysmaps';
  30. protected $tableAlias = 's';
  31. /**
  32. * Get Map data
  33. *
  34. * @param array $options
  35. * @param array $options['nodeids'] Node IDs
  36. * @param array $options['groupids'] HostGroup IDs
  37. * @param array $options['hostids'] Host IDs
  38. * @param boolean $options['monitored_hosts'] only monitored Hosts
  39. * @param boolean $options['templated_hosts'] include templates in result
  40. * @param boolean $options['with_items'] only with items
  41. * @param boolean $options['with_monitored_items'] only with monitored items
  42. * @param boolean $options['with_historical_items'] only with historical items
  43. * @param boolean $options['with_triggers'] only with triggers
  44. * @param boolean $options['with_monitored_triggers'] only with monitored triggers
  45. * @param boolean $options['with_httptests'] only with http tests
  46. * @param boolean $options['with_monitored_httptests'] only with monitored http tests
  47. * @param boolean $options['with_graphs'] only with graphs
  48. * @param boolean $options['editable'] only with read-write permission. Ignored for SuperAdmins
  49. * @param int $options['count'] count Hosts, returned column name is rowscount
  50. * @param string $options['pattern'] search hosts by pattern in host names
  51. * @param int $options['limit'] limit selection
  52. * @param string $options['sortorder']
  53. * @param string $options['sortfield']
  54. * @return array|boolean Host data as array or false if error
  55. */
  56. public function get($options = array()) {
  57. $result = array();
  58. $userType = self::$userData['type'];
  59. // allowed columns for sorting
  60. $sortColumns = array('name', 'width', 'height');
  61. // allowed output options for [ select_* ] params
  62. $subselectsAllowedOutputs = array(API_OUTPUT_REFER, API_OUTPUT_EXTEND);
  63. $sqlParts = array(
  64. 'select' => array('sysmaps' => 's.sysmapid'),
  65. 'from' => array('sysmaps' => 'sysmaps s'),
  66. 'where' => array(),
  67. 'order' => array(),
  68. 'limit' => null
  69. );
  70. $defOptions = array(
  71. 'nodeids' => null,
  72. 'sysmapids' => null,
  73. 'editable' => null,
  74. 'nopermissions' => null,
  75. // filter
  76. 'filter' => null,
  77. 'search' => null,
  78. 'searchByAny' => null,
  79. 'startSearch' => null,
  80. 'excludeSearch' => null,
  81. 'searchWildcardsEnabled' => null,
  82. // output
  83. 'output' => API_OUTPUT_REFER,
  84. 'selectSelements' => null,
  85. 'selectLinks' => null,
  86. 'selectIconMap' => null,
  87. 'countOutput' => null,
  88. 'expandUrls' => null,
  89. 'preservekeys' => null,
  90. 'sortfield' => '',
  91. 'sortorder' => '',
  92. 'limit' => null
  93. );
  94. $options = zbx_array_merge($defOptions, $options);
  95. if (is_array($options['output'])) {
  96. unset($sqlParts['select']['sysmaps']);
  97. $dbTable = DB::getSchema('sysmaps');
  98. $sqlParts['select']['sysmapid'] = 's.sysmapid';
  99. foreach ($options['output'] as $field) {
  100. if (isset($dbTable['fields'][$field])) {
  101. $sqlParts['select'][$field] = 's.'.$field;
  102. }
  103. }
  104. $options['output'] = API_OUTPUT_CUSTOM;
  105. }
  106. // nodeids
  107. $nodeids = !is_null($options['nodeids']) ? $options['nodeids'] : get_current_nodeid();
  108. // sysmapids
  109. if (!is_null($options['sysmapids'])) {
  110. zbx_value2array($options['sysmapids']);
  111. $sqlParts['where']['sysmapid'] = DBcondition('s.sysmapid', $options['sysmapids']);
  112. }
  113. // search
  114. if (!is_null($options['search'])) {
  115. zbx_db_search('sysmaps s', $options, $sqlParts);
  116. }
  117. // filter
  118. if (!is_null($options['filter'])) {
  119. zbx_db_filter('sysmaps s', $options, $sqlParts);
  120. }
  121. // output
  122. if ($options['output'] == API_OUTPUT_EXTEND) {
  123. $sqlParts['select']['sysmaps'] = 's.*';
  124. }
  125. // countOutput
  126. if (!is_null($options['countOutput'])) {
  127. $options['sortfield'] = '';
  128. $sqlParts['select'] = array('count(DISTINCT s.sysmapid) as rowscount');
  129. }
  130. // sorting
  131. zbx_db_sorting($sqlParts, $options, $sortColumns, 's');
  132. // limit
  133. if (zbx_ctype_digit($options['limit']) && $options['limit']) {
  134. $sqlParts['limit'] = $options['limit'];
  135. }
  136. $sysmapids = array();
  137. $sqlParts['select'] = array_unique($sqlParts['select']);
  138. $sqlParts['from'] = array_unique($sqlParts['from']);
  139. $sqlParts['where'] = array_unique($sqlParts['where']);
  140. $sqlParts['order'] = array_unique($sqlParts['order']);
  141. $sqlSelect = '';
  142. $sqlFrom = '';
  143. $sqlWhere = '';
  144. $sqlOrder = '';
  145. if (!empty($sqlParts['select'])) {
  146. $sqlSelect .= implode(',', $sqlParts['select']);
  147. }
  148. if (!empty($sqlParts['from'])) {
  149. $sqlFrom .= implode(',', $sqlParts['from']);
  150. }
  151. if (!empty($sqlParts['where'])) {
  152. $sqlWhere .= ' AND '.implode(' AND ', $sqlParts['where']);
  153. }
  154. if (!empty($sqlParts['order'])) {
  155. $sqlOrder .= ' ORDER BY '.implode(',', $sqlParts['order']);
  156. }
  157. $sqlLimit = $sqlParts['limit'];
  158. $sql = 'SELECT '.zbx_db_distinct($sqlParts).' '.$sqlSelect.
  159. ' FROM '.$sqlFrom.
  160. ' WHERE '.DBin_node('s.sysmapid', $nodeids).
  161. $sqlWhere.
  162. $sqlOrder;
  163. $res = DBselect($sql, $sqlLimit);
  164. while ($sysmap = DBfetch($res)) {
  165. if ($options['countOutput']) {
  166. $result = $sysmap['rowscount'];
  167. }
  168. else {
  169. $sysmapids[$sysmap['sysmapid']] = $sysmap['sysmapid'];
  170. if ($options['output'] == API_OUTPUT_SHORTEN) {
  171. $result[$sysmap['sysmapid']] = array('sysmapid' => $sysmap['sysmapid']);
  172. }
  173. else {
  174. if (!isset($result[$sysmap['sysmapid']])) {
  175. $result[$sysmap['sysmapid']] = array();
  176. }
  177. // originally we intended not to pass those parameters if advanced labels are off, but they might be useful
  178. // leaving this block commented
  179. // if (isset($sysmap['label_format']) && ($sysmap['label_format'] == SYSMAP_LABEL_ADVANCED_OFF)) {
  180. // unset($sysmap['label_string_hostgroup'], $sysmap['label_string_host'], $sysmap['label_string_trigger'], $sysmap['label_string_map'], $sysmap['label_string_image']);
  181. // }
  182. if (!is_null($options['selectSelements']) && !isset($result[$sysmap['sysmapid']]['selements'])) {
  183. $result[$sysmap['sysmapid']]['selements'] = array();
  184. }
  185. if (!is_null($options['selectLinks']) && !isset($result[$sysmap['sysmapid']]['links'])) {
  186. $result[$sysmap['sysmapid']]['links'] = array();
  187. }
  188. if (!is_null($options['selectIconMap']) && !isset($result[$sysmap['sysmapid']]['iconmap'])) {
  189. $result[$sysmap['sysmapid']]['iconmap'] = array();
  190. }
  191. if (!isset($result[$sysmap['sysmapid']]['urls'])) {
  192. $result[$sysmap['sysmapid']]['urls'] = array();
  193. }
  194. $result[$sysmap['sysmapid']] += $sysmap;
  195. }
  196. }
  197. }
  198. if (USER_TYPE_SUPER_ADMIN == $userType || $options['nopermissions']) {
  199. }
  200. else {
  201. if (!empty($result)) {
  202. $linkTriggers = array();
  203. $dbLinkTriggers = DBselect(
  204. 'SELECT slt.triggerid,sl.sysmapid'.
  205. ' FROM sysmaps_link_triggers slt,sysmaps_links sl'.
  206. ' WHERE '.DBcondition('sl.sysmapid', $sysmapids).
  207. ' AND sl.linkid=slt.linkid'
  208. );
  209. while ($linkTrigger = DBfetch($dbLinkTriggers)) {
  210. $linkTriggers[$linkTrigger['sysmapid']] = $linkTrigger['triggerid'];
  211. }
  212. if (!empty($linkTriggers)) {
  213. $trigOptions = array(
  214. 'triggerids' => $linkTriggers,
  215. 'editable' => $options['editable'],
  216. 'output' => API_OUTPUT_SHORTEN,
  217. 'preservekeys' => true
  218. );
  219. $allTriggers = API::Trigger()->get($trigOptions);
  220. foreach ($linkTriggers as $id => $triggerid) {
  221. if (!isset($allTriggers[$triggerid])) {
  222. unset($result[$id], $sysmapids[$id]);
  223. }
  224. }
  225. }
  226. $hostsToCheck = array();
  227. $mapsToCheck = array();
  228. $triggersToCheck = array();
  229. $hostGroupsToCheck = array();
  230. $selements = array();
  231. $dbSelements = DBselect('SELECT se.* FROM sysmaps_elements se WHERE '.DBcondition('se.sysmapid', $sysmapids));
  232. while ($selement = DBfetch($dbSelements)) {
  233. $selements[$selement['selementid']] = $selement;
  234. switch ($selement['elementtype']) {
  235. case SYSMAP_ELEMENT_TYPE_HOST:
  236. $hostsToCheck[$selement['elementid']] = $selement['elementid'];
  237. break;
  238. case SYSMAP_ELEMENT_TYPE_MAP:
  239. $mapsToCheck[$selement['elementid']] = $selement['elementid'];
  240. break;
  241. case SYSMAP_ELEMENT_TYPE_TRIGGER:
  242. $triggersToCheck[$selement['elementid']] = $selement['elementid'];
  243. break;
  244. case SYSMAP_ELEMENT_TYPE_HOST_GROUP:
  245. $hostGroupsToCheck[$selement['elementid']] = $selement['elementid'];
  246. break;
  247. }
  248. }
  249. $nodeids = get_current_nodeid(true);
  250. if (!empty($hostsToCheck)) {
  251. $hostOptions = array(
  252. 'hostids' => $hostsToCheck,
  253. 'nodeids' => $nodeids,
  254. 'editable' => $options['editable'],
  255. 'preservekeys' => true,
  256. 'output' => API_OUTPUT_SHORTEN
  257. );
  258. $allowedHosts = API::Host()->get($hostOptions);
  259. foreach ($hostsToCheck as $elementid) {
  260. if (!isset($allowedHosts[$elementid])) {
  261. foreach ($selements as $selementid => $selement) {
  262. if ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_HOST && bccomp($selement['elementid'], $elementid) == 0) {
  263. unset($result[$selement['sysmapid']], $selements[$selementid]);
  264. }
  265. }
  266. }
  267. }
  268. }
  269. if (!empty($mapsToCheck)) {
  270. $mapOptions = array(
  271. 'sysmapids' => $mapsToCheck,
  272. 'nodeids' => $nodeids,
  273. 'editable' => $options['editable'],
  274. 'preservekeys' => true,
  275. 'output' => API_OUTPUT_SHORTEN
  276. );
  277. $allowedMaps = $this->get($mapOptions);
  278. foreach ($mapsToCheck as $elementid) {
  279. if (!isset($allowedMaps[$elementid])) {
  280. foreach ($selements as $selementid => $selement) {
  281. if ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_MAP && bccomp($selement['elementid'], $elementid) == 0) {
  282. unset($result[$selement['sysmapid']], $selements[$selementid]);
  283. }
  284. }
  285. }
  286. }
  287. }
  288. if (!empty($triggersToCheck)) {
  289. $triggeridOptions = array(
  290. 'triggerids' => $triggersToCheck,
  291. 'nodeids' => $nodeids,
  292. 'editable' => $options['editable'],
  293. 'preservekeys' => true,
  294. 'output' => API_OUTPUT_SHORTEN
  295. );
  296. $allowedTriggers = API::Trigger()->get($triggeridOptions);
  297. foreach ($triggersToCheck as $elementid) {
  298. if (!isset($allowedTriggers[$elementid])) {
  299. foreach ($selements as $selementid => $selement) {
  300. if ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_TRIGGER && bccomp($selement['elementid'], $elementid) == 0) {
  301. unset($result[$selement['sysmapid']], $selements[$selementid]);
  302. }
  303. }
  304. }
  305. }
  306. }
  307. if (!empty($hostGroupsToCheck)) {
  308. $hostgroupOptions = array(
  309. 'groupids' => $hostGroupsToCheck,
  310. 'nodeids' => $nodeids,
  311. 'editable' => $options['editable'],
  312. 'preservekeys' => true,
  313. 'output' => API_OUTPUT_SHORTEN
  314. );
  315. $allowedHostGroups = API::HostGroup()->get($hostgroupOptions);
  316. foreach ($hostGroupsToCheck as $elementid) {
  317. if (!isset($allowedHostGroups[$elementid])) {
  318. foreach ($selements as $selementid => $selement) {
  319. if ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_HOST_GROUP && bccomp($selement['elementid'], $elementid) == 0) {
  320. unset($result[$selement['sysmapid']], $selements[$selementid]);
  321. }
  322. }
  323. }
  324. }
  325. }
  326. }
  327. }
  328. if (!is_null($options['countOutput'])) {
  329. return $result;
  330. }
  331. // adding elements
  332. if (!is_null($options['selectSelements']) && str_in_array($options['selectSelements'], $subselectsAllowedOutputs)) {
  333. $sysmapids = zbx_objectValues($result, 'sysmapid');
  334. $selements = array();
  335. $dbSelements = DBselect(
  336. 'SELECT se.*'.
  337. ' FROM sysmaps_elements se'.
  338. ' WHERE '.DBcondition('se.sysmapid', $sysmapids)
  339. );
  340. while ($selement = DBfetch($dbSelements)) {
  341. $selement['urls'] = array();
  342. $selements[$selement['selementid']] = $selement;
  343. }
  344. if (!is_null($options['expandUrls'])) {
  345. $dbMapUrls = DBselect(
  346. 'SELECT sysmapurlid, sysmapid, name, url, elementtype'.
  347. ' FROM sysmap_url'.
  348. ' WHERE '.DBcondition('sysmapid', $sysmapids)
  349. );
  350. while ($mapUrl = DBfetch($dbMapUrls)) {
  351. foreach ($selements as $snum => $selement) {
  352. if (bccomp($selement['sysmapid'], $mapUrl['sysmapid']) == 0 &&
  353. (
  354. (
  355. $selement['elementtype'] == $mapUrl['elementtype'] &&
  356. $selement['elementsubtype'] == SYSMAP_ELEMENT_SUBTYPE_HOST_GROUP
  357. ) ||
  358. (
  359. $selement['elementsubtype'] == SYSMAP_ELEMENT_SUBTYPE_HOST_GROUP_ELEMENTS &&
  360. $mapUrl['elementtype'] == SYSMAP_ELEMENT_TYPE_HOST
  361. )
  362. )
  363. ) {
  364. $selements[$snum]['urls'][$mapUrl['sysmapurlid']] = $this->expandUrlMacro($mapUrl, $selement);
  365. }
  366. }
  367. }
  368. }
  369. $dbSelementUrls = DBselect(
  370. 'SELECT seu.sysmapelementurlid,seu.selementid,seu.name,seu.url'.
  371. ' FROM sysmap_element_url seu'.
  372. ' WHERE '.DBcondition('seu.selementid', array_keys($selements))
  373. );
  374. while ($selementUrl = DBfetch($dbSelementUrls)) {
  375. if (is_null($options['expandUrls'])) {
  376. $selements[$selementUrl['selementid']]['urls'][$selementUrl['sysmapelementurlid']] = $selementUrl;
  377. }
  378. else {
  379. $selements[$selementUrl['selementid']]['urls'][$selementUrl['sysmapelementurlid']] = $this->expandUrlMacro($selementUrl, $selements[$selementUrl['selementid']]);
  380. }
  381. }
  382. foreach ($selements as $selement) {
  383. if (!isset($result[$selement['sysmapid']]['selements'])) {
  384. $result[$selement['sysmapid']]['selements'] = array();
  385. }
  386. if (!is_null($options['preservekeys'])) {
  387. $result[$selement['sysmapid']]['selements'][$selement['selementid']] = $selement;
  388. }
  389. else {
  390. $result[$selement['sysmapid']]['selements'][] = $selement;
  391. }
  392. }
  393. }
  394. // adding icon maps
  395. if (!is_null($options['selectIconMap']) && str_in_array($options['selectIconMap'], $subselectsAllowedOutputs)) {
  396. $iconMaps = API::IconMap()->get(array(
  397. 'sysmapids' => $sysmapids,
  398. 'output' => $options['selectIconMap'],
  399. 'selectMappings' => API_OUTPUT_EXTEND,
  400. 'preservekeys' => true,
  401. 'nopermissions' => true
  402. ));
  403. foreach ($iconMaps as $iconMap) {
  404. $isysmaps = $iconMap['sysmaps'];
  405. unset($iconMap['sysmaps']);
  406. foreach ($isysmaps as $sysmap) {
  407. $result[$sysmap['sysmapid']]['iconmap'] = $iconMap;
  408. }
  409. }
  410. }
  411. // adding links
  412. if (!is_null($options['selectLinks']) && str_in_array($options['selectLinks'], $subselectsAllowedOutputs)) {
  413. $linkids = array();
  414. $mapLinks = array();
  415. $dbLinks = DBselect('SELECT sl.* FROM sysmaps_links sl WHERE '.DBcondition('sl.sysmapid', $sysmapids));
  416. while ($link = DBfetch($dbLinks)) {
  417. $link['linktriggers'] = array();
  418. $mapLinks[$link['linkid']] = $link;
  419. $linkids[$link['linkid']] = $link['linkid'];
  420. }
  421. $dbLinkTriggers = DBselect('SELECT DISTINCT slt.* FROM sysmaps_link_triggers slt WHERE '.DBcondition('slt.linkid', $linkids));
  422. while ($linkTrigger = DBfetch($dbLinkTriggers)) {
  423. $mapLinks[$linkTrigger['linkid']]['linktriggers'][$linkTrigger['linktriggerid']] = $linkTrigger;
  424. }
  425. foreach ($mapLinks as $link) {
  426. if (!isset($result[$link['sysmapid']]['links'])) {
  427. $result[$link['sysmapid']]['links'] = array();
  428. }
  429. if (!is_null($options['preservekeys'])) {
  430. $result[$link['sysmapid']]['links'][$link['linkid']] = $link;
  431. }
  432. else {
  433. $result[$link['sysmapid']]['links'][] = $link;
  434. }
  435. }
  436. }
  437. // adding urls
  438. if ($options['output'] != API_OUTPUT_SHORTEN) {
  439. $dbUrls = DBselect('SELECT su.* FROM sysmap_url su WHERE '.DBcondition('su.sysmapid', $sysmapids));
  440. while ($url = DBfetch($dbUrls)) {
  441. $sysmapid = $url['sysmapid'];
  442. unset($url['sysmapid']);
  443. $result[$sysmapid]['urls'][] = $url;
  444. }
  445. }
  446. // removing keys (hash -> array)
  447. if (is_null($options['preservekeys'])) {
  448. $result = zbx_cleanHashes($result);
  449. }
  450. return $result;
  451. }
  452. /**
  453. * Get Sysmap IDs by Sysmap params
  454. *
  455. * @param array $sysmap_data
  456. * @param array $sysmap_data['name']
  457. * @param array $sysmap_data['sysmapid']
  458. * @return string sysmapid
  459. */
  460. public function getObjects($sysmapData) {
  461. $options = array(
  462. 'filter' => $sysmapData,
  463. 'output' => API_OUTPUT_EXTEND
  464. );
  465. if (isset($sysmapData['node']))
  466. $options['nodeids'] = getNodeIdByNodeName($sysmapData['node']);
  467. elseif (isset($sysmapData['nodeids']))
  468. $options['nodeids'] = $sysmapData['nodeids'];
  469. $result = $this->get($options);
  470. return $result;
  471. }
  472. public function exists($object) {
  473. $keyFields = array(array('sysmapid', 'name'));
  474. $options = array(
  475. 'filter' => zbx_array_mintersect($keyFields, $object),
  476. 'output' => API_OUTPUT_SHORTEN,
  477. 'nopermissions' => 1,
  478. 'limit' => 1
  479. );
  480. if (isset($object['node']))
  481. $options['nodeids'] = getNodeIdByNodeName($object['node']);
  482. elseif (isset($object['nodeids']))
  483. $options['nodeids'] = $object['nodeids'];
  484. $objs = $this->get($options);
  485. return !empty($objs);
  486. }
  487. public function checkInput(&$maps, $method) {
  488. $create = ($method == 'create');
  489. $update = ($method == 'update');
  490. $delete = ($method == 'delete');
  491. // permissions
  492. if ($update || $delete) {
  493. $mapDbFields = array('sysmapid' => null);
  494. $dbMaps = $this->get(array(
  495. 'sysmapids' => zbx_objectValues($maps, 'sysmapid'),
  496. 'output' => API_OUTPUT_EXTEND,
  497. 'editable' => true,
  498. 'preservekeys' => true,
  499. 'selectLinks' => API_OUTPUT_EXTEND,
  500. 'selectSelements' => API_OUTPUT_EXTEND,
  501. ));
  502. }
  503. else {
  504. $mapDbFields = array(
  505. 'name' => null,
  506. 'width' => null,
  507. 'height' => null,
  508. 'urls' => array(),
  509. 'selements' => array(),
  510. 'links' => array()
  511. );
  512. }
  513. $mapNames = array();
  514. foreach ($maps as &$map) {
  515. if (!check_db_fields($mapDbFields, $map)) {
  516. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Incorrect fields for sysmap'));
  517. }
  518. if ($update || $delete) {
  519. if (!isset($dbMaps[$map['sysmapid']]))
  520. self::exception(ZBX_API_ERROR_PARAMETERS, _('No permissions to referred object or it does not exist!'));
  521. $dbMap = array_merge($dbMaps[$map['sysmapid']], $map);
  522. }
  523. else {
  524. $dbMap = $map;
  525. }
  526. if (isset($map['name'])) {
  527. if (isset($mapNames[$map['name']]))
  528. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Duplicate map name for map "%s".', $dbMap['name']));
  529. else
  530. $mapNames[$map['name']] = $update ? $map['sysmapid'] : 1;
  531. }
  532. if (isset($map['width']) && (($map['width'] > 65535) || ($map['width'] < 1)))
  533. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Incorrect map width value for map "%s".', $dbMap['name']));
  534. if (isset($map['height']) && (($map['height'] > 65535) || ($map['height'] < 1)))
  535. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Incorrect map height value for map "%s".', $dbMap['name']));
  536. // labels
  537. $mapLabels = array('label_type' => array('typeName' => _('icon')));
  538. if ($dbMap['label_format'] == SYSMAP_LABEL_ADVANCED_ON) {
  539. $mapLabels['label_type_hostgroup'] = array('string' => 'label_string_hostgroup', 'typeName' => _('host group'));
  540. $mapLabels['label_type_host'] = array('string' => 'label_string_host', 'typeName' => _('host'));
  541. $mapLabels['label_type_trigger'] = array('string' => 'label_string_trigger', 'typeName' => _('trigger'));
  542. $mapLabels['label_type_map'] = array('string' => 'label_string_map', 'typeName' => _('map'));
  543. $mapLabels['label_type_image'] = array('string' => 'label_string_image', 'typeName' => _('image'));
  544. }
  545. foreach ($mapLabels as $labelName => $labelData) {
  546. if (!isset($map[$labelName])) continue;
  547. if (sysmapElementLabel($map[$labelName]) === false)
  548. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Incorrect %1$s label type value for map "%2$s".', $labelData['typeName'], $dbMap['name']));
  549. if (MAP_LABEL_TYPE_CUSTOM == $map[$labelName]) {
  550. if (!isset($labelData['string']))
  551. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Incorrect %1$s label type value for map "%2$s".', $labelData['typeName'], $dbMap['name']));
  552. if (!isset($map[$labelData['string']]) || zbx_empty($map[$labelData['string']]))
  553. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Custom label for map "%2$s" elements of type "%1$s" may not be empty.', $labelData['typeName'], $dbMap['name']));
  554. }
  555. if (($labelName == 'label_type_image') && (MAP_LABEL_TYPE_STATUS == $map[$labelName]))
  556. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Incorrect %1$s label type value for map "%2$s".', $labelData['typeName'], $dbMap['name']));
  557. if ($labelName == 'label_type' || $labelName == 'label_type_host') continue;
  558. if (MAP_LABEL_TYPE_IP == $map[$labelName])
  559. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Incorrect %1$s label type value for map "%2$s".', $labelData['typeName'], $dbMap['name']));
  560. }
  561. //---
  562. // GRID OPTIONS
  563. // validating grid options
  564. $possibleGridSizes = array(20, 40, 50, 75, 100);
  565. if ($update || $create) {
  566. // grid size
  567. if (isset($map['grid_size']) && !in_array($map['grid_size'], $possibleGridSizes)) {
  568. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Value "%1$s" is invalid for parameter "grid_show". Choices are: "%2$s"', $map['grid_size'], implode('", "', $possibleGridSizes)));
  569. }
  570. // grid auto align
  571. if (isset($map['grid_align']) && $map['grid_align'] != SYSMAP_GRID_ALIGN_ON && $map['grid_align'] != SYSMAP_GRID_ALIGN_OFF) {
  572. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Value "%1$s" is invalid for parameter "grid_align". Choices are: "%2$s" and "%3$s"', $map['grid_align'], SYSMAP_GRID_ALIGN_ON, SYSMAP_GRID_ALIGN_OFF));
  573. }
  574. // grid show
  575. if (isset($map['grid_show']) && $map['grid_show'] != SYSMAP_GRID_SHOW_ON && $map['grid_show'] != SYSMAP_GRID_SHOW_OFF) {
  576. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Value "%1$s" is invalid for parameter "grid_show". Choices are: "%2$s" and "%3$s"', $map['grid_show'], SYSMAP_GRID_SHOW_ON, SYSMAP_GRID_SHOW_OFF));
  577. }
  578. }
  579. // URLS
  580. if (isset($map['urls']) && !empty($map['urls'])) {
  581. $urlNames = zbx_toHash($map['urls'], 'name');
  582. foreach ($map['urls'] as $url) {
  583. if ($url['name'] === '' || $url['url'] === '')
  584. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Link should have both "name" and "url" fields for map "%s".', $dbMap['name']));
  585. if (!isset($urlNames[$url['name']]))
  586. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Link name should be unique for map "%s".', $dbMap['name']));
  587. unset($urlNames[$url['name']]);
  588. }
  589. }
  590. // Map selement links
  591. if (!empty($map['links'])) {
  592. $mapSelements = zbx_toHash($map['selements'], 'selementid');
  593. foreach ($map['links'] as $link) {
  594. if (!isset($mapSelements[$link['selementid1']]))
  595. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Link selementid1 field is pointing to a nonexistent map selement ID "%1$s" for map "%2$s".', $link['selementid1'], $dbMap['name']));
  596. if (!isset($mapSelements[$link['selementid2']]))
  597. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Link selementid2 field is pointing to a nonexistent map selement ID "%1$s" for map "%2$s".', $link['selementid2'], $dbMap['name']));
  598. }
  599. }
  600. }
  601. unset($map);
  602. // Exists
  603. if (($create || $update) && !empty($mapNames)) {
  604. $options = array(
  605. 'filter' => array('name' => array_keys($mapNames)),
  606. 'output' => array('sysmapid', 'name'),
  607. 'nopermissions' => true
  608. );
  609. $existDbMaps = $this->get($options);
  610. foreach ($existDbMaps as $dbMap) {
  611. if ($create || (bccomp($mapNames[$dbMap['name']], $dbMap['sysmapid']) != 0))
  612. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Map with name "%s" already exists', $dbMap['name']));
  613. }
  614. }
  615. //--
  616. return ($update || $delete) ? $dbMaps : true;
  617. }
  618. /**
  619. * Add Map
  620. *
  621. * @param _array $maps
  622. * @param string $maps['name']
  623. * @param array $maps['width']
  624. * @param int $maps['height']
  625. * @param string $maps['backgroundid']
  626. * @param string $maps['highlight']
  627. * @param array $maps['label_type']
  628. * @param int $maps['label_location']
  629. * @param int $maps['grid_size'] size of a one grid cell. 100 refers to 100x100 and so on.
  630. * @param int $maps['grid_show'] does grid need to be shown. Constants: SYSMAP_GRID_SHOW_ON / SYSMAP_GRID_SHOW_OFF
  631. * @param int $maps['grid_align'] does elements need to be aligned to the grid. Constants: SYSMAP_GRID_ALIGN_ON / SYSMAP_GRID_ALIGN_OFF
  632. * @return boolean | array
  633. */
  634. public function create($maps) {
  635. $maps = zbx_toArray($maps);
  636. $this->checkInput($maps, __FUNCTION__);
  637. $sysmapids = DB::insert('sysmaps', $maps);
  638. $newUrls = array();
  639. $newSelements = array();
  640. $newLinks = array();
  641. foreach ($sysmapids as $mnum => $sysmapid) {
  642. foreach ($maps[$mnum]['urls'] as $url) {
  643. $url['sysmapid'] = $sysmapid;
  644. $newUrls[] = $url;
  645. }
  646. foreach ($maps[$mnum]['selements'] as $snum => $selement)
  647. $maps[$mnum]['selements'][$snum]['sysmapid'] = $sysmapid;
  648. $newSelements = array_merge($newSelements, $maps[$mnum]['selements']);
  649. foreach ($maps[$mnum]['links'] as $lnum => $link)
  650. $maps[$mnum]['links'][$lnum]['sysmapid'] = $sysmapid;
  651. $newLinks = array_merge($newLinks, $maps[$mnum]['links']);
  652. }
  653. DB::insert('sysmap_url', $newUrls);
  654. if (!empty($newSelements)) {
  655. $selementids = $this->createSelements($newSelements);
  656. if (!empty($newLinks)) {
  657. // Links
  658. $mapVirtSelements = array();
  659. foreach ($selementids['selementids'] as $snum => $selementid)
  660. $mapVirtSelements[$newSelements[$snum]['selementid']] = $selementid;
  661. foreach ($newLinks as $lnum => $link) {
  662. $newLinks[$lnum]['selementid1'] = $mapVirtSelements[$link['selementid1']];
  663. $newLinks[$lnum]['selementid2'] = $mapVirtSelements[$link['selementid2']];
  664. }
  665. unset($mapVirtSelements);
  666. $linkids = $this->createLinks($newLinks);
  667. // linkTriggers
  668. $newLinkTriggers = array();
  669. foreach ($linkids['linkids'] as $lnum => $linkid) {
  670. if (!isset($newLinks[$lnum]['linktriggers'])) continue;
  671. foreach ($newLinks[$lnum]['linktriggers'] as $linktrigger) {
  672. $linktrigger['linkid'] = $linkid;
  673. $newLinkTriggers[] = $linktrigger;
  674. }
  675. }
  676. if (!empty($newLinkTriggers))
  677. $this->createLinkTriggers($newLinkTriggers);
  678. }
  679. }
  680. return array('sysmapids' => $sysmapids);
  681. }
  682. /**
  683. * Update Map
  684. *
  685. * @param array $maps multidimensional array with Hosts data
  686. * @param string $maps['sysmapid']
  687. * @param string $maps['name']
  688. * @param array $maps['width']
  689. * @param int $maps['height']
  690. * @param string $maps['backgroundid']
  691. * @param array $maps['label_type']
  692. * @param int $maps['label_location']
  693. * @param int $maps['grid_size'] size of a one grid cell. 100 refers to 100x100 and so on.
  694. * @param int $maps['grid_show'] does grid need to be shown. Constants: SYSMAP_GRID_SHOW_ON / SYSMAP_GRID_SHOW_OFF
  695. * @param int $maps['grid_align'] does elements need to be aligned to the grid. Constants: SYSMAP_GRID_ALIGN_ON / SYSMAP_GRID_ALIGN_OFF
  696. * @return boolean
  697. */
  698. public function update($maps) {
  699. $maps = zbx_toArray($maps);
  700. $sysmapids = zbx_objectValues($maps, 'sysmapid');
  701. $dbMaps = $this->checkInput($maps, __FUNCTION__);
  702. $updateMaps = array();
  703. $urlidsToDelete = $urlsToUpdate = $urlsToAdd = array();
  704. $selementsToDelete = $selementsToUpdate = $selementsToAdd = array();
  705. $linksToDelete = $linksToUpdate = $linksToAdd = array();
  706. foreach ($maps as $map) {
  707. $updateMaps[] = array(
  708. 'values' => $map,
  709. 'where' => array('sysmapid' => $map['sysmapid']),
  710. );
  711. $dbMap = $dbMaps[$map['sysmapid']];
  712. // URLS
  713. if (isset($map['urls'])) {
  714. $urlDiff = zbx_array_diff($map['urls'], $dbMap['urls'], 'name');
  715. foreach ($urlDiff['both'] as $updUrl) {
  716. $urlsToUpdate[] = array(
  717. 'values' => $updUrl,
  718. 'where' => array('name' => $updUrl['name'], 'sysmapid' => $map['sysmapid'])
  719. );
  720. }
  721. foreach ($urlDiff['first'] as $newUrl) {
  722. $newUrl['sysmapid'] = $map['sysmapid'];
  723. $urlsToAdd[] = $newUrl;
  724. }
  725. $urlidsToDelete = array_merge($urlidsToDelete, zbx_objectValues($urlDiff['second'], 'sysmapurlid'));
  726. }
  727. // Elements
  728. if (isset($map['selements'])) {
  729. $selementDiff = zbx_array_diff($map['selements'], $dbMap['selements'], 'selementid');
  730. // We need sysmapid for add operations
  731. foreach ($selementDiff['first'] as $newSelement) {
  732. $newSelement['sysmapid'] = $map['sysmapid'];
  733. $selementsToAdd[] = $newSelement;
  734. }
  735. $selementsToUpdate = array_merge($selementsToUpdate, $selementDiff['both']);
  736. $selementsToDelete = array_merge($selementsToDelete, $selementDiff['second']);
  737. }
  738. // Links
  739. if (isset($map['links'])) {
  740. $linkDiff = zbx_array_diff($map['links'], $dbMap['links'], 'linkid');
  741. // We need sysmapid for add operations
  742. foreach ($linkDiff['first'] as $newLink) {
  743. $newLink['sysmapid'] = $map['sysmapid'];
  744. $linksToAdd[] = $newLink;
  745. }
  746. $linksToUpdate = array_merge($linksToUpdate, $linkDiff['both']);
  747. $linksToDelete = array_merge($linksToDelete, $linkDiff['second']);
  748. }
  749. }
  750. DB::update('sysmaps', $updateMaps);
  751. // Urls
  752. DB::insert('sysmap_url', $urlsToAdd);
  753. DB::update('sysmap_url', $urlsToUpdate);
  754. if (!empty($urlidsToDelete))
  755. DB::delete('sysmap_url', array('sysmapurlid' => $urlidsToDelete));
  756. // Selements
  757. $newSelementids = array('selementids' => array());
  758. if (!empty($selementsToAdd))
  759. $newSelementids = $this->createSelements($selementsToAdd);
  760. if (!empty($selementsToUpdate))
  761. $this->updateSelements($selementsToUpdate);
  762. if (!empty($selementsToDelete))
  763. $this->deleteSelements($selementsToDelete);
  764. // Links
  765. if (!empty($linksToAdd) || !empty($linksToUpdate)) {
  766. $mapVirtSelements = array();
  767. foreach ($newSelementids['selementids'] as $snum => $selementid) {
  768. $mapVirtSelements[$selementsToAdd[$snum]['selementid']] = $selementid;
  769. }
  770. foreach ($selementsToUpdate as $selement) {
  771. $mapVirtSelements[$selement['selementid']] = $selement['selementid'];
  772. }
  773. foreach ($linksToAdd as $lnum => $link) {
  774. $linksToAdd[$lnum]['selementid1'] = $mapVirtSelements[$link['selementid1']];
  775. $linksToAdd[$lnum]['selementid2'] = $mapVirtSelements[$link['selementid2']];
  776. }
  777. foreach ($linksToUpdate as $lnum => $link) {
  778. $linksToUpdate[$lnum]['selementid1'] = $mapVirtSelements[$link['selementid1']];
  779. $linksToUpdate[$lnum]['selementid2'] = $mapVirtSelements[$link['selementid2']];
  780. }
  781. unset($mapVirtSelements);
  782. }
  783. $newLinkids = $updLinkids = array('linkids' => array());
  784. if (!empty($linksToAdd)) {
  785. $newLinkids = $this->createLinks($linksToAdd);
  786. }
  787. if (!empty($linksToUpdate)) {
  788. $updLinkids = $this->updateLinks($linksToUpdate);
  789. }
  790. if (!empty($linksToDelete)) {
  791. $this->deleteLinks($linksToDelete);
  792. }
  793. // linkTriggers
  794. $linkTriggersToDelete = $linkTriggersToUpdate = $linkTriggersToAdd = array();
  795. foreach ($newLinkids['linkids'] as $lnum => $linkid) {
  796. if (!isset($linksToAdd[$lnum]['linktriggers'])) continue;
  797. foreach ($linksToAdd[$lnum]['linktriggers'] as $linktrigger) {
  798. $linktrigger['linkid'] = $linkid;
  799. $linkTriggersToAdd[] = $linktrigger;
  800. }
  801. }
  802. $dbLinks = array();
  803. $linkTriggerResource = DBselect('SELECT * FROM sysmaps_link_triggers WHERE '.DBcondition('linkid', $updLinkids['linkids']));
  804. while ($dbLinkTrigger = DBfetch($linkTriggerResource))
  805. zbx_subarray_push($dbLinks, $dbLinkTrigger['linkid'], $dbLinkTrigger);
  806. foreach ($updLinkids['linkids'] as $lnum => $linkid) {
  807. if (!isset($linksToUpdate[$lnum]['linktriggers'])) continue;
  808. $dbLinkTriggers = isset($dbLinks[$linkid]) ? $dbLinks[$linkid] : array();
  809. $dbLinkTriggersDiff = zbx_array_diff($linksToUpdate[$lnum]['linktriggers'], $dbLinkTriggers, 'linktriggerid');
  810. foreach ($dbLinkTriggersDiff['first'] as $newLinkTrigger) {
  811. $newLinkTrigger['linkid'] = $linkid;
  812. $linkTriggersToAdd[] = $newLinkTrigger;
  813. }
  814. $linkTriggersToUpdate = array_merge($linkTriggersToUpdate, $dbLinkTriggersDiff['both']);
  815. $linkTriggersToDelete = array_merge($linkTriggersToDelete, $dbLinkTriggersDiff['second']);
  816. }
  817. if (!empty($linkTriggersToAdd))
  818. $this->createLinkTriggers($linkTriggersToAdd);
  819. if (!empty($linkTriggersToUpdate))
  820. $this->updateLinkTriggers($linkTriggersToUpdate);
  821. if (!empty($linkTriggersToDelete))
  822. $this->deleteLinkTriggers($linkTriggersToDelete);
  823. return array('sysmapids' => $sysmapids);
  824. }
  825. /**
  826. * Delete Map
  827. *
  828. * @param array $sysmaps
  829. * @param array $sysmaps['sysmapid']
  830. * @return boolean
  831. */
  832. public function delete($sysmapids) {
  833. $maps = zbx_toObject($sysmapids, 'sysmapid');
  834. $this->checkInput($maps, __FUNCTION__);
  835. // delete maps from selements of other maps
  836. DB::delete('sysmaps_elements', array(
  837. 'elementid' => $sysmapids,
  838. 'elementtype' => SYSMAP_ELEMENT_TYPE_MAP
  839. ));
  840. DB::delete('screens_items', array(
  841. 'resourceid' => $sysmapids,
  842. 'resourcetype' => SCREEN_RESOURCE_MAP
  843. ));
  844. DB::delete('profiles', array(
  845. 'idx' => 'web.maps.sysmapid',
  846. 'value_id' => $sysmapids
  847. ));
  848. //----
  849. DB::delete('sysmaps', array('sysmapid' => $sysmapids));
  850. return array('sysmapids' => $sysmapids);
  851. }
  852. private function expandUrlMacro($url, $selement) {
  853. switch ($selement['elementtype']) {
  854. case SYSMAP_ELEMENT_TYPE_HOST_GROUP: $macro = '{HOSTGROUP.ID}' ; break;
  855. case SYSMAP_ELEMENT_TYPE_TRIGGER: $macro = '{TRIGGER.ID}' ; break;
  856. case SYSMAP_ELEMENT_TYPE_MAP: $macro = '{MAP.ID}' ; break;
  857. case SYSMAP_ELEMENT_TYPE_HOST: $macro = '{HOST.ID}' ; break;
  858. default: $macro = false;
  859. }
  860. if ($macro)
  861. $url['url'] = str_replace($macro, $selement['elementid'], $url['url']);
  862. return $url;
  863. }
  864. public function isReadable(array $ids) {
  865. if (empty($ids)) {
  866. return true;
  867. }
  868. $ids = array_unique($ids);
  869. $count = $this->get(array(
  870. 'nodeids' => get_current_nodeid(true),
  871. 'sysmapids' => $ids,
  872. 'output' => API_OUTPUT_SHORTEN,
  873. 'countOutput' => true
  874. ));
  875. return (count($ids) == $count);
  876. }
  877. public function isWritable(array $ids) {
  878. if (empty($ids)) {
  879. return true;
  880. }
  881. $ids = array_unique($ids);
  882. $count = $this->get(array(
  883. 'nodeids' => get_current_nodeid(true),
  884. 'sysmapids' => $ids,
  885. 'output' => API_OUTPUT_SHORTEN,
  886. 'editable' => true,
  887. 'countOutput' => true
  888. ));
  889. return (count($ids) == $count);
  890. }
  891. }
  892. ?>