Эхо-массив из MySQL PDO

У меня есть некоторый код MySQL, который я написал, который работает безупречно:

<?php
include 'dbconfig.php';

$startdate = date("Y-m-d", strtotime($_GET['startdate']));
$class = ($_GET['class']);
$city = ($_GET['city']);
$coverage = ($_GET['coverage']);

$sql="SELECT day, week, month FROM pricing 
  WHERE '" . $startdate . "' between start_date AND end_date and class='" . $class . "' and city='" . $city . "' and coverage='" . $coverage . "'";
$result = mysqli_query($conn,$sql);


while($row = mysqli_fetch_array($result)) {

    $date_ranges = array(
        'day'   => $row['day'],
        'week'     => $row['week'],
        'month'     => $row['month']
    );

    mysqli_close($conn);

} 

$json = json_encode($date_ranges);
echo $json;
?>

Однако мне сказали использовать PDO, чтобы быть более безопасным, поэтому я конвертирую код в PDO, и я продвинулся так далеко:

<?php
include 'dbconfig.php';

$startdate = date("Y-m-d", strtotime($_GET['startdate']));
$class = ($_GET['class']);
$city = ($_GET['city']);
$coverage = ($_GET['coverage']);

try {
    $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $stmt = $conn->prepare("SELECT day, week, month FROM pricing 
  WHERE :startdate between start_date AND end_date and class=:class and city=:city and coverage=:coverage"); 

    $stmt->bindParam(':startdate', $startdate);
    $stmt->bindParam(':class', $class);
    $stmt->bindParam(':city', $city);
    $stmt->bindParam(':coverage', $coverage);

    $stmt->execute();

    $result = $stmt->setFetchMode(PDO::FETCH_ASSOC); 
    foreach(new TableRows(new RecursiveArrayIterator($stmt->fetchAll())) as $k=>$v) { 
        echo $v;

    }
}
catch(PDOException $e) {
    echo "Error: " . $e->getMessage();
}
$conn = null;
?>

Часть, которая является проблемой, наверняка заключается в следующем:

$result = $stmt->setFetchMode(PDO::FETCH_ASSOC); 
    foreach(new TableRows(new RecursiveArrayIterator($stmt->fetchAll())) as $k=>$v) { 
        echo $v;

Я пытаюсь получить вывод, чтобы он выглядел так (так же, как и первый):

{"day":"35","week":"150","month":"650"}

Может ли кто-нибудь показать мне, как это сделать? Спасибо!


person Community    schedule 27.09.2019    source источник
comment
Что такое TableRows? Почему вы используете RecursiveArrayIterator?   -  person Don't Panic    schedule 28.09.2019
comment
это ничего - я просто не очень понимаю PDO, и я использую учебник, который я нашел, чтобы изучить его, и это был пример по умолчанию.   -  person    schedule 28.09.2019
comment
Ах я вижу. Я думаю, что это может быть слишком сложно для того, что вы здесь делаете.   -  person Don't Panic    schedule 28.09.2019
comment
Что ты имеешь в виду?   -  person    schedule 28.09.2019
comment
Какой бы учебник вы ни нашли в Интернете, пожалуйста, выбросьте его. Оба примера кода, которые вы показали, полны сомнительного кода. Попробуйте phpdelusions.net/pdo   -  person Dharman    schedule 28.09.2019
comment
Я согласен с этим ^   -  person Don't Panic    schedule 28.09.2019


Ответы (2)


Какой бы учебник вы ни нашли, от него нужно отказаться. Код, который вы пишете, по-прежнему уязвим для SQL-инъекций, и вы не сильно улучшились. Вы только путаете себя с этим учебником. Пожалуйста, посетите https://phpdelusions.net/pdo, чтобы найти хорошее руководство по PDO.

Что касается кода, который вы написали, вы должны рассмотреть несколько изменений:

  1. Установите правильную кодировку и, желательно, отключите эмулированные операторы (по умолчанию включены, но они вам не нужны).

  2. Используйте PHP-класс DateTime вместо strtotime() и date(). Он прочнее и надежнее.

  3. Не используйте класс TableRows, каким бы он ни был. Тебе это не нужно! Прочтите это сообщение: Неустранимая ошибка: класс TableRows не найден в

  4. Не перехватывайте исключения только для того, чтобы отобразить их. Они будут отображаться для вас с помощью PHP. Вы должны ловить их, только если знаете, как с ними обращаться.

<?php

include 'dbconfig.php';

$options = [
    \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
    \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
    \PDO::ATTR_EMULATE_PREPARES => false,
];
$conn = new \PDO("mysql:host=$servername;dbname=$dbname;charset=utf8mb4", $username, $password, $options);

$stmt = $conn->prepare("SELECT day, week, month FROM pricing 
    WHERE :startdate BETWEEN start_date AND end_date 
        AND class=:class 
        AND city=:city 
        AND coverage=:coverage");

// bind in execute with an array. 
$values = [
    'startdate' => (new \DateTime($_GET['startdate']))->format('Y-m-d'),
    'class' => $_GET['class'],
    'city' => $_GET['city'],
    'coverage' => $_GET['coverage']
];
$stmt->execute($values);

// echo all results in JSON format
echo json_encode($stmt->fetchAll());
person Dharman    schedule 27.09.2019
comment
Спасибо, просто к вашему сведению - мне пришлось удалить «Все» в «fetchAll», чтобы он вывел массив в правильном формате. - person ; 28.09.2019
comment
Если это новый вопрос, вы можете опубликовать новый вопрос, и я буду рад взглянуть на него, но я не могу обещать, что смогу ответить. В любом случае, оставьте этот вопрос как есть, если первоначальная проблема была решена. - person Dharman; 29.09.2019
comment
Благодарю вас! Проверьте эту ссылку: codereview.stackexchange. ком/вопросы/229826/ - person ; 29.09.2019

Если вы просто пытаетесь вывести результаты запроса в формате JSON,

echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));

должно работать нормально. Нет необходимости в дополнительных классах или цикле.


Между прочим, то, как вы это делаете с mysqli, может на самом деле иметь проблему, даже если кажется, что оно работает правильно. Похоже, что запрос потенциально может возвращать более одной строки, но $date_ranges перезаписывается каждый раз при запуске цикла, поэтому вы в конечном итоге выведете только последнюю.


Если действительно должен быть только один результат, вы должны использовать fetch() вместо fetchAll(), чтобы вы просто получили один объект в своем выводе JSON, а не массив объектов.

echo json_encode($stmt->fetch(PDO::FETCH_ASSOC));
person Don't Panic    schedule 27.09.2019
comment
который выводит: [{день:35,0:35,неделя:150,1:150,месяц:650,2:650}] вместо {день:35,неделя:150,месяц:650} - person ; 28.09.2019
comment
Разве вы не установили режим выборки FETCH_ASSOC? Это похоже на FETCH_BOTH по умолчанию. - person Don't Panic; 28.09.2019