Вызов компонента
<?$APPLICATION->IncludeComponent(
"kochnev:main.register",
"flat",
Array(
"AUTH" => "Y",
"REQUIRED_FIELDS" => array("EMAIL","NAME","PERSONAL_PHONE"),
"SET_TITLE" => "Y",
"SHOW_FIELDS" => array("EMAIL","NAME","PERSONAL_PHONE"),
"SUCCESS_PAGE" => "/personal/index.php",
"USER_PROPERTY" => array(),
"USER_PROPERTY_NAME" => "",
"USE_BACKURL" => "Y"
)
);?>
template.php
<?php
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) {
die();
}
use Bitrix\Main\Localization\Loc;
global $USER;
if ($USER->IsAuthorized()) {
LocalRedirect('/personal/');
}
if ($arResult["SHOW_SMS_FIELD"] == true) {
CJSCore::Init('phone_auth');
}
Loc::loadMessages(__FILE__);
?>
<div class="auth-form register-form">
<div class="container">
<div class="auth-form__inner">
<div class="auth-form__header d-none">
<h3 class="auth-form__title"><?=Loc::getMessage('AUTH_REGISTER', null, 'Регистрация')?></h3>
</div>
<? if (!empty($arResult["ERRORS"])): ?>
<div class="auth-form__errors">
<? foreach ($arResult["ERRORS"] as $key => $error): ?>
<?
if (intval($key) == 0 && $key !== 0) {
$error = str_replace(
"#FIELD_NAME#",
""" . GetMessage("REGISTER_FIELD_" . $key) . """,
$error
);
}
?>
<div class="auth-form__error"><?=$error?></div>
<? endforeach; ?>
</div>
<? elseif ($arResult["USE_EMAIL_CONFIRMATION"] === "Y"): ?>
<div class="auth-form__errors">
<div class="auth-form__error"><?=GetMessage("REGISTER_EMAIL_WILL_BE_SENT")?></div>
</div>
<? endif; ?>
<? if ($arResult["SHOW_SMS_FIELD"] == true): ?>
<form method="post" action="<?=POST_FORM_ACTION_URI?>" name="regform" class="auth-form__form">
<? if ($arResult["BACKURL"] <> ''): ?>
<input type="hidden" name="backurl" value="<?=$arResult["BACKURL"]?>"/>
<? endif; ?>
<input type="hidden" name="SIGNED_DATA" value="<?=htmlspecialcharsbx($arResult["SIGNED_DATA"])?>"/>
<div class="auth-form__field form-field">
<label class="form-field__label auth-form__label" for="sms_code">
<?=GetMessage("main_register_sms")?><span class="starrequired">*</span>
</label>
<input
type="text"
id="sms_code"
name="SMS_CODE"
value="<?=htmlspecialcharsbx($arResult["SMS_CODE"])?>"
autocomplete="off"
class="form-control auth-form__input"
placeholder="Введите код из SMS"
/>
</div>
<div class="auth-form__submit">
<button type="submit" name="code_submit_button" class="btn auth-form__submit-btn">
<?=GetMessage("main_register_sms_send")?>
</button>
</div>
</form>
<script>
new BX.PhoneAuth({
containerId: 'bx_register_resend',
errorContainerId: 'bx_register_error',
interval: <?= $arResult["PHONE_CODE_RESEND_INTERVAL"] ?>,
data: <?= CUtil::PhpToJSObject(['signedData' => $arResult["SIGNED_DATA"]]) ?>,
onError: function (response) {
var errorDiv = BX('bx_register_error');
var errorNode = BX.findChildByClassName(errorDiv, 'errortext');
errorNode.innerHTML = '';
for (var i = 0; i < response.errors.length; i++) {
errorNode.innerHTML = errorNode.innerHTML + BX.util.htmlspecialchars(response.errors[i].message) + '<br>';
}
errorDiv.style.display = '';
}
});
</script>
<div id="bx_register_error" style="display:none"><? ShowError("error") ?></div>
<div id="bx_register_resend"></div>
<? else: ?>
<form method="post" action="<?=POST_FORM_ACTION_URI?>" name="regform" enctype="multipart/form-data"
class="auth-form__form">
<? if ($arResult["BACKURL"] <> ''): ?>
<input type="hidden" name="backurl" value="<?=$arResult["BACKURL"]?>"/>
<? endif; ?>
<? foreach ($arResult["SHOW_FIELDS"] as $FIELD): ?>
<div class="auth-form__field form-field">
<label for="regFormControlInput_<?=$FIELD?>" class="form-field__label auth-form__label">
<?=GetMessage("REGISTER_FIELD_" . $FIELD)?>
<? if ($arResult["REQUIRED_FIELDS_FLAGS"][$FIELD] === "Y"): ?>
<span class="starrequired">*</span>
<? endif ?>
</label>
<? switch ($FIELD):
case "PASSWORD": ?>
<div class="auth-form__password-wrapper">
<? if ($arResult["SECURE_AUTH"]): ?>
<div class="auth-form__secure-note" id="bx_auth_secure"
style="display:none">
<div class="ui-note">
<span class="auth-form__secure-icon">🔒</span>
<?=GetMessage("AUTH_SECURE_NOTE")?>
</div>
</div>
<script>
document.getElementById('bx_auth_secure').style.display = '';
</script>
<? endif ?>
<input
type="password"
id="regFormControlInput_<?=$FIELD?>"
class="form-control auth-form__input"
name="REGISTER[<?=$FIELD?>]"
value="<?=$arResult["VALUES"][$FIELD]?>"
autocomplete="off"
placeholder="Введите пароль"
/>
</div>
<? break;
case "CONFIRM_PASSWORD": ?>
<input
type="password"
id="regFormControlInput_<?=$FIELD?>"
class="form-control auth-form__input"
name="REGISTER[<?=$FIELD?>]"
value="<?=$arResult["VALUES"][$FIELD]?>"
autocomplete="off"
placeholder="Повторите пароль"
/>
<? break;
case "PERSONAL_PHOTO":
case "WORK_LOGO": ?>
<input
type="file"
id="regFormControlInput_<?=$FIELD?>"
name="REGISTER_FILES_<?=$FIELD?>"
class="form-control auth-form__input auth-form__input--file"
/>
<? break;
case "EMAIL": ?>
<input
type="email"
id="regFormControlInput_<?=$FIELD?>"
class="form-control auth-form__input"
name="REGISTER[<?=$FIELD?>]"
value="<?=$arResult["VALUES"][$FIELD]?>"
placeholder="Введите email"
/>
<? break;
default: ?>
<?
$placeholder = $FIELD === 'PERSONAL_PHONE'
? '+7 (000) 000-00-00'
: GetMessage("REGISTER_FIELD_" . $FIELD);
$maskPhoneClass = $FIELD === 'PERSONAL_PHONE' ? ' _mask_phone' : '';
?>
<input
type="text"
id="regFormControlInput_<?=$FIELD?>"
class="form-control auth-form__input<?=$maskPhoneClass?>"
name="REGISTER[<?=$FIELD?>]"
value="<?=$arResult["VALUES"][$FIELD]?>"
placeholder="<?=$placeholder?>"
/>
<? endswitch; ?>
</div>
<? endforeach; ?>
<? if ($arResult["USE_CAPTCHA"] == "Y"): ?>
<input type="hidden" name="captcha_sid" value="<?=$arResult["CAPTCHA_CODE"]?>"/>
<div class="auth-form__field form-field">
<label class="form-field__label auth-form__label" for="captcha_word">
<?=GetMessage("REGISTER_CAPTCHA_PROMT")?><span class="starrequired">*</span>
</label>
<div class="auth-form__captcha">
<img
src="/bitrix/tools/captcha.php?captcha_sid=<?=$arResult["CAPTCHA_CODE"]?>"
width="180"
height="40"
alt="CAPTCHA"
class="auth-form__captcha-image"
/>
</div>
<input
type="text"
id="captcha_word"
name="captcha_word"
maxlength="50"
value=""
autocomplete="off"
class="form-control auth-form__input"
placeholder="Введите символы с картинки"
/>
</div>
<? endif; ?>
<div class="auth-form__submit">
<input type="submit" class="btn auth-form__submit-btn" name="register_submit_button"
value="<?=GetMessage("AUTH_REGISTER")?>" />
</div>
</form>
<? if ($arResult["GROUP_POLICY"]["PASSWORD_REQUIREMENTS"]): ?>
<div class="auth-form__password-requirements">
<?=$arResult["GROUP_POLICY"]["PASSWORD_REQUIREMENTS"]?>
</div>
<? endif; ?>
<div class="auth-form__links">
<a href="/personal/auth/" class="btn-link">
Уже есть аккаунт? Войти
</a>
</div>
<? endif; ?>
<div class="auth-form__required-note">
<span class="starrequired">*</span><?=GetMessage("AUTH_REQ")?>
</div>
</div>
</div>
</div>
CSS
.register-form .auth-form__title {
margin-bottom: 30px;
}
.auth-form__inner {
max-width: 460px;
padding: clamp(20px, 3vw, 40px);
border-radius: 8px;
border: 1px solid var(--gray-40);
}
.auth-form__form {
display: flex;
flex-direction: column;
gap: 20px;
}
.auth-form__input--file {
padding: 8px 12px;
font-size: 14px;
}
.auth-form__input--file::-webkit-file-upload-button {
background-color: var(--gray-10);
border: 1px solid var(--gray-30);
border-radius: 4px;
padding: 6px 12px;
margin-right: 12px;
font-size: 13px;
color: var(--gray-80);
cursor: pointer;
transition: var(--tr25);
}
.auth-form__input--file::-webkit-file-upload-button:hover {
background-color: var(--gray-20);
border-color: var(--gray-40);
}
.auth-form__password-requirements {
margin-top: 20px;
padding: 12px 16px;
background-color: var(--gray-10);
border: 1px solid var(--gray-30);
border-radius: 6px;
font-size: 14px;
color: var(--gray-70);
}
.auth-form__required-note {
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid var(--gray-20);
font-size: 14px;
color: var(--gray-60);
font-style: italic;
}
.starrequired {
color: var(--red);
margin-left: 2px;
}
.auth-form__errors {
margin-bottom: 20px;
}
.auth-form__error {
background-color: rgba(209, 92, 92, 0.1);
border: 1px solid var(--red);
border-radius: 6px;
padding: 12px 16px;
color: var(--red);
font-size: 14px;
margin-bottom: 8px;
}
.auth-form__error:last-child {
margin-bottom: 0;
}
.ui-checkbox-label {
display: flex;
align-items: flex-start;
gap: 8px;
cursor: pointer;
font-size: 14px;
line-height: 1.4;
}
.ui-checkbox {
position: relative;
width: 18px;
height: 18px;
border: 2px solid var(--gray-40);
border-radius: 3px;
background-color: var(--white);
transition: var(--tr25);
flex-shrink: 0;
margin-top: 2px;
}
.ui-checkbox-label input[type="checkbox"] {
position: absolute;
opacity: 0;
width: 0;
height: 0;
}
.ui-checkbox-label input[type="checkbox"]:checked + .ui-checkbox {
background-color: var(--primary);
border-color: var(--primary);
}
.ui-checkbox-label input[type="checkbox"]:checked + .ui-checkbox::after {
content: '✓';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: var(--white);
font-size: 12px;
font-weight: bold;
}
.ui-checkbox-label input[type="checkbox"]:focus + .ui-checkbox {
box-shadow: var(--box-shadow-focus);
}
.ui-checkbox-text {
color: var(--gray-80);
}
.auth-form__submit {
margin-top: 10px;
}
.auth-form__submit-btn {
width: 100%;
}
.auth-form__links {
display: flex;
flex-direction: column;
gap: 12px;
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid var(--gray-20);
}
@media (max-width: 768px) {
.auth-form {
padding: 40px 0;
}
.auth-form__inner {
margin: 0 20px;
padding: 30px 20px;
}
.auth-form__links {
gap: 8px;
}
.auth-form__title {
font-size: 22px;
}
}
@media (max-width: 480px) {
.register-form .auth-form__inner {
margin: 0 10px;
padding: 24px 16px;
}
.auth-form__title {
font-size: 20px;
}
.form-control {
padding: 10px 14px;
font-size: 16px; /* Важно для iOS, чтобы не зумило */
}
}
.auth-form .ui-checkbox-label {
margin-top: 4px;
}
Опционально
Если в проекте требуется работа с номером телефона в других компонентах, они работают с полем PHONE_NUMBER, которое хранится в другой таблице нежели поля Пользователя. Поэтому поле PERSONAL_PHONE нам не подойдет.
Заберем номер телефона в форме регистрации через PERSONAL_PHONE и запишем его в PHONE_NUMBER.
Копируем компонент в свое пространство имен /local/components/my_folder/main.register.
Далее в файле component.php после
// check emptiness of required fields
foreach ($arResult["SHOW_FIELDS"] as $key)
{
if ($key != "PERSONAL_PHOTO" && $key != "WORK_LOGO")
{
$arResult["VALUES"][$key] = $_REQUEST["REGISTER"][$key];
if (in_array($key, $arResult["REQUIRED_FIELDS"]) && trim($arResult["VALUES"][$key]) == '')
$arResult["ERRORS"][$key] = GetMessage("REGISTER_FIELD_REQUIRED");
}
else
{
$_FILES["REGISTER_FILES_".$key]["MODULE_ID"] = "main";
$arResult["VALUES"][$key] = $_FILES["REGISTER_FILES_".$key];
if (in_array($key, $arResult["REQUIRED_FIELDS"]) && !is_uploaded_file($_FILES["REGISTER_FILES_".$key]["tmp_name"]))
$arResult["ERRORS"][$key] = GetMessage("REGISTER_FIELD_REQUIRED");
}
}
пишем проверку
// Проверяем пользователя по номеру телефона.
// Добавляем номер телефона в PHONE_NUMBER
if(isset($_REQUEST["REGISTER"]["PERSONAL_PHONE"])) {
$phone = '+' . \Helper\ToolsHelper::formatPhoneForTel($_REQUEST["REGISTER"]["PERSONAL_PHONE"]);
$userExists = \Helper\UserHelper::getUserByPhone($phone);
if ($userExists) {
$arResult["ERRORS"]['PERSONAL_PHONE'] = GetMessage("REGISTER_USER_WITH_PHONE_EXIST");
} else {
$arResult["VALUES"]['PHONE_NUMBER'] = $phone;
}
}
Вспомогательные функции
Все опционально и зависит от масок и их наличия.
/**
* Форматируем номер телефона с удалением лишних символов для вставки в ссылку.
* Добавляем добавочный номер по разделителю "_".
* Из строки (8-38553) 25-3-01_2 делаем:
* 1) 83855325301,2 - formatPhoneForTel()
* 2) (8-38553) 25-3-01 доб.2 - formatPhoneForDisplay()
*/
public static function formatPhoneForTel($phone): string
{
// Убираем пробелы и заменяем символ "_".
$phone = str_replace('_', ',', $phone);
// Удаляем символы, которые не являются цифрами, кроме запятой.
return preg_replace('/[^\d,]/', '', $phone);
}
public static function formatPhoneForDisplay($phone): string
{
return str_replace('_', ' доб.', $phone);
}
<?php
namespace Helper;
class UserHelper
{
/**
* Регистрация пользователя по Эл. Почте.
*/
public static function registerByEmailEvent(array &$arFields):array
{
$arFields["LOGIN"] = $arFields["EMAIL"];
return $arFields;
}
/**
* Поиск пользователя по номеру телефона
*
* @param string $phone Номер телефона
*
* @return int|false ID пользователя или false если не найден
*/
public static function getUserByPhone(string $phone): int | false
{
//$phone = $this->normalizePhone($phone);
// Пробуем найти пользователя.
$rawData = \Bitrix\Main\UserPhoneAuthTable::getList([
'filter' => [
'PHONE_NUMBER' => $phone,
],
'select' => [
'USER_ID',
],
])->fetch();
if ($rawData) {
return $rawData['USER_ID'];
}
return false;
}
}