Отразяване на масив от 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. Използвайте класа DateTime на PHP вместо 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. com/questions/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
който извежда: [{day:35,0:35,week:150,1:150,month:650,2:650}] вместо {day:35,week:150,month:650} - person ; 28.09.2019
comment
Не си ли задал режима на извличане на FETCH_ASSOC? Това изглежда като FETCH_BOTH по подразбиране. - person Don't Panic; 28.09.2019