Return User Quota With PHP in Linux

Syed Hassan Sabeeh Kazmi Jan 30, 2023 Jan 19, 2023 PHP PHP Quota
  1. Use the crontab -e to Return User Quota With PHP in Linux OS
  2. Use the repquota -a Command to Return User Quota With PHP in Linux OS
  3. Use the du -bs Command to Return User Quota With PHP in Linux OS
  4. Use MySQL Quota to Return User Quota With PHP in Linux OS
  5. Use the imap_get_quota Function to Return User Quota With PHP in Linux OS
Return User Quota With PHP in Linux

User quota is a term for displaying disk usage and limits of a specific user in Linux OS. In this tutorial, you will learn different ways to get or return a quota to its user with PHP in the Linux operating system.

By default, servers are authorized to print only user quotas as the other quota reports of all filesystems are listed in /etc/mtab, and you can call the rpc.rquotad on the server machine to get the information for filesystems that are NFS-mounted.

It’s essential to learn how to over-quota one or more filesystems if quota exits with a non-zero status, and you will mostly find default filesystems at /etc/mtab and quota.user or quota.group quota files at the filesystem root.

As quotas can protect the user from unintentional abuse, minimizes data exfiltration, and protects user resources from excessive usage, they are important to return for management, updating, or view by the user, as well as to limit the amount of disk space or the number of files that a user can use or access.

Quotas are essential to restrict or track the disk space and the number of files used by a particular user, and they are applied to a specific volume or qtree.

It can be a scenario where you have to disable SELinux as a requirement before returning the user quota with PHP, and you can do this with something like [root@managed2 ~]# setenforce 0.

Use the crontab -e to Return User Quota With PHP in Linux OS

What’s important to consider is that the user (the user who has control over the PHP code) is unable to execute external commands to extract user quota on the Linux OS because he has restricted access to get it.

To gain access or remove the restrictions to get user quota by the system, the user can change the PHP’s configuration according to his server setup, for example, by removing safe_mode, which also can be impossible to do in case the user is on shared hosting and requires to gain access by communicating with the provider over a PHP call.

It is easy to get around PHP limitations by collecting the quotas in a .txt file in an external cron job, but this works only for users who have permission to set up cron jobs or have proper access to the server.

You can get the root access and a readable directory by your web server with the crontab -e command in PHP to save the user quota for user _username in the quota.txt text file located in the webserver folder updated every hour.

To adopt this approach in a user case where the readable format is not G, remove the -s and parse bytes, then convert them to human-readable in PHP.

The user must understand that the cronjob is hourly, and whenever he accesses the user quota, it will not contain the real-time stats of the user quota information and can contain some inconsistencies; however, it can be avoided by updating the webserver quota file frequently by increasing the frequency of the cron.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <?php

        // use `echo "The time is " . date("h:i:sa");` to implement cronjob in your PHP project

        /* Get User Quota Information
        *
        * add `0 * * * * quota -u -s someusername | grep /dev > /path/to/webserver/quota.txt`
        * to save quota setting
        *
        * prepare user account and array the disk space information by ascertaining the available space on its quota
        * and the space used and the space free to use by a specific user
        *
        * @param string $_user The system user name
        *
        * @return array
        */

        function get_QuotaInfo_User($_user) {
            $user_quota = exec("quota -s -u ".$_user);            // query server
            $user_quota = preg_replace("/[\s-]+/", ' ', $user_quota); // clear spaces
            $arr = explode(' ', $user_quota);

            $_free_space = str_replace('M', '', $arr[3]) - str_replace('M', '', $arr[2]);

            return array(
            "total" => $arr[3],
            "used"  => $arr[2],
            "free"  => $_free_space.'M'
            );

        }

        /*
         * you can write this in your php project to return or show the file containing the user quota

          $user_quota_file_txt = file_get_contents("quota.txt");
          $user_quota_array = explode("   ",$user_quota_file_txt);
          function user_quota_exe($str){
            return intval(substr_replace($str, "", -1));
          }

          echo "total quota: ". $user_quota_array[4]."<br>";
          echo "used: ". $user_quota_array[3]."<br>";
          $free =(user_quota_exe($user_quota_array[4]))-user_quota_exe($user_quota_array[3]);
          echo "free: " . $free . "G";

        */

        ?>
    </body>
</html>

Output:

* display text from the `quota.txt` file

Use the repquota -a Command to Return User Quota With PHP in Linux OS

It is a Linux command to return a user quota report on storage usage, and you can adopt this in PHP. However, the primary command to edit quotas is edquota, enabling you to edit daily critical quota files such as /etc/fstab.

Install the quota tool by issuing the command yum install quota and accept any dependencies that might be necessary, and let the installation complete. Afterward, use quotacheck -cu /home to create the database file and run this command again, replacing the -c with -av (new command will look like quotacheck -avu) where -a will check all the local mounted, quota-enabled partitions and -v will use the verbose output.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <?php

        function execCommand($command, $log) {

            if (substr(php_uname(), 0, 7) == "Windows")
            {
                //windows
                // write alternative command for Windows
            }
            else
            {
                //linux
                shell_exec( $command . "repquota -a" );
            }

            // or
            /*

            shell_exec( $command . "repquota -a" ); // just use this line in your code

            */

            return false;
        }

        ?>
    </body>
</html>

Output:

* it will run the `repquota -a` command in PHP code and show the user quota

Users with non-privileged access to Linux servers with shared MySQL and PHP hosting can execute the sudo -u command to get user quota. You can grant this privilege in the sudoers file and execute this command as a non-privileged user.

It is similar to # repquota -a and # repquota /home to show all configured quotas and quotas on a specific partition, respectively. Furthermore, you can utilize Linux commands like # quota -u user and # quota -g group to show quotas that apply to a specific user or user group.

Use the du -bs Command to Return User Quota With PHP in Linux OS

As PHP can’t output quota, you need an easier way to exploit the Linux commands, and using explode is a perfect example of splitting a string by a string to convert your string to an array of strings in PHP. However, you can use crontable to output quota to /temp and fetch it with something like $var = exec("cat /tmp/quotas | grep domz | tail -n 1 | awk '{print $4}'"); in PHP.

Furthermore, working with MySQL to return user quota requires a different approach. It works by checking the size of each database and revoking the INSERT and CREATE privileges for the databases which exceed the given size limit.

As the quota is a database and not user based, it will not work for users who have global privileges, but in most environments, privileges are given in the "db"-table which can be modified in PHP using MySQL.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <?php

        $conn_server = $db_host;
        $conn_user = $db_user;
        $user_passwrd = $db_pass;
        $conn_database = "root_cwp";

        // Create a connection
        $conn = new mysqli($conn_server, $conn_user, $user_passwrd, $conn_database);

        class user_quota_spaceused
        {
            private $conn;

            public function __construct($conn)
            {
                $this->conn = $conn;
            }

            public function calculate()
            {
                $quota['home'] = $this->user_homeQuota();
                $quota['mysql'] = $this->user_MySQL_Quota();

                return $quota;
            }

            public function user_homeQuota()
            {
                $user_quota = shell_exec("du -bs /home/*");
                $userQuota_all = explode("\n", $user_quota);

                $quota = [];
                foreach ($userQuota_all as $user_homeQuota_info) {
                    if (!empty($user_homeQuota_info)) {
                        $user_quotaInfo = explode('/', trim($user_homeQuota_info), 2);
                        $conn_user = trim(str_replace('home/', '', $user_quotaInfo[1]));
                        $user_quota = trim($user_quotaInfo[0]);
                        $quota[$conn_user] = (int) $user_quota;
                    }
                }
                return $quota;
            }

            public function user_MySQL_Quota()
            {
                $com_getallQuota = shell_exec("du -bs /var/lib/mysql/*");
                $userQuota_rows = explode("\n", $com_getallQuota);

                $quota = [];
                foreach ($userQuota_rows as $infoQuota_row) {
                    if (!empty($infoQuota_row)) {
                        $quotaInfo_user = explode('/', trim($infoQuota_row), 2);
                        $userQuota_file = trim($quotaInfo_user[0]);
                        $database_name = trim(str_replace('var/lib/mysql/', '', $quotaInfo_user[1]));
                        $explodedDatabase_name = explode('_', trim($database_name), 2);
                        $conn_quotaUser = $explodedDatabase_name[0];

                        if (isset($explodedDatabase_name[1])) {
                            $conn_user_database = $explodedDatabase_name[1];
                        };

                        if (isset($quota[$conn_quotaUser])) {

                            if (isset($conn_user_database)) {
                                $quota[$conn_quotaUser]['db'][$conn_user_database] = (int) $userQuota_file;
                            }

                            $quota[$conn_quotaUser]['db_quota'] += (int) $userQuota_file;

                            $quota[$conn_quotaUser]['db_count']++;
                        }
                        else
                        {
                                if (isset($conn_user_database)) {
                                    $quota[$conn_quotaUser]['db'][$conn_user_database] = (int) $userQuota_file;
                                }

                                $quota[$conn_quotaUser]['db_quota'] = (int) $userQuota_file;
                                $quota[$conn_quotaUser]['db_count'] = 1;
                        }
                        unset($conn_user_database);
                    }
                }

                return $quota;
            }
        }

        $cwpUsersQuota = new user_quota_spaceused($conn);
        $quota = $cwpUsersQuota->calculate();

        ?>
    </body>
</html>

Output:

* gets user home and MySQL quota info and shows the user quota info on a webpage table

Use MySQL Quota to Return User Quota With PHP in Linux OS

This C++ program describes the process of getting MySQL quota script for a specific user using free and redistributable software, and you can see the GNU General License for more details. Create a Quota table for MySQL quota script using CREATE TABLE with Db and Limit variables.

The field Db stores the information for which database you want to limit the size, and the field Limit is the size limit per user in bytes. Furthermore, the exceeded (Exceeded ENUM (Y,N) DEFAULT N NOT NULL, PRIMARY KEY (Db), UNIQUE (Db)) is only used internally and must be initialized with N.

#!/user/bin/am -q
<?PHP

    /*
     * Settings
     */

    $host_mysql  = 'localhost';

    // do not change the `$nysql_user` because root access is required
    $user_mysql  = 'root';
    $pass_mysql  = '';

    // to check not just the Db but the Db with the user quota table
    $database_mysql    = 'quotadb';
    $table_mysql = 'quota';

    /*
     * it is restricted to change anything below without a proper understanding
     */

    $conn_debug = 0;

    // connection to MySQL server
    if (!mysql_connect($host_mysql, $user_mysql, $pass_mysql))
    {
        echo "Connection to MySQL-server failed!";
        exit;
    }

    // database selection process
    if (!mysql_select_db($database_mysql))
    {
        echo "Selection of database $database_mysql failed!";
        exit;
    }

    // to check the quota in each entry of the quota table from the selected database
    $query_mysql = "SELECT * FROM $table_mysql;";
    $result = mysql_query($query_mysql);

    while ($db_row = mysql_fetch_array($result))
    {
        $database_quota = $db_row['db'];
        $limit_userquota = $db_row['limit'];
        $exceeded_quota = ($db_row['exceeded']=='Y') ? 1 : 0;

        if ($conn_debug){
            echo "Checking quota for '$database_quota'...
            ";
        }

        $show_mysqlQuery = "SHOW TABLE STATUS FROM $database_quota;";
        $query_result = mysql_query($show_mysqlQuery);

        if ($conn_debug){
            echo "SQL-query is `$show_mysqlQuery`
            ";
        }

        $size_userQuota = 0;

        while ($query_row = mysql_fetch_array($query_result))
        {
            if ($conn_debug)
            {
                echo "Result of query:
                "; var_dump($query_row);
            }

            $size_userQuota += $query_row['Data_length'] + $query_row['Index_length'];
        }

        if ($conn_debug){
            echo "Size is $size_userQuota bytes, limit is $limit_userquota bytes
            ";
        }

        if ($conn_debug && $exceeded_quota){
            echo "Quota is marked as exceeded.
            ";
        }

        if ($conn_debug && !$exceeded_quota){
            echo "Quota is not marked as exceeded.
            ";
        }

        if (($size_userQuota > $limit_userquota) && !$exceeded_quota)
        {
            if ($conn_debug){
                echo "Locking database...
                ";
            }

            // save the information in the quota table
            $user_infoQuery = "UPDATE $table_mysql SET exceeded='Y' WHERE db='$database_quota';";
            mysql_query($user_infoQuery);

            if ($conn_debug)
            {
                echo "Querying: $user_infoQuery
                ";
            }

            // dismissing the CREATE and INSERT privileges for the database
            mysql_select_db('mysql');
            $user_infoQuery = "UPDATE db SET Insert_priv='N', Create_priv='N' WHERE Db='$database_quota';";
            mysql_query($user_infoQuery);

            if ($conn_debug)
            {
                echo "Querying: $user_infoQuery
                ";
            }

            mysql_select_db($database_mysql);
        }

        if (($size_userQuota <= $limit_userquota) && $exceeded_quota)
        {
            if ($conn_debug){
                echo "Unlocking database...
                ";
            }

            // to save info in the user quota table
            $user_infoQuery = "UPDATE $table_mysql SET exceeded='N' WHERE db='$database_quota';";
            mysql_query($user_infoQuery);

            if ($conn_debug){
                echo "Querying: $user_infoQuery
                ";
            }

            // granting the CREATE and INSERT privileges for the database
            mysql_select_db('mysql');
            $user_infoQuery = "UPDATE db SET Insert_priv='Y', Create_priv='Y' WHERE Db='$database_quota';";
            mysql_query($user_infoQuery);

            if ($conn_debug){
                echo "Querying: $user_infoQuery
                ";
            }

            mysql_select_db($database_mysql);
        }
    }
?>

Output:

* Select the MySQL user quota from the MySQL database

Use the imap_get_quota Function to Return User Quota With PHP in Linux OS

It helps admin users to retrieve their user quota settings per mailbox or quota usage statics. The imap_get_quota function is for admin users, and the non-admin user version of this group is imap_get_quotaroot(), which they can use for a similar purpose.

Utilize this function and include $imap for the IMAP or Connection instance and the $quota_root as a name in the form of user.name for the mailbox. The finalized function will look something like imap_get_quota(IMAP\Connection $imap, string $quota_root): array|false, which returns an integer array containing the storage limit and usage for the given user.

The return values from this function represent the total amount of allowed space for a particular mailbox or user (represented by the limit) and the user’s current capacity or capacity usage (represented by the usage). It returns false and shows an error in case the user or mailbox information is incorrect or in any other case of failure to retrieve the capacity usage information from the user quota.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <?php
            $userQuota_checkMail = imap_open("{imap.example.org}", "admin_mailaddress", "your_password", OP_HALFOPEN)
                or die("Caution! can't connect to the server: " . imap_last_error());

            $accessuserQuota_checkValue = imap_get_quota($userQuota_checkMail, "user.hassankazmi");

            if (is_array($accessuserQuota_checkValue))
            {
                echo "User's usage level: " . $accessuserQuota_checkValue['usage'];
                echo "User's storage limit: " . $accessuserQuota_checkValue['limit'];
            }

            imap_close($userQuota_checkMail);
        ?>

        // use the following PHP example for `imp_get_quota` 4.3 or greater

        /*
        $userQuota_checkMail = imap_open("{imap.example.org}", "admin_mailadmin", "your_password", OP_HALFOPEN)
            or die("Caution! can't connect to the server: " . imap_last_error());

        $accessuserQuota_checkValue = imap_get_quota($userQuota_checkMail, "user.hassankazmi");
        if (is_array($accessuserQuota_checkValue))
        {
            $user_storageQuota_info = $accessuserQuota_checkValue['STORAGE'];
            echo "User's usage level: " .  $user_storageQuota_info['usage'];
            echo "User's storage limit: " .  $user_storageQuota_info['limit'];

            $user_storageQuota_message = $accessuserQuota_checkValue['MESSAGE'];
            echo "User's MESSAGE usage level: " .  $user_storageQuota_message['usage'];
            echo "User's MESSAGE limit: " .  $user_storageQuota_message['limit'];

            /* ...  */
        }

        imap_close($userQuota_checkMail);
        */
    </body>
</html>

Output:

* user quota info from the mailbox

User's usage level: 32.66 GB
User's storage limit: 60 GB

The original user quota access or return methods in PHP are available for backward compatibility reasons; as of PHP 4.3, the imap_get_quota function is only available to users of the c-client2000 or greater library. It is only a useful function when the user administrator opens the imap for users; otherwise, it will not work.

It’s important to take note of getting the Notice: Unknown error while using the imap functions (Quota root does not exist (errflg=2) or similar errors) after the script finishes. Call the imap_error() functions before closing the imap stream to clear the error stack to stop getting the error notifications.

Furthermore, your IMAP server must have getquota capability for this function to work, and you can check this by logging in directly using telnet <mail server> <port>. For example, use telnet mail.myserver.com 143 and see something like 0 CAPABILITY.

Syed Hassan Sabeeh Kazmi avatar Syed Hassan Sabeeh Kazmi avatar

Hassan is a Software Engineer with a well-developed set of programming skills. He uses his knowledge and writing capabilities to produce interesting-to-read technical articles.

GitHub