• Нужно ли фильтровать глобальные переменные в PHP?

    @alexalexes
    Можно ограничится проверками только тех данных, которые приняты от клиентской части системы и могут быть заведомо изменены пользователем так, чтобы вызвать неожиданное поведение в серверной части.
    Если один метод генерирует данные для другого метода на стороне сервера, и они без проверок не выходят транзитом через клиентскую часть приложения или через другую часть приложения, где есть канал связи (точка отказа), то можно не делать проверки в каждом методе. Важно соблюдать условие, что если какой-то элемент данных пришел от пользователя и на входе в серверной части его проверили один раз (может быть даже заэкранировали), то внутри системы этим элементом данных уже можно спокойно пользоваться.
    Нужно ли фильтровать данные из _COOKIE, _HEADER, _SERVER,
    к примеру
    ?query=
    выдает модальное окошко если запустить $_SERVER['[REQUEST_URI']

    Вы ничего не запускаете, вы просто отдаете ответ браузеру (делаете эхо) от того, что пришло в части строки адреса, где содержатся get-параметры.
    Браузер, не получив внятного описания, что ему ответили html содержимым, пытается обернуть ответ в нечто валидное по html нотации:
    <html>
    <body>
    ?query=<script>alert('о, привет!'); </script>
    </body>
    </html>

    Далее, браузер пытается воспроизвести это. Строит DOM-дерево, находит тег script, пытается выполнить у себя JS-код. На этом можно обжечься когда выводите сведения в textarea.
    $unsafe_string_for_html = "<script>alert('о, привет!'); </script>";
    echo '<textarea>'.$unsafe_string_for_html.'</textarea>';

    Чтобы такое не происходило, перед выводом небезопасных для html разметки элемента данных, нужно над ним провести экранирование.
    $unsafe_string_for_html = "<script>alert('о, привет!'); </script>";
    $safe_string_for_html = htmlspecialchars($unsafe_string_for_html);
    echo '<textarea>'.$safe_string_for_html.'</textarea>';

    Можно провести экранирование и в момент получения данных, тогда при отдаче браузеру можно будет быть уверенным, что это не выполняемые инструкции, а текстовые данные с точки зрения html. Однако, когда сохраняете в базу эти данные или делаете их обработку, нужно иметь ввиду что они прошли экранирование по html и содержание некоторых символов будет немного другое чем это проецируется в браузере.
    Ответ написан
    1 комментарий
  • Как массово изменить расширение изображений на свой фомат в MYSQL базе?

    @alexalexes
    Этим запросом крайне внимательно изучаете - удовлетворяет ли вас результат преобразования строк в result_mod_f1 из mod_f1, и result_mod_f2 из mod_f2.
    select mod_f1,  replace(mod_f1, '.png', '.webp') as result_mod_f1,
              mod_f2,  replace(mod_f2, '.png', '.webp') as result_mod_f2
    from table

    Если что-то не устраивает, переписываете replace-ы.
    Если что-то переписали, то заменяете выражения в правых частях после знака =, чтобы преобразование mod_f1 соответствовало mod_f1, а преобразование mod_f2 для mod_f2.
    /*update table
    set mod_f1 = replace(mod_f1, '.png', '.webp'),
          mod_f2 = replace(mod_f2, '.png', '.webp')*/

    Снимаете комментарий, словно собираетесь открыть защитную крышку на красной кнопке атомной бомбы и выполняете запрос.
    ПС: Желательно делать это в программном средстве, которое поддерживает режим незакрытой транзакции, чтобы можно было откатить.
    ППС: Если таблица очень большая, то лучше обновлять порциями.
    /*update table
    set mod_f1 = replace(mod_f1, '.png', '.webp'),
          mod_f2 = replace(mod_f2, '.png', '.webp')
    where mod_f1 like '%.png%'
          or mod_f2 like '%.png%'
    LIMIT 1000 */
    Ответ написан
    5 комментариев
  • Как в PostgreSQL просуммировать Киловаты, группируя их по временным интервалам?

    @alexalexes
    select p.endpoint_id,
           p.mode_start as event_start,
           (p.mode_start + p.mode_duration) as event_end,
           sum(e.kwh) as sum_kwh
    from periods p
    join energy e on e.endpoint_id = p.endpoint_id -- связываем выставленный период для прибора с показаниями прибора
                 and p.mode_start <= e.event_time -- связывание начало периода с моментом замера 
                 and (p.mode_start + p.mode_duration) > e.event_time -- связывание конца периода с моментом замера
    group by p.endpoint_id, p.mode_start, (p.mode_start + p.mode_duration)
    order by p.endpoint_id, p.mode_start

    Примечание.
    1. Запрос составлен без отладки, требуется отладка.
    2. Если периоды накладываются у одного и того же прибора, то замер, в интервале где происходит накладка, попадет в сумму в обоих периодах.
    3. Если для событий не прописан период, то они не будут учитываться. Можно написать такую связку через left join так: "... energy e left join periods p on ... ", тогда сумма неучтенной энергии упадет в отдельную строку, в которой будет отсутствовать период.
    Запрос для вывода неучтенных замеров:
    select e.endpoint_id,
           p.mode_start as event_start,
           (p.mode_start + p.mode_duration) as event_end,
           sum(e.kwh) as sum_kwh
    from  energy e 
    left join periods p on e.endpoint_id = p.endpoint_id
                 and p.mode_start <= e.event_time
                 and (p.mode_start + p.mode_duration) > e.event_time
    group by e.endpoint_id, p.mode_start, (p.mode_start + p.mode_duration)
    order by e.endpoint_id,
             p.mode_start nulls first -- ставим первой строкой сумму замеров с неучтенными значениями (в пределах одного прибора)
    Ответ написан
  • Как реализовать такое на сайте?

    @alexalexes
    Самый простой концепт:
    1. При успешной авторизации создаем переменную cookie с временем жизни равным времени жизни сессии, с доступом http only, с идентификатором сессии.
    2. Если пользователь разлогинивается, то уничтожаем переменную cookie с идентификатором сессии.
    3. При генерации страницы в php, где нужно вывести статус авторизации, проверяем наличие живой куки.
    4. Если совершаем действие, требующее авторизации, дополнительно проверяем время жизни сессии в базе данных (если такой учет ведется).
    Ответ написан
  • Когда нужно писать имя таблицы в запросе?

    @alexalexes
    Всегда обзывайте каждую таблицу в запросе кратким именем, и это краткое имя используйте в именовании колонок, тогда ни при каких условиях проблем с конфликтом имен не возникнет.
    SELECT t1.ProductCode, t2.Name
    FROM table_one as t1 -- t1 - краткий псевдоним таблицы table_one в пределах select-а
    LEFT OUTER JOIN table_two as t2 -- t2 - краткий псевдоним таблицы table_two в пределах select-а
    ON  t2.id = t1.id_client;
    Ответ написан
  • Как принимать сообщения от посетителей об ошибках на сайте?

    @alexalexes
    Выделите ошибку и нажмите одновременно клавиши «Ctrl» и «Enter»

    Такой функционал был популярен в начале 2000-х, когда основное место в содержимом сайта занимал текст, а верстка была вполне примитивна.
    В сегодняшнее время проблемы на сайте могут быть не только в текстовом содержимом, но и в интерактивном функционале, а такое можно зафиксировать только скриншотом.
    Поэтому, не критично, если у вас на сайте не будет такого функционала с выделением ошибки. Главное, дать возможность отправить сообщение администрации сайта любым доступным способом. Туда хоть копируй текст, хоть делай скриншот.
    Добавлено:
    Для мобильной версии сайта единственный выход - отображать ссылку или кнопку "Сообщить об опечатке" после основного текстового содержания, нажатие на которую вызывает тот же обработчик, что и Ctrl + Enter.
    Ответ написан
  • Создания уникального чата: sql, node, socket.io?

    @alexalexes
    Есть роль А И B. Только роль A может начать чат с ролью B

    Роли у пользователей заданы на уровне учетной записи и не меняются от чата к чату или определяются в момент создания чата?
    То есть при создании чата будут определена роль администратора (создателя) которая будет более привилегирована, чем тот, кому он пишет?
    Чат может содержать только 2х лиц

    Вы очень оптимистичны, выставляя такое ограничение. В следующей итерации разработки вам захочется сделать функционал группового чата. Тогда наличие колонок user_id, second_user_id вам встанет боком.
    В таблицу chat лучше добавить такие колонки:
    id - идент. чата
    date_create - дата создания
    id_user_creator - кто создал чат
    title - название чата (в этой итерации разработки можно не вставлять)
    Для участников чата лучше предусмотреть таблицу chat_participant:
    id - идент. участника
    id_chat - идент. чата из таблицы chat
    id_role - роль в чате (если она определяется в момент создания, для группового чата)
    id_user - пользователь чата
    id_last_read_message - идент. последнего прочитанного сообщения (самый простой вариант, как отмечать что прочитано, и потом определять, есть ли новые сообщения)
    date_include - дата вступления в чат (для группового чата)
    date_exclude - дата исключения из чата (для группового чата)
    Для сообщений чата - таблица chat_message:
    id - id сообщения
    id_partic/id_user - автор сообщения (можно реализовать как по ключу от таблицы участника, так и по таблице пользователей)
    date_create - дата создания сообщения
    date_update - дата обновления сообщения (для продвинутого функционала редактирования сообщений)
    date_delete - дата удаления сообщения (для продвинутого функционала редактирования сообщений)
    text_message - текст сообщения
    Если совсем хотите быть продвинуты в функционале редактирования сообщений, то вы захотите хранить историю изменения сообщений в таблице chat_message_history:
    id - идент. истории
    id_next - указатель на следующую запись истории
    id_message - идент. сообщения
    date_change - дата изменения сообщения
    id_user/id_partic - кто изменил
    text_message - состояние текста сообщения
    Ответ написан
    Комментировать
  • Можно ли удалить некоторый список товаров вместе с изображениями из интернет-магазина на Wordpress через SQL?

    @alexalexes
    Можно. Если файлы изображений хранятся в файловой системе сервера, то составляете запрос, который получает ftp-пути к каждому файлу, по id конкретного товара. Затем составляете запрос-выборку по id товарам, которые нужно удалить.
    1. Запускаете запрос, получающий выборку id товаров.
    2. Выбираете одну строку запроса шага 1.
    3. Запускаете запрос, получающий выборку ftp путей изображений.
    4. Получаете одну строку из запроса шага 3.
    5. Удаляете файл из файловой системы сервера.
    6. Идем на шаг 4, пока не кончится выборка изображений.
    7. Помечаем товар как удаленный (запрос на обновление).
    8. Идем на шаг 2, пока не кончится выборка товаров для удаления.
    Конец.
    Ответ написан
    Комментировать
  • Зачем нужен символ "&" перед функцией?

    @alexalexes
    Ответ написан
    Комментировать
  • Как лучше реализовать вывод в корзину?

    @alexalexes
    1. Ограничьте количество предметов в корзине каким-то макс. значением, оно должно быть явно задано, но не вызывало дискомфорта у пользователей (оно должно иметь такое значение, чтобы в нормальных человеческих условиях оно едва достижимо).
    $max_cart_item_count = 500;
    $curr_cart_item_count = min(count($_SESSION['cart']), $max_cart_item_count);
    for($i = 0; $i < $curr_cart_item_count; $i++)
    ....

    2. Есть опасность применения SQL инъекций.
    В этом месте, где подставляется переменная в текст запроса, если умело закомментировать кавычку, то можно получить полный доступ к базе.
    WHERE `type`= '$id'
    Избегайте подставлять любые переменные с пользовательскими данными в текст запроса ("с пользовательскими данными" и "в текст запроса" - нужно подчеркнуть и осмыслить как отдельные понятия с точки зрения безопасности). Для этого существует специальные методики подготовки запроса:
    $stmt = $conn->stmt_init();
    $stmt->prepare("SELECT * FROM `items` WHERE `type` = ?"); // подставляем текст запроса, причем на месте входных параметров ставим специальные маркеры - плейсхолдеры.
    $stmt->bind_param("i",  $id); // подставляем на место плейсхолдера значение параметра как целочисленный тип
    $stmt->execute(); // вот теперь можно выполнить запрос
    $result = $stmt->get_result();
    while($row = $result->fetch_assoc())
    {
     // Обработка результатов
    }
    Ответ написан
  • Отправка изображения canvas на сервер PHP?

    @alexalexes
    btn_send.addEventListener('click',async() => {
        let blob = await new Promise(resolve => canvasElem.toBlob(resolve, 'image/png'));
        let formData = new FormData(); // Создаем объект формы для наполнения данными, словно мы работаем с тегом form в html.
        formData.append('canvas_field', blob, 'canvas.png'); // это эквивалент тому, что в нашей html форме создаем поле input type="file" name="canvas_field" value="canvas.png" и прикрепляем туда содержимое blob (метод append сам расшаривает blob, дополнительных преобразований не требуется). Естественно, на DOM-дереве это никак не отразится, это модель формы в памяти JS.
        let response = await fetch('web_tp_word.php', {
        method: 'POST',
        body: formData // для fetch не нужно дополнительных параметров, чтобы объяснить как работать с formData. Идеально, чтобы завернуть файл в форму и отправить на сервер.
        });
    });

    На стороне сервера:
    var_dump($_FILES['canvas_field']); // Сервер при вызове скрипта сложит данные файла во временный файл, а как их получить - в $_FILES. Далее можно обрабатывать всеми теми способами, предназначенные для работы с $_FILES. И после уже неважно, как их сгенерировали на клиенте.
    Ответ написан
    1 комментарий
  • Помощь с пониманием устройства debounce?

    @alexalexes
    ...args
    arguments
    Это специальные объекты JavaScript. Их заполняет сама среда интерпретарора JS, когда становится активным контекст вызываемой функции. Очень помогает обрабатывать аргументы функции, когда их количество неизвестно заранее, или нужно специально сделать такую функцию, которая обрабатывает произвольное число аргументов.
    какая из реализаций лучше?
    Если стоит задача написать полифил для поддержки старых версий браузера, то следует использовать объекты JS, которые поддерживаются как можно в ранней версии стандарта языка (смотрите таблицу совместимости браузеров с тем или иным стандартным объектом).
    Если такой задачи нет, то берем стильные, модные, молодежные языковые конструкции.
    Ответ написан
    Комментировать
  • Почему не стоит передавать аргументы в функцию по ссылке?

    @alexalexes
    В отдельных задачах только передача по ссылке и спасет, если стоит цель не хапнуть лишней оперативной памяти при выполнении скрипта.
    Например, вам нужно обработать массив с over9000 элементами какой-то отдельной функцией. При существовании этого массива съедается 70% оперативной памяти. Вот тут вам ссылка на этот массив в помощь.
    Ответ написан
    Комментировать
  • Как правильно изменить sql запрос чтобы считывать данные с двух строк одной базы данных?

    @alexalexes
    Если предположить, что в таблице _post_extras есть столбец user_id, при этом данная таблица хранит расширенные сведения о записях другой таблицы - _post, каждая запись которой связана с первой таблицей отношением 1 к 1, через ключ post_id (название столбца-ключа как с первой таблицей, так и со второй автор не сообщал, но такая связь обязана существовать), получается следующее:
    SELECT SUM(rating) as rating, SUM(vote_num) as num
      FROM " . PREFIX . "_post_extras as pe
      inner join " . PREFIX . "_post as p on p.post_id = pe.post_id -- тут название ключей post_id с обеих сторон нужно уточнять!
    WHERE pe.user_id ='{$id}'
         and p.category = '{$category_id}'

    Также нужно уточнить автору, что должен вернуть запрос. Данный запрос вернет суммарный рейтинг и голосов по конкретному пользователю в конкретной категории публикаций.
    Ответ написан
    Комментировать
  • Как запустить windows с ssd?

    @alexalexes
    Загрузиться с того же носителя, с которым устанавливали Windows и из командой строки поработать с загрузочными записями.
    Ответ написан
  • Можно ли на новой мат.плате установить старую видеокарту?

    @alexalexes
    Во времена царствования AGP интерфейса можно было получить поломку в виде короткого замыкания, если стандарт питания не был соблюден на мат. плате и видеокарте.
    Но сейчас давно времена PCI-E, такое в принципе невозможно на данном интерфейсе. Так что, ставьте смело.
    Ответ написан
    Комментировать
  • Получить аудиофайл из запроса к Google Translate?

    @alexalexes
    https://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&tl=en&q=Ваш+текст+на+английском

    Такой вариант работает, но не исключено, если будете эспериментировать с параметрами или частотой запросов, то будут блокировки.
    Ответ написан
    Комментировать
  • Как сравнить два поля VARCHAR и INT?

    @alexalexes
    Как выглядит ваша проблема:
    Таблица новостей:
    ID, CATEGORIES
    1, '1,13,14'

    Как нужно реализовать:
    Добавить еще таблицу Categories_Of_News
    ID, NEWS_ID, CATEGORY_ID
    1, 1, 1
    2, 1, 13
    3, 1, 14

    Тогда запросы не будут содержать никаких костылей с парсингом строк и у вас будут работать индексы (если их создать).
    Например, получить все категории, в которые входит новость :news_id
    select  C.Id
    from News N
    join Categories_Of_News CoN on CoN.News_Id = N.Id
    join Category C on C.Id = CoN.Category_Id 
    where N.Id = :news_id

    PS: Смотрите, как реализовать связь "многим-ко-многим".
    Ответ написан
    Комментировать
  • Почему событие onchage не срабатывает для select?

    @alexalexes
    Есть события: click, change, input и т.д.
    Привязка обработчика соответствующего события с использованием атрибута тэга осуществляется с приставкой on:
    <select id="selectTheme" onchange="alert('Theme changed')">
    </select>

    Но в тоже время, привязка обработчика события с использованием addEventListener не требует указания on, берется само название события и с названием атрибута не нужно путать:
    sel.addEventListener('change', (event) => {
        	alert('Theme changed');
        })
    Ответ написан
    3 комментария
  • Для чего нужны спецификаторы в C?

    @alexalexes
    Чтобы дать функции printf дополнительную информацию, в каком виде вы хотите вывести результат второго и последующих аргументов этой функции. Спецификаторы имеют определенное отношение к такому понятию, как тип данных. В выводе типа вещественного числа можно настроить знаковую точность, поэтому есть не только %f, но и %0.f и т.д.
    https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D1%81%D...
    Ответ написан
    Комментировать