1<?php 2/* 3** Zabbix 4** Copyright (C) 2001-2021 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 22/** 23 * Class containing methods for operations with http tests. 24 */ 25class CHttpTest extends CApiService { 26 27 protected $tableName = 'httptest'; 28 protected $tableAlias = 'ht'; 29 protected $sortColumns = ['httptestid', 'name']; 30 31 /** 32 * Get data about web scenarios. 33 * 34 * @param array $options 35 * 36 * @return array 37 */ 38 public function get($options = []) { 39 $result = []; 40 41 $sqlParts = [ 42 'select' => ['httptests' => 'ht.httptestid'], 43 'from' => ['httptest' => 'httptest ht'], 44 'where' => [], 45 'group' => [], 46 'order' => [], 47 'limit' => null 48 ]; 49 50 $defOptions = [ 51 'httptestids' => null, 52 'applicationids' => null, 53 'hostids' => null, 54 'groupids' => null, 55 'templateids' => null, 56 'editable' => false, 57 'inherited' => null, 58 'templated' => null, 59 'monitored' => null, 60 'nopermissions' => null, 61 // filter 62 'filter' => null, 63 'search' => null, 64 'searchByAny' => null, 65 'startSearch' => false, 66 'excludeSearch' => false, 67 // output 68 'output' => API_OUTPUT_EXTEND, 69 'expandName' => null, 70 'expandStepName' => null, 71 'selectHosts' => null, 72 'selectSteps' => null, 73 'countOutput' => false, 74 'groupCount' => false, 75 'preservekeys' => false, 76 'sortfield' => '', 77 'sortorder' => '', 78 'limit' => null 79 ]; 80 $options = zbx_array_merge($defOptions, $options); 81 82 // editable + PERMISSION CHECK 83 if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN && !$options['nopermissions']) { 84 $permission = $options['editable'] ? PERM_READ_WRITE : PERM_READ; 85 $userGroups = getUserGroupsByUserId(self::$userData['userid']); 86 87 $sqlParts['where'][] = 'EXISTS ('. 88 'SELECT NULL'. 89 ' FROM hosts_groups hgg'. 90 ' JOIN rights r'. 91 ' ON r.id=hgg.groupid'. 92 ' AND '.dbConditionInt('r.groupid', $userGroups). 93 ' WHERE ht.hostid=hgg.hostid'. 94 ' GROUP BY hgg.hostid'. 95 ' HAVING MIN(r.permission)>'.PERM_DENY. 96 ' AND MAX(r.permission)>='.zbx_dbstr($permission). 97 ')'; 98 } 99 100 // httptestids 101 if (!is_null($options['httptestids'])) { 102 zbx_value2array($options['httptestids']); 103 104 $sqlParts['where']['httptestid'] = dbConditionInt('ht.httptestid', $options['httptestids']); 105 } 106 107 // templateids 108 if (!is_null($options['templateids'])) { 109 zbx_value2array($options['templateids']); 110 111 if (!is_null($options['hostids'])) { 112 zbx_value2array($options['hostids']); 113 $options['hostids'] = array_merge($options['hostids'], $options['templateids']); 114 } 115 else { 116 $options['hostids'] = $options['templateids']; 117 } 118 } 119 // hostids 120 if (!is_null($options['hostids'])) { 121 zbx_value2array($options['hostids']); 122 123 $sqlParts['where']['hostid'] = dbConditionInt('ht.hostid', $options['hostids']); 124 125 if ($options['groupCount']) { 126 $sqlParts['group']['hostid'] = 'ht.hostid'; 127 } 128 } 129 130 // groupids 131 if (!is_null($options['groupids'])) { 132 zbx_value2array($options['groupids']); 133 134 $sqlParts['from']['hosts_groups'] = 'hosts_groups hg'; 135 $sqlParts['where'][] = dbConditionInt('hg.groupid', $options['groupids']); 136 $sqlParts['where'][] = 'hg.hostid=ht.hostid'; 137 138 if ($options['groupCount']) { 139 $sqlParts['group']['hg'] = 'hg.groupid'; 140 } 141 } 142 143 // applicationids 144 if (!is_null($options['applicationids'])) { 145 zbx_value2array($options['applicationids']); 146 147 $sqlParts['where'][] = dbConditionId('ht.applicationid', $options['applicationids']); 148 } 149 150 // inherited 151 if (isset($options['inherited'])) { 152 $sqlParts['where'][] = $options['inherited'] ? 'ht.templateid IS NOT NULL' : 'ht.templateid IS NULL'; 153 } 154 155 // templated 156 if (isset($options['templated'])) { 157 $sqlParts['from']['hosts'] = 'hosts h'; 158 $sqlParts['where']['ha'] = 'h.hostid=ht.hostid'; 159 if ($options['templated']) { 160 $sqlParts['where'][] = 'h.status='.HOST_STATUS_TEMPLATE; 161 } 162 else { 163 $sqlParts['where'][] = 'h.status<>'.HOST_STATUS_TEMPLATE; 164 } 165 } 166 167 // monitored 168 if (!is_null($options['monitored'])) { 169 $sqlParts['from']['hosts'] = 'hosts h'; 170 $sqlParts['where']['hht'] = 'h.hostid=ht.hostid'; 171 172 if ($options['monitored']) { 173 $sqlParts['where'][] = 'h.status='.HOST_STATUS_MONITORED; 174 $sqlParts['where'][] = 'ht.status='.ITEM_STATUS_ACTIVE; 175 } 176 else { 177 $sqlParts['where'][] = '(h.status<>'.HOST_STATUS_MONITORED.' OR ht.status<>'.ITEM_STATUS_ACTIVE.')'; 178 } 179 } 180 181 // search 182 if (is_array($options['search'])) { 183 zbx_db_search('httptest ht', $options, $sqlParts); 184 } 185 186 // filter 187 if (is_array($options['filter'])) { 188 if (array_key_exists('delay', $options['filter']) && $options['filter']['delay'] !== null) { 189 $options['filter']['delay'] = getTimeUnitFilters($options['filter']['delay']); 190 } 191 192 $this->dbFilter('httptest ht', $options, $sqlParts); 193 } 194 195 // limit 196 if (zbx_ctype_digit($options['limit']) && $options['limit']) { 197 $sqlParts['limit'] = $options['limit']; 198 } 199 200 $sqlParts = $this->applyQueryOutputOptions($this->tableName(), $this->tableAlias(), $options, $sqlParts); 201 $sqlParts = $this->applyQuerySortOptions($this->tableName(), $this->tableAlias(), $options, $sqlParts); 202 $res = DBselect(self::createSelectQueryFromParts($sqlParts), $sqlParts['limit']); 203 while ($httpTest = DBfetch($res)) { 204 if ($options['countOutput']) { 205 if ($options['groupCount']) { 206 $result[] = $httpTest; 207 } 208 else { 209 $result = $httpTest['rowscount']; 210 } 211 } 212 else { 213 $result[$httpTest['httptestid']] = $httpTest; 214 } 215 } 216 217 if ($options['countOutput']) { 218 return $result; 219 } 220 221 if ($result) { 222 $result = $this->addRelatedObjects($options, $result); 223 224 // expandName 225 $nameRequested = (is_array($options['output']) && in_array('name', $options['output'])) 226 || $options['output'] == API_OUTPUT_EXTEND; 227 $expandName = $options['expandName'] !== null && $nameRequested; 228 229 // expandStepName 230 $stepNameRequested = $options['selectSteps'] == API_OUTPUT_EXTEND 231 || (is_array($options['selectSteps']) && in_array('name', $options['selectSteps'])); 232 $expandStepName = $options['expandStepName'] !== null && $stepNameRequested; 233 234 if ($expandName || $expandStepName) { 235 $result = resolveHttpTestMacros($result, $expandName, $expandStepName); 236 } 237 238 $result = $this->unsetExtraFields($result, ['hostid'], $options['output']); 239 } 240 241 // removing keys (hash -> array) 242 if (!$options['preservekeys']) { 243 $result = zbx_cleanHashes($result); 244 } 245 246 return $result; 247 } 248 249 /** 250 * Create web scenario. 251 * 252 * @param $httptests 253 * 254 * @return array 255 */ 256 public function create($httptests) { 257 $httptests = $this->convertHttpPairs($httptests); 258 $this->validateCreate($httptests); 259 260 $httptests = Manager::HttpTest()->persist($httptests); 261 262 $this->addAuditBulk(AUDIT_ACTION_ADD, AUDIT_RESOURCE_SCENARIO, $httptests); 263 264 return ['httptestids' => zbx_objectValues($httptests, 'httptestid')]; 265 } 266 267 /** 268 * @param array $httpTests 269 * 270 * @throws APIException if the input is invalid. 271 */ 272 protected function validateCreate(array &$httptests) { 273 $api_input_rules = ['type' => API_OBJECTS, 'flags' => API_NOT_EMPTY | API_NORMALIZE, 'uniq' => [['hostid', 'name']], 'fields' => [ 274 'hostid' => ['type' => API_ID, 'flags' => API_REQUIRED], 275 'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httptest', 'name')], 276 'applicationid' => ['type' => API_ID], 277 'delay' => ['type' => API_TIME_UNIT, 'flags' => API_NOT_EMPTY | API_ALLOW_USER_MACRO, 'in' => '1:'.SEC_PER_DAY], 278 'retries' => ['type' => API_INT32, 'in' => '1:10'], 279 'agent' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'agent')], 280 'http_proxy' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'http_proxy')], 281 'variables' => ['type' => API_OBJECTS, 'uniq' => [['name']], 'fields' => [ 282 'name' => ['type' => API_VARIABLE_NAME, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httptest_field', 'name')], 283 'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httptest_field', 'value')] 284 ]], 285 'headers' => ['type' => API_OBJECTS, 'fields' => [ 286 'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httptest_field', 'name')], 287 'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httptest_field', 'value')] 288 ]], 289 'status' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_STATUS_ACTIVE, HTTPTEST_STATUS_DISABLED])], 290 'authentication' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_AUTH_NONE, HTTPTEST_AUTH_BASIC, HTTPTEST_AUTH_NTLM])], 291 'http_user' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'http_user')], 292 'http_password' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'http_password')], 293 'verify_peer' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_VERIFY_PEER_OFF, HTTPTEST_VERIFY_PEER_ON])], 294 'verify_host' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_VERIFY_HOST_OFF, HTTPTEST_VERIFY_HOST_ON])], 295 'ssl_cert_file' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'ssl_cert_file')], 296 'ssl_key_file' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'ssl_key_file')], 297 'ssl_key_password' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'ssl_key_password')], 298 'steps' => ['type' => API_OBJECTS, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'uniq' => [['name'], ['no']], 'fields' => [ 299 'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep', 'name')], 300 'no' => ['type' => API_INT32, 'flags' => API_REQUIRED], 301 'url' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep', 'url')], 302 'query_fields' => ['type' => API_OBJECTS, 'fields' => [ 303 'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep_field', 'name')], 304 'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httpstep_field', 'value')] 305 ]], 306 'posts' => ['type' => API_HTTP_POST, 'length' => DB::getFieldLength('httpstep', 'posts'), 'name-length' => DB::getFieldLength('httpstep_field', 'name'), 'value-length' => DB::getFieldLength('httpstep_field', 'value')], 307 'variables' => ['type' => API_OBJECTS, 'uniq' => [['name']], 'fields' => [ 308 'name' => ['type' => API_VARIABLE_NAME, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httpstep_field', 'name')], 309 'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httpstep_field', 'value')] 310 ]], 311 'headers' => ['type' => API_OBJECTS, 'fields' => [ 312 'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep_field', 'name')], 313 'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep_field', 'value')] 314 ]], 315 'follow_redirects' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_STEP_FOLLOW_REDIRECTS_OFF, HTTPTEST_STEP_FOLLOW_REDIRECTS_ON])], 316 'retrieve_mode' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_STEP_RETRIEVE_MODE_CONTENT, HTTPTEST_STEP_RETRIEVE_MODE_HEADERS])], 317 'timeout' => ['type' => API_TIME_UNIT, 'flags' => API_NOT_EMPTY | API_ALLOW_USER_MACRO, 'in' => '1:'.SEC_PER_HOUR], 318 'required' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httpstep', 'required')], 319 'status_codes' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httpstep', 'status_codes')] 320 ]] 321 ]]; 322 if (!CApiInputValidator::validate($api_input_rules, $httptests, '/', $error)) { 323 self::exception(ZBX_API_ERROR_PARAMETERS, $error); 324 } 325 326 $names_by_hostid = []; 327 328 foreach ($httptests as $httptest) { 329 $names_by_hostid[$httptest['hostid']][] = $httptest['name']; 330 } 331 332 $this->checkHostPermissions(array_keys($names_by_hostid)); 333 $this->checkDuplicates($names_by_hostid); 334 $this->checkApplications($httptests, __FUNCTION__); 335 $this->validateAuthParameters($httptests, __FUNCTION__); 336 $this->validateSslParameters($httptests, __FUNCTION__); 337 $this->validateSteps($httptests, __FUNCTION__); 338 } 339 340 /** 341 * @param $httptests 342 * 343 * @return array 344 */ 345 public function update($httptests) { 346 $httptests = $this->convertHttpPairs($httptests); 347 $this->validateUpdate($httptests, $db_httptests); 348 349 Manager::HttpTest()->persist($httptests); 350 351 foreach ($db_httptests as &$db_httptest) { 352 unset($db_httptest['headers'], $db_httptest['variables'], $db_httptest['steps']); 353 } 354 unset($db_httptest); 355 356 $this->addAuditBulk(AUDIT_ACTION_UPDATE, AUDIT_RESOURCE_SCENARIO, $httptests, $db_httptests); 357 358 return ['httptestids' => zbx_objectValues($httptests, 'httptestid')]; 359 } 360 361 /** 362 * @param array $httptests 363 * @param array $db_httptests 364 * 365 * @throws APIException if the input is invalid. 366 */ 367 protected function validateUpdate(array &$httptests, array &$db_httptests = null) { 368 $api_input_rules = ['type' => API_OBJECTS, 'flags' => API_NOT_EMPTY | API_NORMALIZE, 'uniq' => [['httptestid']], 'fields' => [ 369 'httptestid' => ['type' => API_ID, 'flags' => API_REQUIRED], 370 'name' => ['type' => API_STRING_UTF8, 'flags' => API_NOT_EMPTY, 'length' => DB::getFieldLength('httptest', 'name')], 371 'applicationid' => ['type' => API_ID], 372 'delay' => ['type' => API_TIME_UNIT, 'flags' => API_NOT_EMPTY | API_ALLOW_USER_MACRO, 'in' => '1:'.SEC_PER_DAY], 373 'retries' => ['type' => API_INT32, 'in' => '1:10'], 374 'agent' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'agent')], 375 'http_proxy' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'http_proxy')], 376 'variables' => ['type' => API_OBJECTS, 'uniq' => [['name']], 'fields' => [ 377 'name' => ['type' => API_VARIABLE_NAME, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httptest_field', 'name')], 378 'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httptest_field', 'value')] 379 ]], 380 'headers' => ['type' => API_OBJECTS, 'fields' => [ 381 'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httptest_field', 'name')], 382 'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httptest_field', 'value')] 383 ]], 384 'status' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_STATUS_ACTIVE, HTTPTEST_STATUS_DISABLED])], 385 'authentication' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_AUTH_NONE, HTTPTEST_AUTH_BASIC, HTTPTEST_AUTH_NTLM])], 386 'http_user' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'http_user')], 387 'http_password' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'http_password')], 388 'verify_peer' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_VERIFY_PEER_OFF, HTTPTEST_VERIFY_PEER_ON])], 389 'verify_host' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_VERIFY_HOST_OFF, HTTPTEST_VERIFY_HOST_ON])], 390 'ssl_cert_file' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'ssl_cert_file')], 391 'ssl_key_file' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'ssl_key_file')], 392 'ssl_key_password' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httptest', 'ssl_key_password')], 393 'steps' => ['type' => API_OBJECTS, 'flags' => API_NOT_EMPTY, 'uniq' => [['httpstepid'], ['name'], ['no']], 'fields' => [ 394 'httpstepid' => ['type' => API_ID], 395 'name' => ['type' => API_STRING_UTF8, 'flags' => API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep', 'name')], 396 'no' => ['type' => API_INT32], 397 'url' => ['type' => API_STRING_UTF8, 'flags' => API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep', 'url')], 398 'query_fields' => ['type' => API_OBJECTS, 'fields' => [ 399 'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep_field', 'name')], 400 'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httpstep_field', 'value')] 401 ]], 402 'posts' => ['type' => API_HTTP_POST, 'length' => DB::getFieldLength('httpstep', 'posts'), 'name-length' => DB::getFieldLength('httpstep_field', 'name'), 'value-length' => DB::getFieldLength('httpstep_field', 'value')], 403 'variables' => ['type' => API_OBJECTS, 'uniq' => [['name']], 'fields' => [ 404 'name' => ['type' => API_VARIABLE_NAME, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httpstep_field', 'name')], 405 'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => DB::getFieldLength('httpstep_field', 'value')] 406 ]], 407 'headers' => ['type' => API_OBJECTS, 'fields' => [ 408 'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep_field', 'name')], 409 'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => DB::getFieldLength('httpstep_field', 'value')] 410 ]], 411 'follow_redirects' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_STEP_FOLLOW_REDIRECTS_OFF, HTTPTEST_STEP_FOLLOW_REDIRECTS_ON])], 412 'retrieve_mode' => ['type' => API_INT32, 'in' => implode(',', [HTTPTEST_STEP_RETRIEVE_MODE_CONTENT, HTTPTEST_STEP_RETRIEVE_MODE_HEADERS])], 413 'timeout' => ['type' => API_TIME_UNIT, 'flags' => API_NOT_EMPTY | API_ALLOW_USER_MACRO, 'in' => '1:'.SEC_PER_HOUR], 414 'required' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httpstep', 'required')], 415 'status_codes' => ['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('httpstep', 'status_codes')] 416 ]] 417 ]]; 418 if (!CApiInputValidator::validate($api_input_rules, $httptests, '/', $error)) { 419 self::exception(ZBX_API_ERROR_PARAMETERS, $error); 420 } 421 422 // permissions 423 $db_httptests = $this->get([ 424 'output' => ['httptestid', 'hostid', 'name', 'applicationid', 'delay', 'retries', 'agent', 'http_proxy', 425 'status', 'authentication', 'http_user', 'http_password', 'verify_peer', 'verify_host', 426 'ssl_cert_file', 'ssl_key_file', 'ssl_key_password', 'templateid' 427 ], 428 'selectSteps' => ['httpstepid', 'name', 'no', 'url', 'timeout', 'posts', 'required', 429 'status_codes', 'follow_redirects', 'retrieve_mode', 'post_type' 430 ], 431 'httptestids' => zbx_objectValues($httptests, 'httptestid'), 432 'editable' => true, 433 'preservekeys' => true 434 ]); 435 436 foreach ($db_httptests as &$db_httptest) { 437 $db_httptest['headers'] = []; 438 $db_httptest['variables'] = []; 439 $db_httptest['steps'] = zbx_toHash($db_httptest['steps'], 'httpstepid'); 440 } 441 unset($db_httptest); 442 443 $names_by_hostid = []; 444 445 foreach ($httptests as $httptest) { 446 if (!array_key_exists($httptest['httptestid'], $db_httptests)) { 447 self::exception(ZBX_API_ERROR_PERMISSIONS, 448 _('No permissions to referred object or it does not exist!') 449 ); 450 } 451 452 $db_httptest = $db_httptests[$httptest['httptestid']]; 453 454 if (array_key_exists('name', $httptest)) { 455 if ($db_httptest['templateid'] != 0) { 456 self::exception(ZBX_API_ERROR_PARAMETERS, _s( 457 'Cannot update a templated web scenario "%1$s": %2$s.', $httptest['name'], 458 _s('unexpected parameter "%1$s"', 'name') 459 )); 460 } 461 462 if ($httptest['name'] !== $db_httptest['name']) { 463 $names_by_hostid[$db_httptest['hostid']][] = $httptest['name']; 464 } 465 } 466 } 467 468 $httptests = $this->extendObjectsByKey($httptests, $db_httptests, 'httptestid', ['hostid', 'name']); 469 470 // uniqueness 471 foreach ($httptests as &$httptest) { 472 $db_httptest = $db_httptests[$httptest['httptestid']]; 473 474 if (array_key_exists('steps', $httptest)) { 475 // unexpected patameters for templated web scenario steps 476 if ($db_httptest['templateid'] != 0) { 477 foreach ($httptest['steps'] as $httpstep) { 478 foreach (['name', 'no'] as $field_name) { 479 if (array_key_exists($field_name, $httpstep)) { 480 self::exception(ZBX_API_ERROR_PARAMETERS, _s( 481 'Cannot update step for a templated web scenario "%1$s": %2$s.', $httptest['name'], 482 _s('unexpected parameter "%1$s"', $field_name) 483 )); 484 } 485 } 486 } 487 } 488 489 $httptest['steps'] = 490 $this->extendObjectsByKey($httptest['steps'], $db_httptest['steps'], 'httpstepid', ['name']); 491 } 492 } 493 unset($httptest); 494 495 $api_input_rules = ['type' => API_OBJECTS, 'uniq' => [['hostid', 'name']], 'fields' => [ 496 'steps' => ['type' => API_OBJECTS, 'uniq' => [['name']]] 497 ]]; 498 if (!CApiInputValidator::validateUniqueness($api_input_rules, $httptests, '/', $error)) { 499 self::exception(ZBX_API_ERROR_PARAMETERS, $error); 500 } 501 502 // validation 503 if ($names_by_hostid) { 504 $this->checkDuplicates($names_by_hostid); 505 } 506 $this->checkApplications($httptests, __FUNCTION__, $db_httptests); 507 $this->validateAuthParameters($httptests, __FUNCTION__, $db_httptests); 508 $this->validateSslParameters($httptests, __FUNCTION__, $db_httptests); 509 $this->validateSteps($httptests, __FUNCTION__, $db_httptests); 510 511 return $httptests; 512 } 513 514 /** 515 * Delete web scenario. 516 * 517 * @param array $httptestids 518 * @param bool $nopermissions 519 * 520 * @return array 521 */ 522 public function delete(array $httptestids, $nopermissions = false) { 523 // TODO: remove $nopermissions hack 524 525 $api_input_rules = ['type' => API_IDS, 'flags' => API_NOT_EMPTY, 'uniq' => true]; 526 if (!CApiInputValidator::validate($api_input_rules, $httptestids, '/', $error)) { 527 self::exception(ZBX_API_ERROR_PARAMETERS, $error); 528 } 529 530 $db_httptests = $this->get([ 531 'output' => ['httptestid', 'name', 'templateid'], 532 'httptestids' => $httptestids, 533 'editable' => true, 534 'preservekeys' => true 535 ]); 536 537 if (!$nopermissions) { 538 foreach ($httptestids as $httptestid) { 539 if (!array_key_exists($httptestid, $db_httptests)) { 540 self::exception(ZBX_API_ERROR_PERMISSIONS, 541 _('No permissions to referred object or it does not exist!') 542 ); 543 } 544 545 $db_httptest = $db_httptests[$httptestid]; 546 547 if ($db_httptest['templateid'] != 0) { 548 self::exception(ZBX_API_ERROR_PARAMETERS, 549 _s('Cannot delete templated web scenario "%1$s".', $db_httptest['name']) 550 ); 551 } 552 } 553 } 554 555 $parent_httptestids = $httptestids; 556 $child_httptestids = []; 557 do { 558 $parent_httptestids = array_keys(DB::select('httptest', [ 559 'output' => [], 560 'filter' => ['templateid' => $parent_httptestids], 561 'preservekeys' => true 562 ])); 563 564 $child_httptestids = array_merge($child_httptestids, $parent_httptestids); 565 } 566 while ($parent_httptestids); 567 568 $del_httptestids = array_merge($httptestids, $child_httptestids); 569 $del_itemids = []; 570 571 $db_httptestitems = DBselect( 572 'SELECT hti.itemid'. 573 ' FROM httptestitem hti'. 574 ' WHERE '.dbConditionInt('hti.httptestid', $del_httptestids) 575 ); 576 while ($db_httptestitem = DBfetch($db_httptestitems)) { 577 $del_itemids[] = $db_httptestitem['itemid']; 578 } 579 580 $db_httpstepitems = DBselect( 581 'SELECT hsi.itemid'. 582 ' FROM httpstepitem hsi,httpstep hs'. 583 ' WHERE hsi.httpstepid=hs.httpstepid'. 584 ' AND '.dbConditionInt('hs.httptestid', $del_httptestids) 585 ); 586 while ($db_httpstepitem = DBfetch($db_httpstepitems)) { 587 $del_itemids[] = $db_httpstepitem['itemid']; 588 } 589 590 if ($del_itemids) { 591 CItemManager::delete($del_itemids); 592 } 593 594 DB::delete('httptest', ['httptestid' => $del_httptestids]); 595 596 $this->addAuditBulk(AUDIT_ACTION_DELETE, AUDIT_RESOURCE_SCENARIO, $db_httptests); 597 598 return ['httptestids' => $httptestids]; 599 } 600 601 /** 602 * Checks if the current user has access to the given hosts and templates. 603 * 604 * @param array $hostids an array of host or template IDs 605 * 606 * @throws APIException if the user doesn't have write permissions for the given hosts. 607 */ 608 private function checkHostPermissions(array $hostids) { 609 if ($hostids) { 610 $count = API::Host()->get([ 611 'countOutput' => true, 612 'hostids' => $hostids, 613 'editable' => true 614 ]); 615 616 if ($count == count($hostids)) { 617 return; 618 } 619 620 $count += API::Template()->get([ 621 'countOutput' => true, 622 'templateids' => $hostids, 623 'editable' => true 624 ]); 625 626 if ($count != count($hostids)) { 627 self::exception(ZBX_API_ERROR_PERMISSIONS, 628 _('No permissions to referred object or it does not exist!') 629 ); 630 } 631 } 632 } 633 634 /** 635 * Check for duplicated web scenarios. 636 * 637 * @param array $names_by_hostid 638 * 639 * @throws APIException if web scenario already exists. 640 */ 641 private function checkDuplicates(array $names_by_hostid) { 642 $sql_where = []; 643 foreach ($names_by_hostid as $hostid => $names) { 644 $sql_where[] = '(ht.hostid='.$hostid.' AND '.dbConditionString('ht.name', $names).')'; 645 } 646 647 $db_httptests = DBfetchArray( 648 DBselect('SELECT ht.name FROM httptest ht WHERE '.implode(' OR ', $sql_where), 1) 649 ); 650 651 if ($db_httptests) { 652 self::exception(ZBX_API_ERROR_PARAMETERS, 653 _s('Web scenario "%1$s" already exists.', $db_httptests[0]['name']) 654 ); 655 } 656 } 657 658 /** 659 * Check that application belongs to web scenario host. 660 * 661 * @param array $httptests 662 * @param string $method 663 * @param array $db_httptests 664 * 665 * @throws APIException if application does not exists or belongs to another host. 666 */ 667 private function checkApplications(array $httptests, $method, array $db_httptests = null) { 668 $applicationids = []; 669 670 foreach ($httptests as $index => $httptest) { 671 if (array_key_exists('applicationid', $httptest) && $httptest['applicationid'] != 0 672 && ($method === 'validateCreate' 673 || $httptest['applicationid'] != $db_httptests[$httptest['httptestid']]['applicationid'])) { 674 $applicationids[$httptest['applicationid']] = true; 675 } 676 } 677 678 if (!$applicationids) { 679 return; 680 } 681 682 $db_applications = DB::select('applications', [ 683 'output' => ['applicationid', 'hostid', 'name', 'flags'], 684 'applicationids' => array_keys($applicationids), 685 'preservekeys' => true 686 ]); 687 688 foreach ($httptests as $index => $httptest) { 689 if (array_key_exists('applicationid', $httptest) && $httptest['applicationid'] != 0 690 && ($method === 'validateCreate' 691 || $httptest['applicationid'] != $db_httptests[$httptest['httptestid']]['applicationid'])) { 692 if (!array_key_exists($httptest['applicationid'], $db_applications)) { 693 self::exception(ZBX_API_ERROR_PARAMETERS, 694 _s('Application with applicationid "%1$s" does not exist.', $httptest['applicationid']) 695 ); 696 } 697 698 $db_application = $db_applications[$httptest['applicationid']]; 699 700 if ($db_application['flags'] == ZBX_FLAG_DISCOVERY_CREATED) { 701 self::exception(ZBX_API_ERROR_PARAMETERS, _s( 702 'Cannot add a discovered application "%1$s" to a web scenario.', $db_application['name'] 703 )); 704 } 705 706 $hostid = ($method === 'validateCreate') 707 ? $httptest['hostid'] 708 : $db_httptests[$httptest['httptestid']]['hostid']; 709 710 if (bccomp($db_application['hostid'], $hostid) != 0) { 711 self::exception(ZBX_API_ERROR_PARAMETERS, 712 _('The web scenario application belongs to a different host than the web scenario host.') 713 ); 714 } 715 } 716 } 717 } 718 719 /** 720 * @param array $httptests 721 * @param string $method 722 * @param array $db_httptests 723 * 724 * @throws APIException 725 */ 726 protected function validateSteps(array &$httptests, $method, array $db_httptests = null) { 727 if ($method === 'validateUpdate') { 728 foreach ($httptests as $httptest) { 729 if (!array_key_exists('steps', $httptest)) { 730 continue; 731 } 732 733 $db_httptest = $db_httptests[$httptest['httptestid']]; 734 735 if ($db_httptest['templateid'] != 0) { 736 if (count($httptest['steps']) != count($db_httptest['steps'])) { 737 self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect templated web scenario step count.')); 738 } 739 740 foreach ($httptest['steps'] as $httpstep) { 741 if (!array_key_exists('httpstepid', $httpstep)) { 742 self::exception(ZBX_API_ERROR_PARAMETERS, _s( 743 'Cannot update step for a templated web scenario "%1$s": %2$s.', $httptest['name'], 744 _s('the parameter "%1$s" is missing', 'httpstepid') 745 )); 746 } 747 elseif (!array_key_exists($httpstep['httpstepid'], $db_httptest['steps'])) { 748 self::exception(ZBX_API_ERROR_PARAMETERS, 749 _('No permissions to referred object or it does not exist!') 750 ); 751 } 752 } 753 } 754 } 755 } 756 757 $this->checkStatusCodes($httptests); 758 $this->validateRetrieveMode($httptests, $method, $db_httptests); 759 } 760 761 /** 762 * Validate http response code range. 763 * Range can be empty string or list of comma separated numeric strings or user macros. 764 * 765 * Examples: '100-199, 301, 404, 500-550, {$MACRO}-200, {$MACRO}-{$MACRO}' 766 * 767 * @param array $httptests 768 * 769 * @throws APIException if the status code range is invalid. 770 */ 771 private function checkStatusCodes(array $httptests) { 772 $ranges_parser = new CRangesParser(['usermacros' => true]); 773 774 foreach ($httptests as $httptest) { 775 if (!array_key_exists('steps', $httptest)) { 776 continue; 777 } 778 779 foreach ($httptest['steps'] as $httpstep) { 780 if (!array_key_exists('status_codes', $httpstep) || $httpstep['status_codes'] === '') { 781 continue; 782 } 783 784 if ($ranges_parser->parse($httpstep['status_codes']) != CParser::PARSE_SUCCESS) { 785 self::exception(ZBX_API_ERROR_PARAMETERS, 786 _s('Invalid response code "%1$s".', $httpstep['status_codes']) 787 ); 788 } 789 } 790 } 791 } 792 793 protected function applyQueryOutputOptions($tableName, $tableAlias, array $options, array $sqlParts) { 794 $sqlParts = parent::applyQueryOutputOptions($tableName, $tableAlias, $options, $sqlParts); 795 796 if (!$options['countOutput']) { 797 // make sure we request the hostid to be able to expand macros 798 if ($options['expandName'] !== null || $options['expandStepName'] !== null || $options['selectHosts'] !== null) { 799 $sqlParts = $this->addQuerySelect($this->fieldId('hostid'), $sqlParts); 800 } 801 } 802 803 return $sqlParts; 804 } 805 806 protected function addRelatedObjects(array $options, array $result) { 807 $result = parent::addRelatedObjects($options, $result); 808 809 $httpTestIds = array_keys($result); 810 811 // adding headers and variables 812 $fields = [ 813 ZBX_HTTPFIELD_HEADER => 'headers', 814 ZBX_HTTPFIELD_VARIABLE => 'variables' 815 ]; 816 foreach ($fields as $type => $field) { 817 if (!$this->outputIsRequested($field, $options['output'])) { 818 unset($fields[$type]); 819 } 820 } 821 822 if ($fields) { 823 $db_httpfields = DB::select('httptest_field', [ 824 'output' => ['httptestid', 'name', 'value', 'type'], 825 'filter' => [ 826 'httptestid' => $httpTestIds, 827 'type' => array_keys($fields) 828 ], 829 'sortfield' => ['httptest_fieldid'] 830 ]); 831 832 foreach ($result as &$httptest) { 833 foreach ($fields as $field) { 834 $httptest[$field] = []; 835 } 836 } 837 unset($httptest); 838 839 foreach ($db_httpfields as $db_httpfield) { 840 $result[$db_httpfield['httptestid']][$fields[$db_httpfield['type']]][] = [ 841 'name' => $db_httpfield['name'], 842 'value' => $db_httpfield['value'] 843 ]; 844 } 845 } 846 847 // adding hosts 848 if ($options['selectHosts'] !== null && $options['selectHosts'] != API_OUTPUT_COUNT) { 849 $relationMap = $this->createRelationMap($result, 'httptestid', 'hostid'); 850 $hosts = API::Host()->get([ 851 'output' => $options['selectHosts'], 852 'hostid' => $relationMap->getRelatedIds(), 853 'nopermissions' => true, 854 'templated_hosts' => true, 855 'preservekeys' => true 856 ]); 857 $result = $relationMap->mapMany($result, $hosts, 'hosts'); 858 } 859 860 // adding steps 861 if ($options['selectSteps'] !== null) { 862 if ($options['selectSteps'] != API_OUTPUT_COUNT) { 863 $fields = [ 864 ZBX_HTTPFIELD_HEADER => 'headers', 865 ZBX_HTTPFIELD_VARIABLE => 'variables', 866 ZBX_HTTPFIELD_QUERY_FIELD => 'query_fields', 867 ZBX_HTTPFIELD_POST_FIELD => 'posts' 868 ]; 869 foreach ($fields as $type => $field) { 870 if (!$this->outputIsRequested($field, $options['selectSteps'])) { 871 unset($fields[$type]); 872 } 873 } 874 875 $db_httpsteps = API::getApiService()->select('httpstep', [ 876 'output' => $this->outputExtend($options['selectSteps'], ['httptestid', 'httpstepid', 'post_type']), 877 'filter' => ['httptestid' => $httpTestIds], 878 'preservekeys' => true 879 ]); 880 $relationMap = $this->createRelationMap($db_httpsteps, 'httptestid', 'httpstepid'); 881 882 if ($fields) { 883 foreach ($db_httpsteps as &$db_httpstep) { 884 foreach ($fields as $type => $field) { 885 if ($type != ZBX_HTTPFIELD_POST_FIELD || $db_httpstep['post_type'] == ZBX_POSTTYPE_FORM) { 886 $db_httpstep[$field] = []; 887 } 888 } 889 } 890 unset($db_httpstep); 891 892 $db_httpstep_fields = DB::select('httpstep_field', [ 893 'output' => ['httpstepid', 'name', 'value', 'type'], 894 'filter' => [ 895 'httpstepid' => array_keys($db_httpsteps), 896 'type' => array_keys($fields) 897 ], 898 'sortfield' => ['httpstep_fieldid'] 899 ]); 900 901 foreach ($db_httpstep_fields as $db_httpstep_field) { 902 $db_httpstep = &$db_httpsteps[$db_httpstep_field['httpstepid']]; 903 904 if ($db_httpstep_field['type'] != ZBX_HTTPFIELD_POST_FIELD 905 || $db_httpstep['post_type'] == ZBX_POSTTYPE_FORM) { 906 $db_httpstep[$fields[$db_httpstep_field['type']]][] = [ 907 'name' => $db_httpstep_field['name'], 908 'value' => $db_httpstep_field['value'] 909 ]; 910 } 911 } 912 unset($db_httpstep); 913 } 914 915 $db_httpsteps = $this->unsetExtraFields($db_httpsteps, ['httptestid', 'httpstepid', 'post_type'], 916 $options['selectSteps'] 917 ); 918 $result = $relationMap->mapMany($result, $db_httpsteps, 'steps'); 919 } 920 else { 921 $dbHttpSteps = DBselect( 922 'SELECT hs.httptestid,COUNT(hs.httpstepid) AS stepscnt'. 923 ' FROM httpstep hs'. 924 ' WHERE '.dbConditionInt('hs.httptestid', $httpTestIds). 925 ' GROUP BY hs.httptestid' 926 ); 927 while ($dbHttpStep = DBfetch($dbHttpSteps)) { 928 $result[$dbHttpStep['httptestid']]['steps'] = $dbHttpStep['stepscnt']; 929 } 930 } 931 } 932 933 return $result; 934 } 935 936 /** 937 * @param array $httptests 938 * @param string $method 939 * @param array $db_httptests 940 * 941 * @throws APIException if auth parameters are invalid. 942 */ 943 private function validateAuthParameters(array &$httptests, $method, array $db_httptests = null) { 944 foreach ($httptests as &$httptest) { 945 if (array_key_exists('authentication', $httptest) || array_key_exists('http_user', $httptest) 946 || array_key_exists('http_password', $httptest)) { 947 $httptest += [ 948 'authentication' => ($method === 'validateUpdate') 949 ? $db_httptests[$httptest['httptestid']]['authentication'] 950 : HTTPTEST_AUTH_NONE 951 ]; 952 953 if ($httptest['authentication'] == HTTPTEST_AUTH_NONE) { 954 foreach (['http_user', 'http_password'] as $field_name) { 955 $httptest += [$field_name => '']; 956 957 if ($httptest[$field_name] !== '') { 958 self::exception(ZBX_API_ERROR_PARAMETERS, 959 _s('Incorrect value for field "%1$s": %2$s.', $field_name, _('should be empty')) 960 ); 961 } 962 } 963 } 964 } 965 } 966 unset($httptest); 967 } 968 969 /** 970 * @param array $httptests 971 * @param string $method 972 * @param array $db_httptests 973 * 974 * @throws APIException if SSL cert is present but SSL key is not. 975 */ 976 private function validateSslParameters(array &$httptests, $method, array $db_httptests = null) { 977 foreach ($httptests as &$httptest) { 978 if (array_key_exists('ssl_key_password', $httptest) 979 || array_key_exists('ssl_key_file', $httptest) 980 || array_key_exists('ssl_cert_file', $httptest)) { 981 if ($method === 'validateCreate') { 982 $httptest += [ 983 'ssl_key_password' => '', 984 'ssl_key_file' => '', 985 'ssl_cert_file' => '' 986 ]; 987 } 988 else { 989 $db_httptest = $db_httptests[$httptest['httptestid']]; 990 $httptest += [ 991 'ssl_key_password' => $db_httptest['ssl_key_password'], 992 'ssl_key_file' => $db_httptest['ssl_key_file'], 993 'ssl_cert_file' => $db_httptest['ssl_cert_file'] 994 ]; 995 } 996 997 if ($httptest['ssl_key_password'] != '' && $httptest['ssl_key_file'] == '') { 998 self::exception(ZBX_API_ERROR_PARAMETERS, 999 _s('Empty SSL key file for web scenario "%1$s".', $httptest['name']) 1000 ); 1001 } 1002 1003 if ($httptest['ssl_key_file'] != '' && $httptest['ssl_cert_file'] == '') { 1004 self::exception(ZBX_API_ERROR_PARAMETERS, 1005 _s('Empty SSL certificate file for web scenario "%1$s".', $httptest['name']) 1006 ); 1007 } 1008 } 1009 } 1010 unset($httptest); 1011 } 1012 1013 /** 1014 * @param array $httptests 1015 * @param string $method 1016 * @param array $db_httptests 1017 * 1018 * @throws APIException if parameters is invalid. 1019 */ 1020 private function validateRetrieveMode(array &$httptests, $method, array $db_httptests = null) { 1021 foreach ($httptests as &$httptest) { 1022 if (!array_key_exists('steps', $httptest)) { 1023 continue; 1024 } 1025 1026 foreach ($httptest['steps'] as &$httpstep) { 1027 if (array_key_exists('retrieve_mode', $httpstep) 1028 || array_key_exists('posts', $httpstep) 1029 || array_key_exists('required', $httpstep)) { 1030 1031 if ($method === 'validateCreate' || !array_key_exists('httpstepid', $httpstep)) { 1032 $httpstep += [ 1033 'retrieve_mode' => HTTPTEST_STEP_RETRIEVE_MODE_CONTENT, 1034 'posts' => '', 1035 'required' => '' 1036 ]; 1037 } 1038 else { 1039 $db_httptest = $db_httptests[$httptest['httptestid']]; 1040 $db_httpstep = $db_httptest['steps'][$httpstep['httpstepid']]; 1041 $httpstep += ['retrieve_mode' => $db_httpstep['retrieve_mode']]; 1042 $httpstep += [ 1043 'posts' => ($httpstep['retrieve_mode'] == HTTPTEST_STEP_RETRIEVE_MODE_CONTENT) 1044 ? $db_httpstep['posts'] 1045 : '', 1046 'required' => ($httpstep['retrieve_mode'] == HTTPTEST_STEP_RETRIEVE_MODE_CONTENT) 1047 ? $db_httpstep['required'] 1048 : '' 1049 ]; 1050 } 1051 1052 if ($httpstep['retrieve_mode'] == HTTPTEST_STEP_RETRIEVE_MODE_HEADERS) { 1053 if (($httpstep['posts'] !== '' && $httpstep['posts'] !== []) || $httpstep['required'] !== '') { 1054 $field_name = $httpstep['required'] !== '' ? 'required' : 'posts'; 1055 1056 self::exception(ZBX_API_ERROR_PARAMETERS, 1057 _s('Incorrect value for field "%1$s": %2$s.', $field_name, _('should be empty')) 1058 ); 1059 } 1060 } 1061 } 1062 } 1063 unset($httpstep); 1064 } 1065 unset($httptest); 1066 } 1067 1068 /** 1069 * Convert string to HTTP pair array. 1070 * 1071 * @param string $data 1072 * @param string $delimiter 1073 * 1074 * @return mixed 1075 */ 1076 private function convertHTTPPairString($data, $delimiter) { 1077 /* converts to pair array */ 1078 $pairs = array_values(array_filter(explode("\n", str_replace("\r", "\n", $data)))); 1079 foreach ($pairs as &$pair) { 1080 $pair = explode($delimiter, $pair, 2); 1081 $pair = [ 1082 'name' => $pair[0], 1083 'value' => array_key_exists(1, $pair) ? $pair[1] : '' 1084 ]; 1085 } 1086 unset($pair); 1087 1088 return $pairs; 1089 } 1090 1091 /** 1092 * Convert headers and variables from string to HTTP pair array. 1093 * @deprecated conversion will be removed in future 1094 * 1095 * @param array $httptests 1096 * 1097 * @return array 1098 */ 1099 private function convertHttpPairs($httptests) { 1100 reset($httptests); 1101 1102 if (!is_int(key($httptests))) { 1103 $httptests = [$httptests]; 1104 } 1105 1106 $fields = [ 1107 'headers' => ':', 1108 'variables' => '=' 1109 ]; 1110 1111 foreach ($httptests as &$httptest) { 1112 foreach ($fields as $field => $delimiter) { 1113 if (is_array($httptest) && array_key_exists($field, $httptest) && is_string($httptest[$field])) { 1114 $this->deprecated('using string format for field "'.$field.'" is deprecated.'); 1115 $httptest[$field] = $this->convertHTTPPairString($httptest[$field], $delimiter); 1116 } 1117 } 1118 1119 if (array_key_exists('steps', $httptest) && is_array($httptest['steps'])) { 1120 foreach ($httptest['steps'] as &$step) { 1121 foreach ($fields as $field => $delimiter) { 1122 if (is_array($step) && array_key_exists($field, $step) && is_string($step[$field])) { 1123 $this->deprecated('using string format for field "'.$field.'" is deprecated.'); 1124 $step[$field] = $this->convertHTTPPairString($step[$field], $delimiter); 1125 } 1126 } 1127 } 1128 unset($step); 1129 } 1130 } 1131 unset($httptest); 1132 1133 return $httptests; 1134 } 1135} 1136