mirror of
https://gitee.com/ledc/IYUUAutoReseed
synced 2025-05-19 07:55:21 +00:00
移除、添加文件
This commit is contained in:
parent
87d9f81bad
commit
e61b47f3e8
@ -13,7 +13,7 @@ use IYUU\Library\Table;
|
||||
class AutoReseed
|
||||
{
|
||||
// 版本号
|
||||
const VER = '1.10.19';
|
||||
const VER = '1.10.21';
|
||||
// RPC连接
|
||||
private static $links = [];
|
||||
// 客户端配置
|
||||
@ -298,7 +298,7 @@ class AutoReseed
|
||||
continue;
|
||||
}
|
||||
echo "正在从下载器 clients_".$k." 获取种子哈希……".PHP_EOL;
|
||||
$hashArray = self::$links[$k]['rpc']->getList();
|
||||
$hashArray = self::$links[$k]['rpc']->all();
|
||||
if (empty($hashArray)) {
|
||||
continue;
|
||||
}
|
||||
@ -618,7 +618,7 @@ class AutoReseed
|
||||
}
|
||||
echo "正在从下载器 clients_".$k." 获取种子哈希……".PHP_EOL;
|
||||
$move = []; // 客户端做种列表 传址
|
||||
$hashArray = self::$links[$k]['rpc']->getList($move);
|
||||
$hashArray = self::$links[$k]['rpc']->all($move);
|
||||
if (empty($hashArray)) {
|
||||
// 失败
|
||||
continue;
|
||||
|
@ -1,66 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: David <367013672@qq.com>
|
||||
* Date: 2020-2-14
|
||||
* Time: 21:31:49
|
||||
*/
|
||||
|
||||
namespace IYUU\Client;
|
||||
|
||||
abstract class AbstractClient
|
||||
{
|
||||
/**
|
||||
* 公共方法:创建客户端实例
|
||||
*/
|
||||
public static function create($config = array())
|
||||
{
|
||||
$type = $config['type'];
|
||||
$host = $config['host'];
|
||||
$username = $config['username'];
|
||||
$password = $config['password'];
|
||||
$file = __DIR__ . DIRECTORY_SEPARATOR . $type . DIRECTORY_SEPARATOR . $type .'.php';
|
||||
if (!is_file($file)) {
|
||||
die($file.' 文件不存在');
|
||||
}
|
||||
$className = "\IYUU\Client\\" . $type . "\\" . $type;
|
||||
if (class_exists($className)) {
|
||||
echo $type." 客户端正在实例化!".PHP_EOL;
|
||||
return new $className($host, $username, $password);
|
||||
} else {
|
||||
die($className.' 客户端不存在');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询Bittorrent客户端状态
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function status();
|
||||
|
||||
/**
|
||||
* 获取种子列表
|
||||
* @return array(
|
||||
'hash' => string json,
|
||||
'sha1' => string,
|
||||
'hashString '=> array
|
||||
)
|
||||
*/
|
||||
abstract public function getList(&$move = array());
|
||||
|
||||
/**
|
||||
* 添加种子连接
|
||||
*/
|
||||
abstract public function add($torrent_url, $save_path = '', $extra_options = array());
|
||||
|
||||
/**
|
||||
* 添加种子原数据
|
||||
*/
|
||||
abstract public function add_metainfo($torrent_url, $save_path = '', $extra_options = array());
|
||||
|
||||
/**
|
||||
* 删除种子
|
||||
*/
|
||||
abstract public function delete($hash, $deleteFiles = false);
|
||||
}
|
@ -1,351 +0,0 @@
|
||||
<?php
|
||||
namespace IYUU\Client\qBittorrent;
|
||||
|
||||
use Curl\Curl;
|
||||
use IYUU\Client\AbstractClient;
|
||||
|
||||
/**
|
||||
* https://github.com/qbittorrent/qBittorrent/wiki/Web-API-Documentation
|
||||
*/
|
||||
class qBittorrent extends AbstractClient
|
||||
{
|
||||
private $debug;
|
||||
private $url;
|
||||
private $api_version;
|
||||
private $curl;
|
||||
protected $delimiter;
|
||||
private $endpoints = [
|
||||
'login' => [
|
||||
'1' => '/login',
|
||||
'2' => '/api/v2/auth/login'
|
||||
],
|
||||
'app_version' => [
|
||||
'1' => '/version/qbittorrent',
|
||||
'2' => '/api/v2/app/version'
|
||||
],
|
||||
'api_version' => [
|
||||
'1' => '/version/api',
|
||||
'2' => '/api/v2/app/webapiVersion'
|
||||
],
|
||||
'build_info' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/app/buildInfo'
|
||||
],
|
||||
'preferences' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/app/preferences'
|
||||
],
|
||||
'setPreferences' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/app/setPreferences'
|
||||
],
|
||||
'defaultSavePath' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/app/defaultSavePath'
|
||||
],
|
||||
'torrent_list' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/info'
|
||||
],
|
||||
'torrent_add' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/add'
|
||||
],
|
||||
'torrent_delete' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/delete'
|
||||
],
|
||||
'torrent_pause' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/pause'
|
||||
],
|
||||
'torrent_resume' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/resume'
|
||||
],
|
||||
'set_torrent_location' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/setLocation'
|
||||
],
|
||||
'maindata' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/sync/maindata'
|
||||
]
|
||||
];
|
||||
|
||||
public function __construct($url='', $username='', $password='', $api_version = 2, $debug = false)
|
||||
{
|
||||
$this->debug = $debug;
|
||||
$this->url = rtrim($url, '/');
|
||||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
$this->api_version = $api_version;
|
||||
$this->curl = new Curl();
|
||||
$this->curl->setOpt(CURLOPT_SSL_VERIFYPEER, false); // 禁止验证证书
|
||||
$this->curl->setOpt(CURLOPT_SSL_VERIFYHOST, 2); // 不检查证书
|
||||
$this->curl->setOpt(CURLOPT_CONNECTTIMEOUT, 60); // 超时
|
||||
$this->curl->setOpt(CURLOPT_TIMEOUT, 600); // 超时
|
||||
// Authenticate and get cookie, else throw exception
|
||||
if (!$this->authenticate()) {
|
||||
throw new \Exception("qBittorrent Unable to authenticate with Web Api.");
|
||||
}
|
||||
}
|
||||
|
||||
public function appVersion()
|
||||
{
|
||||
return $this->getData('app_version');
|
||||
}
|
||||
|
||||
public function apiVersion()
|
||||
{
|
||||
return $this->getData('api_version');
|
||||
}
|
||||
|
||||
public function buildInfo()
|
||||
{
|
||||
return $this->getData('build_info');
|
||||
}
|
||||
|
||||
public function preferences($data = null)
|
||||
{
|
||||
if (!empty($data)) {
|
||||
return $this->postData('setPreferences', ['json' => json_encode($data)]);
|
||||
}
|
||||
|
||||
return $this->getData('preferences');
|
||||
}
|
||||
|
||||
public function torrentList()
|
||||
{
|
||||
return $this->getData('torrent_list');
|
||||
}
|
||||
/**
|
||||
* @param array $extra_options
|
||||
array(
|
||||
'urls' => '',
|
||||
'savepath' => '',
|
||||
'cookie' => '',
|
||||
'category' => '',
|
||||
'skip_checking' => true,
|
||||
'paused' => true,
|
||||
'root_folder' => true,
|
||||
)
|
||||
* @return array
|
||||
*/
|
||||
public function add($torrent_url, $save_path = '', $extra_options = array())
|
||||
{
|
||||
if (!empty($save_path)) {
|
||||
$extra_options['savepath'] = $save_path;
|
||||
}
|
||||
$extra_options['urls'] = $torrent_url;
|
||||
#$extra_options['skip_checking'] = 'true'; //跳校验
|
||||
// 关键 上传文件流 multipart/form-data【严格按照api文档编写】
|
||||
$post_data = $this->buildUrls($extra_options);
|
||||
#p($post_data);
|
||||
// 设置请求头
|
||||
$this->curl->setHeader('Content-Type', 'multipart/form-data; boundary='.$this->delimiter);
|
||||
$this->curl->setHeader('Content-Length', strlen($post_data));
|
||||
return $this->postData('torrent_add', $post_data);
|
||||
}
|
||||
|
||||
public function add_metainfo($torrent_metainfo, $save_path = '', $extra_options = array())
|
||||
{
|
||||
if (!empty($save_path)) {
|
||||
$extra_options['savepath'] = $save_path;
|
||||
}
|
||||
$extra_options['torrents'] = $torrent_metainfo;
|
||||
#$extra_options['skip_checking'] = 'true'; //跳校验
|
||||
// 关键 上传文件流 multipart/form-data【严格按照api文档编写】
|
||||
$post_data = $this->buildData($extra_options);
|
||||
// 设置请求头
|
||||
$this->curl->setHeader('Content-Type', 'multipart/form-data; boundary='.$this->delimiter);
|
||||
$this->curl->setHeader('Content-Length', strlen($post_data));
|
||||
return $this->postData('torrent_add', $post_data);
|
||||
}
|
||||
|
||||
public function torrentDeleteAll($deleteFiles = false)
|
||||
{
|
||||
$torrents = json_decode($this->torrentList());
|
||||
$response = '';
|
||||
foreach ($torrents as $torrent) {
|
||||
$response .= $this->delete($torrent->hash, $deleteFiles);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function torrentPause($hash)
|
||||
{
|
||||
return $this->postData('torrent_pause', ['hashes' => $hash]);
|
||||
}
|
||||
|
||||
public function torrentResume($hash)
|
||||
{
|
||||
return $this->postData('torrent_resume', ['hashes' => $hash]);
|
||||
}
|
||||
|
||||
public function setTorrentLocation($hash, $location)
|
||||
{
|
||||
return $this->postData('set_torrent_location', ['hashes' => $hash, 'location' => $location]);
|
||||
}
|
||||
|
||||
private function getData($endpoint)
|
||||
{
|
||||
$this->curl->get($this->url . $this->endpoints[$endpoint][$this->api_version]);
|
||||
|
||||
if ($this->debug) {
|
||||
var_dump($this->curl->request_headers);
|
||||
var_dump($this->curl->response_headers);
|
||||
}
|
||||
|
||||
if ($this->curl->error) {
|
||||
return $this->errorMessage();
|
||||
}
|
||||
|
||||
return $this->curl->response;
|
||||
}
|
||||
|
||||
private function postData($endpoint, $data)
|
||||
{
|
||||
$this->curl->post($this->url . $this->endpoints[$endpoint][$this->api_version], $data);
|
||||
|
||||
if ($this->debug) {
|
||||
var_dump($this->curl->request_headers);
|
||||
var_dump($this->curl->response_headers);
|
||||
}
|
||||
|
||||
if ($this->curl->error) {
|
||||
return $this->errorMessage();
|
||||
}
|
||||
|
||||
return $this->curl->response;
|
||||
}
|
||||
|
||||
private function authenticate()
|
||||
{
|
||||
$this->curl->post($this->url . $this->endpoints['login'][$this->api_version], [
|
||||
'username' => $this->username,
|
||||
'password' => $this->password
|
||||
]);
|
||||
|
||||
if ($this->debug) {
|
||||
var_dump($this->curl->request_headers);
|
||||
var_dump($this->curl->response_headers);
|
||||
}
|
||||
|
||||
// Find authentication cookie and set in curl connection
|
||||
foreach ($this->curl->response_headers as $header) {
|
||||
if (preg_match('/SID=(\S[^;]+)/', $header, $matches)) {
|
||||
$qb415 = '; QB_'.$matches[0]; // 兼容qBittorrent v4.1.5[小钢炮等]
|
||||
$this->curl->setHeader('Cookie', $matches[0].$qb415);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function errorMessage()
|
||||
{
|
||||
return 'Curl Error Code: ' . $this->curl->error_code . ' (' . $this->curl->response . ')';
|
||||
}
|
||||
/**
|
||||
* 拼接种子urls multipart/form-data
|
||||
* https://github.com/qbittorrent/qBittorrent/wiki/Web-API-Documentation#add-new-torrent
|
||||
*/
|
||||
private function buildUrls($param)
|
||||
{
|
||||
$this->delimiter = uniqid();
|
||||
$eol = "\r\n";
|
||||
$data = '';
|
||||
// 拼接文件流
|
||||
foreach ($param as $name => $content) {
|
||||
$data .= "--" . $this->delimiter . $eol;
|
||||
$data .= 'Content-Disposition: form-data; name="' .$name. '"' . $eol . $eol;
|
||||
$data .= $content . $eol;
|
||||
}
|
||||
$data .= "--" . $this->delimiter . "--" . $eol;
|
||||
return $data;
|
||||
}
|
||||
/**
|
||||
* 拼接种子上传文件流 multipart/form-data
|
||||
* https://github.com/qbittorrent/qBittorrent/wiki/Web-API-Documentation#add-new-torrent
|
||||
*/
|
||||
private function buildData($param)
|
||||
{
|
||||
$this->delimiter = uniqid();
|
||||
$eol = "\r\n";
|
||||
$data = '';
|
||||
// 拼接文件流
|
||||
$data .= "--" . $this->delimiter . $eol;
|
||||
$data .= 'Content-Disposition: form-data; name="' .$param['name']. '"; filename="'.$param['filename'].'"' . $eol;
|
||||
$data .= 'Content-Type: application/x-bittorrent' . $eol . $eol;
|
||||
$data .= $param['torrents'] . $eol;
|
||||
unset($param['name']);
|
||||
unset($param['filename']);
|
||||
unset($param['torrents']);
|
||||
if (!empty($param)) {
|
||||
foreach ($param as $name => $content) {
|
||||
$data .= "--" . $this->delimiter . $eol;
|
||||
$data .= 'Content-Disposition: form-data; name="' . $name . '"' . $eol . $eol;
|
||||
$data .= $content . $eol;
|
||||
}
|
||||
}
|
||||
$data .= "--" . $this->delimiter . "--" . $eol;
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 抽象方法,子类实现
|
||||
*/
|
||||
public function status()
|
||||
{
|
||||
return $this->appVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* 抽象方法,子类实现
|
||||
*/
|
||||
public function getList(&$move = array())
|
||||
{
|
||||
$result = $this->getData('torrent_list');
|
||||
$res = json_decode($result, true);
|
||||
if (empty($res)) {
|
||||
echo "获取种子列表失败,可能qBittorrent暂时无响应,请稍后重试!".PHP_EOL;
|
||||
return array();
|
||||
}
|
||||
// 过滤,只保留正常做种
|
||||
$res = array_filter($res, function ($v) {
|
||||
if (isset($v['state']) && in_array($v['state'], array('uploading','stalledUP','pausedUP','queuedUP','checkingUP','forcedUP'))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, ARRAY_FILTER_USE_BOTH);
|
||||
|
||||
if (empty($res)) {
|
||||
echo "未获取到正常做种数据,请多保种,然后重试!".PHP_EOL;
|
||||
return array();
|
||||
}
|
||||
// 提取数组:hashString
|
||||
$info_hash = array_column($res, 'hash');
|
||||
// 升序排序
|
||||
sort($info_hash);
|
||||
$json = json_encode($info_hash, JSON_UNESCAPED_UNICODE);
|
||||
// 去重 应该从文件读入,防止重复提交
|
||||
$sha1 = sha1($json);
|
||||
// 组装返回数据
|
||||
$hashArray['hash'] = $json;
|
||||
$hashArray['sha1'] = $sha1;
|
||||
// 变换数组:hashString为键
|
||||
$hashArray['hashString'] = array_column($res, "save_path", 'hash');
|
||||
return $hashArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* 抽象方法,子类实现
|
||||
*/
|
||||
public function delete($hash='', $deleteFiles = false)
|
||||
{
|
||||
return $this->postData('torrent_delete', ['hashes' => $hash, 'deleteFiles' => $deleteFiles ? 'true':'false']);
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Rhilip
|
||||
* Date: 1/17/2020
|
||||
* Time: 2020
|
||||
*/
|
||||
|
||||
namespace IYUU\Client\transmission;
|
||||
|
||||
/**
|
||||
* This is the type of exception the TransmissionRPC class will throw
|
||||
*/
|
||||
class TransmissionRPCException extends \Exception
|
||||
{
|
||||
/**
|
||||
* Exception: Invalid arguments
|
||||
*/
|
||||
const E_INVALIDARG = -1;
|
||||
|
||||
/**
|
||||
* Exception: Invalid Session-Id
|
||||
*/
|
||||
const E_SESSIONID = -2;
|
||||
|
||||
/**
|
||||
* Exception: Error while connecting
|
||||
*/
|
||||
const E_CONNECTION = -3;
|
||||
|
||||
/**
|
||||
* Exception: Error 401 returned, unauthorized
|
||||
*/
|
||||
const E_AUTHENTICATION = -4;
|
||||
|
||||
/**
|
||||
* Exception constructor
|
||||
*/
|
||||
public function __construct($message = null, $code = 0, \Exception $previous = null)
|
||||
{
|
||||
// PHP version 5.3.0 and above support Exception linking
|
||||
if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
} else {
|
||||
parent::__construct($message, $code);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,763 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Transmission bittorrent client/daemon RPC communication class
|
||||
* Copyright (C) 2010 Johan Adriaans <johan.adriaans@gmail.com>,
|
||||
* Bryce Chidester <bryce@cobryce.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* PHP version specific information
|
||||
* version_compare() (PHP 4 >= 4.1.0, PHP 5)
|
||||
* ctype_digit() (PHP 4 >= 4.0.4, PHP 5)
|
||||
* stream_context_create (PHP 4 >= 4.3.0, PHP 5)
|
||||
* PHP Class support (PHP 5) (PHP 4 might work, untested)
|
||||
*/
|
||||
|
||||
namespace IYUU\Client\transmission;
|
||||
|
||||
use IYUU\Client\AbstractClient;
|
||||
|
||||
/**
|
||||
* A friendly little version check...
|
||||
*/
|
||||
if (version_compare(PHP_VERSION, '5.2.10', '<')) {
|
||||
die("The TransmissionRPC class requires PHP version 5.2.10 or above." . PHP_EOL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmission bittorrent client/daemon RPC communication class
|
||||
*
|
||||
* Usage example:
|
||||
* <code>
|
||||
* $rpc = new TransmissionRPC($rpc_url);
|
||||
* $result = $rpc->add_file( $url_or_path_to_torrent, $target_folder );
|
||||
* </code>
|
||||
*
|
||||
*/
|
||||
class transmission extends AbstractClient
|
||||
{
|
||||
/**
|
||||
* User agent used in all http communication
|
||||
*/
|
||||
const HTTP_UA = 'TransmissionRPC for PHP/0.3';
|
||||
|
||||
/**
|
||||
* The URL to the bittorent client you want to communicate with
|
||||
* the port (default: 9091) can be set in you Transmission preferences
|
||||
* @var string
|
||||
*/
|
||||
public $url = '';
|
||||
|
||||
/**
|
||||
* If your Transmission RPC requires authentication, supply username here
|
||||
* @var string
|
||||
*/
|
||||
public $username = '';
|
||||
|
||||
/**
|
||||
* If your Transmission RPC requires authentication, supply password here
|
||||
* @var string
|
||||
*/
|
||||
public $password = '';
|
||||
|
||||
/**
|
||||
* Print debugging information, default is off
|
||||
* @var bool
|
||||
*/
|
||||
public $debug = false;
|
||||
|
||||
/**
|
||||
* Transmission RPC version
|
||||
* @var int
|
||||
*/
|
||||
protected $rpc_version = 0;
|
||||
|
||||
/**
|
||||
* Transmission uses a session id to prevent CSRF attacks
|
||||
* @var string
|
||||
*/
|
||||
protected $session_id = '';
|
||||
|
||||
/**
|
||||
* Default values for stream context
|
||||
* @var array
|
||||
*/
|
||||
private $default_context_opts = array(
|
||||
'http' => array(
|
||||
'user_agent' => self::HTTP_UA,
|
||||
'timeout' => '60', // Don't want to be too slow
|
||||
'ignore_errors' => true, // Leave the error parsing/handling to the code
|
||||
),
|
||||
"ssl"=>array(
|
||||
"verify_peer"=>false,
|
||||
"verify_peer_name"=>false,
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Constants for torrent status
|
||||
*/
|
||||
const TR_STATUS_STOPPED = 0;
|
||||
const TR_STATUS_CHECK_WAIT = 1;
|
||||
const TR_STATUS_CHECK = 2;
|
||||
const TR_STATUS_DOWNLOAD_WAIT = 3;
|
||||
const TR_STATUS_DOWNLOAD = 4;
|
||||
const TR_STATUS_SEED_WAIT = 5;
|
||||
const TR_STATUS_SEED = 6;
|
||||
|
||||
const RPC_LT_14_TR_STATUS_CHECK_WAIT = 1;
|
||||
const RPC_LT_14_TR_STATUS_CHECK = 2;
|
||||
const RPC_LT_14_TR_STATUS_DOWNLOAD = 4;
|
||||
const RPC_LT_14_TR_STATUS_SEED = 8;
|
||||
const RPC_LT_14_TR_STATUS_STOPPED = 16;
|
||||
|
||||
/**
|
||||
* Takes the connection parameters
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
*/
|
||||
public function __construct($url = 'http://127.0.0.1:9091/transmission/rpc', $username = null, $password = null)
|
||||
{
|
||||
$this->url = rtrim($url, '/');
|
||||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start one or more torrents
|
||||
*
|
||||
* @param int|array ids A list of transmission torrent ids
|
||||
* @return mixed
|
||||
* @throws TransmissionRPCException
|
||||
*/
|
||||
public function start($ids)
|
||||
{
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
}
|
||||
$request = array("ids" => $ids);
|
||||
return $this->request("torrent-start", $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop one or more torrents
|
||||
*
|
||||
* @param int|array ids A list of transmission torrent ids
|
||||
* @return mixed
|
||||
* @throws TransmissionRPCException
|
||||
*/
|
||||
public function stop($ids)
|
||||
{
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
}
|
||||
$request = array("ids" => $ids);
|
||||
return $this->request("torrent-stop", $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reannounce one or more torrents
|
||||
*
|
||||
* @param int|array ids A list of transmission torrent ids
|
||||
* @return mixed
|
||||
* @throws TransmissionRPCException
|
||||
*/
|
||||
public function reannounce($ids)
|
||||
{
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
}
|
||||
$request = array("ids" => $ids);
|
||||
return $this->request("torrent-reannounce", $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify one or more torrents
|
||||
*
|
||||
* @param int|array ids A list of transmission torrent ids
|
||||
* @return mixed
|
||||
* @throws TransmissionRPCException
|
||||
*/
|
||||
public function verify($ids)
|
||||
{
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
}
|
||||
$request = array("ids" => $ids);
|
||||
return $this->request("torrent-verify", $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information on torrents in transmission, if the ids parameter is
|
||||
* empty all torrents will be returned. The fields array can be used to return certain
|
||||
* fields. Default fields are: "id", "name", "status", "doneDate", "haveValid", "totalSize".
|
||||
* See https://github.com/transmission/transmission/blob/2.9x/extras/rpc-spec.txt for available fields
|
||||
*
|
||||
* @param array fields An array of return fields
|
||||
* @param int|array ids A list of transmission torrent ids
|
||||
*
|
||||
* Request:
|
||||
* {
|
||||
* "arguments": {
|
||||
* "fields": [ "id", "name", "totalSize" ],
|
||||
* "ids": [ 7, 10 ]
|
||||
* },
|
||||
* "method": "torrent-get",
|
||||
* "tag": 39693
|
||||
* }
|
||||
*
|
||||
* Response:
|
||||
* {
|
||||
* "arguments": {
|
||||
* "torrents": [
|
||||
* {
|
||||
* "id": 10,
|
||||
* "name": "Fedora x86_64 DVD",
|
||||
* "totalSize": 34983493932,
|
||||
* },
|
||||
* {
|
||||
* "id": 7,
|
||||
* "name": "Ubuntu x86_64 DVD",
|
||||
* "totalSize", 9923890123,
|
||||
* }
|
||||
* ]
|
||||
* },
|
||||
* "result": "success",
|
||||
* "tag": 39693
|
||||
* }
|
||||
* @return mixed
|
||||
* @throws TransmissionRPCException
|
||||
*/
|
||||
public function get($ids = array(), $fields = array())
|
||||
{
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
} // Convert $ids to an array if only a single id was passed
|
||||
if (count($fields) == 0) {
|
||||
$fields = array("id", "name", "status", "doneDate", "haveValid", "totalSize");
|
||||
} // Defaults
|
||||
$request = array(
|
||||
"fields" => $fields,
|
||||
"ids" => $ids
|
||||
);
|
||||
return $this->request("torrent-get", $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set properties on one or more torrents, available fields are:
|
||||
* "bandwidthPriority" | number this torrent's bandwidth tr_priority_t
|
||||
* "downloadLimit" | number maximum download speed (in K/s)
|
||||
* "downloadLimited" | boolean true if "downloadLimit" is honored
|
||||
* "files-wanted" | array indices of file(s) to download
|
||||
* "files-unwanted" | array indices of file(s) to not download
|
||||
* "honorsSessionLimits" | boolean true if session upload limits are honored
|
||||
* "ids" | array torrent list, as described in 3.1
|
||||
* "location" | string new location of the torrent's content
|
||||
* "peer-limit" | number maximum number of peers
|
||||
* "priority-high" | array indices of high-priority file(s)
|
||||
* "priority-low" | array indices of low-priority file(s)
|
||||
* "priority-normal" | array indices of normal-priority file(s)
|
||||
* "seedRatioLimit" | double session seeding ratio
|
||||
* "seedRatioMode" | number which ratio to use. See tr_ratiolimit
|
||||
* "uploadLimit" | number maximum upload speed (in K/s)
|
||||
* "uploadLimited" | boolean true if "uploadLimit" is honored
|
||||
* See https://github.com/transmission/transmission/blob/2.9x/extras/rpc-spec.txt for more information
|
||||
*
|
||||
* @param array arguments An associative array of arguments to set
|
||||
* @param int|array ids A list of transmission torrent ids
|
||||
* @return mixed
|
||||
* @throws TransmissionRPCException
|
||||
*/
|
||||
public function set($ids = array(), $arguments = array())
|
||||
{
|
||||
// See https://github.com/transmission/transmission/blob/2.9x/extras/rpc-spec.txt for available fields
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
} // Convert $ids to an array if only a single id was passed
|
||||
if (!isset($arguments['ids'])) {
|
||||
$arguments['ids'] = $ids;
|
||||
} // Any $ids given in $arguments overrides the method parameter
|
||||
return $this->request("torrent-set", $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new torrent
|
||||
*
|
||||
* Available extra options:
|
||||
* key | value type & description
|
||||
* ---------------------+-------------------------------------------------
|
||||
* "download-dir" | string path to download the torrent to
|
||||
* "filename" | string filename or URL of the .torrent file
|
||||
* "metainfo" | string base64-encoded .torrent content
|
||||
* "paused" | boolean if true, don't start the torrent
|
||||
* "peer-limit" | number maximum number of peers
|
||||
* "bandwidthPriority" | number torrent's bandwidth tr_priority_t
|
||||
* "files-wanted" | array indices of file(s) to download
|
||||
* "files-unwanted" | array indices of file(s) to not download
|
||||
* "priority-high" | array indices of high-priority file(s)
|
||||
* "priority-low" | array indices of low-priority file(s)
|
||||
* "priority-normal" | array indices of normal-priority file(s)
|
||||
*
|
||||
* Either "filename" OR "metainfo" MUST be included.
|
||||
* All other arguments are optional.
|
||||
*
|
||||
* @param string $torrent_location The URL or path to the torrent file
|
||||
* @param string $save_path Folder to save torrent in
|
||||
* @param array $extra_options Optional extra torrent options
|
||||
* @return mixed
|
||||
* @throws TransmissionRPCException
|
||||
*/
|
||||
public function add_file($torrent_location, $save_path = '', $extra_options = array())
|
||||
{
|
||||
if (!empty($save_path)) {
|
||||
$extra_options['download-dir'] = $save_path;
|
||||
}
|
||||
$extra_options['filename'] = $torrent_location;
|
||||
|
||||
return $this->request("torrent-add", $extra_options);
|
||||
}
|
||||
|
||||
/* Add a new torrent using a file path or a URL (For backwards compatibility)
|
||||
* @param torrent_location The URL or path to the torrent file
|
||||
* @param save_path Folder to save torrent in
|
||||
* @param extra options Optional extra torrent options
|
||||
*/
|
||||
public function add($torrent_location, $save_path = '', $extra_options = array())
|
||||
{
|
||||
return $this->add_file($torrent_location, $save_path, $extra_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a torrent using the raw torrent data
|
||||
*
|
||||
* @param string $torrent_metainfo The raw, unencoded contents (metainfo) of a torrent
|
||||
* @param string $save_path Folder to save torrent in
|
||||
* @param array $extra_options Optional extra torrent options
|
||||
* @return mixed
|
||||
* @throws TransmissionRPCException
|
||||
*/
|
||||
public function add_metainfo($torrent_metainfo, $save_path = '', $extra_options = array())
|
||||
{
|
||||
if (!empty($save_path)) {
|
||||
$extra_options['download-dir'] = $save_path;
|
||||
}
|
||||
$extra_options['metainfo'] = base64_encode($torrent_metainfo);
|
||||
|
||||
return $this->request("torrent-add", $extra_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove torrent from transmission
|
||||
*
|
||||
* @param bool delete_local_data Also remove local data?
|
||||
* @param int|array ids A list of transmission torrent ids
|
||||
* @return mixed
|
||||
* @throws TransmissionRPCException
|
||||
*/
|
||||
public function delete($ids, $delete_local_data = false)
|
||||
{
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
} // Convert $ids to an array if only a single id was passed
|
||||
$request = array(
|
||||
"ids" => $ids,
|
||||
"delete-local-data" => $delete_local_data
|
||||
);
|
||||
return $this->request("torrent-remove", $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move local storage location
|
||||
*
|
||||
* @param int|array ids A list of transmission torrent ids
|
||||
* @param string target_location The new storage location
|
||||
* @param string move_existing_data Move existing data or scan new location for available data
|
||||
* @return mixed
|
||||
* @throws TransmissionRPCException
|
||||
*/
|
||||
public function move($ids, $target_location, $move_existing_data = true)
|
||||
{
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
} // Convert $ids to an array if only a single id was passed
|
||||
$request = array(
|
||||
"ids" => $ids,
|
||||
"location" => $target_location,
|
||||
"move" => $move_existing_data
|
||||
);
|
||||
return $this->request("torrent-set-location", $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 3.7. Renaming a Torrent's Path
|
||||
*
|
||||
* Method name: "torrent-rename-path"
|
||||
*
|
||||
* For more information on the use of this function, see the transmission.h
|
||||
* documentation of tr_torrentRenamePath(). In particular, note that if this
|
||||
* call succeeds you'll want to update the torrent's "files" and "name" field
|
||||
* with torrent-get.
|
||||
*
|
||||
* Request arguments:
|
||||
*
|
||||
* string | value type & description
|
||||
* ---------------------------------+-------------------------------------------------
|
||||
* "ids" | array the torrent torrent list, as described in 3.1
|
||||
* | (must only be 1 torrent)
|
||||
* "path" | string the path to the file or folder that will be renamed
|
||||
* "name" | string the file or folder's new name
|
||||
* Response arguments: "path", "name", and "id", holding the torrent ID integer
|
||||
*
|
||||
* @param int|array ids A 1-element list of transmission torrent ids
|
||||
* @param string path The path to the file or folder that will be renamed
|
||||
* @param string name The file or folder's new name
|
||||
* @return mixed
|
||||
* @throws TransmissionRPCException
|
||||
*/
|
||||
public function rename($ids, $path, $name)
|
||||
{
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
} // Convert $id to an array if only a single id was passed
|
||||
if (count($ids) !== 1) {
|
||||
throw new TransmissionRPCException('A single id is accepted', TransmissionRPCException::E_INVALIDARG);
|
||||
}
|
||||
|
||||
$request = array(
|
||||
"ids" => $ids,
|
||||
"path" => $path,
|
||||
"name" => $name
|
||||
);
|
||||
return $this->request("torrent-rename-path", $request);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve session statistics
|
||||
*
|
||||
* @returns array of statistics
|
||||
*/
|
||||
public function sstats()
|
||||
{
|
||||
return $this->request("session-stats", array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all session variables
|
||||
*
|
||||
* @returns array of session information
|
||||
*/
|
||||
public function sget()
|
||||
{
|
||||
return $this->request("session-get", array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set session variable(s)
|
||||
*
|
||||
* @param array of session variables to set
|
||||
* @return mixed
|
||||
* @throws TransmissionRPCException
|
||||
*/
|
||||
public function sset($arguments)
|
||||
{
|
||||
return $this->request("session-set", $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the interpretation of the torrent status
|
||||
*
|
||||
* @param int The integer "torrent status"
|
||||
* @returns string The translated meaning
|
||||
* @return string
|
||||
*/
|
||||
public function getStatusString($intstatus)
|
||||
{
|
||||
if ($this->rpc_version < 14) {
|
||||
if ($intstatus == self::RPC_LT_14_TR_STATUS_CHECK_WAIT) {
|
||||
return "Waiting to verify local files";
|
||||
}
|
||||
if ($intstatus == self::RPC_LT_14_TR_STATUS_CHECK) {
|
||||
return "Verifying local files";
|
||||
}
|
||||
if ($intstatus == self::RPC_LT_14_TR_STATUS_DOWNLOAD) {
|
||||
return "Downloading";
|
||||
}
|
||||
if ($intstatus == self::RPC_LT_14_TR_STATUS_SEED) {
|
||||
return "Seeding";
|
||||
}
|
||||
if ($intstatus == self::RPC_LT_14_TR_STATUS_STOPPED) {
|
||||
return "Stopped";
|
||||
}
|
||||
} else {
|
||||
if ($intstatus == self::TR_STATUS_CHECK_WAIT) {
|
||||
return "Waiting to verify local files";
|
||||
}
|
||||
if ($intstatus == self::TR_STATUS_CHECK) {
|
||||
return "Verifying local files";
|
||||
}
|
||||
if ($intstatus == self::TR_STATUS_DOWNLOAD) {
|
||||
return "Downloading";
|
||||
}
|
||||
if ($intstatus == self::TR_STATUS_SEED) {
|
||||
return "Seeding";
|
||||
}
|
||||
if ($intstatus == self::TR_STATUS_STOPPED) {
|
||||
return "Stopped";
|
||||
}
|
||||
if ($intstatus == self::TR_STATUS_SEED_WAIT) {
|
||||
return "Queued for seeding";
|
||||
}
|
||||
if ($intstatus == self::TR_STATUS_DOWNLOAD_WAIT) {
|
||||
return "Queued for download";
|
||||
}
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Here be dragons (Internal methods)
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Clean up the request array. Removes any empty fields from the request
|
||||
*
|
||||
* @param array array The request associative array to clean
|
||||
* @returns array The cleaned array
|
||||
* @return array|null
|
||||
*/
|
||||
protected function cleanRequestData($array)
|
||||
{
|
||||
if (!is_array($array) || count($array) == 0) {
|
||||
return null;
|
||||
} // Nothing to clean
|
||||
setlocale(LC_NUMERIC, 'en_US.utf8'); // Override the locale - if the system locale is wrong, then 12.34 will encode as 12,34 which is invalid JSON
|
||||
foreach ($array as $index => $value) {
|
||||
if (is_object($value)) {
|
||||
$array[$index] = $value->toArray();
|
||||
} // Convert objects to arrays so they can be JSON encoded
|
||||
if (is_array($value)) {
|
||||
$array[$index] = $this->cleanRequestData($value);
|
||||
} // Recursion
|
||||
if (empty($value) && $value !== 0) { // Remove empty members
|
||||
unset($array[$index]);
|
||||
continue; // Skip the rest of the tests - they may re-add the element.
|
||||
}
|
||||
if (is_numeric($value)) {
|
||||
$array[$index] = $value + 0;
|
||||
} // Force type-casting for proper JSON encoding (+0 is a cheap way to maintain int/float/etc)
|
||||
if (is_bool($value)) {
|
||||
$array[$index] = ($value ? 1 : 0);
|
||||
} // Store boolean values as 0 or 1
|
||||
if (is_string($value)) {
|
||||
$type = mb_detect_encoding($value, "auto");
|
||||
if ($type !== 'UTF-8') {
|
||||
$array[$index] = mb_convert_encoding($value, "UTF-8");
|
||||
//utf8_encode( $value ); // Make sure all data is UTF-8 encoded for Transmission
|
||||
}
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行 rpc 请求
|
||||
*
|
||||
* @param string $method 请求类型/方法, 详见 $this->allowMethods
|
||||
* @param array $arguments 附加参数, 可选
|
||||
* @return array
|
||||
* @throws TransmissionRPCException
|
||||
*/
|
||||
protected function request($method, $arguments = array())
|
||||
{
|
||||
// Check the parameters
|
||||
if (!is_scalar($method)) {
|
||||
throw new TransmissionRPCException('Method name has no scalar value', TransmissionRPCException::E_INVALIDARG);
|
||||
}
|
||||
if (!is_array($arguments)) {
|
||||
throw new TransmissionRPCException('Arguments must be given as array', TransmissionRPCException::E_INVALIDARG);
|
||||
}
|
||||
|
||||
$arguments = $this->cleanRequestData($arguments); // Sanitize input
|
||||
|
||||
// Grab the X-Transmission-Session-Id if we don't have it already
|
||||
if (!$this->session_id) {
|
||||
if (!$this->GetSessionID()) {
|
||||
throw new TransmissionRPCException('Unable to acquire X-Transmission-Session-Id', TransmissionRPCException::E_SESSIONID);
|
||||
}
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'method' => $method,
|
||||
'arguments' => $arguments
|
||||
);
|
||||
|
||||
$header = array(
|
||||
'Content-Type: application/json',
|
||||
'Authorization: Basic ' . base64_encode(sprintf("%s:%s", $this->username, $this->password)),
|
||||
'X-Transmission-Session-Id: ' . $this->session_id
|
||||
);
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $this->url);
|
||||
if (stripos($this->url, 'https://') === 0) {
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 禁止验证证书
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // 不检查证书
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
|
||||
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
||||
curl_setopt($ch, CURLOPT_USERPWD, $this->username . ':' . $this->password);
|
||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 600);
|
||||
$content = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if (!$content) {
|
||||
$content = array('result' => 'failed');
|
||||
}
|
||||
return json_decode($content, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an empty GET on the Transmission RPC to get the X-Transmission-Session-Id
|
||||
* and store it in $this->session_id
|
||||
*
|
||||
* @return string
|
||||
* @throws TransmissionRPCException
|
||||
*/
|
||||
public function GetSessionID()
|
||||
{
|
||||
if (!$this->url) {
|
||||
throw new TransmissionRPCException("Class must be initialized before GetSessionID() can be called.", TransmissionRPCException::E_INVALIDARG);
|
||||
}
|
||||
|
||||
// Setup the context
|
||||
$contextopts = $this->default_context_opts; // Start with the defaults
|
||||
|
||||
// Make sure it's blank/empty (reset)
|
||||
$this->session_id = null;
|
||||
|
||||
// Setup authentication (if provided)
|
||||
if ($this->username && $this->password) {
|
||||
$contextopts['http']['header'] = sprintf("Authorization: Basic %s\r\n", base64_encode($this->username . ':' . $this->password));
|
||||
}
|
||||
|
||||
if ($this->debug) {
|
||||
echo "TRANSMISSIONRPC_DEBUG:: GetSessionID():: Stream context created with options:" .
|
||||
PHP_EOL . print_r($contextopts, true);
|
||||
}
|
||||
|
||||
$context = stream_context_create($contextopts); // Create the context for this request
|
||||
if (!$fp = @fopen($this->url, 'r', false, $context)) { // Open a filepointer to the data, and use fgets to get the result
|
||||
throw new TransmissionRPCException('Unable to connect to ' . $this->url, TransmissionRPCException::E_CONNECTION);
|
||||
}
|
||||
|
||||
// Check the response (headers etc)
|
||||
$stream_meta = stream_get_meta_data($fp);
|
||||
fclose($fp);
|
||||
if ($this->debug) {
|
||||
echo "TRANSMISSIONRPC_DEBUG:: GetSessionID():: Stream meta info: " .
|
||||
PHP_EOL . print_r($stream_meta, true);
|
||||
}
|
||||
if ($stream_meta['timed_out']) {
|
||||
throw new TransmissionRPCException("Timed out connecting to {$this->url}", TransmissionRPCException::E_CONNECTION);
|
||||
}
|
||||
if (substr($stream_meta['wrapper_data'][0], 9, 3) == "401") {
|
||||
throw new TransmissionRPCException("Invalid username/password.", TransmissionRPCException::E_AUTHENTICATION);
|
||||
} elseif (substr($stream_meta['wrapper_data'][0], 9, 3) == "409") { // This is what we're hoping to find
|
||||
// Loop through the returned headers and extract the X-Transmission-Session-Id
|
||||
foreach ($stream_meta['wrapper_data'] as $header) {
|
||||
if (strpos($header, 'X-Transmission-Session-Id: ') === 0) {
|
||||
if ($this->debug) {
|
||||
echo "TRANSMISSIONRPC_DEBUG:: GetSessionID():: Session-Id header: " .
|
||||
PHP_EOL . print_r($header, true);
|
||||
}
|
||||
$this->session_id = trim(substr($header, 27));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$this->session_id) { // Didn't find a session_id
|
||||
throw new TransmissionRPCException("Unable to retrieve X-Transmission-Session-Id", TransmissionRPCException::E_SESSIONID);
|
||||
}
|
||||
} else {
|
||||
throw new TransmissionRPCException("Unexpected response from Transmission RPC: " . $stream_meta['wrapper_data'][0]);
|
||||
}
|
||||
return $this->session_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 抽象方法,子类实现
|
||||
*/
|
||||
public function status()
|
||||
{
|
||||
$rs = $this->sstats();
|
||||
return isset($rs['result']) ? $rs['result'] : 'error';
|
||||
}
|
||||
|
||||
/**
|
||||
* 抽象方法,子类实现
|
||||
*/
|
||||
public function getList(&$move = array())
|
||||
{
|
||||
$ids = array();
|
||||
$fields = array( "id", "status", "name", "hashString", "downloadDir", "torrentFile" );
|
||||
$res = $this->get($ids, $fields);
|
||||
if (isset($res['result']) && $res['result'] == 'success') {
|
||||
// 成功
|
||||
} else {
|
||||
// 失败
|
||||
echo "获取种子列表失败,可能transmission暂时无响应,请稍后重试!".PHP_EOL;
|
||||
return array();
|
||||
}
|
||||
if (empty($res['arguments']['torrents'])) {
|
||||
echo "未获取到正常做种数据,请多保种,然后重试!".PHP_EOL;
|
||||
return array();
|
||||
}
|
||||
$res = $res['arguments']['torrents'];
|
||||
// 过滤,只保留正常做种
|
||||
$res = array_filter($res, function ($v) {
|
||||
return isset($v['status']) && $v['status']===6;
|
||||
}, ARRAY_FILTER_USE_BOTH);
|
||||
|
||||
if (empty($res)) {
|
||||
echo "未获取到正常做种数据,请多保种,然后重试!".PHP_EOL;
|
||||
return array();
|
||||
}
|
||||
// 提取数组:hashString
|
||||
$info_hash = array_column($res, 'hashString');
|
||||
// 升序排序
|
||||
sort($info_hash);
|
||||
$json = json_encode($info_hash, JSON_UNESCAPED_UNICODE);
|
||||
// 去重 应该从文件读入,防止重复提交
|
||||
$sha1 = sha1($json);
|
||||
// 组装返回数据
|
||||
$hashArray['hash'] = $json;
|
||||
$hashArray['sha1'] = $sha1;
|
||||
// 变换数组:hashString为键
|
||||
$hashArray['hashString'] = array_column($res, "downloadDir", 'hashString');
|
||||
$move = array_column($res, null, 'hashString');
|
||||
return $hashArray;
|
||||
}
|
||||
}
|
@ -13,7 +13,8 @@
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-curl": "*",
|
||||
"curl/curl": "^2.2"
|
||||
"curl/curl": "^2.3",
|
||||
"ledccn/bittorrentclient": "dev-master"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
83
composer.lock
generated
83
composer.lock
generated
@ -1,83 +0,0 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "10281f19c929443b7db18d1ab159ec63",
|
||||
"packages": [
|
||||
{
|
||||
"name": "curl/curl",
|
||||
"version": "2.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-mod/curl.git",
|
||||
"reference": "d22086dd2eee5ca02e4c29b9a5bdf3645bfdbbff"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-mod/curl/zipball/d22086dd2eee5ca02e4c29b9a5bdf3645bfdbbff",
|
||||
"reference": "d22086dd2eee5ca02e4c29b9a5bdf3645bfdbbff",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"php": "^5.6 | ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.7",
|
||||
"squizlabs/php_codesniffer": "~2.1"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Curl": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Hassan Amouhzi",
|
||||
"email": "hassan@anezi.net",
|
||||
"homepage": "http://hassan.amouhzi.com"
|
||||
},
|
||||
{
|
||||
"name": "php-curl-class",
|
||||
"homepage": "https://github.com/php-curl-class"
|
||||
},
|
||||
{
|
||||
"name": "user52",
|
||||
"homepage": "https://github.com/user52"
|
||||
}
|
||||
],
|
||||
"description": "cURL class for PHP",
|
||||
"homepage": "https://github.com/php-mod/curl",
|
||||
"keywords": [
|
||||
"curl",
|
||||
"dot"
|
||||
],
|
||||
"time": "2018-12-04T19:47:03+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-curl": "*"
|
||||
},
|
||||
"platform-dev": []
|
||||
}
|
7
vendor/autoload.php
vendored
7
vendor/autoload.php
vendored
@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
// autoload.php @generated by Composer
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInitd8553673db02b2a444a853f28e16196e::getLoader();
|
445
vendor/composer/ClassLoader.php
vendored
445
vendor/composer/ClassLoader.php
vendored
@ -1,445 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
/**
|
||||
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||
*
|
||||
* $loader = new \Composer\Autoload\ClassLoader();
|
||||
*
|
||||
* // register classes with namespaces
|
||||
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||
* $loader->add('Symfony', __DIR__.'/framework');
|
||||
*
|
||||
* // activate the autoloader
|
||||
* $loader->register();
|
||||
*
|
||||
* // to enable searching the include path (eg. for PEAR packages)
|
||||
* $loader->setUseIncludePath(true);
|
||||
*
|
||||
* In this example, if you try to use a class in the Symfony\Component
|
||||
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||
* the autoloader will first look for the class under the component/
|
||||
* directory, and it will then fallback to the framework/ directory if not
|
||||
* found before giving up.
|
||||
*
|
||||
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @see http://www.php-fig.org/psr/psr-0/
|
||||
* @see http://www.php-fig.org/psr/psr-4/
|
||||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
// PSR-4
|
||||
private $prefixLengthsPsr4 = array();
|
||||
private $prefixDirsPsr4 = array();
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
private $prefixesPsr0 = array();
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
private $useIncludePath = false;
|
||||
private $classMap = array();
|
||||
private $classMapAuthoritative = false;
|
||||
private $missingClasses = array();
|
||||
private $apcuPrefix;
|
||||
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
return call_user_func_array('array_merge', $this->prefixesPsr0);
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $classMap Class to filename map
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
if ($this->classMap) {
|
||||
$this->classMap = array_merge($this->classMap, $classMap);
|
||||
} else {
|
||||
$this->classMap = $classMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
(array) $paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
(array) $paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
// Register directories for a new namespace.
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
(array) $paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 base directories
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr0 = (array) $paths;
|
||||
} else {
|
||||
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
if (!$prefix) {
|
||||
$this->fallbackDirsPsr4 = (array) $paths;
|
||||
} else {
|
||||
$length = strlen($prefix);
|
||||
if ('\\' !== $prefix[$length - 1]) {
|
||||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
$this->useIncludePath = $useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to check if the autoloader uses the include path to check
|
||||
* for classes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseIncludePath()
|
||||
{
|
||||
return $this->useIncludePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off searching the prefix and fallback directories for classes
|
||||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should class lookup fail if not found in the current class map?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isClassMapAuthoritative()
|
||||
{
|
||||
return $this->classMapAuthoritative;
|
||||
}
|
||||
|
||||
/**
|
||||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getApcuPrefix()
|
||||
{
|
||||
return $this->apcuPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
spl_autoload_unregister(array($this, 'loadClass'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given class or interface.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
* @return bool|null True if loaded, null otherwise
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the path to the file where the class is defined.
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return string|false The path if found, false otherwise
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
// class map lookup
|
||||
if (isset($this->classMap[$class])) {
|
||||
return $this->classMap[$class];
|
||||
}
|
||||
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||
return false;
|
||||
}
|
||||
if (null !== $this->apcuPrefix) {
|
||||
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||
if ($hit) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
$file = $this->findFileWithExtension($class, '.php');
|
||||
|
||||
// Search for Hack files if we are running on HHVM
|
||||
if (false === $file && defined('HHVM_VERSION')) {
|
||||
$file = $this->findFileWithExtension($class, '.hh');
|
||||
}
|
||||
|
||||
if (null !== $this->apcuPrefix) {
|
||||
apcu_add($this->apcuPrefix.$class, $file);
|
||||
}
|
||||
|
||||
if (false === $file) {
|
||||
// Remember that this class does not exist.
|
||||
$this->missingClasses[$class] = true;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||
|
||||
$first = $class[0];
|
||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||
$subPath = $class;
|
||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||
$subPath = substr($subPath, 0, $lastPos);
|
||||
$search = $subPath . '\\';
|
||||
if (isset($this->prefixDirsPsr4[$search])) {
|
||||
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||
if (file_exists($file = $dir . $pathEnd)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 lookup
|
||||
if (false !== $pos = strrpos($class, '\\')) {
|
||||
// namespaced class name
|
||||
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||
} else {
|
||||
// PEAR-like class name
|
||||
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||
}
|
||||
|
||||
if (isset($this->prefixesPsr0[$first])) {
|
||||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
||||
// PSR-0 include paths.
|
||||
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*/
|
||||
function includeFile($file)
|
||||
{
|
||||
include $file;
|
||||
}
|
21
vendor/composer/LICENSE
vendored
21
vendor/composer/LICENSE
vendored
@ -1,21 +0,0 @@
|
||||
|
||||
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
9
vendor/composer/autoload_classmap.php
vendored
9
vendor/composer/autoload_classmap.php
vendored
@ -1,9 +0,0 @@
|
||||
<?php
|
||||
|
||||
// autoload_classmap.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
);
|
10
vendor/composer/autoload_files.php
vendored
10
vendor/composer/autoload_files.php
vendored
@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
// autoload_files.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'45702aba72a3d88d5dd1a153f5231b73' => $baseDir . '/app/helper.php',
|
||||
);
|
10
vendor/composer/autoload_namespaces.php
vendored
10
vendor/composer/autoload_namespaces.php
vendored
@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
// autoload_namespaces.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'Curl' => array($vendorDir . '/curl/curl/src'),
|
||||
);
|
10
vendor/composer/autoload_psr4.php
vendored
10
vendor/composer/autoload_psr4.php
vendored
@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
// autoload_psr4.php @generated by Composer
|
||||
|
||||
$vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
'IYUU\\' => array($baseDir . '/app'),
|
||||
);
|
70
vendor/composer/autoload_real.php
vendored
70
vendor/composer/autoload_real.php
vendored
@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInitd8553673db02b2a444a853f28e16196e
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
public static function loadClassLoader($class)
|
||||
{
|
||||
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||
require __DIR__ . '/ClassLoader.php';
|
||||
}
|
||||
}
|
||||
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInitd8553673db02b2a444a853f28e16196e', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInitd8553673db02b2a444a853f28e16196e', 'loadClassLoader'));
|
||||
|
||||
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||
if ($useStaticLoader) {
|
||||
require_once __DIR__ . '/autoload_static.php';
|
||||
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInitd8553673db02b2a444a853f28e16196e::getInitializer($loader));
|
||||
} else {
|
||||
$map = require __DIR__ . '/autoload_namespaces.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
$loader->set($namespace, $path);
|
||||
}
|
||||
|
||||
$map = require __DIR__ . '/autoload_psr4.php';
|
||||
foreach ($map as $namespace => $path) {
|
||||
$loader->setPsr4($namespace, $path);
|
||||
}
|
||||
|
||||
$classMap = require __DIR__ . '/autoload_classmap.php';
|
||||
if ($classMap) {
|
||||
$loader->addClassMap($classMap);
|
||||
}
|
||||
}
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
if ($useStaticLoader) {
|
||||
$includeFiles = Composer\Autoload\ComposerStaticInitd8553673db02b2a444a853f28e16196e::$files;
|
||||
} else {
|
||||
$includeFiles = require __DIR__ . '/autoload_files.php';
|
||||
}
|
||||
foreach ($includeFiles as $fileIdentifier => $file) {
|
||||
composerRequired8553673db02b2a444a853f28e16196e($fileIdentifier, $file);
|
||||
}
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
|
||||
function composerRequired8553673db02b2a444a853f28e16196e($fileIdentifier, $file)
|
||||
{
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
require $file;
|
||||
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
}
|
||||
}
|
46
vendor/composer/autoload_static.php
vendored
46
vendor/composer/autoload_static.php
vendored
@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
// autoload_static.php @generated by Composer
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInitd8553673db02b2a444a853f28e16196e
|
||||
{
|
||||
public static $files = array (
|
||||
'45702aba72a3d88d5dd1a153f5231b73' => __DIR__ . '/../..' . '/app/helper.php',
|
||||
);
|
||||
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
'I' =>
|
||||
array (
|
||||
'IYUU\\' => 5,
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixDirsPsr4 = array (
|
||||
'IYUU\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/../..' . '/app',
|
||||
),
|
||||
);
|
||||
|
||||
public static $prefixesPsr0 = array (
|
||||
'C' =>
|
||||
array (
|
||||
'Curl' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/curl/curl/src',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInitd8553673db02b2a444a853f28e16196e::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInitd8553673db02b2a444a853f28e16196e::$prefixDirsPsr4;
|
||||
$loader->prefixesPsr0 = ComposerStaticInitd8553673db02b2a444a853f28e16196e::$prefixesPsr0;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
}
|
119
vendor/composer/installed.json
vendored
119
vendor/composer/installed.json
vendored
@ -1,119 +0,0 @@
|
||||
[
|
||||
{
|
||||
"name": "curl/curl",
|
||||
"version": "2.2.0",
|
||||
"version_normalized": "2.2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-mod/curl.git",
|
||||
"reference": "d22086dd2eee5ca02e4c29b9a5bdf3645bfdbbff"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-mod/curl/zipball/d22086dd2eee5ca02e4c29b9a5bdf3645bfdbbff",
|
||||
"reference": "d22086dd2eee5ca02e4c29b9a5bdf3645bfdbbff",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"php": "^5.6 | ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.7",
|
||||
"squizlabs/php_codesniffer": "~2.1"
|
||||
},
|
||||
"time": "2018-12-04T19:47:03+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Curl": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Hassan Amouhzi",
|
||||
"email": "hassan@anezi.net",
|
||||
"homepage": "http://hassan.amouhzi.com"
|
||||
},
|
||||
{
|
||||
"name": "php-curl-class",
|
||||
"homepage": "https://github.com/php-curl-class"
|
||||
},
|
||||
{
|
||||
"name": "user52",
|
||||
"homepage": "https://github.com/user52"
|
||||
}
|
||||
],
|
||||
"description": "cURL class for PHP",
|
||||
"homepage": "https://github.com/php-mod/curl",
|
||||
"keywords": [
|
||||
"curl",
|
||||
"dot"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "owner888/phpspider",
|
||||
"version": "v2.1.6",
|
||||
"version_normalized": "2.1.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/owner888/phpspider.git",
|
||||
"reference": "e6021148adec201418c16ba26f39bc013ba5b4d9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/owner888/phpspider/zipball/e6021148adec201418c16ba26f39bc013ba5b4d9",
|
||||
"reference": "e6021148adec201418c16ba26f39bc013ba5b4d9",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-pcntl、ext-redis": "For better performance. "
|
||||
},
|
||||
"time": "2018-08-15T08:04:29+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"phpspider\\": "./"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Seatle Yang",
|
||||
"email": "seatle@foxmail.com",
|
||||
"homepage": "http://www.phpspider.org",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "The PHPSpider Framework.",
|
||||
"homepage": "http://www.phpspider.org",
|
||||
"keywords": [
|
||||
"framework",
|
||||
"phpspider"
|
||||
]
|
||||
}
|
||||
]
|
11
vendor/curl/curl/.gitignore
vendored
11
vendor/curl/curl/.gitignore
vendored
@ -1,11 +0,0 @@
|
||||
vendor/*
|
||||
*.orig
|
||||
.buildpath
|
||||
.project
|
||||
.settings/*
|
||||
.idea/*
|
||||
composer.lock
|
||||
*~
|
||||
tests/phpunit_report/*
|
||||
/.settings/
|
||||
/.php_cs.cache
|
113
vendor/curl/curl/.gitlab-ci.yml
vendored
113
vendor/curl/curl/.gitlab-ci.yml
vendored
@ -1,113 +0,0 @@
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
|
||||
build-test-server:
|
||||
image: docker:latest
|
||||
stage: build
|
||||
services:
|
||||
- docker:dind
|
||||
script:
|
||||
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
|
||||
- docker build --pull -t "$CI_REGISTRY_IMAGE:server-test" tests/server
|
||||
- docker push "$CI_REGISTRY_IMAGE:server-test"
|
||||
only:
|
||||
changes:
|
||||
- tests/server
|
||||
|
||||
tests-php5.6:
|
||||
image: alpine:3.7
|
||||
stage: test
|
||||
services:
|
||||
- name: "$CI_REGISTRY_IMAGE:server-test"
|
||||
alias: server_test
|
||||
script:
|
||||
- apk add --no-cache php5-cli php5-curl php5-gd php5-phar php5-json php5-openssl php5-dom php5-xml php5-zlib
|
||||
- ln -s /usr/bin/php5 /usr/bin/php
|
||||
- php --version
|
||||
- if [ ! -f composer.phar ]; then DOWLOAD_COMPOSER=1 ; fi;
|
||||
- if [ -n "$DOWLOAD_COMPOSER" ] ; then php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" ; fi;
|
||||
- if [ -n "$DOWLOAD_COMPOSER" ] ; then php -r "if (hash_file('sha384', 'composer-setup.php') === '93b54496392c062774670ac18b134c3b3a95e5a5e5c8f1a9f115f203b75bf9a129d5daa8ba6a13e2cc8a1da0806388a8') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" ; fi;
|
||||
- if [ -n "$DOWLOAD_COMPOSER" ] ; then php composer-setup.php ; fi;
|
||||
- if [ -n "$DOWLOAD_COMPOSER" ] ; then php -r "unlink('composer-setup.php');" ; fi;
|
||||
- php composer.phar install
|
||||
- vendor/bin/phpcs --warning-severity=0 --standard=PSR2 src
|
||||
- vendor/bin/phpunit
|
||||
cache:
|
||||
key: php5.6
|
||||
paths:
|
||||
- composer.phar
|
||||
- vendor
|
||||
|
||||
tests-php7.0:
|
||||
image: alpine:3.5
|
||||
stage: test
|
||||
services:
|
||||
- name: "$CI_REGISTRY_IMAGE:server-test"
|
||||
alias: server_test
|
||||
script:
|
||||
- apk add --no-cache php7 php7-curl php7-gd php7-phar php7-json php7-openssl php7-dom php7-mbstring
|
||||
- ln -s /usr/bin/php7 /usr/bin/php
|
||||
- php --version
|
||||
- if [ ! -f composer.phar ]; then DOWLOAD_COMPOSER=1 ; fi;
|
||||
- if [ -n "$DOWLOAD_COMPOSER" ] ; then php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" ; fi;
|
||||
- if [ -n "$DOWLOAD_COMPOSER" ] ; then php -r "if (hash_file('sha384', 'composer-setup.php') === '93b54496392c062774670ac18b134c3b3a95e5a5e5c8f1a9f115f203b75bf9a129d5daa8ba6a13e2cc8a1da0806388a8') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" ; fi;
|
||||
- if [ -n "$DOWLOAD_COMPOSER" ] ; then php composer-setup.php ; fi;
|
||||
- if [ -n "$DOWLOAD_COMPOSER" ] ; then php -r "unlink('composer-setup.php');" ; fi;
|
||||
- php composer.phar install
|
||||
- vendor/bin/phpcs --warning-severity=0 --standard=PSR2 src
|
||||
- nohup php -S localhost:8000 -t tests/server/php-curl-test > phpd.log 2>&1 &
|
||||
- vendor/bin/phpunit
|
||||
cache:
|
||||
key: php7.0
|
||||
paths:
|
||||
- composer.phar
|
||||
- vendor
|
||||
|
||||
tests-php7.1:
|
||||
image: alpine:3.7
|
||||
stage: test
|
||||
services:
|
||||
- name: "$CI_REGISTRY_IMAGE:server-test"
|
||||
alias: server_test
|
||||
script:
|
||||
- apk add --no-cache php7-cli php7-curl php7-gd php7-phar php7-json php7-openssl php7-dom php7-simplexml php7-tokenizer php7-mbstring php7-xml
|
||||
- php --version
|
||||
- if [ ! -f composer.phar ]; then DOWLOAD_COMPOSER=1 ; fi;
|
||||
- if [ -n "$DOWLOAD_COMPOSER" ] ; then php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" ; fi;
|
||||
- if [ -n "$DOWLOAD_COMPOSER" ] ; then php -r "if (hash_file('sha384', 'composer-setup.php') === '93b54496392c062774670ac18b134c3b3a95e5a5e5c8f1a9f115f203b75bf9a129d5daa8ba6a13e2cc8a1da0806388a8') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" ; fi;
|
||||
- if [ -n "$DOWLOAD_COMPOSER" ] ; then php composer-setup.php ; fi;
|
||||
- if [ -n "$DOWLOAD_COMPOSER" ] ; then php -r "unlink('composer-setup.php');" ; fi;
|
||||
- php composer.phar install
|
||||
- vendor/bin/phpcs --warning-severity=0 --standard=PSR2 src
|
||||
- nohup php -S localhost:8000 -t tests/server/php-curl-test > phpd.log 2>&1 &
|
||||
- vendor/bin/phpunit
|
||||
cache:
|
||||
key: php7.1
|
||||
paths:
|
||||
- composer.phar
|
||||
- vendor
|
||||
|
||||
tests-php7.2:
|
||||
image: alpine:3.8
|
||||
stage: test
|
||||
services:
|
||||
- name: "$CI_REGISTRY_IMAGE:server-test"
|
||||
alias: server_test
|
||||
script:
|
||||
- apk add --no-cache php7-cli php7-curl php7-gd php7-phar php7-json php7-openssl php7-dom php7-simplexml php7-tokenizer php7-mbstring php7-xml
|
||||
- php --version
|
||||
- if [ ! -f composer.phar ]; then DOWLOAD_COMPOSER=1 ; fi;
|
||||
- if [ -n "$DOWLOAD_COMPOSER" ] ; then php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" ; fi;
|
||||
- if [ -n "$DOWLOAD_COMPOSER" ] ; then php -r "if (hash_file('sha384', 'composer-setup.php') === '93b54496392c062774670ac18b134c3b3a95e5a5e5c8f1a9f115f203b75bf9a129d5daa8ba6a13e2cc8a1da0806388a8') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" ; fi;
|
||||
- if [ -n "$DOWLOAD_COMPOSER" ] ; then php composer-setup.php ; fi;
|
||||
- if [ -n "$DOWLOAD_COMPOSER" ] ; then php -r "unlink('composer-setup.php');" ; fi;
|
||||
- php composer.phar install
|
||||
- vendor/bin/phpcs --warning-severity=0 --standard=PSR2 src
|
||||
- nohup php -S localhost:8000 -t tests/server/php-curl-test > phpd.log 2>&1 &
|
||||
- vendor/bin/phpunit
|
||||
cache:
|
||||
key: php7.2
|
||||
paths:
|
||||
- composer.phar
|
||||
- vendor
|
20
vendor/curl/curl/LICENSE
vendored
20
vendor/curl/curl/LICENSE
vendored
@ -1,20 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 php-mod
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
125
vendor/curl/curl/README.md
vendored
125
vendor/curl/curl/README.md
vendored
@ -1,125 +0,0 @@
|
||||
# PHP Curl Class
|
||||
|
||||
This library provides an object-oriented wrapper of the PHP cURL extension.
|
||||
|
||||
If you have questions or problems with installation or usage [create an Issue](https://github.com/php-mod/curl/issues).
|
||||
|
||||
## Installation
|
||||
|
||||
In order to install this library via composer run the following command in the console:
|
||||
|
||||
```sh
|
||||
composer require curl/curl
|
||||
```
|
||||
|
||||
or add the package manually to your composer.json file in the require section:
|
||||
|
||||
```json
|
||||
"curl/curl": "^2.0"
|
||||
```
|
||||
|
||||
## Usage examples
|
||||
|
||||
```php
|
||||
$curl = new Curl\Curl();
|
||||
$curl->get('http://www.example.com/');
|
||||
```
|
||||
|
||||
```php
|
||||
$curl = new Curl\Curl();
|
||||
$curl->get('http://www.example.com/search', array(
|
||||
'q' => 'keyword',
|
||||
));
|
||||
```
|
||||
|
||||
```php
|
||||
$curl = new Curl\Curl();
|
||||
$curl->post('http://www.example.com/login/', array(
|
||||
'username' => 'myusername',
|
||||
'password' => 'mypassword',
|
||||
));
|
||||
```
|
||||
|
||||
```php
|
||||
$curl = new Curl\Curl();
|
||||
$curl->setBasicAuthentication('username', 'password');
|
||||
$curl->setUserAgent('');
|
||||
$curl->setReferrer('');
|
||||
$curl->setHeader('X-Requested-With', 'XMLHttpRequest');
|
||||
$curl->setCookie('key', 'value');
|
||||
$curl->get('http://www.example.com/');
|
||||
|
||||
if ($curl->error) {
|
||||
echo $curl->error_code;
|
||||
}
|
||||
else {
|
||||
echo $curl->response;
|
||||
}
|
||||
|
||||
var_dump($curl->request_headers);
|
||||
var_dump($curl->response_headers);
|
||||
```
|
||||
|
||||
```php
|
||||
$curl = new Curl\Curl();
|
||||
$curl->setOpt(CURLOPT_RETURNTRANSFER, TRUE);
|
||||
$curl->setOpt(CURLOPT_SSL_VERIFYPEER, FALSE);
|
||||
$curl->get('https://encrypted.example.com/');
|
||||
```
|
||||
|
||||
```php
|
||||
$curl = new Curl\Curl();
|
||||
$curl->put('http://api.example.com/user/', array(
|
||||
'first_name' => 'Zach',
|
||||
'last_name' => 'Borboa',
|
||||
));
|
||||
```
|
||||
|
||||
```php
|
||||
$curl = new Curl\Curl();
|
||||
$curl->patch('http://api.example.com/profile/', array(
|
||||
'image' => '@path/to/file.jpg',
|
||||
));
|
||||
```
|
||||
|
||||
```php
|
||||
$curl = new Curl\Curl();
|
||||
$curl->delete('http://api.example.com/user/', array(
|
||||
'id' => '1234',
|
||||
));
|
||||
```
|
||||
|
||||
```php
|
||||
$curl->close();
|
||||
```
|
||||
|
||||
```php
|
||||
// Example access to curl object.
|
||||
curl_set_opt($curl->curl, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1');
|
||||
curl_close($curl->curl);
|
||||
```
|
||||
|
||||
```php
|
||||
// Example of downloading a file or any other content
|
||||
$curl = new Curl\Curl();
|
||||
// open the file where the request response should be written
|
||||
$file_handle = fopen($target_file, 'w+');
|
||||
// pass it to the curl resource
|
||||
$curl->setOpt(CURLOPT_FILE, $file_handle);
|
||||
// do any type of request
|
||||
$curl->get('https://github.com');
|
||||
// disable writing to file
|
||||
$curl->setOpt(CURLOPT_FILE, null);
|
||||
// close the file for writing
|
||||
fclose($file_handle);
|
||||
```
|
||||
|
||||
|
||||
## Testing
|
||||
|
||||
In order to test the library:
|
||||
|
||||
1. Create a fork
|
||||
2. Clone the fork to your machine
|
||||
3. Install the depencies `composer install`
|
||||
4. Run the unit tests `./vendor/bin/phpunit tests`
|
36
vendor/curl/curl/composer.json
vendored
36
vendor/curl/curl/composer.json
vendored
@ -1,36 +0,0 @@
|
||||
{
|
||||
"name": "curl/curl",
|
||||
"description": "cURL class for PHP",
|
||||
"keywords": ["dot", "curl"],
|
||||
"homepage": "https://github.com/php-mod/curl",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "php-curl-class",
|
||||
"homepage": "https://github.com/php-curl-class"
|
||||
},
|
||||
{
|
||||
"name": "Hassan Amouhzi",
|
||||
"email": "hassan@anezi.net",
|
||||
"homepage": "http://hassan.amouhzi.com"
|
||||
},
|
||||
{
|
||||
"name": "user52",
|
||||
"homepage": "https://github.com/user52"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^5.6 | ^7.0",
|
||||
"ext-curl": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.7",
|
||||
"squizlabs/php_codesniffer": "~2.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Curl": "src/"
|
||||
}
|
||||
}
|
||||
}
|
24
vendor/curl/curl/phpunit.xml.dist
vendored
24
vendor/curl/curl/phpunit.xml.dist
vendored
@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="true"
|
||||
verbose="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
>
|
||||
<php>
|
||||
<ini name="display_errors" value="on"/>
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="PHP MP4Box Tests Suite">
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
</phpunit>
|
719
vendor/curl/curl/src/Curl/Curl.php
vendored
719
vendor/curl/curl/src/Curl/Curl.php
vendored
@ -1,719 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Curl;
|
||||
|
||||
/**
|
||||
* An object-oriented wrapper of the PHP cURL extension.
|
||||
*
|
||||
* This library requires to have the php cURL extensions installed:
|
||||
* https://php.net/manual/curl.setup.php
|
||||
*
|
||||
* Example of making a get request with parameters:
|
||||
*
|
||||
* ```php
|
||||
* $curl = new Curl\Curl();
|
||||
* $curl->get('http://www.example.com/search', array(
|
||||
* 'q' => 'keyword',
|
||||
* ));
|
||||
* ```
|
||||
*
|
||||
* Example post request with post data:
|
||||
*
|
||||
* ```php
|
||||
* $curl = new Curl\Curl();
|
||||
* $curl->post('http://www.example.com/login/', array(
|
||||
* 'username' => 'myusername',
|
||||
* 'password' => 'mypassword',
|
||||
* ));
|
||||
* ```
|
||||
*
|
||||
* @see https://php.net/manual/curl.setup.php
|
||||
*/
|
||||
class Curl
|
||||
{
|
||||
// The HTTP authentication method(s) to use.
|
||||
|
||||
/**
|
||||
* @var string Type AUTH_BASIC
|
||||
*/
|
||||
const AUTH_BASIC = CURLAUTH_BASIC;
|
||||
|
||||
/**
|
||||
* @var string Type AUTH_DIGEST
|
||||
*/
|
||||
const AUTH_DIGEST = CURLAUTH_DIGEST;
|
||||
|
||||
/**
|
||||
* @var string Type AUTH_GSSNEGOTIATE
|
||||
*/
|
||||
const AUTH_GSSNEGOTIATE = CURLAUTH_GSSNEGOTIATE;
|
||||
|
||||
/**
|
||||
* @var string Type AUTH_NTLM
|
||||
*/
|
||||
const AUTH_NTLM = CURLAUTH_NTLM;
|
||||
|
||||
/**
|
||||
* @var string Type AUTH_ANY
|
||||
*/
|
||||
const AUTH_ANY = CURLAUTH_ANY;
|
||||
|
||||
/**
|
||||
* @var string Type AUTH_ANYSAFE
|
||||
*/
|
||||
const AUTH_ANYSAFE = CURLAUTH_ANYSAFE;
|
||||
|
||||
/**
|
||||
* @var string The user agent name which is set when making a request
|
||||
*/
|
||||
const USER_AGENT = 'PHP Curl/1.9 (+https://github.com/php-mod/curl)';
|
||||
|
||||
private $_cookies = array();
|
||||
|
||||
private $_headers = array();
|
||||
|
||||
/**
|
||||
* @var resource Contains the curl resource created by `curl_init()` function
|
||||
*/
|
||||
public $curl;
|
||||
|
||||
/**
|
||||
* @var bool Whether an error occured or not
|
||||
*/
|
||||
public $error = false;
|
||||
|
||||
/**
|
||||
* @var int Contains the error code of the curren request, 0 means no error happend
|
||||
*/
|
||||
public $error_code = 0;
|
||||
|
||||
/**
|
||||
* @var string If the curl request failed, the error message is contained
|
||||
*/
|
||||
public $error_message = null;
|
||||
|
||||
/**
|
||||
* @var bool Whether an error occured or not
|
||||
*/
|
||||
public $curl_error = false;
|
||||
|
||||
/**
|
||||
* @var int Contains the error code of the curren request, 0 means no error happend.
|
||||
* @see https://curl.haxx.se/libcurl/c/libcurl-errors.html
|
||||
*/
|
||||
public $curl_error_code = 0;
|
||||
|
||||
/**
|
||||
* @var string If the curl request failed, the error message is contained
|
||||
*/
|
||||
public $curl_error_message = null;
|
||||
|
||||
/**
|
||||
* @var bool Whether an error occured or not
|
||||
*/
|
||||
public $http_error = false;
|
||||
|
||||
/**
|
||||
* @var int Contains the status code of the current processed request.
|
||||
*/
|
||||
public $http_status_code = 0;
|
||||
|
||||
/**
|
||||
* @var string If the curl request failed, the error message is contained
|
||||
*/
|
||||
public $http_error_message = null;
|
||||
|
||||
/**
|
||||
* @var string|array TBD (ensure type) Contains the request header informations
|
||||
*/
|
||||
public $request_headers = null;
|
||||
|
||||
/**
|
||||
* @var string|array TBD (ensure type) Contains the response header informations
|
||||
*/
|
||||
public $response_headers = array();
|
||||
|
||||
/**
|
||||
* @var string Contains the response from the curl request
|
||||
*/
|
||||
public $response = null;
|
||||
|
||||
/**
|
||||
* @var bool Whether the current section of response headers is after 'HTTP/1.1 100 Continue'
|
||||
*/
|
||||
protected $response_header_continue = false;
|
||||
|
||||
/**
|
||||
* Constructor ensures the available curl extension is loaded.
|
||||
*
|
||||
* @throws \ErrorException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (!extension_loaded('curl')) {
|
||||
throw new \ErrorException('The cURL extensions is not loaded, make sure you have installed the cURL extension: https://php.net/manual/curl.setup.php');
|
||||
}
|
||||
|
||||
$this->init();
|
||||
}
|
||||
|
||||
// private methods
|
||||
|
||||
/**
|
||||
* Initializer for the curl resource.
|
||||
*
|
||||
* Is called by the __construct() of the class or when the curl request is reseted.
|
||||
* @return self
|
||||
*/
|
||||
private function init()
|
||||
{
|
||||
$this->curl = curl_init();
|
||||
$this->setUserAgent(self::USER_AGENT);
|
||||
$this->setOpt(CURLINFO_HEADER_OUT, true);
|
||||
$this->setOpt(CURLOPT_HEADER, false);
|
||||
$this->setOpt(CURLOPT_RETURNTRANSFER, true);
|
||||
$this->setOpt(CURLOPT_HEADERFUNCTION, array($this, 'addResponseHeaderLine'));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle writing the response headers
|
||||
*
|
||||
* @param resource $curl The current curl resource
|
||||
* @param string $header_line A line from the list of response headers
|
||||
*
|
||||
* @return int Returns the length of the $header_line
|
||||
*/
|
||||
public function addResponseHeaderLine($curl, $header_line)
|
||||
{
|
||||
$trimmed_header = trim($header_line, "\r\n");
|
||||
|
||||
if ($trimmed_header === "") {
|
||||
$this->response_header_continue = false;
|
||||
} elseif (strtolower($trimmed_header) === 'http/1.1 100 continue') {
|
||||
$this->response_header_continue = true;
|
||||
} elseif (!$this->response_header_continue) {
|
||||
$this->response_headers[] = $trimmed_header;
|
||||
}
|
||||
|
||||
return strlen($header_line);
|
||||
}
|
||||
|
||||
// protected methods
|
||||
|
||||
/**
|
||||
* Execute the curl request based on the respectiv settings.
|
||||
*
|
||||
* @return int Returns the error code for the current curl request
|
||||
*/
|
||||
protected function exec()
|
||||
{
|
||||
$this->response_headers = array();
|
||||
$this->response = curl_exec($this->curl);
|
||||
$this->curl_error_code = curl_errno($this->curl);
|
||||
$this->curl_error_message = curl_error($this->curl);
|
||||
$this->curl_error = !($this->curl_error_code === 0);
|
||||
$this->http_status_code = curl_getinfo($this->curl, CURLINFO_HTTP_CODE);
|
||||
$this->http_error = in_array(floor($this->http_status_code / 100), array(4, 5));
|
||||
$this->error = $this->curl_error || $this->http_error;
|
||||
$this->error_code = $this->error ? ($this->curl_error ? $this->curl_error_code : $this->http_status_code) : 0;
|
||||
$this->request_headers = preg_split('/\r\n/', curl_getinfo($this->curl, CURLINFO_HEADER_OUT), null, PREG_SPLIT_NO_EMPTY);
|
||||
$this->http_error_message = $this->error ? (isset($this->response_headers['0']) ? $this->response_headers['0'] : '') : '';
|
||||
$this->error_message = $this->curl_error ? $this->curl_error_message : $this->http_error_message;
|
||||
|
||||
return $this->error_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|object|string $data
|
||||
*/
|
||||
protected function preparePayload($data)
|
||||
{
|
||||
$this->setOpt(CURLOPT_POST, true);
|
||||
|
||||
if (is_array($data) || is_object($data)) {
|
||||
$skip = false;
|
||||
foreach ($data as $key => $value) {
|
||||
// If a value is an instance of CurlFile skip the http_build_query
|
||||
// see issue https://github.com/php-mod/curl/issues/46
|
||||
// suggestion from: https://stackoverflow.com/a/36603038/4611030
|
||||
if ($value instanceof \CurlFile) {
|
||||
$skip = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$skip) {
|
||||
$data = http_build_query($data);
|
||||
}
|
||||
}
|
||||
|
||||
$this->setOpt(CURLOPT_POSTFIELDS, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set auth options for the current request.
|
||||
*
|
||||
* Available auth types are:
|
||||
*
|
||||
* + self::AUTH_BASIC
|
||||
* + self::AUTH_DIGEST
|
||||
* + self::AUTH_GSSNEGOTIATE
|
||||
* + self::AUTH_NTLM
|
||||
* + self::AUTH_ANY
|
||||
* + self::AUTH_ANYSAFE
|
||||
*
|
||||
* @param int $httpauth The type of authentication
|
||||
*/
|
||||
protected function setHttpAuth($httpauth)
|
||||
{
|
||||
$this->setOpt(CURLOPT_HTTPAUTH, $httpauth);
|
||||
}
|
||||
|
||||
// public methods
|
||||
|
||||
/**
|
||||
* @deprecated calling exec() directly is discouraged
|
||||
*/
|
||||
public function _exec()
|
||||
{
|
||||
return $this->exec();
|
||||
}
|
||||
|
||||
// functions
|
||||
|
||||
/**
|
||||
* Make a get request with optional data.
|
||||
*
|
||||
* The get request has no body data, the data will be correctly added to the $url with the http_build_query() method.
|
||||
*
|
||||
* @param string $url The url to make the get request for
|
||||
* @param array $data Optional arguments who are part of the url
|
||||
* @return self
|
||||
*/
|
||||
public function get($url, $data = array())
|
||||
{
|
||||
if (count($data) > 0) {
|
||||
$this->setOpt(CURLOPT_URL, $url.'?'.http_build_query($data));
|
||||
} else {
|
||||
$this->setOpt(CURLOPT_URL, $url);
|
||||
}
|
||||
$this->setOpt(CURLOPT_HTTPGET, true);
|
||||
$this->exec();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a post request with optional post data.
|
||||
*
|
||||
* @param string $url The url to make the post request
|
||||
* @param array $data Post data to pass to the url
|
||||
* @return self
|
||||
*/
|
||||
public function post($url, $data = array())
|
||||
{
|
||||
$this->setOpt(CURLOPT_URL, $url);
|
||||
$this->preparePayload($data);
|
||||
$this->exec();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a put request with optional data.
|
||||
*
|
||||
* The put request data can be either sent via payload or as get paramters of the string.
|
||||
*
|
||||
* @param string $url The url to make the put request
|
||||
* @param array $data Optional data to pass to the $url
|
||||
* @param bool $payload Whether the data should be transmitted trough payload or as get parameters of the string
|
||||
* @return self
|
||||
*/
|
||||
public function put($url, $data = array(), $payload = false)
|
||||
{
|
||||
if (! empty($data)) {
|
||||
if ($payload === false) {
|
||||
$url .= '?'.http_build_query($data);
|
||||
} else {
|
||||
$this->preparePayload($data);
|
||||
}
|
||||
}
|
||||
|
||||
$this->setOpt(CURLOPT_URL, $url);
|
||||
$this->setOpt(CURLOPT_CUSTOMREQUEST, 'PUT');
|
||||
$this->exec();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a patch request with optional data.
|
||||
*
|
||||
* The patch request data can be either sent via payload or as get paramters of the string.
|
||||
*
|
||||
* @param string $url The url to make the patch request
|
||||
* @param array $data Optional data to pass to the $url
|
||||
* @param bool $payload Whether the data should be transmitted trough payload or as get parameters of the string
|
||||
* @return self
|
||||
*/
|
||||
public function patch($url, $data = array(), $payload = false)
|
||||
{
|
||||
if (! empty($data)) {
|
||||
if ($payload === false) {
|
||||
$url .= '?'.http_build_query($data);
|
||||
} else {
|
||||
$this->preparePayload($data);
|
||||
}
|
||||
}
|
||||
|
||||
$this->setOpt(CURLOPT_URL, $url);
|
||||
$this->setOpt(CURLOPT_CUSTOMREQUEST, 'PATCH');
|
||||
$this->exec();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a delete request with optional data.
|
||||
*
|
||||
* @param string $url The url to make the delete request
|
||||
* @param array $data Optional data to pass to the $url
|
||||
* @param bool $payload Whether the data should be transmitted trough payload or as get parameters of the string
|
||||
* @return self
|
||||
*/
|
||||
public function delete($url, $data = array(), $payload = false)
|
||||
{
|
||||
if (! empty($data)) {
|
||||
if ($payload === false) {
|
||||
$url .= '?'.http_build_query($data);
|
||||
} else {
|
||||
$this->preparePayload($data);
|
||||
}
|
||||
}
|
||||
|
||||
$this->setOpt(CURLOPT_URL, $url);
|
||||
$this->setOpt(CURLOPT_CUSTOMREQUEST, 'DELETE');
|
||||
$this->exec();
|
||||
return $this;
|
||||
}
|
||||
|
||||
// setters
|
||||
|
||||
/**
|
||||
* Pass basic auth data.
|
||||
*
|
||||
* If the the rquested url is secured by an httaccess basic auth mechanism you can use this method to provided the auth data.
|
||||
*
|
||||
* ```php
|
||||
* $curl = new Curl();
|
||||
* $curl->setBasicAuthentication('john', 'doe');
|
||||
* $curl->get('http://example.com/secure.php');
|
||||
* ```
|
||||
*
|
||||
* @param string $username The username for the authentification
|
||||
* @param string $password The password for the given username for the authentification
|
||||
* @return self
|
||||
*/
|
||||
public function setBasicAuthentication($username, $password)
|
||||
{
|
||||
$this->setHttpAuth(self::AUTH_BASIC);
|
||||
$this->setOpt(CURLOPT_USERPWD, $username.':'.$password);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide optional header informations.
|
||||
*
|
||||
* In order to pass optional headers by key value pairing:
|
||||
*
|
||||
* ```php
|
||||
* $curl = new Curl();
|
||||
* $curl->setHeader('X-Requested-With', 'XMLHttpRequest');
|
||||
* $curl->get('http://example.com/request.php');
|
||||
* ```
|
||||
*
|
||||
* @param string $key The header key
|
||||
* @param string $value The value for the given header key
|
||||
* @return self
|
||||
*/
|
||||
public function setHeader($key, $value)
|
||||
{
|
||||
$this->_headers[$key] = $key.': '.$value;
|
||||
$this->setOpt(CURLOPT_HTTPHEADER, array_values($this->_headers));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a User Agent.
|
||||
*
|
||||
* In order to provide you cusomtized user agent name you can use this method.
|
||||
*
|
||||
* ```php
|
||||
* $curl = new Curl();
|
||||
* $curl->setUserAgent('My John Doe Agent 1.0');
|
||||
* $curl->get('http://example.com/request.php');
|
||||
* ```
|
||||
*
|
||||
* @param string $useragent The name of the user agent to set for the current request
|
||||
* @return self
|
||||
*/
|
||||
public function setUserAgent($useragent)
|
||||
{
|
||||
$this->setOpt(CURLOPT_USERAGENT, $useragent);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Call setReferer() instead
|
||||
*/
|
||||
public function setReferrer($referrer)
|
||||
{
|
||||
$this->setReferer($referrer);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the HTTP referer header.
|
||||
*
|
||||
* The $referer informations can help identify the requested client where the requested was made.
|
||||
*
|
||||
* @param string $referer An url to pass and will be set as referer header
|
||||
* @return self
|
||||
*/
|
||||
public function setReferer($referer)
|
||||
{
|
||||
$this->setOpt(CURLOPT_REFERER, $referer);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set contents of HTTP Cookie header.
|
||||
*
|
||||
* @param string $key The name of the cookie
|
||||
* @param string $value The value for the provided cookie name
|
||||
* @return self
|
||||
*/
|
||||
public function setCookie($key, $value)
|
||||
{
|
||||
$this->_cookies[$key] = $value;
|
||||
$this->setOpt(CURLOPT_COOKIE, http_build_query($this->_cookies, '', '; '));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set customized curl options.
|
||||
*
|
||||
* To see a full list of options: http://php.net/curl_setopt
|
||||
*
|
||||
* @see http://php.net/curl_setopt
|
||||
*
|
||||
* @param int $option The curl option constante e.g. `CURLOPT_AUTOREFERER`, `CURLOPT_COOKIESESSION`
|
||||
* @param mixed $value The value to pass for the given $option
|
||||
*/
|
||||
public function setOpt($option, $value)
|
||||
{
|
||||
return curl_setopt($this->curl, $option, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get customized curl options.
|
||||
*
|
||||
* To see a full list of options: http://php.net/curl_getinfo
|
||||
*
|
||||
* @see http://php.net/curl_getinfo
|
||||
*
|
||||
* @param int $option The curl option constante e.g. `CURLOPT_AUTOREFERER`, `CURLOPT_COOKIESESSION`
|
||||
* @param mixed $value The value to check for the given $option
|
||||
*/
|
||||
public function getOpt($option)
|
||||
{
|
||||
return curl_getinfo($this->curl, $option);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the endpoint set for curl
|
||||
*
|
||||
* @see http://php.net/curl_getinfo
|
||||
*
|
||||
* @return string of endpoint
|
||||
*/
|
||||
public function getEndpoint()
|
||||
{
|
||||
return $this->getOpt(CURLINFO_EFFECTIVE_URL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable verbositiy.
|
||||
*
|
||||
* @todo As to keep naming convention it should be renamed to `setVerbose()`
|
||||
*
|
||||
* @param string $on
|
||||
* @return self
|
||||
*/
|
||||
public function verbose($on = true)
|
||||
{
|
||||
$this->setOpt(CURLOPT_VERBOSE, $on);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all curl options.
|
||||
*
|
||||
* In order to make multiple requests with the same curl object all settings requires to be reset.
|
||||
* @return self
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->close();
|
||||
$this->_cookies = array();
|
||||
$this->_headers = array();
|
||||
$this->error = false;
|
||||
$this->error_code = 0;
|
||||
$this->error_message = null;
|
||||
$this->curl_error = false;
|
||||
$this->curl_error_code = 0;
|
||||
$this->curl_error_message = null;
|
||||
$this->http_error = false;
|
||||
$this->http_status_code = 0;
|
||||
$this->http_error_message = null;
|
||||
$this->request_headers = null;
|
||||
$this->response_headers = array();
|
||||
$this->response = null;
|
||||
$this->init();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closing the current open curl resource.
|
||||
* @return self
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if (is_resource($this->curl)) {
|
||||
curl_close($this->curl);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the connection when the Curl object will be destroyed.
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Was an 'info' header returned.
|
||||
* @return bool
|
||||
*/
|
||||
public function isInfo()
|
||||
{
|
||||
return $this->http_status_code >= 100 && $this->http_status_code < 200;
|
||||
}
|
||||
|
||||
/**
|
||||
* Was an 'OK' response returned.
|
||||
* @return bool
|
||||
*/
|
||||
public function isSuccess()
|
||||
{
|
||||
return $this->http_status_code >= 200 && $this->http_status_code < 300;
|
||||
}
|
||||
|
||||
/**
|
||||
* Was a 'redirect' returned.
|
||||
* @return bool
|
||||
*/
|
||||
public function isRedirect()
|
||||
{
|
||||
return $this->http_status_code >= 300 && $this->http_status_code < 400;
|
||||
}
|
||||
|
||||
/**
|
||||
* Was an 'error' returned (client error or server error).
|
||||
* @return bool
|
||||
*/
|
||||
public function isError()
|
||||
{
|
||||
return $this->http_status_code >= 400 && $this->http_status_code < 600;
|
||||
}
|
||||
|
||||
/**
|
||||
* Was a 'client error' returned.
|
||||
* @return bool
|
||||
*/
|
||||
public function isClientError()
|
||||
{
|
||||
return $this->http_status_code >= 400 && $this->http_status_code < 500;
|
||||
}
|
||||
|
||||
/**
|
||||
* Was a 'server error' returned.
|
||||
* @return bool
|
||||
*/
|
||||
public function isServerError()
|
||||
{
|
||||
return $this->http_status_code >= 500 && $this->http_status_code < 600;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific response header key or all values from the response headers array.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* ```php
|
||||
* $curl = (new Curl())->get('http://example.com');
|
||||
*
|
||||
* echo $curl->getResponseHeaders('Content-Type');
|
||||
* ```
|
||||
*
|
||||
* Or in order to dump all keys with the given values use:
|
||||
*
|
||||
* ```php
|
||||
* $curl = (new Curl())->get('http://example.com');
|
||||
*
|
||||
* var_dump($curl->getResponseHeaders());
|
||||
* ```
|
||||
*
|
||||
* @param string $headerKey Optional key to get from the array.
|
||||
* @return bool|string
|
||||
* @since 1.9
|
||||
*/
|
||||
public function getResponseHeaders($headerKey = null)
|
||||
{
|
||||
$headers = array();
|
||||
$headerKey = strtolower($headerKey);
|
||||
|
||||
foreach ($this->response_headers as $header) {
|
||||
$parts = explode(":", $header, 2);
|
||||
|
||||
$key = isset($parts[0]) ? $parts[0] : null;
|
||||
$value = isset($parts[1]) ? $parts[1] : null;
|
||||
|
||||
$headers[trim(strtolower($key))] = trim($value);
|
||||
}
|
||||
|
||||
if ($headerKey) {
|
||||
return isset($headers[$headerKey]) ? $headers[$headerKey] : false;
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
public function getResponse()
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
public function getErrorCode()
|
||||
{
|
||||
return $this->curl_error_code;
|
||||
}
|
||||
|
||||
public function getErrorMessage()
|
||||
{
|
||||
return $this->curl_error_message;
|
||||
}
|
||||
|
||||
public function getHttpStatus()
|
||||
{
|
||||
return $this->http_status_code;
|
||||
}
|
||||
}
|
277
vendor/curl/curl/tests/CurlTest.php
vendored
277
vendor/curl/curl/tests/CurlTest.php
vendored
@ -1,277 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Curl;
|
||||
|
||||
class CurlTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
const TEST_URL = 'http://server_test';
|
||||
|
||||
/**
|
||||
*
|
||||
* @var Curl
|
||||
*/
|
||||
protected $curl;
|
||||
|
||||
function setUp() {
|
||||
$this->curl = new Curl();
|
||||
$this->curl->setOpt(CURLOPT_SSL_VERIFYPEER, FALSE);
|
||||
$this->curl->setOpt(CURLOPT_SSL_VERIFYHOST, FALSE);
|
||||
}
|
||||
|
||||
function server($request_method, $data='') {
|
||||
$request_method = strtolower($request_method);
|
||||
$this->curl->$request_method(self::TEST_URL . '/server.php', $data);
|
||||
return $this->curl->response;
|
||||
}
|
||||
|
||||
public function testExtensionLoaded() {
|
||||
|
||||
$this->assertTrue(extension_loaded('curl'));
|
||||
}
|
||||
|
||||
public function testUserAgent() {
|
||||
|
||||
$this->curl->setUserAgent(Curl::USER_AGENT);
|
||||
$this->assertEquals(Curl::USER_AGENT, $this->server('GET', array(
|
||||
'test' => 'server',
|
||||
'key' => 'HTTP_USER_AGENT',
|
||||
)));
|
||||
|
||||
}
|
||||
|
||||
public function testGet() {
|
||||
$this->assertTrue($this->server('GET', array(
|
||||
'test' => 'server',
|
||||
'key' => 'REQUEST_METHOD',
|
||||
)) === 'GET');
|
||||
}
|
||||
|
||||
public function testPostRequestMethod() {
|
||||
$this->assertTrue($this->server('POST', array(
|
||||
'test' => 'server',
|
||||
'key' => 'REQUEST_METHOD',
|
||||
)) === 'POST');
|
||||
}
|
||||
|
||||
public function testPostData() {
|
||||
$this->assertTrue($this->server('POST', array(
|
||||
'test' => 'post',
|
||||
'key' => 'test',
|
||||
)) === 'post');
|
||||
}
|
||||
|
||||
public function testPostMultidimensionalData() {
|
||||
|
||||
$data = array(
|
||||
'key' => 'file',
|
||||
'file' => array(
|
||||
'wibble',
|
||||
'wubble',
|
||||
'wobble',
|
||||
),
|
||||
);
|
||||
|
||||
$this->curl->post(self::TEST_URL . '/post_multidimensional.php', $data);
|
||||
|
||||
$this->assertEquals(
|
||||
'key=file&file%5B0%5D=wibble&file%5B1%5D=wubble&file%5B2%5D=wobble',
|
||||
$this->curl->response);
|
||||
|
||||
}
|
||||
|
||||
public function testPostFilePathUpload()
|
||||
{
|
||||
|
||||
$file_path = $this->get_png();
|
||||
|
||||
$data = array(
|
||||
'key' => 'image',
|
||||
'image' => '@' . $file_path,
|
||||
);
|
||||
|
||||
$this->curl->setOpt(CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
$this->curl->post(self::TEST_URL . '/post_file_path_upload.php', $data);
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'request_method' => 'POST',
|
||||
'key' => 'image',
|
||||
'mime_content_type' => 'ERROR', // Temp change the image response, but assuming this is not fixing the issue indeed.
|
||||
//'mime_content_type' => 'image/png'
|
||||
),
|
||||
json_decode($this->curl->response, true));
|
||||
|
||||
unlink($file_path);
|
||||
}
|
||||
|
||||
public function testPutRequestMethod() {
|
||||
$this->assertTrue($this->server('PUT', array(
|
||||
'test' => 'server',
|
||||
'key' => 'REQUEST_METHOD',
|
||||
)) === 'PUT');
|
||||
}
|
||||
|
||||
public function testPutData() {
|
||||
$this->assertTrue($this->server('PUT', array(
|
||||
'test' => 'put',
|
||||
'key' => 'test',
|
||||
)) === 'put');
|
||||
}
|
||||
|
||||
public function testPutFileHandle() {
|
||||
$png = $this->create_png();
|
||||
$tmp_file = $this->create_tmp_file($png);
|
||||
|
||||
$this->curl->setOpt(CURLOPT_PUT, TRUE);
|
||||
$this->curl->setOpt(CURLOPT_INFILE, $tmp_file);
|
||||
$this->curl->setOpt(CURLOPT_INFILESIZE, strlen($png));
|
||||
$this->curl->put(self::TEST_URL . '/server.php', array(
|
||||
'test' => 'put_file_handle',
|
||||
));
|
||||
|
||||
fclose($tmp_file);
|
||||
|
||||
$this->assertTrue($this->curl->response === 'image/png');
|
||||
}
|
||||
|
||||
public function testDelete() {
|
||||
$this->assertTrue($this->server('DELETE', array(
|
||||
'test' => 'server',
|
||||
'key' => 'REQUEST_METHOD',
|
||||
)) === 'DELETE');
|
||||
|
||||
$this->assertTrue($this->server('DELETE', array(
|
||||
'test' => 'delete',
|
||||
'key' => 'test',
|
||||
)) === 'delete');
|
||||
}
|
||||
|
||||
public function testBasicHttpAuth() {
|
||||
|
||||
$data = array();
|
||||
|
||||
$this->curl->get(self::TEST_URL . '/http_basic_auth.php', $data);
|
||||
|
||||
$this->assertEquals('canceled', $this->curl->response);
|
||||
|
||||
$username = 'myusername';
|
||||
$password = 'mypassword';
|
||||
|
||||
$this->curl->setBasicAuthentication($username, $password);
|
||||
|
||||
$this->curl->get(self::TEST_URL . '/http_basic_auth.php', $data);
|
||||
|
||||
$this->assertEquals(
|
||||
'{"username":"myusername","password":"mypassword"}',
|
||||
$this->curl->response);
|
||||
}
|
||||
|
||||
public function testReferrer() {
|
||||
$this->curl->setReferer('myreferrer');
|
||||
$this->assertTrue($this->server('GET', array(
|
||||
'test' => 'server',
|
||||
'key' => 'HTTP_REFERER',
|
||||
)) === 'myreferrer');
|
||||
}
|
||||
|
||||
public function testDeprecatedReferrer() {
|
||||
$this->curl->setReferrer('myreferrer');
|
||||
$this->assertTrue($this->server('GET', array(
|
||||
'test' => 'server',
|
||||
'key' => 'HTTP_REFERER',
|
||||
)) === 'myreferrer');
|
||||
}
|
||||
|
||||
public function testCookies() {
|
||||
$this->curl->setCookie('mycookie', 'yum');
|
||||
$this->assertTrue($this->server('GET', array(
|
||||
'test' => 'cookie',
|
||||
'key' => 'mycookie',
|
||||
)) === 'yum');
|
||||
}
|
||||
|
||||
public function testError() {
|
||||
$this->curl->setOpt(CURLOPT_CONNECTTIMEOUT_MS, 2000);
|
||||
$this->curl->get('http://1.2.3.4/');
|
||||
$this->assertTrue($this->curl->error === TRUE);
|
||||
$this->assertTrue($this->curl->curl_error === TRUE);
|
||||
$this->assertTrue($this->curl->curl_error_code === CURLE_OPERATION_TIMEOUTED);
|
||||
}
|
||||
|
||||
public function testHeaders() {
|
||||
$this->curl->setHeader('Content-Type', 'application/json');
|
||||
$this->curl->setHeader('X-Requested-With', 'XMLHttpRequest');
|
||||
$this->curl->setHeader('Accept', 'application/json');
|
||||
$this->assertTrue($this->server('GET', array(
|
||||
'test' => 'server',
|
||||
'key' => 'CONTENT_TYPE',
|
||||
)) === 'application/json');
|
||||
$this->assertTrue($this->server('GET', array(
|
||||
'test' => 'server',
|
||||
'key' => 'HTTP_X_REQUESTED_WITH',
|
||||
)) === 'XMLHttpRequest');
|
||||
$this->assertTrue($this->server('GET', array(
|
||||
'test' => 'server',
|
||||
'key' => 'HTTP_ACCEPT',
|
||||
)) === 'application/json');
|
||||
}
|
||||
|
||||
public function testHeadersWithContinue() {
|
||||
$headers = file(dirname(__FILE__) . '/data/response_headers_with_continue.txt');
|
||||
|
||||
$this->curl->response_headers = array();
|
||||
foreach($headers as $header_line) {
|
||||
$this->curl->addResponseHeaderLine(null, $header_line);
|
||||
}
|
||||
|
||||
$expected_headers = array_values(array_filter(array_map(function($l) { return trim($l, "\r\n"); }, array_slice($headers, 1))));
|
||||
|
||||
$this->assertEquals($expected_headers, $this->curl->response_headers);
|
||||
}
|
||||
|
||||
public function testReset()
|
||||
{
|
||||
$curl = $this->getMockBuilder(get_class($this->curl))->getMock();
|
||||
$curl->expects($this->once())->method('reset')->with();
|
||||
// lets make small request
|
||||
$curl->setOpt(CURLOPT_CONNECTTIMEOUT_MS, 2000);
|
||||
$curl->get('http://1.2.3.4/');
|
||||
$curl->reset();
|
||||
$this->assertFalse($curl->error);
|
||||
$this->assertSame(0, $curl->error_code);
|
||||
$this->assertNull($curl->error_message);
|
||||
$this->assertFalse($curl->curl_error);
|
||||
$this->assertSame(0, $curl->curl_error_code);
|
||||
$this->assertNull($curl->curl_error_message);
|
||||
$this->assertFalse($curl->http_error);
|
||||
$this->assertSame(0, $curl->http_status_code);
|
||||
$this->assertNull($curl->http_error_message);
|
||||
$this->assertNull($curl->request_headers);
|
||||
$this->assertEmpty($curl->response_headers);
|
||||
$this->assertNull($curl->response);
|
||||
}
|
||||
|
||||
function create_png() {
|
||||
// PNG image data, 1 x 1, 1-bit colormap, non-interlaced
|
||||
ob_start();
|
||||
imagepng(imagecreatefromstring(base64_decode('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7')));
|
||||
$raw_image = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $raw_image;
|
||||
}
|
||||
|
||||
function create_tmp_file($data) {
|
||||
$tmp_file = tmpfile();
|
||||
fwrite($tmp_file, $data);
|
||||
rewind($tmp_file);
|
||||
return $tmp_file;
|
||||
}
|
||||
|
||||
function get_png() {
|
||||
$tmp_filename = tempnam('/tmp', 'php-curl-class.');
|
||||
file_put_contents($tmp_filename, $this->create_png());
|
||||
return $tmp_filename;
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
HTTP/1.1 100 Continue
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Server: nginx/1.1.19
|
||||
Date: Fri, 11 Aug 2017 13:22:00 GMT
|
||||
Content-Type: image/jpeg
|
||||
Content-Length: 62574
|
||||
Connection: close
|
||||
Cache-Control: max-age=7257600
|
||||
Expires: Fri, 03 Nov 2017 13:22:00 GMT
|
||||
Strict-Transport-Security: max-age=31536000; includeSubDomains
|
||||
X-Frame-Option: DENY
|
||||
|
BIN
vendor/curl/curl/tests/data/test.png
vendored
BIN
vendor/curl/curl/tests/data/test.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 2.8 KiB |
9
vendor/curl/curl/tests/server/Dockerfile
vendored
9
vendor/curl/curl/tests/server/Dockerfile
vendored
@ -1,9 +0,0 @@
|
||||
FROM alpine:3.7
|
||||
|
||||
RUN apk add --no-cache php5-cli php5-curl php5-gd php5-phar php5-json php5-openssl php5-dom
|
||||
|
||||
COPY php-curl-test php-curl-test
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["php5", "-S", "0.0.0.0:80", "-t", "php-curl-test"]
|
@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
// The commands
|
||||
$commands = array(
|
||||
'cd ../../.. && git pull',
|
||||
);
|
||||
|
||||
// Run the commands for output
|
||||
$output = '';
|
||||
foreach($commands AS $command){
|
||||
// Run it
|
||||
$tmp = shell_exec($command);
|
||||
// Output
|
||||
$output .= "<span style=\"color: #6BE234;\">\$</span> <span style=\"color: #729FCF;\">{$command}\n</span>";
|
||||
$output .= htmlentities(trim($tmp)) . "\n";
|
||||
}
|
||||
|
||||
// Make it pretty for manual user access (and why not?)
|
||||
?>
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>GIT DEPLOYMENT SCRIPT</title>
|
||||
</head>
|
||||
<body style="background-color: #000000; color: #FFFFFF; font-weight: bold; padding: 0 10px;">
|
||||
<pre>
|
||||
. ____ . ____________________________
|
||||
|/ \| | |
|
||||
[| <span style="color: #FF0000;">♥ ♥</span> |] | Git Deployment Script v0.1 |
|
||||
|___==___| / © oodavid 2012 |
|
||||
|____________________________|
|
||||
|
||||
<?php echo $output; ?>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!isset($_SERVER['PHP_AUTH_USER'])) {
|
||||
header('WWW-Authenticate: Basic realm="My Realm"');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
echo 'canceled';
|
||||
exit;
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(array(
|
||||
'username' => $_SERVER['PHP_AUTH_USER'],
|
||||
'password' => $_SERVER['PHP_AUTH_PW'],
|
||||
));
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
$request_method = isset($_SERVER['REQUEST_METHOD']) ?
|
||||
$_SERVER['REQUEST_METHOD'] : '';
|
||||
|
||||
$data_values = $request_method === 'POST' ? $_POST : $_GET;
|
||||
|
||||
$key = isset($data_values['key']) ? $data_values['key'] : '';
|
||||
|
||||
$response = array();
|
||||
|
||||
$response['request_method'] = $request_method;
|
||||
$response['key'] = $key;
|
||||
|
||||
if(isset($_FILES[$key])) {
|
||||
$response['mime_content_type'] = mime_content_type($_FILES[$key]['tmp_name']);
|
||||
} else {
|
||||
$response['mime_content_type'] = 'ERROR';
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
@ -1,4 +0,0 @@
|
||||
<?php
|
||||
|
||||
$http_raw_post_data = file_get_contents('php://input');
|
||||
echo $http_raw_post_data;
|
@ -1,31 +0,0 @@
|
||||
<?php
|
||||
$request_method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : '';
|
||||
$data_values = $request_method === 'POST' ? $_POST : $_GET;
|
||||
$test = isset($data_values['test']) ? $data_values['test'] : '';
|
||||
$key = isset($data_values['key']) ? $data_values['key'] : '';
|
||||
|
||||
if ($test === 'put_file_handle') {
|
||||
$tmp_filename = tempnam('/tmp', 'php-curl-class.');
|
||||
file_put_contents($tmp_filename, file_get_contents('php://input'));
|
||||
echo mime_content_type($tmp_filename);
|
||||
unlink($tmp_filename);
|
||||
exit;
|
||||
}
|
||||
|
||||
header('Content-Type: text/plain');
|
||||
|
||||
$data_mapping = array(
|
||||
'cookie' => '_COOKIE',
|
||||
'delete' => '_GET',
|
||||
'post' => '_POST',
|
||||
'put' => '_GET',
|
||||
'server' => '_SERVER',
|
||||
);
|
||||
|
||||
if(isset($data_mapping[$test])) {
|
||||
$data = ${$data_mapping[$test]};
|
||||
$value = isset($data[$key]) ? $data[$key] : '';
|
||||
echo $value;
|
||||
} else {
|
||||
echo "Error.";
|
||||
}
|
6
vendor/ledccn/bittorrentclient/.gitignore
vendored
Normal file
6
vendor/ledccn/bittorrentclient/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/.git
|
||||
composer.lock
|
||||
vendor
|
||||
vendor/
|
||||
.idea
|
||||
.idea/
|
26
vendor/ledccn/bittorrentclient/composer.json
vendored
Normal file
26
vendor/ledccn/bittorrentclient/composer.json
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "ledccn/bittorrentclient",
|
||||
"description": "实现对下载服务器管理的代码库",
|
||||
"type": "library",
|
||||
"keywords": ["transmission", "qBittorrent"],
|
||||
"homepage": "https://github.com/ledccn/BittorrentClient",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"authors": [
|
||||
{
|
||||
"name": "David",
|
||||
"email": "367013672@qq.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^5.6 | ^7.0",
|
||||
"curl/curl": "^2.3",
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"IYUU\\Client\\": "src"
|
||||
}
|
||||
}
|
||||
}
|
23
vendor/ledccn/bittorrentclient/readme.md
vendored
Normal file
23
vendor/ledccn/bittorrentclient/readme.md
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
## 项目简介
|
||||
|
||||
下载服务器的支持库,目前支持
|
||||
|
||||
- transmission
|
||||
|
||||
- qBittorrent
|
||||
|
||||
|
||||
## 使用方法
|
||||
https://packagist.org/packages/ledccn/bittorrentclient
|
||||
|
||||
```php
|
||||
composer require ledccn/bittorrentclient:dev-master
|
||||
```
|
||||
|
||||
|
||||
## 其他项目
|
||||
|
||||
| 名称 | 简介 |
|
||||
| ---------------------------------------------------------- | ------------------------------------------------------------ |
|
||||
| [IYUUAutoReseed](https://github.com/ledccn/IYUUAutoReseed) | IYUU自动辅种工具,功能分为两大块:自动辅种、自动转移。目前能对支持的PT站点自动辅种,支持下载器集群,支持多盘位,支持多下载目录,支持远程连接等;可以实现各下载器之间自动转移做种客户端,让下载器各司其职(专职的保种、专职的下载)。 |
|
||||
|
145
vendor/ledccn/bittorrentclient/src/AbstractClient.php
vendored
Normal file
145
vendor/ledccn/bittorrentclient/src/AbstractClient.php
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
/**
|
||||
* 下载服务器抽象类
|
||||
* Created by PhpStorm
|
||||
* User: David <367013672@qq.com>
|
||||
* Date: 2020-1-11
|
||||
*/
|
||||
namespace IYUU\Client;
|
||||
|
||||
abstract class AbstractClient
|
||||
{
|
||||
/**
|
||||
* 完整的下载服务器地址
|
||||
* @var string
|
||||
*/
|
||||
protected $url = '';
|
||||
|
||||
/**
|
||||
* 下载服务器用户名
|
||||
* @var string
|
||||
*/
|
||||
protected $username = '';
|
||||
|
||||
/**
|
||||
* 密码
|
||||
* @var string
|
||||
*/
|
||||
protected $password = '';
|
||||
/**
|
||||
* 调试开关
|
||||
* @var bool
|
||||
*/
|
||||
public $debug = false;
|
||||
|
||||
/**
|
||||
* 公共方法:创建客户端实例
|
||||
* @param array $config
|
||||
* array(
|
||||
* 'type' => '',
|
||||
* 'host' => '',
|
||||
* 'endpoint' => '',
|
||||
* 'username' => '',
|
||||
* 'password' => '',
|
||||
* )
|
||||
* @return mixed 客户端实例
|
||||
* @throws \IYUU\Client\ClientException
|
||||
*/
|
||||
public static function create($config = [])
|
||||
{
|
||||
// 下载服务器类型
|
||||
$type = isset($config['type']) ? $config['type'] : '';
|
||||
$file = __DIR__ . DIRECTORY_SEPARATOR . $type . DIRECTORY_SEPARATOR . $type .'.php';
|
||||
if (!is_file($file)) {
|
||||
throw new ClientException($file.' 文件不存在');
|
||||
}
|
||||
$className = "IYUU\\Client\\" . $type . "\\" . $type;
|
||||
if (class_exists($className)) {
|
||||
echo $type." 客户端正在实例化!".PHP_EOL;
|
||||
return new $className($config);
|
||||
} else {
|
||||
throw new ClientException($className.' 客户端class不存在');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化必须的参数
|
||||
* @descr 子类调用
|
||||
* @param array $config
|
||||
*/
|
||||
protected function initialize($config = [])
|
||||
{
|
||||
$host = isset($config['host']) ? $config['host'] : ''; // 地址端口
|
||||
$endpoint = isset($config['endpoint']) ? $config['endpoint'] : ''; // 接入点
|
||||
$username = isset($config['username']) ? $config['username'] : ''; // 用户名
|
||||
$password = isset($config['password']) ? $config['password'] : ''; // 密码
|
||||
$debug = isset($config['debug']) ? $this->booleanParse($config['debug']) : false; // 调试开关
|
||||
|
||||
$this->url = rtrim($host, '/') . $endpoint;
|
||||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
$this->debug = $debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对布尔型进行格式化
|
||||
* @param mixed $value 变量值
|
||||
* @return boolean/string 格式化后的变量
|
||||
*/
|
||||
public function booleanParse($value)
|
||||
{
|
||||
$rs = $value;
|
||||
|
||||
if (!is_bool($value)) {
|
||||
if (is_numeric($value)) {
|
||||
$rs = $value > 0 ? true : false;
|
||||
} elseif (is_string($value)) {
|
||||
$rs = in_array(strtolower($value), ['ok', 'true', 'success', 'on', 'yes', '(ok)', '(true)', '(success)', '(on)', '(yes)']) ? true : false;
|
||||
} else {
|
||||
$rs = $value ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
return $rs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询Bittorrent客户端状态
|
||||
* @return string
|
||||
*/
|
||||
abstract public function status();
|
||||
|
||||
/**
|
||||
* 获取所有种子的列表
|
||||
* @param array $move
|
||||
* @return array(
|
||||
* 'hash' => string json,
|
||||
* 'sha1' => string,
|
||||
* 'hashString '=> array
|
||||
* )
|
||||
*/
|
||||
abstract public function all(&$move = array());
|
||||
|
||||
/**
|
||||
* 添加种子连接
|
||||
* @param string $torrent_url
|
||||
* @param string $save_path
|
||||
* @param array $extra_options
|
||||
*/
|
||||
abstract public function add($torrent_url, $save_path = '', $extra_options = array());
|
||||
|
||||
/**
|
||||
* 添加种子原数据
|
||||
* @param string $torrent_metainfo
|
||||
* @param string $save_path
|
||||
* @param array $extra_options
|
||||
*/
|
||||
abstract public function add_metainfo($torrent_metainfo, $save_path = '', $extra_options = array());
|
||||
|
||||
/**
|
||||
* 删除种子
|
||||
* @param $torrent
|
||||
* @param bool $deleteFiles
|
||||
*/
|
||||
abstract public function delete($torrent, $deleteFiles = false);
|
||||
}
|
12
vendor/ledccn/bittorrentclient/src/ClientException.php
vendored
Normal file
12
vendor/ledccn/bittorrentclient/src/ClientException.php
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace IYUU\Client;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class ClientException
|
||||
*/
|
||||
class ClientException extends Exception
|
||||
{
|
||||
|
||||
}
|
11
vendor/ledccn/bittorrentclient/src/qBittorrent/config.json
vendored
Normal file
11
vendor/ledccn/bittorrentclient/src/qBittorrent/config.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "qBittorrent",
|
||||
"author": "David",
|
||||
"homepage": "https://github.com/qbittorrent/qBittorrent",
|
||||
"version": "1.0",
|
||||
"icon": "https://www.iyuu.cn/usr/uploads/client/qBittorrent.ico",
|
||||
"allowCustomPath": true,
|
||||
"pathDescription": "当前目录列表配置是指定硬盘上的绝对路径,如 /volume1/music/ 或 D:\\download\\music\\",
|
||||
"description": "当前支持 qBittorrent v4.1+,由于浏览器限制,需要禁用 qBittorrent 的『启用跨站请求伪造(CSRF)保护』功能才能正常使用",
|
||||
"warning": "注意:由于 qBittorrent 验证机制限制,第一次测试连接成功后,后续测试无论密码正确与否都会提示成功。"
|
||||
}
|
674
vendor/ledccn/bittorrentclient/src/qBittorrent/qBittorrent.php
vendored
Normal file
674
vendor/ledccn/bittorrentclient/src/qBittorrent/qBittorrent.php
vendored
Normal file
@ -0,0 +1,674 @@
|
||||
<?php
|
||||
namespace IYUU\Client\qBittorrent;
|
||||
|
||||
use Curl\Curl;
|
||||
use IYUU\Client\AbstractClient;
|
||||
use IYUU\Client\ClientException;
|
||||
|
||||
/**
|
||||
* qBittorrent下载服务器的API操作类
|
||||
* 开源项目地址:https://github.com/qbittorrent/qBittorrent
|
||||
* API文档:https://github.com/qbittorrent/qBittorrent/wiki/Web-API-Documentation
|
||||
*/
|
||||
class qBittorrent extends AbstractClient
|
||||
{
|
||||
/**
|
||||
* API主版本号
|
||||
* @var int|mixed|string
|
||||
*/
|
||||
private $api_version = '';
|
||||
|
||||
/**
|
||||
* CSRF使用的Session或者Cookie
|
||||
* @var string
|
||||
*/
|
||||
private $session_id = '';
|
||||
|
||||
/**
|
||||
* curl实例
|
||||
* @var Curl
|
||||
*/
|
||||
private $curl;
|
||||
|
||||
/**
|
||||
* 分隔符
|
||||
* @var string
|
||||
*/
|
||||
protected $delimiter = '';
|
||||
|
||||
/**
|
||||
* 各版的API接入点
|
||||
* @var array
|
||||
*/
|
||||
private $endpoints = [
|
||||
'login' => [
|
||||
'1' => '/login',
|
||||
'2' => '/api/v2/auth/login'
|
||||
],
|
||||
'logout'=> [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/auth/logout'
|
||||
],
|
||||
'app_version' => [
|
||||
'1' => '/version/qbittorrent',
|
||||
'2' => '/api/v2/app/version'
|
||||
],
|
||||
'api_version' => [
|
||||
'1' => '/version/api',
|
||||
'2' => '/api/v2/app/webapiVersion'
|
||||
],
|
||||
'build_info' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/app/buildInfo'
|
||||
],
|
||||
'preferences' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/app/preferences'
|
||||
],
|
||||
'setPreferences' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/app/setPreferences'
|
||||
],
|
||||
'defaultSavePath' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/app/defaultSavePath'
|
||||
],
|
||||
'downloadLimit' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/transfer/downloadLimit'
|
||||
],
|
||||
'setDownloadLimit' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/transfer/setDownloadLimit'
|
||||
],
|
||||
'uploadLimit' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/transfer/uploadLimit'
|
||||
],
|
||||
'setUploadLimit' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/transfer/setUploadLimit'
|
||||
],
|
||||
'torrent_list' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/info'
|
||||
],
|
||||
'torrent_properties' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/properties'
|
||||
],
|
||||
'torrent_trackers' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/trackers'
|
||||
],
|
||||
'torrent_files' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/files'
|
||||
],
|
||||
'torrent_pieceStates' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/pieceStates'
|
||||
],
|
||||
'torrent_pieceHashes' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/pieceHashes'
|
||||
],
|
||||
'torrent_pause' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/pause'
|
||||
],
|
||||
'torrent_resume' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/resume'
|
||||
],
|
||||
'torrent_delete' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/delete'
|
||||
],
|
||||
'torrent_recheck' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/recheck' // 重新校验种子
|
||||
],
|
||||
'torrent_reannounce' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/reannounce' // 重新宣告种子
|
||||
],
|
||||
'torrent_add' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/add'
|
||||
],
|
||||
'torrent_addTrackers' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/addTrackers'
|
||||
],
|
||||
'torrent_editTracker' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/editTracker'
|
||||
],
|
||||
'torrent_removeTrackers' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/removeTrackers'
|
||||
],
|
||||
'torrent_addPeers' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/addPeers'
|
||||
],
|
||||
'torrent_increasePrio' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/increasePrio'
|
||||
],
|
||||
'torrent_decreasePrio' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/decreasePrio'
|
||||
],
|
||||
'torrent_downloadLimit' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/downloadLimit'
|
||||
],
|
||||
'torrent_setDownloadLimit' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/setDownloadLimit'
|
||||
],
|
||||
'torrent_setShareLimits' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/setShareLimits'
|
||||
],
|
||||
'torrent_uploadLimit' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/uploadLimit'
|
||||
],
|
||||
'torrent_setUploadLimit' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/setUploadLimit'
|
||||
],
|
||||
'torrent_setLocation' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/setLocation'
|
||||
],
|
||||
'torrent_rename' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/rename'
|
||||
],
|
||||
'torrent_setCategory' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/setCategory'
|
||||
],
|
||||
'torrent_categories' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/categories'
|
||||
],
|
||||
'torrent_createCategory' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/createCategory'
|
||||
],
|
||||
'torrent_editCategory' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/editCategory'
|
||||
],
|
||||
'torrent_removeCategories' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/removeCategories'
|
||||
],
|
||||
'torrent_addTags' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/addTags'
|
||||
],
|
||||
'torrent_removeTags' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/removeTags'
|
||||
],
|
||||
'torrent_tags' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/tags'
|
||||
],
|
||||
'torrent_createTags' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/createTags'
|
||||
],
|
||||
'torrent_deleteTags' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/deleteTags'
|
||||
],
|
||||
'torrent_setAutoManagement' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/setAutoManagement'
|
||||
],
|
||||
'torrent_toggleSequentialDownload' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/toggleSequentialDownload'
|
||||
],
|
||||
'torrent_toggleFirstLastPiecePrio' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/toggleFirstLastPiecePrio'
|
||||
],
|
||||
'torrent_setForceStart' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/setForceStart'
|
||||
],
|
||||
'torrent_setSuperSeeding' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/setSuperSeeding'
|
||||
],
|
||||
'torrent_renameFile' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/torrents/renameFile'
|
||||
],
|
||||
'maindata' => [
|
||||
'1' => null,
|
||||
'2' => '/api/v2/sync/maindata'
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param array $config
|
||||
* @throws ClientException
|
||||
*/
|
||||
public function __construct($config = [])
|
||||
{
|
||||
$this->initialize($config);
|
||||
$this->api_version = isset($config['api_version']) && $config['api_version'] ? $config['api_version'] : 2;
|
||||
$this->curl = new Curl();
|
||||
$this->curl->setOpt(CURLOPT_SSL_VERIFYPEER, false); // 禁止验证证书
|
||||
$this->curl->setOpt(CURLOPT_SSL_VERIFYHOST, 2); // 不检查证书
|
||||
$this->curl->setOpt(CURLOPT_CONNECTTIMEOUT, 60); // 超时
|
||||
$this->curl->setOpt(CURLOPT_TIMEOUT, 600); // 超时
|
||||
if (!$this->login()) {
|
||||
throw new ClientException("qBittorrent Unable to authenticate with Web Api.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* app编译版本
|
||||
* @return string
|
||||
*/
|
||||
public function appVersion()
|
||||
{
|
||||
return $this->getData('app_version');
|
||||
}
|
||||
|
||||
/**
|
||||
* api版本
|
||||
* @return string
|
||||
*/
|
||||
public function apiVersion()
|
||||
{
|
||||
return $this->getData('api_version');
|
||||
}
|
||||
|
||||
/**
|
||||
* 编译信息
|
||||
* @return array
|
||||
*/
|
||||
public function buildInfo()
|
||||
{
|
||||
return $this->getData('build_info');
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载器验证
|
||||
* @return bool
|
||||
*/
|
||||
public function login()
|
||||
{
|
||||
$this->curl->post($this->url . $this->endpoints['login'][$this->api_version], [
|
||||
'username' => $this->username,
|
||||
'password' => $this->password
|
||||
]);
|
||||
|
||||
if ($this->debug) {
|
||||
var_dump($this->curl->request_headers);
|
||||
var_dump($this->curl->response_headers);
|
||||
}
|
||||
|
||||
// Find authentication cookie and set in curl connection
|
||||
foreach ($this->curl->response_headers as $header) {
|
||||
if (preg_match('/SID=(\S[^;]+)/', $header, $matches)) {
|
||||
$this->session_id = $matches[0];
|
||||
$qb415 = '; QB_'.$matches[0]; // 兼容qBittorrent v4.1.5[小钢炮等]
|
||||
$this->curl->setHeader('Cookie', $matches[0].$qb415);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
* @return mixed
|
||||
*/
|
||||
public function logout()
|
||||
{
|
||||
$this->session_id = '';
|
||||
$this->getData('logout');
|
||||
$this->curl->reset();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下载器首选项
|
||||
* @return mixed
|
||||
*/
|
||||
public function preferences()
|
||||
{
|
||||
return $this->getData('preferences');
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置下载器首选项
|
||||
* @param array $data
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function setPreferences($data = [])
|
||||
{
|
||||
if (!empty($data)) {
|
||||
return $this->postData('setPreferences', ['json' => json_encode($data)]);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取种子列表
|
||||
* @return mixed
|
||||
*/
|
||||
public function torrentList()
|
||||
{
|
||||
return $this->getData('torrent_list');
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加种子链接
|
||||
* @param $torrent_url
|
||||
* @param string $save_path
|
||||
* @param array $extra_options
|
||||
* array(
|
||||
* 'urls' => '',
|
||||
* 'savepath' => '',
|
||||
* 'cookie' => '',
|
||||
* 'category' => '',
|
||||
* 'skip_checking' => true,
|
||||
* 'paused' => true,
|
||||
* 'root_folder' => true,
|
||||
* )
|
||||
* @return array
|
||||
*/
|
||||
public function add($torrent_url, $save_path = '', $extra_options = array())
|
||||
{
|
||||
if (!empty($save_path)) {
|
||||
$extra_options['savepath'] = $save_path;
|
||||
}
|
||||
$extra_options['urls'] = $torrent_url;
|
||||
#$extra_options['skip_checking'] = 'true'; //跳校验
|
||||
// 关键 上传文件流 multipart/form-data【严格按照api文档编写】
|
||||
$post_data = $this->buildUrls($extra_options);
|
||||
#p($post_data);
|
||||
// 设置请求头
|
||||
$this->curl->setHeader('Content-Type', 'multipart/form-data; boundary='.$this->delimiter);
|
||||
$this->curl->setHeader('Content-Length', strlen($post_data));
|
||||
return $this->postData('torrent_add', $post_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加种子元数据
|
||||
* @param string $torrent_metainfo
|
||||
* @param string $save_path
|
||||
* @param array $extra_options
|
||||
* @return false|string|null
|
||||
*/
|
||||
public function add_metainfo($torrent_metainfo, $save_path = '', $extra_options = array())
|
||||
{
|
||||
if (!empty($save_path)) {
|
||||
$extra_options['savepath'] = $save_path;
|
||||
}
|
||||
$extra_options['torrents'] = $torrent_metainfo;
|
||||
#$extra_options['skip_checking'] = 'true'; //跳校验
|
||||
// 关键 上传文件流 multipart/form-data【严格按照api文档编写】
|
||||
$post_data = $this->buildData($extra_options);
|
||||
// 设置请求头
|
||||
$this->curl->setHeader('Content-Type', 'multipart/form-data; boundary='.$this->delimiter);
|
||||
$this->curl->setHeader('Content-Length', strlen($post_data));
|
||||
return $this->postData('torrent_add', $post_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除所有种子
|
||||
* @param bool $deleteFiles
|
||||
* @return string
|
||||
*/
|
||||
public function deleteAll($deleteFiles = false)
|
||||
{
|
||||
$torrents = json_decode($this->torrentList());
|
||||
$response = '';
|
||||
foreach ($torrents as $torrent) {
|
||||
$response .= $this->delete($torrent->hash, $deleteFiles);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停种子
|
||||
* @param string $hash info_hash可以|分隔,删除多个种子;也可以传入all,删除所有种子
|
||||
* @return false|string|null
|
||||
*/
|
||||
public function pause($hash)
|
||||
{
|
||||
return $this->postData('torrent_pause', ['hashes' => $hash]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复做种
|
||||
* @param string $hash info_hash可以|分隔,删除多个种子;也可以传入all,删除所有种子
|
||||
* @return false|string|null
|
||||
*/
|
||||
public function resume($hash)
|
||||
{
|
||||
return $this->postData('torrent_resume', ['hashes' => $hash]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 抽象方法,子类实现
|
||||
* 删除种子
|
||||
* @param string $hash info_hash可以|分隔,删除多个种子;也可以传入all,删除所有种子
|
||||
* @param bool $deleteFiles 是否同时删除数据
|
||||
* @return false|string|null
|
||||
*/
|
||||
public function delete($hash = '', $deleteFiles = false)
|
||||
{
|
||||
return $this->postData('torrent_delete', ['hashes' => $hash, 'deleteFiles' => $deleteFiles ? 'true':'false']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新校验种子
|
||||
* @param string $hash info_hash可以|分隔,删除多个种子;也可以传入all,删除所有种子
|
||||
* @return false|string|null
|
||||
*/
|
||||
public function recheck($hash)
|
||||
{
|
||||
return $this->postData('torrent_recheck', ['hashes' => $hash]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新宣告种子
|
||||
* @param string $hash info_hash可以|分隔,删除多个种子;也可以传入all,删除所有种子
|
||||
* @return false|string|null
|
||||
*/
|
||||
public function reannounce($hash)
|
||||
{
|
||||
return $this->postData('torrent_reannounce', ['hashes' => $hash]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $hash
|
||||
* @param $location
|
||||
* @return false|string|null
|
||||
*/
|
||||
public function setTorrentLocation($hash, $location)
|
||||
{
|
||||
return $this->postData('torrent_setLocation', ['hashes' => $hash, 'location' => $location]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前Curl对象
|
||||
* @return Curl
|
||||
*/
|
||||
public function curl()
|
||||
{
|
||||
return $this->curl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 基本get方法
|
||||
* @param $endpoint
|
||||
* @return mixed
|
||||
*/
|
||||
private function getData($endpoint)
|
||||
{
|
||||
$this->curl->get($this->url . $this->endpoints[$endpoint][$this->api_version]);
|
||||
|
||||
if ($this->debug) {
|
||||
var_dump($this->curl->request_headers);
|
||||
var_dump($this->curl->response_headers);
|
||||
var_dump($this->curl->response);
|
||||
}
|
||||
|
||||
if ($this->curl->error) {
|
||||
return $this->errorMessage();
|
||||
}
|
||||
|
||||
return $this->curl->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 基本post方法
|
||||
* @param $endpoint
|
||||
* @param $data
|
||||
* @return mixed
|
||||
*/
|
||||
private function postData($endpoint, $data)
|
||||
{
|
||||
$this->curl->post($this->url . $this->endpoints[$endpoint][$this->api_version], $data);
|
||||
|
||||
if ($this->debug) {
|
||||
var_dump($this->curl->request_headers);
|
||||
var_dump($this->curl->response_headers);
|
||||
var_dump($this->curl->response);
|
||||
}
|
||||
|
||||
if ($this->curl->error) {
|
||||
return $this->errorMessage();
|
||||
}
|
||||
|
||||
return $this->curl->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回错误信息
|
||||
* @return string
|
||||
*/
|
||||
private function errorMessage()
|
||||
{
|
||||
return 'Curl Error Code: ' . $this->curl->error_code . ' (' . $this->curl->response . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接种子urls multipart/form-data
|
||||
* https://github.com/qbittorrent/qBittorrent/wiki/Web-API-Documentation#add-new-torrent
|
||||
* @param array $param
|
||||
* @return string
|
||||
*/
|
||||
public function buildUrls($param)
|
||||
{
|
||||
$this->delimiter = uniqid();
|
||||
$eol = "\r\n";
|
||||
$data = '';
|
||||
// 拼接文件流
|
||||
foreach ($param as $name => $content) {
|
||||
$data .= "--" . $this->delimiter . $eol;
|
||||
$data .= 'Content-Disposition: form-data; name="' .$name. '"' . $eol . $eol;
|
||||
$data .= $content . $eol;
|
||||
}
|
||||
$data .= "--" . $this->delimiter . "--" . $eol;
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接种子上传文件流 multipart/form-data
|
||||
* https://github.com/qbittorrent/qBittorrent/wiki/Web-API-Documentation#add-new-torrent
|
||||
* @param array $param
|
||||
* @return string
|
||||
*/
|
||||
public function buildData($param)
|
||||
{
|
||||
$this->delimiter = uniqid();
|
||||
$eol = "\r\n";
|
||||
$data = '';
|
||||
// 拼接文件流
|
||||
$data .= "--" . $this->delimiter . $eol;
|
||||
$data .= 'Content-Disposition: form-data; name="' .$param['name']. '"; filename="'.$param['filename'].'"' . $eol;
|
||||
$data .= 'Content-Type: application/x-bittorrent' . $eol . $eol;
|
||||
$data .= $param['torrents'] . $eol;
|
||||
unset($param['name']);
|
||||
unset($param['filename']);
|
||||
unset($param['torrents']);
|
||||
if (!empty($param)) {
|
||||
foreach ($param as $name => $content) {
|
||||
$data .= "--" . $this->delimiter . $eol;
|
||||
$data .= 'Content-Disposition: form-data; name="' . $name . '"' . $eol . $eol;
|
||||
$data .= $content . $eol;
|
||||
}
|
||||
}
|
||||
$data .= "--" . $this->delimiter . "--" . $eol;
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 抽象方法,子类实现
|
||||
*/
|
||||
public function status()
|
||||
{
|
||||
return $this->appVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* 抽象方法,子类实现
|
||||
* @param array $torrentList
|
||||
* @return array
|
||||
*/
|
||||
public function all(&$torrentList = array())
|
||||
{
|
||||
$result = $this->getData('torrent_list');
|
||||
$res = json_decode($result, true);
|
||||
if (empty($res)) {
|
||||
echo "获取种子列表失败,可能qBittorrent暂时无响应,请稍后重试!".PHP_EOL;
|
||||
return array();
|
||||
}
|
||||
// 过滤,只保留正常做种
|
||||
$res = array_filter($res, function ($v) {
|
||||
if (isset($v['state']) && in_array($v['state'], array('uploading','stalledUP','pausedUP','queuedUP','checkingUP','forcedUP'))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, ARRAY_FILTER_USE_BOTH);
|
||||
|
||||
if (empty($res)) {
|
||||
echo "未获取到正常做种数据,请多保种,然后重试!".PHP_EOL;
|
||||
return array();
|
||||
}
|
||||
// 提取数组:hashString
|
||||
$info_hash = array_column($res, 'hash');
|
||||
// 升序排序
|
||||
sort($info_hash);
|
||||
$json = json_encode($info_hash, JSON_UNESCAPED_UNICODE);
|
||||
// 去重 应该从文件读入,防止重复提交
|
||||
$sha1 = sha1($json);
|
||||
// 组装返回数据
|
||||
$hashArray['hash'] = $json;
|
||||
$hashArray['sha1'] = $sha1;
|
||||
// 变换数组:hashString键名、目录为键值
|
||||
$hashArray['hashString'] = array_column($res, "save_path", 'hash');
|
||||
$torrentList = array_column($res, null, 'hash');
|
||||
return $hashArray;
|
||||
}
|
||||
}
|
10
vendor/ledccn/bittorrentclient/src/transmission/config.json
vendored
Normal file
10
vendor/ledccn/bittorrentclient/src/transmission/config.json
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "Transmission",
|
||||
"author": "David",
|
||||
"homepage": "https://github.com/transmission/transmission",
|
||||
"version": "1.0",
|
||||
"icon": "https://www.iyuu.cn/usr/uploads/client/transmission.ico",
|
||||
"allowCustomPath": true,
|
||||
"pathDescription": "当前目录列表配置是指定硬盘上的绝对路径,如 /volume1/music/",
|
||||
"description": "默认情况下,系统会请求 http://ip:port/transmission/rpc 这个路径,如果无法连接,请确认 `settings.json` 文件的 `rpc-url` 值;"
|
||||
}
|
990
vendor/ledccn/bittorrentclient/src/transmission/transmission.php
vendored
Normal file
990
vendor/ledccn/bittorrentclient/src/transmission/transmission.php
vendored
Normal file
@ -0,0 +1,990 @@
|
||||
<?php
|
||||
namespace IYUU\Client\transmission;
|
||||
|
||||
use Curl\Curl;
|
||||
use IYUU\Client\AbstractClient;
|
||||
use IYUU\Client\ClientException;
|
||||
|
||||
/**
|
||||
* Transmission下载服务器的RPC操作类
|
||||
* 开源项目地址:https://github.com/transmission/transmission
|
||||
* API文档:https://github.com/transmission/transmission/blob/master/extras/rpc-spec.txt
|
||||
*/
|
||||
class transmission extends AbstractClient
|
||||
{
|
||||
/**
|
||||
* UserAgent
|
||||
*/
|
||||
const UA = 'TransmissionRPC for PHP/7.0.0';
|
||||
|
||||
/**
|
||||
* Transmission RPC version
|
||||
* @var int
|
||||
*/
|
||||
protected $rpc_version = 0;
|
||||
|
||||
/**
|
||||
* CSRF使用的Session或者Cookie
|
||||
* @var string
|
||||
*/
|
||||
protected $session_id = '';
|
||||
|
||||
/**
|
||||
* 种子状态码 torrent status
|
||||
*/
|
||||
const TR_STATUS_STOPPED = 0; // Torrent is stopped
|
||||
const TR_STATUS_CHECK_WAIT = 1; // Queued to check files
|
||||
const TR_STATUS_CHECK = 2; // Checking files
|
||||
const TR_STATUS_DOWNLOAD_WAIT = 3; // Queued to download
|
||||
const TR_STATUS_DOWNLOAD = 4; // Downloading
|
||||
const TR_STATUS_SEED_WAIT = 5; // Queued to seed
|
||||
const TR_STATUS_SEED = 6; // Seeding
|
||||
|
||||
const RPC_LT_14_TR_STATUS_CHECK_WAIT = 1;
|
||||
const RPC_LT_14_TR_STATUS_CHECK = 2;
|
||||
const RPC_LT_14_TR_STATUS_DOWNLOAD = 4;
|
||||
const RPC_LT_14_TR_STATUS_SEED = 8;
|
||||
const RPC_LT_14_TR_STATUS_STOPPED = 16;
|
||||
|
||||
/**
|
||||
* Exception: Invalid arguments
|
||||
*/
|
||||
const E_INVALIDARG = -1;
|
||||
|
||||
/**
|
||||
* Exception: Invalid Session-Id
|
||||
*/
|
||||
const E_SESSIONID = -2;
|
||||
|
||||
/**
|
||||
* Exception: Error while connecting
|
||||
*/
|
||||
const E_CONNECTION = -3;
|
||||
|
||||
/**
|
||||
* Exception: Error 401 returned, unauthorized
|
||||
*/
|
||||
const E_AUTHENTICATION = -4;
|
||||
|
||||
/**
|
||||
* Curl实例
|
||||
* @var
|
||||
*/
|
||||
private $curl;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct($config = [])
|
||||
{
|
||||
$this->initialize($config);
|
||||
$this->curl = new Curl();
|
||||
$this->curl->setOpt(CURLOPT_CONNECTTIMEOUT, 60); // 超时
|
||||
$this->curl->setOpt(CURLOPT_TIMEOUT, 600); // 超时
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始一个或多个种子
|
||||
* Start one or more torrents
|
||||
* @param int|array ids A list of transmission torrent ids
|
||||
* @return mixed
|
||||
* @throws ClientException
|
||||
*/
|
||||
public function start($ids)
|
||||
{
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
}
|
||||
$request = array("ids" => $ids);
|
||||
return $this->request("torrent-start", $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止一个或多个种子
|
||||
* Stop one or more torrents
|
||||
* @param int|array ids A list of transmission torrent ids
|
||||
* @return mixed
|
||||
* @throws ClientException
|
||||
*/
|
||||
public function stop($ids)
|
||||
{
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
}
|
||||
$request = array("ids" => $ids);
|
||||
return $this->request("torrent-stop", $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验一个或多个种子
|
||||
* Verify one or more torrents
|
||||
*
|
||||
* @param int|array ids A list of transmission torrent ids
|
||||
* @return mixed
|
||||
* @throws ClientException
|
||||
*/
|
||||
public function verify($ids)
|
||||
{
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
}
|
||||
$request = array("ids" => $ids);
|
||||
return $this->request("torrent-verify", $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个或多个种子
|
||||
* Remove torrent from transmission
|
||||
* @param int|array ids A list of transmission torrent ids
|
||||
* @param bool $delete_local_data 是否删除数据
|
||||
* @return mixed
|
||||
* @throws ClientException
|
||||
*/
|
||||
public function delete($ids, $delete_local_data = false)
|
||||
{
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
}
|
||||
$request = array(
|
||||
"ids" => $ids,
|
||||
"delete-local-data" => $delete_local_data
|
||||
);
|
||||
return $this->request("torrent-remove", $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从announce获取一个或多个种子的更多Peer
|
||||
* Reannounce one or more torrents
|
||||
* @param int|array ids A list of transmission torrent ids
|
||||
* @return mixed
|
||||
* @throws ClientException
|
||||
*/
|
||||
public function reannounce($ids)
|
||||
{
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
}
|
||||
$request = array("ids" => $ids);
|
||||
return $this->request("torrent-reannounce", $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个种子或所有种子的参数
|
||||
* Get information on torrents in transmission, if the ids parameter is
|
||||
* empty all torrents will be returned. The fields array can be used to return certain
|
||||
* fields. Default fields are: "id", "name", "status", "doneDate", "haveValid", "totalSize".
|
||||
* key | type | source
|
||||
----------------------------+-----------------------------+---------
|
||||
activityDate | number | tr_stat
|
||||
addedDate | number | tr_stat
|
||||
bandwidthPriority | number | tr_priority_t
|
||||
comment | string | tr_info
|
||||
corruptEver | number | tr_stat
|
||||
creator | string | tr_info
|
||||
dateCreated | number | tr_info
|
||||
desiredAvailable | number | tr_stat
|
||||
doneDate | number | tr_stat
|
||||
downloadDir | string | tr_torrent
|
||||
downloadedEver | number | tr_stat
|
||||
downloadLimit | number | tr_torrent
|
||||
downloadLimited | boolean | tr_torrent
|
||||
error | number | tr_stat
|
||||
errorString | string | tr_stat
|
||||
eta | number | tr_stat
|
||||
etaIdle | number | tr_stat
|
||||
files | array (see below) | n/a
|
||||
fileStats | array (see below) | n/a
|
||||
hashString | string | tr_info
|
||||
haveUnchecked | number | tr_stat
|
||||
haveValid | number | tr_stat
|
||||
honorsSessionLimits | boolean | tr_torrent
|
||||
id | number | tr_torrent
|
||||
isFinished | boolean | tr_stat
|
||||
isPrivate | boolean | tr_torrent
|
||||
isStalled | boolean | tr_stat
|
||||
leftUntilDone | number | tr_stat
|
||||
magnetLink | string | n/a
|
||||
manualAnnounceTime | number | tr_stat
|
||||
maxConnectedPeers | number | tr_torrent
|
||||
metadataPercentComplete | double | tr_stat
|
||||
name | string | tr_info
|
||||
peer-limit | number | tr_torrent
|
||||
peers | array (see below) | n/a
|
||||
peersConnected | number | tr_stat
|
||||
peersFrom | object (see below) | n/a
|
||||
peersGettingFromUs | number | tr_stat
|
||||
peersSendingToUs | number | tr_stat
|
||||
percentDone | double | tr_stat
|
||||
pieces | string (see below) | tr_torrent
|
||||
pieceCount | number | tr_info
|
||||
pieceSize | number | tr_info
|
||||
priorities | array (see below) | n/a
|
||||
queuePosition | number | tr_stat
|
||||
rateDownload (B/s) | number | tr_stat
|
||||
rateUpload (B/s) | number | tr_stat
|
||||
recheckProgress | double | tr_stat
|
||||
secondsDownloading | number | tr_stat
|
||||
secondsSeeding | number | tr_stat
|
||||
seedIdleLimit | number | tr_torrent
|
||||
seedIdleMode | number | tr_inactvelimit
|
||||
seedRatioLimit | double | tr_torrent
|
||||
seedRatioMode | number | tr_ratiolimit
|
||||
sizeWhenDone | number | tr_stat
|
||||
startDate | number | tr_stat
|
||||
status | number | tr_stat
|
||||
trackers | array (see below) | n/a
|
||||
trackerStats | array (see below) | n/a
|
||||
totalSize | number | tr_info
|
||||
torrentFile | string | tr_info
|
||||
uploadedEver | number | tr_stat
|
||||
uploadLimit | number | tr_torrent
|
||||
uploadLimited | boolean | tr_torrent
|
||||
uploadRatio | double | tr_stat
|
||||
wanted | array (see below) | n/a
|
||||
webseeds | array (see below) | n/a
|
||||
webseedsSendingToUs | number | tr_stat
|
||||
| |
|
||||
-------------------+--------+-----------------------------+
|
||||
files | array of objects, each containing: |
|
||||
+-------------------------+------------+
|
||||
| bytesCompleted | number | tr_torrent
|
||||
| length | number | tr_info
|
||||
| name | string | tr_info
|
||||
-------------------+--------------------------------------+
|
||||
fileStats | a file's non-constant properties. |
|
||||
| array of tr_info.filecount objects, |
|
||||
| each containing: |
|
||||
+-------------------------+------------+
|
||||
| bytesCompleted | number | tr_torrent
|
||||
| wanted | boolean | tr_info
|
||||
| priority | number | tr_info
|
||||
-------------------+--------------------------------------+
|
||||
peers | array of objects, each containing: |
|
||||
+-------------------------+------------+
|
||||
| address | string | tr_peer_stat
|
||||
| clientName | string | tr_peer_stat
|
||||
| clientIsChoked | boolean | tr_peer_stat
|
||||
| clientIsInterested | boolean | tr_peer_stat
|
||||
| flagStr | string | tr_peer_stat
|
||||
| isDownloadingFrom | boolean | tr_peer_stat
|
||||
| isEncrypted | boolean | tr_peer_stat
|
||||
| isIncoming | boolean | tr_peer_stat
|
||||
| isUploadingTo | boolean | tr_peer_stat
|
||||
| isUTP | boolean | tr_peer_stat
|
||||
| peerIsChoked | boolean | tr_peer_stat
|
||||
| peerIsInterested | boolean | tr_peer_stat
|
||||
| port | number | tr_peer_stat
|
||||
| progress | double | tr_peer_stat
|
||||
| rateToClient (B/s) | number | tr_peer_stat
|
||||
| rateToPeer (B/s) | number | tr_peer_stat
|
||||
-------------------+--------------------------------------+
|
||||
peersFrom | an object containing: |
|
||||
+-------------------------+------------+
|
||||
| fromCache | number | tr_stat
|
||||
| fromDht | number | tr_stat
|
||||
| fromIncoming | number | tr_stat
|
||||
| fromLpd | number | tr_stat
|
||||
| fromLtep | number | tr_stat
|
||||
| fromPex | number | tr_stat
|
||||
| fromTracker | number | tr_stat
|
||||
-------------------+--------------------------------------+
|
||||
pieces | A bitfield holding pieceCount flags | tr_torrent
|
||||
| which are set to 'true' if we have |
|
||||
| the piece matching that position. |
|
||||
| JSON doesn't allow raw binary data, |
|
||||
| so this is a base64-encoded string. |
|
||||
-------------------+--------------------------------------+
|
||||
priorities | an array of tr_info.filecount | tr_info
|
||||
| numbers. each is the tr_priority_t |
|
||||
| mode for the corresponding file. |
|
||||
-------------------+--------------------------------------+
|
||||
trackers | array of objects, each containing: |
|
||||
+-------------------------+------------+
|
||||
| announce | string | tr_tracker_info
|
||||
| id | number | tr_tracker_info
|
||||
| scrape | string | tr_tracker_info
|
||||
| tier | number | tr_tracker_info
|
||||
-------------------+--------------------------------------+
|
||||
trackerStats | array of objects, each containing: |
|
||||
+-------------------------+------------+
|
||||
| announce | string | tr_tracker_stat
|
||||
| announceState | number | tr_tracker_stat
|
||||
| downloadCount | number | tr_tracker_stat
|
||||
| hasAnnounced | boolean | tr_tracker_stat
|
||||
| hasScraped | boolean | tr_tracker_stat
|
||||
| host | string | tr_tracker_stat
|
||||
| id | number | tr_tracker_stat
|
||||
| isBackup | boolean | tr_tracker_stat
|
||||
| lastAnnouncePeerCount | number | tr_tracker_stat
|
||||
| lastAnnounceResult | string | tr_tracker_stat
|
||||
| lastAnnounceStartTime | number | tr_tracker_stat
|
||||
| lastAnnounceSucceeded | boolean | tr_tracker_stat
|
||||
| lastAnnounceTime | number | tr_tracker_stat
|
||||
| lastAnnounceTimedOut | boolean | tr_tracker_stat
|
||||
| lastScrapeResult | string | tr_tracker_stat
|
||||
| lastScrapeStartTime | number | tr_tracker_stat
|
||||
| lastScrapeSucceeded | boolean | tr_tracker_stat
|
||||
| lastScrapeTime | number | tr_tracker_stat
|
||||
| lastScrapeTimedOut | boolean | tr_tracker_stat
|
||||
| leecherCount | number | tr_tracker_stat
|
||||
| nextAnnounceTime | number | tr_tracker_stat
|
||||
| nextScrapeTime | number | tr_tracker_stat
|
||||
| scrape | string | tr_tracker_stat
|
||||
| scrapeState | number | tr_tracker_stat
|
||||
| seederCount | number | tr_tracker_stat
|
||||
| tier | number | tr_tracker_stat
|
||||
-------------------+-------------------------+------------+
|
||||
wanted | an array of tr_info.fileCount | tr_info
|
||||
| 'booleans' true if the corresponding |
|
||||
| file is to be downloaded. |
|
||||
-------------------+--------------------------------------+
|
||||
webseeds | an array of strings: |
|
||||
+-------------------------+------------+
|
||||
| webseed | string | tr_info
|
||||
+-------------------------+------------+
|
||||
*
|
||||
* @param array fields An array of return fields
|
||||
* @param int|array ids A list of transmission torrent ids
|
||||
* 示例 Example:
|
||||
Say we want to get the name and total size of torrents #7 and #10.
|
||||
|
||||
请求 Request:
|
||||
{
|
||||
"arguments": {
|
||||
"fields": [ "id", "name", "totalSize" ],
|
||||
"ids": [ 7, 10 ]
|
||||
},
|
||||
"method": "torrent-get",
|
||||
"tag": 39693
|
||||
}
|
||||
|
||||
响应 Response:
|
||||
{
|
||||
"arguments": {
|
||||
"torrents": [
|
||||
{
|
||||
"id": 10,
|
||||
"name": "Fedora x86_64 DVD",
|
||||
"totalSize": 34983493932,
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "Ubuntu x86_64 DVD",
|
||||
"totalSize", 9923890123,
|
||||
}
|
||||
]
|
||||
},
|
||||
"result": "success",
|
||||
"tag": 39693
|
||||
}
|
||||
*
|
||||
* @return mixed
|
||||
* @throws ClientException
|
||||
*/
|
||||
public function get($ids = [], $fields = [])
|
||||
{
|
||||
$default = ["id", "name", "status", "doneDate", "haveValid", "totalSize"];
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
}
|
||||
if (empty($fields)) {
|
||||
$fields = $default;
|
||||
} else {
|
||||
$fields = is_array($fields) ? array_merge($default, $fields) : $default;
|
||||
}
|
||||
$request = array(
|
||||
"fields" => $fields,
|
||||
"ids" => $ids
|
||||
);
|
||||
return $this->request("torrent-get", $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置一个或多个种子的参数
|
||||
* Set properties on one or more torrents, available fields are:
|
||||
* string | value type & description
|
||||
----------------------+-------------------------------------------------
|
||||
"bandwidthPriority" | number this torrent's bandwidth tr_priority_t
|
||||
"downloadLimit" | number maximum download speed (KBps)
|
||||
"downloadLimited" | boolean true if "downloadLimit" is honored
|
||||
"files-wanted" | array indices of file(s) to download
|
||||
"files-unwanted" | array indices of file(s) to not download
|
||||
"honorsSessionLimits" | boolean true if session upload limits are honored
|
||||
"ids" | array torrent list, as described in 3.1
|
||||
"location" | string new location of the torrent's content
|
||||
"peer-limit" | number maximum number of peers
|
||||
"priority-high" | array indices of high-priority file(s)
|
||||
"priority-low" | array indices of low-priority file(s)
|
||||
"priority-normal" | array indices of normal-priority file(s)
|
||||
"queuePosition" | number position of this torrent in its queue [0...n)
|
||||
"seedIdleLimit" | number torrent-level number of minutes of seeding inactivity
|
||||
"seedIdleMode" | number which seeding inactivity to use. See tr_idlelimit
|
||||
"seedRatioLimit" | double torrent-level seeding ratio
|
||||
"seedRatioMode" | number which ratio to use. See tr_ratiolimit
|
||||
"trackerAdd" | array strings of announce URLs to add
|
||||
"trackerRemove" | array ids of trackers to remove
|
||||
"trackerReplace" | array pairs of <trackerId/new announce URLs>
|
||||
"uploadLimit" | number maximum upload speed (KBps)
|
||||
"uploadLimited" | boolean true if "uploadLimit" is honored
|
||||
*
|
||||
* @param array arguments An associative array of arguments to set
|
||||
* @param int|array ids A list of transmission torrent ids
|
||||
* @return mixed
|
||||
* @throws ClientException
|
||||
*/
|
||||
public function set($ids = array(), $arguments = array())
|
||||
{
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
}
|
||||
if (!isset($arguments['ids'])) {
|
||||
$arguments['ids'] = $ids;
|
||||
}
|
||||
return $this->request("torrent-set", $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加新种子 (URL)
|
||||
* Add a new torrent
|
||||
*
|
||||
* Request arguments:
|
||||
* key | value type & description
|
||||
---------------------+-------------------------------------------------
|
||||
"cookies" | string pointer to a string of one or more cookies.
|
||||
"download-dir" | string path to download the torrent to
|
||||
"filename" | string filename or URL of the .torrent file
|
||||
"metainfo" | string base64-encoded .torrent content
|
||||
"paused" | boolean if true, don't start the torrent
|
||||
"peer-limit" | number maximum number of peers
|
||||
"bandwidthPriority" | number torrent's bandwidth tr_priority_t
|
||||
"files-wanted" | array indices of file(s) to download
|
||||
"files-unwanted" | array indices of file(s) to not download
|
||||
"priority-high" | array indices of high-priority file(s)
|
||||
"priority-low" | array indices of low-priority file(s)
|
||||
"priority-normal" | array indices of normal-priority file(s)
|
||||
*
|
||||
* 参数内必须包含"filename"或"metainfo"字段,其他字段都可选。
|
||||
* Either "filename" OR "metainfo" MUST be included.
|
||||
All other arguments are optional.
|
||||
*
|
||||
* @param string $filename 字符串文件名或种子url;The URL or path to the torrent file
|
||||
* @param string $save_path Folder to save torrent in
|
||||
* @param array $extra_options Optional extra torrent options
|
||||
* @return mixed
|
||||
* @throws ClientException
|
||||
*/
|
||||
public function add($filename, $save_path = '', $extra_options = array())
|
||||
{
|
||||
if (!empty($save_path)) {
|
||||
$extra_options['download-dir'] = $save_path;
|
||||
}
|
||||
$extra_options['filename'] = $filename;
|
||||
|
||||
return $this->request("torrent-add", $extra_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加新种子 (元数据)
|
||||
* Add a torrent using the raw torrent data
|
||||
* @param string $torrent_metainfo The raw, unencoded contents (metainfo) of a torrent
|
||||
* @param string $save_path Folder to save torrent in
|
||||
* @param array $extra_options Optional extra torrent options
|
||||
* @return mixed
|
||||
* @throws ClientException
|
||||
*/
|
||||
public function add_metainfo($torrent_metainfo, $save_path = '', $extra_options = array())
|
||||
{
|
||||
if (!empty($save_path)) {
|
||||
$extra_options['download-dir'] = $save_path;
|
||||
}
|
||||
$extra_options['metainfo'] = base64_encode($torrent_metainfo);
|
||||
|
||||
return $this->request("torrent-add", $extra_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 变更数据保存目录
|
||||
* Move local storage location
|
||||
*
|
||||
* Request arguments:
|
||||
string | value type & description
|
||||
---------------------------------+-------------------------------------------------
|
||||
"ids" | array torrent list, as described in 3.1
|
||||
"location" | string the new torrent location
|
||||
"move" | boolean if true, move from previous location.
|
||||
| otherwise, search "location" for files
|
||||
| (default: false)
|
||||
*
|
||||
* @param int|array $ids A list of transmission torrent ids
|
||||
* @param string $target_location The new storage location
|
||||
* @param boolean $move_existing_data Move existing data or scan new location for available data
|
||||
* @return mixed
|
||||
* @throws ClientException
|
||||
*/
|
||||
public function move($ids, $target_location, $move_existing_data = true)
|
||||
{
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
}
|
||||
$request = array(
|
||||
"ids" => $ids,
|
||||
"location" => $target_location,
|
||||
"move" => $move_existing_data
|
||||
);
|
||||
return $this->request("torrent-set-location", $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改种子文件或目录名称
|
||||
* Renaming a Torrent's Path
|
||||
*
|
||||
* For more information on the use of this function, see the transmission.h
|
||||
documentation of tr_torrentRenamePath(). In particular, note that if this
|
||||
call succeeds you'll want to update the torrent's "files" and "name" field
|
||||
with torrent-get.
|
||||
|
||||
Request arguments:
|
||||
|
||||
string | value type & description
|
||||
---------------------------------+-------------------------------------------------
|
||||
"ids" | array the torrent torrent list, as described in 3.1
|
||||
| (must only be 1 torrent)
|
||||
"path" | string the path to the file or folder that will be renamed
|
||||
"name" | string the file or folder's new name
|
||||
|
||||
Response arguments: "path", "name", and "id", holding the torrent ID integer
|
||||
*
|
||||
* @param int|array ids A 1-element list of transmission torrent ids
|
||||
* @param string path The path to the file or folder that will be renamed
|
||||
* @param string name The file or folder's new name
|
||||
* @return mixed
|
||||
* @throws ClientException
|
||||
*/
|
||||
public function rename($ids, $path, $name)
|
||||
{
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
}
|
||||
if (count($ids) !== 1) {
|
||||
throw new ClientException('A single id is accepted', self::E_INVALIDARG);
|
||||
}
|
||||
|
||||
$request = array(
|
||||
"ids" => $ids,
|
||||
"path" => $path,
|
||||
"name" => $name
|
||||
);
|
||||
return $this->request("torrent-rename-path", $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Session 请求
|
||||
* (4.1) Session 参数
|
||||
* string | value type | description
|
||||
* ---------------------------------+------------+-------------------------------------
|
||||
* "alt-speed-down" | number | max global download speed (KBps)
|
||||
* "alt-speed-enabled" | boolean | true means use the alt speeds
|
||||
* "alt-speed-time-begin" | number | when to turn on alt speeds (units: minutes after midnight)
|
||||
* "alt-speed-time-enabled" | boolean | true means the scheduled on/off times are used
|
||||
* "alt-speed-time-end" | number | when to turn off alt speeds (units: same)
|
||||
* "alt-speed-time-day" | number | what day(s) to turn on alt speeds (look at tr_sched_day)
|
||||
* "alt-speed-up" | number | max global upload speed (KBps)
|
||||
* "blocklist-url" | string | location of the blocklist to use for "blocklist-update"
|
||||
* "blocklist-enabled" | boolean | true means enabled
|
||||
* "blocklist-size" | number | number of rules in the blocklist
|
||||
* "cache-size-mb" | number | maximum size of the disk cache (MB)
|
||||
* "config-dir" | string | location of transmission's configuration directory
|
||||
* "download-dir" | string | default path to download torrents
|
||||
* "download-queue-size" | number | max number of torrents to download at once (see download-queue-enabled)
|
||||
* "download-queue-enabled" | boolean | if true, limit how many torrents can be downloaded at once
|
||||
* "dht-enabled" | boolean | true means allow dht in public torrents
|
||||
* "encryption" | string | "required", "preferred", "tolerated"
|
||||
* "idle-seeding-limit" | number | torrents we're seeding will be stopped if they're idle for this long
|
||||
* "idle-seeding-limit-enabled" | boolean | true if the seeding inactivity limit is honored by default
|
||||
* "incomplete-dir" | string | path for incomplete torrents, when enabled
|
||||
* "incomplete-dir-enabled" | boolean | true means keep torrents in incomplete-dir until done
|
||||
* "lpd-enabled" | boolean | true means allow Local Peer Discovery in public torrents
|
||||
* "peer-limit-global" | number | maximum global number of peers
|
||||
* "peer-limit-per-torrent" | number | maximum global number of peers
|
||||
* "pex-enabled" | boolean | true means allow pex in public torrents
|
||||
* "peer-port" | number | port number
|
||||
* "peer-port-random-on-start" | boolean | true means pick a random peer port on launch
|
||||
* "port-forwarding-enabled" | boolean | true means enabled
|
||||
* "queue-stalled-enabled" | boolean | whether or not to consider idle torrents as stalled
|
||||
* "queue-stalled-minutes" | number | torrents that are idle for N minuets aren't counted toward seed-queue-size or download-queue-size
|
||||
* "rename-partial-files" | boolean | true means append ".part" to incomplete files
|
||||
* "rpc-version" | number | the current RPC API version 当前RPC版本号
|
||||
* "rpc-version-minimum" | number | the minimum RPC API version supported 支持RPC的最小版本号
|
||||
* "script-torrent-done-filename" | string | filename of the script to run
|
||||
* "script-torrent-done-enabled" | boolean | whether or not to call the "done" script
|
||||
* "seedRatioLimit" | double | the default seed ratio for torrents to use
|
||||
* "seedRatioLimited" | boolean | true if seedRatioLimit is honored by default
|
||||
* "seed-queue-size" | number | max number of torrents to uploaded at once (see seed-queue-enabled)
|
||||
* "seed-queue-enabled" | boolean | if true, limit how many torrents can be uploaded at once
|
||||
* "speed-limit-down" | number | max global download speed (KBps)
|
||||
* "speed-limit-down-enabled" | boolean | true means enabled
|
||||
* "speed-limit-up" | number | max global upload speed (KBps)
|
||||
* "speed-limit-up-enabled" | boolean | true means enabled
|
||||
* "start-added-torrents" | boolean | true means added torrents will be started right away
|
||||
* "trash-original-torrent-files" | boolean | true means the .torrent file of added torrents will be deleted
|
||||
* "units" | object | see below
|
||||
* "utp-enabled" | boolean | true means allow utp
|
||||
* "version" | string | long version string "$version ($revision)"
|
||||
* ---------------------------------+------------+-----------------------------+
|
||||
* units | object containing: |
|
||||
+--------------+--------+------------------+
|
||||
| speed-units | array | 4 strings: KB/s, MB/s, GB/s, TB/s
|
||||
| speed-bytes | number | number of bytes in a KB (1000 for kB; 1024 for KiB)
|
||||
| size-units | array | 4 strings: KB/s, MB/s, GB/s, TB/s
|
||||
| size-bytes | number | number of bytes in a KB (1000 for kB; 1024 for KiB)
|
||||
| memory-units | array | 4 strings: KB/s, MB/s, GB/s, TB/s
|
||||
| memory-bytes | number | number of bytes in a KB (1000 for kB; 1024 for KiB)
|
||||
+--------------+--------+------------------+
|
||||
*
|
||||
* 当前RPC版本号"rpc-version" indicates the RPC interface version supported by the RPC server.
|
||||
* It is incremented when a new version of Transmission changes the RPC interface.
|
||||
*
|
||||
* 支持RPC的最小版本号"rpc-version-minimum" indicates the oldest API supported by the RPC server.
|
||||
* It is changes when a new version of Transmission changes the RPC interface
|
||||
* in a way that is not backwards compatible. There are no plans for this
|
||||
* to be common behavior.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 获取会话
|
||||
* Retrieve all session variables
|
||||
* Method name: "session-get"
|
||||
Request arguments: an optional "fields" array of keys (see 4.1)
|
||||
Response arguments: key/value pairs matching the request's "fields"
|
||||
argument if present, or all supported fields (see 4.1) otherwise.
|
||||
*
|
||||
* @returns array of session information
|
||||
* @throws ClientException
|
||||
*/
|
||||
public function sessionGet()
|
||||
{
|
||||
return $this->request("session-get", array());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置会话
|
||||
* Set session variable(s)
|
||||
* Method name: "session-set"
|
||||
Request arguments: one or more of 4.1's arguments, except: "blocklist-size",
|
||||
"config-dir", "rpc-version", "rpc-version-minimum",
|
||||
"version", and "session-id"
|
||||
Response arguments: none
|
||||
*
|
||||
* @param array of session variables to set
|
||||
* @return mixed
|
||||
* @throws ClientException
|
||||
*/
|
||||
public function sessionSet($arguments)
|
||||
{
|
||||
return $this->request("session-set", $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* 会话状态统计
|
||||
* Retrieve session statistics
|
||||
*
|
||||
* Method name: "session-stats"
|
||||
Request arguments: none
|
||||
Response arguments:
|
||||
|
||||
string | value type
|
||||
---------------------------+-------------------------------------------------
|
||||
"activeTorrentCount" | number
|
||||
"downloadSpeed" | number
|
||||
"pausedTorrentCount" | number
|
||||
"torrentCount" | number
|
||||
"uploadSpeed" | number
|
||||
---------------------------+-------------------------------+
|
||||
"cumulative-stats" | object, containing: |
|
||||
+------------------+------------+
|
||||
| uploadedBytes | number | tr_session_stats
|
||||
| downloadedBytes | number | tr_session_stats
|
||||
| filesAdded | number | tr_session_stats
|
||||
| sessionCount | number | tr_session_stats
|
||||
| secondsActive | number | tr_session_stats
|
||||
---------------------------+-------------------------------+
|
||||
"current-stats" | object, containing: |
|
||||
+------------------+------------+
|
||||
| uploadedBytes | number | tr_session_stats
|
||||
| downloadedBytes | number | tr_session_stats
|
||||
| filesAdded | number | tr_session_stats
|
||||
| sessionCount | number | tr_session_stats
|
||||
| secondsActive | number | tr_session_stats
|
||||
*
|
||||
* @returns array of statistics
|
||||
* @throws ClientException
|
||||
*/
|
||||
public function sessionStats()
|
||||
{
|
||||
return $this->request("session-stats", array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the interpretation of the torrent status
|
||||
*
|
||||
* @param int The integer "torrent status"
|
||||
* @returns string The translated meaning
|
||||
* @return string
|
||||
*/
|
||||
public function getStatusString($intstatus)
|
||||
{
|
||||
if ($this->rpc_version < 14) {
|
||||
if ($intstatus == self::RPC_LT_14_TR_STATUS_CHECK_WAIT) {
|
||||
return "Waiting to verify local files";
|
||||
}
|
||||
if ($intstatus == self::RPC_LT_14_TR_STATUS_CHECK) {
|
||||
return "Verifying local files";
|
||||
}
|
||||
if ($intstatus == self::RPC_LT_14_TR_STATUS_DOWNLOAD) {
|
||||
return "Downloading";
|
||||
}
|
||||
if ($intstatus == self::RPC_LT_14_TR_STATUS_SEED) {
|
||||
return "Seeding";
|
||||
}
|
||||
if ($intstatus == self::RPC_LT_14_TR_STATUS_STOPPED) {
|
||||
return "Stopped";
|
||||
}
|
||||
} else {
|
||||
if ($intstatus == self::TR_STATUS_CHECK_WAIT) {
|
||||
return "Waiting to verify local files";
|
||||
}
|
||||
if ($intstatus == self::TR_STATUS_CHECK) {
|
||||
return "Verifying local files";
|
||||
}
|
||||
if ($intstatus == self::TR_STATUS_DOWNLOAD) {
|
||||
return "Downloading";
|
||||
}
|
||||
if ($intstatus == self::TR_STATUS_SEED) {
|
||||
return "Seeding";
|
||||
}
|
||||
if ($intstatus == self::TR_STATUS_STOPPED) {
|
||||
return "Stopped";
|
||||
}
|
||||
if ($intstatus == self::TR_STATUS_SEED_WAIT) {
|
||||
return "Queued for seeding";
|
||||
}
|
||||
if ($intstatus == self::TR_STATUS_DOWNLOAD_WAIT) {
|
||||
return "Queued for download";
|
||||
}
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
* 对请求数据预处理
|
||||
* Clean up the request array. Removes any empty fields from the request
|
||||
*
|
||||
* @param array array The request associative array to clean
|
||||
* @returns array The cleaned array
|
||||
* @return array|null
|
||||
*/
|
||||
protected function cleanRequestData($array)
|
||||
{
|
||||
if (!is_array($array) || count($array) == 0) {
|
||||
return null;
|
||||
}
|
||||
setlocale(LC_NUMERIC, 'en_US.utf8'); // Override the locale - if the system locale is wrong, then 12.34 will encode as 12,34 which is invalid JSON
|
||||
foreach ($array as $index => $value) {
|
||||
if (is_object($value)) {
|
||||
$array[$index] = $value->toArray();
|
||||
} // Convert objects to arrays so they can be JSON encoded
|
||||
if (is_array($value)) {
|
||||
$array[$index] = $this->cleanRequestData($value);
|
||||
} // Recursion
|
||||
if (empty($value) && ($value !== 0 || $value !== false)) { // Remove empty members
|
||||
unset($array[$index]);
|
||||
continue; // Skip the rest of the tests - they may re-add the element.
|
||||
}
|
||||
if (is_numeric($value)) {
|
||||
$array[$index] = $value + 0;
|
||||
} // Force type-casting for proper JSON encoding (+0 is a cheap way to maintain int/float/etc)
|
||||
if (is_bool($value)) {
|
||||
$array[$index] = ($value ? 1 : 0);
|
||||
} // Store boolean values as 0 or 1
|
||||
if (is_string($value)) {
|
||||
$type = mb_detect_encoding($value, 'auto');
|
||||
if ($type !== 'UTF-8') {
|
||||
$array[$index] = mb_convert_encoding($value, 'UTF-8');
|
||||
}
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前Curl对象
|
||||
* @return Curl
|
||||
*/
|
||||
public function curl()
|
||||
{
|
||||
return $this->curl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行 rpc 请求
|
||||
* @param string $method 请求类型/方法, 详见 $this->allowMethods
|
||||
* @param array $arguments 附加参数, 可选
|
||||
* @return array
|
||||
* @throws ClientException
|
||||
*/
|
||||
protected function request($method, $arguments = array())
|
||||
{
|
||||
if (!is_scalar($method)) {
|
||||
throw new ClientException('Method name has no scalar value', self::E_INVALIDARG);
|
||||
}
|
||||
if (!is_array($arguments)) {
|
||||
throw new ClientException('Arguments must be given as array', self::E_INVALIDARG);
|
||||
}
|
||||
|
||||
$arguments = $this->cleanRequestData($arguments); // Sanitize input
|
||||
|
||||
// Grab the X-Transmission-Session-Id if we don't have it already
|
||||
if (!$this->session_id) {
|
||||
if (!$this->GetSessionID()) {
|
||||
throw new ClientException('Unable to acquire X-Transmission-Session-Id', self::E_SESSIONID);
|
||||
}
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'method' => $method,
|
||||
'arguments' => $arguments
|
||||
);
|
||||
$header = array(
|
||||
'Content-Type' => 'application/json',
|
||||
'Authorization' => 'Basic ' . base64_encode(sprintf("%s:%s", $this->username, $this->password)),
|
||||
'X-Transmission-Session-Id' => $this->session_id
|
||||
);
|
||||
$curl = $this->curl;
|
||||
if (stripos($this->url, 'https://') === 0) {
|
||||
$curl->setOpt(CURLOPT_SSL_VERIFYPEER, false); // 禁止验证证书
|
||||
$curl->setOpt(CURLOPT_SSL_VERIFYHOST, 2); // 不检查证书
|
||||
}
|
||||
foreach ($header as $key => $value) {
|
||||
$curl->setHeader($key, $value);
|
||||
}
|
||||
$curl->setUserAgent(self::UA);
|
||||
$curl->setBasicAuthentication($this->username, $this->password);
|
||||
$curl->post($this->url, $data, true);
|
||||
$content = $curl->response;
|
||||
|
||||
if ($this->debug) {
|
||||
var_dump($curl->request_headers);
|
||||
var_dump($curl->response_headers);
|
||||
var_dump($curl->response);
|
||||
}
|
||||
|
||||
if (!$content) {
|
||||
$content = array('result' => 'failed');
|
||||
}
|
||||
return json_decode($content, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an empty GET on the Transmission RPC to get the X-Transmission-Session-Id
|
||||
* and store it in $this->session_id
|
||||
* @return string
|
||||
*/
|
||||
public function GetSessionID()
|
||||
{
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $this->url);
|
||||
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
||||
curl_setopt($ch, CURLOPT_USERPWD, $this->username.':'.$this->password);
|
||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
|
||||
$content = curl_exec($ch);
|
||||
$error_code = curl_errno($ch);
|
||||
$error_message = curl_error($ch);
|
||||
$http_status_code = intval(curl_getinfo($ch, CURLINFO_HTTP_CODE));
|
||||
|
||||
if ($this->debug) {
|
||||
var_dump($http_status_code);
|
||||
var_dump($error_message);
|
||||
var_dump($error_code);
|
||||
var_dump($content);
|
||||
}
|
||||
|
||||
// 401 Invalid username/password
|
||||
// 409 成功
|
||||
// 其他 Unexpected response from Transmission RPC
|
||||
curl_close($ch);
|
||||
if($content && preg_match("/<code>X-Transmission-Session-Id: (.*?)<\/code>/", $content, $match)) {
|
||||
$this->session_id = isset($match[1]) ? $match[1] : null;
|
||||
}
|
||||
|
||||
return $this->session_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 抽象方法,子类实现
|
||||
* 获取下载器链接状态
|
||||
* @throws ClientException
|
||||
*/
|
||||
public function status()
|
||||
{
|
||||
$rs = $this->sessionStats();
|
||||
return isset($rs['result']) ? $rs['result'] : 'error';
|
||||
}
|
||||
|
||||
/**
|
||||
* 抽象方法,子类实现
|
||||
* 获取所有种子的列表
|
||||
* @param array $torrentList
|
||||
* @return array
|
||||
* array(
|
||||
* 'hash' => string json,
|
||||
* 'sha1' => string,
|
||||
* 'hashString '=> array
|
||||
* )
|
||||
* @throws ClientException
|
||||
*/
|
||||
public function all(&$torrentList = array())
|
||||
{
|
||||
$ids = array();
|
||||
$fields = array( "id", "status", "name", "hashString", "downloadDir", "torrentFile" );
|
||||
$res = $this->get($ids, $fields);
|
||||
if (isset($res['result']) && $res['result'] === 'success') {
|
||||
// 成功
|
||||
} else {
|
||||
// 失败
|
||||
echo "从客户端获取种子列表失败,可能transmission暂时无响应,请稍后重试!".PHP_EOL;
|
||||
return array();
|
||||
}
|
||||
if (empty($res['arguments']['torrents'])) {
|
||||
echo "从客户端未获取到数据,请稍后重试!".PHP_EOL;
|
||||
return array();
|
||||
}
|
||||
$res = $res['arguments']['torrents'];
|
||||
// 过滤,只保留正常做种
|
||||
$res = array_filter($res, function ($v) {
|
||||
return isset($v['status']) && $v['status'] === 6;
|
||||
}, ARRAY_FILTER_USE_BOTH);
|
||||
|
||||
if (empty($res)) {
|
||||
echo "从客户端未获取到正常做种数据,请多保种,然后重试!".PHP_EOL;
|
||||
return array();
|
||||
}
|
||||
// 提取数组:hashString
|
||||
$info_hash = array_column($res, 'hashString');
|
||||
// 升序排序
|
||||
sort($info_hash);
|
||||
$json = json_encode($info_hash, JSON_UNESCAPED_UNICODE);
|
||||
// 去重 应该从文件读入,防止重复提交
|
||||
$sha1 = sha1($json);
|
||||
// 组装返回数据
|
||||
$hashArray['hash'] = $json;
|
||||
$hashArray['sha1'] = $sha1;
|
||||
// 变换数组:hashString为键名、目录为键值
|
||||
$hashArray['hashString'] = array_column($res, "downloadDir", 'hashString');
|
||||
$torrentList = array_column($res, null, 'hashString');
|
||||
return $hashArray;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user