use TorrentFile from Rhilip\Bencode

This commit is contained in:
NekoCH
2026-01-09 13:10:51 +08:00
parent 0a568c0d19
commit 4035f4084f
5 changed files with 286 additions and 337 deletions

View File

@@ -54,7 +54,7 @@
"meilisearch/meilisearch-php": "^1.0",
"orangehill/iseed": "^3.0",
"phpgangsta/googleauthenticator": "dev-master",
"rhilip/bencode": "^2.0",
"rhilip/bencode": "^2.5.0",
"rlanvin/php-ip": "^3.0",
"spatie/laravel-activitylog": "^4.10",
"stichoza/google-translate-php": "^5.2"

470
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -6615,4 +6615,9 @@ function hide_text($text) {
return '<span class="hidden-text">' . $text . '</span>';
}
function make_content_disposition(string $filename, string $disposition = 'attachment'): string {
$filenameFallback = str_replace('%', '', Str::ascii($filename));
return \Symfony\Component\HttpFoundation\HeaderUtils::makeDisposition($disposition, $filename, $filenameFallback);
}
?>

View File

@@ -1,4 +1,7 @@
<?php
use Rhilip\Bencode\TorrentFile;
require_once("../include/bittorrent.php");
dbconn();
require_once ROOT_PATH . get_langfile_path("functions.php");
@@ -89,7 +92,7 @@ if ($CURUSER['downloadpos']=="no") {
//$ssl_torrent = $trackerSchemaAndHost['ssl_torrent'];
//$base_announce_url = $trackerSchemaAndHost['base_announce_url'];
$res = sql_query("SELECT torrents.name, torrents.filename, torrents.save_as, torrents.size, torrents.owner, torrents.banned, torrents.approval_status, torrents.price, categories.mode as search_box_id FROM torrents left join categories on torrents.category = categories.id WHERE torrents.id = ".sqlesc($id)) or sqlerr(__FILE__, __LINE__);
$res = sql_query("SELECT torrents.name, torrents.filename, torrents.save_as, torrents.size, torrents.owner, torrents.banned, torrents.approval_status, torrents.price, torrents.added, categories.mode as search_box_id FROM torrents left join categories on torrents.category = categories.id WHERE torrents.id = ".sqlesc($id)) or sqlerr(__FILE__, __LINE__);
$row = mysql_fetch_assoc($res);
if (!$row) {
do_log("[TORRENT_NOT_EXISTS_IN_DATABASE] $id");
@@ -140,10 +143,13 @@ if (strlen($CURUSER['passkey']) != 32) {
$CURUSER['passkey'] = md5($CURUSER['username'].date("Y-m-d H:i:s").$CURUSER['passhash']);
sql_query("UPDATE users SET passkey=".sqlesc($CURUSER['passkey'])." WHERE id=".sqlesc($CURUSER['id']));
}
$dict = \Rhilip\Bencode\Bencode::load($fn);
$dict['announce'] = get_tracker_schema_and_host($CURUSER['tracker_url_id'], true) . "?passkey=" . $CURUSER['passkey'];
$dict['comment'] = getSchemeAndHttpHost(true) . "/details.php?id=" . $id;
do_log(sprintf("[ANNOUNCE_URL], user: %s, torrent: %s, url: %s", $CURUSER['id'] ?? '', $id, $dict['announce']));
$dict = TorrentFile::load($fn);
$dict->cleanRootFields();
$dict->setAnnounce(get_tracker_schema_and_host($CURUSER['tracker_url_id'], true) . "?passkey=" . $CURUSER['passkey']);
$dict->setComment(getSchemeAndHttpHost(true) . "/details.php?id=" . $id);
$dict->setCreatedBy($SITENAME);
$dict->setCreationDate(strtotime($row['added']));
do_log(sprintf("[ANNOUNCE_URL], user: %s, torrent: %s, url: %s", $CURUSER['id'] ?? '', $id, $dict->getAnnounce()));
/**
* does not support multi-tracker
*
@@ -197,30 +203,10 @@ header ("Content-Transfer-Encoding: binary");
*/
header("Content-Type: application/x-bittorrent");
if ( str_replace("Gecko", "", $_SERVER['HTTP_USER_AGENT']) != $_SERVER['HTTP_USER_AGENT'])
{
header ("Content-Disposition: attachment; filename=\"$torrentnameprefix.".$row["save_as"].".torrent\" ; charset=utf-8");
}
else if ( str_replace("Firefox", "", $_SERVER['HTTP_USER_AGENT']) != $_SERVER['HTTP_USER_AGENT'] )
{
header ("Content-Disposition: attachment; filename=\"$torrentnameprefix.".$row["save_as"].".torrent\" ; charset=utf-8");
}
else if ( str_replace("Opera", "", $_SERVER['HTTP_USER_AGENT']) != $_SERVER['HTTP_USER_AGENT'] )
{
header ("Content-Disposition: attachment; filename=\"$torrentnameprefix.".$row["save_as"].".torrent\" ; charset=utf-8");
}
else if ( str_replace("IE", "", $_SERVER['HTTP_USER_AGENT']) != $_SERVER['HTTP_USER_AGENT'] )
{
header ("Content-Disposition: attachment; filename=".str_replace("+", "%20", rawurlencode("$torrentnameprefix." . $row["save_as"] .".torrent")));
}
else
{
header ("Content-Disposition: attachment; filename=".str_replace("+", "%20", rawurlencode("$torrentnameprefix." . $row["save_as"] .".torrent")));
}
header("Content-Disposition: " . make_content_disposition($torrentnameprefix . $row["save_as"] . '.torrent'));
//header ("Content-Disposition: attachment; filename=".$row["filename"]."");
//ob_implicit_flush(true);
//print(benc($dict));
echo \Rhilip\Bencode\Bencode::encode($dict);
echo $dict->dumpToString();
?>

View File

@@ -1,5 +1,8 @@
<?php
//require_once("../include/benc.php");
use Rhilip\Bencode\ParseException;
use Rhilip\Bencode\TorrentFile;
require_once("../include/bittorrent.php");
ini_set("upload_max_filesize",$max_torrent_size);
@@ -83,13 +86,11 @@ $audiocodecid = intval($_POST["audiocodec_sel"][$catmod] ?? 0);
if (!is_valid_id($catid))
bark($lang_takeupload['std_category_unselected']);
if (!validfilename($fname))
bark($lang_takeupload['std_invalid_filename']);
if (!preg_match('/^(.+)\.torrent$/si', $fname, $matches))
bark($lang_takeupload['std_filename_not_torrent']);
$shortfname = $torrent = $matches[1];
if (!empty($_POST["name"]))
$torrent = unesc($_POST["name"]);
$torrent = trim(unesc($_POST["name"]));
if ($f['size'] > $max_torrent_size)
bark($lang_takeupload['std_torrent_file_too_big'].number_format($max_torrent_size).$lang_takeupload['std_remake_torrent_note']);
$tmpname = $f["tmp_name"];
@@ -108,79 +109,36 @@ if ($maxPrice > 0 && isset($_POST['price']) && $_POST['price'] > $maxPrice && $p
}
try {
$dict = \Rhilip\Bencode\Bencode::load($tmpname);
} catch (\Rhilip\Bencode\ParseErrorException $e) {
bark($lang_takeupload['std_not_bencoded_file']);
$dict = TorrentFile::load($tmpname);
$dict->unhybridizedTo();
$dict->parse();
} catch (ParseException $e) {
bark($e->getMessage());
}
function checkTorrentDict($dict, $key, $type = null)
{
global $lang_takeupload;
if (!is_array($dict)) bark($lang_takeupload['std_not_a_dictionary']);
$value = $dict[$key];
if (!isset($value)) bark($lang_takeupload['std_dictionary_is_missing_key']);
if (!is_null($type)) {
$isFunction = 'is_' . $type;
if (function_exists($isFunction) && !$isFunction($value)) {
bark($lang_takeupload['std_invalid_entry_in_dictionary']);
}
}
return $value;
}
$info = checkTorrentDict($dict, 'info');
if (isset($dict['piece layers']) || isset($info['files tree']) || (isset($info['meta version']) && $info['meta version'] == 2)) {
bark('Torrent files created with Bittorrent Protocol v2, or hybrid torrents are not supported.');
}
$plen = checkTorrentDict($info, 'piece length', 'integer'); // Only Check without use
$dname = checkTorrentDict($info, 'name', 'string');
$pieces = checkTorrentDict($info, 'pieces', 'string');
if (strlen($pieces) % 20 != 0)
bark($lang_takeupload['std_invalid_pieces']);
$filelist = array();
$totallen = $info['length'] ?? null;
if (isset($totallen)) {
$filelist[] = array($dname, $totallen);
$type = "single";
}
else {
$flist = checkTorrentDict($info, 'files', 'array');
if (!isset($flist)) bark($lang_takeupload['std_missing_length_and_files']);
if (!count($flist)) bark("no files");
$totallen = 0;
foreach ($flist as $fn) {
$ll = checkTorrentDict($fn, 'length', 'integer');
$path_key = isset($fn['path.utf-8']) ? 'path.utf-8' : 'path';
$ff = checkTorrentDict($fn, $path_key, 'list');
$totallen += $ll;
$ffa = array();
foreach ($ff as $ffe) {
if (!is_string($ffe)) bark($lang_takeupload['std_filename_errors']);
$ffa[] = $ffe;
}
if (!count($ffa)) bark($lang_takeupload['std_filename_errors']);
$ffe = implode("/", $ffa);
$filelist[] = array($ffe, $ll);
}
$type = "multi";
}
$dict['announce'] = get_protocol_prefix() . $announce_urls[0]; // change announce url to local
$dict['info']['private'] = 1;
//The following line requires uploader to re-download torrents after uploading
//even the torrent is set as private and with uploader's passkey in it.
$dict['info']['source'] = "[$BASEURL] $SITENAME";
unset ($dict['announce-list']); // remove multi-tracker capability
unset ($dict['nodes']); // remove cached peers (Bitcomet & Azareus)
$dict->cleanRootFields()
->setComment(getSchemeAndHttpHost())
->setCreationDate(time())
->setCreatedBy($SITENAME)
->setAnnounce(get_protocol_prefix() . $announce_urls[0]) // change announce url to local
->setPrivate(true)
->setSource("[$BASEURL] $SITENAME");
$infohash = pack("H*", sha1(\Rhilip\Bencode\Bencode::encode($dict['info']))); // double up on the becoding solves the occassional misgenerated infohash
$filelist = $dict->getFileList();
$dname = $dict->getName();
$type = $dict->getFileMode();
$totallen = $dict->getSize();
$pieces = $dict->getInfoField('pieces');
$piecesCount = strlen($pieces) / 20;
$maxPieceCount = 24576;
$idealPiecesCount = $totallen / (8 * 1024 ** 2);
if ($piecesCount > $maxPieceCount && $idealPiecesCount < $maxPieceCount) {
bark('Too many pieces');
}
$infohash = $dict->getInfoHashV1ForAnnounce();
$exists = \App\Models\Torrent::query()->where('info_hash', $infohash)->first(['id']);
if ($exists) {
// bark($lang_takeupload['std_torrent_existed']);
@@ -351,7 +309,7 @@ $insert = [
// 'pt_gen' => $_POST['pt_gen'] ?? '',
// 'technical_info' => $_POST['technical_info'] ?? '',
'cover' => $cover,
'pieces_hash' => sha1($info['pieces']),
'pieces_hash' => sha1($pieces),
'cache_stamp' => time(),
];
/**
@@ -412,7 +370,7 @@ $id = \Nexus\Database\NexusDB::insert('torrents', $insert);
//$id = mysql_insert_id();
$torrentFilePath = "$torrentSavePath/$id.torrent";
$saveResult = \Rhilip\Bencode\Bencode::dump($torrentFilePath, $dict);
$saveResult = $dict->dump($torrentFilePath);
if ($saveResult === false) {
sql_query("delete from torrents where id = $id limit 1");
bark("save torrent to $torrentFilePath fail.");
@@ -442,7 +400,7 @@ if (!empty($tagIdArr)) {
@sql_query("DELETE FROM files WHERE torrent = $id");
foreach ($filelist as $file) {
@sql_query("INSERT INTO files (torrent, filename, size) VALUES ($id, ".sqlesc($file[0]).",".$file[1].")");
@sql_query("INSERT INTO files (torrent, filename, size) VALUES ($id, ".sqlesc($file['path']).",".$file['size'].")");
}
$extra['torrent_id'] = $id;
\App\Models\TorrentExtra::query()->create($extra);