• Почему на некоторые сайты не получается зайти по ip?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    На одном IP может быть много доменов. Все они определяются веб сервером.
    Когда мы отправляем http запрос на toster.ru то мы подключаемся к айпи адресу, и в заголовке host передаем доменное имя, веб сервер ищет конфиг который подходит под это доменное имя и и передает управление этому конфигу.
    https://nginx.org/ru/docs/http/server_names.html
    Когда же мы подключаемся по айпи адресу, то в заголовке host передается айпи адрес, сервер не может найти конфиг для этого хоста и запускает дефолтный со страничкой nginx.
    Ответ написан
    2 комментария
  • В чем разница между транзакцией и самодельной проверки?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    Разница в том, что в случае с транзакцией вы можете откатить все изменения. И с транзакциями обычно тоже используются условия:
    $db->beginTransaction();
    if ($query->execute()) {
        if ($query->execute()) {
            $db->commit();
            return true;
        }
    }
    
    $db->rollback();
    return false;


    В таком случае, если хоть один запрос не сработал, то транзакция откатывает все изменения. А в первом вашем случае если 1 запрос отработал, а второй нет, то данные не откатываются.
    Ответ написан
  • Мой ubuntu сервер пытаются взломать, как защититься?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    1) Перенести порт ssh сервера со стандартного на другой, это отобьет большую часть ботов/сканнеров
    2) Запретить авторизацию пользователю root по ssh
    3) Поставить Fail2Ban для блокировки айпишников с которых идет брут

    P.S. Разные порты это скорее всего порты исходящего соединения, поэтому они разные, к вам же они все стучатся на порт который указан в конфиге sshd
    Ответ написан
    1 комментарий
  • Как сделать генератор случайных чисел, основанный на seed?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    function myRand($min, $max, $seed)
    {
        srand($seed);
        return rand($min, $max);
    }
    Ответ написан
    Комментировать
  • Как реализовать обмен сообщениями между двумя пользователями на Golang?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    Создаете структуру Clients. в ней поля nickname, connect.
    type Client struct {
           ID        int                  // Идентификатор юзера
           Nickname   string             // Никнейм клиента
           Conn 	 *websocket.Conn    // Сокет клиента
    }

    После авторизации клиента на вашем сокет сервере, добавляете его в глобальный массив clients, ну и собственно ловите пакеты сообщений, например в json:
    {"to" : "nickname", "message" : "hello"}
    Дальше циклом пробегаетесь по массиву clients и если ник клиента совпадает с полем to из json, то отправляете ему сообщение.
    P. S. Самое поверхностное описание, без углубления в каналы юзера/сессии/аутентификацию/работы с json
    Ответ написан
  • Как спарсить нужную часть текста?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    В массиве будут записи вида [0 => [], 1 => []], останется только по массиву пройтись foreach и сохранить в нужном виде (csv, tsv, ...)
    <?php
    
    function parse($text) {
        $lines = explode("\n", $text);
        $result = [];
        $switched = false;
        $i = 0;
        foreach($lines as $line) {
            
            // Add item
            if (count($matches = preg_split('/->/', $line, -1, PREG_SPLIT_NO_EMPTY)) == 2) {
                if (!isset($result[$i])) {
                    $result[$i] = [];
                }
                $result[$i][$matches[0]] = $matches[1];
                $switched = false;
            } else if (!$switched) {
                $i++;
                $switched = true;
            }
        }
        return $result;
    }
    
    $text = "
    _wpcf7->104
    _wpcf7_version->4.7
    _wpcf7_locale->ru_RU
    _wpcf7_unit_tag->wpcf7-f104-p157-o3
    _wpnonce->2b8273a977
    your-name->Krisan Lang
    menu-968->Firma
    text-463->Best OÜ
    tel-179->58813468606
    your-email->kridgfgstjan@best5apartments.ee
    
    November 29, 2017, 18:07:14
    _wpcf7->104
    _wpcf7_version->4.7
    _wpcf7_locale->ru_RU
    _wpcf7_unit_tag->wpcf7-f104-p67-o1
    _wpnonce->2b8273a977
    your-name->Liis dfValma
    menu-968->Eraisik
    text-463->
    tel-179->5396643367
    your-email->liisvalma2401@gmail.com
    ";
    
    
    print_r(parse($text));
    Ответ написан
  • Как выгрузить из текста все телефонные номера?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    Регулярка, но, вероятно, она будет лишнее забирать, нужно еще сделать пост проверку всех результатов, либо подогнать эту регулярку под текст(сделать строже матчинг):
    \d{2,3}(?:\s*)\d+

    preg_match_all("/\d{2,3}(?:\s*)\d+/", $input_lines, $output_array);
    Ответ написан
    Комментировать
  • Деление статьи через n-слов и после ближайшего /p посредством {pagebreak}, как?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    Регулярка для поиска проблемных мест:
    /<([a-z]+)>(?<!<p>).+(?!(?:<\/p>|<\/\1>))\{PAGEBREAK\}.+<\/\1>/


    Выносит PAGEBREAK за тэг. Применять ее нужнок уже готовому тексту. Применять ко всему тексту не рекомендую, так как могут быть проблемы с производительностью. Лучше отдельно к каждому параграфу. Можно разбить по параграфам в массив и массив передавать в preg_replace:
    preg_replace("/(?P<start><([a-z]+)>(?<!<p>).+(?!(?:<\/p>|<\/\2>)))\{PAGEBREAK\}(?P<end>.+<\/\2>)/", "\1 \3 {PAGEBREAK}", $input_lines);
    Ответ написан
    Комментировать
  • Как суммировать значения дубликатов массива?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    <?php
    $array = [
    [
      'player_id' => 1,
      'count_goals' => 1
    ],
    [
      'player_id' => 1,
      'count_goals' => 1
    ],
    [
      'player_id' => 1,
      'count_goals' => 1
    ],
    [
      'player_id' => 1,
      'count_goals' => 1
    ],
    ];
    
    function filter($array)
    {
    	$result = [];
      	foreach($array as $key => $value) {
    		if (array_key_exists($value['player_id'], $result)) {
    			$result[$value['player_id']]['count_goals'] += $value['count_goals'];
    		} else {
    			$result[$value['player_id']] = $value;	
    		}
      	}
      return array_values($result);
    }
    
    print_r(filter($array));
    Ответ написан
    3 комментария
  • Как распарсить массив?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    <?php
    $a = [
    'color' => ['red', 'blue', 'orange'],
    'size' => ['10-12', '12-14', '13-13'],
    'somekey' => ['val1', 'val2', 'val3'],
    ];
    
    function addValue(&$arr, $key, $val)
    {
    	if (!count($arr)) {
    		$arr[] = [$key => $val];
    		return;
    	}
    	foreach($arr as $num => $values) {
    		$arr[$num][$key] = $val;	
    	}
    	
    }
    
    $b = [];
    
    foreach($a as $key => $values) {
    	
    	$copyB = $b;
    	$newB = [];
    	foreach($values as $value) {
    		$currentB = $copyB;
    		addValue($currentB, $key, $value);
    		$newB = array_merge($newB, $currentB);
    	}
    	$b = $newB;
    	
    }
    
    print_r($b);
    Ответ написан
    3 комментария
  • Как вывести записи отсеяв копии определенному по полю в yii2?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    SELECT DISTINCT code_medication, MIN(price) FROM tailings t GROUP BY code_medication LIMIT 50;


    Product::find()
    ->distinct()
    ->select('code, MIN(price)')
    ->from('product')
    ->groupBy('code');


    SELECT * FROM tailings t WHERE t.price = (SELECT MIN(t2.price) FROM tailings t2 WHERE t2.code_medication = t.code_medication) GROUP BY t.code_medication;


    $subQuery = (new Query())->select('MIN(t2.price)')->from('tailings t2')->where('t2.code_medication = t.code_medication');
    $query = Product::find()->from('tailings t')->where(['t.price' =>  $subQuery])->groupBy('t.code_medication');
    
    $countQuery = clone $query;
    
    $pages = new Pagination([
          'totalCount' => $countQuery->count(),
          'pageSize' => 15,
          'forcePageParam' => false,
          'pageSizeParam' => false,
        ]);
        
    $products = $query->offset($pages->offset)->limit($pages->limit)->all();
    Ответ написан
  • Как правильно сравнить даты?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    Вариантов много, можно создать свой валидатор:
    ['birth_date', 'date', 'timestampAttribute' => 'birth_date', 'timestampAttributeFormat' => 'php:Y-m-d'],
    ['death_date', 'date', 'timestampAttribute' => 'death_date', 'timestampAttributeFormat' => 'php:Y-m-d'],
    ['death_date', function($attribute, $params) {
        if (\DateTime::createFromFormat("Y-m-d", $this->{$attribute})->getTimestamp() < \DateTime::createFromFormat("Y-m-d", $this->birth_date)->getTimestamp()) {
        $this->addError($attribute, 'Дата смерти не может быть меньше даты рождения.');    
    }
    }]


    Можно все это проверять в afterValidate():
    if (\DateTime::createFromFormat("Y-m-d", $this->death_date)->getTimestamp() < \DateTime::createFromFormat("Y-m-d", $this->birth_date)->getTimestamp()) {
        $this->addError($attribute, 'Дата смерти не может быть меньше даты рождения.');    
    }
    Ответ написан
    Комментировать
  • Как сделать фильтрацию по ролям в GridView?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    Делаете LEFT JOIN к таблице auth_assignment и указываете роль, делаете проверку связанной таблицы на NULL
    $aq = Users::find()->distinct()->alias('u');
    if ($this->role !== null) {
        $aq->leftJoin('auth_assignment a', 'a.user_id = u.id AND a.item_name = :role', [':role' => $this->role]);
        $aq->where("a.user_id IS NOT NULL");
    }


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

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    Статичный метод отдает объект класса QueryBuilder
    Ответ написан
    Комментировать
  • Условие если N одинаковых элементов в массиве?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    package main
    
    import "fmt"
    
    // Структура для сохранения результатов
    type concurrences struct {
    	number int
    	count int
    }
    
    // Функция для инкремента элемента
    func inc(num int) {
    	changed := false
    	for i:=0; i < len(conc); i++  {
    		if conc[i].number == num {
    			conc[i].count++
    			changed = true
    			break
    		}
    	}
    	if !changed {
    		conc = append(conc, concurrences{num, 1})
    	}
    }
    
    var conc = []concurrences{}
    
    // Массив с элементами
    var numbers = []int{1, 2, 6, 2, 1, 9, 0, 3}
    
    func main() {
    
    	for i:=0; i < len(numbers); i++  {
    		inc(numbers[i])
    	}
    
    	// Отдаст элемент и кол-во его вхождений в массив
    	// [{1 2} {2 2} {6 1} {9 1} {0 1} {3 1}]
    	fmt.Println(conc)
    
    	 // N - кол-во вхождений элемента в массив
    	 N := 2
    
    	 // Выводим все элементы которые есть в массиве N раз
    	 for i:=0; i < len(conc); i++ {
    		if conc[i].count == N {
    			fmt.Println(conc[i].number)
    		}
    	 }
    
    }
    Ответ написан
    Комментировать
  • YII2 "failed to open stream: No such file or directory" Как исправить?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    @webroot указывает на корень приложения, нужно использовать его:
    $file->saveAs(Yii::getAlias('@webroot').'/uploads/'.$file->name);
    Ответ написан
    Комментировать
  • Не вывести аватарку через Steam API, как правильно построить код?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    Когда-то писал библиотеку для Steam API, может пригодится:
    https://github.com/mhthnz/SteamPlayer
    Есть методы для получения ссылки на аватар (3 размеров) и скачивание аватара:
    // Steam api key
    SteamPlayer::$API_KEY = 'api key'; 
    
    // Массив идентификаторов стима
    $steamIDs = [
        'xxxxxxxxxxxxxxxxxxxxx', 
        'xxxxxxxxxxxxxxxxxxxxx', 
        'xxxxxxxxxxxxxxxxxxxxx'
    ];
    
    // Отдает коллекцию объектов SteamPlayer
    $SteamPlayerCollection = SteamPlayer::Create($steamIDs);
    
    // Получаем массив инстансов SteamPlayer[] и выводим ссылку на большой аватара у каждого
    foreach($SteamPlayerCollection->get() as $player){
        echo $player->avatar(SteamPlayer::AVATAR_LARGE);
    }
    Ответ написан
    Комментировать
  • Куда мог деться php.ini?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    Создайте PHP файл и впишите туда:
    phpinfo();

    Либо из консоли.

    Linux/Unix/MacOS:
    php -i | grep 'php\.ini'
    Windows:
    php.exe -i | findstr /R /C:"php\.ini"
    Ответ написан
    8 комментариев
  • Как запретить некоторым пользователям обращение к modules?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    В кофиге:
    'modules' = [
        'admin' => [
            'class' => 'admin\Module',
            'as access' => [
                'class' => 'yii\filters\AccessControl',
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => ['admin'],
                    ],
                ],
            ],
        ],
    ]
    Ответ написан
    Комментировать
  • Как организовать использование виджета alert с pjax?

    mhthnz
    @mhthnz
    PHP, YII2, Golang, Linux
    Мне кажется виджет вам тут не нужен, используйте стандартный метод сохранения - через экшин контроллера, ибо виджеты предназначены в основном для отображения каких то частей фронтенда. Так же увас дублирование кода очень большое, вы 3 раза рендерите вьюху, тогда как можно все это сделать 1 раз после условий. Так же нет смысла что-то записывать в сессию так как вы рендерите через pjax, вам достаточно передать сообщение во вьюху, и там его отрендерить в виде alert'a и не нужно будет использовать виджет Alert.
    Controller's action:
    $message = $status = null;
    
    if (Yii::$app->request->post()) {
        if ($model->save()) {
            $status = 'success';
            $message = 'Спасибо операция окончена';
        } else {
            $status = 'error';
            $message = 'Извините произошла ошибка';
        }
    }
    
    $this->render('html', [
            'model' => $model,
            'status' => $status,
            'message' => $message,
    ]);


    View:
    <?php if ($status !== null && $message !== null): ?>
        <div class="alert alert-<?=$status?>">
          <strong><?=$status?>!</strong> <?=$message?>
        </div>
    <?php endif; ?>
    .......
    .......
    Ответ написан
    Комментировать