Скрипт PHP / MySQL для отправки писем - одно письмо слишком много

Я сделал PHP-скрипт для отправки отчетов из базы данных MySQL пользователям по электронной почте. Каждый пользователь должен получать только свои данные (со своим идентификатором). Скрипт tabela.php создает html-таблицу с пользовательским контентом.

<?php

//select data
$sql = "SELECT oports.id, oports.handlowiec, oports.data_rozp, oports.data_przed, oports.nazwa, oports.city, oports.nip, oports.inic, db_users.email FROM oports, db_users WHERE db_users.id = oports.user_id and db_users.id = '{$sqlid}'";

//execute query
$wynik = $polaczenie->query($sql);

//make table schema
echo "<p style=\"font-size:14px;\">There is your report:<br></p>";
echo "<p>";
echo "<table boder=\"1\"><tr>";
echo "<td bgcolor=\"#f4df8b\"><strong>ID</strong></td>";
echo "<td bgcolor=\"#f9d74d\"><strong>name</strong></td>";
echo "<td bgcolor=\"#f4df8b\"><strong>Date started</strong></td>";
echo "<td bgcolor=\"#f9d74d\"><strong>Date deadline</strong></td>";
echo "<td bgcolor=\"#f4df8b\"><strong>Company name</strong></td>";
echo "<td bgcolor=\"#f9d74d\"><strong>City</strong></td>";
echo "<td bgcolor=\"#f4df8b\"><strong>NIP</strong></td>";
echo "<td bgcolor=\"#f9d74d\"><strong>Initials</strong></td>";
echo "</tr>";

//loop for show data in table
 while ( $row = mysqli_fetch_row($wynik) ) {
    echo "</tr>";
    echo "<td bgcolor=\"#f7e8ab\">" . $row[0] . "</td>";
    echo "<td bgcolor=\"#fbe383\">" . $row[1] . "</td>";
    echo "<td bgcolor=\"#f7e8ab\">" . $row[2] . "</td>";
    echo "<td bgcolor=\"#fbe383\">" . $row[3] . "</td>";
    echo "<td bgcolor=\"#f7e8ab\">" . $row[4] . "</td>";
    echo "<td bgcolor=\"#fbe383\">" . $row[5] . "</td>";
    echo "<td bgcolor=\"#f7e8ab\">" . $row[6] . "</td>";
    echo "<td bgcolor=\"#fbe383\">" . $row[7] . "</td>";
    echo "</tr>";
 }
 echo "</table>";
 echo "<br>";
 echo "<p style=\"font-size:10px;\">Jest to e-mail wygenerowany z systemu CRM. Prosimy na niego nie odpowiadać</p>";

 ?>

Скрипт sender.php отправляет данные пользователю:

<?php

include 'connect.php';

//connect with database
$polaczenie = @new mysqli($host, $db_user, $db_password, $db_name);

//set charset to show polish letters
$polaczenie->set_charset("utf8");

//check connection
if ($polaczenie->connect_errno!=0)
    {
        echo "Error: ".$polaczenie->connect_errno." Opis: ". $polaczenie->connect_error;
    }
    else 
    {
        //define id variable
        $sqlid = 1;

        //select emails for user with id = sqlid
        $zap = "SELECT email from db_users where id = '{$sqlid}'";    

        //make query (for while loop)
        $zapt = $polaczenie->query($zap);

            //while there are some data, make instructions in loop
            while (($zapt -> fetch_assoc()) !== null)
            {
                    //there are results
                    //execute query again (without this loop do not work properly)
                    $zap = "SELECT email from db_users where id = '{$sqlid}'";
                    //show email and save to variable rowxx
                    $zapx = mysqli_query($polaczenie,$zap);
                    while ($rowx = mysqli_fetch_assoc($zapx)) {
                        print_r ($rowx);
                        $rowxx = $rowx["email"];
                    }
                    //include content of tabela.php
                    ob_start();
                    include "tabela.php";
                    $content = ob_get_clean();

                    //define mail headers, subject and message
                    $od  = "From: [email protected] \r\n";
                    $od .= 'MIME-Version: 1.0'."\r\n";
                    $od .= 'Content-type: text/html; charset=utf-8'."\r\n"; 
                    $to = $rowxx;
                    $subject = "Raport szans";
                    $message = $content;

                    if (mail($to, $subject, $message, $od)) 
                    {
                        echo "Mail sent!";
                    } 
                    else 
                    {
                        echo "Error with sending!";
                    }

                    $sqlid++;
                    $zapt = $polaczenie->query($zap);

            }
                //else

                echo 'No results';


        $polaczenie->close(); 
        }

?>

Скрипт работает нормально, но отправляет одно письмо слишком много для пользователя с последним идентификатором. Если есть 4 пользователя, последний получит два письма вместо одного - первое с правильными данными, а второе без данных (пустая таблица). Вывод сценария sender.php:

Array ( [email] => [email protected] ) Mail sent!Array ( [email] => [email protected] ) Mail sent!Array ( [email] => [email protected] ) Mail sent!Array ( [email] => [email protected] ) Mail sent!Mail sent!No results

Итак, я вижу, что в последней отправленной почте нет адреса электронной почты, но я получаю его на [email protected]. Почему?

while (($zapt -> fetch_assoc()) !== null) кажется подозрительным ... почему бы просто не while($zapt->fetch_assoc()) как false !== null
CD001 27.04.2018 17:27

почему вы используете вложенные while с тем же запросом? Возможные SQL-инъекции в SQL также вызывают подозрение.

Raymond Nijland 27.04.2018 17:28
ПРЕДУПРЕЖДЕНИЕ: при использовании mysqli вы должны использовать параметризованные запросы и bind_param для добавления пользовательских данных в свой запрос. НЕ использует для этого строковую интерполяцию или конкатенацию, потому что вы создали серьезный Ошибка SQL-инъекции. НИКОГДА помещает данные пользователя $_POST, $_GET или любой непосредственно в запрос, это может быть очень вредно, если кто-то попытается воспользоваться вашей ошибкой.
tadman 27.04.2018 20:43

Примечание. Объектно-ориентированный интерфейс mysqli значительно менее подробен, что упрощает чтение и аудит кода, и его нелегко спутать с устаревшим интерфейсом mysql_query. Прежде чем вы слишком увлечетесь процедурным стилем, стоит переключиться на него. Пример: $db = new mysqli(…) и $db->prepare("…"). Процедурный интерфейс является артефактом эпохи PHP 4, когда был представлен API mysqli, и его не следует использовать в новом коде.

tadman 27.04.2018 20:43

Я внес изменения в свой код в соответствии с вашими комментариями (упрощенный while, удалите вложенные while) и изменил порядок запросов в цикле while - и теперь работает отлично, но прежде чем добавить ответ, я хотел бы знать, как можно выполнить SQL-инъекцию в мой сценарий? У меня нет ни $ _POST, ни $ _GET, как туда вставить код? Конечно, печать писем в выводе скрипта сейчас нужна только для отладки. Этот скрипт будет добавлен в Cron или Task Scheduler.

Mateusz Nitka 30.04.2018 13:47
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
5
223
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Итак, я внес изменения в свой код (упростил while, удалил вложенные while и изменил порядок запросов в цикле while, который был причиной отправки одного письма слишком много), и теперь он работает отлично, но я до сих пор не знаю, как возможна SQL-инъекция. , потому что нет ни POST, ни GET.

<?php

include 'connect.php';

//connect with database
$polaczenie = @new mysqli($host, $db_user, $db_password, $db_name);

//set charset to show polish letters
$polaczenie->set_charset("utf8");

//check connection
if ($polaczenie->connect_errno!=0)
    {
        echo "Error: ".$polaczenie->connect_errno." Opis: ". $polaczenie->connect_error;
    }
    else 
    {
        //define id variable
        $sqlid = 1;

        //select emails for user with id = sqlid
        $zap = "SELECT email from db_users where id = '{$sqlid}'";    

        //make query (for while loop)
        $zapt = $polaczenie->query($zap);

            //while there are some data, make instructions in loop
            while ($rowx = $zapt -> fetch_assoc())
            {
                    //show e-mail recipient (for debug only)
                    print_r ($rowx);
                    $rowxx = $rowx["email"];

                    //include content of tabela.php
                    ob_start();
                    include "tabela.php";
                    $content = ob_get_clean();

                    //define mail headers, subject and message
                    $od  = "From: [email protected] \r\n";
                    $od .= 'MIME-Version: 1.0'."\r\n";
                    $od .= 'Content-type: text/html; charset=utf-8'."\r\n"; 
                    $to = $rowxx;
                    $subject = "Raport szans";
                    $message = $content;

                    if (mail($to, $subject, $message, $od)) 
                    {
                        echo "Mail sent!";
                    } 
                    else 
                    {
                        echo "Error with sending!";
                    }

                    //increment sqlid
                    $sqlid++;

                    //execute query again
                    $zap = "SELECT email from db_users where id = '{$sqlid}'";
                    $zapt = $polaczenie->query($zap);

            }
                //else

                echo 'No results';


        $polaczenie->close(); 
        }

?>

Другие вопросы по теме