How to Create a Tracker, Part 3: Torrent & User Details

August 17, 2009 by Hangman

In this third part of the tutorial (Parts I & II here), our goal is to show some information about our torrents and users. We’ll go through a bunch of tips and snippets that any developer may find useful while developing a torrent site, such as some util functions to display relative times, friendly sizes and a tree with files and folders.

Article republished with permission from Valadiléne.org - source here.

A look at files tables

xbt_files, the table which contains records for all tracked torrents, gives us access to some information we’ll need to show on our torrent details page:

  • info_hash - Info hash of the torrent
  • leechers/seeders - Explains itself. Number of current leechers/seeders
  • completed - Number of times this torrent has been 100% downloaded by a peer
  • mtime - Last time this torrent has been updated as Unix timestamp
  • ctime - Time this torrent has been added to the tracker as Unix timestamp
  • flags - When this value is set to 1, XBTT will stop tracking the torrent and delete its record (we won’t need it here)

Our ideal details page will display those values in a cool box or table. The nicest way to display those time values is using a function that shows them as a relative time string. You may want to use this snippet at Snipplr.

The xbt_files_users table stores a torrent-user map for each torrent entry with information on peer activity.

  • fid - torrent ID
  • uid - user ID
  • active - whether this activity is still going on
  • announced - Number of announces
  • completed - Number of 100% complete transfers
  • downloaded/left/uploaded - Downloaded, left, uploaded bytes
  • mtime - Last update time

What we’ve just seen is all data related to peer activity. As well as this kind of stuff, we may want to display .torrent files details, just like any other torrent site does (just see the Details tab on any Minonova torrent). We’re going to look at some code to get this data and display it in a friendly way.

Getting .torrent metadata

In the previous part we’ve seen how to open a .torrent file and have access to bencoded values through File_Bittorrent2. The following code snippets will make use of this library.

First of all, we have to locate the .torrent file we want to open. If we have stored them using torrent IDs as filenames (as we’ve done in part 2), opening the file is as easy as those lines:

<?php
define(‘TORRENT_UPLOAD_PATH’,‘uploads’);

$filename=TORRENT_UPLOAD_PATH.$id.‘.torrent’;
$dec=new File_Bittorrent2_Decode;
$info=$dec->decodeFile($filename);
?>

To display sizes we will use this handy function:

<?php
function mksize($bytes)
{
        if ($bytes < 1000 * 1024)
                return number_format($bytes / 1024, 2) . " kB";
        if ($bytes < 1000 * 1048576)
                return number_format($bytes / 1048576, 2) . " MB";
        if ($bytes < 1000 * 1073741824)
                return number_format($bytes / 1073741824, 2) . " GB";
        if ($bytes < 1000 * 1099511627776)
                return number_format($bytes / 1099511627776, 2) . " TB";
        if ($bytes < 1000 * 1125899906842620)
                return number_format($bytes / 1125899906842620, 2) . " PB";
        if ($bytes < 1000 * 1152921504606850000)
                return number_format($bytes / 1152921504606850000, 2) . " EB";
}
?>

Now we’re ready to show the stuff we need:

Filename: <?php echo $filename ?>
Info hash <?php echo $info[‘info_hash’] ?>
Total size <?php echo mksize($info[’size’]) ?> in <?php echo count($info[‘files’]) ?> files

Torrent files tree

In order to display the files contained in our torrent, we’re going to output a file-tree including directories. As we have noticed, $info['files'] is an array containing all the files in the torrent. They are stored as paths, for example “directory/file1.txt”, “directory/file2.txt”, and so on, so, in order to build a tree, we need to separate directories from filenames and put them in a multidimensional array first. This is done by the following code.

<?php
function buildTreeArray($files)
{
    $ret = array();

    foreach ($files as $k => $v)
    {
        $filename=$v[‘filename’];

        $parts = preg_split(‘/\//’, $filename, -1, PREG_SPLIT_NO_EMPTY);
        $leaf = array_pop($parts);

        // build parent structure
        $parent = &$ret;
        foreach ($parts as $part)
        {
                $parent = &$parent[$part];
        }

        if (empty($parent[$leaf]))
        {
                $v[‘filename’]=$leaf;
                $parent[$leaf] = $v;
        }
    }

    return $ret;
}
?>

This function will loop through each file, split directories from filenames and organize them in a new array, which we can now display in a barebones HTML tree using a recursive function. Of course you will have to customize it using HTML/CSS or whatever and maybe add an appropriate icon before each file based on its extension; I’ll leave that to your creativity. Comments should be self-explanatory.

<?php
function outputTree($files, $indent=0)
{
    echo "<ul>";

    foreach($files as $k=>$v)
    {
        $entry=isset($v[‘filename’]) ? $v[‘filename’] : $k;
        $size=$v[’size’];

        if($indent==0)
        {
            // root
            $is_folder=true;
        }
        elseif(is_array($v) && (!array_key_exists(‘filename’,$v) && !array_key_exists(’size’,$v)))
        {
            // normal node
            $is_folder=true;
        }
        else
        {
            // leaf node, i.e. a file
        $is_folder=false;
        }

        if($is_folder)
        {
            // we could output a folder icon here
        }
        else
        {
            // we could output an appropriate icon
            // based on file extension here
            $ext=pathinfo($entry,PATHINFO_EXTENSION);
        }

        echo "<li>";
        echo $entry; // output folder name or filename

        if(!$is_folder)
        {
            // if it’s not a folder, show file size
            echo " (".mksize($size).")";
        }

        echo "</li>";
 
        if(is_array($v) && $is_folder)
        {
            outputTree($v, ($indent+1));
        }
    }

    echo "</ul>";
}
?>

Some user data

Now that we are done with torrent data, there is nothing left to show but some user details in profiles.
We need to fetch data from xbt_users, which contains trivial stuff like downloaded and uploaded bytes.
An important thing to show is the user ratio, which can be calculated by simply dividing uploaded by downloaded.

<?php
function get_ratio($ul,$dl)
{
    if($dl<=0 || $ul<=0)
        return ‘-’;

    return $ratio=round($ul/$dl, 2);
}
?>

Conclusion

This time we have looked at the structure of some XBTT tables which store information about tracker and torrent data. Also, we’ve fetched metadata from .torrent files and shown some snippets to output them in a nice and friendly way. I hope this helps out someone in speeding up development of new custom made torrent sites. Stay tuned for the following parts of the guide!