PHP Mistakes You Should Avoid

#[Pragmatic(Kiwi)]
6 min readMay 19, 2022

--

Thinking that PHP Support A Character Data Type

Data Types define the type of data a variable can store. PHP allows eight different types of data types. All of them are discussed below. There are pre-defined, user-defined, and special data types.

The predefined data types are: Boolean, Integer, Double, String

The user-defined data types are: Array, Objects

The special data types are: NULL, resource

Looking at the following code we can assume that PHP is going to print every letter from “a” to “z” but it also starts printing everything from “aa” to “yz”. But why?

As you can see above, there is no “char” data type in PHP, only string is available. Keeping this in mind, incrementing the string “z” in PHP yields “aa”.

And confusingly, lexicographically “aa” is less than “z”!

Which means when $c reaches “z” it transforms into “aa” and has to keep going until it reaches “za” that meets our condition, our first value greater than “z”.

But one way to print every letter avoiding the issue above is the following:

Not Validating Cookie Data

Cookies are text files stored on the client computer and they are kept of use tracking purpose. PHP transparently supports HTTP cookies.

Cookies are usually set in an HTTP header (although JavaScript can also set a cookie directly on a browser). A PHP script that sets a cookie might send headers that look something like this −

HTTP/1.1 200 OK
Date: Fri, 04 Feb 2000 21:03:38 GMT
Server: Apache/1.3.9 (UNIX) PHP/4.0b3
Set-Cookie: name=xyz; expires=Friday, 02-Jan-11 23:11:31 GMT;
path=/; domain=example.com
Connection: close
Content-Type: application/json

How much do you trust your cookies? Most of us don’t think twice about this harmless bit of data that is passed by a cookie. How could it be harmful?

If you are not validating cookie data, you are actually opening your code to potential harmful data.

You should be using htmlspecialchars() to validate cookies before storing them in a database.

(PHP 4, PHP 5, PHP 7, PHP 8) htmlspecialchars — Convert special characters to HTML entities

You should check out OWASP TOP 10 yearly for vulnearbilities that could target your web application.

Assuming $_POST Will Always Contain Your POST Data

PHP $_POST is a PHP super global variable which is used to collect form data after submitting an HTML form with method=”post”. $_POST is also widely used to pass variables.

Despite this, the $_POST array won’t always contain your POST data and can easily be empty. Let’s take an example and assume we make a server request with a jQuery.ajax() call like so:

We are sending the data as “application/json” which is standard for any API.

On the server side we simply dump the $_POST array and surprisingly we find it empty:

var_dump($_POST)> array(0) { }

So where did the data that we sent go to?

It turns out PHP only parses a POSt payload automatically when it is of content type applicationn/x-www-form-urlencoded or multipart/form-data. This is because those two types were essentially the only ones used years ago when PHP’s $_POST was implemented.

Because $_POST is a global variable, if we override it once (at the beginning of our script) it will be referenceable throughout our code.

Most PHP frameworks usually deal with this automatically.

If we process a POST payload with a content type of application/json we need to manually parse the request contents and then override the $_PSOT variable:

After this we correctly see what we have sent in the API call.

Misusing empty()

(PHP 4, PHP 5, PHP 7, PHP 8) empty — Determine whether a variable is empty

Determine whether a variable is considered to be empty. A variable is considered empty if it does not exist or if its value equals false. empty() does not generate a warning if the variable does not exist.

empty(mixed $var): bool
var Variable to be checked

No warning is generated if the variable does not exist. That means empty() is essentially the concise equivalent to !isset($var) || $var == false.

Some people use the empty() method for boolean checks for just almost anything and everything. There are cases where this can lead to confusion.

Coming back to ArrayObject instances. It’s easy to assume that arrays and ArrayObject will behave identically. This proves to be a dangerous assumption.

For example:

Why don’t both of them have the same output?

To avoid these issues, the better approach is to check for empty array structures with the count() method.

(PHP 4, PHP 5, PHP 7, PHP 8) count — Counts all elements in an array or in a Countable object

And since PHP casts 0 to false, count() can be also used withing the if() statement to check for empty arrays. note that in PHP, count() is constant complexity O(1) on arrays which makes it even clearer that it’s the right choice.

The main point is that empty() should be used with care as it can lend itself to confusing or dangerously misleading results if one is not careful.

Misunderstanding How isset() Works

(PHP 4, PHP 5, PHP 7, PHP 8) isset — Determine if a variable is declared and is different than null

isset(mixed $var, mixed ...$vars): bool

isset() will return false when checking a variable that has been assigned to null. Also note that a null character ("\0") is not equivalent to the PHP null constant.

Despite this, it not only returns false if an item does not exist but also if it’s null.

The behaviour is more prolematic than it might appear at first and is a common source of problems. Take for example:

What if the ‘key’ exists but its value is null? The code will have flawed logic as it evaluates to false.

For cases where it is important to check if a variable was really set (between a variable that wasn’t set and a variable that was set to null) the array_key_exists() method is a much more robust solution. Just like so:

(PHP 4 >= 4.0.7, PHP 5, PHP 7, PHP 8) array_key_exists — Checks if the given key or index exists in the array

By combining array_key_exists() with get_defined_vars() we can reliably check whether a variable within the current scope has been set or not.

Performing Queries In A Loop

First of all, executing queries in a loop can be very, very, very slow. 31 times slower than executing the same amount of queries at a point in time. If you decide to perform queries in a loop, you are going to open a new connection every time you are going through the loop.

While there may be nothing wrong with either approach, it can be very scary when dealing with big queries.

As a result, each iteration will result in a separate query to the database. So if for example, you supplied an array of 1000 values to the loop, it would generate 1000 separate queries to the resource. If such a script is called in multiple threads, it could potentially bring the system to a grinding halt.

It’s essential to recognize when queries are being made, either directly or indirectly. Whenever possible, gather the values and then run the query to run everything.

--

--