• Как правильно перебрать вложенный массив и вывести результат?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Так и выводить. Во внутреннем фориче только категории, а не всё подряд.
    echo "<ul>\n";
    foreach ($goods as $name => $categories) {
        echo "<li>$name: ";
        foreach ($categories as $i =>$category) {
            echo $i ? ", " : "";
            echo $category;
        }
        echo "</li>\n";
    }
    echo "</ul>\n";
    Ответ написан
  • Как передать массив в Bash-скрипт?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Так и передать, а потом разбить на элементы
    Вариантов разбивки много, например из головы такой
    #!/bin/bash
    echo $1
    for lang in $(echo $2 | tr "," "\n")
    do
      echo $lang
    done


    ./script.sh "other parameter" ru,en,fr,de,kk,pe
    Ответ написан
    Комментировать
  • Как в php получить Последнее значение из таблицы mysql определенной даты даты?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Выносить имя таблицы и колонки в переменные не нужно. Их надо написать прямо в запросе.
    А дату надо подставлять в запрос через подготовленные выражения.

    Если в БД хранится только дата, то чтобы получить все строки за определённую дату, код будет такой.
    $sql = "SELECT * FROM название таблицы WHERE  DATE = ?";
    $result = $conn->execute_query($sql, [$dateNew]);
    $usersArray = $result->fetch_all(MYSQLI_ASSOC);

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

    SELECT * FROM название таблицы WHERE  DATE BETWEEN ? AND ?

    и в него подставлять значения "$dateNew 00:00:00" и "$dateNew 23:23:59"

    Чтобы получить одну запись, надо добавить в запрос оператор LIMIT 1, а fetch_all(MYSQLI_ASSOC) поменять на fetch_assoc()
    Чтобы получить "последнюю" запись, надо добавить в запрос сортировку по тому полю, по которому считается последовательность добавления. И сделать сортировку в обратном порядке
    Ответ написан
    1 комментарий
  • Как тестировать запросы и ответы из базы данных через phpunit?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Мне кажется, что найденные варианты работают не так. Используются они оба, а какой именно - зависит от того, что именно вы тестируете - запрос или ответ.

    Если говорить про "запросы к БД", то для таких тестов "массив с данными" использовать просто глупо. Это получится какой-то формальный тест: "проверяем, что метод возвращает массив из трех строк - и тут же возвращаем этот самый массив". В чем смысл? Если вы тестируете запрос к БД, то и надо тестировать запрос к БД. По-другому никак.

    Здесь я отвлекусь, и порассуждаю на тему того, что на самом деле тестирование - это гораздо более трудоёмкая задача, чем обычно считается. И как следствие, большая часть тестов - это такая вот туфта. Либо тест заранее возвращает нужные данные, либо тестирует один-два кейса. А вариантов неправильных входящих данных ведь может быть огромное количество. То есть по-хорошему на такой заведомо сложный (и принципиально неделимый!) метод нужно десятка два тестов.

    И сюда же использование для тестов БД другой системы. Например основная БД MySQL, а для тестов используется Sqlite. Тут сразу можно сказать, что это профанация. Различие даже в какой-то одной настройке БД может повлиять на результаты запроса (и теста как следствие) - а тут и вовсе используется совсем другая БД.

    С другой стороны, работу с БД скорее стоит тестировать не в юнит тестах, а скажем в интеграционных. Но не будем углубляться.


    Массив же "с данными, симулирующими ответ из базы данных" используется на следующему уровне, там где требуется "ответ из базы данных". Взьмём метод, который использует данные, полученные из БД. Например авторизация юзера. Этот метод должен не сам лезть в базу, а дёргать отдельный метод, вполне возможно, что совсем другого класса. И вот чтобы протестировать авторизацию, вы и мокаете метод для работы с БД, и из этого мока возвращаете тот самый массив без всякого обращения к бд.

    Здесь нелишне будет напомнить название доклада с одной из последних конференций по пхп. Дословно не помню, но что-то вроде "Делайте методы как можно короче. Ваши тесты скажут вам спасибо." Собственно, именно при тестировании очень быстро начинаешь понимать удобство атомарных (то есть выполняющих какую-то одну простую операцию) методов. А без тестов пройдёт довольно много времени, пока не понадобится этот длинный метод отрефакторить, и по итогам менять кучу кода, который его вызывает.

    Так что разбивайте ваши длинные методы на мелкие, и тогда вопрос, как их тестировать, в большинстве случаев отпадёт сам собой.
    Ответ написан
    1 комментарий
  • Почему после отправки формы обратной связи на почту приходят иероглифы?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    mail("info@grillgrad.ru", "order", "Имя: $name. Телефон: $phone" ,"Content-Type: text/plain; charset=UTF-8");

    Вместо вот этого всего
    Ответ написан
  • Почему не всегда правильно происходит вставка данных в MySQL?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Если я правильно понял, ваш вопрос состоит в том, что при вводе в форму значений name1 name2 name3 вы иногда получаете в БД запись с name1, name2, name2 name1.
    Мы не знаем, почему так происходит.
    Кроме этого, мы не знаем, с чего вы взяли, что в форму вводили именно name1 name2 name3.

    Самым очевидным объяснением (исходя из доступной нам информации) является то, что в форму тупо ввели именно эти значения: в первое поле формы name1, во второе - name2, а в третье - name2 и name1. Это простое и логически непротиворечивое объяснение. Если оно вам не подходит, то вы должны добавить в свой вопрос дополнительную информацию, которая делает это объяснение невозможным. Например привести логи, которые показывают, что в форму было введено совсем не это. Или по крайней мере добавить в вопрос полный код формы и скрипта-обработчика, а не какой-то огрызок.

    Кроме этого, как вам правильно заметили в комментариях, надо учиться работать с БД правильно. И никогда не подставлять переменные прямо в запрос, а передавать их через символы подстановки. Таким образом вы сразу отсеете большое количество вероятных проблем. Читайте как правильно использовать mysqli
    Ответ написан
    Комментировать
  • Почему код некорректно работает с кириллицей?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Неэффективность этого решения просто вопиёт к небу. Перебирать строку столько раз, сколько в ней букв - это же кощунство. Неужели нельзя за один проход посчитать символы, а за второй вывести их веса? И получить условные O(n*3) вместо O(n*3 + n^2).
    $len = mb_strlen($string);
    $counts = array_count_values(mb_str_split($string));
    foreach ($counts as $letter => $count) {
        echo "$letter: " . round($count / $len * 100, 1). "\n";
    }

    И заодно не придётся выковыривать из строки отдельные символы, которые мы уже выковыряли через mb_str_split.

    А для практики будет полезнее реализовать подсчет символов самостоятельно, без использования встроенной функции РНР
    Ответ написан
    Комментировать
  • Как правильно хранить массив со словарями в MySQL?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    массив в БД э то таблица.
    вложенный массив - это связанная таблица
    по таблице на пользователя никогда не создают
    делается одна таблица, в которой у записи есть id пользователя
    по этому id выбираются все строки, принадлежащие пользователю

    подробнее можно сказать только увидев предполагаемую структуру данных
    про приведенный в вопросе огрызок можно только сказать, что наверное это будет таблица messages с полями id, user_id, role, content
    Ответ написан
    Комментировать
  • Как организовать умное кеширование MYSQL?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Как всегда, в заголовке одно, а в тексте вопроса совсем другое. И никакое кэширование автору делать на самом деле неохота - это же переделывать всё придется.

    При этом чего именно нужно автору, из вопроса непонятно. То ли проблема с потреблением памяти, то ли скорость запросов, то ли вообще никаких проблем нет, а просто поговорить на с кем.

    Ускорение запросов решается за счет создания индексов. Не "есть индексация", а конкретные осмысленные индексы для каждого используемого запроса. Если конкретный запрос тормозит, ему надо сделать explain, и на основе полученного результата подумать и реализовать индексы.
    При этом нормально индексы работают только если все они помещаются в памяти. А это значит, что по поводу "7 гигов занято" надо не плакать а радоваться.
    Существование "таблиц" для новых и старых сообщений в рамках одной таблицы - это партиционирование, например по дате. Но опять же, сначала надо определиться задачей, которую мы решаем.
    Ответ написан
    7 комментариев
  • Почему не работают cookie на хостинге?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Извините, но это не функция, а туфта.

    Главная проблема всех программистов-любителей в отсутствии логики. Вы делаете утверждения, которые вообще никак не следуют из приведённой информации. А зачастую и противоречат ей.

    Чтобы утверждать, что не работают именно куки, а не что-то ещё, в "функции" не должно быть никаких "$keys", "$a" и "$_SESSION". Это самая простейшая, базовая логика. Если мы проверяем какой-то функционал, то проверяем только его. Не внося никаких дополнительных сущностей.

    Учитывая, что сессионная кука ставится, это означает, что куки работают. А не работает "функция". И разбираться надо с ней. С помощью отладки.

    В принципе, неплохо проверить содержимое всех этих $keys", и "$_SESSION". Но в первую очередь надо сравнить НТТР заголовки, устанавливающие и ту и другую куку. При проблемах с куками надо смотреть не в Storage, а в Request. Там написано, какие и как именно куки ставятся, и какие куки браузер возвращает. И вот там-то и надо смотреть. А если самому непонятно, то в своем вопросе привести все заголовки Set-cookie из запроса. А не "функцию".
    Ответ написан
    1 комментарий
  • Есть ли в PHP готовый инструмент для получения элемента массива вложенность которого хранится в другом массиве?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Есть. Называется цикл.
    Ответ написан
    Комментировать
  • Почему игнорируется блок кода при подключении к бд?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Вопрос очень важный. Он показывает, насколько изменились подходы к программированию за четверть века.
    Вот этот детский лепет -
    spoiler
    if ($conn->connect_error) {
        die("Connection failed: " . $conn->connect_error);
    } else {
    echo "Connected successfully";
    }
    - происходит прямиком из прошлого века. Именно так писали на РНР3, в 1998 году.

    С тех пор прошло уже 25 лет, а пехопа всё так и пишет РНР немного подрос, и проверять ошибки при работе с БД вручную стало не нужно. А чтобы увидеть ошибку, надо всего лишь включить вывод ошибок РНР. На домашнем сервере достаточно просто написать в начале скрипта

    ini_set('display_errors', 1);

    (и не забыть поставить 0, когда код поедет на боевой).

    Соответственно, блок кода "игнорируется" просто потому, что ошибка является фатальной, и выполнение скрипта останавливается, ещё до всех этих if ($conn.
    Ответ написан
    Комментировать
  • Как корректно искать по регулярным выражениям в SQL?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Документацию полезно иногда читать.
    В ней шрифтом по фону написано, что
    To use a literal instance of a special character in a regular expression, precede it by two backslash (\) characters. The MySQL parser interprets one of the backslashes, and the regular expression library interprets the other.
    Ответ написан
    1 комментарий
  • Как написать bash скрипт для ffmpeg большого количества файлов?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Непонятно, к чему столько телодвижений
    просто заходим в папку и выполняем в командной строке несложную команду
    for file in *.mp3; do ffmpeg -i image.jpg -i "$file" -acodec copy  "${file%.*}.mp4"; done


    Общий принцип "выполнить команду для всех файлов" легко гуглится. Единственная хитрость - обрезка расширения, но вполне можно было ведь и оставить.
    Ответ написан
    Комментировать
  • Как мне выводить из базы данных информацию по группам?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Я только недавно начал изучать программирование

    Это очень похвально. Только ради бога, учите его по нормальным учебникам, а не по видеокурсам, которые делали неграмотные дети на мамкином ноутбуке.
    Примеры говнокода

    • unction selectAll1 - это глупость и говнокод. У функции должно быть осмысленное имя
    • ($table1 , $table2 , $table3 , $table4 , $table5){ - это глупость и говнокод. Учитывая, что функция в любом случае уникальная для используемых таблиц, передавать их в качестве параметров имеет 0 смысла.
    • global $pdo; - это глупость и говнокод. Потом сами не будете знать, что откуда взялось. Все параметры надо передавать в функцию явно.
    • dbCheckError($query); - это глупость и говнокод. Специально проверять запрос на ошибки не нужно. Надо написать один общий обработчик ошибок для всего сайта и любых ошибок.
    • <?=$contacts['filial']?> - это говнокод и дыра в безопасности. В любых данных, выводимых в HTML, должны экранироваться спецсимволы HTML


    Поскольку вы используете PDO, то можете сразу получить трехмерный массив, сгруппированный по одному полю
    function listContactsByDepartment ($pdo){
        $sql = "SELECT 
        t3.department, -- обращаем внимание на эту строчку. Она должна быть первой
        t1.id,
        t1.full_name,
        t1.email_user,
        t1.tel_number,
        t2.filial,
        t3.department_email,
        t4.position,
        t5.number
        FROM contact_work AS t1 INNER JOIN filial_work AS t2  ON t1. id_filial = t2.id 
        INNER JOIN department_work AS t3 ON t1. id_department = t3.id
        INNER JOIN position AS t4 ON t1. id_position = t4.id
        INNER JOIN number_work AS t5 ON t1. id_number = t5.id
        ORDER BY `t2`.`filial` ASC , `t3`.`department` DESC ";
        return $pdo->query($sql)->fetchAll(PDO::FETCH_GROUP); # Обращаем внимание на эту константу
    }
    $contacts = listContactsByDepartment ($pdo);

    Из этой функции вы получите трехмерный массив, который выводится двумя вложенными циклами
    <?php foreach($contacts as $department_title => $department_contacts): ?>
                          <tr>
                            <td colspan=10><?=htmlspecialchars($department_title) ?>
                          <tr>
        <?php foreach($department_contacts as $row): ?>
                          <tr>
                            <td><?=htmlspecialchars($row['filial']) ?></td>
                            ...
                          </tr>
        <?php endforeach ?>
    <?php endforeach ?>
    Ответ написан
    Комментировать
  • Почему не сохраняется первый файл?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Я думаю, что аффтар не справился с циклами. И подставляет телегу вперед лошади оба имени файла в первой же итерации. Тогда всё объяснимо:
    - и ВНЕЗАПНО возможность записи в несуществующий файл
    - и битвы бессмертных файлов, из которых останется только один

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

    Если бы автор осилил сразу привести полный код, а не какой-то огрызок, то куча людей не потратила бы кучу времени на бессмысленные гадания.
    Ответ написан
    1 комментарий
  • Include не работает после переезда на другой хостинг?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    • include "https://сайт/include.php"; - это идиотизм, и не должно работать. и не будет. Можно сразу забыть и идти исправлять на нормальные пути. Будет гораздо быстрее чем ныть здесь.
      Можно попробовать заменить на include $_SERVER['DOCUMENT_ROOT']."/include.php"; если это свой сайт. Если чужой, то просто выкинуть эту строчку совсем. Ну или попробовать заменить на file_get_contents
    • include "include.php"; будут работать, если указать абсолютный путь. Хотя бы так,include __DIR__."/include.php";, но в некоторых случаях может не сработать
    • если инклюды "заработали" после добавления AddHandler application/x-httpd-php .php .html .shtml .htm в файл .htaccess, это значит, что не работали не инклюды, а не работал РНР в html файлах. Он как бы и не должен, но на этом кривом сайте видимо такое использовалось. В любом случае эта строчка никакого отношения к инклюдам не имеет.
    Ответ написан
  • Почему возникает SQLSTATE[HY000]: General error: 2014 при прямой вставке данных в MySQL таблицы через DBAL?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Потому что при работе через API запросы должны выполняться по одному, а не кучей.
    Все эти точечки с запятой предназначены для консоли, а через API с мультизапросами всегда будут проблемы (даже если у какого-то умника в его песочнице с куличиками проблем до сих пор не было).
    Потому что API предназначено для выполнения запросов по одному.

    Тем более что здесь нужно всего три запроса, а не 100500. Множественная вставка делается не так, а одним запросом. При этом, как нас учат в первом классе, запросы должны быть параметризованными а не вот это вот всё.
    Ответ написан
  • В чем ошибка SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Дополню предыдущий ответ правильным кодом, без вот этих всех бессмысленных телодвижений, которые понатыканы в исходном вопросе.
    $query = "UPDATE `users` SET `address`= ?,`phone_number`=?  WHERE email=?";
    $params = [
        $address,
        $phone_number,
        $email,
    ];
    $stmt = $pdo->prepare($query);
    $stmt->execute($params);

    Только орфографические ошибки в именах полей поправил
    Ответ написан
    Комментировать