1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
ldap.php
См. документацию.
1<?php
2
7
14
15class CLDAP
16{
17 var $arFields, $arGroupList = false;
18 var $conn;
19
20 protected static $PHOTO_ATTRIBS = array("thumbnailPhoto", "jpegPhoto");
21 protected $arGroupMaps;
22 protected $groupsLists = array();
23
28
33
38
39 protected $isTlsStarted = false;
40
41 public function __construct($arFields = [])
42 {
43 $this->arFields = $arFields;
44 }
45
46 public function Connect()
47 {
48 global $APPLICATION;
49
50 $encryptionType = EncryptionType::tryFrom((int)$this->arFields['CONNECTION_TYPE']) ?? EncryptionType::None;
51 $port = (int)$this->arFields['PORT'] > 0 ? (int)$this->arFields['PORT'] : $encryptionType->port();
52 $host = str_starts_with($this->arFields['SERVER'], 'ldap://') || str_starts_with($this->arFields['SERVER'], 'ldaps://')
53 ? $this->arFields['SERVER']
54 : $encryptionType->scheme() . '://' . $this->arFields['SERVER'];
55
56 if ($this->conn = @ldap_connect("$host:$port"))
57 {
58 $ldapOptTimelimit = isset($this->arFields["LDAP_OPT_TIMELIMIT"]) ? (int)$this->arFields["LDAP_OPT_TIMELIMIT"] : 100;
59 $ldapOptTimeout = isset($this->arFields["LDAP_OPT_TIMEOUT"]) ? (int)$this->arFields["LDAP_OPT_TIMEOUT"] : 5;
60 $ldapOptNetworkTimeout = isset($this->arFields["LDAP_OPT_NETWORK_TIMEOUT"]) ? (int)$this->arFields["LDAP_OPT_NETWORK_TIMEOUT"] : 5;
61
62 @ldap_set_option($this->conn, LDAP_OPT_PROTOCOL_VERSION, 3);
63 @ldap_set_option($this->conn, LDAP_OPT_REFERRALS, 0);
64 @ldap_set_option($this->conn, LDAP_OPT_SIZELIMIT, COption::GetOptionInt("ldap", "group_limit", 0));
65 @ldap_set_option($this->conn, LDAP_OPT_TIMELIMIT, $ldapOptTimelimit);
66 @ldap_set_option($this->conn, LDAP_OPT_TIMEOUT, $ldapOptTimeout);
67 @ldap_set_option($this->conn, LDAP_OPT_NETWORK_TIMEOUT, $ldapOptNetworkTimeout);
68
69 $login = $this->arFields["~ADMIN_LOGIN"] ?? $this->arFields["ADMIN_LOGIN"];
70 $pass = $this->arFields["~ADMIN_PASSWORD"] ?? $this->arFields["ADMIN_PASSWORD"];
71
72 return $this->Bind($login, $pass);
73 }
74 else
75 {
76 $APPLICATION->ThrowException('ldap_connect() error. '.$this->getLastErrorDescription());
77 }
78
79 return false;
80 }
81
82 public function BindAdmin()
83 {
84 if($this->arFields["ADMIN_LOGIN"] == '')
85 return false;
86
87 return $this->Bind(
88 ($this->arFields["~ADMIN_LOGIN"] ?? $this->arFields["ADMIN_LOGIN"]),
89 ($this->arFields["~ADMIN_PASSWORD"] ?? $this->arFields["ADMIN_PASSWORD"])
90 );
91 }
92
93 public function Bind($login, $password)
94 {
95 if(!$this->conn)
96 return false;
97
98 global $APPLICATION;
99
100 if(mb_strpos($password, "\0") !== false || $password == '')
101 return false;
102
103 if(intval($this->arFields["CONNECTION_TYPE"]) === EncryptionType::Tls->value)
104 if(!$this->startTls())
105 return false;
106
107 if(!@ldap_bind($this->conn, $login, $password))
108 {
109 $APPLICATION->ThrowException('ldap_bind() error. '.$this->getLastErrorDescription());
110 return false;
111 }
112
113 return true;
114 }
115
116 protected function startTls()
117 {
118 global $APPLICATION;
119
120 if($this->isTlsStarted)
121 return true;
122
123 if(!@ldap_start_tls($this->conn))
124 {
125 $APPLICATION->ThrowException('ldap_start_tls() error. '.$this->getLastErrorDescription());
126 return false;
127 }
128
129 $this->isTlsStarted = true;
130 return true;
131 }
132
133 public function Disconnect()
134 {
135 ldap_close($this->conn);
136 }
137
141 public function RootDSE(): array
142 {
143 $values = $this->_RootDSE('namingcontexts');
144 if (!$values)
145 {
146 $values = $this->_RootDSE('namingContexts');
147 }
148
149 if (!$values)
150 {
151 return [];
152 }
153
154 unset($values['count']);
155
156 return $values;
157 }
158
163 public function _RootDSE($filtr)
164 {
165 $sr = ldap_read($this->conn, '', 'objectClass=*', Array($filtr));
166 if ($sr === false)
167 {
168 return false;
169 }
170
171 $entry = ldap_first_entry($this->conn, $sr);
172
173 $attributes = ldap_get_attributes($this->conn, $entry);
174 $values = false;
175
176 if ($attributes['count'] > 0)
177 $values = @ldap_get_values_len($this->conn, $entry, $filtr);
178 return $values;
179 }
180
181 public function WorkAttr($values)
182 {
183 if(is_array($values) && $values['count']==1)
184 {
185 return $values[0];
186 }
187
188 unset($values['count']);
189
190 return $values;
191 }
192
193 public function QueryArray($str = '(ObjectClass=*)', $fields = false)
194 {
195 global $APPLICATION;
196
197 if($this->arFields['BASE_DN'] == '')
198 return false;
199
200 $arBaseDNs = explode(";", $this->arFields['BASE_DN']);
201 $info = false;
202 $i=0;
203
204 foreach($arBaseDNs as $BaseDN)
205 {
206 $BaseDN = trim($BaseDN);
207 if($BaseDN == "")
208 continue;
209
210 $defaultMaxPageSizeAD = 1000;
211 $pageSize = isset($this->arFields['MAX_PAGE_SIZE']) && intval($this->arFields['MAX_PAGE_SIZE'] > 0) ? intval($this->arFields['MAX_PAGE_SIZE']) : $defaultMaxPageSizeAD;
212 $cookie = '';
213
214 do
215 {
216 $searchAttributes = is_array($fields) ? $fields : [];
217 $searchControls = null;
219 {
220 $searchControls = [
221 ['oid' => LDAP_CONTROL_PAGEDRESULTS, 'value' => ['size' => $pageSize, 'cookie' => $cookie]],
222 ];
223 }
224
225 $sr = @ldap_search(
226 $this->conn,
227 $BaseDN,
228 $str,
229 $searchAttributes,
230 0,
231 -1,
232 -1,
233 LDAP_DEREF_NEVER,
234 $searchControls
235 );
236
237 if ($sr)
238 {
240 {
241 ldap_parse_result(
242 $this->conn,
243 $sr,
244 $error_code,
245 $matched_dn,
246 $error_message,
247 $referrals,
248 $controls
249 );
250 $cookie = $controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'] ?? '';
251 }
252
253 $entry = ldap_first_entry($this->conn, $sr);
254
255 if($entry)
256 {
257 if(!is_array($info))
258 {
259 $info = Array();
260 $i=0;
261 }
262
263 do
264 {
265 $attributes = ldap_get_attributes($this->conn, $entry);
266
267 for($j=0; $j<$attributes['count']; $j++)
268 {
269 $values = @ldap_get_values_len($this->conn, $entry, $attributes[$j]);
270
271 if($values === false)
272 continue;
273
274 $bPhotoAttr = in_array($attributes[$j], self::$PHOTO_ATTRIBS);
275 $info[$i][mb_strtolower($attributes[$j])] = $bPhotoAttr ? $values : $this->WorkAttr($values);
276 }
277 if(!is_set($info[$i], 'dn'))
278 {
279 $info[$i]['dn'] = ldap_get_dn($this->conn, $entry);
280 }
281 $i++;
282
283 }
284 while($entry = ldap_next_entry($this->conn, $entry));
285 }
286 }
287 elseif($sr === false)
288 {
289 $APPLICATION->ThrowException("LDAP_SEARCH_ERROR");
290 }
291
292 } while($cookie !== null && $cookie != '');
293 }
294
295 return $info;
296 }
297
298 public function Query($str = '(ObjectClass=*)', $fields = false)
299 {
300 $info = $this->QueryArray($str, $fields);
301 $info = is_array($info) ? $info : [];
302 $result = new CDBResult;
303 $result->InitFromArray($info);
304 return $result;
305 }
306
307 protected function setFieldAsAttr(array $attrArray, $fieldName)
308 {
309 $field = $this->arFields["~" . $fieldName] ?? $this->arFields[$fieldName];
310 $field = mb_strtolower($field);
311
312 if(!in_array($field, $attrArray))
313 $attrArray[] = $field;
314
315 return $attrArray;
316 }
317
318 // query for group list from AD - server
319 public function GetGroupListArray($query = '')
320 {
321 $group_filter = $this->arFields['GROUP_FILTER'];
322 if(trim($group_filter) <> '' && mb_substr(trim($group_filter), 0, 1) != '(')
323 $group_filter = '('.trim($group_filter).')';
324 $query = '(&'.$group_filter.$query.')';
325
326 if (!array_key_exists($query, $this->groupsLists))
327 {
328 $this->BindAdmin();
329
330 $arGroupAttr = array(
331 "name", "cn", "gidNumber", "description", "memberof",
332 "primarygrouptoken", "primarygroupid", "samaccountname",
333 "distinguishedname"
334 );
335
336 foreach(array("GROUP_ID_ATTR", "GROUP_NAME_ATTR", "GROUP_MEMBERS_ATTR") as $fieldName)
337 $arGroupAttr = $this->setFieldAsAttr($arGroupAttr, $fieldName);
338
339 if ($this->arFields['USER_GROUP_ACCESSORY'] == 'Y')
340 $arGroupAttr = $this->setFieldAsAttr($arGroupAttr, "USER_GROUP_ATTR");
341
342 $arGroupsTmp = $this->QueryArray($query, $arGroupAttr);
343
344 if (!$arGroupsTmp)
345 return false;
346
347 $arGroups = array();
348 $group_id_attr = mb_strtolower($this->arFields['GROUP_ID_ATTR']);
349
350 if(is_set($this->arFields, 'GROUP_NAME_ATTR'))
351 $group_name_attr = mb_strtolower($this->arFields['GROUP_NAME_ATTR']);
352 else
353 $group_name_attr = false;
354
355 foreach ($arGroupsTmp as $grp)
356 {
357 $grp['ID'] = $grp[$group_id_attr];
358
359 if ($group_name_attr && is_set($grp, $group_name_attr))
360 $grp['NAME'] = $grp[$group_name_attr];
361
362 $arGroups[$grp['ID']] = $grp;
363 }
364
365 $this->groupsLists[$query] = $arGroups;
366 }
367
368 return $this->groupsLists[$query];
369 }
370
371 public function GetGroupList($query = '')
372 {
374 $result = new CDBResult();
375 $result->InitFromArray($arGroups);
376
377 return $result;
378 }
379
380 protected static function isApplicationPassword(string $login, string $password, bool $isPasswordOriginal): bool
381 {
382 if(!ApplicationPasswordTable::isPassword($password))
383 {
384 return false;
385 }
386
387 $externalUserId = static::OnFindExternalUser($login);
388
389 if($externalUserId <= 0)
390 {
391 return false;
392 }
393
394 return ApplicationPasswordTable::findPassword($externalUserId, $password, $isPasswordOriginal) !== false;
395 }
396
397 public static function OnUserLogin(&$arArgs)
398 {
399 global $APPLICATION;
400
401 if(!function_exists("ldap_connect"))
402 {
403 return 0;
404 }
405
406 $login = (string)$arArgs["LOGIN"];
407 $password = (string)$arArgs["PASSWORD"];
408
409 if($login === '' || $password === '')
410 {
411 return 0;
412 }
413
414 $isPasswordOriginal = isset($arArgs["PASSWORD_ORIGINAL"]) && $arArgs["PASSWORD_ORIGINAL"] === "Y";
415
416 if(static::isApplicationPassword($login, $password, $isPasswordOriginal))
417 {
418 return 0;
419 }
420
421 $filter = ["ACTIVE" => "Y"];
422 $prefix = mb_strpos($login, "\\");
423
424 if($prefix===false && COption::GetOptionString("ldap", "ntlm_auth_without_prefix", "Y") !== "Y")
425 {
426 return 0;
427 }
428
429 if($prefix > 0)
430 {
431 $filter["CODE"] = mb_substr($login, 0, $prefix);
432 $login = mb_substr($login, $prefix + 1);
433 }
434
435 $params = [
436 "LOGIN" => &$login,
437 "PASSWORD" => &$password,
438 "LDAP_FILTER" => &$filter,
439 ];
440
441 $APPLICATION->ResetException();
442 foreach(GetModuleEvents("ldap", "OnBeforeUserLogin", true) as $arEvent)
443 {
444 if(ExecuteModuleEventEx($arEvent, [&$params]) === false)
445 {
446 if($err = $APPLICATION->GetException())
447 {
448 $arArgs['RESULT_MESSAGE'] = ["MESSAGE"=>$err->GetString()."<br>", "TYPE"=>"ERROR"];
449 }
450 else
451 {
452 $APPLICATION->ThrowException("Unknown error");
453 $arArgs['RESULT_MESSAGE'] = ["MESSAGE"=>"Unknown error"."<br>", "TYPE"=>"ERROR"];
454 }
455
456 return 0;
457 }
458 }
459
467 $otp = (string)($arArgs["OTP"] ?? '');
468
469 if ($otp !== '' && mb_substr($password, -6) === $otp)
470 {
471 $password = mb_substr($password, 0, -6);
472 }
473
474 $userId = 0;
476
477 while($xLDAP = $dbRes->GetNextServer())
478 {
479 if($xLDAP->Connect())
480 {
481 $arLdapUser = false;
482
483 if($otp !== '')
484 {
485 $arLdapUser = $xLDAP->FindUser($login, $password.$otp);
486 }
487
488 if(!$arLdapUser && $password !== '')
489 {
490 $arLdapUser = $xLDAP->FindUser($login, $password);
491 }
492
493 // user AD parameters are queried here, inside FindUser function
494 if($arLdapUser)
495 {
496 $userId = $xLDAP->SetUser(
497 $arLdapUser,
498 (COption::GetOptionString("ldap", "add_user_when_auth", "Y") === "Y")
499 );
500
501 $xLDAP->Disconnect();
502
503 if ($userId > 0)
504 {
505 $arArgs["STORE_PASSWORD"] = "N";
506 break;
507 }
508
509 if(\Bitrix\Ldap\Limit::isUserLimitExceeded())
510 {
511 $arArgs['RESULT_MESSAGE'] = \Bitrix\Ldap\Limit::getUserLimitNotifyMessage();
512 break;
513 }
514 }
515 else
516 {
517 $xLDAP->Disconnect();
518 }
519 }
520 }
521
522 return $userId;
523 }
524
525 // this function is called on user logon (either normal or ntlm) to find user in ldap
526 public function FindUser($LOGIN, $PASSWORD = false)
527 {
528 $login_field = $LOGIN;
529 $password_field = $PASSWORD;
530
531 $this->BindAdmin();
532
533 $user_filter = "(&".$this->arFields["~USER_FILTER"]."(".$this->arFields["~USER_ID_ATTR"]."=".$this->specialchars($login_field)."))";
534 $dbLdapUsers = $this->Query($user_filter);
535 if (!$dbLdapUsers)
536 return false;
537
538 if($arLdapUser = $dbLdapUsers->Fetch())
539 {
540 if($PASSWORD !== false) // also check auth
541 {
542 $user_dn = $arLdapUser['dn'];
543
544 if (!$this->Bind($user_dn, $password_field))
545 return false;
546 }
547
548 return $this->GetUserFields($arLdapUser);
549 }
550
551 return false;
552 }
553
559 public function getLdapValueByBitrixFieldName($fieldName, $arLdapUser)
560 {
561 global $USER_FIELD_MANAGER;
562 if(!isset($this->arFields["FIELD_MAP"][$fieldName]))
563 return false;
564
565 $attr = $this->arFields["FIELD_MAP"][$fieldName];
566 $arRes = $USER_FIELD_MANAGER->GetUserFields("USER", 0, LANGUAGE_ID);
567 $result = false;
568
569 if(is_array($arRes[$fieldName]))
570 {
571 if($arRes[$fieldName]["MULTIPLE"]=="Y")
572 {
573 if (is_array($arLdapUser[mb_strtolower($attr)]))
574 $result = array_values($arLdapUser[mb_strtolower($attr)]);
575 else
576 $result = array($arLdapUser[mb_strtolower($attr)]);
577 }
578 else if (!empty($arLdapUser[mb_strtolower($attr)]))
579 $result = $arLdapUser[mb_strtolower($attr)];
580 else if (!empty($arRes[$fieldName]['SETTINGS']['DEFAULT_VALUE']))
581 {
582 if (is_array($arRes[$fieldName]['SETTINGS']['DEFAULT_VALUE']))
583 {
584 if (!empty($arRes[$fieldName]['SETTINGS']['DEFAULT_VALUE']['VALUE']))
585 $result = $arRes[$fieldName]['SETTINGS']['DEFAULT_VALUE']['VALUE'];
586 }
587 else
588 $result = $arRes[$fieldName]['SETTINGS']['DEFAULT_VALUE'];
589 }
590
591 }
592 elseif(preg_match("/(.*)&([0-9]+)/", $attr, $arMatch))
593 {
594 if(intval($arLdapUser[mb_strtolower($arMatch[1])]) & intval($arMatch[2]))
595 $result = "N";
596 else
597 $result = "Y";
598 }
599 elseif ($fieldName == "PERSONAL_PHOTO")
600 {
601 if($arLdapUser[mb_strtolower($attr)] == "")
602 return false;
603
604 $fExt = CLdapUtil::GetImgTypeBySignature($arLdapUser[mb_strtolower($attr)][0]);
605
606 if(!$fExt)
607 return false;
608
609 $tmpDir = CTempFile::GetDirectoryName();
610 CheckDirPath($tmpDir);
611
612 $fname = "ad_".rand().".".$fExt;
613
614 if(!file_put_contents($tmpDir.$fname,$arLdapUser[mb_strtolower($attr)][0]))
615 return false;
616
617 $result = array(
618 "name" => $fname,
619 "type" => CFile::GetContentType($tmpDir.$fname),
620 "tmp_name" => $tmpDir.$fname
621 );
622 }
623 else
624 $result = $arLdapUser[mb_strtolower($attr)];
625
626 if(is_null($result))
627 $result = false;
628
629 return $result;
630 }
631
632 public static function OnFindExternalUser($login)
633 {
634 $login = (string)$login;
635
636 if($login === '')
637 {
638 return 0;
639 }
640
641 // Hit cache
642 static $result = [];
643
644 if(isset($result[$login]))
645 {
646 return $result[$login];
647 }
648
649 $filter = ["ACTIVE" => "Y"];
650 $prefix = mb_strpos($login, "\\");
651
652 if($prefix === false && COption::GetOptionString("ldap", "ntlm_auth_without_prefix", "Y") !== "Y")
653 {
654 return 0;
655 }
656
657 if($prefix > 0)
658 {
659 $filter["CODE"] = mb_substr($login, 0, $prefix);
660 $login = mb_substr($login, $prefix + 1);
661 }
662
663 $userId = 0;
664
665 $dbServ = CLdapServer::GetList([], $filter);
666
667 while($serv = $dbServ->GetNextServer())
668 {
669 if($serv->Connect())
670 {
671 if($arLdapUser = $serv->FindUser($login))
672 {
673 $userId = $serv->SetUser(
674 $arLdapUser,
675 (COption::GetOptionString("ldap", "add_user_when_auth", "Y") === "Y")
676 );
677 }
678
679 $serv->Disconnect();
680
681 if($userId > 0)
682 {
683 break;
684 }
685 }
686 }
687
689 return $userId;
690 }
691
692 // converts LDAP values to those suitable for user fields
693 public function GetUserFields($arLdapUser, &$departmentCache=FALSE)
694 {
695 global $APPLICATION;
696
698 'DN' => $arLdapUser['dn'],
699 'LOGIN' => $arLdapUser[mb_strtolower($this->arFields['~USER_ID_ATTR'])],
700 'EXTERNAL_AUTH_ID' => 'LDAP#'.$this->arFields['ID'],
701 'LDAP_GROUPS' => $arLdapUser[mb_strtolower($this->arFields['~USER_GROUP_ATTR'])],
702 );
703
704 // for each field, do the conversion
705
706 foreach($this->arFields["FIELD_MAP"] as $userField=>$attr)
707 $arFields[$userField] = $this->getLdapValueByBitrixFieldName($userField, $arLdapUser);
708
709 $APPLICATION->ResetException();
710 $db_events = GetModuleEvents("ldap", "OnLdapUserFields");
711 while($arEvent = $db_events->Fetch())
712 {
713 $arParams = array(array(&$arFields, &$arLdapUser));
714 if(ExecuteModuleEventEx($arEvent, $arParams)===false)
715 {
716 if(!$APPLICATION->GetException())
717 $APPLICATION->ThrowException("Unknown error");
718 return false;
719 }
720 $arFields = $arParams[0][0];
721 }
722
723 // set a department field, if needed
724 if (empty($arFields['UF_DEPARTMENT']) && isModuleInstalled('intranet')
725 && $this->arFields['IMPORT_STRUCT'] && $this->arFields['IMPORT_STRUCT']=='Y')
726 {
727 //$arLdapUser[$this->arFields['USER_DN_ATTR']]
728 $username = $arLdapUser[$this->arFields['USER_ID_ATTR']];
729 if ($arDepartment = $this->GetDepartmentIdForADUser($arLdapUser[$this->arFields['USER_DEPARTMENT_ATTR']],$arLdapUser[$this->arFields['USER_MANAGER_ATTR']],$username,$departmentCache))
730 {
731 // fill in cache. it is done outside the function because it has many exit points
732 if ($departmentCache)
733 $departmentCache[$username] = $arDepartment;
734
735 // this is not final assignment
736 // $arFields['UF_DEPARTMENT'] sould contain array of department ids,
737 // but somehow we have to return an information whether this user is a department head,
738 // so we'll save this data here temporarily
739 $arFields['UF_DEPARTMENT'] = $arDepartment;
740 }
741 else
742 {
743 $arFields['UF_DEPARTMENT'] = array();
744 }
745
746 // at this point $arFields['UF_DEPARTMENT'] should be set to some value, even an empty array is ok
747 }
748
749 if (!is_array($arFields['LDAP_GROUPS']))
750 $arFields['LDAP_GROUPS'] = (!empty($arFields['LDAP_GROUPS']) ? array($arFields['LDAP_GROUPS']) : array());
751
752 $primarygroupid_name_attr = 'primarygroupid';
753 $primarygrouptoken_name_attr = 'primarygrouptoken';
754
755 $groupMemberAttr = null;
756 $userIdAttr = null;
757
758 if ($this->arFields['USER_GROUP_ACCESSORY'] == 'Y')
759 {
760 $primarygroupid_name_attr = mb_strtolower($this->arFields['GROUP_ID_ATTR']);
761 $primarygrouptoken_name_attr = mb_strtolower($this->arFields['USER_GROUP_ATTR']);
762 $userIdAttr = mb_strtolower($this->arFields['USER_ID_ATTR']);
763 $groupMemberAttr = mb_strtolower($this->arFields['GROUP_MEMBERS_ATTR']);
764 }
765
766 $arAllGroups = $this->GetGroupListArray();
767
768 if (!is_array($arAllGroups) || count($arAllGroups) <= 0)
769 return $arFields;
770
771 $arGroup = reset($arAllGroups);
772
773 do
774 {
775 if(in_array($arGroup['ID'], $arFields['LDAP_GROUPS']))
776 continue;
777
778 if (
779 (is_set($arLdapUser, $primarygroupid_name_attr)
780 && $arGroup[$primarygrouptoken_name_attr] == $arLdapUser[$primarygroupid_name_attr]
781 )
782 ||
783 ($this->arFields['USER_GROUP_ACCESSORY'] == 'Y'
784 && is_set($arGroup, $groupMemberAttr)
785 && (
786 (is_array($arGroup[$groupMemberAttr])
787 && in_array($arLdapUser[$userIdAttr], $arGroup[$groupMemberAttr])
788 )
789 ||
790 $arLdapUser[$userIdAttr] == $arGroup[$groupMemberAttr]
791 )
792 )
793 )
794
795 {
796 $arFields['LDAP_GROUPS'][] = $arGroup['ID'];
797 if ($this->arFields['USER_GROUP_ACCESSORY'] == 'N')
798 break;
799 }
800 }
801 while ($arGroup = next($arAllGroups));
802
803 return $arFields;
804 }
805
806 // Gets department ID for AD user. If department doesn't exist, creates a new one. Returns FALSE if there should be no department set.
807 // returns array:
808 // 'ID' - department id
809 // 'IS_HEAD' - true if this user is head of the department, false if not
810 public function GetDepartmentIdForADUser($department, $managerDN, $username, &$cache=FALSE, $iblockId = FALSE, $names = FALSE)
811 {
812 global $USER_FIELD_MANAGER;
813
814 // check for loops in manager structure, if loop is found - quit
815 // should be done before cache lookup
816 if ($names && isset($names[$username]))
817 return false;
818
819 // if department id for this user is already stored in cache
820 if ($cache)
821 {
822 $departmentCached = $cache[$username];
823 // if user was not set as head earlier, then do not get his id from cache
824 if ($departmentCached)
825 return $departmentCached;
826 }
827
828 // if it is a first call in recursive chain
829 if (!$iblockId)
830 {
831 // check module inclusions
832 if (!IsModuleInstalled('intranet') || !CModule::IncludeModule('iblock'))
833 return false;
834
835 // get structure's iblock id
836 $iblockId=COption::GetOptionInt("intranet", "iblock_structure", false);
837 if (!$iblockId)
838 return false;
839
840 $names = array();
841 }
842
843 // save current username as already visited
844 $names[$username] = true;
845
846 $arManagerDep = null;
847 $mgrDepartment = null;
848
849 // if there's a manager - query it
850 if ($managerDN)
851 {
852 preg_match('/^((CN|uid)=.*?)(\,){1}([^\,])*(=){1}/i', $managerDN, $matches); //Extract "CN=User Name" from full name
853 $user = isset($matches[1]) ? str_replace('\\', '',$matches[1]) : "";
854 $userArr = $this->GetUserArray($user);
855
856 if (is_array($userArr) && count($userArr) > 0)
857 {
858 foreach($userArr as $possibleManager)
859 {
860 if(!isset($possibleManager['dn']) || $managerDN != $possibleManager['dn'])
861 {
862 continue;
863 }
864
865 // contents of userArr are already in local encoding, no need for conversion here
866 $mgrDepartment = $possibleManager[$this->arFields['USER_DEPARTMENT_ATTR']];
867 if ($mgrDepartment && trim($mgrDepartment)!='')
868 {
869 // if manager's department name is set - then get its id
870 $mgrManagerDN = $possibleManager[$this->arFields['USER_MANAGER_ATTR']];
871 $mgrUserName = $possibleManager[$this->arFields['USER_ID_ATTR']];
872 $arManagerDep = $this->GetDepartmentIdForADUser($mgrDepartment, $mgrManagerDN, $mgrUserName, $cache, $iblockId, $names);
873 // fill in cache
874 if ($cache && $arManagerDep)
875 $cache[$mgrUserName] = $arManagerDep;
876 }
877 }
878 }
879 }
880
881 // prepare result and create department (if needed)
883 'IS_HEAD' => ($this->arFields['SET_DEPARTMENT_HEAD'] == 'Y')
884 );
885
886 if ($arManagerDep)
887 {
888 // if got manager's data correctly
889 if ($department && trim($department)!='' && ($mgrDepartment!=$department))
890 {
891 // if our department is set && differs from manager's, set manager's as parent
892 $parentSectionId = $arManagerDep['ID'];
893 }
894 else
895 {
896 // - if user has no department, but somehow have manager - then he is assumed to be in manager's department
897 // - if user has same department name as manager - then he is not head
898 // here we can return manager's department id immediately
899 $arResult = $arManagerDep;
900 $arResult['IS_HEAD'] = false;
901 return $arResult;
902 }
903 }
904 else
905 {
906 // if there's no manager's data
907 if ($department && trim($department)!='')
908 {
909 $parentSectionId = $this->arFields['ROOT_DEPARTMENT'];
910 }
911 else
912 {
913 // if no manager's department and no own department:
914 // - use default as our department and root as parent section if default is set
915 // - or just root if default has empty value
916 // - or return false, if setting of default department is turned off
917 if ($this->arFields['STRUCT_HAVE_DEFAULT'] && $this->arFields['STRUCT_HAVE_DEFAULT'] == "Y")
918 {
919 // can use default department
920 $department = $this->arFields['DEFAULT_DEPARTMENT_NAME'];
921 if ($department && trim($department)!='')
922 {
923 // if department is not empty
924 $parentSectionId = $this->arFields['ROOT_DEPARTMENT'];
925 }
926 else
927 {
928 // if it is empty - return parent
929 return array('ID' => $this->arFields['ROOT_DEPARTMENT']);
930 }
931 }
932 else
933 {
934 // if no department in AD and no default - then do not set a department
935 return false;
936 }
937 }
938 }
939 // 3. if there's no department set for this user, this means there was no default department name (which substituted in *) - then there's no need to set department id for this user at all
940 if (!$department || trim($department)=='')
941 return false;
942
943 // 4. detect this user's department ID, using parent id and department name string, which we certainly have now (these 2 parameters are required to get an ID)
944
945 // see if this department already exists
946 $bs = new CIBlockSection();
947 $dbExistingSections = GetIBlockSectionList(
948 $iblockId,
949 ($parentSectionId >= 0 ? $parentSectionId : false),
950 Array("left_margin" => "asc"),
951 0,
952 Array('NAME' => $department)
953 );
954
955 $departmentId = false;
956 if($arItem = $dbExistingSections->GetNext())
957 $departmentId = $arItem['ID'];
958 if (!$departmentId)
959 {
960 //create new department
961 $arNewSectFields = Array(
962 "ACTIVE" => "Y",
963 "IBLOCK_ID" => $iblockId,
964 "NAME" => $department
965 );
966 if ($parentSectionId>=0)
967 $arNewSectFields["IBLOCK_SECTION_ID"] = $parentSectionId;
968 // and get its ID
969 $departmentId = $bs->Add($arNewSectFields);
970 }
971
972 $arElement = $USER_FIELD_MANAGER->GetUserFields(
973 'IBLOCK_'.$iblockId.'_SECTION',
974 $departmentId
975 );
976
977 // if the head of the department is already set, do not change it
978 if (!empty($arElement['UF_HEAD']['VALUE']))
979 $arResult['IS_HEAD'] = false;
980
981 $arResult['ID'] = $departmentId;
982 return $arResult;
983 }
984
985
986 // get user list (with attributes) from AD server
987 public function GetUserList($arFilter = Array())
988 {
989 $query = '';
990 foreach($arFilter as $key=>$value)
991 {
992 $key = mb_strtoupper($key);
993 switch($key)
994 {
995 case 'GROUP_ID':
996 //"SELECT ".
997 // "FROM "
998
999 case 'GROUP_DN':
1000 $temp = '';
1001 if(!is_array($value))
1002 $value = array($value);
1003 foreach($value as $group)
1004 {
1005 if($group == '')
1006 continue;
1007 $temp .= '('.$this->arFields['USER_GROUP_ATTR'].'='.$this->specialchars($group).')';
1008 }
1009 $query .= '(|'.$temp.')';
1010 break;
1011 }
1012 }
1013
1014 $user_filter = $this->arFields['USER_FILTER'];
1015 if(trim($user_filter) <> '' && mb_substr(trim($user_filter), 0, 1) != '(')
1016 $user_filter = '('.trim($user_filter).')';
1017 $query = '(&'.$user_filter.$query.')';
1018 $arResult = $this->Query($query);
1019 return $arResult;
1020 }
1021
1022 public function GetUserArray($cn)
1023 {
1024 $user_filter = $this->arFields['USER_FILTER'];
1025
1026 if(trim($user_filter) <> '' && mb_substr(trim($user_filter), 0, 1) != '(')
1027 {
1028 $user_filter = '('.trim($user_filter).')';
1029 }
1030
1031 $query = '(&'.$user_filter.'('.$cn.'))';
1032 return $this->QueryArray($query);
1033 }
1034
1035 public function specialchars($str)
1036 {
1037 $from = Array("\\", ',', '+', '"', '<', '>', ';', "\n", "\r", '=', '*');
1038 $to = Array('\5C', '\2C', '\2B', '\22', '\3C', '\3E', '\3B', '\0A', '\0D', '\3D', '\*');
1039 return str_replace($from, $to, $str);
1040 }
1041
1042 public static function OnExternalAuthList()
1043 {
1044 $arResult = Array();
1045 $db_ldap_serv = CLdapServer::GetList();
1046 while($arLDAP = $db_ldap_serv->Fetch())
1047 {
1048 $arResult[] = Array(
1049 'ID' => 'LDAP#'.$arLDAP['ID'],
1050 'NAME' => $arLDAP['NAME']
1051 );
1052 }
1053 return $arResult;
1054 }
1055
1056 public static function NTLMAuth()
1057 {
1058 global $USER;
1059
1060 if($USER->IsAuthorized())
1061 return;
1062
1063 if(!array_key_exists("AUTH_TYPE", $_SERVER) || ($_SERVER["AUTH_TYPE"] != "NTLM" && $_SERVER["AUTH_TYPE"] != "Negotiate"))
1064 return;
1065
1066 $ntlm_varname = trim(COption::GetOptionString('ldap', 'ntlm_varname', 'REMOTE_USER'));
1067 $LOGIN = isset($_SERVER[$ntlm_varname]) ? (string)$_SERVER[$ntlm_varname] : '';
1068
1069 if($LOGIN !== '')
1070 {
1071 $DOMAIN = "";
1072
1073 if(($pos = mb_strpos($LOGIN, "\\")) !== false)
1074 {
1075 $DOMAIN = mb_substr($LOGIN, 0, $pos);
1076 $LOGIN = mb_substr($LOGIN, $pos + 1);
1077 }
1078 elseif($_SERVER["AUTH_TYPE"] == "Negotiate" && (($pos = mb_strpos($LOGIN, "@")) !== false))
1079 {
1080 $DOMAIN = mb_substr($LOGIN, $pos + 1);
1081 $LOGIN = mb_substr($LOGIN, 0, $pos);
1082 }
1083
1084 $arFilterServer = array('ACTIVE' => 'Y');
1085
1086 if($DOMAIN <> '')
1087 {
1088 $arFilterServer['CODE'] = $DOMAIN;
1089 }
1090 else
1091 {
1092 $DEF_DOMAIN_ID = COption::GetOptionInt('ldap', 'ntlm_default_server', 0);
1093 if($DEF_DOMAIN_ID > 0)
1094 $arFilterServer['ID'] = $DEF_DOMAIN_ID;
1095 else
1096 return;
1097 }
1098
1099 $db_ldap_serv = CLdapServer::GetList(Array(), $arFilterServer);
1100
1101 /*@var $xLDAP CLDAP*/
1102 while($xLDAP = $db_ldap_serv->GetNextServer())
1103 {
1104 if($xLDAP->Connect())
1105 {
1106 if($arLdapUser = $xLDAP->FindUser($LOGIN))
1107 {
1108 $ID = $xLDAP->SetUser($arLdapUser, (COption::GetOptionString("ldap", "add_user_when_auth", "Y")=="Y"));
1109
1110 if($ID > 0)
1111 {
1112 $USER->Authorize($ID);
1113 $xLDAP->Disconnect();
1114 return;
1115 }
1116 }
1117
1118 $xLDAP->Disconnect();
1119 }
1120 }
1121 }
1122 }
1123
1132 public function GetAllMemberOf($arFindGroups, &$arUserGroups, $arAllGroups)
1133 {
1134 if(!$arFindGroups || $arFindGroups=='')
1135 return;
1136
1137 if(!is_array($arFindGroups))
1138 $arFindGroups = Array($arFindGroups);
1139
1140 foreach($arFindGroups as $group_id)
1141 {
1142 if(in_array($group_id, $arUserGroups))
1143 continue;
1144
1145 $arUserGroups[] = $group_id;
1146 $this->GetAllMemberOf($arAllGroups[$group_id]["memberof"], $arUserGroups, $arAllGroups);
1147 }
1148 }
1149
1150 public function GetGroupMaps()
1151 {
1152 global $DB;
1153
1154 if(!is_array($this->arGroupMaps))
1155 {
1156 $this->arGroupMaps = array();
1157 $rsCorellations = $DB->Query("SELECT LDAP_GROUP_ID, GROUP_ID FROM b_ldap_group WHERE LDAP_SERVER_ID=".intval($this->arFields['ID']));
1158
1159 while ($arCorellation = $rsCorellations->Fetch())
1160 {
1161 if(!is_array($this->arGroupMaps[$arCorellation["LDAP_GROUP_ID"]]))
1162 $this->arGroupMaps[$arCorellation["LDAP_GROUP_ID"]] = array();
1163
1164 $this->arGroupMaps[$arCorellation["LDAP_GROUP_ID"]][] = $arCorellation["GROUP_ID"];
1165 }
1166 }
1167
1168 return $this->arGroupMaps;
1169 }
1170
1171 //Need this to delete old photo
1172 public static function PrepareUserPhoto($uid, &$arLdapUser)
1173 {
1174 if(!isset($arLdapUser["PERSONAL_PHOTO"]))
1175 return false;
1176
1177 $dbRes = CUser::GetById($uid);
1178 $arUser = $dbRes->Fetch();
1179
1180 if(!isset($arUser["PERSONAL_PHOTO"]))
1181 return false;
1182
1183 if($arLdapUser["PERSONAL_PHOTO"] == "")
1184 $arLdapUser["PERSONAL_PHOTO"]["del"] = "Y";
1185
1186 $arLdapUser["PERSONAL_PHOTO"]["old_file"] = $arUser["PERSONAL_PHOTO"];
1187
1188 return true;
1189 }
1190
1191 // update user info, using previously loaded data from AD, make additional calls to AD if needed
1192 public function SetUser($arLdapUser, $bAddNew = true)
1193 {
1194 global $USER;
1195
1196 $isHead = false;
1197 $bUSERGen = false;
1198 $userActive = '';
1199
1200 if(!is_object($USER))
1201 {
1202 $USER = new CUser();
1203 $bUSERGen = true;
1204 }
1205
1206 // process previously saved department data
1207 if (IsModuleInstalled('intranet') && is_array($arLdapUser['UF_DEPARTMENT']))
1208 {
1209 $isHead = $arLdapUser['UF_DEPARTMENT']['IS_HEAD'];
1210 // replace temporary value with a real one
1211 $arLdapUser['UF_DEPARTMENT'] = array($arLdapUser['UF_DEPARTMENT']['ID']);
1212 }
1213
1214 if(isset($arLdapUser["ID"]))
1215 {
1216 $ID = intval($arLdapUser["ID"]);
1217 self::PrepareUserPhoto($ID,$arLdapUser);
1218 $USER->Update($ID, $arLdapUser);
1219 }
1220 else
1221 {
1222 $ldapUserID = 0;
1223 $bitrixUserId = 0;
1224 $res = CUser::GetList(
1225 "", "",
1226 array('LOGIN_EQUAL_EXACT' => $arLdapUser['LOGIN']),
1227 array('FIELDS' => array('ID', 'EXTERNAL_AUTH_ID', 'ACTIVE'))
1228 );
1229
1230 while($ar_res = $res->Fetch())
1231 {
1232 if($ar_res['EXTERNAL_AUTH_ID'] == $arLdapUser['EXTERNAL_AUTH_ID'])
1233 {
1234 $bitrixUserId = $ar_res['ID'];
1235 $userActive = $ar_res['ACTIVE'];
1236 break;
1237 }
1238 else
1239 {
1240 $bAddNew = ($bAddNew && COption::GetOptionString("ldap", "ldap_create_duplicate_login_user", 'Y') == 'Y');
1241 }
1242 }
1243
1244 if($bitrixUserId <= 0 && $ldapUserID <= 0)
1245 {
1246 if($bAddNew && !\Bitrix\Ldap\Limit::isUserLimitExceeded())
1247 {
1248 if($arLdapUser["EMAIL"] == '')
1249 {
1250 $arLdapUser["EMAIL"] = COption::GetOptionString("ldap", "default_email", 'no@email.test');
1251 }
1252
1253 $arLdapUser['PASSWORD'] = (string)(new Password());
1254 $ID = $USER->Add($arLdapUser);
1255 }
1256 else
1257 {
1258 $ID = 0;
1259 }
1260 }
1261 else
1262 {
1263 $ID = ($ldapUserID > 1 ? $ldapUserID : $bitrixUserId);
1264 self::PrepareUserPhoto($ID,$arLdapUser);
1265
1266 //Performance to skip \CIntranetEventHandlers::UpdateActivity();
1267 if(isset($arLdapUser['ACTIVE']) && $userActive == $arLdapUser['ACTIVE'])
1268 unset($arLdapUser['ACTIVE']);
1269
1270 $USER->Update($ID, $arLdapUser);
1271 }
1272
1273 $ID = intval($ID);
1274 }
1275
1276 // - add this user to groups
1277 if ($ID > 0)
1278 {
1279 // - set as head of department
1280 if (IsModuleInstalled('intranet') && $isHead)
1281 {
1282 CLdapUtil::SetDepartmentHead($ID,$arLdapUser['UF_DEPARTMENT'][0]);
1283 }
1284
1285 $arGroupMaps = $this->GetGroupMaps();
1286
1287 if(!empty($arGroupMaps))
1288 {
1289 // For each group finding all superior ones
1290 $arUserLdapGroups = Array();
1291 $arLdapGroups = $this->GetGroupListArray();
1292 $this->GetAllMemberOf($arLdapUser['LDAP_GROUPS'], $arUserLdapGroups, $arLdapGroups);
1293
1294 $arGroupMaps = $this->GetGroupMaps();
1295 $arUserBitrixGroups = $USER->GetUserGroup($ID);
1296 $arUserBitrixGroupsNew = array();
1297
1298 $prevGroups = $arUserBitrixGroups;
1299 sort($prevGroups);
1300
1301 foreach($arGroupMaps as $fromLdapGroup=>$arToUserGroups)
1302 {
1303 foreach($arToUserGroups as $toUserGroup)
1304 {
1305 if (($k = array_search($toUserGroup, $arUserBitrixGroups)) !== false)
1306 {
1307 unset($arUserBitrixGroups[$k]);
1308 }
1309
1310 // If there is such a group among user's
1311 if (in_array($fromLdapGroup, $arUserLdapGroups))
1312 {
1313 $arUserBitrixGroupsNew[] = $toUserGroup;
1314 }
1315 }
1316 }
1317 $arUserBitrixGroups = array_merge($arUserBitrixGroups, array_unique($arUserBitrixGroupsNew));
1318 sort($arUserBitrixGroups);
1319
1320 if($arUserBitrixGroups <> $prevGroups)
1321 {
1322 $USER->SetUserGroup($ID, $arUserBitrixGroups);
1323 }
1324 }
1325 }
1326
1327 if($bUSERGen)
1328 {
1329 unset($USER);
1330 }
1331
1332 return $ID;
1333 }
1334
1335 protected function getLastErrorDescription()
1336 {
1337 $result = '';
1338
1339 if($this->conn)
1340 {
1341 $ldapError = ldap_error($this->conn);
1342
1343 if($ldapError <> '')
1344 $result = "\nldap_error: '".$ldapError."'\nldap_errno: '".ldap_errno($this->conn)."'";
1345 }
1346
1347 return $result;
1348 }
1349
1350 public static function onEventLogGetAuditTypes(): array
1351 {
1352 return array(
1353 "LDAP_USER_LIMIT_EXCEEDED" => Loc::getMessage("LDAP_USER_LIMIT_EXCEEDED_EVENT_TYPE"),
1354 );
1355 }
1356}
$arParams
Определения access_dialog.php:21
$ar_res
Определения options_user_settings_set.php:16
global $APPLICATION
Определения include.php:80
$arResult
Определения generate_coupon.php:16
$login
Определения change_password.php:8
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
Определения check_mail.php:18
static getUserLimitNotifyMessage()
Определения limit.php:42
Определения dbresult.php:88
Определения iblocksection.php:5
Определения ldap.php:16
static isApplicationPassword(string $login, string $password, bool $isPasswordOriginal)
Определения ldap.php:380
$arGroupList
Определения ldap.php:17
GetAllMemberOf($arFindGroups, &$arUserGroups, $arAllGroups)
Определения ldap.php:1132
__construct($arFields=[])
Определения ldap.php:41
FindUser($LOGIN, $PASSWORD=false)
Определения ldap.php:526
getLdapValueByBitrixFieldName($fieldName, $arLdapUser)
Определения ldap.php:559
RootDSE()
Определения ldap.php:141
setFieldAsAttr(array $attrArray, $fieldName)
Определения ldap.php:307
$arFields
Определения ldap.php:17
GetUserList($arFilter=Array())
Определения ldap.php:987
startTls()
Определения ldap.php:116
GetGroupMaps()
Определения ldap.php:1150
Query($str='(ObjectClass=*)', $fields=false)
Определения ldap.php:298
const CONNECTION_TYPE_SIMPLE
Определения ldap.php:27
GetDepartmentIdForADUser($department, $managerDN, $username, &$cache=FALSE, $iblockId=FALSE, $names=FALSE)
Определения ldap.php:810
_RootDSE($filtr)
Определения ldap.php:163
static OnUserLogin(&$arArgs)
Определения ldap.php:397
GetGroupListArray($query='')
Определения ldap.php:319
static OnExternalAuthList()
Определения ldap.php:1042
GetUserFields($arLdapUser, &$departmentCache=FALSE)
Определения ldap.php:693
static PrepareUserPhoto($uid, &$arLdapUser)
Определения ldap.php:1172
BindAdmin()
Определения ldap.php:82
const CONNECTION_TYPE_TLS
Определения ldap.php:37
$arGroupMaps
Определения ldap.php:21
QueryArray($str='(ObjectClass=*)', $fields=false)
Определения ldap.php:193
Connect()
Определения ldap.php:46
static $PHOTO_ATTRIBS
Определения ldap.php:20
const CONNECTION_TYPE_SSL
Определения ldap.php:32
$conn
Определения ldap.php:18
static OnFindExternalUser($login)
Определения ldap.php:632
specialchars($str)
Определения ldap.php:1035
WorkAttr($values)
Определения ldap.php:181
GetGroupList($query='')
Определения ldap.php:371
$isTlsStarted
Определения ldap.php:39
SetUser($arLdapUser, $bAddNew=true)
Определения ldap.php:1192
static NTLMAuth()
Определения ldap.php:1056
$groupsLists
Определения ldap.php:22
GetUserArray($cn)
Определения ldap.php:1022
static onEventLogGetAuditTypes()
Определения ldap.php:1350
Disconnect()
Определения ldap.php:133
getLastErrorDescription()
Определения ldap.php:1335
Bind($login, $password)
Определения ldap.php:93
static GetList($arOrder=Array(), $arFilter=Array())
Определения ldap_server.php:19
static SetDepartmentHead($userId, $sectionId)
Определения ldap_util.php:260
static isLdapPaginationAviable()
Определения ldap_util.php:465
static GetImgTypeBySignature($signature)
Определения ldap_util.php:435
Определения user.php:6037
$str
Определения commerceml2.php:63
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$arGroups
Определения options.php:1766
$res
Определения filter_act.php:7
global $USER_FIELD_MANAGER
Определения attempt.php:6
$result
Определения get_property_values.php:14
$query
Определения get_search.php:11
if($ajaxMode) $ID
Определения get_user.php:27
$host
Определения .description.php:9
$uid
Определения hot_keys_act.php:8
GetIBlockSectionList($IBLOCK, $SECT_ID=false, $arOrder=array("left_margin"=>"asc"), $cnt=0, $arFilter=array())
Определения iblock.php:462
$iblockId
Определения iblock_catalog_edit.php:30
$filter
Определения iblock_catalog_list.php:54
Bind()
Определения idea_idea_comment.php:33
$_SERVER["DOCUMENT_ROOT"]
Определения cron_frame.php:9
global $DB
Определения cron_frame.php:29
global $USER
Определения csv_new_run.php:40
$pageSize
Определения csv_new_run.php:34
if($NS['step']==6) if( $NS[ 'step']==7) if(COption::GetOptionInt('main', 'disk_space', 0) > 0) $info
Определения backup.php:924
CheckDirPath($path)
Определения tools.php:2707
ExecuteModuleEventEx($arEvent, $arParams=[])
Определения tools.php:5214
IsModuleInstalled($module_id)
Определения tools.php:5301
GetModuleEvents($MODULE_ID, $MESSAGE_ID, $bReturnArray=false)
Определения tools.php:5177
is_set($a, $k=false)
Определения tools.php:2133
EncryptionType
Определения EncryptionType.php:6
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
if(empty($signedUserToken)) $key
Определения quickway.php:257
$i
Определения factura.php:643
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799
$password
Определения result.php:7
$pass
Определения result.php:5
$matches
Определения index.php:22
$otp
Определения options_user_settings.php:33
$arRes
Определения options.php:104
$k
Определения template_pdf.php:567
$arFilter
Определения user_search.php:106
$dbRes
Определения yandex_detail.php:168
$fields
Определения yandex_run.php:501