Anonymous 3D Imageboard http://cyberia.digital/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

58 lines
15KB

  1. <?php
  2. /**
  3. * PHP BitTorrent
  4. *
  5. * Copyright (c) 2011-2013, Christer Edvartsen <cogo@starzinger.net>
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to
  9. * deal in the Software without restriction, including without limitation the
  10. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  11. * sell copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  23. * IN THE SOFTWARE.
  24. *
  25. * @package PHPBitTorrent
  26. * @author Christer Edvartsen <cogo@starzinger.net>
  27. * @copyright Copyright (c) 2011-2013, Christer Edvartsen <cogo@starzinger.net>
  28. * @license http://www.opensource.org/licenses/mit-license MIT License
  29. * @link https://github.com/christeredvartsen/php-bittorrent
  30. * @version 1.1.0
  31. */
  32. Phar::mapPhar();
  33. $basePath = 'phar://' . __FILE__;
  34. spl_autoload_register(function($class) use ($basePath) {
  35. if (strpos($class, 'PHP\\BitTorrent\\') !== 0) {
  36. return false;
  37. }
  38. $file = $basePath . DIRECTORY_SEPARATOR . substr(str_replace('\\', DIRECTORY_SEPARATOR, $class), 4) . '.php';
  39. if (file_exists($file)) {
  40. require $file;
  41. return true;
  42. }
  43. return false;
  44. });
  45. __HALT_COMPILER(); ?>
  46. E���������������� ���BitTorrent/����¤ðP��������ÿ���������BitTorrent/EncoderInterface.phpþ���¤ðPþ���KeÝ]¶���������BitTorrent/Encoder.phpÅ��¤ðPÅ��Ú³ïê¶���������BitTorrent/Torrent.php+��¤ðP+��q¨'�¶���������BitTorrent/Decoder.phpé ��¤ðPé ��á«ð¶���������BitTorrent/DecoderInterface.php ��¤ðP ��;Q,b¶������<?php
  47. namespace PHP\BitTorrent; interface EncoderInterface { function setParam($key, $value); function encode($var); function encodeInteger($integer); function encodeString($string); function encodeList($list); function encodeDictionary($dictionary); } <?php
  48. namespace PHP\BitTorrent; use InvalidArgumentException; class Encoder implements EncoderInterface { private $params = array( 'encodeEmptyArrayAsDictionary' => false, ); public function __construct(array $params = array()) { $this->params = array_replace($this->params, $params); } public function setParam($key, $value) { $this->params[$key] = $value; return $this; } public function encode($var) { if ($this->isInt($var)) { return $this->encodeInteger($var); } else if (is_string($var)) { return $this->encodeString($var); } else if (is_array($var)) { $size = count($var); if (!$size && $this->params['encodeEmptyArrayAsDictionary']) { return $this->encodeDictionary($var); } for ($i = 0; $i < $size; $i++) { if (!isset($var[$i])) { return $this->encodeDictionary($var); } } return $this->encodeList($var); } throw new InvalidArgumentException('Variables of type ' . gettype($var) . ' can not be encoded.'); } public function encodeInteger($integer) { if ($this->isInt($integer)) { return 'i' . $integer . 'e'; } throw new InvalidArgumentException('Expected an integer.'); } public function encodeString($string) { if (!is_string($string)) { throw new InvalidArgumentException('Expected string, got: ' . gettype($string) . '.'); } return strlen($string) . ':' . $string; } public function encodeList($list) { if (!is_array($list)) { throw new InvalidArgumentException('Expected array, got: ' . gettype($list) . '.'); } $ret = 'l'; foreach ($list as $value) { $ret .= $this->encode($value); } return $ret . 'e'; } public function encodeDictionary($dictionary) { if (!is_array($dictionary)) { throw new InvalidArgumentException('Expected array, got: ' . gettype($dictionary) . '.'); } ksort($dictionary); $ret = 'd'; foreach ($dictionary as $key => $value) { $ret .= $this->encodeString((string) $key) . $this->encode($value); } return $ret . 'e'; } private function isInt($var) { return is_int($var) || (PHP_INT_SIZE === 4 && is_numeric($var) && (strpos($var, '.') === false)); } } <?php
  49. namespace PHP\BitTorrent; use RecursiveDirectoryIterator, RecursiveIteratorIterator, RuntimeException, InvalidArgumentException; class Torrent { private $pieceLengthExp = 18; private $announce; private $announceList; private $comment; private $createdBy = 'PHP BitTorrent'; private $createdAt; private $info; private $extraMeta; public function __construct($announceUrl = null) { if ($announceUrl !== null) { $this->setAnnounce($announceUrl); } } static public function createFromTorrentFile($path, DecoderInterface $decoder = null) { if (!is_file($path)) { throw new InvalidArgumentException($path . ' does not exist.'); } if ($decoder === null) { $decoder = new Decoder(); } $decodedFile = $decoder->decodeFile($path); $torrent = new static(); if (isset($decodedFile['announce'])) { $torrent->setAnnounce($decodedFile['announce']); unset($decodedFile['announce']); } if (isset($decodedFile['announce-list'])) { $torrent->setAnnounceList($decodedFile['announce-list']); unset($decodedFile['announce-list']); } if (isset($decodedFile['comment'])) { $torrent->setComment($decodedFile['comment']); unset($decodedFile['comment']); } if (isset($decodedFile['created by'])) { $torrent->setCreatedBy($decodedFile['created by']); unset($decodedFile['created by']); } if (isset($decodedFile['creation date'])) { $torrent->setCreatedAt($decodedFile['creation date']); unset($decodedFile['creation date']); } if (isset($decodedFile['info'])) { $torrent->setInfo($decodedFile['info']); unset($decodedFile['info']); } if (count($decodedFile) > 0) { $torrent->setExtraMeta($decodedFile); } return $torrent; } static public function createFromPath($path, $announceUrl) { $torrent = new static($announceUrl); $files = array(); $absolutePath = realpath($path); $pathIsFile = false; if (is_file($absolutePath)) { $pathIsFile = true; $files[] = array( 'filename' => basename($absolutePath), 'filesize' => filesize($absolutePath), ); } else if (is_dir($absolutePath)) { $dir = new RecursiveDirectoryIterator($absolutePath); $iterator = new RecursiveIteratorIterator($dir); foreach ($iterator as $entry) { $filename = $entry->getFilename(); if ($filename === '.' || $filename === '..') { continue; } $files[] = array( 'filename' => str_replace($absolutePath . DIRECTORY_SEPARATOR, '', (string) $entry), 'filesize' => $entry->getSize(), ); } } else { throw new InvalidArgumentException('Invalid path: ' . $path); } $info = array( 'piece length' => pow(2, $torrent->getPieceLengthExp()) ); $pieces = array(); if ($pathIsFile) { $filePath = dirname($absolutePath); $info['name'] = $files[0]['filename']; $info['length'] = $files[0]['filesize']; $position = 0; $fp = fopen($filePath . DIRECTORY_SEPARATOR . $files[0]['filename'], 'rb'); while ($position < $info['length']) { $part = fread($fp, min($info['piece length'], $info['length'] - $position)); $pieces[] = sha1($part, true); $position += $info['piece length']; if ($position > $info['length']) { $position = $info['length']; } } fclose($fp); $pieces = implode('', $pieces); } else { $info['name'] = basename($absolutePath); usort($files, function($a, $b) { if ($a['filename'] < $b['filename']) { return -1; } else if ($a['filename'] > $b['filename']) { return 1; } return 0; }); $part = ''; $done = 0; foreach ($files as $file) { $filename = $file['filename']; $filesize = $file['filesize']; $info['files'][] = array( 'length' => $filesize, 'path' => explode(DIRECTORY_SEPARATOR, $filename) ); $position = 0; $fp = fopen($absolutePath . DIRECTORY_SEPARATOR . $filename, 'rb'); while ($position < $filesize) { $bytes = min(($filesize - $position), ($info['piece length'] - $done)); $part .= fread($fp, $bytes); $done += $bytes; $position += $bytes; if ($done === $info['piece length']) { $pieces[] = sha1($part, true); $part = ''; $done = 0; } } fclose($fp); } if ($done > 0) { $pieces[] = sha1($part, true); } $pieces = implode('', $pieces); } $info['pieces'] = $pieces; ksort($info); $torrent->setInfo($info); return $torrent; } public function setPieceLengthExp($pieceLengthExp) { $this->pieceLengthExp = (int) $pieceLengthExp; return $this; } public function getPieceLengthExp() { return $this->pieceLengthExp; } public function setAnnounce($announceUrl) { $this->announce = $announceUrl; return $this; } public function getAnnounce() { return $this->announce; } public function setAnnounceList($announceList) { $this->announceList = $announceList; return $this; } public function getAnnounceList() { return $this->announceList; } public function setComment($comment) { $this->comment = $comment; return $this; } public function getComment() { return $this->comment; } public function setCreatedBy($createdBy) { $this->createdBy = $createdBy; return $this; } public function getCreatedBy() { return $this->createdBy; } public function setCreatedAt($createdAt) { $this->createdAt = (int) $createdAt; return $this; } public function getCreatedAt() { return $this->createdAt; } public function setInfo(array $info) { $this->info = $info; return $this; } public function getInfo() { return $this->info; } public function setExtraMeta(array $extra) { $this->extraMeta = $extra; return $this; } public function getExtraMeta() { return $this->extraMeta; } public function save($filename, EncoderInterface $encoder = null) { if (!is_writable($filename) && !is_writable(dirname($filename))) { throw new InvalidArgumentException('Could not open file "' . $filename . '" for writing.'); } $announce = $this->getAnnounce(); if (empty($announce)) { throw new RuntimeException('Announce URL is missing.'); } $info = $this->getInfoPart(); if ($encoder === null) { $encoder = new Encoder(); } $createdAt = $this->getCreatedAt(); if (empty($createdAt)) { $createdAt = time(); } $torrent = array( 'announce' => $announce, 'creation date' => $createdAt, 'info' => $info, ); if (($announceList = $this->getAnnounceList()) !== null) { $torrent['announce-list'] = $announceList; } if (($comment = $this->getComment()) !== null) { $torrent['comment'] = $comment; } if (($createdBy = $this->getCreatedBy()) !== null) { $torrent['created by'] = $createdBy; } if (($extra = $this->getExtraMeta()) !== null && is_array($extra)) { foreach ($extra as $extraKey => $extraValue) { if (array_key_exists($extraKey, $torrent)) { throw new RuntimeException(sprintf('Duplicate key in extra meta info. "%s" already exists.', $extraKey)); } $torrent[$extraKey] = $extraValue; } } $dictionary = $encoder->encodeDictionary($torrent); file_put_contents($filename, $dictionary); return $this; } public function getFileList() { $info = $this->getInfoPart(); if (isset($info['length'])) { return $info['name']; } return $info['files']; } public function getSize() { $info = $this->getInfoPart(); if (isset($info['length'])) { return $info['length']; } $files = $this->getFileList(); $size = 0; foreach ($files as $file) { $size = $this->add($size, $file['length']); } return $size; } public function getName() { $info = $this->getInfoPart(); return $info['name']; } public function getHash($raw = false) { $info = $this->getInfoPart(); $encoder = new Encoder(); return sha1($encoder->encodeDictionary($info), $raw); } public function getEncodedHash() { return urlencode($this->getHash(true)); } private function getInfoPart() { $info = $this->getInfo(); if ($info === null) { throw new RuntimeException('The info part of the torrent is not set.'); } return $info; } private function add($a, $b) { if (PHP_INT_SIZE === 4) { return bcadd($a, $b); } return $a + $b; } } <?php
  50. namespace PHP\BitTorrent; use InvalidArgumentException; class Decoder implements DecoderInterface { private $encoder; public function __construct(EncoderInterface $encoder = null) { if ($encoder === null) { $encoder = new Encoder(); } $this->encoder = $encoder; } public function decodeFile($file, $strict = false) { if (!is_readable($file)) { throw new InvalidArgumentException('File ' . $file . ' does not exist or can not be read.'); } $dictionary = $this->decodeDictionary(file_get_contents($file, true)); if ($strict) { if (!isset($dictionary['announce']) || !is_string($dictionary['announce'])) { throw new InvalidArgumentException('Missing "announce" key.'); } else if (!isset($dictionary['info']) || !is_array($dictionary['info'])) { throw new InvalidArgumentException('Missing "info" key.'); } } return $dictionary; } public function decode($string) { if ($string[0] === 'i') { return $this->decodeInteger($string); } else if ($string[0] === 'l') { return $this->decodeList($string); } else if ($string[0] === 'd') { return $this->decodeDictionary($string); } else if (preg_match('/^\d+:/', $string)) { return $this->decodeString($string); } throw new InvalidArgumentException('Parameter is not correctly encoded.'); } public function decodeInteger($integer) { if ($integer[0] !== 'i' || (!$ePos = strpos($integer, 'e'))) { throw new InvalidArgumentException('Invalid integer. Integers must start wth "i" and end with "e".'); } $integer = substr($integer, 1, ($ePos - 1)); $len = strlen($integer); if (($integer[0] === '0' && $len > 1) || ($integer[0] === '-' && $integer[1] === '0') || !is_numeric($integer)) { throw new InvalidArgumentException('Invalid integer value.'); } if (PHP_INT_SIZE === 8) { return (int) $integer; } return $integer; } public function decodeString($string) { $stringParts = explode(':', $string, 2); if (count($stringParts) !== 2) { throw new InvalidArgumentException('Invalid string. Strings consist of two parts separated by ":".'); } $length = (int) $stringParts[0]; $lengthLen = strlen($length); if (($lengthLen + 1 + $length) > strlen($string)) { throw new InvalidArgumentException('The length of the string does not match the prefix of the encoded data.'); } return substr($string, ($lengthLen + 1), $length); } public function decodeList($list) { if ($list[0] !== 'l') { throw new InvalidArgumentException('Parameter is not an encoded list.'); } $ret = array(); $length = strlen($list); $i = 1; while ($i < $length) { if ($list[$i] === 'e') { break; } $part = substr($list, $i); $decodedPart = $this->decode($part); $ret[] = $decodedPart; $i += strlen($this->encoder->encode($decodedPart)); } return $ret; } public function decodeDictionary($dictionary) { if ($dictionary[0] !== 'd') { throw new InvalidArgumentException('Parameter is not an encoded dictionary.'); } $length = strlen($dictionary); $ret = array(); $i = 1; while ($i < $length) { if ($dictionary[$i] === 'e') { break; } $keyPart = substr($dictionary, $i); $key = $this->decodeString($keyPart); $keyPartLength = strlen($this->encoder->encodeString($key)); $valuePart = substr($dictionary, ($i + $keyPartLength)); $value = $this->decode($valuePart); $valuePartLength = strlen($this->encoder->encode($value)); $ret[$key] = $value; $i += ($keyPartLength + $valuePartLength); } return $ret; } } <?php
  51. namespace PHP\BitTorrent; interface DecoderInterface { function decodeFile($file, $strict = false); function decode($string); function decodeInteger($integer); function decodeString($string); function decodeList($list); function decodeDictionary($dictionary); } hlH }‹øYVKåk~c‰§÷~¥���GBMB