phpbittorrentmagnet-uri

PHP - Download the list of files (or metadata?) of a torrent from a magnet URI / URL / Link?


To be clear, I am not trying to actually download the contents of the torrent. I just want to find out what files are IN the torrent (from its magnet link) so I can make sure it doesn't contain bogus spyware or such.

I need a bit of PHP code that takes in a magnet link (ie, "magnet:?xt=urn:btih:12cb31ae6fd4624fe6be48.....")

And what I'm looking to do is get back the list of files (or all the metadata) that are in that torrent. But I can't even get as far as downloading the contents of the torrent file from the magnet link.

I have code that converts a full magnet URI into something like this:

Array
(
    [xt] => urn:btih:12cb31ae6fd4624fe6be485c...
    [dn] => Son.of.a.Critch.S0...
    [tr] => Array
        (
            [0] => udp://example.com:80/announce
            [1] => udp://example2.com:6969/announce
            [2] => udp://example3.com.is:6969/announce                
        )

)

But from here, how do I actually retrieve the torrent's file list and/or metadata?


EDIT: It was suggested this q/a might help: How to pull the torrent file from DHT? but that does not address what I am asking in this question, nor does it take into account PHP in any way. The accepted answer is just "you'll need to implement all the technical details." I am hoping to find out exactly HOW to do that, preferably in PHP, and preferably with something which has already been written.


Solution

  • This is the OP. I did eventually figure out a work-around that does what I need. I have to run an executable on the server and capture the output in PHP, and parse the text.

    My steps are outlined below for anyone who might find this useful:

    I'm running on a Linux server (ubuntu 24 at the moment) and simply downloaded the pre-compiled linux binary for rqbit: https://github.com/ikatson/rqbit (see the releases). I used version 8.0.0 for amd64. and placed in /usr/bin. You'll need to set appropriate permissions to make sure it can be called from a PHP script.

    Your PHP script would make a call that looks something like this:

    $magnet_uri = 'magnet:?xt=urn:btih:7AAD10A9....blah..blah.../announce';
    $cmd = "timeout 7 rqbit download --list -o /tmp '$magnet_uri' ";
    
    $contents = '';
    $p = proc_open(@$cmd, array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $io);
    
    // Read output sent to stdout.
    while (!feof($io[1])) {
      $contents .= fgets($io[1]);
     }
    // Read output sent to stderr.
    while (!feof($io[2])) {
      $contents .= fgets($io[2])
    }
    
    fclose($io[1]);
    fclose($io[2]);
    proc_close($p);
    
    // $contents now contains the output. 
    // echo to the screen to check for permission errors, and use fancy regex 
    // to get the file list and other metadata about the torrent.
    

    Let me walk through what's happening in $cmd:

    1. We assume that $magnet_uri contains the full magnet link for the torrent.

    2. The program rqbit sometimes won't actually end, especially if there's goofy stuff going on with the servers, so I start the command with timeout 7 meaning after 7 seconds, Linux will send a command to kill the process, if it is still going on. I find that if it hasn't loaded within 5 seconds, it's probably a low-quality or even bogus torrent.

    3. We give rqbit the command download followed by --list. Because of this nothing actually gets downloaded. Instead, it just outputs the torrent information, including the file list, to the screen.

    4. If we are specifying the download command, we still have to tell it an "output" folder, even though we aren't actually downloading anything. -o /tmp does that. Don't worry, nothing gets downloaded.

    5. Finally, we specify the full magnet uri within single quotes.

    6. The rest of the code (proc_open until proc_close) is just about running the program and capturing the output the the $contents variable, which you can then manipulate with preg_match_all to get the files and other metadata you might want.

    I hope this helps out others out there!