PHP Function to validate setting

I am currently validating a POST value using a REGEX and a SWITCH, it’s works perfectly but isn’t really scalable as it means manually editing the PHP file when new values are added to the form. Instead I have decided to create a function which calls a MySQL database to determine if the POST value is valid or not.

// Validate flag value
function ValidateFlagValue($FlagName, $FlagValue) {
	
	$stmt_query = "SELECT flag_name FROM flags WHERE flag_name = ? AND flag_min >= ? AND flag_max <= ? LIMIT 1";
	
	// Prepate statement
	mysqli_stmt_prepare($stmt, $stmt_query);

    // Bind parameters
    mysqli_stmt_bind_param($stmt, "sii", $FlagName, $FlagValue, $FlagValue);

    // Execute statement
    mysqli_stmt_execute($stmt);

    // Store results
    mysqli_stmt_store_result($stmt);

    // Count results
    if (mysqli_stmt_num_rows($stmt) == 1 ) {
    	return true;
    } else {
    	return false;
    }

    // Close statement
    mysqli_stmt_close($stmt);
}

Is this the right way to go about this?
And have I written the function correctly?

Hi AndyPHP welcome to the forum

I don’t see where you’re passing in the POST value. You’re naming it “flag_” ?

Also note that “return” causes the script to exit so any code after that won’t run.
In this case, the script exiting will close things down anyway, but something to keep in mind.

There is one critical problem and two improvements that can be made.

The problem is that nowhere $stmt is defined. You have to create it out of $mysqli instance that have to be added to function parameter list.

First improvement belongs to SQL where you can use BETWEEN clause and thus avoud binding the same variable twice.

Another one is based on the extreme verbosity of raw mysqli API. I strongly recommend you to use PDO instead. Look how dramatically shorter your code could be with PDO:

// Validate flag value
function ValidateFlagValue($pdo, $FlagName, $FlagValue)
{
    $sql  = "SELECT 1 FROM flags WHERE flag_name = ? AND ? BETWEEN flag_min AND flag_max LIMIT 1";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([$FlagName, $FlagValue]);
    return $stmt->fetchColumn();
}

PDO not only lets you avoid manual binding at all, but also have a very handy function to return the query result at once.

So again, consider PDO instead of mysqli. Give PDO a try and you will see how powerful it can be.

The array passed to the execute is being manually bound as strings. If you want to bind something that isn’t a string you still need separate bind statements.

Yes, but you wouldn’t want anything else anyway, given you are using mysql and emulation mode is already turned off.

A lot of people clutter their database with integer ids that are not strings.

It’s all right. Mysql uses loose typing and thus will gladly cast your string to int. No big deal.

does it also handle converting strings to blobs?

For musql they are the same. The only difference for the “b” type in mysqli and param_lob in PDO is that data being sent to the server in packets. For such a case when you need to send a string that size exceeds max_allowed_packet, seperate binding is the only way, I have to admit.

I wouldn’t store such blobs though

1 Like

So how would you go about storing images IN the database then (which is essential once you get a larger system using transactions) if you don’t store them as blobs?

As I said,

First, for the images which weight is less than 2 megabytes, it’s ok to send them as strings.

Second, personally I’d never store big images in database at all, as for the web development it’s just insane.

And third, I already agreed, that for the blobs of more than 2 megs in size separate binding is the only way, so I would usr it, if it ever happens.

I think we’re a little bit off topic now but thanks for helping.

I have stayed well clear of OOP for 7 years because I simply don’t understand it. However given that I want to learn C# in the coming few years I’m going to give it another try. I will write out some OOP PHP and PDO and come back once I have a noddy script.

Keep in mind that you don’t need to know how to write OOP to use it.

True, a basic understanding helps and knowing the syntax is essential, but there are a lot of OOP classes you can use now without needing to fuss much.

I suggest you turn on error reporting and display and give it a try (in your dev environment only please). The error messages will help you to learn what needs to be done.

I am rebuilding my dev box as we speak but I am hoping I’ve got the first part right :stuck_out_tongue:

pdo.inc.php

<?php

// Connect to MySQL
$dsn = 'mysql:dbname=dev; host=127.0.0.1';
$user = 'devuser';
$password = 'devpass';

try {
	$dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
	echo 'Failed to connect to MySQL: ' . $e->getMessage();
}

?>
1 Like

Unfortunately, you didn’t. In this snippet you shouldn’t use try catch, yet you have to set exception mode for PDO. So it rather should be

$dsn = 'mysql:dbname=dev;host=127.0.0.1';
$dbh = new PDO($dsn, $user, $password,[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);

See this is why I’d rather use MySQLi at least I know what I’m doing…

So it literally just …

<?php

// Connect to MySQL
$dsn = 'mysql:dbname=dev;host=127.0.0.1';
$dbh = new PDO($dsn, $user, $password,[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);

?>

pdo.inc.php

<?php
// Connect to MySQL
$dsn = 'mysql:dev=dev;host=127.0.0.1';
$username = 'dev';
$password = 'dev.dev';

$pdo = new PDO($dsn, $username, $password,[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
?>

functions.inc.php

<?php
include_once('pdo.inc.php');

function ValidateFlagValue($pdo, $FlagName, $FlagValue)
{
    $sql  = "SELECT 1 FROM flags WHERE flagname = ? AND ? BETWEEN MIN(flagvalue) AND MAX(flagvalue) LIMIT 1";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([$FlagName, $FlagValue]);
    return $stmt->fetchColumn();
}

function GetFlagDescription($pdo, $FlagName, $FlagValue)
{
    $sql  = "SELECT 1 FROM flags WHERE flagname = ? AND flagvalue = ? LIMIT 1";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([$FlagName, $FlagValue]);
    return $stmt->fetchColumn();
}
?>

test.php

<?php
include_once('functions.inc.php');

if (ValidateFlagValue('intent',2)) {
	echo "flag valid";
} else {
	echo "flag invalid";
}
?>

I’m not understanding this PDO at all :angry:

Why are you passing $pdo into the function because it doesn’t work.

Needs to be $dsn = 'mysql:dbname=dev;host=127.0.0.1';
Don’t replace dbname because that is how you connect to your database. It’s equivalent to procedural mysqli_*'s prepare($db, ..) where $db is the database you want to use.

Also, you should take note that square bracket arrays [] are available only from PHP 5.4 +. So don’t use square bracket arrays [] if you have PHP 5.3. You’ll get an error. Use array(); as an alternative if you have PHP 5.3 and below.

The reason why they are passing the $pdo/db variable is because in PHP, you don’t really want to create a new database connection every time you do a query. It’s easier to re-use the connection then closing it and re-opening it. In a way, it’s kind of like how system admins are with up-time.

You don’t need to. You can still use OOP mysqli_*.

<?php
// Connect to MySQL
$host = '127.0.0.1';
$username = 'dev';
$password = 'dev.dev';
$db = 'dev';

$mysqli = new mysqli($host, $username, $password, $db);
if($mysqli->connect_errno) {

    die('Do not display any errors here. You should NEVER display errors to the user.');

}

$sql = 'SELECT 1 FROM flags WHERE flagname = ? AND ? BETWEEN MIN(flagvalue) AND MAX(flagvalue) LIMIT 1';
$prepare = $mysqli->prepare($sql);
$prepare->bind_param('ss', $flagname, $flagname2);
$prepare->execute();
$prepare->store_result();

if($prepare->num_rows) {

    $prepare->bind_result($first_flag);

    while($prepare->fetch()) {

        print($first_flag);

    }

} else {

    print('No record with that information');

}

Also take note, you should always be using num_rows and rowCount() as it helps prevent white pages (nothing is displayed, no errors, no warning, nothing) and prevents error warning. It is also helps better user experience.

1 Like

I don’t know PDO or OOP :frowning:

<?php

// Connect to MySQL
$dsn = 'mysql:dbname=dev_pof;host=127.0.0.1';
$username = 'dev';
$password = 'dev.dev';

$pdo = new PDO($dsn, $username, $password,[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);

// Function to validate the flag value
function CheckFlagValue($pdo, $FlagName, $FlagValue)
{
    $sql  = "SELECT 1 FROM flags WHERE flagname = ? AND flagvalue = ? LIMIT 1";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([$FlagName, $FlagValue]);
    return $stmt->fetchColumn();
}

// Function to get the flag description
function GetFlagDescription($pdo, $FlagName, $FlagValue)
{
    $sql  = "SELECT flagdescription FROM flags WHERE flagname = ? AND flagvalue = ? LIMIT 1";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([$FlagName, $FlagValue]);
    return $stmt->fetchColumn();
}

echo GetFlagDescription($pdo, 'intent', 9);

?>

The GetFlagDescription function is working and shows the flag description when the flag name and value are passed.

However CheckFlagValue I need this function to return true or false depending on the row count. There doesn’t seem to be a row count function for PDO??

rowCount needs to be rowCount();
It has to be after the ->execute() or it won’t work. Also, it’s best to check if the row actually exists for all your query calls. Let’s say you only have 2 rows of data in your database and someone typed in their address bar ?flag=3. What then? It’ll display a big white blank page and nothing else. If you don’t handle errors the right way, your users will question, “Does this webmaster know what he’s doing because the page shows nothing?”

It’s best to handle errors the proper way so that users don’t keep sending feedbacks about blank pages. This is also a way for hackers to hack your website. If your page crashes after a certain amount of data, they know that those data don’t exist and they can exploit it. So rather than giving them a free pass, you should handle your errors the right and proper way by using num_rows (mysqli_*) and rowCount() (PDO).