PDA

View Full Version : Attachment.php


rin
08-13-2009, 11:54 AM
Hello,

I was wondering about the following:
If I download or view an attachment via the vBulletin attachment.php, would it be possible to write its filesize into the database?
My idea is this: Every time a member downloads something, the filesize will be added to a user-specific table.
Once the number in that table matches or is bigger than the allowed quota, the attachment.php would return an error. That quota-number in the table would then periodically be erased.
Generally, the question is: Can I get this data (attachment filesize) and write it into the database?

Dismounted
08-13-2009, 12:06 PM
The filesize for each attachment is already stored in the database. It is stored in the "filesize" field in attachment.

rin
08-13-2009, 12:23 PM
Great, I have just installed a test installation and can see what you refer to.
I don't have the chance to check for filesystem attachments, but I assume it is the same method, each attachment getting its own attachment ID and the filesize info in the database.

So in order to control a users bandwidth consumption, I would grab the attachments filesize when attachment.php is called and add it to the user specific attachment_quota table.

Can you point me to a tutorial how to write vBulletin addons? As I tried looking around but didn't find anything.
Or would you suggest that I hard-code it into the files?

rin
08-15-2009, 01:15 AM
Gotta bump this. =)

Lynne
08-15-2009, 03:51 AM
There isn't really one particular tutorial on how to write a product. You can look through the articles forum, but I think most users learn by looking at other products to see how it was done.

AndrewD
08-15-2009, 03:14 PM
Instead of patching the attachment system, you could try the Links and Downloads Manager, which includes bandwidth control. See url in my signature.

rin
08-16-2009, 12:40 AM
Instead of patching the attachment system, you could try the Links and Downloads Manager, which includes bandwidth control. See url in my signature.
Hello Andrew. I am not sure, about the addon LDM. Currently I am serving more than 120.000 attachments (100+ GB) and how I understand LDM, it will only account for the attachments uploaded after the addon has been activated.
Seeing how many attachments I am serving, I would prefer to have the limit as simple as possible. Only adding a new row to all members, summing and controlling their bandwidth usage that way.

--------------- Added 1250388287 at 1250388287 ---------------

Please bear with me. Since I have asked for an addon like this for several days and so far no one else sees its uses, I might want to try and code it myself with my rather limited knowledge of php and mysql.
So if I want to start, I would like to ask you some questions.
The hook to be used for an addon like this should be attachment_start, right?
Then I want to write the code similar to this:
GET attachment-filesize -> write filesize to member download quota table

check member-usergroup; if is member of X usergroup = limit quota->X bytes
if member-download-quota > usergroup-limit THEN stop and write attachment quota message.
if member-download-quota <= usergroup limit THEN go on.

Additionally, I would set up a cron job that runs for example, every 24 hours and clears the member-download-quota table so the member is able to download again.

Is it a good approach?

--------------- Added 1250393636 at 1250393636 ---------------

So far, I got this:
if($vbulletin-userinfo['usergroupid'] = 7) { $download_quota = 15728640; } // Moderators
if($vbulletin-userinfo[download_quota'] < $download_quota)
{
$new_download_quota = $vbulletin-userinfo['download_quota'] + $attachmentinfo['filesize'];

$db->query_write("
UPDATE " . TABLE_PREFIX . "user SET
download_quota = $new_download_quota
WHERE userid = $vbulletin-userinfo[userid]
")
}
else
{
print "error";
}
First I create a new table in user called "download_quota".
Then I set a different download quota for all existing usergroups. In this case it's 15 MB in bytes.
Then I go check if the users current download_quota is less than the allowed 15MB.
If that is the case, I will add the filesize of the current attachment to the download_quota field for the specific user.
If it's bigger I return error. =)
Is it that simple?

AndrewD
08-16-2009, 08:53 AM
Hello Andrew. I am not sure, about the addon LDM. Currently I am serving more than 120.000 attachments (100+ GB) and how I understand LDM, it will only account for the attachments uploaded after the addon has been activated.
Seeing how many attachments I am serving, I would prefer to have the limit as simple as possible. Only adding a new row to all members, summing and controlling their bandwidth usage that way.

--------------- Added 1250388287 at 1250388287 ---------------

Please bear with me. Since I have asked for an addon like this for several days and so far no one else sees its uses, I might want to try and code it myself with my rather limited knowledge of php and mysql.
So if I want to start, I would like to ask you some questions.
The hook to be used for an addon like this should be attachment_start, right?
Then I want to write the code similar to this:
GET attachment-filesize -> write filesize to member download quota table

check member-usergroup; if is member of X usergroup = limit quota->X bytes
if member-download-quota > usergroup-limit THEN stop and write attachment quota message.
if member-download-quota <= usergroup limit THEN go on.

Additionally, I would set up a cron job that runs for example, every 24 hours and clears the member-download-quota table so the member is able to download again.

Is it a good approach?

--------------- Added 1250393636 at 1250393636 ---------------

So far, I got this:
if($vbulletin-userinfo['usergroupid'] = 7) { $download_quota = 15728640; } // Moderators
if($vbulletin-userinfo[download_quota'] < $download_quota)
{
$new_download_quota = $vbulletin-userinfo['download_quota'] + $attachmentinfo['filesize'];

$db->query_write("
UPDATE " . TABLE_PREFIX . "user SET
download_quota = $new_download_quota
WHERE userid = $vbulletin-userinfo[userid]
")
}
else
{
print "error";
}
First I create a new table in user called "download_quota".
Then I set a different download quota for all existing usergroups. In this case it's 15 MB in bytes.
Then I go check if the users current download_quota is less than the allowed 15MB.
If that is the case, I will add the filesize of the current attachment to the download_quota field for the specific user.
If it's bigger I return error. =)
Is it that simple?

Your approach looks broadly ok, but my experience is that you will find complications. For example, users can be members of multiple usergroups - which one defines their quota? What happens if a transfer fails to complete? Are you happy with just knowing each user's total transfer or do you want information on the specific files that were downloaded? etc, etc. It's worth thinking these points through before writing any code, just to be clear in your own mind about the consequences of alternative approaches.

I'm not sure of the need for a separate table for the user group allowances, although this is a straightforward solution. Another approach would be to hold this array as a serialised string in the data cache. This would reduce the required sql traffic.

rin
08-16-2009, 09:10 AM
Hi Andrew, thanks for your reply.
Since most of the attachments are pictures and less than 200KB in filesize, I wouldn't mind broken transfers. If in the membership plan 10MB bandwidth are mentioned, I would secretly allow members a bandwidth consumption of around 15MB to avoid situations like that.
I would reduce usergroups to the basic ones and don't let members have multiple usergroups.
In my case those would simply be: Banned and Guests (no access anyway), Unsubscribed, Subscribed, Actives and the obvious i.e. Moderators and Administrators.

Because I am thinking about a subscription plan for my website. So I need to make it more valueable for members to pay a sum once in a while. I want to achieve that by giving users bandwith (or not).

I have further worked on it:
if($vbulletin->userinfo['usergroupid'] = 6) { $limitation = 1; }

$result = $db->query_read("SELECT current_bandwidth FROM " . TABLE_PREFIX . "user WHERE userid = $vbulletin->userinfo[userid]); // Get the current bandwidth usage
$current_quota = $result['current_bandwidth'] + $attachmentinfo['filesize']; // Calculate the current quota being used including the file which the user wants to download now.

if($current_quota < $limitation)
{
SHOW ATTACHMENT
}
else
{
DON'T SHOW ATTACHMENT
}
$db_query_write("UPDATE " . TABLE_PREFIX . "user SET current_bandwidth = $current_quota WHERE userid = $vbulletin->userinfo['userid']");

I am going to try this out on my test-installation now. But I am sure it will be broken in one way or another.
So please, if by looking over the code you find anything which doesn't match up, I hope you can help me.
Cheers

--------------- Added 1250419067 at 1250419067 ---------------

As predicted, it doesn't work.
When opening attachments, it will not write the quota into the database.
I use the "attachment_start" hook.

--------------- Added 1250431666 at 1250431666 ---------------

Strange enough, even if I active the following plugin, all thumbnails and attachments are broken.
$db->query_write("
UPDATE " . TABLE_PREFIX . "user SET
current_bandwidth = 10
WHERE userid = $vbulletin->userinfo[userid]
");
I have used attachment_start and attachment_display as hooks.

AndrewD
08-16-2009, 01:49 PM
Hi Andrew, thanks for your reply.
Since most of the attachments are pictures and less than 200KB in filesize, I wouldn't mind broken transfers. If in the membership plan 10MB bandwidth are mentioned, I would secretly allow members a bandwidth consumption of around 15MB to avoid situations like that.
I would reduce usergroups to the basic ones and don't let members have multiple usergroups.
In my case those would simply be: Banned and Guests (no access anyway), Unsubscribed, Subscribed, Actives and the obvious i.e. Moderators and Administrators.

Because I am thinking about a subscription plan for my website. So I need to make it more valueable for members to pay a sum once in a while. I want to achieve that by giving users bandwith (or not).

I have further worked on it:
if($vbulletin->userinfo['usergroupid'] = 6) { $limitation = 1; }

$result = $db->query_read("SELECT current_bandwidth FROM " . TABLE_PREFIX . "user WHERE userid = $vbulletin->userinfo[userid]); // Get the current bandwidth usage
$current_quota = $result['current_bandwidth'] + $attachmentinfo['filesize']; // Calculate the current quota being used including the file which the user wants to download now.

if($current_quota < $limitation)
{
SHOW ATTACHMENT
}
else
{
DON'T SHOW ATTACHMENT
}
$db_query_write("UPDATE " . TABLE_PREFIX . "user SET current_bandwidth = $current_quota WHERE userid = $vbulletin->userinfo['userid']");

I am going to try this out on my test-installation now. But I am sure it will be broken in one way or another.
So please, if by looking over the code you find anything which doesn't match up, I hope you can help me.
Cheers

--------------- Added 1250419067 at 1250419067 ---------------

As predicted, it doesn't work.
When opening attachments, it will not write the quota into the database.
I use the "attachment_start" hook.

--------------- Added 1250431666 at 1250431666 ---------------

Strange enough, even if I active the following plugin, all thumbnails and attachments are broken.
$db->query_write("
UPDATE " . TABLE_PREFIX . "user SET
current_bandwidth = 10
WHERE userid = $vbulletin->userinfo[userid]
");
I have used attachment_start and attachment_display as hooks.

In your last example, and I imagine in your full code, there is a syntax error. The following works correctly:


$vbulletin->db->query_write("
UPDATE " . TABLE_PREFIX . "user
SET current_bandwidth = 10
WHERE userid = " . $vbulletin->userinfo[userid]
);

rin
08-16-2009, 02:08 PM
Hey thanks! =) Your code works properly.
Now I tried to stop the script from executing.
I tried using die() and exit() but both did not stop the script from showing the attachment.
What would I need to do in order to stop the attachment from showing up?

Dismounted
08-17-2009, 06:24 AM
exit; should stop execution of the script. Are you sure the code is actually run?

rin
08-17-2009, 09:39 AM
What I tried was to create a new plugin with hook "attachment_start" and with the simple line exit(). But still, the attachment would show up. I cleared the cache and it still showed up.

--------------- Added 1250506111 at 1250506111 ---------------

Got it working now.
Strange thing is, it will not exit the script when the thumb and attachment have been cached before?
Is there a better hook for this purpose than attachment_start?

--------------- Added 1250506751 at 1250506751 ---------------

It is very strange. On my test installation, it would work with 2 pictures, it would not work with another and it would show the path to the other instead of anything else.

AndrewD
08-17-2009, 01:03 PM
What I tried was to create a new plugin with hook "attachment_start" and with the simple line exit(). But still, the attachment would show up. I cleared the cache and it still showed up.

--------------- Added 1250506111 at 1250506111 ---------------

Got it working now.
Strange thing is, it will not exit the script when the thumb and attachment have been cached before?
Is there a better hook for this purpose than attachment_start?

--------------- Added 1250506751 at 1250506751 ---------------

It is very strange. On my test installation, it would work with 2 pictures, it would not work with another and it would show the path to the other instead of anything else.

I imagine this is a consequence of how your browser handles files. attachment.php sends a series of browser headers, including some which allow the browser to cache the file for a year. Once those headers have been sent, you no longer have control over file delivery because it is being picked up locally and not retransmitted.

rin
08-17-2009, 01:55 PM
Yup, I have just tried around a little bit and found out that cached attachments are shown in either case.
May I ask for help on this one:
$query = $db->query_read("SELECT current_bandwidth FROM " . TABLE_PREFIX . "user WHERE userid = " . $vbulletin->userinfo[userid]);

$add = $query[current_bandwidth] + 550;
Either the mySQL query is corrupt or the value of $query[current_bandwidth] is 0. Which it should not be since it has some value in the database. My guess would be that I can not call the value via the method I used. But after searching around, also in vBulletin code I didn't find a suitable solution.

AndrewD
08-17-2009, 02:27 PM
Yup, I have just tried around a little bit and found out that cached attachments are shown in either case.
May I ask for help on this one:
$query = $db->query_read("SELECT current_bandwidth FROM " . TABLE_PREFIX . "user WHERE userid = " . $vbulletin->userinfo[userid]);

$add = $query[current_bandwidth] + 550;
Either the mySQL query is corrupt or the value of $query[current_bandwidth] is 0. Which it should not be since it has some value in the database. My guess would be that I can not call the value via the method I used. But after searching around, also in vBulletin code I didn't find a suitable solution.

Reading from the database is a two-stage process, unless you are sure that there is only a single record to fetch. You either use the following sequence:


$asb = $vbulletin->db->query_read("
SELECT current_bandwidth FROM " . TABLE_PREFIX . "user
WHERE userid = " . $vbulletin->userinfo[userid]);
while ($query = $vbulletin->db->fetch_array($asb)) {
// process record
}


or, if you arre certain there is one record only, the following:


$query = $vbulletin->db->query_first("
SELECT current_bandwidth FROM " . TABLE_PREFIX . "user
WHERE userid = " . $vbulletin->userinfo[userid]);

rin
08-17-2009, 02:53 PM
Great news. You just helped me to get the script working. Here's the code:
$limit = 10000000;
$query = $vbulletin->db->query_first("
SELECT current_bandwidth FROM " . TABLE_PREFIX . "user
WHERE userid = " . $vbulletin->userinfo[userid]);

$add = $query['current_bandwidth'] + $attachmentinfo['filesize'];

$vbulletin->db->query_write("
UPDATE " . TABLE_PREFIX . "user
SET current_bandwidth = $add
WHERE userid = " . $vbulletin->userinfo[userid]
);
if($add > $limit)
{ exit(); }
Working! One more thing I was wondering, if exiting the script like this, it will cache a blank attachment. So in case I up the limit a bit, it will not reload the actual attachment, but still show the blank one. I guess there's no easy way around this except for emptying the cache.
Also, currently, when the limit is crossed, it will show a blank attachment. Is it possible to use the space for a proper message telling the user that their bandwidth has exceeded the allowance?
Simply adding a print wouldn't do the trick.

AndrewD
08-17-2009, 04:09 PM
One more thing I was wondering, if exiting the script like this, it will cache a blank attachment. So in case I up the limit a bit, it will not reload the actual attachment, but still show the blank one. I guess there's no easy way around this except for emptying the cache.

Also, currently, when the limit is crossed, it will show a blank attachment. Is it possible to use the space for a proper message telling the user that their bandwidth has exceeded the allowance?
Simply adding a print wouldn't do the trick.

You need to construct and send an appropriate html error page, including non-caching headers.

rin
08-18-2009, 01:23 AM
I found this article. Is it helpful to follow some of its instructions for the task that you described?
https://vborg.vbsupport.ru/showthread.php?t=98009

AndrewD
08-18-2009, 04:37 AM
I found this article. Is it helpful to follow some of its instructions for the task that you described?
https://vborg.vbsupport.ru/showthread.php?t=98009

You could simply try:


eval(standard_error('Unable to download attachment - bandwidth allowance exceeded'));