update webman

This commit is contained in:
david 2022-10-03 11:03:11 +08:00
parent a0cd0704e6
commit fb8e6a0234
553 changed files with 45100 additions and 6651 deletions

11
app/Request.php Normal file
View File

@ -0,0 +1,11 @@
<?php
namespace app;
/**
* Class Request
* @package support
*/
class Request extends \support\Request
{
}

View File

@ -1,4 +1,5 @@
<?php
namespace app\common;
/**
@ -60,6 +61,18 @@ class Config
return $writeLen === 0 ? false : $writeLen;
}
/**
* 创建文件路径
* @param string $name
* @param string $type
* @return string
*/
public static function createFilePath(string $name = '', string $type = 'array'): string
{
$ext = self::extMap[$type] ?? self::extMap['object'];
return db_path() . DIRECTORY_SEPARATOR . $name . $ext;
}
/**
* 读取配置
* @param string $filename 文件名
@ -99,11 +112,11 @@ class Config
/**
* 删除配置
* @param string $name
* @param string|null $name
* @param bool $absolutePath
* @return bool
*/
public static function delete(string $name, bool $absolutePath = false): bool
public static function delete(?string $name, bool $absolutePath = false): bool
{
if ($name === null || $name === '') {
return false;
@ -115,16 +128,4 @@ class Config
}
return true;
}
/**
* 创建文件路径
* @param string $name
* @param string $type
* @return string
*/
public static function createFilePath(string $name = '', string $type = 'array'):string
{
$ext = self::extMap[$type] ?? self::extMap['object'];
return db_path() . DIRECTORY_SEPARATOR . $name . $ext;
}
}

View File

@ -1,4 +1,5 @@
<?php
namespace app\common;
/**

View File

@ -1,4 +1,5 @@
<?php
namespace app\common;
/**

View File

@ -1,4 +1,5 @@
<?php
namespace app\common\components;
use app\common\Constant;
@ -33,6 +34,18 @@ class Curl
{
}
/**
* GET请求
* @param string $url
* @param array $data 数据
* @param bool $reset 是否重置Curl(默认true)
* @return ICurl
*/
public static function get(string $url, array $data = array(), bool $reset = true): ICurl
{
return static::one($reset)->get($url, $data);
}
/**
* 单例
* @param bool $reset
@ -58,18 +71,6 @@ class Curl
return self::$_instance;
}
/**
* GET请求
* @param string $url
* @param array $data 数据
* @param bool $reset 是否重置Curl(默认true)
* @return ICurl
*/
public static function get(string $url, array $data = array(), bool $reset = true): ICurl
{
return static::one($reset)->get($url, $data);
}
/**
* POST请求
* @param string $url

View File

@ -1,5 +1,6 @@
<?php
declare(strict_types=1);
namespace app\common\event;
use Throwable;
@ -8,7 +9,7 @@ use Throwable;
* 事件调度器
* Class EventDispatcher
*/
class EventDispatcher implements ListenerProviderInterface, EventDispatcherInterface
class EventDispatcher
{
/**
* @var EventListenerInterface
@ -17,9 +18,9 @@ class EventDispatcher implements ListenerProviderInterface, EventDispatcherInter
/**
* EventDispatcher constructor.
* @param EventListenerInterface ...$listeners
* @param EventListenerInterface[] $listeners
*/
public function __construct($listeners)
public function __construct(array $listeners)
{
$eventListeners = [];
foreach ($listeners as $listener) {
@ -30,26 +31,6 @@ class EventDispatcher implements ListenerProviderInterface, EventDispatcherInter
$this->eventListeners = $eventListeners;
}
/**
* 检出当前事件的所有监听器
*
* @param object $event
* An event for which to return the relevant listeners.
* @return iterable[callable]
* An iterable (array, iterator, or generator) of callables. Each
* callable MUST be type-compatible with $event.
*/
public function getListenersForEvent(object $event): iterable
{
$class = get_class($event);
$listeners = $this->eventListeners[$class] ?? [];
$iterable = [];
foreach ($listeners as $listener) {
$iterable[] = [$listener, 'process'];
}
return $iterable;
}
/**
* 派发当前事件到所有监听器的process处理方法
*
@ -71,4 +52,24 @@ class EventDispatcher implements ListenerProviderInterface, EventDispatcherInter
}
return $event;
}
/**
* 检出当前事件的所有监听器
*
* @param object $event
* An event for which to return the relevant listeners.
* @return iterable[callable]
* An iterable (array, iterator, or generator) of callables. Each
* callable MUST be type-compatible with $event.
*/
public function getListenersForEvent(object $event): iterable
{
$class = get_class($event);
$listeners = $this->eventListeners[$class] ?? [];
$iterable = [];
foreach ($listeners as $listener) {
$iterable[] = [$listener, 'process'];
}
return $iterable;
}
}

View File

@ -1,21 +0,0 @@
<?php
declare(strict_types=1);
namespace app\common\event;
/**
* Defines a dispatcher for events.
*/
interface EventDispatcherInterface
{
/**
* Provide all relevant listeners with an event to process.
*
* @param object $event
* The object to process.
*
* @return object
* The Event that was passed, now modified by listeners.
*/
public function dispatch(object $event);
}

View File

@ -1,5 +1,6 @@
<?php
declare(strict_types=1);
namespace app\common\event;
/**

View File

@ -1,18 +0,0 @@
<?php
declare(strict_types=1);
namespace app\common\event;
/**
* Mapper from an event to the listeners that are applicable to that event.
*/
interface ListenerProviderInterface
{
/**
* @param object $event
* An event for which to return the relevant listeners.
* @return iterable[callable]
* An iterable (array, iterator, or generator) of callables. Each
* callable MUST be type-compatible with $event.
*/
public function getListenersForEvent(object $event) : iterable;
}

View File

@ -1,5 +1,6 @@
<?php
declare(strict_types=1);
namespace app\common\event;
/**

View File

@ -1,4 +1,5 @@
<?php
namespace app\common\exception;
use Exception;

View File

@ -1,4 +1,5 @@
<?php
namespace app\common\exception;
use Throwable;

View File

@ -1,4 +1,5 @@
<?php
namespace app\controller;
use support\Request;

View File

@ -1,7 +1,7 @@
<?php
namespace app\controller;
use app\common\exception\BusinessException;
use app\common\Constant;
use app\domain\Users as domainUsers;
use support\Request;

View File

@ -1,4 +1,5 @@
<?php
namespace app\controller;
use app\domain\Users as domainUsers;

View File

@ -1,11 +1,10 @@
<?php
namespace app\controller;
use support\Request;
use support\Response;
use app\common\exception\BusinessException;
use app\common\Config as Conf;
use app\common\Constant;
use app\domain\Config;
use IYUU\Reseed\AutoReseed;

View File

@ -1,4 +1,5 @@
<?php
namespace app\controller;
use support\Request;

View File

@ -1,4 +1,5 @@
<?php
namespace app\domain;
/**

View File

@ -1,4 +1,5 @@
<?php
namespace app\domain\Command;
use app\domain\CommandInterface;

View File

@ -1,4 +1,5 @@
<?php
namespace app\domain\Command;
use app\domain\CommandInterface;

View File

@ -1,4 +1,5 @@
<?php
namespace app\domain\Command;
use app\domain\CommandInterface;

View File

@ -1,4 +1,5 @@
<?php
namespace app\domain\Command;
use app\domain\CommandInterface;

View File

@ -1,4 +1,5 @@
<?php
namespace app\domain;
/**

View File

@ -1,4 +1,5 @@
<?php
namespace app\domain;
use app\common\Config as Conf;
@ -127,6 +128,19 @@ class Config
return $rs;
}
/**
* 排除字段
* @param $data
*/
protected static function createDataExcludeKeys(&$data)
{
if (is_array($data)) {
foreach ([Constant::config_filename, Constant::action] as $key) {
unset($data[$key]);
}
}
}
/**
* 简单操作的增删改查
* @param string $config_filename
@ -141,19 +155,6 @@ class Config
return Constant::RS;
}
/**
* 排除字段
* @param $data
*/
protected static function createDataExcludeKeys(&$data)
{
if (is_array($data)) {
foreach ([Constant::config_filename, Constant::action] as $key) {
unset($data[$key]);
}
}
}
/**
* IYUU密钥
* @return array
@ -181,15 +182,6 @@ class Config
return Conf::get(self::filename['clients'], Constant::config_format, []);
}
/**
* 计划任务
* @return array
*/
public static function getCrontab():array
{
return Conf::get(self::filename['crontab'], Constant::config_format, []);
}
/**
* 目录
* @return array
@ -199,15 +191,6 @@ class Config
return Conf::get(self::filename['folder'], Constant::config_format, []);
}
/**
* 用户拥有的站点
* @return array
*/
public static function getUserSites():array
{
return Conf::get(self::filename['user_sites'], Constant::config_format, []);
}
/**
* 所有站点
* @return array
@ -246,6 +229,15 @@ class Config
return array_key_exists($uuid, $cron) ? $cron[$uuid] : [];
}
/**
* 计划任务
* @return array
*/
public static function getCrontab(): array
{
return Conf::get(self::filename['crontab'], Constant::config_format, []);
}
/**
* 禁用用户已经配置过的站点
* @param array $sites
@ -262,6 +254,15 @@ class Config
return $sites;
}
/**
* 用户拥有的站点
* @return array
*/
public static function getUserSites(): array
{
return Conf::get(self::filename['user_sites'], Constant::config_format, []);
}
/**
* 禁用用户未配置的站点
* @param array $sites

View File

@ -1,4 +1,5 @@
<?php
namespace app\domain\ConfigParser;
use app\domain\ConfigParserInterface;
@ -10,12 +11,13 @@ class Move implements ConfigParserInterface
* 路径分隔符
*/
const Delimiter = '{#**#}';
/**
* 根据参数,解析转移做种的运行时配置
* @param string $uuid
* @return array
*/
public static function parser($uuid = ''):array
public static function parser(string $uuid = ''): array
{
$rs = [
'clients' => [],

View File

@ -1,4 +1,5 @@
<?php
namespace app\domain\ConfigParser;
use app\domain\ConfigParserInterface;
@ -18,7 +19,7 @@ class Reseed implements ConfigParserInterface
* @param string $uuid
* @return array
*/
public static function parser($uuid = ''):array
public static function parser(string $uuid = ''): array
{
$rs = [
'sites' => [],
@ -65,6 +66,16 @@ class Reseed implements ConfigParserInterface
return $rs;
}
/**
* 清理辅种缓存
* @return bool
*/
public static function clearReseedCache(): bool
{
$dir = self::getReseedCachePath();
return !is_dir($dir) || IFile::rmdir($dir, true);
}
/**
* 获取辅种缓存的存放路径
* @return string
@ -74,6 +85,16 @@ class Reseed implements ConfigParserInterface
return runtime_path() . DIRECTORY_SEPARATOR . 'torrent' . DIRECTORY_SEPARATOR . 'cachehash';
}
/**
* 清理转移缓存
* @return bool
*/
public static function clearMoveCache(): bool
{
$dir = self::getMoveCachePath();
return !is_dir($dir) || IFile::rmdir($dir, true);
}
/**
* 获取转移缓存的存放路径
* @return string
@ -82,24 +103,4 @@ class Reseed implements ConfigParserInterface
{
return runtime_path() . DIRECTORY_SEPARATOR . 'torrent' . DIRECTORY_SEPARATOR . 'cachemove';
}
/**
* 清理辅种缓存
* @return bool
*/
public static function clearReseedCache():bool
{
$dir = self::getReseedCachePath();
return is_dir($dir) ? IFile::rmdir($dir, true) : true;
}
/**
* 清理转移缓存
* @return bool
*/
public static function clearMoveCache():bool
{
$dir = self::getMoveCachePath();
return is_dir($dir) ? IFile::rmdir($dir, true) : true;
}
}

View File

@ -1,4 +1,5 @@
<?php
namespace app\domain\ConfigParser;
use app\domain\ConfigParserInterface;
@ -11,7 +12,7 @@ class Rss implements ConfigParserInterface
* @param string $uuid
* @return array
*/
public static function parser($uuid = ''):array
public static function parser(string $uuid = ''): array
{
$rs = [
'site' => [],

View File

@ -1,4 +1,5 @@
<?php
namespace app\domain\ConfigParser;
use app\domain\ConfigParserInterface;
@ -11,7 +12,7 @@ class Spiders implements ConfigParserInterface
* @param string $uuid
* @return array
*/
public static function parser($uuid = ''):array
public static function parser(string $uuid = ''): array
{
return Rss::parser($uuid);
}

View File

@ -1,4 +1,5 @@
<?php
namespace app\domain;
/**

View File

@ -1,4 +1,5 @@
<?php
namespace app\domain;
use app\common\Config as Conf;
@ -35,24 +36,22 @@ class Crontab
const pid_suffix = '.pid';
// 管理员用户名,用户名密码都为空字符串时说明不用验证
public static $adminName = '';
// 管理员密码,用户名密码都为空字符串时说明不用验证
public static $adminPassword = '';
/**
* linux系统的crontab任务永远在第1秒执行,且添加定时任务后的1分钟之内是不会执行该任务(即使语法上完全满足)
* @var mixed
*/
const cron_minute = '%s %s %s %s %s';
const cron_second = '%s %s %s %s %s %s';
// 管理员密码,用户名密码都为空字符串时说明不用验证
const cron_second = '%s %s %s %s %s %s';
/**
* where可能的值
*/
const WHERE = [
'day', 'day_n', 'hour', 'hour_n', 'minute', 'minute_n', 'second', 'second_n', 'week', 'month'
];
public static $adminName = '';
public static $adminPassword = '';
/**
* 构造方法
@ -97,24 +96,6 @@ class Crontab
}
}
/**
* 删除计划任务 钩子
* @param string $uuid uuid或文件名
* @return bool
*/
public static function deleteHock(string $uuid):bool
{
if (empty($uuid)) {
return false;
}
$file_name = self::getFilePath($uuid, self::cron_dir, self::cron_suffix);
clearstatcache();
if (is_file($file_name)) {
return @unlink($file_name);
}
return true;
}
/**
* 转换为Linux的Crontab语法
* @param array $param 数据
@ -140,12 +121,12 @@ class Crontab
public static function parseCron(array $param): string
{
$cron = '';
$where = isset($param['where']) ? $param['where'] : null; //条件
$weeks = isset($param['weeks']) ? $param['weeks'] : null; //星期
$day = isset($param['day']) ? $param['day'] : null; //天
$hour = isset($param['hour']) ? $param['hour'] : null; //时
$minute= isset($param['minute']) ? $param['minute'] : null; //分
$second= isset($param['second']) ? $param['second'] : '*'; //秒
$where = $param['where'] ?? null; //条件
$weeks = $param['weeks'] ?? null; //星期
$day = $param['day'] ?? null; //天
$hour = $param['hour'] ?? null; //时
$minute = $param['minute'] ?? null; //分
$second = $param['second'] ?? '*'; //秒
if ($where === null || !in_array($where, self::WHERE)) {
throw new \InvalidArgumentException('Invalid cron param where');
}
@ -198,17 +179,6 @@ class Crontab
return Command::parse($param);
}
/**
* 创建计划任务文件
* @param string $filename 文件的完整路径
* @param mixed $param 数据
* @return bool|int 结果
*/
public static function writeCronFile($filename, $param)
{
return Conf::set($filename, $param, 'json', true);
}
/**
* 获取文件路径
* @param string $filename 文件名
@ -216,7 +186,7 @@ class Crontab
* @param string $suffix 扩展名
* @return string 文件的完整路径
*/
public static function getFilePath($filename = '', $dir = 'cron_dir', $suffix = '.crontab'):string
public static function getFilePath(string $filename = '', string $dir = 'cron_dir', string $suffix = '.crontab'): string
{
clearstatcache();
$_dir = cron_path() . DIRECTORY_SEPARATOR . $dir;
@ -225,12 +195,41 @@ class Crontab
return $_dir . DIRECTORY_SEPARATOR . $filename . $suffix;
}
/**
* 创建计划任务文件
* @param string $filename 文件的完整路径
* @param mixed $param 数据
* @return bool|int 结果
*/
public static function writeCronFile(string $filename, $param)
{
return Conf::set($filename, $param, 'json', true);
}
/**
* 删除计划任务 钩子
* @param string $uuid uuid或文件名
* @return bool
*/
public static function deleteHock(string $uuid): bool
{
if (empty($uuid)) {
return false;
}
$file_name = self::getFilePath($uuid, self::cron_dir, self::cron_suffix);
clearstatcache();
if (is_file($file_name)) {
return @unlink($file_name);
}
return true;
}
/**
* 根据任务名字拼接lock文件路径
* @param string $filename
* @return string
*/
public static function getLockFile($filename = ''):string
public static function getLockFile(string $filename = ''): string
{
return self::getFilePath($filename, self::lock_dir, self::lock_suffix);
}
@ -240,21 +239,11 @@ class Crontab
* @param string $filename
* @return string
*/
public static function getPidFile($filename = ''):string
public static function getPidFile(string $filename = ''): string
{
return self::getFilePath($filename, self::pid_dir, self::pid_suffix);
}
/**
* 拼接任务log文件的完整路径
* @param string $filename
* @return string
*/
public static function getLogFile($filename = ''):string
{
return self::getFilePath($filename, self::log_dir, '.log');
}
/**
* 根据uuid运行任务
* @param string $uuid
@ -273,14 +262,33 @@ class Crontab
}
/**
* 读取计划任务的日志
* @param string $uuid
* @return string
* 异步执行命令
* @descr 原理为php的程序执行函数后台执行
* @param string $cmd 任务执行的命令
* @param string $uuid 任务的UUID通常作为唯一的日志文件名
*/
public static function readLogs(string $uuid = ''):string
public static function execute(string $cmd = '', string $uuid = '')
{
$logFile = self::getLogFile($uuid);
return Conf::get($logFile, 'raw', '', true);
// 清理上次的日志
self::clearLogs($uuid);
// 运行命令
if (DIRECTORY_SEPARATOR === '\\') {
pclose(popen('start /B ' . $cmd . ' >> ' . $logFile, 'r'));
} else {
pclose(popen($cmd . ' >> ' . $logFile . ' 2>&1 &', 'r'));
//exec($cmd.' >> '.$logFile.' 2>&1 &');
}
}
/**
* 拼接任务log文件的完整路径
* @param string $filename
* @return string
*/
public static function getLogFile(string $filename = ''): string
{
return self::getFilePath($filename, self::log_dir, '.log');
}
/**
@ -295,6 +303,17 @@ class Crontab
return is_bool($ret) ? $ret : ($ret >= 10);
}
/**
* 读取计划任务的日志
* @param string $uuid
* @return string
*/
public static function readLogs(string $uuid = ''): string
{
$logFile = self::getLogFile($uuid);
return Conf::get($logFile, 'raw', '', true);
}
/**
* 清理所有计划任务的日志
* @return int
@ -311,24 +330,4 @@ class Crontab
return $count;
}
/**
* 异步执行命令
* @descr 原理为php的程序执行函数后台执行
* @param string $cmd 任务执行的命令
* @param string $uuid 任务的UUID通常作为唯一的日志文件名
*/
public static function execute($cmd = '', $uuid = '')
{
$logFile = self::getLogFile($uuid);
// 清理上次的日志
self::clearLogs($uuid);
// 运行命令
if (DIRECTORY_SEPARATOR === '\\') {
pclose(popen('start /B '.$cmd.' >> '.$logFile, 'r'));
} else {
pclose(popen($cmd.' >> '.$logFile.' 2>&1 &', 'r'));
//exec($cmd.' >> '.$logFile.' 2>&1 &');
}
}
}

View File

@ -1,4 +1,5 @@
<?php
namespace app\domain;
use support\Request;
@ -24,6 +25,45 @@ class Users
return $session->has(Constant::Session_Token_Key);
}
/**
* 用户绑定
* @descr 接口地址 https://api.iyuu.cn/index.php?s=App.User.Login
* 接口文档 https://api.iyuu.cn/docs.php?service=App.User.Login&detail=1&type=fold
* @param string $token
* @param Request $request
* @return array
*/
public static function bindToken(string $token, Request $request): array
{
$curl = Curl::one();
$url = Constant::API_BASE . Constant::API['login'];
$data = [
'token' => $token,
'id' => $request->post('id') + 0,
'passkey' => sha1($request->post('passkey')), // 避免泄露用户密钥passkey
'site' => $request->post('site'),
];
$res = $curl->get($url, $data);
$rs = json_decode($res->response, true);
if (empty($res->response) || empty($rs) || !is_array($rs)) {
$rs = Constant::RS;
$rs['ret'] = 500;
$rs['msg'] = "用户绑定出错,无法访问{$url}接口请检查本地网络或重新创建容器网络模式改为HOST模式。";
return $rs;
}
if (isset($rs['ret']) && ($rs['ret'] === 200) && isset($rs['data']['success']) && $rs['data']['success']) {
//绑定成功
return self::checkToken($token, $request);
} else {
//绑定失败
$rs['ret'] = 401;
$msg = !empty($rs['msg']) ? $rs['msg'] : '远端服务器无响应,请稍后重试!';
$msg = !empty($rs['data']['errmsg']) ? $rs['data']['errmsg'] : $msg;
$rs['msg'] = $msg;
return $rs;
}
}
/**
* 检查token及绑定状态
* - 接口api.iyuu.cn返回的信息原样返回给前端
@ -69,45 +109,6 @@ class Users
return $rs;
}
/**
* 用户绑定
* @descr 接口地址 https://api.iyuu.cn/index.php?s=App.User.Login
* 接口文档 https://api.iyuu.cn/docs.php?service=App.User.Login&detail=1&type=fold
* @param string $token
* @param Request $request
* @return array
*/
public static function bindToken(string $token, Request $request):array
{
$curl = Curl::one();
$url = Constant::API_BASE . Constant::API['login'];
$data = [
'token' => $token,
'id' => $request->post('id') + 0,
'passkey'=> sha1($request->post('passkey')), // 避免泄露用户密钥passkey
'site' => $request->post('site'),
];
$res = $curl->get($url, $data);
$rs = json_decode($res->response, true);
if (empty($res->response) || empty($rs) || !is_array($rs)) {
$rs = Constant::RS;
$rs['ret'] = 500;
$rs['msg'] = "用户绑定出错,无法访问{$url}接口请检查本地网络或重新创建容器网络模式改为HOST模式。";
return $rs;
}
if (isset($rs['ret']) && ($rs['ret'] === 200) && isset($rs['data']['success']) && $rs['data']['success']) {
//绑定成功
return self::checkToken($token, $request);
} else {
//绑定失败
$rs['ret'] = 401;
$msg = !empty($rs['msg']) ? $rs['msg'] : '远端服务器无响应,请稍后重试!';
$msg = !empty($rs['data']['errmsg']) ? $rs['data']['errmsg'] : $msg;
$rs['msg'] = $msg;
return $rs;
}
}
/**
* 验证用户输入的密码
* @param Request $request
@ -134,6 +135,15 @@ class Users
return true;
}
/**
* 用户特征文件名
* @return string
*/
public static function getUserProfileName(): string
{
return 'userProfile';
}
/**
* 设置用户密码
* @param string $password
@ -170,13 +180,4 @@ class Users
{
return md5($salt . $password . $salt);
}
/**
* 用户特征文件名
* @return string
*/
public static function getUserProfileName():string
{
return 'userProfile';
}
}

View File

@ -1,4 +1,9 @@
<?php
/**
* 自定义函数
* 【载入时机】worker子进程
*/
use app\common\components\Curl as ICurl;
use app\domain\Config as domainConfig;

114
app/helpers.php Normal file
View File

@ -0,0 +1,114 @@
<?php
/**
* 自定义函数
* 【载入时机】composer.json
*/
/**
* 数据目录
* @return string
*/
function db_path(): string
{
return base_path() . DIRECTORY_SEPARATOR . 'db';
}
/**
* 计划任务目录
*/
function cron_path(): string
{
return runtime_path() . DIRECTORY_SEPARATOR . 'crontab';
}
if (!function_exists('env')) {
/**
* @param $key
* @param null $default
* @return array|bool|string|null
*/
function env($key, $default = null)
{
$value = getenv($key);
if ($value === false) {
return $default;
}
switch (strtolower($value)) {
case 'true':
case '(true)':
return true;
case 'false':
case '(false)':
return false;
case 'empty':
case '(empty)':
return '';
case 'null':
case '(null)':
return null;
}
if (($valueLength = strlen($value)) > 1 && $value[0] === '"' && $value[$valueLength - 1] === '"') {
return substr($value, 1, -1);
}
return $value;
}
}
/**
* CLI打印调试
* @param $data
* @param bool $echo
* @return string
*/
function cli($data, bool $echo = true): string
{
$str = '----------------------------------------date:' . date("Y-m-d H:i:s") . PHP_EOL;
if (is_bool($data)) {
$show_data = $data ? 'true' : 'false';
} elseif (is_null($data)) {
$show_data = 'null';
} else {
$show_data = print_r($data, true);
}
$str .= $show_data;
$str .= PHP_EOL . '----------------------------------------memory_get_usage:' . memory_get_usage(true) . PHP_EOL . PHP_EOL;
if ($echo) {
echo $str;
return '';
}
return $str;
}
/**
* 是否win平台
* @return bool
*/
function isWin(): bool
{
return DIRECTORY_SEPARATOR === '\\';
}
/**
* 对布尔型进行格式化
* @param mixed $value 变量值
* @return boolean string 格式化后的变量
*/
function booleanParse($value): bool
{
$rs = $value;
if (!is_bool($value)) {
if (is_numeric($value)) {
$rs = ($value + 0) > 0;
} elseif (is_string($value)) {
$rs = in_array(strtolower($value), ['ok', 'true', 'success', 'on', 'yes', '(ok)', '(true)', '(success)', '(on)', '(yes)']);
} else {
$rs = (bool)$value;
}
}
return $rs;
}

View File

@ -12,7 +12,7 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace support\middleware;
namespace app\middleware;
use Webman\MiddlewareInterface;
use Webman\Http\Response;

View File

@ -1,44 +0,0 @@
<?php
namespace app\middleware;
use support\bootstrap\Container;
use Webman\MiddlewareInterface;
use Webman\Http\Response;
use Webman\Http\Request;
/**
* [中间件] 控制器钩子
* @descr 每个控制器执行前调用beforeAction()执行后调用afterAction()
* Class ActionHook
* @package app\middleware
*/
class ActionHook implements MiddlewareInterface
{
public function process(Request $request, callable $next) : Response
{
if ($request->controller) {
// 禁止直接访问beforeAction afterAction
if ($request->action === 'beforeAction' || $request->action === 'afterAction') {
return response('<h1>404 Not Found</h1>', 404);
}
$controller = Container::get($request->controller);
//请求前的流程
if (method_exists($controller, 'beforeAction')) {
$before_response = call_user_func([$controller, 'beforeAction'], $request);
if ($before_response instanceof Response) {
return $before_response;
}
}
$response = $next($request);
//请求后的流程
if (method_exists($controller, 'afterAction')) {
$after_response = call_user_func([$controller, 'afterAction'], $request, $response);
if ($after_response instanceof Response) {
return $after_response;
}
}
return $response;
}
return $next($request);
}
}

View File

@ -1,4 +1,5 @@
<?php
namespace app\middleware;
use Webman\MiddlewareInterface;

View File

@ -12,7 +12,7 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace support\middleware;
namespace app\middleware;
use Webman\MiddlewareInterface;
use Webman\Http\Response;

View File

@ -1,28 +1,27 @@
<?php
namespace app\model;
use support\Model;
class Test extends Model
{
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = false;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'test';
/**
* The primary key associated with the table.
*
* @var string
*/
protected $primaryKey = 'id';
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = false;
}

View File

@ -2,9 +2,9 @@
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="/favicon.ico" />
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1" name="viewport">
<link href="/favicon.ico" rel="shortcut icon"/>
<title>webman</title>
</head>

View File

@ -1,8 +1,9 @@
<?php
require_once dirname(__DIR__) . '/init.php';
require_once dirname(__DIR__) . '/vendor/autoload.php';
require_once ROOT_PATH . '/app/functions.php';
require_once ROOT_PATH . '/src/helper.php';
echo microtime(true) . ' 当前脚本路径:' . __FILE__ . PHP_EOL;
use IYUU\Reseed\AutoReseed;
use Workerman\Autoloader;

View File

@ -1,8 +1,9 @@
<?php
require_once dirname(__DIR__) . '/init.php';
require_once dirname(__DIR__) . '/vendor/autoload.php';
require_once ROOT_PATH . '/app/functions.php';
require_once ROOT_PATH . '/src/helper.php';
echo microtime(true) . ' 当前脚本路径:' . __FILE__ . PHP_EOL;
use IYUU\Reseed\MoveTorrent;
use Workerman\Autoloader;

View File

@ -1,5 +1,5 @@
<?php
require_once dirname(__DIR__) . '/init.php';
require_once dirname(__DIR__) . '/vendor/autoload.php';
require_once ROOT_PATH . '/app/functions.php';
require_once ROOT_PATH . '/src/helper.php';
echo microtime(true) . ' 当前脚本路径:' . __FILE__ . PHP_EOL;

View File

@ -1,5 +1,5 @@
<?php
require_once dirname(__DIR__) . '/init.php';
require_once dirname(__DIR__) . '/vendor/autoload.php';
require_once ROOT_PATH . '/app/functions.php';
require_once ROOT_PATH . '/src/helper.php';
echo microtime(true) . ' 当前脚本路径:' . __FILE__ . PHP_EOL;

View File

@ -25,8 +25,9 @@
},
"require": {
"php": ">=7.2",
"workerman/webman-framework": "^1.0",
"workerman/webman-framework": "^1.4.7",
"monolog/monolog": "^2.0",
"webman/console": "^1.2.12",
"vlucas/phpdotenv": "5.1.0",
"rhilip/bencode": "^2.1",
"workerman/crontab": "^1.0",
@ -37,22 +38,36 @@
"ext-mbstring": "*",
"ext-curl": "*",
"ext-dom": "*",
"ledccn/bittorrentclient": "dev-master"
"ledccn/bittorrentclient": "dev-master",
"webman/event": "^1.0",
"ext-simplexml": "*"
},
"suggest": {
"ext-event": "For better performance. "
},
"autoload": {
"psr-4": {
"": "./",
"IYUU\\": "src/"
},
"files": [
"./support/helpers.php"
"./init.php",
"./support/helpers.php",
"./app/helpers.php"
]
},
"scripts": {
"post-autoload-dump": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-package-install": [
"support\\Plugin::install"
],
"post-package-update": [
"support\\Plugin::install"
],
"pre-package-uninstall": [
"support\\Plugin::uninstall"
]
}
}

View File

@ -1,18 +1,15 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
use app\Request;
return [
'debug' => env('APP_DEBUG', false),
'default_timezone' => 'Asia/Shanghai',
'error_reporting' => E_ALL,
'request_class' => Request::class,
'public_path' => base_path() . DIRECTORY_SEPARATOR . 'public',
'runtime_path' => base_path(false) . DIRECTORY_SEPARATOR . 'runtime',
'controller_suffix' => '',
//关闭控制器复用每个请求都会触发对应控制器的__construct()构造函数
'controller_reuse' => false,
];

View File

@ -14,6 +14,8 @@
return [
'files' => [
base_path() . '/app/functions.php'
base_path() . '/app/functions.php',
base_path() . '/app/Request.php',
base_path() . '/support/Response.php',
]
];

View File

@ -13,10 +13,5 @@
*/
return [
support\bootstrap\Container::class,
support\bootstrap\Session::class,
//support\bootstrap\db\Laravel::class,
//support\bootstrap\Redis::class,
support\bootstrap\Log::class,
support\bootstrap\Translation::class,
];

View File

@ -1,6 +1,2 @@
<?php
return [
'EventListener' => [
IYUU\Library\EventListen\send::class,
],
];
return [];

View File

@ -19,6 +19,7 @@ return [
'class' => Monolog\Handler\RotatingFileHandler::class,
'constructor' => [
runtime_path() . '/logs/webman.log',
7, //$maxFiles
Monolog\Logger::DEBUG,
],
'formatter' => [

View File

@ -5,8 +5,6 @@
return [
'' => [
app\middleware\AuthCheck::class,
app\middleware\ActionHook::class,
//support\middleware\AuthCheckTest::class,
//support\middleware\AccessControlTest::class,
]
];

View File

@ -19,8 +19,8 @@ use support\view\ThinkPHP;
return [
// 文件更新检测
'IYUUFileMonitor' => [
'handler' => process\FileMonitor::class,
'monitor' => [
'handler' => process\Monitor::class,
'reloadable' => false,
'constructor' => [
// 监控这些目录
@ -30,12 +30,13 @@ return [
base_path() . '/process',
base_path() . '/src',
base_path() . '/support',
base_path() . '/resource'
base_path() . '/resource',
base_path() . '/.env',
],
// Files with these suffixes will be monitored
'monitor_extensions' => [
'php', 'html', 'htm', 'env'
],
// 监控这些后缀的文件
'monitor_extenstions' => [
'php', 'html', 'htm'
]
]
],
// 其它进程

View File

@ -3,13 +3,16 @@ return [
'listen' => 'http://0.0.0.0:8787',
'transport' => 'tcp',
'context' => [],
'name' => 'IYUUAutoReseed',
'name' => 'IYUUPlus',
'count' => env('SERVER_PROCESS_COUNT', 2),
'user' => env('SERVER_PROCESS_USER', ''),
'group' => env('SERVER_PROCESS_GROUP', ''),
'event_loop' => '',
'stop_timeout' => 2,
'pid_file' => runtime_path() . '/webman.pid',
'log_file' => runtime_path() . '/workerman.log',
'max_request' => 1000,
'status_file' => runtime_path() . '/webman.status',
'stdout_file' => runtime_path() . '/logs/stdout.log',
'max_request' => 1000,
'max_package_size' => 10 * 1024 * 1024
];

View File

@ -16,7 +16,7 @@ return [
'type' => 'file', // or redis or redis_cluster
'handler' => Webman\FileSessionHandler::class,
'handler' => Webman\Session\FileSessionHandler::class,
'config' => [
'file' => [

View File

@ -18,6 +18,6 @@
return [
'enable' => true, // 是否支持静态文件
'middleware' => [ // 静态文件中间件
support\middleware\StaticFile::class,
app\middleware\StaticFile::class,
],
];

View File

@ -24,9 +24,6 @@ echo microtime(true).' 当前运行环境:'.PHP_OS_FAMILY.PHP_EOL;
echo microtime(true) . ' 当前接口类型:' . PHP_SAPI . PHP_EOL;
echo microtime(true) . ' PHP二进制文件' . PHP_BINARY . PHP_EOL;
echo microtime(true) . ' PHP版本号' . PHP_VERSION . PHP_EOL;
echo microtime(true).' 正在加载composer包管理器...'.PHP_EOL;
require_once __DIR__ . '/vendor/autoload.php';
echo microtime(true).' composer依赖载入完成'.PHP_EOL;
// 定义目录
defined('ROOT_PATH') or define('ROOT_PATH', __DIR__);

View File

@ -1,106 +0,0 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace process;
use Workerman\Timer;
use Workerman\Worker;
class FileMonitor
{
/**
* @var array
*/
protected $_paths = [];
/**
* @var array
*/
protected $_extensions = [];
/**
* pidFile
*/
const pidFile = 'IYUUFileMonitor.pid';
/**
* FileMonitor constructor.
* @param $monitor_dir
* @param $monitor_extenstions
*/
public function __construct($monitor_dir, $monitor_extenstions)
{
if (function_exists('posix_getpid')) {
\file_put_contents(runtime_path() . \DIRECTORY_SEPARATOR . self::pidFile, \posix_getpid());
}
if (Worker::$daemonize) {
#return;
}
$this->_paths = (array)$monitor_dir;
$this->_extensions = $monitor_extenstions;
Timer::add(1, function () {
foreach ($this->_paths as $path) {
$this->check_files_change($path);
}
});
}
/**
* 析构方法
*/
public function __destruct()
{
is_file(runtime_path() . \DIRECTORY_SEPARATOR . self::pidFile) and @\unlink(runtime_path() . \DIRECTORY_SEPARATOR . self::pidFile);
}
/**
* @param $monitor_dir
*/
public function check_files_change($monitor_dir)
{
static $last_mtime;
if (!$last_mtime) {
$last_mtime = time();
}
clearstatcache();
if (!is_dir($monitor_dir)) {
return;
}
// recursive traversal directory
$dir_iterator = new \RecursiveDirectoryIterator($monitor_dir);
$iterator = new \RecursiveIteratorIterator($dir_iterator);
foreach ($iterator as $file) {
/** var SplFileInfo $file */
if (is_dir($file)) {
continue;
}
// check mtime
if ($last_mtime < $file->getMTime() && in_array($file->getExtension(), $this->_extensions)) {
$var = 0;
exec("php -l " . $file, $out, $var);
if ($var) {
$last_mtime = $file->getMTime();
continue;
}
echo $file . " update and reload\n";
// send SIGUSR1 signal to master process for reload
posix_kill(posix_getppid(), SIGUSR1);
$last_mtime = $file->getMTime();
break;
}
}
}
}

195
process/Monitor.php Normal file
View File

@ -0,0 +1,195 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace process;
use Workerman\Timer;
use Workerman\Worker;
/**
* Class FileMonitor
* @package process
*/
class Monitor
{
/**
* @var array
*/
protected $_paths = [];
/**
* @var array
*/
protected $_extensions = [];
/**
* FileMonitor constructor.
* @param $monitor_dir
* @param $monitor_extensions
* @param $memory_limit
*/
public function __construct($monitor_dir, $monitor_extensions, $memory_limit = null)
{
$this->_paths = (array)$monitor_dir;
$this->_extensions = $monitor_extensions;
if (!Worker::getAllWorkers()) {
return;
}
$disable_functions = explode(',', ini_get('disable_functions'));
if (in_array('exec', $disable_functions, true)) {
echo "\nMonitor file change turned off because exec() has been disabled by disable_functions setting in " . PHP_CONFIG_FILE_PATH . "/php.ini\n";
} else {
if (!Worker::$daemonize) {
Timer::add(1, function () {
$this->checkAllFilesChange();
});
}
}
$memory_limit = $this->getMemoryLimit($memory_limit);
if ($memory_limit && DIRECTORY_SEPARATOR === '/') {
Timer::add(60, [$this, 'checkMemory'], [$memory_limit]);
}
}
/**
* @param $monitor_dir
*/
public function checkFilesChange($monitor_dir)
{
static $last_mtime, $too_many_files_check;
if (!$last_mtime) {
$last_mtime = time();
}
clearstatcache();
if (!is_dir($monitor_dir)) {
if (!is_file($monitor_dir)) {
return;
}
$iterator = [new \SplFileInfo($monitor_dir)];
} else {
// recursive traversal directory
$dir_iterator = new \RecursiveDirectoryIterator($monitor_dir, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS);
$iterator = new \RecursiveIteratorIterator($dir_iterator);
}
$count = 0;
foreach ($iterator as $file) {
$count ++;
/** var SplFileInfo $file */
if (is_dir($file)) {
continue;
}
// check mtime
if ($last_mtime < $file->getMTime() && in_array($file->getExtension(), $this->_extensions, true)) {
$var = 0;
exec('"'.PHP_BINARY . '" -l ' . $file, $out, $var);
if ($var) {
$last_mtime = $file->getMTime();
continue;
}
$last_mtime = $file->getMTime();
echo $file . " update and reload\n";
// send SIGUSR1 signal to master process for reload
if (DIRECTORY_SEPARATOR === '/') {
posix_kill(posix_getppid(), SIGUSR1);
} else {
return true;
}
break;
}
}
if (!$too_many_files_check && $count > 1000) {
echo "Monitor: There are too many files ($count files) in $monitor_dir which makes file monitoring very slow\n";
$too_many_files_check = 1;
}
}
/**
* @return bool
*/
public function checkAllFilesChange()
{
foreach ($this->_paths as $path) {
if ($this->checkFilesChange($path)) {
return true;
}
}
return false;
}
/**
* @param $memory_limit
* @return void
*/
public function checkMemory($memory_limit)
{
$ppid = posix_getppid();
$children_file = "/proc/$ppid/task/$ppid/children";
if (!is_file($children_file) || !($children = file_get_contents($children_file))) {
return;
}
foreach (explode(' ', $children) as $pid) {
$pid = (int)$pid;
$status_file = "/proc/$pid/status";
if (!is_file($status_file) || !($status = file_get_contents($status_file))) {
continue;
}
$mem = 0;
if (preg_match('/VmRSS\s*?:\s*?(\d+?)\s*?kB/', $status, $match)) {
$mem = $match[1];
}
$mem = (int)($mem / 1024);
if ($mem >= $memory_limit) {
posix_kill($pid, SIGINT);
}
}
}
/**
* Get memory limit
* @return float
*/
protected function getMemoryLimit($memory_limit)
{
if ($memory_limit === 0) {
return 0;
}
$use_php_ini = false;
if (!$memory_limit) {
$memory_limit = ini_get('memory_limit');
$use_php_ini = true;
}
if ($memory_limit == -1) {
return 0;
}
$unit = $memory_limit[strlen($memory_limit) - 1];
if ($unit == 'G') {
$memory_limit = 1024 * (int)$memory_limit;
} else if ($unit == 'M') {
$memory_limit = (int)$memory_limit;
} else if ($unit == 'K') {
$memory_limit = (int)($memory_limit / 1024);
} else {
$memory_limit = (int)($memory_limit / (1024 * 1024));
}
if ($memory_limit < 30) {
$memory_limit = 30;
}
if ($use_php_ini) {
$memory_limit = (int)(0.8 * $memory_limit);
}
return $memory_limit;
}
}

View File

@ -1,4 +1,5 @@
<?php
namespace IYUU\Library;
/**
@ -71,6 +72,39 @@ class Context
return $value;
}
/**
* 移除指定Session
* @param string $key
* @return Context
*/
public function unsetSession(string $key): Context
{
unset($this->session[$key]);
return $this;
}
/**
* 读取不可访问属性的值时__get() 会被调用
*
* @param string $name 参数名字
* @return mixed
*/
public function __get(string $name)
{
return $this->getSession($name, null);
}
/**
* 在给不可访问属性赋值时__set() 会被调用
*
* @param string $name 参数名字
* @param mixed $value 参数解析后的值
*/
public function __set(string $name, $value)
{
$this->setSession($name, $value);
}
/**
* 获取Session
* @param string|null $key
@ -105,39 +139,6 @@ class Context
return $this;
}
/**
* 移除指定Session
* @param string $key
* @return Context
*/
public function unsetSession(string $key): Context
{
unset($this->session[$key]);
return $this;
}
/**
* 读取不可访问属性的值时__get() 会被调用
*
* @param string $name 参数名字
* @return mixed
*/
public function __get(string $name)
{
return $this->getSession($name, null);
}
/**
* 在给不可访问属性赋值时__set() 会被调用
*
* @param string $name 参数名字
* @param mixed $value 参数解析后的值
*/
public function __set(string $name, $value)
{
$this->setSession($name, $value);
}
/**
* 当对不可访问属性调用 isset() empty() __isset() 会被调用
*

View File

@ -1,26 +0,0 @@
<?php
namespace IYUU\Library\EventListen;
use app\common\event\EventListenerInterface;
class send implements EventListenerInterface
{
/**
* 需要订阅的事件
* - 返回要监听的事件数组,可监听多个事件
* @return array
*/
public function events():array
{
return [];
}
/**
* 订阅器的处理方法(事件触发后,会执行该方法)
*
* @param object $event
*/
public function process(object $event):void
{
}
}

View File

@ -1,4 +1,5 @@
<?php
namespace IYUU\Library;
/**
@ -8,6 +9,7 @@ namespace IYUU\Library;
class IFile
{
private $resource = null; //文件资源句柄
/**
* @brief 构造函数,打开资源流,并独占锁定
* @param String $fileName 文件路径名
@ -34,55 +36,15 @@ class IFile
}
/**
* @brief 获取文件内容
* @return String 文件内容
* @brief 创建文件夹
* @param String $path 路径
* @param int $chmod 文件夹权限
* @note $chmod 参数不能是字符串(加引号)否则linux会出现权限问题
* @return bool
*/
public function read()
public static function mkdir($path, $chmod = 0777)
{
$content = null;
while (!feof($this->resource)) {
$content.= fread($this->resource, 1024);
}
return $content;
}
/**
* @brief 文件写入操作
* @param String $content 要写入的文件内容
* @return Int or false 写入的字符数; false:写入失败;
*/
public function write($content)
{
$worldsnum = fwrite($this->resource, $content);
$this->save();
return is_bool($worldsnum) ? false : $worldsnum;
}
/**
* @brief 清空目录下的所有文件
* @param string $dir
* @return bool false:失败; true:成功;
*/
public static function clearDir($dir)
{
if ($dir[0] != '.' && is_dir($dir) && is_writable($dir)) {
$dirRes = opendir($dir);
while (false !== ($fileName = readdir($dirRes))) {
if ($fileName[0] !== '.') {
$fullpath = $dir.'/'.$fileName;
if (is_file($fullpath)) {
self::unlink($fullpath);
} else {
self::clearDir($fullpath);
rmdir($fullpath);
}
}
}
closedir($dirRes);
return true;
} else {
return false;
}
return is_dir($path) or (self::mkdir(dirname($path), $chmod) and mkdir($path, $chmod));
}
/**
@ -99,18 +61,6 @@ class IFile
}
}
/**
* @brief 创建文件夹
* @param String $path 路径
* @param int $chmod 文件夹权限
* @note $chmod 参数不能是字符串(加引号)否则linux会出现权限问题
* @return bool
*/
public static function mkdir($path, $chmod=0777)
{
return is_dir($path) or (self::mkdir(dirname($path), $chmod) and mkdir($path, $chmod));
}
/**
* @brief 复制文件
* @param String $from 源文件路径
@ -164,9 +114,7 @@ class IFile
if ($recursive == true) {
self::clearDir($dir);
return self::rmdir($dir, false);
}
//非强制删除
} //非强制删除
else {
if (rmdir($dir)) {
return true;
@ -178,6 +126,33 @@ class IFile
return false;
}
/**
* @brief 清空目录下的所有文件
* @param string $dir
* @return bool false:失败; true:成功;
*/
public static function clearDir($dir)
{
if ($dir[0] != '.' && is_dir($dir) && is_writable($dir)) {
$dirRes = opendir($dir);
while (false !== ($fileName = readdir($dirRes))) {
if ($fileName[0] !== '.') {
$fullpath = $dir . '/' . $fileName;
if (is_file($fullpath)) {
self::unlink($fullpath);
} else {
self::clearDir($fullpath);
rmdir($fullpath);
}
}
}
closedir($dirRes);
return true;
} else {
return false;
}
}
/**
* @brief 获取文件类型
* @param String $fileName 文件名
@ -268,14 +243,6 @@ class IFile
return false;
}
/**
* @brief 释放文件锁定
*/
public function save()
{
flock($this->resource, LOCK_UN);
}
/**
* @brief 获取文件扩展名
* @param String $fileName 文件名
@ -287,6 +254,39 @@ class IFile
return $fileInfoArray['extension'];
}
/**
* @brief 获取文件内容
* @return String 文件内容
*/
public function read()
{
$content = null;
while (!feof($this->resource)) {
$content .= fread($this->resource, 1024);
}
return $content;
}
/**
* @brief 文件写入操作
* @param String $content 要写入的文件内容
* @return Int or false 写入的字符数; false:写入失败;
*/
public function write($content)
{
$worldsnum = fwrite($this->resource, $content);
$this->save();
return is_bool($worldsnum) ? false : $worldsnum;
}
/**
* @brief 释放文件锁定
*/
public function save()
{
flock($this->resource, LOCK_UN);
}
/**
* @brief 析构函数,释放文件连接句柄
*/

View File

@ -3,6 +3,7 @@
* Rpc操作类
* 把RSS解码与添加下载任务解耦
*/
namespace IYUU\Library;
use IYUU\Client\AbstractClient;
@ -10,8 +11,12 @@ use IYUU\Client\AbstractClient;
class Rpc
{
// 站点标识
protected static $site = '';
/**
* 退出状态码
*/
public static $ExitCode = 0;
// 下载种子的请求类型 GET POST
protected static $site = '';
protected static $method = 'GET';
/**
* 运行时解析的配置
@ -50,10 +55,6 @@ class Rpc
* RPC连接
*/
protected static $links = array();
/**
* 退出状态码
*/
public static $ExitCode = 0;
/**
* 初始化

View File

@ -1,4 +1,5 @@
<?php
namespace IYUU\Library;
use DOMDocument;
@ -6,10 +7,10 @@ use DOMXpath;
class Selector
{
public static $error = null;
private static $dom = null;
private static $dom_auth = '';
private static $xpath = null;
public static $error = null;
/**
* @param $html
@ -36,36 +37,6 @@ class Selector
}
}
/**
* @param $html
* @param string $selector
* @param string $selector_type
* @return mixed|null
*/
public static function remove($html, $selector, $selector_type = 'xpath')
{
if (empty($html) || empty($selector)) {
return null;
}
$selector_type = strtolower($selector_type);
switch ($selector_type) {
case 'xpath':
$remove_html = self::_xpath_select($html, $selector, true);
break;
case 'regex':
$remove_html = self::_regex_select($html, $selector, true);
break;
case 'css':
$remove_html = self::_css_select($html, $selector, true);
break;
default:
return null;
}
return str_replace($remove_html, '', $html);
}
/**
* xpath选择器
*
@ -111,8 +82,7 @@ class Selector
// 如果是img标签直接取src值
if ($nodeType == 1 && in_array($nodeName, array('img'))) {
$content = $element->getAttribute('src');
}
// 如果是标签属性,直接取节点值
} // 如果是标签属性,直接取节点值
elseif ($nodeType == 2 || $nodeType == 3 || $nodeType == 4) {
$content = $element->nodeValue;
} else {
@ -132,20 +102,6 @@ class Selector
return count($result) > 1 ? $result : $result[0];
}
/**
* css选择器
*
* @param $html
* @param string $selector
* @param bool $remove
* @return array|string|null
*/
private static function _css_select($html, $selector, $remove = false)
{
$selector = self::css_to_xpath($selector);
return self::_xpath_select($html, $selector, $remove);
}
/**
* 正则选择器
*
@ -165,8 +121,7 @@ class Selector
// 一个都没有匹配到
if ($count === 0) {
return null;
}
// 只匹配一个,就是只有一个 ()
} // 只匹配一个,就是只有一个 ()
elseif ($count == 2) {
// 删除的话取匹配到的所有内容
if ($remove) {
@ -187,6 +142,20 @@ class Selector
return count($result) > 1 ? $result : $result[0];
}
/**
* css选择器
*
* @param $html
* @param string $selector
* @param bool $remove
* @return array|string|null
*/
private static function _css_select($html, $selector, $remove = false)
{
$selector = self::css_to_xpath($selector);
return self::_xpath_select($html, $selector, $remove);
}
/**
* CSS表达式转换为Xpath表达式
* @param string $selectors
@ -202,24 +171,21 @@ class Selector
$is_tag = preg_match('@^[\w|\||-]+$@', $s) || $s == '*';
if ($is_tag) {
$xquery .= $s;
}
// ID
} // ID
elseif ($s[0] == '#') {
if ($delimiter_before) {
$xquery .= '*';
}
// ID用精确查询
$xquery .= "[@id='" . substr($s, 1) . "']";
}
// CLASSES
} // CLASSES
elseif ($s[0] == '.') {
if ($delimiter_before) {
$xquery .= '*';
}
// CLASS用模糊查询
$xquery .= "[contains(@class,'" . substr($s, 1) . "')]";
}
// ATTRIBUTES
} // ATTRIBUTES
elseif ($s[0] == '[') {
if ($delimiter_before) {
$xquery .= '*';
@ -238,32 +204,25 @@ class Selector
} else {
$xquery .= "[@{$attr}='{$value}']";
}
}
// attr without specified value
} // attr without specified value
else {
$xquery .= "[@{$attr}]";
}
}
// ~ General Sibling Selector
} // ~ General Sibling Selector
elseif ($s[0] == '~') {
}
// + Adjacent sibling selectors
} // + Adjacent sibling selectors
elseif ($s[0] == '+') {
}
// PSEUDO CLASSES
} // PSEUDO CLASSES
elseif ($s[0] == ':') {
}
// DIRECT DESCENDANDS
} // DIRECT DESCENDANDS
elseif ($s == '>') {
$xquery .= '/';
$delimiter_before = 2;
}
// ALL DESCENDANDS
} // ALL DESCENDANDS
elseif ($s == ' ') {
$xquery .= '//';
$delimiter_before = 2;
}
// ERRORS
} // ERRORS
else {
exit("Unrecognized token '$s'");
}
@ -309,8 +268,7 @@ class Selector
$i++;
}
$queries[] = $tmp;
}
// IDs
} // IDs
elseif ($c == '#') {
$i++;
while (isset($query[$i]) && (self::is_char($query[$i]) || $query[$i] == '-')) {
@ -318,8 +276,7 @@ class Selector
$i++;
}
$queries[] = '#' . $tmp;
}
// SPECIAL CHARS
} // SPECIAL CHARS
elseif (in_array($c, $special_chars)) {
$queries[] = $c;
$i++;
@ -327,28 +284,24 @@ class Selector
// } else if ( $c.$query[$i+1] == '//') {
// $return[] = ' ';
// $i = $i+2;
}
// MAPPED SPECIAL CHARS
} // MAPPED SPECIAL CHARS
elseif (isset($special_chars_mapping[$c])) {
$queries[] = $special_chars_mapping[$c];
$i++;
}
// COMMA
} // COMMA
elseif ($c == ',') {
$i++;
while (isset($query[$i]) && $query[$i] == ' ') {
$i++;
}
}
// CLASSES
} // CLASSES
elseif ($c == '.') {
while (isset($query[$i]) && (self::is_char($query[$i]) || in_array($query[$i], $class_chars))) {
$tmp .= $query[$i];
$i++;
}
$queries[] = $tmp;
}
// ~ General Sibling Selector
} // ~ General Sibling Selector
elseif ($c == '~') {
$space_allowed = true;
$tmp .= $query[$i++];
@ -366,8 +319,7 @@ class Selector
$i++;
}
$queries[] = $tmp;
}
// + Adjacent sibling selectors
} // + Adjacent sibling selectors
elseif ($c == '+') {
$space_allowed = true;
$tmp .= $query[$i++];
@ -385,8 +337,7 @@ class Selector
$i++;
}
$queries[] = $tmp;
}
// ATTRS
} // ATTRS
elseif ($c == '[') {
$stack = 1;
$tmp .= $c;
@ -403,8 +354,7 @@ class Selector
}
$queries[] = $tmp;
$i++;
}
// PSEUDO CLASSES
} // PSEUDO CLASSES
elseif ($c == ':') {
$stack = 1;
$tmp .= $query[$i++];
@ -471,4 +421,34 @@ class Selector
{
return in_array($pattern[mb_strlen($pattern) - 1], array('^', '*', '$'));
}
/**
* @param $html
* @param string $selector
* @param string $selector_type
* @return mixed|null
*/
public static function remove($html, $selector, $selector_type = 'xpath')
{
if (empty($html) || empty($selector)) {
return null;
}
$selector_type = strtolower($selector_type);
switch ($selector_type) {
case 'xpath':
$remove_html = self::_xpath_select($html, $selector, true);
break;
case 'regex':
$remove_html = self::_regex_select($html, $selector, true);
break;
case 'css':
$remove_html = self::_css_select($html, $selector, true);
break;
default:
return null;
}
return str_replace($remove_html, '', $html);
}
}

View File

@ -1,4 +1,5 @@
<?php
namespace IYUU\Library;
/**
@ -103,23 +104,6 @@ class Table
$this->checkColWidth($header);
}
/**
* 设置输出表格数据 及对齐方式
* @access public
* @param array $rows 要输出的表格数据(二维数组)
* @param int $align 对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
* @return void
*/
public function setRows($rows, $align = self::ALIGN_LEFT)
{
$this->rows = $rows;
$this->cellAlign = $align;
foreach ($rows as $row) {
$this->checkColWidth($row);
}
}
/**
* 检查列数据的显示宽度
* @access public
@ -155,71 +139,6 @@ class Table
$this->checkColWidth($row);
}
/**
* 设置输出表格的样式
* @access public
* @param string $style 样式名
* @return void
*/
public function setStyle($style)
{
$this->style = isset($this->format[$style]) ? $style : 'default';
}
/**
* 输出分隔行
* @access public
* @param string $pos 位置
* @return string
*/
protected function renderSeparator($pos)
{
$style = $this->getStyle($pos);
$array = [];
foreach ($this->colWidth as $width) {
$array[] = str_repeat($style[1], $width + 2);
}
return $style[0] . implode($style[2], $array) . $style[3] . PHP_EOL;
}
/**
* 输出表格头部
* @access public
* @return string
*/
protected function renderHeader()
{
$style = $this->getStyle('cell');
$content = $this->renderSeparator('top');
foreach ($this->header as $key => $header) {
$array[] = ' ' . str_pad($header, $this->colWidth[$key], $style[1], $this->headerAlign);
}
if (!empty($array)) {
$content .= $style[0] . implode(' ' . $style[2], $array) . ' ' . $style[3] . PHP_EOL;
if ($this->rows) {
$content .= $this->renderSeparator('middle');
}
}
return $content;
}
protected function getStyle($style)
{
if ($this->format[$this->style]) {
$style = $this->format[$this->style][$style];
} else {
$style = [' ', ' ', ' ', ' '];
}
return $style;
}
/**
* 输出表格
* @access public
@ -264,4 +183,86 @@ class Table
return $content;
}
/**
* 设置输出表格数据 及对齐方式
* @access public
* @param array $rows 要输出的表格数据(二维数组)
* @param int $align 对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
* @return void
*/
public function setRows($rows, $align = self::ALIGN_LEFT)
{
$this->rows = $rows;
$this->cellAlign = $align;
foreach ($rows as $row) {
$this->checkColWidth($row);
}
}
/**
* 输出表格头部
* @access public
* @return string
*/
protected function renderHeader()
{
$style = $this->getStyle('cell');
$content = $this->renderSeparator('top');
foreach ($this->header as $key => $header) {
$array[] = ' ' . str_pad($header, $this->colWidth[$key], $style[1], $this->headerAlign);
}
if (!empty($array)) {
$content .= $style[0] . implode(' ' . $style[2], $array) . ' ' . $style[3] . PHP_EOL;
if ($this->rows) {
$content .= $this->renderSeparator('middle');
}
}
return $content;
}
protected function getStyle($style)
{
if ($this->format[$this->style]) {
$style = $this->format[$this->style][$style];
} else {
$style = [' ', ' ', ' ', ' '];
}
return $style;
}
/**
* 设置输出表格的样式
* @access public
* @param string $style 样式名
* @return void
*/
public function setStyle($style)
{
$this->style = isset($this->format[$style]) ? $style : 'default';
}
/**
* 输出分隔行
* @access public
* @param string $pos 位置
* @return string
*/
protected function renderSeparator($pos)
{
$style = $this->getStyle($pos);
$array = [];
foreach ($this->colWidth as $width) {
$array[] = str_repeat($style[1], $width + 2);
}
return $style[0] . implode($style[2], $array) . $style[3] . PHP_EOL;
}
}

View File

@ -1,4 +1,5 @@
<?php
namespace IYUU\Reseed;
use Curl\Curl;
@ -19,41 +20,6 @@ use app\domain\Crontab as domainCrontab;
*/
class AutoReseed
{
/**
* 解析的运行时配置
* @var array
*/
protected static $conf = [];
/**
* RPC连接
* @var array
*/
protected static $links = [];
/**
* 客户端
* @var array
*/
protected static $clients = [];
/**
* 站点
* @var array
*/
private static $sites = [];
/**
* 用户选择辅种的站点
* @var array
*/
private static $_sites = [];
/**
* 推荐的合作站点
* @var array
*/
private static $recommend = [];
/**
* 不辅种的站点
* @var array
*/
private static $noReseed = [];
/**
* 运行缓存目录
* @var string
@ -74,6 +40,26 @@ class AutoReseed
* @var string
*/
public static $cacheNotify = TORRENT_PATH . DIRECTORY_SEPARATOR . 'cacheNotify' . DIRECTORY_SEPARATOR;
/**
* 退出状态码
* @var int
*/
public static $ExitCode = 0;
/**
* 解析的运行时配置
* @var array
*/
protected static $conf = [];
/**
* RPC连接
* @var array
*/
protected static $links = [];
/**
* 客户端
* @var array
*/
protected static $clients = [];
/**
* @var null | Curl
*/
@ -83,11 +69,6 @@ class AutoReseed
* @var string
*/
protected static $pid_file = '';
/**
* 退出状态码
* @var int
*/
public static $ExitCode = 0;
/**
* 微信通知消息体
* @var array
@ -115,11 +96,30 @@ class AutoReseed
'torrent_id' => 0,
'error' => '',
);
/**
* 临时变量
*/
protected static $temp = [];
/**
* 站点
* @var array
*/
private static $sites = [];
/**
* 用户选择辅种的站点
* @var array
*/
private static $_sites = [];
/**
* 推荐的合作站点
* @var array
*/
private static $recommend = [];
/**
* 不辅种的站点
* @var array
*/
private static $noReseed = [];
/**
* 初始化
@ -187,7 +187,7 @@ class AutoReseed
* 保存进程pid文件
* @param string $cron_name
*/
protected static function savePid($cron_name = '')
protected static function savePid(string $cron_name = '')
{
self::$conf['cron_name'] = $cron_name; // 保存计划任务名字
//pid文件
@ -347,91 +347,6 @@ class AutoReseed
}
}
/**
* @brief 添加下载任务
* @param $clientKey
* @param string $torrent 种子元数据
* @param string $save_path 保存路径
* @param array $extra_options
* @return bool
*/
protected static function add($clientKey, $torrent, $save_path = '', $extra_options = array())
{
try {
$is_url = static::isTorrentUrl($torrent);
// 下载服务器类型
$type = static::$links[$clientKey]['type'];
// 判断
switch ($type) {
case 'transmission':
$extra_options['paused'] = isset($extra_options['paused']) ? $extra_options['paused'] : true;
if ($is_url) {
$result = static::getRpc($clientKey)->add($torrent, $save_path, $extra_options); // URL添加
} else {
$result = static::getRpc($clientKey)->add_metainfo($torrent, $save_path, $extra_options); // 元数据添加
}
if (isset($result['result']) && $result['result'] == 'success') {
$_key = isset($result['arguments']['torrent-added']) ? 'torrent-added' : 'torrent-duplicate';
$id = $result['arguments'][$_key]['id'];
$name = $result['arguments'][$_key]['name'];
print "名字:" .$name . PHP_EOL;
print "********RPC添加下载任务成功 [" .$result['result']. "] (id=" .$id. ")".PHP_EOL.PHP_EOL;
return true;
} else {
$err = isset($result['result']) ? $result['result'] : '未知错误,请稍后重试!';
if (strpos($err, 'http error 404: Not Found') !== false) {
static::sendNotify('404');
}
print "-----RPC添加种子任务失败 [{$err}]" . PHP_EOL.PHP_EOL;
}
break;
case 'qBittorrent':
//如果用户的下载器设置自动种子管理,需要传入这个参数
if (isset(static::$links[$clientKey]['_config']['autoTMM'])) {
$extra_options['autoTMM'] = 'false'; //关闭自动种子管理
}
// 添加任务校验后是否暂停
if (isset($extra_options['paused'])) {
$extra_options['paused'] = $extra_options['paused'] ? 'true' : 'false';
} else {
$extra_options['paused'] = 'true';
}
// 是否创建根目录
$extra_options['root_folder'] = static::$links[$clientKey]['root_folder'] ? 'true' : 'false';
if ($is_url) {
$result = static::getRpc($clientKey)->add($torrent, $save_path, $extra_options); // URL添加
} else {
$extra_options['name'] = 'torrents';
$extra_options['filename'] = time().'.torrent';
$result = static::getRpc($clientKey)->add_metainfo($torrent, $save_path, $extra_options); // 元数据添加
}
if ($result === 'Ok.') {
print "********RPC添加下载任务成功 [{$result}]".PHP_EOL.PHP_EOL;
return true;
} else {
print "-----RPC添加种子任务失败 [{$result}]".PHP_EOL.PHP_EOL;
}
break;
default:
echo '[下载器类型错误] '.$type. PHP_EOL. PHP_EOL;
break;
}
} catch (Exception $e) {
echo '[添加下载任务出错] ' . $e->getMessage() . PHP_EOL;
}
return false;
}
/**
* 判断内容是否为种子的URL链接
* @param string $torrent
* @return bool
*/
protected static function isTorrentUrl(string $torrent)
{
return (stripos($torrent, 'http://') === 0) || (stripos($torrent, 'https://') === 0) || (strpos($torrent, 'magnet:?xt=urn:btih:') === 0);
}
/**
* 辅种或转移,总入口
* @throws ClientException
@ -512,13 +427,29 @@ class AutoReseed
}
/**
* 优化IDE跟踪
* @param string $clientKey
* @return qBittorrent|transmission
* 追加式写入日志
* @param string|int|array|object $data
* @param string $name
* @param string $path
* @return bool|int
*/
public static function getRpc(string $clientKey)
protected static function wLog($data, string $name = '', string $path = '')
{
return static::$links[$clientKey]['rpc'];
if (is_bool($data)) {
$show_data = $data ? 'true' : 'false';
} elseif (is_null($data)) {
$show_data = 'null';
} else {
$show_data = print_r($data, true);
}
// 写入日志
$dir = empty($path) ? static::$cacheDir : $path;
IFile::mkdir($dir);
$file = $dir . $name . '.txt';
$pointer = @fopen($file, "a");
$result = @fwrite($pointer, $show_data);
@fclose($pointer);
return $result;
}
/**
@ -649,7 +580,7 @@ class AutoReseed
$reseedPass = true;
echo "当前站点触发人机验证,已加入流控列表" . PHP_EOL;
self::ff($siteName. '站点,辅种时触发人机验证');
self::ff($siteName . '站点,辅种时触发流量控制');
break;
}
} else {
@ -715,8 +646,8 @@ class AutoReseed
$download_page = str_replace($remove, '', self::$sites[$sid]['download_page']) . str_replace('&amp;', '&', $matchs[1]);
$_url = $protocol . self::$sites[$sid]['base_url'] . '/' . $download_page;
print "下载种子:" . $_url . PHP_EOL;
$url = download($_url, $cookie, $userAgent);
if (strpos($url, '第一次下载提示') != false) {
$url = download($_url, $cookie, $userAgent, 'POST');
if (strpos($url, '第一次下载提示')) {
self::$noReseed[] = $siteName;
$reseedPass = true;
@ -731,7 +662,18 @@ class AutoReseed
}
break;
default:
// 默认站点推送给下载器种子URL链接
// 未特殊定义凭借cookie下载种子的站点
print "下载种子:" . $_url . PHP_EOL;
$url = download($_url, $cookie, $userAgent);
if (strpos($url, '第一次下载提示')) {
self::$noReseed[] = $siteName;
$reseedPass = true;
echo "当前站点触发第一次下载提示,已加入排除列表" . PHP_EOL;
echo "请进入种子详情页下载种子成功后更新cookie" . PHP_EOL;
sleepIYUU(30, '请进入种子详情页下载种子成功后更新cookie');
self::ff($siteName . '站点,辅种时触发第一次下载提示!');
}
break;
}
// 检查switch内是否异常
@ -780,48 +722,19 @@ class AutoReseed
}
/**
* 请求NexusPHP详情页
* @descr 天空、瓷器、城市 个别站用到
* @param $protocol string 协议
* @param $torrent array 种子
* @param $cookie string Cookie
* @param $userAgent string UA
* @return mixed|null
* 设置通知主体
* @param string $siteName
* @param int $sid
* @param int $torrent_id
*/
private static function getNexusPHPdetailsPage($protocol, $torrent, $cookie, $userAgent)
private static function setNotify($siteName = '', $sid = 0, $torrent_id = 0)
{
$sid = $torrent['sid'];
$torrent_id = $torrent['torrent_id'];
// 拼接详情页URL
$details = str_replace('{}', $torrent_id, 'details.php?id={}&hit=1');
$details_url = $protocol . self::$sites[$sid]['base_url'] . '/' .$details;
print "种子详情页:".$details_url.PHP_EOL;
$details_html = download($details_url, $cookie, $userAgent);
// 删种检查
if (strpos($details_html, '没有该ID的种子') != false) {
echo '种子已被删除!'.PHP_EOL;
self::sendNotify('404');
return null;
}
return $details_html;
}
/**
* 微信通知cookie失效延时15秒提示
* @descr 天空、瓷器、城市 个别站用到
* @param $siteName
*/
private static function cookieExpired($siteName)
{
$msg = $siteName. '站点cookie已过期请更新后重新辅种';
$msg_md5 = md5($msg);
if (empty(static::$temp[$msg_md5])) {
self::ff($msg);
static::$temp[$msg_md5] = $msg;
}
sleepIYUU(15, 'cookie已过期请更新后重新辅种出现此提示切莫惊慌请根据提示信息手动访问种子详情页检查种子是否被删除。');
self::$errNotify = array(
'sign' => Oauth::getSign(),
'site' => $siteName,
'sid' => $sid,
'torrent_id' => $torrent_id,
);
}
/**
@ -917,6 +830,68 @@ class AutoReseed
return true;
}
/**
* 请求NexusPHP详情页
* @descr 天空、瓷器、城市 个别站用到
* @param $protocol string 协议
* @param $torrent array 种子
* @param $cookie string Cookie
* @param $userAgent string UA
* @return mixed|null
*/
private static function getNexusPHPdetailsPage($protocol, $torrent, $cookie, $userAgent)
{
$sid = $torrent['sid'];
$torrent_id = $torrent['torrent_id'];
// 拼接详情页URL
$details = str_replace('{}', $torrent_id, 'details.php?id={}&hit=1');
$details_url = $protocol . self::$sites[$sid]['base_url'] . '/' . $details;
print "种子详情页:" . $details_url . PHP_EOL;
$details_html = download($details_url, $cookie, $userAgent);
// 删种检查
if (strpos($details_html, '没有该ID的种子') != false) {
echo '种子已被删除!' . PHP_EOL;
self::sendNotify('404');
return null;
}
return $details_html;
}
/**
* 微信通知cookie失效延时15秒提示
* @descr 天空、瓷器、城市 个别站用到
* @param $siteName
*/
private static function cookieExpired($siteName)
{
$msg = $siteName . '站点cookie已过期请更新后重新辅种';
$msg_md5 = md5($msg);
if (empty(static::$temp[$msg_md5])) {
self::ff($msg);
static::$temp[$msg_md5] = $msg;
}
sleepIYUU(15, 'cookie已过期请更新后重新辅种出现此提示切莫惊慌请根据提示信息手动访问种子详情页检查种子是否被删除。');
}
/**
* 微信推送 爱语飞飞
* @param string $text
* @param string $desp
* @return false|string
*/
protected static function ff($text = '', $desp = '')
{
$token = static::$conf['iyuu.cn'];
$desp = empty($desp) ? date("Y-m-d H:i:s") : $desp;
$data = array(
'text' => $text,
'desp' => $desp
);
return ICurl::http_post('https://iyuu.cn/' . $token . '.send', $data);
}
/**
* 获取站点种子的URL
* @param string $site 站点名称
@ -1052,6 +1027,148 @@ class AutoReseed
return $signString;
}
/**
* @brief 添加下载任务
* @param $clientKey
* @param string $torrent 种子元数据
* @param string $save_path 保存路径
* @param array $extra_options
* @return bool
*/
protected static function add($clientKey, $torrent, $save_path = '', $extra_options = array())
{
try {
$is_url = static::isTorrentUrl($torrent);
// 下载服务器类型
$type = static::$links[$clientKey]['type'];
// 判断
switch ($type) {
case 'transmission':
$extra_options['paused'] = isset($extra_options['paused']) ? $extra_options['paused'] : true;
if ($is_url) {
$result = static::getRpc($clientKey)->add($torrent, $save_path, $extra_options); // URL添加
} else {
$result = static::getRpc($clientKey)->add_metainfo($torrent, $save_path, $extra_options); // 元数据添加
}
if (isset($result['result']) && $result['result'] == 'success') {
$_key = isset($result['arguments']['torrent-added']) ? 'torrent-added' : 'torrent-duplicate';
$id = $result['arguments'][$_key]['id'];
$name = $result['arguments'][$_key]['name'];
print "名字:" . $name . PHP_EOL;
print "********RPC添加下载任务成功 [" . $result['result'] . "] (id=" . $id . ")" . PHP_EOL . PHP_EOL;
return true;
} else {
$err = isset($result['result']) ? $result['result'] : '未知错误,请稍后重试!';
if (strpos($err, 'http error 404: Not Found') !== false) {
static::sendNotify('404');
}
print "-----RPC添加种子任务失败 [{$err}]" . PHP_EOL . PHP_EOL;
}
break;
case 'qBittorrent':
//如果用户的下载器设置自动种子管理,需要传入这个参数
if (isset(static::$links[$clientKey]['_config']['autoTMM'])) {
$extra_options['autoTMM'] = 'false'; //关闭自动种子管理
}
// 添加任务校验后是否暂停
if (isset($extra_options['paused'])) {
$extra_options['paused'] = $extra_options['paused'] ? 'true' : 'false';
} else {
$extra_options['paused'] = 'true';
}
// 是否创建根目录
$extra_options['root_folder'] = static::$links[$clientKey]['root_folder'] ? 'true' : 'false';
if ($is_url) {
$result = static::getRpc($clientKey)->add($torrent, $save_path, $extra_options); // URL添加
} else {
$extra_options['name'] = 'torrents';
$extra_options['filename'] = time() . '.torrent';
$result = static::getRpc($clientKey)->add_metainfo($torrent, $save_path, $extra_options); // 元数据添加
}
if ($result === 'Ok.') {
print "********RPC添加下载任务成功 [{$result}]" . PHP_EOL . PHP_EOL;
return true;
} else {
print "-----RPC添加种子任务失败 [{$result}]" . PHP_EOL . PHP_EOL;
}
break;
default:
echo '[下载器类型错误] ' . $type . PHP_EOL . PHP_EOL;
break;
}
} catch (Exception $e) {
echo '[添加下载任务出错] ' . $e->getMessage() . PHP_EOL;
}
return false;
}
/**
* 判断内容是否为种子的URL链接
* @param string $torrent
* @return bool
*/
protected static function isTorrentUrl(string $torrent)
{
return (stripos($torrent, 'http://') === 0) || (stripos($torrent, 'https://') === 0) || (strpos($torrent, 'magnet:?xt=urn:btih:') === 0);
}
/**
* 优化IDE跟踪
* @param string $clientKey
* @return qBittorrent|transmission
*/
public static function getRpc(string $clientKey)
{
return static::$links[$clientKey]['rpc'];
}
/**
* 错误的种子通知服务器
* @param string $error
* @return bool
*/
private static function sendNotify($error = '')
{
self::$errNotify['error'] = $error;
// 存在错误通知缓存,直接返回(减少请求次数)
$errNotifyCacheFile = self::errNotifyCacheFile(self::$errNotify['sid'], self::$errNotify['torrent_id']);
if (is_file($errNotifyCacheFile)) {
echo '感谢您的参与,失效种子已经成功汇报过!!' . PHP_EOL;
return true;
}
// 创建错误通知缓存
file_put_contents($errNotifyCacheFile, json_encode(self::$errNotify, JSON_UNESCAPED_UNICODE));
$notify = http_build_query(self::$errNotify);
self::$errNotify = array(
'sign' => '',
'site' => '',
'sid' => 0,
'torrent_id' => 0,
'error' => '',
);
$res = self::$curl->get(Constant::API_BASE . Constant::API['notify'] . '?' . $notify);
$res = json_decode($res->response, true);
if (isset($res['data']['success']) && $res['data']['success']) {
echo '感谢您的参与,失效种子上报成功!!' . PHP_EOL;
}
return true;
}
/**
* 拼接错误通知缓存的文件路径
* @param int $site_id
* @param int $torrent_id
* @return string
*/
private static function errNotifyCacheFile($site_id = 0, $torrent_id = 0)
{
$filename = $site_id . '_' . $torrent_id . '.txt';
return self::$cacheNotify . $filename;
}
/**
* 微信模板消息拼接方法
* @return string 发送情况json
@ -1106,110 +1223,4 @@ class AutoReseed
$desp .= $br . '*此消息将在3天后过期*。';
return self::ff($text, $desp);
}
/**
* 错误的种子通知服务器
* @param string $error
* @return bool
*/
private static function sendNotify($error = '')
{
self::$errNotify['error'] = $error;
// 存在错误通知缓存,直接返回(减少请求次数)
$errNotifyCacheFile = self::errNotifyCacheFile(self::$errNotify['sid'], self::$errNotify['torrent_id']);
if (is_file($errNotifyCacheFile)) {
echo '感谢您的参与,失效种子已经成功汇报过!!'.PHP_EOL;
return true;
}
// 创建错误通知缓存
file_put_contents($errNotifyCacheFile, json_encode(self::$errNotify, JSON_UNESCAPED_UNICODE));
$notify = http_build_query(self::$errNotify);
self::$errNotify = array(
'sign' => '',
'site' => '',
'sid' => 0,
'torrent_id'=> 0,
'error' => '',
);
$res = self::$curl->get(Constant::API_BASE . Constant::API['notify'] . '?' . $notify);
$res = json_decode($res->response, true);
if (isset($res['data']['success']) && $res['data']['success']) {
echo '感谢您的参与,失效种子上报成功!!'.PHP_EOL;
}
return true;
}
/**
* 拼接错误通知缓存的文件路径
* @param int $site_id
* @param int $torrent_id
* @return string
*/
private static function errNotifyCacheFile($site_id = 0, $torrent_id = 0)
{
$filename = $site_id . '_' . $torrent_id . '.txt';
return self::$cacheNotify . $filename;
}
/**
* 设置通知主体
* @param string $siteName
* @param int $sid
* @param int $torrent_id
*/
private static function setNotify($siteName = '', $sid = 0, $torrent_id = 0)
{
self::$errNotify = array(
'sign' => Oauth::getSign(),
'site' => $siteName,
'sid' => $sid,
'torrent_id'=> $torrent_id,
);
}
/**
* 微信推送 爱语飞飞
* @param string $text
* @param string $desp
* @return false|string
*/
protected static function ff($text='', $desp='')
{
$token = static::$conf['iyuu.cn'];
$desp = empty($desp) ? date("Y-m-d H:i:s") : $desp;
$data = array(
'text' => $text,
'desp' => $desp
);
return ICurl::http_post('https://iyuu.cn/'.$token.'.send', $data);
}
/**
* 追加式写入日志
* @param string|int|array|object $data
* @param string $name
* @param string $path
* @return bool|int
*/
protected static function wLog($data, string $name = '', string $path = '')
{
if (is_bool($data)) {
$show_data = $data ? 'true' : 'false';
} elseif (is_null($data)) {
$show_data = 'null';
} else {
$show_data = print_r($data, true);
}
// 写入日志
$dir = empty($path) ? static::$cacheDir : $path;
IFile::mkdir($dir);
$file = $dir . $name . '.txt';
$pointer = @fopen($file, "a");
$result = @fwrite($pointer, $show_data);
@fclose($pointer);
return $result;
}
}

View File

@ -1,4 +1,5 @@
<?php
namespace IYUU\Reseed;
use app\domain\ConfigParser\Move as domainMove;
@ -32,6 +33,7 @@ class MoveTorrent extends AutoReseed
'MoveSuccess' => 0, // 移动成功
'MoveError' => 0, // 移动失败
);
/**
* 初始化
*/
@ -172,7 +174,8 @@ class MoveTorrent extends AutoReseed
if (empty($parsed_torrent['announce'])) {
$needPatchTorrent = true;
}
} catch (ParseException $e) {}
} catch (ParseException $e) {
}
if ($needPatchTorrent) {
echo '未发现tracker信息尝试补充tracker信息...' . PHP_EOL;
if (empty($parsed_torrent)) {

View File

@ -1,4 +1,5 @@
<?php
namespace IYUU\Reseed;
use Curl\Curl;
@ -8,9 +9,9 @@ use Curl\Curl;
*/
class Oauth
{
private static $conf = [];
// 登录缓存路径
const SiteLoginCache = RUNTIME_PATH . DS . 'db' . DS . 'siteLoginCache_{}.json';
// 登录缓存路径
private static $conf = [];
/**
* 初始化
@ -23,20 +24,6 @@ class Oauth
self::$conf = $config;
}
/**
* 从配置文件内读取爱语飞飞token作为鉴权参数
*/
public static function getSign()
{
$token = empty(self::$conf['iyuu.cn']) ? '' : self::$conf['iyuu.cn'];
if (empty($token) || strlen($token) < 46) {
echo "缺少辅种接口请求参数爱语飞飞token ".PHP_EOL;
echo "请访问https://iyuu.cn 用微信扫码申请。".PHP_EOL.PHP_EOL;
exit(1);
}
return $token;
}
/**
* 用户注册与登录
* 作用在服务器端实现微信用户与合作站点用户id的关联
@ -92,6 +79,20 @@ class Oauth
return $ret;
}
/**
* 从配置文件内读取爱语飞飞token作为鉴权参数
*/
public static function getSign()
{
$token = empty(self::$conf['iyuu.cn']) ? '' : self::$conf['iyuu.cn'];
if (empty($token) || strlen($token) < 46) {
echo "缺少辅种接口请求参数爱语飞飞token " . PHP_EOL;
echo "请访问https://iyuu.cn 用微信扫码申请。" . PHP_EOL . PHP_EOL;
exit(1);
}
return $token;
}
/**
* 写鉴权成功缓存
* @desc 作用:减少对服务器请求,跳过鉴权提示信息;

View File

@ -1,4 +1,5 @@
<?php
namespace IYUU\Rss;
use DOMDocument;
@ -10,11 +11,25 @@ use app\domain\ConfigParser\Rss as domainRss;
abstract class AbstractRss
{
const encoding = 'UTF-8';
const CONNECTTIMEOUT = 30;
const TIMEOUT = 600;
/**
* 站点名转换为文件名,所使用的映射表
*/
const SITENAME_TO_FILENAME_MAP = Constant::SITENAME_TO_FILENAME_MAP;
/**
* 运行时解析的配置
* @var array
*/
protected static $conf = [];
// 网页编码
/**
* 站点标志
* @var string
*/
public $site = '';
// 超时时间
/**
* 域名
* @var string
@ -32,11 +47,6 @@ abstract class AbstractRss
* RSS订阅的默认页面
*/
public $rss_page = 'torrentrss.php?rows=50&linktype=dl&passkey={}';
// 网页编码
const encoding = 'UTF-8';
// 超时时间
const CONNECTTIMEOUT = 30;
const TIMEOUT = 600;
/**
* curl
* @var Curl
@ -46,7 +56,6 @@ abstract class AbstractRss
* passkey
*/
public $passkey = '';
/**
* 种子ID正则
* @var string
@ -54,15 +63,75 @@ abstract class AbstractRss
public $torrent_id_regex = '/id=(\d+)/i';
/**
* 运行时解析的配置
* @var array
* 构造方法,配置应用信息
* @param bool $init 是否初始化domainRss获取全部站点名时候需要到
*/
protected static $conf = [];
final public function __construct($init = true)
{
if ($init) {
echo $this->site . " 正在初始化RSS配置..." . PHP_EOL;
//cli(self::$conf);
$this->_initialize();
$this->init();
echo $this->site . " RSS解码类实例化成功" . PHP_EOL;
}
}
/**
* 站点名转换为文件名,所使用的映射表
* 初始化 第一步,初始化父类的关键参数
*/
const SITENAME_TO_FILENAME_MAP = Constant::SITENAME_TO_FILENAME_MAP;
final protected function _initialize()
{
//云端下发
$this->host = static::getHost(); // 示例https://baidu.com/
// 初始化curl
$this->curl = new Curl();
$this->curl->setOpt(CURLOPT_SSL_VERIFYPEER, false); // 禁止验证对等证书
//$this->curl->setOpt(CURLOPT_SSL_VERIFYHOST, 2); // 检查证书
$this->curl->setOpt(CURLOPT_CONNECTTIMEOUT, self::CONNECTTIMEOUT); // 超时
$this->curl->setOpt(CURLOPT_TIMEOUT, self::TIMEOUT); // 超时
$this->curl->setOpt(CURLOPT_FOLLOWLOCATION, 1); // 自动跳转跟随请求Location
$this->curl->setOpt(CURLOPT_MAXREDIRS, 2); // 递归次数
$this->curl->setUserAgent(static::getUserAgent());
}
/**
* 获得当前站点HOST
* @return string
*/
protected static function getHost(): string
{
//站点配置
$sites = static::$conf['sites'];
$protocol = isset($sites['is_https']) && ($sites['is_https'] === 0) ? 'http://' : 'https://';
$domain = $sites['base_url'];
return $protocol . $domain . '/'; // 示例https://baidu.com/
}
/**
* 获得用户浏览器UA
* @return string
*/
protected static function getUserAgent(): string
{
//常规配置
$default = empty(static::$conf['default']) ? [] : static::$conf['default'];
return !empty($default['ua']) ? $default['ua'] : Constant::UserAgent;
}
/**
* 初始化 第二步,子类可以重写此方法
*/
protected function init()
{
//站点配置
$config = static::$conf['site'];
$this->passkey = !empty($config['passkey']) ? $config['passkey'] : '';
if (empty($this->passkey)) {
die($this->site . ' 没有配置密钥,初始化错误。' . PHP_EOL);
}
}
/**
* 实例化
@ -140,65 +209,127 @@ abstract class AbstractRss
}
/**
* 构造方法,配置应用信息
* @param bool $init 是否初始化domainRss获取全部站点名时候需要到
* 获取配置
* @param null $key 配置键值
* @param null $default 默认
* @return array|mixed|null
*/
final public function __construct($init = true)
public static function getConfig($key = null, $default = null)
{
if ($init) {
echo $this->site." 正在初始化RSS配置...". PHP_EOL;
//cli(self::$conf);
$this->_initialize();
$this->init();
echo $this->site." RSS解码类实例化成功".PHP_EOL;
if ($key === null) {
return self::$conf;
}
$key_array = \explode('.', $key);
$value = self::$conf;
foreach ($key_array as $index) {
if (!isset($value[$index])) {
return $default;
}
$value = $value[$index];
}
return $value;
}
/**
* 公共方法实现rss订阅下载子类可以重写此方法
* @return void
*/
public function run()
{
echo "正在初始化RPC链接..." . PHP_EOL;
Rpc::init($this->site, static::getTorrentDownloadMethod($this->site), self::$conf);
$html = $this->get();
#cli($html);
$this->checkCallback($html);
$data = $this->decode($html);
echo "已解码正在推送给RPC下载器..." . PHP_EOL;
//cli($data);exit;
Rpc::call($data);
exit(0);
}
/**
* 取站点下载种子时使用的方法(post/get)
* @param string $site_name
* @return string
*/
public static function getTorrentDownloadMethod(string $site_name): string
{
$method = Constant::SITE_DOWNLOAD_METHOD_POST;
return in_array($site_name, $method) ? 'POST' : 'GET';
}
/**
* 请求url获取html页面子类可以重写此方法
* @return string
*/
public function get()
{
if (!empty(static::$conf['urladdress'])) {
$url = static::$conf['urladdress'];
} else {
$url = $this->rss_page;
}
if (empty($url)) {
die('缺少 rss.page 配置');
}
$url = str_replace("{}", $this->passkey, $url);
echo $this->site . " 正在请求RSS... {$url}" . PHP_EOL;
$url = (stripos($url, 'http://') === 0 || stripos($url, 'https://') === 0) ? $url : $this->host . $url;
$res = $this->curl->get($url);
//cli($res);exit;
if ($res->http_status_code == 200) {
echo "RSS获取信息成功" . PHP_EOL;
return $res->response;
}
echo "RSS获取信息失败请重试" . PHP_EOL;
return null;
}
/**
* 回调函数,子类可以重写此方法
* @param string $html
*/
public function checkCallback($html = '')
{
if (strpos((string)$html, 'invalid passkey') !== false) {
die('passkey填写错误请重新填写');
}
if (is_null($html)) {
exit(1);
}
}
/**
* 初始化 第一步,初始化父类的关键参数
* 抽象方法,在子类中实现
* 解码html为种子数组
* @param string $html
* @return array
* Array
* (
* [id] => 118632
* [h1] => CCTV5+ 2019 ATP Men's Tennis Final 20191115B HDTV 1080i H264-HDSTV
* [title] => 央视体育赛事频道 2019年ATP男子网球年终总决赛 单打小组赛 纳达尔VS西西帕斯 20191115[优惠剩余时间4时13分]
* [details] => https://xxx.me/details.php?id=118632
* [download] => https://xxx.me/download.php?id=118632
* [filename] => 118632.torrent
* [type] => 0
* [sticky] => 1
* [time] => Array
* (
* [0] => "2019-11-16 20:41:53">4时13分
* [1] => "2019-11-16 14:41:53">1<br />46
* )
* [comments] => 0
* [size] => 5232.64MB
* [seeders] => 69
* [leechers] => 10
* [completed] => 93
* [percentage] => 100%
* [owner] => 匿名
* )
*/
final protected function _initialize()
{
//云端下发
$this->host = static::getHost(); // 示例https://baidu.com/
// 初始化curl
$this->curl = new Curl();
$this->curl->setOpt(CURLOPT_SSL_VERIFYPEER, false); // 禁止验证对等证书
//$this->curl->setOpt(CURLOPT_SSL_VERIFYHOST, 2); // 检查证书
$this->curl->setOpt(CURLOPT_CONNECTTIMEOUT, self::CONNECTTIMEOUT); // 超时
$this->curl->setOpt(CURLOPT_TIMEOUT, self::TIMEOUT); // 超时
$this->curl->setOpt(CURLOPT_FOLLOWLOCATION, 1); // 自动跳转跟随请求Location
$this->curl->setOpt(CURLOPT_MAXREDIRS, 2); // 递归次数
$this->curl->setUserAgent(static::getUserAgent());
}
/**
* 初始化 第二步,子类可以重写此方法
*/
protected function init()
{
//站点配置
$config = static::$conf['site'];
$this->passkey = !empty($config['passkey']) ? $config['passkey'] : '';
if (empty($this->passkey)) {
die($this->site.' 没有配置密钥,初始化错误。'.PHP_EOL);
}
}
/**
* 过滤XML文档中不需要的元素子类可以重写此方法
* @param DOMDocument $item
* @return DOMDocument | DOMNode
*/
protected function filterNexusPHP($item)
{
$node = $item->getElementsByTagName('description')->item(0);
if ($node != null) {
$item->removeChild($node);
}
return $item;
}
abstract public function decode($html = '');
/**
* NexusPHP通用RSS解码子类可以重写此方法
@ -246,149 +377,16 @@ abstract class AbstractRss
}
/**
* 取站点下载种子时使用的方法(post/get)
* @param string $site_name
* @return string
* 过滤XML文档中不需要的元素子类可以重写此方法
* @param DOMDocument $item
* @return DOMDocument | DOMNode
*/
public static function getTorrentDownloadMethod(string $site_name):string
protected function filterNexusPHP($item)
{
$method = Constant::SITE_DOWNLOAD_METHOD_POST;
return in_array($site_name, $method) ? 'POST' : 'GET';
$node = $item->getElementsByTagName('description')->item(0);
if ($node != null) {
$item->removeChild($node);
}
/**
* 公共方法实现rss订阅下载子类可以重写此方法
* @return void
*/
public function run()
{
echo "正在初始化RPC链接...". PHP_EOL;
Rpc::init($this->site, static::getTorrentDownloadMethod($this->site), self::$conf);
$html = $this->get();
#cli($html);
$this->checkCallback($html);
$data = $this->decode($html);
echo "已解码正在推送给RPC下载器...". PHP_EOL;
//cli($data);exit;
Rpc::call($data);
exit(0);
}
/**
* 请求url获取html页面子类可以重写此方法
* @return string
*/
public function get()
{
if (!empty(static::$conf['urladdress'])) {
$url = static::$conf['urladdress'];
} else {
$url = $this->rss_page;
}
if (empty($url)) {
die('缺少 rss.page 配置');
}
$url = str_replace("{}", $this->passkey, $url);
echo $this->site." 正在请求RSS... {$url}". PHP_EOL;
$url = (stripos($url, 'http://') === 0 || stripos($url, 'https://') === 0) ? $url : $this->host . $url;
$res = $this->curl->get($url);
//cli($res);exit;
if ($res->http_status_code == 200) {
echo "RSS获取信息成功". PHP_EOL;
return $res->response;
}
echo "RSS获取信息失败请重试". PHP_EOL;
return null;
}
/**
* 回调函数,子类可以重写此方法
* @param string $html
*/
public function checkCallback($html = '')
{
if (strpos((string)$html, 'invalid passkey') !== false) {
die('passkey填写错误请重新填写');
}
if (is_null($html)) {
exit(1);
return $item;
}
}
/**
* 获取配置
* @param null $key 配置键值
* @param null $default 默认
* @return array|mixed|null
*/
public static function getConfig($key = null, $default = null)
{
if ($key === null) {
return self::$conf;
}
$key_array = \explode('.', $key);
$value = self::$conf;
foreach ($key_array as $index) {
if (!isset($value[$index])) {
return $default;
}
$value = $value[$index];
}
return $value;
}
/**
* 获得当前站点HOST
* @return string
*/
protected static function getHost():string
{
//站点配置
$sites = static::$conf['sites'];
$protocol = isset($sites['is_https']) && ($sites['is_https'] === 0) ? 'http://' : 'https://';
$domain = $sites['base_url'];
return $protocol . $domain . '/'; // 示例https://baidu.com/
}
/**
* 获得用户浏览器UA
* @return string
*/
protected static function getUserAgent():string
{
//常规配置
$default = empty(static::$conf['default']) ? [] : static::$conf['default'];
return !empty($default['ua']) ? $default['ua'] : Constant::UserAgent;
}
/**
* 抽象方法,在子类中实现
* 解码html为种子数组
* @param string $html
* @return array
* Array
(
[id] => 118632
[h1] => CCTV5+ 2019 ATP Men's Tennis Final 20191115B HDTV 1080i H264-HDSTV
[title] => 央视体育赛事频道 2019年ATP男子网球年终总决赛 单打小组赛 纳达尔VS西西帕斯 20191115[优惠剩余时间4时13分]
[details] => https://xxx.me/details.php?id=118632
[download] => https://xxx.me/download.php?id=118632
[filename] => 118632.torrent
[type] => 0
[sticky] => 1
[time] => Array
(
[0] => "2019-11-16 20:41:53">4时13分
[1] => "2019-11-16 14:41:53">1<br />46
)
[comments] => 0
[size] => 5232.64MB
[seeders] => 69
[leechers] => 10
[completed] => 93
[percentage] => 100%
[owner] => 匿名
)
*/
abstract public function decode($html = '');
}

View File

@ -2,6 +2,7 @@
/**
* beitai RSS解码类
*/
namespace IYUU\Rss;
class beitai extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* btschool RSS解码类
*/
namespace IYUU\Rss;
class btschool extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* chdbits RSS解码类
*/
namespace IYUU\Rss;
class chdbits extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* discfan RSS解码类
*/
namespace IYUU\Rss;
class discfan extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* dmhy RSS解码类
*/
namespace IYUU\Rss;
class dmhy extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* beitai RSS解码类
*/
namespace IYUU\Rss;
class dragonhd extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* eastgame RSS解码类
*/
namespace IYUU\Rss;
class eastgame extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* chdbits RSS解码类
*/
namespace IYUU\Rss;
class haidan extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* hd4fans RSS解码类
*/
namespace IYUU\Rss;
class hd4fans extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* hdai RSS解码类
*/
namespace IYUU\Rss;
class hdai extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* hdarea RSS解码类
*/
namespace IYUU\Rss;
class hdarea extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* hdatmos RSS解码类
*/
namespace IYUU\Rss;
class hdatmos extends AbstractRss

View File

@ -1,4 +1,5 @@
<?php
namespace IYUU\Rss;
use DOMDocument;
@ -22,6 +23,7 @@ class hdbits extends AbstractRss
* RSS订阅页面
*/
public $rss_page = 'rss/feed?passkey={}';
/**
* 抽象方法,在类中实现
* 请求url获取html页面

View File

@ -2,6 +2,7 @@
/**
* hdchina RSS解码类
*/
namespace IYUU\Rss;
class hdchina extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* hdcity RSS解码类
*/
namespace IYUU\Rss;
use Curl\Curl;

View File

@ -2,6 +2,7 @@
/**
* hddolby RSS解码类
*/
namespace IYUU\Rss;
class hddolby extends AbstractRss
@ -24,6 +25,7 @@ class hddolby extends AbstractRss
die($this->site . ' 没有配置密钥,初始化错误。' . PHP_EOL);
}
}
/**
* 抽象方法,在类中实现
* 解码html为种子数组

View File

@ -2,6 +2,7 @@
/**
* hdfans RSS解码类
*/
namespace IYUU\Rss;
class hdfans extends AbstractRss

View File

@ -2,18 +2,18 @@
/**
* hdhome RSS解码类
*/
namespace IYUU\Rss;
class hdhome extends AbstractRss
{
public static $official = array('HDHome', 'HDH', 'HDHTV', 'HDHPad', 'HDHWEB');
/**
* 站点标志
* @var string
*/
public $site = 'hdhome';
public static $official = array('HDHome','HDH','HDHTV','HDHPad','HDHWEB');
/**
* 初始化 第二步
*/
@ -26,6 +26,7 @@ class hdhome extends AbstractRss
die($this->site . ' 没有配置密钥,初始化错误。' . PHP_EOL);
}
}
/**
* 抽象方法,在类中实现
* 解码html为种子数组

View File

@ -1,4 +1,5 @@
<?php
namespace IYUU\Rss;
use DOMDocument;

View File

@ -2,18 +2,18 @@
/**
* hdsky RSS解码类
*/
namespace IYUU\Rss;
class hdsky extends AbstractRss
{
public static $official = array('HDSky', 'HDS', 'HDSPad', 'LUTV', 'iHD', 'HDSCD', 'HDSTV', 'HDSWEB');
/**
* 站点标志
* @var string
*/
public $site = 'hdsky';
public static $official = array('HDSky','HDS','HDSPad','LUTV','iHD','HDSCD','HDSTV','HDSWEB');
/**
* 抽象方法,在类中实现
* 解码html为种子数组

View File

@ -2,6 +2,7 @@
/**
* hdtime RSS解码类
*/
namespace IYUU\Rss;
class hdtime extends AbstractRss

View File

@ -1,4 +1,5 @@
<?php
namespace IYUU\Rss;
use DOMDocument;

View File

@ -2,6 +2,7 @@
/**
* hdzone RSS解码类
*/
namespace IYUU\Rss;
class hdzone extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* hitpt RSS解码类
*/
namespace IYUU\Rss;
class hitpt extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* joyhd RSS解码类
*/
namespace IYUU\Rss;
class joyhd extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* keepfrds RSS解码类
*/
namespace IYUU\Rss;
class keepfrds extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* leaguehd RSS解码类
*/
namespace IYUU\Rss;
class leaguehd extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* mteam RSS解码类
*/
namespace IYUU\Rss;
class mteam extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* nanyangpt RSS解码类
*/
namespace IYUU\Rss;
class nanyangpt extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* nicept RSS解码类
*/
namespace IYUU\Rss;
class nicept extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* npupt RSS解码类
*/
namespace IYUU\Rss;
class npupt extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* opencd RSS解码类
*/
namespace IYUU\Rss;
class opencd extends AbstractRss

View File

@ -2,6 +2,7 @@
/**
* oshen RSS解码类
*/
namespace IYUU\Rss;
class oshen extends AbstractRss

Some files were not shown because too many files have changed in this diff Show More