* $b = new Bitcollider(); * * # Normally bitcollider doesn't calculate md5 * $b->set_calculate_md5(true); * $b->analyze_file('/path/to/my/test.txt'); * echo($b->get_sha1()); * echo($b->get_md5()); * * # There are many format-specific getters. Because * # we're looking at a text file, the following will * # print nothing: * echo($b->getmp3bitrate()); * * # These utility functions generate MAGNET links * # * # http://magnet-uri.sourceforge.net/ * # * echo($b->getmagnetlink()); * * # A magnet link can optionally include a direct * # download file URL in addition to file hashes * echo($b->getmagnetlink('http://example.com/test.txt)); * */ class Bitcollider { var $BITCOLLIDER = '/usr/local/bin/bitcollider'; function set_program_location($bitcollider_full_path) { $this->BITCOLLIDER = $bitcollider_full_path; } var $file_metadata; var $calculate_md5 = false; function set_calculate_md5($boolean) { $this->calculate_md5 = $boolean; } var $calculate_crc32 = false; function set_calculate_crc32($boolean) { $this->calculate_crc32 = $boolean; } /** * Invokes the bitcollider program. * @return bool false if the program exists with a nonzero error code. */ function analyze_file($filename) { $filename = escapeshellarg($filename); $cmd = "$this->BITCOLLIDER -p"; if ($this->calculate_md5) { $cmd .= " --md5"; } if ($this->calculate_crc32) { $cmd .= " --crc32"; } $cmd .= " $filename"; exec($cmd, $out, $return_code); if ($return_code != 0) { return false; } $this->file_metadata = array(); foreach($out as $line) { if (preg_match('/^(\S+?)=(.*)$/',$line,$matches)) { $key = $matches[1]; $value = $matches[2]; $this->file_metadata[$key] = $value; } } return true; } function get_magnetlink($file_url='') { return magnetlink($this->get_sha1(), $this->get_filename(), $file_url, $this->get_treetiger(), $this->get_kzhash()); } function get_sha1() { $a = $this->get_sha1_treetiger(); return $a[0]; } function get_treetiger() { $a = $this->get_sha1_treetiger(); return $a[1]; } function get_bitprint() { return $this->file_metadata['bitprint']; } function get_md5() { return $this->file_metadata['tag.md5.md5']; } function get_ed2k() { return $this->file_metadata['tag.ed2k.ed2khash']; } function get_kzhash() { return $this->file_metadata['tag.kzhash.kzhash']; } function get_crc32() { return $this->file_metadata['tag.crc32.crc32']; } function get_filename() { return $this->file_metadata['tag.filename.filename']; } function get_filelength() { return $this->file_metadata['tag.file.length']; } function get_first20bytes() { return $this->file_metadata['tag.file.first20']; } function get_audiotracktitle() { return $this->file_metadata['tag.audiotrack.title']; } function get_audiotrackartist() { return $this->file_metadata['tag.audiotrack.artist']; } function get_audiotrackalbum() { return $this->file_metadata['tag.audiotrack.album']; } function get_audiotracknumber() { return $this->file_metadata['tag.audiotrack.tracknumber']; } function get_audiotrackyear() { return $this->file_metadata['tag.audiotrack.year']; } function get_vorbisbitrate() { return $this->file_metadata['tag.vorbis.bitrate']; } function get_vorbisduration() { return $this->file_metadata['tag.vorbis.duration']; } function get_vorbissamplerate() { return $this->file_metadata['tag.vorbis.samplerate']; } function get_vorbischannels() { return $this->file_metadata['tag.vorbis.channels']; } function get_vorbisencoder() { return $this->file_metadata['tag.vorbis.encoder']; } function get_vorbisaudiosha1() { return $this->file_metadata['tag.vorbis.audio_sha1']; } function get_mp3bitrate() { return $this->file_metadata['tag.mp3.bitrate']; } function get_mp3vbr() { return $this->file_metadata['tag.mp3.vbr']; } function get_mp3duration() { return $this->file_metadata['tag.mp3.duration']; } function get_mp3stereo() { return $this->file_metadata['tag.mp3.stereo']; } function get_mp3encoder() { return $this->file_metadata['tag.mp3.encoder']; } function get_mp3audiosha1() { return $this->file_metadata['tag.mp3.audio_sha1']; } function get_imageformat() { return $this->file_metadata['tag.image.format']; } function get_imagewidth() { return $this->file_metadata['tag.image.width']; } function get_imageheight() { return $this->file_metadata['tag.image.height']; } function get_imagebpp() { return $this->file_metadata['tag.image.bpp']; } function get_id3genre() { return $this->file_metadata['tag.id3genre.genre']; } function get_wavsamplesize() { return $this->file_metadata['tag.wav.samplesize']; } function get_wavduration() { return $this->file_metadata['tag.wav.duration']; } function get_wavsamplerate() { return $this->file_metadata['tag.wav.samplerate']; } function get_wavchannels() { return $this->file_metadata['tag.wav.channels']; } function get_wavaudiosha1() { return $this->file_metadata['tag.wav.audio_sha1']; } function get_videoformat() { return $this->file_metadata['tag.video.format']; } function get_videowidth() { return $this->file_metadata['tag.video.width']; } function get_videoheight() { return $this->file_metadata['tag.video.height']; } function get_videofps() { return $this->file_metadata['tag.video.fps']; } function get_videoduration() { return $this->file_metadata['tag.video.duration']; } function get_videobitrate() { return $this->file_metadata['tag.video.bitrate']; } function get_videocodec() { return $this->file_metadata['tag.video.codec']; } function get_sha1_treetiger() { if (preg_match('/([A-Za-z2-7]{32})\.([A-Za-z2-7]{39})/',$this->get_bitprint(),$matches)) { return array($matches[1],$matches[2]); } return array('',''); } } /** * Create {@link http://magnet-uri.sourceforge.net MAGNET link}. * * Standalone function, useful if you already know file hashes. * If using a Bitcollider object call $b->magnet_link() instead. * * Any parameter may be an empty string, in which case it will * be ignored. Typically $sha1 and $filename are always used. * * @param string $sha1 Base32-encoded full file SHA1 hash * @param string $filename * @param string $fileurl Direct link for file, typically http * @param string $treetiger Base32-encoded tiger tree hash * @param string $kzhash Hex-encoded kazaa hash * * @return string A {@link http://magnet-uri.sourceforge.net MAGNET link} */ function magnetlink($sha1, $filename, $fileurl, $treetiger, $kzhash) { $m = ""; if ($sha1 && $treetiger) { $m .= "xt=urn:bitprint:$sha1.$treetiger"; } else { if ($sha1) { $m .= "xt=urn:sha1:$sha1"; } else if ($treetiger) { $m .= "xt=urn:tree:tiger:$treetiger"; } } if ($kzhash) { if ($m) { $m .= "&"; } $m .= "xt=urn:kzhash:$kzhash"; } if ($filename) { if ($m) { $m .= "&"; } $filename = urlencode($filename); $m .= "dn=$filename"; } if ($fileurl) { if ($m) { $m .= "&"; } $fileurl = urlencode($fileurl); $m .= "xs=$fileurl"; } return "magnet:?$m"; } /** * Convert hex (base16) encoding to * {@link http://www.faqs.org/rfcs/rfc3548.html Base32} encoding. * * Probably horribly inefficient. Quick hack to work around initial * failure to get solution using pack() to work and length limitations * of base_convert(). * * Example use: obtain base32 encoded full-file SHA1 hash. * * $sha1_32 = hex_to_base32(sha1_file($filename)); * * * If you're using the Bitcollider object you do not need to use this * function. * * @param string $hex Hex (Base16) encoded string * * @return string Base32 encoded string */ function hex_to_base32($hex) { $b32_alpha_to_rfc3548_chars = array( '0' => 'A', '1' => 'B', '2' => 'C', '3' => 'D', '4' => 'E', '5' => 'F', '6' => 'G', '7' => 'H', '8' => 'I', '9' => 'J', 'a' => 'K', 'b' => 'L', 'c' => 'M', 'd' => 'N', 'e' => 'O', 'f' => 'P', 'g' => 'Q', 'h' => 'R', 'i' => 'S', 'j' => 'T', 'k' => 'U', 'l' => 'V', 'm' => 'W', 'n' => 'X', 'o' => 'Y', 'p' => 'Z', 'q' => '2', 'r' => '3', 's' => '4', 't' => '5', 'u' => '6', 'v' => '7' ); for ($pos = 0; $pos < strlen($hex); $pos += 10) { $hs = substr($hex,$pos,10); $b32_alpha_part = base_convert($hs,16,32); $expected_b32_len = strlen($hs) * 0.8; $actual_b32_len = strlen($b32_alpha_part); $b32_padding_needed = $expected_b32_len - $actual_b32_len; for ($i = $b32_padding_needed; $i > 0; $i--) { $b32_alpha_part = '0' . $b32_alpha_part; } $b32_alpha .= $b32_alpha_part; } for ($i = 0; $i < strlen($b32_alpha); $i++) { $b32_rfc3548 .= $b32_alpha_to_rfc3548_chars[$b32_alpha[$i]]; } return $b32_rfc3548; } ?>