Anders Gerner
Anders Gerner

Reputation: 775

How to make dynamic postgres prepared statements in PHP

I'm trying to make some prepared statements in PHP using postgres.

It's a bit difficult to explaing so i'll just show you:

$stmt = "SELECT * FROM customer WHERE zip = '$1'";

if(isset($_POST["CITY"])){ 
   $stmt .= "AND city = '$2'";
}

if(isset($_POST["COUNTRY"])){ 
   $stmt .= "AND country = '$3'";
}

$result = pg_prepare("myconnection", "my query", $stmt);

$result1 = pg_execute("myconnection","my query", array("0000","someCity","someCountry"));

Sorry if some of the code is wrong but it's a freehand example. What I need is to be able to make the prepared statement dynamic depending on if some variables isset/not-null. It doesn't seem to work when posting 3 variables in the array when the statement only expects 1 or if i only need to add $1 and $3 but not $2. I hope you understand.

I need to use it this weekend, so I hope someone knows!

Thank you in advance!

Upvotes: 0

Views: 3666

Answers (4)

Clodoaldo Neto
Clodoaldo Neto

Reputation: 125244

Don't do string concatenation. Check if the parameters are set. If not set them to empty. Use a single query string:

$zip = $_POST["zip"];
$city = $_POST["city"];
$country = $_POST["country"];

if (!isset($zip)) $zip = '';
if (!isset($city)) $city = '';
if (!isset($country)) $country = '';

$stmt = "
    select *
    from customer
    where
        (zip = '$1' or '$1' = '')
        and
        (city = '$2' or '$2' = '')
        and
        (country = '$3' or '$3' = '')
";

$result = pg_prepare("myconnection", "my query", $stmt);
$result1 = pg_execute(
        "myconnection",
        "my query",
        array($zip, $city, $country)
        );

Each condition will only be enforced if the respective parameter is not the empty string.

The same logic could use the null value in stead of empty those columns contain empty strings that should be selected.

Upvotes: 0

regan_leah
regan_leah

Reputation: 294

Although both Daniel and aymeric are correct - no sense in testing twice, nor using numbers. See below:

$some_vars = array();
$some_vars[":zip"] = $_POST["ZIP"];
$stmt = "SELECT * FROM customer WHERE zip = :zip";

if(isset($_POST["CITY"])){ 
    $some_vars[":city"] = $_POST["CITY"]);
    $stmt .= " AND city = :city";
}

if(isset($_POST["COUNTRY"])){ 
    $some_vars[":country"] = $_POST["COUNTRY"]);
    $stmt .= " AND country = :country";
}

$result = pg_prepare("myconnection", "my query", $stmt);
$result1 = pg_execute("myconnection","my query", $some_vars);

Don't forget to sanitize and such.

Upvotes: 0

aymeric
aymeric

Reputation: 3895

There is nothing wrong in having 3 different statements (one for each case) and execute the one that applies depending on the number of parameters passed. Example:

EDIT: I modified the code to match all cases:

  • Only the zip specified
  • Zip + city
  • Zip + country
  • Zip + city + country

(even if there are some other cases, you'll understand the idea)

$stmt = "SELECT * FROM customer WHERE zip = '$1'";

if(isset($_POST["CITY"]) && isset($_POST["COUNTRY"])) { 
   $stmt3 = $stmt . " AND city = '$2'" . " AND country = '$3'";
} elseif(isset($_POST["CITY"])) { 
   $stmt1 = $stmt . " AND city = '$2'";
} elseif(isset($_POST["COUNTRY"])) {
   $stmt2 = $stmt . " AND country = '$2'";
}

if(isset($stmt3)) {
   $result = pg_prepare("myconnection", "my query", $stmt3);
   $result1 = pg_execute("myconnection","my query", array("0000","someCity","someCountry"));
} elseif(isset($stmt2)) {
   $result = pg_prepare("myconnection", "my query", $stmt2);
   $result1 = pg_execute("myconnection","my query", array("0000","someCountry"));
} elseif(isset($stmt1)) {
   $result = pg_prepare("myconnection", "my query", $stmt1);
   $result1 = pg_execute("myconnection","my query", array("0000","someCity"));
} else {
   $result = pg_prepare("myconnection", "my query", $stmt);
   $result1 = pg_execute("myconnection","my query", array("0000"));
}

I omitted (just as you did) all the error checks for brevity.

Upvotes: 1

Daniel Vérité
Daniel Vérité

Reputation: 61526

In a prepared statement, the SQL is static on purpose. The number of parameters cannot vary once the statement is prepared.

But it'd be easy for your code to submit the right number of parameters depending on the statement. You could add a variable for the counter of parameters, and a dynamic php array to pass to pg_execute instead of hard-coded literals. And they would be incremented/populated inside the if (isset(...)) branches.

Upvotes: 1

Related Questions