ПОЧЕМУ выполнение массива в функции ниже вызывает исключение? - PullRequest
0 голосов
/ 28 февраля 2019

Я работаю над приложением голосования ussd, и у меня все получилось, кроме сохранения голосов в базе данных и обновления таблицы.

Функция, которая обрабатывает save_vote, указана ниже;

function save_vote($phone_number, $voted_for) {
        // Just the digits, please
        $phone_number = preg_replace('/\D/', '', $phone_number);

        // Check to see if person has already voted
        $stmt = $this->db->prepare('SELECT COUNT(*) FROM voters WHERE phone_number=?');
        $stmt->execute(array($phone_number));

        // If not, save their vote
        if ($stmt->fetchColumn() == 0)
        {
            // Save voter
            $stmt = $this->db->prepare('INSERT INTO voters (phone_number, voted_for) VALUES (?, ?)');
            $stmt->execute(array($phone_number, $voted_for));

            // Update vote count
            $stmt = $this->db->prepare('UPDATE brands SET votes = votes + 1 WHERE id=?');
            $stmt->execute(array($voted_for));

            return 'Thank you, your vote has been recorded';
        }
        else {
            return 'Sorry, you can only vote once.';
        }
    }

Значения, передаваемые в функцию: DB->save_vote('02778995805', 2)

В журналах сервера возникает следующее исключение:

1 {main}

2019-02-28T13: 50: 49.813224 + 00: 00 app [web.1]: добавляется в /app/db.php в строке 57

, а в строке 57 находится код $stmt->execute(array($phone_number)); is at.

Буду признателен за помощь в объяснении того, что может быть не так.

Спасибо

Как и просили комментарии, см. ниже

дБ.php code:

<?php
/**
 * Created by PhpStorm.
 * User: kqwameselase
 * Date: 2019-02-27
 * Time: 22:53
 */
    class DB {
        const DB_NAME = 'votes.sqlite';

    protected $db;

    function __construct() {
        $this->db = new PDO('sqlite:'.self::DB_NAME);
    }

    function init() {
        // Create two tables, one to store the brands being voted on and their vote counts (brands) and one to store the people that have voted (voters).
        $this->db->exec('CREATE TABLE IF NOT EXISTS brands (id INTEGER PRIMARY KEY, name TEXT, votes INTEGER);');
        $this->db->exec('CREATE TABLE IF NOT EXISTS voters (id INTEGER PRIMARY KEY, phone_number TEXT, voted_for INTEGER);');
    }

    function add_brand($name) {
        // Check to make sure the brand name doesn't already exist
        $stmt = $this->db->prepare('SELECT COUNT(*) FROM brands WHERE name=?');
        $stmt->execute(array($name));

        // If not, insert it
        if ($stmt->fetchColumn() == 0)
        {
            $stmt = $this->db->prepare('INSERT INTO brands (name, votes) VALUES (?, 0)');
            $stmt->execute(array($name));
        }
    }

    function get_brands() {
        $result = $this->db->query('SELECT * FROM brands');

        foreach ($result as $row)
        {
            $brand['id'] = $row['id'];
            $brand['name'] = $row['name'];
            $brand['votes'] = $row['votes'];

            $brands[] = $brand;
        }

        return $brands;
    }

    /**
     * @param $phone_number
     * @param $voted_for
     * @return string
     */


function save_vote($phone_number, $voted_for) {
        // Just the digits, please
        $phone_number = intval(preg_replace('/\D/', '', $phone_number));

        // Check to see if person has already voted
        $stmt = $this->db->prepare('SELECT COUNT(*) FROM voters WHERE phone_number=?');
        $stmt->bindParam(1, $phone_number, PDO::PARAM_INT);
        $stmt->execute();

        // If not, save their vote
        if ($stmt->fetchColumn() == 0)
        {
            // Save voter
            $stmt = $this->db->prepare('INSERT INTO voters (phone_number, voted_for) VALUES (?, ?)');
            $stmt->bindParam(1, $phone_number, PDO::PARAM_INT);
            $stmt->bindParam(2, $voted_for, PDO::PARAM_INT);
            $stmt->execute();

            // Update vote count
            $stmt = $this->db->prepare('UPDATE brands SET votes = votes + 1 WHERE id=?');
            $stmt->bindParam(1,$voted_for, PDO::PARAM_INT);
            $stmt->execute();

            return 'Thank you, your vote has been recorded';
        }
        else {
            return 'Sorry, you can only vote once.';
        }
    }
/*        function save_vote($phone_number, $voted_for) {
            // Just the digits, please
            $phone_number = intval(preg_replace('/\D/', '', $phone_number));

        // Check to see if person has already voted
        $stmt = $this->db->prepare('SELECT COUNT(*) FROM voters WHERE phone_number=?');
        $stmt->bindParam('i', $phone_number);
        $stmt->execute();

        // If not, save their vote
        if ($stmt->fetchColumn() == 0)
        {
            // Save voter
            $stmt = $this->db->prepare('INSERT INTO voters (phone_number, voted_for) VALUES (?, ?)');
            $stmt->bindParam('ii', $phone_number, $voted_for); // we suppose tha rhe $voted_for is integer if not use intval
            $stmt->execute();

            // Update vote count
            $stmt = $this->db->prepare('UPDATE brands SET votes = votes + 1 WHERE id=?');
            $stmt->bindParam('i',$voted_for);// we suppose tha rhe $voted_for is integer if not use intval
            $stmt->execute();

            return 'Thank you, your vote has been recorded';
        }
        else {
            return 'Sorry, you can only vote once.';
        }
    }*/

/*        function save_vote($phone_number, $voted_for) {
            // Just the digits, please
            $phone_number = preg_replace('/\D/', '', $phone_number);

        // Check to see if person has already voted
        $stmt = $this->db->prepare('SELECT COUNT(*) FROM voters WHERE phone_number=?');
        $stmt->bind_param(int, $phone_number);
        $stmt->execute();
        //$stmt->execute(array($phone_number));

        // If not, save their vote
        if ($stmt->fetchColumn() == 0)
        {
            // Save voter
            $stmt = $this->db->prepare('INSERT INTO voters (phone_number, voted_for) VALUES (?, ?)');
            $stmt->execute(array($phone_number, $voted_for));

            // Update vote count
            $stmt = $this->db->prepare('UPDATE brands SET votes = votes + 1 WHERE id=?');
            $stmt->execute(array($voted_for));

            return 'Thank you, your vote has been recorded';
        }
        else {
            return 'Sorry, you can only vote once.';
        }
    }*/
}

Вот обновленная функция, которая обрабатывает save_vote

function save_vote($phone_number, $voted_for) {
            // Just the digits, please
            $phone_number = intval(preg_replace('/\D/', '', $phone_number));

            // Check to see if person has already voted
            //$stmt = $this->db->prepare("SELECT COUNT(*) FROM voters WHERE phone_number=?");
            //$stmt->bindValue(1, $phone_number, PDO::PARAM_INT);
            //$stmt->execute();

            //Try catch exception to check connection to Database.
            try{
                $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                //echo "Connected !";
                //Check to see if person has already voted
                try{
                    $stmt = "SELECT COUNT(*) FROM voters WHERE phone_number=?";
                    $results = $this->db->prepare($stmt);
                    $results->bindParam(1, $phone_number, PDO::PARAM_INT);

                    //Verify execution of query
                    if($results->execute()){
                        // If number not already voted, save their vote
                        if ($results->fetchColumn() == 0)
                        {
                            // Save voter
                            $stmt2 = "INSERT INTO voters (phone_number, voted_for) VALUES (?, ?)";
                            $stmt2query = $this->db->prepare($stmt2);
                            $stmt2query->bindValue(1, $phone_number, PDO::PARAM_INT);
                            $stmt2query->bindValue(2, $voted_for, PDO::PARAM_INT);
                            $stmt2query->execute();

                            // Update vote count
                            $stmt3 = "UPDATE brands SET votes = votes + 1 WHERE id=?";
                            $stmt3query = $this->db->prepare($stmt3);
                            $stmt3query->bindValue(1,$voted_for, PDO::PARAM_INT);
                            $stmt3query->execute();

                            return 'Thank you, your vote has been recorded';
                        }
                        else {
                            return 'Sorry, you can only vote once.';
                        }
                    }
                    else {
                        return "There is some problem in updating your profile. Please contact site admin";
                    }

                }  catch (PDOException $e)  {
                    echo $e;
                    die();
                }

                //$values = $results->fetchAll(PDO::FETCH_OBJ);
                //echo $values;


            }  catch (PDOException $e)  {
                echo $e;
                die();
            }


        }

Вот код voice-now.php, где пользователи взаимодействуют с системой.

<?php
/**
 * Created by PhpStorm.
 * User: kqwameselase
 * Date: 2019-02-27
 * Time: 10:29
 */
date_default_timezone_set('Africa/Ghana');

require_once('db.php');
header('Content-type: application/json; charset=utf-8');
header("Access-Control-Allow-Origin: http://apps.smsgh.com");
header("Access-Control-Allow-Methods: POST, GET, OPTIONS");



// Begin by reading the HTTP request body contents.
// Since we expect is to be in JSON format, let's parse as well.
$ussdRequest = json_decode(@file_get_contents('php://input'));

// Our response object. We shall use PHP's json_encode function
// to convert the various properties (we'll set later) into JSON.
$ussdResponse = new stdClass;

// Check if no errors occured.
if ($ussdRequest != NULL)
    switch ($ussdRequest->Type) {
        // Initiation request. This is the first type of request every
        // USSD application will receive. So let's display our main menu.
        case 'Initiation':

            $ussdResponse->Message =
                "Welcome to Ghana Beverage Awards 2019. Vote for your preferred product of the year.\n" .
                "1. Origin Beer \n2. Club Beer \n3. Star Beer \n4. Guinness \n5. Gulder";
            $ussdResponse->Type = 'Response';
            break;


        // Response request. This is where all other interactions occur.
        // Every time the mobile subscriber responds to any of our vote options,
        // this will be the type of request we shall receive.
        case 'Response':
            switch ($ussdRequest->Sequence) {

                // Menu selection. Note that everytime we receive a request
                // in a particular session, the Sequence will increase by 1.
                // Sequence number 1 was that of the initiation request.
                case 2:
                    $items = array('1' => 'Origin Beer', '2' => 'Club Beer', '3' => 'Star Beer', '4' => 'Guinness', '5' => 'Gulder');
                    if (isset($items[$ussdRequest->Message])) {
                        $ussdResponse->Message = 'Please confirm your preferred product of the year is  '
                            . $items[$ussdRequest->Message] . "?\n1. Yes\n2. No";
                        $ussdResponse->Type = 'Response';
                        $ussdResponse->ClientState = $items[$ussdRequest->Message];
                    } else {
                        $ussdResponse->Message = 'Invalid option.';
                        $ussdResponse->Type = 'Release';
                    }
                    break;

                // Order confirmation. Here the user has responded to our
                // previously sent menu (i.e. Please confirm your preferred product of the year is...)
                // Note that we saved the option the user selected in our
                // previous dialog into the ClientState property.
                case 3:
                    switch ($ussdRequest->Message) {
                        case '1':
                            $db = new DB();

                            // save_vote will check to see if the person has already voted
                            $phone_number = $ussdRequest->Mobile;

                            //Return the array number for the selected vote to be used when updated votes
                            $items2 = array('1' => 'Origin Beer', '2' => 'Club Beer', '3' => 'Star Beer', '4' => 'Guinness', '5' => 'Gulder');
                            $voted_for = array_search($ussdRequest->ClientState, $items2) ;

                            $response = $db->save_vote($phone_number, $voted_for);
                            //echo $response;

                            //Display Success message after vote saved.
                            $ussdResponse->Message =
                                'Thank you. You have successfully voted for '
                                . $ussdRequest->ClientState . ' as your preferred Product of the Year.';


                            break;
                        case '2':
                            $ussdResponse->Message = 'Vote cancelled.';
                            break;
                        default:
                            $ussdResponse->Message = 'Invalid selection.';
                            break;
                    }
                    $ussdResponse->Type = "Release";
                    break;

                // Unexpected request. If the code here should ever
                // execute, it means the request is probably forged.
                default:
                    $ussdResponse->Message = 'Unexpected request.';
                    $ussdResponse->Type = 'Release';
                    break;
            }
            break;

        // Session cleanup.
        // Not much to do here.
        default:
            $ussdResponse->Message = 'Duh.';
            $ussdResponse->Type = 'Release';
            break;
    }
// An error has occured.
// Probably the request JSON could not be parsed.
else {
    $ussdResponse->Message = 'Invalid USSD request.';
    $ussdResponse->Type = 'Release';
}
// Let's set the HTTP content-type of our response, encode our
// USSD response object into JSON, and flush the output.

header('Content-type: application/json; charset=utf-8');
echo json_encode($ussdResponse);

Полная ошибка на каждую герою. Журналы:

2019-02-28T16: 31: 19.510613 + 00: 00 приложение [web.1]: [28-Feb-2019 16:31: 19 UTC] PHP фатальная ошибка: необученная ошибка: вызов функции-члена bindParam () для bool в /app/db.php:62 2019-02-28T16: 31: 19.510703 + 00: 00 app [web.1]: стектрассировка: 2019-02-28T16: 31: 19.510862 + 00: 00 app [web.1]:

0 /app/vote-now.php(77): DB-> save_vote (277655805, 1)Приложение 2019-02-28T16: 31: 19.510947 + 00: 00 [web.1]: # 1 {main}

2019-02-28T16: 31: приложение 19.511072 + 00: 00 [web.1]: добавлено в /app/db.php в строке 62 2019-02-28T16: 31: 19.512333 + 00: 00 app [web.1]: 10.45.101.19 - - [28 / Feb / 2019: 16: 31: 19 +0000] "POST /vote-now.php HTTP / 1.1" 500 - "http://apps.smsgh.com/USSDSimulator/"" Mozilla / 5.0 (Macintosh;Intel Mac OS X 10_14_3) AppleWebKit / 537,36 (KHTML, как Gecko) Chrome / 72.0.3626.109 Safari / 537,36

Ответы [ 2 ]

0 голосов
/ 04 марта 2019

Я думаю, что вы не используете типы по мере необходимости -> Я использую обновленный код, который вы ввели:

Я вижу две проблемы:

  1. Номер телефона является строкойа не целое число.
  2. Вы ожидаете, что $ussdRequest->Mobile будет int, но оно дает строку .
  3. Если вы сохраняете телефонные номера как числа, я рекомендуюпереключиться на символы ...

Но чтобы быть уверенным, нам нужна структура вашей таблицы + класс $ussdRequest для дальнейшей проверки.

Попробуйте использовать это :

$stmt2query->bindParam(1, $phone_number.'';, PDO::PARAM_STR);
$stmt2query->bindParam(2, intval($voted_for), PDO::PARAM_INT);

.'' и intval() просто для того, чтобы убедиться, что вы передаете правильные типы, если это работает, тогда переосмыслите ваши типы и проверьте, где происходит преобразование ...

Надеюсь, я помог.

0 голосов
/ 28 февраля 2019

Подготовленные операторы не могут принимать массивы в функции execute().Вам нужно будет привязать каждый параметр следующим образом (замените «s» на тип данных, который вы хотите, например, string, int и т. Д.):

$stmt = $this->db->prepare('SELECT COUNT(*) FROM voters WHERE phone_number=?');
$stmt->bind_param("s", $phone_number);
$stmt->execute();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...