• Как сгенерировать безопасный хэш в yii2?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    можно использовать функцию generateRandomString() из компонента security. Эта функция создает случайную строку указанной длины, которую можно использовать как соль для хеша

    public function beforeSave($insert)
    {
        if ($this->isNewRecord || $this->isAttributeChanged('password')) {
            $this->password_hash = Yii::$app->security->generatePasswordHash($this->password);
        }
        
        if ($this->isNewRecord || $this->isAttributeChanged('refresh_token')) {
            $salt = Yii::$app->security->generateRandomString();
            $this->refresh_token_salt = $salt;
            $this->refresh_token_hash = Yii::$app->security->generatePasswordHash($this->refresh_token . $salt);
        }
    
        return parent::beforeSave($insert);
    }


    А в методе actionRefresh вы можете использовать эту соль, чтобы проверить правильность refresh_token:

    public function actionRefresh()
    {
        $refresh_token = Yii::$app->request->headers->get('Authorization');
        $refresh_token = substr($refresh_token, 7);
    
        $decoded = User::getUserDataFromJWT($refresh_token);
    
        $user = User::find()
            ->where(['id' => $decoded->data->user_id])
            ->one();
    
        if ($user && $user->refresh_token_salt) {
            $refresh_token_hash = Yii::$app->security->generatePasswordHash($refresh_token . $user->refresh_token_salt);
            if (Yii::$app->security->validatePassword($refresh_token_hash, $user->refresh_token_hash)) {
                // Refresh token is valid
            }
        }
    }
    Ответ написан
  • Вывести картинку связанного свойства в битриксе?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    Вы пытаетесь перебирать массив $arResult["PROPERTIES"]["articlesAuthor"] вместо массива $arResult["PROPERTIES"]["articlesAuthor"]["VALUE"].

    <?foreach ($arResult["PROPERTIES"]["articlesAuthor"]["VALUE"] as $articlesID):?>
        <?
        $res = CIBlockElement::GetByID($articlesID);
        if($ar_res = $res->GetNext()): ?>
            <img src="<?=CFile::GetPath($ar_res["PREVIEW_PICTURE"]);?>" title=""/>
        <?endif;?>
    <?endforeach;?>
    Ответ написан
  • Как оптимизировать пагинацию отсортированных по времени создания записей?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    Можно использовать альтернативный подход, который называется "ключевая пагинация" (keyset pagination). Вместо использования offset/limit, вы будете использовать значения последнего элемента на предыдущей странице для запроса следующей страницы данных.

    Для этог нужно добавить индекс на столбец с датой создания в вашей таблице, если его еще нет:
    CREATE INDEX idx_created_at ON your_table_name (created_at);


    Запрос
    SELECT * FROM table_name
    WHERE created_at < (SELECT created_at FROM table_name WHERE id = :last_id)
    ORDER BY created_at DESC
    LIMIT 1000;

    Здесь :last_id - это идентификатор последней записи на предыдущей странице.
    Ответ написан
  • Как объединить 3 массива из файлов после цикла foreach?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    public function getFilesGenres() {
        $files = scandir(__DIR__.'/genres');
        $config = config('songscrud.genres.langs');
    
        $resultArray = [];
        foreach($config as $lang) {
            foreach ($files as $file) {
                if(preg_match('/\.(php)/', $file)) {
                    $path = __DIR__.'/genres/' . $file;
                    $ext = pathinfo($file, PATHINFO_FILENAME);
    
                    if ($lang === $ext) {
                        $array = require($path);
                        $resultArray = array_merge($resultArray, $array);
                    }
                }
            }
        }
    
        return $resultArray;
    }
    Ответ написан
  • Почему структура не имплементирует интерфейс?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    Ты возвращаешь указатель на структуру *balance вместо того, чтобы возвращать значение, реализующее интерфейс Monetary - а это не соответствует требованиям интерфейса Account, которые указывают, что метод GetBalance() должен возвращать тип, реализующий интерфейс Monetary.

    type Account interface {
        GetBalance() Monetary
    }
    
    type account struct {
        b Monetary
    }
    
    func (a *account) GetBalance() Monetary {
        return a.b
    }
    
    func NewAccount() *account {
        return &account{
            b: &balance{},
        }
    }
    
    func main() {
        var acc Account = NewAccount()
        fmt.Println(acc)
    }
    Ответ написан
    2 комментария
  • Кросс компиляция syscall?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    Используй syscall.Handle для файла дескриптора fd

    syscall.Sendto(syscall.Handle(fd), data, 0, &syscall.SockaddrInet4{Port: port, Addr: [4]byte{127, 0, 0, 1}})
    ....
    syscall.SetsockoptInt(syscall.Handle(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
    Ответ написан
  • Как задать имя страницы HTML, используя JS и тип «объект»?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    Object.keys(menuItems).forEach(function(key) {
      if (menuItems[key] === pageName) {
        document.title = key;
      }
    });
    Ответ написан
    Комментировать
  • Как исправить код?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    Проблема в том, что векторы l, r и k индексируются с 0, а не с 1.
    Замените индексацию в векторах на индексацию с 0, а в вычислении индексов подстроки используй l[i] - 1 вместо l[i], а также k[i] - 1 вместо k[i] при вызове insert().

    Например так
    #include <iostream>
    #include <vector>
    #include <string>
    
    using namespace std;
    
    int main() {
        string s;
        int q;
        cin >> s >> q;
    
        vector<int> l(q), r(q), k(q);
        for (int i = 0; i < q; ++i) {
            cin >> l[i] >> r[i] >> k[i];
        }
    
        for (int i = q - 1; i >= 0; --i) {
            string t = s.substr(l[i] - 1, r[i] - l[i] + 1);
            s.erase(l[i] - 1, r[i] - l[i] + 1);
            if (k[i] == 0) {
                s = t + s;
            } else {
                s.insert(k[i] - 1, t);
            }
        }
    
        cout << s << endl;
    
        return 0;
    }
    Ответ написан
  • Чем отличаются два варианта регулярки?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    Вторая регулярка (?=(слово\s*.*?))"(?=\n*.*»)использует positive lookahead, чтобы найти первую двойную кавычку после слова "слово", за которой следует символ переноса строки, а затем где-то далее в тексте находится символ «. Она не заменяет текст, а только находит первую двойную кавычку, соответствующую критериям.

    Я бы сделал вот так
    newText = newText.replace(/(слово\s*.*?)"(?=\n*.*»)/giu, function(match, group) {
        return group + "«";
    });
    Ответ написан
    Комментировать
  • Как исправить регулярное выражение оборачивания тегом?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    Попробуй так
    html = html.replace(new RegExp(`\\b${localStorage.getItem('selectedText')}\\b(?!([^<]+)?>)`, 'g'), `<strong class='highlightText'>$&</strong>`);
    Ответ написан
    Комментировать
  • Как исправить ошибку с Valchan горутины?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    Ошибка связана с тем, что вы пытаетесь отправить данные по каналу valChan, но все горутины уже завершили свою работу.

    func scanFiles(file1, file2 *bufio.Scanner, config Config) {
        scanWg := new(sync.WaitGroup)
        scanWg.Add(2)
    
        file1SubStrings := make(map[string]string)
        file2SubStrings := make(map[string]string)
    
        go func() {
            var substr []string
            for file1.Scan() {
                substr = strings.Split(file1.Text(), ":")
                if len(substr) > 0 {
                    file1SubStrings[substr[1]] = substr[0]
                }
            }
            scanWg.Done()
        }()
    
        go func() {
            var substr []string
            for file2.Scan() {
                substr = strings.Split(file2.Text(), ":")
                if len(substr) > 0 {
                    file2SubStrings[substr[0]] = substr[1]
                }
            }
            scanWg.Done()
        }()
    
        scanWg.Wait()
    
        if file2SubStrings != nil && file1SubStrings != nil {
            wg := new(sync.WaitGroup)
            valChan := make(chan struct{ k, v string })
    
            for i := 0; i < config.Count_check; i++ {
                wg.Add(1)
                go findIntersections(valChan, file2SubStrings, wg, config)
            }
    
            for k, v := range file1SubStrings {
                valChan <- struct{ k, v string }{k: k, v: v}
            }
    
            close(valChan)
            wg.Wait()
        }
    }
    Ответ написан
  • Что делать с ошибкой запроса left join guid при сопоставлении?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    Попробуй так
    SELECT * FROM `first` as t1
     LEFT JOIN `second` as t2 ON t1.id COLLATE utf8_unicode_ci = t2.number_id COLLATE utf8_unicode_ci;


    Но COLLATE может замедлить выполнение запроса, поскольку серверу придется преобразовывать значения перед сравнением, если это возможно - поменяй кодировку одного из столбцов
    Ответ написан
    1 комментарий
  • Как выбрать несколько категорий?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    $data = array(
        "login_name"=>"*****",
        "login_password"=>"*****",
        "login"=>"dologin",
        "mod"=>"addnews",
        "action"=>"addnews",
        "category[]"=>"4",
        "category[]"=>"5",
        "category[]"=>"9",
    );
    Ответ написан
    Комментировать
  • Ошибка с xhprof при обновлении yum upgrade, как исправить?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    попробуй напрямую из rpm пакета
    sudo rpm -Uvh --nodeps http://rpms.remirepo.net/enterprise/7/php80/x86_64/php-pecl-xhprof-2.3.9-1.el7.remi.8.1.x86_64.rpm
    Ответ написан
  • Как в workerman реализовать приватность?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    const div = document.querySelector("echo");
    const ws = new WebSocket("ws://localhost:2346");
    
    document.addEventListener('keydown', function(){
        ws.send(JSON.stringify("123"));
    });
    ws.onmessage = response => {
      let data = JSON.parse(response.data);
      console.log(data);
    }


    <?php
    use Workerman\Worker;
    
    require_once __DIR__ . "/vendor/autoload.php";
    
    $wsWorker = new Worker("websocket://0.0.0.0:2346");
    $wsWorker->count = 4;
    
    $wsWorker->onConnect = function($con){
      echo "подключен";
    };
    
    $wsWorker->onMessage = function($con, $data) {
      // Вместо отправки ответа всем подключенным пользователям отправляем его только тому, кто сделал запрос
      $con->send($data);
    };
    
    $wsWorker->onClose = function($con){
      echo "отключен";
    };
    
    Worker::runAll();
    ?>
    Ответ написан
    Комментировать
  • Как найти сумму двух map-ов в Golang?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    Самый очевидный вариант
    for k, v := range z {
        x[k] += v
    }


    более универсальный
    func sumMaps(maps ...map[types.Category]int) map[types.Category]int {
        result := make(map[types.Category]int)
    
        // складываем значения из всех map-ов
        for _, m := range maps {
            for k, v := range m {
                result[k] += v
            }
        }
    
        return result
    }

    result := sumMaps(map1, map2, map3)

    Или через Fan-in.
    Ответ написан
    Комментировать
  • Как сделать установщик Java через Installshield?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    Чтобы создать установщик Java через InstallShield, нужно выполнить следующие шаги:

    Создайте новый проект InstallShield и настройте его под нужды вашей программы.

    Добавьте файлы для установки, включая исполняемый файл лаунчера и установочный файл Java.

    Настройте свойства установочного пакета. Например, укажите путь установки, иконку и название программы.

    Настройте действия, которые должен выполнить установщик при установке. Например, установите Java и настройте переменные среды.

    Создайте скрипт, который будет выполняться при запуске установщика. В этом скрипте можно проверить, установлена ли Java на компьютере пользователя, и предложить пользователю установить ее, если она не установлена.

    Проверьте, что установщик работает корректно, запустив его на тестовом компьютере.

    Подготовьте установочный пакет для распространения.

    В целом, процесс создания установщика Java в InstallShield похож на создание установщика любой другой программы. Но нужно учесть, что Java может быть установлена на компьютере пользователя, поэтому нужно проверять ее наличие и, если нужно, устанавливать.
    Ответ написан
  • Как из списка списков получить такой результат?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    Чтобы получить транспонированную матрицу из списка списков, необходимо использовать функцию zip() в сочетании с оператором * для распаковки списков. Вот как это можно сделать:

    lst = [['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9']]
    result = [list(x) for x in zip(*lst)]


    В результате вы получите список списков, где каждый вложенный список представляет собой строку транспонированной матрицы.

    Чтобы вывести элементы этой матрицы в виде таблицы, можно использовать циклы, например так:
    for row in result:
        print(' '.join(row))


    Этот код выведет элементы матрицы в виде таблицы, где каждая строка будет расположена в новой строке, а элементы будут разделены пробелами.
    Ответ написан
    Комментировать
  • Как перевести Jira с протокола http на https?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    При переключении Jira с протокола HTTP на HTTPS нужно выполнить несколько шагов, чтобы настроить SSL-сертификат и привязать его к Jira. Описанные вами шаги выглядят правильными, но возможно есть несколько моментов, которые могут привести к проблемам.

    Вот несколько дополнительных шагов, которые могут помочь вам настроить HTTPS для Jira:

    Убедитесь, что вы правильно указали путь к хранилищу ключей, когда настраивали Connector в server.xml.

    Убедитесь, что вы используете правильные значения для параметров keystoreFile, keystorePass и keyAlias в Connector. Например, keystoreFile должен содержать полный путь к файлу хранилища ключей Jira (например, "C:/jira.jks"), а keystorePass должен содержать пароль, который вы использовали при создании хранилища ключей.

    Убедитесь, что вы настроили Jira таким образом, чтобы он работал через протокол HTTPS. Для этого вам нужно отредактировать файл Jira-инициализации (например, jira-config.properties) и указать свойства jira.protocol и jira.port следующим образом:

    jira.protocol=https
    jira.port=443

    После настройки сервера вам может потребоваться перезапустить Jira, чтобы изменения вступили в силу.

    Проверьте наличие ошибок в журналах приложений, чтобы убедиться, что конфигурация сервера была настроена правильно.

    Проверьте, что вы можете получить доступ к Jira через протокол HTTPS, используя браузер. Если все настроено правильно, вы должны увидеть защищенный замок в адресной строке браузера.

    Надеюсь, эти дополнительные шаги помогут вам успешно настроить HTTPS для Jira.
    Ответ написан
  • Как прописать container query в styled-component?

    OrlovEvgenii
    @OrlovEvgenii
    golang developer / DevOps
    Container Query (CQ) - это техника, которая позволяет определять стили компонента на основе его контекста, включая размеры его родительского контейнера. Однако, CQ в настоящее время не является стандартом CSS и не поддерживается в стандартных браузерах.

    Вместо использования CQ, можно использовать принцип Mobile First и создавать медиа-запросы для разных ширин экрана. Вот пример, как это можно сделать в styled-components:
    const Container = styled.div`
      max-width: 370px;
      
      @media (max-width: 370px) {
        /* Стили для контейнера, если ширина <= 370px */
      }
    
      @media (max-width: 314px) {
        /* Стили для контейнера, если ширина <= 314px */
      }
    
      @media (max-width: 270px) {
        /* Стили для контейнера, если ширина <= 270px */
      }
    `;
    
    const Header = styled.div`
      height: 180px;
      
      @media (max-width: 370px) {
        height: 150px;
      }
    
      @media (max-width: 314px) {
        height: 120px;
      }
    
      @media (max-width: 270px) {
        height: 90px;
      }
    `;
    
    <Container>
      <Header />
    </Container>

    Здесь мы определяем стили для компонента Container с помощью медиа-запросов для разных ширин экрана. Аналогично, мы определяем стили для компонента Header с помощью медиа-запросов для изменения его высоты в зависимости от ширины экрана.
    Ответ написан