Finding bugs using PHPStan as a Static Analyzer

With PHP being an interpreted language it has a downside when it comes to finding bugs in your code. It will not show you errors in your software until you actually run it. PHPStan tries to solve this problem by doing static analysis on your code. It was recently created by Ondrej Mirtes.

Running PHPStan will tell you about bugs in your codebase almost instantly (yes, it’s very fast). At the time of writing this article, PHPStan currently checks your code on:

  • The existence of classes and interfaces in an instance of, catch type hints, other language constructs, and even annotations. PHP does not do this and just stays silent instead.
  • Existence of variables while respecting scopes of branches and loops.
  • Existence and visibility of called methods and functions.
  • Existence and visibility of accessed properties and constants.
  • Correct types assigned to properties.
  • The correct number and types of parameters are passed to constructors, methods, and functions.
  • Correct types returned from methods and functions.
  • The correct number of parameters passed to sprintf/printf calls is based on format strings.
  • Useless casts like (string) ‘foo’.
  • Unused constructor parameters – they can either be deleted or the author forgot to use them in the class code.
  • That only objects are passed to the clone keyword.

As you can see, it contains a lot of useful checks which will warn you of potential bugs before you even run your code.

Installing PHPStan

Installing PHPStan is as easy as including it in your project through composer:

$ composer require --dev phpstan/phpstan

We can now run PHPStan from the base directory of our project:

$ vendor/bin/phpstan analyze -l 4 src

A breakdown of this command:

  • vendor/bin/phpstan is the executable
  • analyze tells PHPStan to analyze all files in the given directories
  • -l 4 means that we want to analyse on the most strict level
  • src is the directory we want to analyse

Try running this in your own project and see what kind of potential errors are living in your codebase.

Integrating PHPStan into CI

It’s super easy to use PHPStan in Continuous Integration. For most of my personal projects, I use TravisCI. Since we’ve included PHPStan as a dev-dependency in our composer.json file we just have to add the PHPStan executable to the scripts that the CI-software needs to run.

For TravisCI, this means just changing the default script in a .travis.yml like this:

language: php
php:
  - '8.0'
install: composer install

# Simply add these lines
script:
    - vendor/bin/phpunit
    - vendor/bin/phpstan analyse src tests --level=4

The default script that TravisCI runs for PHP projects is simply phpunit. Now we’ve added PHPStan to it. If PHPStan finds any errors within your project, the build will fail.

Error Handling in PHP (Part 2)

Now that we know, how to log errors in any system developed in PHP, we can move to our next section for keeping track of these logged errors. If you haven’t read how to log errors, read part 1 of error handling in PHP.

To keep track of these logged errors, we need to create a script to read those log files in a systematic way. Refer to the below code to read log files,

public function errorLogs($filePath = 'error.log') {

        $fileContent = file($filePath);

        $errorsArray = array();
        if(sizeof($fileContent) == 0) {
            return false;
        }

        foreach($fileContent as $row) {
            $errors = explode(":  ", $row);

            if(empty($errors[1])) continue;
            $errorsArray[] = $errors;
        }

        return array_reverse($errorsArray, true);
}

Explanation:

$fileContent = file($filePath);

This line of code will read the file line by line from the provided file path.

if(sizeof($fileContent) == 0) {
    return false;
}

After reading the file, if the size of the file content is 0 then, the function will return false. So, the purpose of this function is to stop the execution of the function if the provided file is empty and returns false.

foreach($fileContent as $row) {
      $errors = explode(":  ", $row);

      if(empty($errors[1])) continue;
      $errorsArray[] = $errors;
}

This part of the function will loop through the log contents row by row. For each row, it will explode the line with ‘:’ to separate the date and actual error details.

If the error details are empty for any row, it will skip that row. Otherwise, it will collect the errors in another array.

return array_reverse($errorsArray, true);

The last line of the function will reverse the error data and returned the reversed result. So, that we can see the latest errors first.

This way we can create a simple function to display the list of errors in a tabular format from the error log files we generated for each of the modules in the application system.

Error handling in PHP (Part 1)

Error handling is an important part of any developer as it provides vital flaws about the program developed by the developer. So, it becomes very crucial to learn the techniques to manage it.

As a developer, we have been told that you should not show errors on the production server because of the security risk due to the path displayed by the PHP errors displayed on the screen. So, we add the following code for the production server,

ini_set('error_reporting', 0);
error_reporting(0);

ini_set('display_errors', FALSE);

But, without error logs, developers cannot able to know actual problems or flaws in the system. So, rather than hiding errors, developers should store them in the log files. We can achieve this using the following code,

ini_set('error_reporting', E_ALL);
error_reporting(E_ALL);
ini_set('log_errors', TRUE);
ini_set('html_errors', FALSE);
ini_set('error_log', LOG_PATH.'error.log');
ini_set('display_errors', FALSE);

This way, we can manage error logs and hide errors on the production server. We can manage separate log files for the different modules of the project.

How to get the last executed query in PHP CodeIgniter?

Are you wanted to get the last executed SQL query in the CodeIgniter project? then, I will help to get the latest query in CodeIgniter

We can get the last executed query using the last_query() function of the inbuilt db class of the CodeIgniter. This function can be used with simple syntax like $this->db->last_query() to see SQL statements of last executed query in PHP CodeIgniter app. You have to simple code that functions after the main query that you wanted to check.

Here is a simple function code which can be added in any controller of the CodeIgniter project and also output for the last query:

Example:

public function check_query_function() {

    $sql = $this->db->get("products");
  
    $query = $this->db->last_query();
   
    echo "<pre>";
    print_r($query);
    exit;
}

Output:

SELECT * FROM `products`

Change the Upload size on Ubuntu PHP.ini

On Ubuntu server, maximal file size upload limit in php scripts is set to 2Mb as default. There may be different filesize updated later in php.ini which is not sufficient to upload large database backup in phpMyAdmin.

In order to change that, two things are important,
– Current upload_max_filesize value
– Current location of php.ini file

On Ubuntu server, maximal file size upload limit in php scripts is set to 2Mb as default.  There may be different filesize updated later in php.ini which is not sufficient to upload large database backup in phpMyAdmin.

In order to change that, two things are important,

  • Current upload_max_filesize value
  • Current location of php.ini file

To find current upload_max_filesize value, create a file called ‘pinfo.php’ at your webserver root folder with following content:

phpinfo();

Now, open recently created file in browser via http://localhost/pinfo.php (replace localhost with the servername if necessary) and look for the line

upload_max_filesize 2M

which will show you the actual maximum file size.

To change the upload_max_filesize value, open php.ini file from the location provided in information displayed from pinfo.php file. If php.ini file location is/etc/php5/apache2/php.ini, then open a ssh connection to your server and edit the file /etc/php5/apache2/php.ini as follows

sudo nano /etc/php5/apache2/php.ini

search for “upload_max_filesize” with Ctrl-W and change “2M” to “20M”. Save the file with Ctrl-O and exit with Ctrl-X. Restart the apache server with

sudo /etc/init.d/apache2 restart

and visit again http://localhost/info.php to check if the maximum file size was changed.

There is another way to change upload_max_filesize value for specific project or website only.

If you enabled mod_rewrite you can also put this to your .htaccess file:

php_value upload_max_filesize = 16G
php_value post_max_size = 16G

So, upload_max_filesize value in php.ini file can be changed using .htaccess for project specific and from php.ini file itself for whole server specific.