Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP PDO: SQL query not returning expected result

Tags:

php

mysql

pdo

I have a function (see bottom) in PHP, which queries a MySQL database. When I use the following values:

  • $map => 1,
  • $limit => 10,
  • $from => 0,
  • $to => CURRENT_TIMESTAMP

With the SQL statement:

SELECT user,
       scoreVal AS score,
       UNIX_TIMESTAMP(timestamp) AS timestamp 
  FROM Score 
 WHERE timestamp >= :from 
   AND timestamp <= :to 
   AND map = :map 
 ORDER BY scoreVal DESC, timestamp ASC 
 LIMIT :limit

In phpMyAdmin, I get the following result:

phpMyAdmin result

However the PHP PDO gets returned an empty array.

My attempts to debug so far:

  • I have replaced he prepared SQL query with static values instead of placeholders - Returns correctly
  • Trying each placeholder separately, replacing the rest with tested hard-coded values - Returns nothing
  • Instead of passing variables to placeholders I pass fixed constants in the execute(Array()) part. - Returns nothing.
  • I have furthermore discovered after turning on mySQL query logs, that the PHP client Connects, but then quits without sending any queries.

From this, I believe it to be a problem with the place holders within the function, however I have been unable to find a reason why they are failing. This is most probably occurring on the PHP side, as no errors are being thrown by MySQL to the error file.

This is the function I am using, with the variables being passed in:

  • $map => 1,
  • $limit => 10,
  • $from => 0,
  • $to => 0

Function:

/**
 * Gets the highscore list for the map in that timespan
 * @param  integer $map   Id of map for which to fetch the highscore
 * @param  integer $limit Maximum no. of records to fetch
 * @param  integer $from  Timestamp from when to find rank
 * @param  integer $to    Timestamp up to when to find rank
 * @return array   Array of highscores arranged by rank for the map in the format [{"user"=>$user,"score"=>score,"timestamp" => timestamp}]
 */
function get_highscore_list($map,$limit,$from,$to){
    $sql = "SELECT user,scoreVal AS score,UNIX_TIMESTAMP(timestamp) AS timestamp FROM Score WHERE timestamp >= :from AND timestamp <= :to AND map = :map ORDER BY scoreVal DESC, timestamp ASC LIMIT :limit";
    if ($to==intval(0)){
        $max =1;
        $sql = str_replace(":to","NOW()",$sql,$max);
    }
    try{
    $conn = request_connection();
    $stmt = $conn->prepare($sql);
    $stmt->execute(array(':map'=>$map,':from'=>$from,':limit'=>$limit));
    $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
    }catch(PDOException $e){
        $_POST["exception"]=$e;
        continue;
    }
    return $result;
}

EDITS


Format of MySQL table:

MySQL table format


I have tried outputting the $conn->errorInfo();, however as no error is being thrown, I get returned an array of values: [00000,null,null]


The request_connection function only returns the result of this function, and it is working for all of my other statements.

/**
 * Creates a new PDO connection to the database specified in the configuration file
 * @author Ignacy Debicki
 * @return PDO A new open PDO connection to the database
 */
function create_connection(){
    try {
        $config = parse_ini_file('caDB.ini');
        $conn = new PDO('mysql' . ':host=' . $config['dbHost'] . ';dbname=' . $config['db'],$config['dbPHPUser'], $config['dbPHPPass']);
        date_default_timezone_set($config['dbTimezone']);
        return $conn;
    } catch(PDOException $e){
        throw new Exception("Failed to initiate connection",102,$e);
    }   
}

Thanks

like image 681
Ignacy Debicki Avatar asked Jan 07 '16 16:01

Ignacy Debicki


1 Answers

After many hours of trying, I have finally found my solution.

Two important statements that I had missed out from creating my connection are:

$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

which turn on error reporting (See https://stackoverflow.com/a/8776392/2891273).

Once I turned this on, it was trivial to catch my problem, which was due to the overwriting of the :to parameter if $to was 0, the number of parameters passed in the $conn->execute() statement was mismatched with the number of parameters in the sql query.

My solution was to use $conn->bindValue() for each parameter instead, using an if statement to check if to bind to the :to parameter. Below is my solution:

function get_highscore_list($map,$limit,$from,$to){
    $sql='SELECT user, scoreVal AS score, UNIX_TIMESTAMP(timestamp) AS timestamp FROM Score WHERE map = :map AND timestamp >= :from AND timestamp <= :to ORDER BY scoreVal DESC, timestamp ASC LIMIT :limit';
    if ($to==0){
        $sql = str_replace(":to",'CURRENT_TIMESTAMP()',$sql);
    }
    $conn = request_connection();
    $stmt = $conn->prepare($sql);
    $stmt->bindValue(':map',$map,PDO::PARAM_INT);
    $stmt->bindValue(':from',$from,PDO::PARAM_INT);
    if ($to!=0){
        $stmt->bindValue(':to',$to,PDO::PARAM_INT);
    }
    $stmt->bindValue(':limit',$limit,PDO::PARAM_INT);
    $stmt->execute();
    $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
    return $result;
}
like image 126
Ignacy Debicki Avatar answered Sep 23 '22 07:09

Ignacy Debicki