Get torrent data with PHP

Tags: ,

To use this code you first need to include a file with the benc, bdec and hex2bin functions. You can get these functions from here: functions.phps.

<?php

include 'functions.php';

$torrent_data = bdec(file_get_contents('yourfile.torrent'));

To get the torrent data (like the announce url, the files etc) it is enough if we decode the content of the torrent.

On the other hand, if we want to read the number of seeds, leechs and downloads, we must encode the info part of the torrent, encrypt it with the sha1 function and convert the result to lowercase.

$info = strtolower(sha1(benc($torrent_data['info'])));
$scrape = str_replace('announce', 'scrape', $torrent_data['announce']);
$sources = bdec(@file_get_contents($scrape . '?info_hash=' . urlencode(hex2bin($info))));

Since it’s the scrape telling us how many seeds, leechs and downloads the torrent has, we have to change the announce url to the scrape url and read those informations.

Now we have everything we need to display the information. Let’s see how our torrent is structured.

echo '< pre>';
print_r($torrent_data);
echo '< /pre>';

We get an array with informations like the announce url, the creation date, another array with the files and more. What we want to display is the file (or files) in the torrent and the number of people sharing the files.

Let’s display the files in the torrent. The torrent structure is different if has one file or more files in it, so we first have to count the number of files and then, if the number is bigger than 1, do a loop and display every one of them, else display only the name of that one file.

$c = count($torrent_data['info']['files']);
echo '< h2>Files< /h2>';

if ($c > 1) {
	for ($i = 0; $i < $c; $i++) {
		echo $torrent_data['info']['files'][$i]['path']['0'] . '<br/>';
	}
} else {
	echo $torrent_data['info']['name'] . '<br/>';
}

Now we have our files listed. But to display the sources we find a little problem: the array in which the sources are stored is the binary version of our $info variable. We can reach them using the hex2bin function we have in our functions.php file.

$seeds = $sources['files'][hex2bin($info)]['complete'];
$leechs = $sources['files'][hex2bin($info)]['incomplete'];
$downloads = $sources['files'][hex2bin($info)]['downloaded'];

echo '< h2>Sources< /h2>' .
	'<b>Seeds:</b> ' . $seeds . '<br/>' .
	'<b>Leechs:</b> ' . $leechs . '<br/>' .
	'<b>Downloads:</b> ' . $downloads . '<br/>';

?>

I prepared a test file torrent.php. The torrent it is checking is a music torrent from thepiratebay.org.

You can download the source of this test file here: torrent.phps.

Same as always, if you don’t understand something you can ask it in the comments.

If you liked this post think about subscribing to my RSS feed and prevent missing anything interesting. It's free, fast and doesn't hurt. Promise. Click here.
Rate this post:

56 Comments »

  1. Gr33n3gg Says:

    OMG, I’ve been searching for this for a while. Me and a colleague are working on a BitTorrent search engine and I could not find the PHP BitTorrent library (404). Also, what license is this (your above work)?
    As I plan to use this in my work.
    Anyway, thanks alot ;)

  2. nasal Says:

    Hey, thanks for the comment!

    No problem, just use it! If you need any more help feel free to ask :)

  3. Gr33n3gg Says:

    Bok!
    Thanks alot, I’ve really been looking for this. Once I get the BitTorrent site up, I’ll be sure to include credits and post the link back here. ;)

  4. nasal Says:

    i’ll be happy to use it :p the site i mean :p

  5. Davide Says:

    I was looking for something like that for a really long time.

    Thank-you so much for sharing this code!!!

    Davide (from Italy). ;)

  6. davide Says:

    Hello again,

    it is possible to print the announce-list too?

    Thanks!

  7. nasal Says:

    Sure, if i’m not wrong it is stored in:

    $torrent_data['info']['announce']
    ;)

  8. Davide Says:

    Here’s a way to print the file size too (in Megabytes).
    Hope this helps!

    if ($c > 1) {
    for ($i = 0; $i < $c; $i++) {
    echo $torrent_data['info']['files'][$i]['path']['0'] . ‘ (‘ . round((($torrent_data['info']['files'][$i]['length'])/1048576),2) . ‘ MB) ‘;
    }
    } else {
    echo $torrent_data['info']['name'] . ‘ (‘ . round((($torrent_data['info']['length'])/1048576),2) . ‘ MB) ‘;
    }

  9. Davide Says:

    The following code prints the announce(s):

    $counter = count($torrent_data['announce-list']);
    if ($counter > 0) {
    $announcelist = ($torrent_data['announce-list']);
    echo ‘Announce list:’;
    $c = count($announcelist);
    for ($i = 0; $i < $c; $i++) {
    echo $announcelist[$i]['0'];
    }
    } else {
    $announce = $torrent_data['announce'];
    echo ‘Announce:’ . $announce;
    }

  10. nasal Says:

    Thanks Davide!

    You can use the script in my new post (Format file sizes with PHP) to display the filesize in some value other then MB (if it is bigger or smaller then 1mb for example)!

  11. You could also check out PEAR’s well documented and tested File_Bittorrent2: http://pear.php.net/package/File_Bittorrent2

  12. [...] This new post to Rudi’s blog shows how, with the help of an external class you can use PHP to grab information from a torrent file. [...]

  13. nasal Says:

    Thanks for the suggestion!

  14. [...] This new post to Rudi’s blog shows how, with the help of an external class you can use PHP to grab information from a torrent file. [...]

  15. Gr33n3gg Says:

    I’m back! Heres the link to the torrent site I’ve been working on: http://torrentino.2500mhz.info

    Thanks alot for your code. One problem that I’ve been having is that browse.php is really slow, because it includes all the code needed to query the tracker to get the info (its in a for() loop). Any ideas?

  16. nasal Says:

    sure :)
    when adding the torrent, add it’s info into the database you’ve got..

    add a seeders, leechers, announce and downloaded rows to the torrent table and then do the torrent info-reading work when uploading the torrent and read the database when listing them..

    in can send you my code if you would lile to take a look :)

  17. Gr33n3gg Says:

    Not sure I get you, but when adding the torrent, add all the torrent related info?
    Thats a pretty good idea, but I use a relational flat-file database. Would that still work?
    Thanks

  18. nasal Says:

    yes, sorry for complicating simple things :D
    oh.. never worked with those, sorry.. but you could definitely give it a try!

    good luck!

  19. Gr33n3gg Says:

    Well I tried it but it doesn’t update the torrent info (seeders, etc..) when its in the databse. So I would need cron jobs or something of the like to run every X minutes.
    Thanks for your help though.

  20. nasal Says:

    why don’t u just put an update button near the info of each torrent and then when somebody needs fresh stats, he just presses the button?

  21. aozaki Says:

    yo, thx for the script. Though, it seems for some reason it cannot get info on torrents hosted on… nyatorrents for example… i tried changing the file_get_contents function for one with Curl, but still gets nothing. No idea why =/ error log shows nothing, so, im confused… if u could help me out with this i’ll be very grateful.

  22. nasal Says:

    maybe the tracker doesn’t allow scraping from other sources.. i’ve already seen some of them like demonoid (at least.. once it didn’t work with them, dunno about now)

  23. aozaki Says:

    Hmmm… yeah, i thought so too.
    But I also thought that there should be a way to fix this… like, when u write the scraping URL (the coded one that the script gives you) you can actually get the scrape info, either as text or as downloadable file… so I also tried doing the User agent thing on Curl, but still won’t work :<

    Anyways, thx for the fast reply and the script, guess I’ll try searching some more options as to how to get this to work with that kind of bt trackers.

  24. Gr33n3gg Says:

    Heh, thats not a bad idea :) Sorta like Mininova, after X minutes you can update it or it updates it for you.
    Thanks for all your help ;)

  25. nasal Says:

    @aozaki: i think it’s just not possible for some trackers.. read this on google groups, what Sanko Robinson replies, saying: “Remember that there are some trackers that simply do not support scrape, so the scrape_downloaded(), et. al calls will always return 0.”

    @Gr33n3gg: anytime!

  26. Gr33n3gg Says:

    Hmm, I’m having trouble finding the total size of the files (from the torrent). Not individual files, but all the files as a whole. Any ideas?

  27. Aozaki Says:

    hmm, if im not guessing wrong, its on the same array inside torrent['info'].
    In this case it’ll be:

    $torrent_data['info']['length'];

    That should give you the whole size.

  28. nasal Says:

    That works if there’s only one file in the torrent…
    make a loop and sum all the sizes of the files, like this:
    $sum = 0;

    if (@substr($torrent['info']['files'], ‘[\'files\']‘)) {
    foreach ($torrent['info']['files'] as $file) {
    $sum += $file['length'];
    }
    echo round($sum / pow(1024, 2)) . ‘ MB‘ . “\n”;
    } else {
    echo round(@$torrent['info']['length'] / pow(1024, 2)) . ‘ MB
    ‘ . “\n”;
    }

    (or use this snippet to format the size)

  29. Aozaki Says:

    Using snippet:

    ####################################
    $c = count($torrent_data['info']['files']);
    $sum = 0;

    if ($c > 1) {
    for ($i = 0; $i < $c; $i++) {
    $sum += $torrent_data['info']['files'][$i]['length'];
    }
    $bt_size=mksize($sum);
    } else {
    $bt_size=mksize($torrent_data['info']['length']);
    }

  30. Gr33n3gg Says:

    Aha, great thanks alot! :D

  31. Pery Says:

    nasal – This is extraordinary! I’ve been looking for a script that can provide these functions for a long time, and it’s almost impossible to find without having to use some kind of either copyrighted or open source project which a bunch of features that you don’t really need.

    There’s one thing holding me back, though, which is an issue on my part. In order for me to be able to use this, I have to include the script as an external file with PERL, and use an input to switch the get-url with a database field from my site, which is fairly easy, but I cannot do this when there’s an include file present (functions.php) as the included file won’t be able to read the switch (atleast not from my attempts).. Is there a way to include the functions.php in the actual script? This may be a silly question, but I’m no good with PHP.

    Once again, thank you for posting this!

    Best regards, Pery.

  32. nasal Says:

    Hey Pery, thanks!

    Yes, you can do it.. All you have to do is copy the content of the functions.php file to your script, put it on top of everything, it should work flawlessly!

    Have a great day!
    Rudi

  33. Pery Says:

    ####################################
    $c = count($torrent_data['info']['files']);
    $sum = 0;

    if ($c > 1) {
    for ($i = 0; $i < $c; $i++) {
    $sum += $torrent_data['info']['files'][$i]['length'];
    }
    $bt_size=mksize($sum);
    } else {
    $bt_size=mksize($torrent_data['info']['length']);
    }

    This prints 0.00KB on all files.. Any ideas?

  34. Pery Says:

    Hey Rudi,

    How exactly would it be possible for me to use a variable within the quotes in file_get_contents, like this:

    $torrent_data = bdec(file_get_contents($GLOBALS['values']['file']));

    I’ve been struggeling with this for about a week, and I cannot for the life of me figure out how to make it work without using quotes, which again will not work because I’m using a variable. What was your idea for inputing file URLs when you wrote it?

    I would be very greatful if I could get some help on this =)

  35. DragonPrince Says:

    Hi nasal,
    This is a real nice code but the functions.phps link is not working. So, could you plz help friend.

  36. nasal Says:

    Hey!

    It works for me.. anyway, try this.

    Have a nice day!

  37. DragonPrince Says:

    Thanks friend :-)

  38. DragonPrince Says:

    Hi nasal,
    The code is working super fine friend. Have been searching for this code for ages. I am really grateful to you friend.
    I was just wondering if there is a way to include a group of torrent files from a particular location. Maybe from a server?
    Like opening the info of the first file displaying it and then the content of the second file and so on.

  39. planethax Says:

    This looks great, I am going to try and implement into my tracker.

    1 question, does this work/how would this work with a torrent with multiple trackers?

    My goal is to get a torrent that has been uploaded to my server, get the seeds/peers downloads from all trackers listed in torrent (may have 1 tracker or 10 or more) add all the seeds and display, add all the leachers and display etc.

    I am using btit source, so hope this wont be to difficult.

    Thank you

  40. planethax Says:

    sorry , to big to fit here, I will make link to a file shortly, I am not able to remove or edit prev posts
    sorry again

  41. planethax Says:

    getscrape file is here
    http://www.dslrchat.com/n3torrent/getscrape.txt

    again, sorry for prev posts.

  42. nasal Says:

    No problem at all :)

    With my script all you’d have to do is cycle through all the announces and scrape all of them in a for() function.. I will give a quick look at your function and see what you can do there!

  43. ram Says:

    I have a torrent file and i want to post it to
    my blog which can be downloaded.How i do that

  44. hayden Says:

    @ram just upload it and link it like you would an image. it really depends on your blog type.

    btw here a nice torrent scraper class:

    http://www.phpclasses.org/browse/package/3138.html

  45. LogIN Says:

    I don’t really get it, how is that seeds and leeche information is written in torrent file?
    Isn’t that info that should only tracker know about? What info is that? and is it accurate? thanks

  46. nasal Says:

    it is accurate, you don’t get the info from the torrent but from the tracker (in the code you can notice we connect to the scrape and get the information from there :)

  47. LogIN Says:

    Damn mate i didn’t saw it it was in from my eyes whole day…

    You made my day happy :D
    i’ll be back :)

  48. John Adams Says:

    Hey nasal,

    First of all, thanks a million for this wonderful tutorial. As a follow up question, can you also tell me how to obtain the list of peers participating in the swarm and the method for initiating a BT Handshake?

    Thanks,
    John

  49. nasal Says:

    Hey, thanks for the nice comment!

    I’m sorry but I cannot help you in this. I never tried to do this and honestly I didn’t develop anything related to torrents in a while.. Maybe you could try and download an opensource tracker and check it’s code.

    Have a great day!

  50. John Adams Says:

    Hi nasal,

    That’s completely fine. But in any case, thanks for this wonderful tutorial :)

    Have a nice day,
    John

  51. bharath Says:

    Functions file not opening please send me the link………………

  52. bharath Says:

    Seeds peers and downloads information are not getting displayed ??

  53. Roland Says:

    Hi nasal. I have a problem. The script works just fine until I’m trying to scrape a torrent larger than 2 GigaBytes.

    Can you help me please to figure out the reason this problem appears?

  54. bqobd Says:

    How to get seed/leech info.. realy want this to work!.. cant get that info from a tpb torrent :/

  55. nasal Says:

    @Roland: sorry for the late reply but i’m a bit busy lately, i’ll give a look at the situation but i’m really busy atm, so i can’t promise you i’ll do it soon!

    @bqobd: it depends on the tracker they are uploaded to, some of them don’t allow scraping!

RSS feed for comments on this post. TrackBack URL

Leave a comment