我正在开发一个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应用程序[web.1]:在第57行的/app/db.php中抛出
第57行是代码$stmt->execute(array($phone_number));
所在的位置。
将感谢您帮助我们解释可能出问题的地方。
谢谢
根据评论的要求,请参阅下文
db.php代码:
<?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();
}
}
这是用户与系统互动的“ vote-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);
每个heroku日志的完全错误:
2019-02-28T16:31:19.510613 + 00:00 app [web.1]:[28-Feb-2019 16:31:19 [UTC] PHP致命错误:未捕获错误:调用成员函数 /app/db.php中的bool上的bindParam():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 app [web.1]:#1 {main}
2019-02-28T16:31:19.511072 + 00:00 app [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
答案 0 :(得分:-1)
准备好的语句不能在execute()
函数中接受数组。您需要像这样绑定每个参数(将“ s”替换为所需的数据类型,即字符串,整数等):
$stmt = $this->db->prepare('SELECT COUNT(*) FROM voters WHERE phone_number=?');
$stmt->bind_param("s", $phone_number);
$stmt->execute();
答案 1 :(得分:-1)
我认为您没有使用所需的类型->我正在使用您输入的更新代码:
我看到两个问题:
$ussdRequest->Mobile
是一个 int,但它给出一个字符串。但是请确保我们需要您的表结构+ $ussdRequest
类以供进一步检查。
尝试使用此功能:
$stmt2query->bindParam(1, $phone_number.'';, PDO::PARAM_STR);
$stmt2query->bindParam(2, intval($voted_for), PDO::PARAM_INT);
.''
和intval()
只是用来确保您传递正确的类型,如果可以,那么请重新考虑您的类型并检查转换的位置...
希望我能帮上忙。