дисковая квота на виртуальном хостинге

Как  на виртуальном хостинге гарантировать, что клиент не сможет выбрать дисковое пространство больше, чем ему положено по тарифу?

Обычно, клиент может загружать файлы на сервер хостинга по FTP и HTTP, будем исходить именно из этого.
В случае FTP задача решается достаточно просто, так как многие FTP-серверы имеют встроенную поддержку квот, например, ProFTPD и pure-ftpd.
С HTTP дело обстоит гораздо сложнее, тут такого простого стандартного решения не существует. Для себя я нашёл решение работающее, если хостинг использует PHP (только):
Для PHP есть расширение suhosin, кроме повышения безопасности, этот модуль предоставляет возможность "проверять" все загружаемые до того, как они попадут в клиентский PHP-скрипт. Опция suhosin.upload.verification_script, как следует из названия, задаёт имя программы (скрипта), который решает "хороший" файл загружен или нет, в качестве параметра скрипт получает полное имя загруженного файла.
Так как я на хостинг-сервере использую PureFTP c поддержкой виртуальных квот, то и скрипт у меня соответствующий:

#!/usr/bin/perl -w
use strict;

use Sys::Syslog qw/:standard :macros/;
use File::stat;
use DBI;

use vars qw/$res $database $hostname $port $user $password $uploaded_filename/;

BEGIN {
    openlog('php_upload_check', 'nofatal,pid', LOG_LOCAL7);
    $SIG{__DIE__} = sub {
        syslog(LOG_ERR, @_);
        CORE::die @_;
        return 1;
    };
    $SIG{__WARN__} = sub {
        syslog(LOG_WARNING, @_);
        return 1;
    };
}

END {
    syslog LOG_INFO, "result for file [%s] is [%s]\n", $uploaded_filename, $res;
    closelog();
}

# default result
$res = '0 quota exceeded';

$database = 'pureftpd';
$hostname = 'localhost';
$port = '/tmp/mysql.sock';
$user = 'pureftp';
$password = 'dbpassvv0rd';

$uploaded_filename = shift @ARGV or die "required filename parameter is missed";

my $fstat = stat($uploaded_filename) or die "failed stat($uploaded_filename): $!";

my $dbh = DBI->connect("DBI:mysql:$database:$hostname:$port", $user, $password)
    or die "Can't connect to [$database]: $DBI::errstr";

my $sth = $dbh->prepare( qq{SELECT vhost_type, Dir, Quota FROM users WHERE is_enabled='Y' AND Uid=? LIMIT 1} )
    or die "Can't prepare statement: $DBI::errstr";

my $rc = $sth->execute(scalar $fstat->uid) or die "Can't execute statement: $DBI::errstr";

if (my ($vhost_type, $dir, $quota) = $sth->fetchrow_array()) {
    if ($vhost_type eq 'OWN') {
        $res = '1 quota OK';
    } else {
        $dir =~ s{(/var/webroot/+[^/]+)(?:.*)?$}{$1};
        open(QUOTA_FILE , '<', "$dir/.ftpquota") or warn "can't open [$dir/.ftpquota]: $!";
        my $line = ;
        close(QUOTA_FILE) or warn "can't close [$dir/.ftpquota]: $!";
        $line =~ m/^\d+\s(\d+)$/;
        my $used_space = $1;
        $res = '1 quota OK' if ($used_space + $fstat->size <= $quota * 1024 * 1024);
    }
}

# check for problems which may have terminated the fetch early
warn $sth->errstr if $sth->err;

$sth->finish();

$dbh->disconnect;

print "$res\n";


Конечно, необходимо указать скрипт в php.ini:
[suhosin]
suhosin.upload.verification_script = /var/adm/php_upload_check
, настроить syslog, для FreeBSD можно так:
!php_upload_check
*.*                                             /var/log/httpd/php_upload_check.log
и тогда в логах при загрузке файла появляются записи вроде
Jan 16 15:36:14 vhosting php_upload_check[93237]: result for file [/var/webroot/clienthosting.ru/temp/php7MNnRm] is [1 quota OK]

Комментарии

Популярные сообщения из этого блога

streaming multicast IPTV to HLS (nginx+RTMP)

using pg_partman to help partitioning postgresql for zabbix