perf: 增加原生缓存

This commit is contained in:
Ying
2023-06-19 14:36:07 +08:00
parent 2b8f874450
commit 331d7b0582
1486 changed files with 105475 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
<?php
namespace app\common\bootstrap;
use support\Cache;
use support\Log;
use think\Container;
use think\DbManager;
use Webman\Bootstrap;
use Workerman\Timer;
use Workerman\Worker;
class RedisCache implements Bootstrap
{
public static function start(?Worker $worker)
{
// TODO: Implement start() method.
if ($worker) {
try {
Timer::add(55, function () {
Cache::get('ping');
});
} catch (\Throwable $e) {
Log::error('RedisCache error: ' . $e->getMessage());
}
}
if (class_exists(DbManager::class)) {
$manager_instance = Container::getInstance()->make(DbManager::class);
$manager_instance->setCache(Cache::instance());
}
}
}

View File

@@ -0,0 +1,226 @@
<?php
declare(strict_types=1);
// +----------------------------------------------------------------------
// | swiftAdmin 极速开发框架 [基于WebMan开发]
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2030 http://www.swiftadmin.net
// +----------------------------------------------------------------------
// | swiftAdmin.net High Speed Development Framework
// +----------------------------------------------------------------------
// | Author: meystack <coolsec@foxmail.com> Apache 2.0 License
// +----------------------------------------------------------------------
namespace app\common\driver\notice;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\PHPMailer;
use Psr\SimpleCache\InvalidArgumentException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
class EmailDriver
{
/**
* @PHPMailer 对象实例
*/
public object $mail;
//默认配置
protected array $config = [
'smtp_debug' => false, // 是否调试
'smtp_host' => 'smtp.163.com', // 服务器地址
'smtp_port' => 587, // 服务器端口
'smtp_user' => 'yourname@163.com', // 邮件用户名
'smtp_pass' => '****', // 邮件密码
'smtp_name' => '管理员', // 发送邮件显示
];
/**
* 类构造函数
* class constructor.
* @throws DataNotFoundException
* @throws DbException
* @throws Exception
* @throws ModelNotFoundException
* @throws InvalidArgumentException
*/
public function __construct()
{
// 此配置项为数组
$email = saenv('email');
$this->config = array_merge($this->config, $email);
// 创建PHPMailer对象实例
$this->mail = new PHPMailer();
$this->mail->CharSet = 'UTF-8';
$this->mail->IsSMTP();
/**
* 是否开启调试模式
*/
$this->mail->SMTPDebug = $this->config['smtp_debug'];
$this->mail->SMTPAuth = true;
$this->mail->SMTPSecure = 'ssl';
$this->mail->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
);
$this->mail->Host = $this->config['smtp_host'];
$this->mail->Port = $this->config['smtp_port'];
$this->mail->Username = $this->config['smtp_user'];
$this->mail->Password = trim($this->config['smtp_pass']);
$this->mail->SetFrom($this->config['smtp_user'], $this->config['smtp_name']);
}
/**
* 设置邮件主题
* @param string $subject 邮件主题
* @return $this
*/
public function Subject(string $subject): EmailDriver
{
$this->mail->Subject = $subject;
return $this;
}
/**
* 设置发件人
* @param string $email 发件人邮箱
* @param string $name 发件人名称
* @return $this
* @throws Exception
*/
public function from(string $email, string $name = ''): EmailDriver
{
$this->mail->setFrom($email, $name);
return $this;
}
/**
* 设置邮件内容
* @param $MsgHtml
* @param boolean $isHtml 是否HTML格式
* @return $this
* @throws Exception
*/
public function MsgHTML($MsgHtml, bool $isHtml = true): EmailDriver
{
if ($isHtml) {
$this->mail->msgHTML($MsgHtml);
} else {
$this->mail->Body = $MsgHtml;
}
return $this;
}
/**
* 设置收件人
* @param $email
* @return $this
* @throws Exception
*/
public function address($email): EmailDriver
{
$list = $this->buildAddress($email);
foreach ($list as $address => $name) {
$this->mail->addAddress($address, $name);
}
return $this;
}
/**
* 构建Email地址
* @param $emails
* @return array
*/
protected function buildAddress($emails): array
{
if (!is_array($emails)) {
$emails = explode(',', str_replace(";", ",", $emails));
}
foreach ($emails as $key => $value) {
$list[is_numeric($key) ? $value : $key] = is_numeric($key) ? "" : $value;
}
return $list ?? [];
}
/**
* 设置抄送
* @param string $address
* @param string $name
* @return EmailDriver
* @throws @\PHPMailer\PHPMailer\Exception
*/
public function addCC(string $address, string $name = ''): EmailDriver
{
$this->mail->addCC($address, $name);
return $this;
}
/**
* 设置密送
* @param string $address
* @param string $name
* @return EmailDriver
* @throws @\PHPMailer\PHPMailer\Exception
*/
public function addBCC(string $address, string $name = ''): EmailDriver
{
$this->mail->addBCC($address, $name);
return $this;
}
/**
* 添加附件
* @param string $path 附件路径
* @param string $name 附件名称
* @throws Exception
*/
public function attachment(string $path, string $name = ''): EmailDriver
{
if (is_file($path)) {
$this->mail->addAttachment($path, $name);
}
return $this;
}
/**
* 发送邮件
* @return boolean
* @throws Exception
*/
public function send(): bool
{
if (!$this->mail->send()) {
throw new Exception($this->mail->ErrorInfo);
}
return true;
}
/**
* 测试发送邮件
* @param array $config
* @return bool
* @throws Exception
*/
public function testEmail(array $config = []): bool
{
$this->config = array_merge($this->config, $config);
$this->mail->Host = $this->config['smtp_host'];
$this->mail->Port = $this->config['smtp_port'];
$this->mail->Username = $this->config['smtp_user'];
$this->mail->Password = trim($this->config['smtp_pass']);
$this->mail->SetFrom($this->config['smtp_user'], $this->config['smtp_name']);
if (!$this->address($config['smtp_test'])->Subject("测试邮件")->MsgHTML("如果您看到这封邮件,说明测试成功了!")->send()) {
throw new Exception($this->mail->ErrorInfo);
}
return true;
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace app\common\exception;
/**
* 全局操作异常类
* Class OperateException
* @package app\common\exception
*/
class DumpException extends \Exception
{
/**
* 附加数据
* @var array
*/
public array $data = [];
public function __construct($message = '', $code = 0, array $data = [], \Throwable $previous = null)
{
$this->data = $data;
$this->code = $code;
$this->message = $message;
parent::__construct($this->message, $this->code, $previous);
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace app\common\exception;
use app\common\library\ResultCode;
/**
* 全局操作异常类
* Class OperateException
* @package app\common\exception
*/
class OperateException extends \Exception
{
/**
* 附加数据
* @var array
*/
public array $data = [];
public function __construct($message = '', $code = 0, array $data = [], \Throwable $previous = null)
{
$this->data = $data;
$this->code = $code ?: ResultCode::UNKNOWN['code'];
$this->message = $message ?: ResultCode::UNKNOWN['msg'];
parent::__construct($this->message, $this->code, $previous);
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace app\common\exception\user;
use app\common\library\ResultCode;
/**
* 用户异常类
* Class UserException
*/
class UserException extends \Exception
{
/**
* 附加数据
* @var array
*/
public array $data = [];
public function __construct($message = '', $code = 0, array $data = [], \Throwable $previous = null)
{
$this->data = $data;
$this->code = $code ?: ResultCode::UNKNOWN['code'];
$this->message = $message ?: ResultCode::UNKNOWN['msg'];
parent::__construct($this->message, $this->code, $previous);
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace app\common\logic\user;
use app\common\service\BaseServiceLogic;
/**
* 用户逻辑层
* Class UserLogic
*/
class UserLogic extends BaseServiceLogic
{
}

View File

@@ -0,0 +1,89 @@
<?php
namespace app\common\service;
/**
* 基础服务类
* @package app\common\service
*/
class BaseServiceLogic
{
/**
* 返回状态码
* @var int
*/
protected static int $code = 0;
/**
* 错误信息
* @var string
*/
protected static string $error;
/**
* 返回数据
* @var array
*/
protected static array $data;
/**
* 设置返回状态码
* @param int $code
* @return void
*/
public static function setCode(int $code): void
{
self::$code = $code;
}
/**
* 获取返回状态码
* @return int
* @return void
*/
public static function getCode(): int
{
return self::$code;
}
/**
* 设置错误信息
* @param string $error
* @return void
*/
public static function setError(string $error): void
{
self::$error = $error;
}
/**
* 获取错误信息
* @return string
* @return void
*/
public static function getError(): string
{
return self::$error;
}
/**
* 设置返回数据
* @param array $data
* @return void
*/
public static function setData(array $data): void
{
self::$data = $data;
}
/**
* 获取返回数据
* @return array
* @return void
*/
public static function getData(): array
{
return self::$data;
}
}

View File

@@ -0,0 +1,171 @@
<?php
declare(strict_types=1);
// +----------------------------------------------------------------------
// | swiftAdmin 极速开发框架 [基于WebMan开发]
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2030 http://www.swiftadmin.net
// +----------------------------------------------------------------------
// | swiftAdmin.net High Speed Development Framework
// +----------------------------------------------------------------------
// | Author: meystack <coolsec@foxmail.com> Apache 2.0 License
// +----------------------------------------------------------------------
namespace app\common\service\notice;
use app\common\driver\notice\EmailDriver;
use app\common\exception\OperateException;
use app\common\model\system\User;
use app\common\model\system\UserValidate;
use PHPMailer\PHPMailer\Exception;
use Psr\SimpleCache\InvalidArgumentException;
use support\App;
use system\Random;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
class EmailService
{
/**
* 发送间隔时间
* @var int
*/
const EMAIL_SEND_INTERVAL = 60;
/**
* 验证码过期时间
* @var int
*/
const EXPIRE_TIME = 5; //验证码过期时间(分钟)
/**
* 发送邮件
* @param $email
* @param $title
* @param $content
* @return bool
* @throws \Exception
*/
public static function send($email, $title, $content): bool
{
$eDriver = new EmailDriver();
try {
$eDriver->address($email)->Subject($title)->MsgHTML($content)->send();
} catch (\PHPMailer\PHPMailer\Exception $e) {
throw new \Exception($e->getMessage());
}
return true;
}
/**
* 发送验证码
* @param $email
* @param $event
* @return bool
* @throws OperateException
* @throws InvalidArgumentException
*/
public static function captcha($email, $event): bool
{
$result = self::getLastMsg($email, $event);
if (!empty($result) && time() - strtotime($result['create_time']) < self::EMAIL_SEND_INTERVAL) {
throw new OperateException(__('发送频繁'));
}
$userinfo = (new User())->where('email', $email)->findOrEmpty()->toArray();
if (in_array($event, ['register', 'change']) && $userinfo) {
throw new OperateException(__('当前邮箱已被注册'));
} else if ($event == 'forgot' && !$userinfo) {
throw new OperateException(__('当前邮箱不存在'));
}
$captcha = Random::number();
$filePath = root_path() . 'extend/conf/tpl/captcha.tpl';
if (!is_file($filePath)) {
throw new OperateException(__('验证码模板不存在'));
}
$eDriver = new EmailDriver();
$data = [$captcha, saenv('site_name'), date('Y-m-d H:i:s')];
$content = str_replace(['{code}', '{site_name}', '{time}'], $data, read_file($filePath));
try {
// 发送邮件
$eDriver->address($email)->Subject("验证码")->MsgHTML($content)->send();
// 保存验证码
(new UserValidate())->create([
'code' => $captcha,
'event' => $event,
'email' => $email,
'status' => 1,
]);
} catch (\Throwable $th) {
throw new OperateException(__('验证码发送失败'));
}
return true;
}
/**
* 校验验证码
* @param $email
* @param $code
* @param $event
* @return bool
* @throws \Exception
*/
public static function checkCaptcha($email, $code, $event): bool
{
$model = new UserValidate();
$result = $model->where([
['event', '=', $event],
['email', '=', $email],
['code', '=', $code],
['status', '=', 1],
])->order("id", "desc")->findOrEmpty()->toArray();
if (!empty($result)) {
$model->where('id', $result['id'])->update(['status' => 0]);
$expires = time() - strtotime($result['create_time']);
if ($expires <= self::EXPIRE_TIME * 60) {
return true;
}
}
return false;
}
/**
* 获取最后一条
* @param string $email
* @param string $event
* @return array
*/
public static function getLastMsg(string $email, string $event): array
{
return (new UserValidate())->where([
['email', '=', $email],
['event', '=', $event],
])->order('id', 'desc')->findOrEmpty()->toArray();
}
/**
* 过滤邮箱格式
* @param string $email
* @return string
*/
public static function filterEmail(string $email): string
{
return filter_var($email, FILTER_SANITIZE_EMAIL);
}
/**
* @param array $params
* @return bool
* @throws Exception
*/
public static function testEmail(array $params = []): bool
{
$eDriver = new EmailDriver();
return $eDriver->testEmail($params);
}
}

View File

@@ -0,0 +1,159 @@
<?php
declare (strict_types=1);
// +----------------------------------------------------------------------
// | swiftAdmin 极速开发框架 [基于WebMan开发]
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2030 http://www.swiftadmin.net
// +----------------------------------------------------------------------
// | swiftAdmin.net High Speed Development Framework
// +----------------------------------------------------------------------
// | Author: meystack <coolsec@foxmail.com> Apache 2.0 License
// +----------------------------------------------------------------------
namespace app\common\service\notice;
use app\common\exception\OperateException;
use app\common\model\system\User;
use app\common\model\system\UserValidate;
use Psr\SimpleCache\InvalidArgumentException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use Webman\Event\Event;
class SmsService
{
/**
* 发送间隔时间
* @var int
*/
const EMAIL_SEND_INTERVAL = 60;
/**
* 验证码过期时间
* @var int
*/
const EXPIRE_TIME = 5; //验证码过期时间(分钟)
/**
* 类构造函数
* class constructor
* @access public
*/
public function __construct()
{}
/**
* 发送短信
* @param $mobile
* @param $event
* @return bool
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws \Exception|\Psr\SimpleCache\InvalidArgumentException
*/
public static function send($mobile, $event): bool
{
$result = self::getLastMsg($mobile, $event);
if (!empty($result)
&& time() - strtotime($result['create_time']) < self::EMAIL_SEND_INTERVAL) {
throw new OperateException(__('发送频繁'));
}
$userinfo = (new User())->where('mobile', $mobile)->findOrEmpty()->toArray();
if (in_array($event, ['register', 'change']) && $userinfo) {
throw new OperateException(__('当前手机号已注册'));
} else if ($event == 'forgot' && !$userinfo) {
throw new OperateException(__('当前手机号未注册'));
}
if (!Event::hasListener('smsMsgSend')) {
throw new OperateException(__('短信插件未安装'));
}
list($smsType, $config) = self::getSmsConfig();
$smsConf = include(root_path() . "extend/conf/sms/sms.php");
if (!isset($smsConf[$smsType][$event]['template'])) {
throw new OperateException(__('短信模板错误'));
}
$response = Event::emit('smsMsgSend', [
'mobile' => $mobile,
'event' => $event,
'template' => $smsConf[$smsType][$event]['template'],
],true);
if (isset($response['error']) && $response['error']) {
throw new \Exception($response['error']);
}
return true;
}
/**
* 校验验证码
* @param $mobile
* @param $captcha
* @param $event
* @return bool
* @throws DbException
*/
public static function checkCaptcha($mobile, $captcha, $event): bool
{
$model = new UserValidate();
$result = $model->where([
['event', '=', $event],
['mobile', '=', $mobile],
['code', '=', $captcha],
['status', '=', 1],
])->order("id", "desc")->findOrEmpty()->toArray();
if (!empty($result)) {
$model->where('id', $result['id'])->update(['status' => 0]);
$expires = time() - strtotime($result['create_time']);
if ($expires <= self::EXPIRE_TIME * 60) {
return true;
}
}
return false;
}
/**
* 获取最后一条
* @param string $mobile
* @param string $event
* @return array
*/
public static function getLastMsg(string $mobile, string $event): array
{
$mobile = str_replace(['+86', '-', ' ', '.'], '', $mobile);
return (new UserValidate())->where([
['mobile', '=', $mobile],
['event', '=', $event],
])->order('id', 'desc')->findOrEmpty()->toArray();
}
/**
* 校验手机号
* @param $mobile
* @return bool
*/
public static function filterMobile($mobile): bool
{
$pattern = '/^((13[0-9])|(14[5,7,9])|(15[^4])|(18[0-9])|(17[0,1,3,5,6,7,8]))\d{8}$/';
return (bool)preg_match($pattern, $mobile);
}
/**
* 获取配置信息
* @return array
* @throws InvalidArgumentException
*/
protected static function getSmsConfig(): array
{
$smsType = saenv('smstype');
$config = saenv($smsType) ?? [];
return ['type' => $smsType, 'config' => $config];
}
}

View File

@@ -0,0 +1,494 @@
<?php
namespace app\common\service\user;
use app\common\exception\OperateException;
use app\common\exception\user\UserException;
use app\common\model\system\User as UserModel;
use app\common\model\system\UserLog;
use app\common\model\system\UserNotice;
use app\common\service\notice\EmailService;
use app\common\service\notice\SmsService;
use PHPMailer\PHPMailer\Exception;
use Psr\SimpleCache\InvalidArgumentException;
use system\Random;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use support\Cache;
use Webman\Event\Event;
/**
* 用户中心服务
* @package app\common\service\system
*/
class UserService
{
/**
* 保活时间
* @var int
*/
protected static int $keepTime = 604800;
/**
* 类构造函数
* class constructor.
*/
public function __construct()
{
self::$keepTime = config('cookie.expire');
}
/**
* 注册服务
* @param array $post
* @return array
* @throws DbException
* @throws InvalidArgumentException
* @throws OperateException
*/
public static function register(array $post): array
{
if (!saenv('user_status')) {
throw new OperateException('暂未开放注册!');
}
// 是否手机注册
$regType = saenv('user_register_style');
if ($regType == 'mobile') {
$mobile = $post['mobile'] ?? '';
$captcha = $post['captcha'] ?? '';
if (!SmsService::checkCaptcha($mobile, $captcha, 'register')) {
throw new OperateException('验证码错误');
}
}
// 禁止批量注册
$where[] = ['create_ip', '=', request()->getRealIp()];
$where[] = ['create_time', '>', linux_time(1)];
$totalMax = UserModel::where($where)->count();
if ($totalMax >= saenv('user_register_second')) {
throw new OperateException('禁止批量注册');
}
try {
// 加密盐值
$salt = Random::alpha();
$userInfo = [
'nickname' => $post['nickname'],
'email' => $post['email'] ?? '',
'mobile' => $post['mobile'] ?? '',
'salt' => $salt,
'pwd' => encryptPwd($post['pwd'], $salt),
'invite_id' => input('inviter', request()->cookie('inviter')),
];
$userInfo = self::createUser($userInfo);
} catch (\Throwable $e) {
throw new OperateException($e->getMessage());
}
return self::createUserCookies($userInfo);
}
/**
* 登录服务
* @param string $nickname
* @param string $pwd
* @return array
* @throws InvalidArgumentException|OperateException
*/
public static function accountLogin(string $nickname, string $pwd): array
{
// 普通登录支持邮箱和用户名登录
if (filter_var($nickname, FILTER_VALIDATE_EMAIL)) {
$where[] = ['email', '=', htmlspecialchars(trim($nickname))];
} else {
$where[] = ['nickname', '=', htmlspecialchars(trim($nickname))];
}
$userInfo = UserModel::where($where)->findOrEmpty()->toArray();
if (empty($userInfo)) {
throw new OperateException('用户名或密码错误');
}
$uPwd = encryptPwd($pwd, $userInfo['salt']);
if ($userInfo['pwd'] != $uPwd) {
$errorMsg = '用户名或密码错误';
UserLog::write($errorMsg, $userInfo['nickname'], $userInfo['id']);
throw new OperateException($errorMsg);
}
if (!$userInfo['status']) {
$errorMsg = '用户禁用或未审核,请联系管理员';
UserLog::write($errorMsg, $userInfo['nickname'], $userInfo['id']);
throw new OperateException($errorMsg);
}
return self::createUserCookies($userInfo);
}
/**
* 手机登录
* @param string $mobile
* @param string $captcha
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws InvalidArgumentException
* @throws ModelNotFoundException|OperateException
*/
public static function mobileLogin(string $mobile, string $captcha): array
{
if (!SmsService::checkCaptcha($mobile, $captcha, 'login')) {
throw new OperateException('验证码错误');
}
$userInfo = UserModel::where(['mobile' => $mobile])->findOrEmpty()->toArray();
if (empty($userInfo)) {
$maxId = UserModel::max('id');
$userInfo = [
'nickname' => 'u' . ($maxId + 1),
'mobile' => $mobile,
];
return self::createUser($userInfo);
} else if (!$userInfo['status']) {
$errorMsg = '用户禁用或未审核,请联系管理员';
UserLog::write($errorMsg, $userInfo['nickname'], $userInfo['id']);
throw new OperateException($errorMsg);
}
self::updateUser($userInfo);
return self::createUserCookies($userInfo);
}
/**
* 创建用户
* @param array $userInfo
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException|OperateException
*/
public static function createUser(array $userInfo): array
{
if (isset($userInfo['nickname']) && UserModel::getByNickname($userInfo['nickname'])) {
throw new OperateException('当前用户名已被占用!');
}
if (isset($userInfo['email']) && UserModel::getByEmail($userInfo['email'])) {
throw new OperateException('当前邮箱已被占用!');
}
if (isset($userInfo['mobile']) && UserModel::getByMobile($userInfo['mobile'])) {
throw new OperateException('当前手机号已被占用!');
}
if (isset($userInfo['pwd']) && $userInfo['pwd']) {
$userInfo['salt'] = Random::alpha();
$userInfo['pwd'] = encryptPwd($userInfo['pwd'], $userInfo['salt']);
}
$userInfo['login_time'] = time();
$userInfo['login_ip'] = request()->getRealIp();
$userInfo['create_ip'] = request()->getRealIp();
try {
$userInfo = UserModel::create($userInfo)->toArray();
} catch (\Throwable $th) {
throw new OperateException($th->getMessage());
}
return $userInfo;
}
/**
*
* 返回前端令牌
* @param array $userInfo
* @return array
*/
public static function createUserCookies(array $userInfo = []): array
{
$userToken = UserTokenService::buildToken($userInfo['id']);
$response = response()
->cookie('uid', $userInfo['id'], self::$keepTime, '/')
->cookie('token', $userToken, self::$keepTime, '/')
->cookie('nickname', $userInfo['nickname'], self::$keepTime, '/');
Cache::set($userToken, $userInfo['id'], self::$keepTime);
Cache::set('user_info_' . $userInfo['id'], $userInfo, self::$keepTime);
\Webman\Event\Event::emit("userLoginSuccess", $userInfo);
return ['token' => $userToken, 'id' => $userInfo['id'], 'response' => $response];
}
/**
* 更新用户信息
* @param array $userInfo
*/
public static function updateUser(array $userInfo = []): void
{
$data['login_time'] = time();
$data['login_ip'] = request()->getRealIp();
$data['login_count'] = $userInfo['login_count'] + 1;
$data['update_time'] = time();
UserModel::update($data, ['id' => $userInfo['id']]);
UserLog::write('登录成功', $userInfo['nickname'], $userInfo['id'], 1);
Event::emit('userLoginSuccess', $userInfo);
}
/**
* 退出登录
* @return void
* @throws InvalidArgumentException
*/
public static function logout(): void
{
response()->cookie('uid', null);
response()->cookie('token', null);
response()->cookie('nickname', null);
Cache::delete(UserTokenService::getToken());
}
/**
* @param array $params
* @param int $userId
* @return bool
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws OperateException
*/
public static function editProfile(array $params = [], int $userId = 0): bool
{
$userInfo = UserModel::where('id', $userId)->findOrEmpty()->toArray();
if (empty($userInfo)) {
throw new OperateException('用户不存在');
}
$data = [];
if (isset($params['nickname']) && $params['nickname']) {
// 验证昵称是否存在
$data['nickname'] = $params['nickname'];
if ($data['nickname'] != $userInfo['nickname']
&& UserModel::where('nickname', $data['nickname'])->find()) {
throw new OperateException('昵称已存在');
}
}
$fields = ['avatar', 'name', 'wechat', 'qq', 'idCard', 'address', 'gender'];
foreach ($fields as $field) {
if (isset($params[$field])) {
$data[$field] = $params[$field];
}
}
try {
UserModel::update($data, ['id' => $userId]);
} catch (\Exception $e) {
throw new OperateException($e->getMessage());
}
return true;
}
/**
* 忘记密码
* @param array $params
* @return bool
* @throws DataNotFoundException|DbException|ModelNotFoundException|OperateException
*/
public static function forgotPwd(array $params = []): bool
{
$value = $params['name'] ?? '';
$pwd = $params['pwd'] ?? '';
$captcha = $params['captcha'] ?? '';
$filterVar = filter_var($value, FILTER_VALIDATE_EMAIL);
// 获取验证服务类
$checkClass = $filterVar ? EmailService::class : SmsService::class;
if (!$checkClass::checkCaptcha($value, $captcha, 'forgot')) {
throw new OperateException('无效的验证码');
}
$where = [$filterVar ? 'email' : 'mobile' => $value];
$userInfo = UserModel::where($where)->findOrEmpty()->toArray();
if (empty($userInfo)) {
throw new OperateException('用户不存在');
}
try {
$salt = Random::alpha();
$pwd = encryptPwd($pwd, $salt);
UserModel::update(['id' => $userInfo['id'], 'pwd' => $pwd, 'salt' => $salt]);
} catch (\Exception $e) {
throw new OperateException($e->getMessage());
}
return true;
}
/**
* 修改密码
* @param array $params
* @param int $userId
* @return bool
* @throws OperateException
*/
public static function changePwd(array $params = [], int $userId = 0): bool
{
$pwd = $params['pwd'] ?? '';
$oldPwd = $params['oldpwd'] ?? '';
$userInfo = UserModel::where('id', $userId)->findOrEmpty()->toArray();
if (empty($userInfo)) {
throw new OperateException('用户不存在');
}
$yPwd = encryptPwd($oldPwd, $userInfo['salt']);
if (!empty($userInfo['pwd']) && $yPwd != $userInfo['pwd']) {
throw new OperateException('原密码错误');
}
$salt = Random::alpha();
$pwd = encryptPwd($pwd, $salt);
try {
UserModel::update([
'id' => $userId,
'pwd' => $pwd,
'salt' => $salt,
]);
} catch (\Exception $e) {
throw new OperateException($e->getMessage());
}
return true;
}
/**
* 修改手机号
* @param $email
* @param $captcha
* @param $event
* @param $userId
* @return bool
* @throws Exception
* @throws UserException|OperateException
*/
public static function changeEmail($email, $captcha, $event, $userId): bool
{
if (!EmailService::filterEmail($email)) {
throw new OperateException("邮箱格式不正确");
}
if ($email && UserModel::getByEmail($email)) {
throw new OperateException("您输入的邮箱已被占用");
}
try {
EmailService::checkCaptcha($email, $captcha, $event);
UserModel::update(['id' => $userId, 'email' => $email]);
} catch (\Throwable $e) {
throw new OperateException($e->getMessage());
}
return true;
}
/**
* 修改手机号
* @param $mobile
* @param $captcha
* @param $event
* @param $userId
* @return bool
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws UserException|OperateException
*/
public static function changeMobile($mobile, $captcha, $event, $userId): bool
{
if (!SmsService::filterMobile($mobile)) {
throw new OperateException("手机号码格式不正确");
}
if ($mobile && UserModel::getByMobile($mobile)) {
throw new OperateException("您输入的手机号已被占用");
}
try {
if (!SmsService::checkCaptcha($mobile, $captcha, $event)) {
throw new UserException('无效的验证码');
}
UserModel::update(['id' => $userId, 'mobile' => (int)$mobile]);
} catch (\Throwable $e) {
throw new OperateException($e->getMessage());
}
return true;
}
/**
* 获取消息列表
* @param int $limit
* @param int $page
* @param array $where
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public static function listMessage(mixed $limit = 10, mixed $page = 1, array $where = []): array
{
$count = (new UserNotice)->where($where)->count();
$page = ($count <= $limit) ? 1 : $page;
$list = (new UserNotice)->where($where)->order('id', 'desc')->limit($limit)->page($page)->select()->toArray();
return [$list, $count];
}
/**
* 读取消息
* @param $id
* @param int $userId
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException|OperateException
*/
public static function viewMessage($id, int $userId = 0): array
{
$where[] = ['id', '=', $id];
$where[] = ['user_id', '=', $userId];
$msgInfo = UserNotice::where($where)->findOrEmpty()->toArray();
if (empty($msgInfo)) {
throw new OperateException('消息不存在');
}
if ($msgInfo['status'] == 0) {
UserNotice::update(['id' => $id, 'status' => 1]);
}
if ($msgInfo['send_id']) {
$fromInfo = UserModel::where('id', $msgInfo['send_id'])->findOrEmpty()->toArray();
$msgInfo['nickname'] = $fromInfo['nickname'] ?? 'Unknown';
}
$unread = UserNotice::where(['user_id' => $userId, 'status' => 0])->count();
return ['msgInfo' => $msgInfo, 'unread' => $unread];
}
/**
* @param $ids
* @param string $type
* @param int $userId
* @return bool
* @throws UserException
*/
public static function batchMessage($ids, string $type = 'del', int $userId = 0): bool
{
$where[] = ['user_id', '=', $userId];
$where[] = ['id', 'in', implode(',', $ids)];
try {
$type == 'del' ? UserNotice::where($where)->delete() : UserNotice::where($where)->update(['status' => 1]);
} catch (\Exception $e) {
throw new UserException($e->getMessage());
}
return true;
}
}

View File

@@ -0,0 +1,82 @@
<?php
namespace app\common\service\user;
use app\common\model\system\User as UserModel;
use Psr\SimpleCache\InvalidArgumentException;
use system\Random;
use support\Cache;
/**
* 用户token服务
* Class UserTokenService
*/
class UserTokenService
{
/**
* 保活时间
* @var int
*/
protected static int $keepTime = 604800;
/**
* 类构造函数
* class constructor.
*/
public function __construct()
{
self::$keepTime = config('cookie.expire');
}
/**
* 校验登录
* @return array
* @throws InvalidArgumentException
*/
public static function isLogin(): array
{
$token = self::getToken();
$userId = self::checkToken($token);
if (empty($userId)) {
return [];
}
$userInfo = UserModel::with('group')->where(['id' => $userId])->findOrEmpty()->toArray();
$userInfo['has_password'] = empty($userInfo['password']) ? 0 : 1;
unset($userInfo['password'], $userInfo['salt']);
return $userInfo;
}
/**
* 生成token
* @access protected
* @param int $id
* @return string
*/
public static function buildToken(int $id = 0): string
{
return md5(Random::alpha(16) . $id . time());
}
/**
* 获取token
* return string
*/
public static function getToken(): string
{
$token = request()->header('Authorization') ?: request()->header('token');
return $token ?? input('token', request()->cookie('token')) ?: 'undefined';
}
/**
* 校验token
* @access protected
* @param string $token
* @return mixed
* @throws InvalidArgumentException
*/
public static function checkToken(string $token): mixed
{
return Cache::get($token) ?? 0;
}
}

View File

@@ -0,0 +1,113 @@
<?php
namespace app\common\service\utils;
use system\Random;
/**
* FTP上传类
* Class FtpService
* @package app\common\service\utils
*/
class FtpService
{
/**
* 默认配置
* @var array
*/
protected static array $config = [
'upload_ftp_host' => '127.0.0.1', // 服务器地址
'upload_ftp_port' => 21, // 服务器端口
'upload_ftp_user' => 'username', // FTP用户名
'upload_ftp_pass' => 'password', // FTP密码
'upload_path' => 'upload', // 上传路径
];
/**
* 类构造函数
* class constructor.
* @throws \Exception
*/
public function __construct()
{
$config = saenv('upload', true);
self::$config = array_merge(self::$config, $config);
}
/**
* FTP上传函数
* @access public
* @param string $source 源文件
* @param string $filepath 文件路径
* @param string $filename 文件名称
* @return bool
*/
public static function ftpUpload(string $source, string $filepath, string $filename): bool
{
if (!empty($source) && !empty($filepath)) {
// 链接FTP
$connect = @ftp_connect(self::$config['upload_ftp_host'], self::$config['upload_ftp_port']) or die('Could not connect');
if (!ftp_login($connect, self::$config['upload_ftp_user'], self::$config['upload_ftp_pass'])) {
return false;
}
// 开启被动模式
@ftp_pasv($connect, TRUE);
$source = @fopen($source, "r");
// 循环创建文件夹
$filepath = str_replace("\\", '/', $filepath);
$dirs = explode('/', $filepath);
foreach ($dirs as $val) {
if (!@ftp_chdir($connect, $val)) {
if (!ftp_mkdir($connect, $val)) {
//创建失败
return false;
}
// 切换目录
@ftp_chdir($connect, $val);
}
}
if (!@ftp_fput($connect, $filename, $source, FTP_BINARY)) {
return false;
}
@ftp_close($connect);
return true;
} else {
return false;
}
}
/**
* FTP测试函数
* @access public
* @param array $config 配置信息
* @return bool true|false
*/
public static function ftpTest(array $config): bool
{
try {
$connect = @ftp_connect($config['host'], (int)$config['port']);
@ftp_login($connect, $config['user'], $config['pass']);
// 开启被动模式
ftp_pasv($connect, TRUE);
$folder = Random::alpha(16);
if (ftp_mkdir($connect, $folder)) {
// 读取测试文件
$location = __DIR__;
$source = fopen($location, "r"); // 上传测试文件
$filename = $folder . "/target.txt";
ftp_fput($connect, $filename, $source, FTP_BINARY);
// 删除测试文件
ftp_delete($connect, $filename);
ftp_rmdir($connect, $folder);
ftp_close($connect);
return true;
}
} catch (\Throwable $th) {
return false;
}
return false;
}
}

View File

@@ -0,0 +1,31 @@
<layout name="layout:layout"/>
<!-- 内容主体区域 -->
<div id="content">
<div class="layui-fluid">
<form class="layui-form layui-form-fixed" action="/index/user/changeEmail">
<div class="layui-form-item">
<label class="layui-form-label">{:__('邮箱地址')}</label>
<div class="layui-input-inline" style="width: 265px">
<input name="email" placeholder="{:__('请输入邮箱地址')}" type="text" class="layui-input email"
autocomplete="off" lay-verify="required|email"/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">{:__('验证码')}</label>
<div class="layui-input-inline">
<input name="captcha" placeholder="{:__('请输入验证码')}" type="text" class="layui-input"
autocomplete="off" lay-verify="required" maxlength="10"/>
</div>
<button class="layui-btn layui-btn-normal" type="button" lay-ajax data-url="/api/ajax/emailSend"
data-object="email:email,event:event">{:__('获取')}
</button>
</div>
<input type="text" hidden name="event" class="event" value="change">
<div class="layui-footer layui-form-item layui-center">
<button class="layui-btn layui-btn-primary" type="button" sa-event="closeDialog">{:__('取消')}</button>
<button class="layui-btn layui-btn-normal " data-reload="parent" lay-filter="submitIframe" lay-submit>{:__('提交')}</button>
</div>
</form>
</div>
</div>

View File

@@ -0,0 +1,30 @@
<layout name="layout:layout"/>
<!-- 内容主体区域 -->
<div id="content">
<div class="layui-fluid">
<form class="layui-form layui-form-fixed" action="/index/user/changeMobile">
<div class="layui-form-item">
<label class="layui-form-label">{:__('手机号')}</label>
<div class="layui-input-inline" style="width: 265px">
<input name="mobile" placeholder="{:__('请输入号码')}" type="text" class="layui-input mobile"
autocomplete="off" lay-verify="required|phone"/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">{:__('验证码')}</label>
<div class="layui-input-inline">
<input name="captcha" placeholder="{:__('请输入验证码')}" type="text" class="layui-input"
autocomplete="off" lay-verify="required" maxlength="10"/>
</div>
<button class="layui-btn layui-btn-normal" type="button" lay-ajax data-url="/api/ajax/smsSend"
data-object="mobile:mobile,event:event">{:__('获取')}
</button>
</div>
<input type="text" hidden name="event" class="event" value="change">
<div class="layui-footer layui-form-item layui-center">
<button class="layui-btn layui-btn-primary" type="button" sa-event="closeDialog">{:__('取消')}</button>
<button class="layui-btn layui-btn-normal" data-reload="parent" lay-filter="submitIframe" lay-submit>{:__('提交')}</button>
</div>
</form>
</div>
</div>

View File

@@ -0,0 +1,82 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>修改密码 | {$site_name}</title>
<include file="user:include"/>
</head>
<body>
<div class="layui-card-body">
<form action="/index/user/changePwd" class="layui-form layui-form-fixed">
<input type="text" name="nickname" value="{$user.nickname}" hidden="">
<div class="layui-form-item">
<label class="layui-form-label">原密码</label>
<div class="layui-input-block">
<input type="text" id="oldpwd" name="oldpwd" class="layui-input" >
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">新密码</label>
<div class="layui-input-block">
<input type="password" id="pwd" name="pwd" class="layui-input" >
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">确认密码</label>
<div class="layui-input-block">
<input type="password" id="repwd" name="repwd" class="layui-input" >
</div>
</div>
<div class="layui-form-item" style="margin-top: 22px;text-align: center;">
<button type="button" class="layui-btn layui-btn-primary" sa-event="closeDialog" >关闭</button>
<button type="submit" class="layui-btn layui-btn-normal" lay-submit="" lay-filter="submit">立即提交</button>
</div>
</form>
</div>
<script>
layui.use(['jquery','form'],function(){
var $ = layui.jquery;
var form = layui.form;
//监听提交
form.on('submit(submit)', function(data){
if($("#pwd").val().length < 6){
layer.tips('请至少输入6个字符作为密码',"#pwd",{'tips':3});
return false;
}
if ($("#pwd").val() !== $("#repwd").val()) {
layer.tips('两次输入的密码不一样!',"#repwd",{'tips':3});
return false;
}
$.ajax({
url: $(this).attr('action'),
type: 'POST',
dataType: 'json',
timeout: 6000,
data: data.field,
success: function(res){
if (res.code === 200) {
top.layer.msg(res.msg);
parent.location.reload();
}
else {
top.layer.msg(res.msg,'error');
}
}
});
return false;
});
})
</script>
</body>
</html>

View File

@@ -0,0 +1,234 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>{$site_name} 用户登录</title>
<meta http-equiv="Cache-Control" content="no-transform"/>
<meta http-equiv="Cache-Control" content="no-siteapp"/>
<meta name="applicable-device" content="pc,mobile">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
<script src="/static/js/layui/layui.js"></script>
<link rel="stylesheet" type="text/css" href="/static/js/layui/css/font-awesome.css"/>
<link rel="stylesheet" type="text/css" href="/static/js/layui/css/layui.css"/>
<link rel="stylesheet" type="text/css" href="/static/css/login.css"/>
<script src="/static/js/center.js?v={:release()}"></script>
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"/>
</head>
<body>
<div id="header"></div>
<div id="content" class="userLogin layui-fluid">
<div class="formLogin form-items active">
<div class="layui-tab layui-tab-brief">
<ul class="layui-tab-title">
<li class="layui-this" data-action="login">账号登录</li>
<li data-action="mobileLogin">免密登录</li>
</ul>
<div class="layui-tab-content pb0">
<div class="layui-tab-item layui-show">
<form class="layui-form login" action="/index/user/login" method="post">
<div class="layui-form-item item-input">
<input type="text" id="nickname" name="nickname" lay-verify="required" data-title="账号"
placeholder="{:__('请输入账号或邮箱')}" class="inputStyle" value="">
</div>
<div class="layui-form-item item-input">
<input type="password" id="pwd" name="pwd" lay-verify="required" data-title="密码"
maxlength="32"
placeholder="{:__('密码')}" class="inputStyle" value="">
<span class="fr-icon visiblePwd"><i class="layui-icon fa-eye-slash"></i></span>
</div>
</form>
</div>
<div class="layui-tab-item">
<form class="layui-form mobileLogin" action="/index/user/mobileLogin" method="post">
<div class="layui-form-item item-input">
<input type="text" id="mobile" name="mobile" lay-verify="required" data-title="手机号"
placeholder="{:__('请输入手机号码')}" class="inputStyle mobile" value="15100000000">
</div>
<div class="layui-form-item item-input">
<input type="text" id="captcha" name="captcha" lay-verify="required" data-title="验证码"
maxlength="6"
placeholder="{:__('验证码')}" class="inputStyle" value="123456">
<input type="text" hidden name="event" class="event" value="login">
<span class="fr-icon getCaptcha" lay-ajax data-url="/api/ajax/smsSend"
data-object="mobile:mobile,event:event">获取验证码</span>
</div>
</form>
</div>
</div>
</div>
<div class="layui-form">
<input type="hidden" id="token" name="__token__" value="{:token()}"/>
<div class="layui-form-item">
<div class="fl">
<input type="checkbox" name="remember" lay-skin="primary"
title="{:__('记住密码')}" checked>
</div>
<div class="fr">
<a lay-open data-title="找回密码" data-area="500px,320px" data-object="top"
data-url="/index/user/forgot"
class="forgot-link" style="margin-top: 7px;">{:__('忘记密码?')}</a>
</div>
</div>
<div class="layui-form-item">
<input id="iframeSubmit" type="submit" value="{:__('立即登录')}"
class="layui-btn layui-btn-login layui-btn-fluid layui-btn-normal">
</div>
<div class="agreement">
<span>未注册手机验证后自动登录,注册即代表同意<a href="#">《用户协议》</a>以及网站<a
href="#">《隐私保护指引》</a></span>
</div>
</div>
</div>
<div class="scanLogin form-items">
<div class="qrcode-title">扫码登录</div>
<div class="qrcode-Box">
<div class="qrcode-img" id="qrcode" title="">
<canvas width="150" height="150" style="display: none;"></canvas>
<img id="scanCover" src="/static/images/qrcode-qun.png" style="display: block;" width="150" height="150"
alt="Scan me!">
</div>
<p>打开<a href="#" target="_blank" rel="noopener noreferrer">{$site_name} App</a></p>
<p>在「我的」页面右上角打开扫一扫</p>
</div>
</div>
<div class="loginLine"></div>
<div class="socialLogin">
<span class="social-title">社交帐号登录</span>
<div class="social-group">
<a class="social-item" href="{:url('/index/third/login',['type'=>'weixin'])}&ref={$referer}"
target="_top">
<span>
<i class="layui-icon layui-icon-login-wechat"></i>
<span class="tit">微信</span>
</span>
</a>
<a class="social-item" href="{:url('/index/third/login',['type'=>'qq'])}&ref={$referer}"
target="_top">
<span>
<i class="layui-icon layui-icon-login-qq"></i>
<span class="tit">QQ</span>
</span>
</a>
<a class="social-item" href="{:url('/index/third/login',['type'=>'weibo'])}&ref={$referer}"
target="_top">
<span><i class="layui-icon layui-icon-login-weibo"></i>
<span class="tit">微博</span></span>
</a>
</div>
</div>
<div class="appUserDown">
<div class="fr">
<a class="link" href="#" target="_top">
<span>
<i class="layui-icon fa-apple"></i>
<i class="layui-icon fa-android"></i>
<i class="layui-icon fa-windows"></i>
<span class="tit">下载 APP</span>
</span>
</a>
</div>
</div>
<div class="switchTabs" id="switchTabs">
<img class="switch-item active" data-action="scanLogin" src="/static/images/qrcode-login.png" alt="qrcode">
<img class="switch-item" data-action="login" src="/static/images/mobile-login.png" alt="qrcode">
</div>
</div>
<script>
layui.use(['jquery', 'layer'], function (e) {
let $ = layui.jquery;
let layer = layui.layer;
let queryTicket = null;
/* 点击执行登录 */
$('#iframeSubmit').click(function (e) {
let data = {};
let action = $('li.layui-this').data('action');
let form = $('form.' + action);
form.find('input').each(function (index, item) {
let value = $(item).val();
let name = $(item).attr('name');
let title = $(item).data('title');
if (!value) {
layer.msg(title + '不能为空', 'info');
$(item).focus();
return false;
}
data[name] = value;
});
/* 发送登录数据 */
if (Object.keys(data).length >= 2) {
$.post(form.attr('action'), data, function (res) {
if (res.code === 200) {
layer.msg(res.msg);
setTimeout(function () {
window.location.href = '/index/user/index';
}, 1000);
} else {
layer.msg(res.msg, 'error')
}
}, 'json');
}
})
/* 显示隐藏密码 */
$('.visiblePwd').click(function () {
let type = $('#pwd').attr('type');
if (type === 'password') {
$('#pwd').attr('type', 'text');
$(this).find('i.layui-icon').addClass('fa-eye').removeClass('fa-eye-slash');
} else {
$('#pwd').attr('type', 'password');
$(this).find('i.layui-icon').addClass('fa-eye-slash').removeClass('fa-eye');
}
});
/* 切换登录方式 */
$("#switchTabs .switch-item").click(function () {
$(this).removeClass('active');
let action = $(this).data('action');
$("#switchTabs .switch-item").not($(this)).addClass('active');
if (action === 'scanLogin') {
$('.scanLogin').addClass('active');
$('.formLogin').removeClass('active');
$.get('/index/user/scanLogin', {}, function (res) {
if (res.code === 200) {
!queryTicket && queryRequest(res.data.ticket);
$('#scanCover').attr('src', res.data.qrcode || '/static/images/qrcode.png');
} else {
layer.msg(res.msg, 'info');
}
})
} else {
clearInterval(queryTicket);
queryTicket = null;
$('.formLogin').addClass('active');
$('.scanLogin').removeClass('active');
}
});
/* 定时器 */
const queryRequest = function (ticket) {
queryTicket = setInterval(function () {
$.post('/index/user/scanTicket', {
ticket: ticket,
}, function (res) {
if (res.code === 200) {
clearInterval(queryTicket);
top.layer.msg(res.msg);
top.location.reload();
}
}, 'json');
}, 1000);
}
});
</script>
</body>
</html>

477
public/static/css/login.css Normal file
View File

@@ -0,0 +1,477 @@
/**
* 用户登录样式表
@ author: meystack
@ version: 1.0.0
*/
body {
color: #1a1a1a;
background-size: cover;
background-image: url("/static/images/background.svg");
background-color: #e9f0f4;
}
a {
text-decoration: none
}
.fl {
float: left
}
.fr {
float: right
}
.pb0 {
padding-bottom: 0;
}
.red {
color: red;
}
.active {
display: block !important;
}
.forgot-link {
margin-top: 7px;
color: #1890ff;
cursor: pointer;
}
i, em, span, label, i, a {
font-style: normal;
display: inline-block;
}
.layui-fluid {
padding: 30px 20px 20px;
}
.layui-center {
text-align: center;
}
.layui-btn, .layui-input, .layui-select, .layui-textarea {
height: 33px;
line-height: 33px;
}
.layui-btn-login {
height: 38px;
line-height: 38px;
}
input[type=button]:hover, input[type=submit]:hover {
color: #ffffff;
cursor: pointer;
}
input:hover {
border: 1px solid #1890ff;
}
.layui-btn-primary:hover {
color: #fff;
background-color: #1890ff !important;
}
.layui-form-checked[lay-skin="primary"] i {
border-color: #1890ff !important;
background-color: #1890ff !important;
color: #fff;
}
.layui-form-checkbox[lay-skin=primary]:hover i {
border-color: #1890ff;
color: #fff;
}
#ajaxLogin {
padding: 20px!important;
overflow: hidden;
}
#ajaxLogin .item, #ajaxLogin .layui-col-xs7 {
border: 1px solid #d9d9d9;
border-radius: 5px;
position: relative;
margin-bottom: 10px;
}
#ajaxLogin .layui-col-xs3 {
width: 36%;
}
#ajaxLogin .layui-form-item .item .layui-input {
border: 0;
padding-left: 38px;
border-radius: 5px;
}
#ajaxLogin .other-link {
padding: 20px 0 20px 0;
margin-bottom: 8px;
border-bottom: 1px solid #e6e6e6
}
#ajaxLogin .other-link a {
vertical-align: middle;
margin-left: 13px;
width: 56px;
height: 56px;
display: inline-block;
}
#ajaxLogin .other-link span.other {
font-size: 12px;
color: #999;
margin-left: 38px;
}
#ajaxLogin .other-link .wx {
background: url(/static/images/wx.png) no-repeat
}
#ajaxLogin .other-link .qq {
background: url(/static/images/qq.png) no-repeat
}
#ajaxLogin .other-link .sina {
background: url(/static/images/sina.png) no-repeat
}
#ajaxLogin .other-link .wx:hover {
background: url(/static/images/wx_h.png) no-repeat
}
#ajaxLogin .other-link .qq:hover {
background: url(/static/images/qq_h.png) no-repeat
}
#ajaxLogin .other-link .sina:hover {
background: url(/static/images/sina_h.png) no-repeat
}
#ajaxLogin .left-icon {
position: absolute;
left: 1px;
top: -2px;
width: 38px;
line-height: 36px;
text-align: center;
color: #d2d2d2;
}
.userLogin {
padding: 0;
width: 400px;
margin: 10% auto;
background-color: #FFF;
border-radius: 5px;
box-sizing: border-box;
box-shadow: 0 1px 3px rgb(26 26 26 / 10%);
}
.userLogin .form-header {
text-align: left;
display: flex;
color: #1E9FFF;
padding: 15px 30px 10px;
border-bottom: 1px solid #ebebeb;
}
.userLogin .form-header i {
margin-right: 10px;
}
.userLogin .form-header i,.userLogin .form-header h6 {
display: inline-block;
font-size: 22px!important;
vertical-align: middle;
}
.userLogin .formLogin {
display: none;
padding: 0 24px 3px;
position: relative;
border-radius: 5px 5px 0 0;
}
.userLogin .formLogin .layui-tab-brief > .layui-tab-title li {
color: #1a1a1a !important;
font-size: 16px;
}
.userLogin .formLogin .layui-tab-brief > .layui-tab-title li.layui-this {
position: relative;
color: #1a1a1a;
font-weight: 600;
font-synthesis: style;
}
.userLogin .formLogin .layui-tab-brief > .layui-tab-more li.layui-this:after, .layui-tab-brief > .layui-tab-title .layui-this:after {
border: none;
border-radius: 0;
border-bottom: 3px solid #0085ff;
}
.userLogin .formLogin .layui-tab-title {
display: inline-block;
height: 60px;
font-size: 16px;
line-height: 65px;
margin-right: 24px;
cursor: pointer;
}
.userLogin .formLogin .layui-tab-title .layui-this:after {
height: 49px;
}
.userLogin .formLogin .item-input {
margin-top: 15px;
border-bottom: 1px solid #ebebeb;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
height: 50px;
line-height: 50px;
position: relative;
}
.userLogin .formLogin .layui-form-item .inputStyle {
display: inline-block;
outline: 0;
flex: 1 1;
overflow: hidden;
font-family: inherit;
font-size: inherit;
font-weight: inherit;
background: transparent;
border: 0;
resize: none;
z-index: 100;
height: 30px;
line-height: 30px;
padding: 0 0 0 5px;
}
.userLogin .formLogin .fr-icon {
cursor: pointer;
color: #8590a6;
}
.userLogin .agreement {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
color: grey;
font-size: 12px;
line-height: 22px;
text-align: left;
}
.userLogin .agreement a {
color: #0085ff;
text-decoration: none;
}
.userLogin .socialLogin {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
color: #8590a6;
height: 60px;
line-height: 60px;
padding: 0 24px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.userLogin .socialLogin .social-group {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
margin-left: 2px;
-webkit-transition: opacity .3s ease;
transition: opacity .3s ease;
}
.userLogin .socialLogin .social-group .social-item {
display: -ms-inline-flexbox;
display: inline-flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
cursor: pointer;
height: auto;
padding: 0 6px;
line-height: inherit;
background-color: transparent;
border: 0;
border-radius: 0;
}
.userLogin .socialLogin .social-group .social-item .layui-icon {
font-size: 18px;
margin-right: 3px;
vertical-align: middle;
}
.userLogin .socialLogin .social-group .social-item .layui-icon-login-qq {
color: rgb(80, 200, 253);
}
.userLogin .socialLogin .social-group .social-item .layui-icon-login-wechat {
color: rgb(96, 200, 77);
}
.userLogin .socialLogin .social-group .social-item .layui-icon-login-weibo {
color: rgb(251, 102, 34);
}
.userLogin .socialLogin .social-group .social-item .tit {
color: #8590a6;
font-size: 14px;
display: inline-block;
vertical-align: middle;
}
.userLogin .socialLogin .social-group .social-item:hover {
opacity: .8;
}
.userLogin .appUserDown {
background-color: #f6f6f6;
color: #0084ff;
padding: 15px;
overflow: hidden;
}
.userLogin .appUserDown .link {
display: -ms-inline-flexbox;
display: inline-flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
cursor: pointer;
height: auto;
padding: 0 6px;
line-height: inherit;
background-color: transparent;
border: 0;
border-radius: 0;
}
.userLogin .appUserDown .link .layui-icon {
font-size: 18px;
margin-right: 10px;
color: #008DFD;
vertical-align: middle;
}
.userLogin .appUserDown .link .tit {
color: #008DFD;
display: inline-block;
vertical-align: middle;
box-sizing: border-box;
margin: 0;
min-width: 0;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
display: inline-block;
text-align: center;
line-height: inherit;
-webkit-text-decoration: none;
text-decoration: none;
border: 0;
border-radius: 4px;
font-size: 16px;
font-weight: 600;
border-radius: 4px;
background-color: unset;
font-size: inherit;
font-weight: inherit;
padding: 0;
}
.userLogin .switchTabs {
position: absolute;
width: 52px;
height: 52px;
top: 0;
cursor: pointer;
right: 8px;
}
.userLogin .scanLogin {
text-align: center;
overflow: hidden;
display: none;
padding: 35px 0;
}
.userLogin .scanLogin .qrcode-title {
font-size: 24px;
color: #1a1a1a;
line-height: 33px;
margin-bottom: 50px;
margin-top: 3px;
}
.userLogin .scanLogin .qrcode-Box {
height: 210px;
}
.userLogin .scanLogin .qrcode-Box .qrcode-img {
margin: 0 auto 15px;
line-height: 0;
height: 150px;
width: 150px;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
.userLogin .scanLogin .qrcode-Box p {
font-size: 14px;
line-height: 22px;
}
.userLogin .scanLogin .qrcode-Box p a {
color: #175199;
}
.userLogin .switch-item {
display: none;
}
.userLogin .loginLine {
box-sizing: border-box;
min-width: 0;
border-top: 1px solid;
border-color: #EBEBEB;
margin: 5px 24px 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 777 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

File diff suppressed because one or more lines are too long

7
security.sh Normal file
View File

@@ -0,0 +1,7 @@
#!/bin/bash
# 执行安全脚本 sh security.sh
base=$(dirname $(realpath ${BASH_SOURCE}))
chown www:www $base -R
chmod 555 $base -R
chmod u+w ${base}"/runtime" -R
chmod u+w ${base}"/public/upload" -R

120
vendor/bin/carbon vendored Normal file
View File

@@ -0,0 +1,120 @@
#!/usr/bin/env php
<?php
/**
* Proxy PHP file generated by Composer
*
* This file includes the referenced bin path (../nesbot/carbon/bin/carbon)
* using a stream wrapper to prevent the shebang from being output on PHP<8
*
* @generated
*/
namespace Composer;
$GLOBALS['_composer_bin_dir'] = __DIR__;
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
if (PHP_VERSION_ID < 80000) {
if (!class_exists('Composer\BinProxyWrapper')) {
/**
* @internal
*/
final class BinProxyWrapper
{
private $handle;
private $position;
private $realpath;
public function stream_open($path, $mode, $options, &$opened_path)
{
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
$opened_path = substr($path, 17);
$this->realpath = realpath($opened_path) ?: $opened_path;
$opened_path = $this->realpath;
$this->handle = fopen($this->realpath, $mode);
$this->position = 0;
return (bool) $this->handle;
}
public function stream_read($count)
{
$data = fread($this->handle, $count);
if ($this->position === 0) {
$data = preg_replace('{^#!.*\r?\n}', '', $data);
}
$this->position += strlen($data);
return $data;
}
public function stream_cast($castAs)
{
return $this->handle;
}
public function stream_close()
{
fclose($this->handle);
}
public function stream_lock($operation)
{
return $operation ? flock($this->handle, $operation) : true;
}
public function stream_seek($offset, $whence)
{
if (0 === fseek($this->handle, $offset, $whence)) {
$this->position = ftell($this->handle);
return true;
}
return false;
}
public function stream_tell()
{
return $this->position;
}
public function stream_eof()
{
return feof($this->handle);
}
public function stream_stat()
{
return array();
}
public function stream_set_option($option, $arg1, $arg2)
{
return true;
}
public function url_stat($path, $flags)
{
$path = substr($path, 17);
if (file_exists($path)) {
return stat($path);
}
return false;
}
}
}
if (
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
) {
include("phpvfscomposer://" . __DIR__ . '/..'.'/nesbot/carbon/bin/carbon');
exit(0);
}
}
include __DIR__ . '/..'.'/nesbot/carbon/bin/carbon';

5
vendor/bin/carbon.bat vendored Normal file
View File

@@ -0,0 +1,5 @@
@ECHO OFF
setlocal DISABLEDELAYEDEXPANSION
SET BIN_TARGET=%~dp0/carbon
SET COMPOSER_RUNTIME_BIN_DIR=%~dp0
php "%BIN_TARGET%" %*

858
vendor/illuminate/collections/Arr.php vendored Normal file
View File

@@ -0,0 +1,858 @@
<?php
namespace Illuminate\Support;
use ArgumentCountError;
use ArrayAccess;
use Illuminate\Support\Traits\Macroable;
use InvalidArgumentException;
class Arr
{
use Macroable;
/**
* Determine whether the given value is array accessible.
*
* @param mixed $value
* @return bool
*/
public static function accessible($value)
{
return is_array($value) || $value instanceof ArrayAccess;
}
/**
* Add an element to an array using "dot" notation if it doesn't exist.
*
* @param array $array
* @param string|int|float $key
* @param mixed $value
* @return array
*/
public static function add($array, $key, $value)
{
if (is_null(static::get($array, $key))) {
static::set($array, $key, $value);
}
return $array;
}
/**
* Collapse an array of arrays into a single array.
*
* @param iterable $array
* @return array
*/
public static function collapse($array)
{
$results = [];
foreach ($array as $values) {
if ($values instanceof Collection) {
$values = $values->all();
} elseif (! is_array($values)) {
continue;
}
$results[] = $values;
}
return array_merge([], ...$results);
}
/**
* Cross join the given arrays, returning all possible permutations.
*
* @param iterable ...$arrays
* @return array
*/
public static function crossJoin(...$arrays)
{
$results = [[]];
foreach ($arrays as $index => $array) {
$append = [];
foreach ($results as $product) {
foreach ($array as $item) {
$product[$index] = $item;
$append[] = $product;
}
}
$results = $append;
}
return $results;
}
/**
* Divide an array into two arrays. One with keys and the other with values.
*
* @param array $array
* @return array
*/
public static function divide($array)
{
return [array_keys($array), array_values($array)];
}
/**
* Flatten a multi-dimensional associative array with dots.
*
* @param iterable $array
* @param string $prepend
* @return array
*/
public static function dot($array, $prepend = '')
{
$results = [];
foreach ($array as $key => $value) {
if (is_array($value) && ! empty($value)) {
$results = array_merge($results, static::dot($value, $prepend.$key.'.'));
} else {
$results[$prepend.$key] = $value;
}
}
return $results;
}
/**
* Convert a flatten "dot" notation array into an expanded array.
*
* @param iterable $array
* @return array
*/
public static function undot($array)
{
$results = [];
foreach ($array as $key => $value) {
static::set($results, $key, $value);
}
return $results;
}
/**
* Get all of the given array except for a specified array of keys.
*
* @param array $array
* @param array|string|int|float $keys
* @return array
*/
public static function except($array, $keys)
{
static::forget($array, $keys);
return $array;
}
/**
* Determine if the given key exists in the provided array.
*
* @param \ArrayAccess|array $array
* @param string|int $key
* @return bool
*/
public static function exists($array, $key)
{
if ($array instanceof Enumerable) {
return $array->has($key);
}
if ($array instanceof ArrayAccess) {
return $array->offsetExists($key);
}
if (is_float($key)) {
$key = (string) $key;
}
return array_key_exists($key, $array);
}
/**
* Return the first element in an array passing a given truth test.
*
* @param iterable $array
* @param callable|null $callback
* @param mixed $default
* @return mixed
*/
public static function first($array, callable $callback = null, $default = null)
{
if (is_null($callback)) {
if (empty($array)) {
return value($default);
}
foreach ($array as $item) {
return $item;
}
}
foreach ($array as $key => $value) {
if ($callback($value, $key)) {
return $value;
}
}
return value($default);
}
/**
* Return the last element in an array passing a given truth test.
*
* @param array $array
* @param callable|null $callback
* @param mixed $default
* @return mixed
*/
public static function last($array, callable $callback = null, $default = null)
{
if (is_null($callback)) {
return empty($array) ? value($default) : end($array);
}
return static::first(array_reverse($array, true), $callback, $default);
}
/**
* Flatten a multi-dimensional array into a single level.
*
* @param iterable $array
* @param int $depth
* @return array
*/
public static function flatten($array, $depth = INF)
{
$result = [];
foreach ($array as $item) {
$item = $item instanceof Collection ? $item->all() : $item;
if (! is_array($item)) {
$result[] = $item;
} else {
$values = $depth === 1
? array_values($item)
: static::flatten($item, $depth - 1);
foreach ($values as $value) {
$result[] = $value;
}
}
}
return $result;
}
/**
* Remove one or many array items from a given array using "dot" notation.
*
* @param array $array
* @param array|string|int|float $keys
* @return void
*/
public static function forget(&$array, $keys)
{
$original = &$array;
$keys = (array) $keys;
if (count($keys) === 0) {
return;
}
foreach ($keys as $key) {
// if the exact key exists in the top-level, remove it
if (static::exists($array, $key)) {
unset($array[$key]);
continue;
}
$parts = explode('.', $key);
// clean up before each pass
$array = &$original;
while (count($parts) > 1) {
$part = array_shift($parts);
if (isset($array[$part]) && static::accessible($array[$part])) {
$array = &$array[$part];
} else {
continue 2;
}
}
unset($array[array_shift($parts)]);
}
}
/**
* Get an item from an array using "dot" notation.
*
* @param \ArrayAccess|array $array
* @param string|int|null $key
* @param mixed $default
* @return mixed
*/
public static function get($array, $key, $default = null)
{
if (! static::accessible($array)) {
return value($default);
}
if (is_null($key)) {
return $array;
}
if (static::exists($array, $key)) {
return $array[$key];
}
if (! str_contains($key, '.')) {
return $array[$key] ?? value($default);
}
foreach (explode('.', $key) as $segment) {
if (static::accessible($array) && static::exists($array, $segment)) {
$array = $array[$segment];
} else {
return value($default);
}
}
return $array;
}
/**
* Check if an item or items exist in an array using "dot" notation.
*
* @param \ArrayAccess|array $array
* @param string|array $keys
* @return bool
*/
public static function has($array, $keys)
{
$keys = (array) $keys;
if (! $array || $keys === []) {
return false;
}
foreach ($keys as $key) {
$subKeyArray = $array;
if (static::exists($array, $key)) {
continue;
}
foreach (explode('.', $key) as $segment) {
if (static::accessible($subKeyArray) && static::exists($subKeyArray, $segment)) {
$subKeyArray = $subKeyArray[$segment];
} else {
return false;
}
}
}
return true;
}
/**
* Determine if any of the keys exist in an array using "dot" notation.
*
* @param \ArrayAccess|array $array
* @param string|array $keys
* @return bool
*/
public static function hasAny($array, $keys)
{
if (is_null($keys)) {
return false;
}
$keys = (array) $keys;
if (! $array) {
return false;
}
if ($keys === []) {
return false;
}
foreach ($keys as $key) {
if (static::has($array, $key)) {
return true;
}
}
return false;
}
/**
* Determines if an array is associative.
*
* An array is "associative" if it doesn't have sequential numerical keys beginning with zero.
*
* @param array $array
* @return bool
*/
public static function isAssoc(array $array)
{
$keys = array_keys($array);
return array_keys($keys) !== $keys;
}
/**
* Determines if an array is a list.
*
* An array is a "list" if all array keys are sequential integers starting from 0 with no gaps in between.
*
* @param array $array
* @return bool
*/
public static function isList($array)
{
return ! self::isAssoc($array);
}
/**
* Join all items using a string. The final items can use a separate glue string.
*
* @param array $array
* @param string $glue
* @param string $finalGlue
* @return string
*/
public static function join($array, $glue, $finalGlue = '')
{
if ($finalGlue === '') {
return implode($glue, $array);
}
if (count($array) === 0) {
return '';
}
if (count($array) === 1) {
return end($array);
}
$finalItem = array_pop($array);
return implode($glue, $array).$finalGlue.$finalItem;
}
/**
* Key an associative array by a field or using a callback.
*
* @param array $array
* @param callable|array|string $keyBy
* @return array
*/
public static function keyBy($array, $keyBy)
{
return Collection::make($array)->keyBy($keyBy)->all();
}
/**
* Prepend the key names of an associative array.
*
* @param array $array
* @param string $prependWith
* @return array
*/
public static function prependKeysWith($array, $prependWith)
{
return Collection::make($array)->mapWithKeys(function ($item, $key) use ($prependWith) {
return [$prependWith.$key => $item];
})->all();
}
/**
* Get a subset of the items from the given array.
*
* @param array $array
* @param array|string $keys
* @return array
*/
public static function only($array, $keys)
{
return array_intersect_key($array, array_flip((array) $keys));
}
/**
* Pluck an array of values from an array.
*
* @param iterable $array
* @param string|array|int|null $value
* @param string|array|null $key
* @return array
*/
public static function pluck($array, $value, $key = null)
{
$results = [];
[$value, $key] = static::explodePluckParameters($value, $key);
foreach ($array as $item) {
$itemValue = data_get($item, $value);
// If the key is "null", we will just append the value to the array and keep
// looping. Otherwise we will key the array using the value of the key we
// received from the developer. Then we'll return the final array form.
if (is_null($key)) {
$results[] = $itemValue;
} else {
$itemKey = data_get($item, $key);
if (is_object($itemKey) && method_exists($itemKey, '__toString')) {
$itemKey = (string) $itemKey;
}
$results[$itemKey] = $itemValue;
}
}
return $results;
}
/**
* Explode the "value" and "key" arguments passed to "pluck".
*
* @param string|array $value
* @param string|array|null $key
* @return array
*/
protected static function explodePluckParameters($value, $key)
{
$value = is_string($value) ? explode('.', $value) : $value;
$key = is_null($key) || is_array($key) ? $key : explode('.', $key);
return [$value, $key];
}
/**
* Run a map over each of the items in the array.
*
* @param array $array
* @param callable $callback
* @return array
*/
public static function map(array $array, callable $callback)
{
$keys = array_keys($array);
try {
$items = array_map($callback, $array, $keys);
} catch (ArgumentCountError) {
$items = array_map($callback, $array);
}
return array_combine($keys, $items);
}
/**
* Push an item onto the beginning of an array.
*
* @param array $array
* @param mixed $value
* @param mixed $key
* @return array
*/
public static function prepend($array, $value, $key = null)
{
if (func_num_args() == 2) {
array_unshift($array, $value);
} else {
$array = [$key => $value] + $array;
}
return $array;
}
/**
* Get a value from the array, and remove it.
*
* @param array $array
* @param string|int $key
* @param mixed $default
* @return mixed
*/
public static function pull(&$array, $key, $default = null)
{
$value = static::get($array, $key, $default);
static::forget($array, $key);
return $value;
}
/**
* Convert the array into a query string.
*
* @param array $array
* @return string
*/
public static function query($array)
{
return http_build_query($array, '', '&', PHP_QUERY_RFC3986);
}
/**
* Get one or a specified number of random values from an array.
*
* @param array $array
* @param int|null $number
* @param bool $preserveKeys
* @return mixed
*
* @throws \InvalidArgumentException
*/
public static function random($array, $number = null, $preserveKeys = false)
{
$requested = is_null($number) ? 1 : $number;
$count = count($array);
if ($requested > $count) {
throw new InvalidArgumentException(
"You requested {$requested} items, but there are only {$count} items available."
);
}
if (is_null($number)) {
return $array[array_rand($array)];
}
if ((int) $number === 0) {
return [];
}
$keys = array_rand($array, $number);
$results = [];
if ($preserveKeys) {
foreach ((array) $keys as $key) {
$results[$key] = $array[$key];
}
} else {
foreach ((array) $keys as $key) {
$results[] = $array[$key];
}
}
return $results;
}
/**
* Set an array item to a given value using "dot" notation.
*
* If no key is given to the method, the entire array will be replaced.
*
* @param array $array
* @param string|int|null $key
* @param mixed $value
* @return array
*/
public static function set(&$array, $key, $value)
{
if (is_null($key)) {
return $array = $value;
}
$keys = explode('.', $key);
foreach ($keys as $i => $key) {
if (count($keys) === 1) {
break;
}
unset($keys[$i]);
// If the key doesn't exist at this depth, we will just create an empty array
// to hold the next value, allowing us to create the arrays to hold final
// values at the correct depth. Then we'll keep digging into the array.
if (! isset($array[$key]) || ! is_array($array[$key])) {
$array[$key] = [];
}
$array = &$array[$key];
}
$array[array_shift($keys)] = $value;
return $array;
}
/**
* Shuffle the given array and return the result.
*
* @param array $array
* @param int|null $seed
* @return array
*/
public static function shuffle($array, $seed = null)
{
if (is_null($seed)) {
shuffle($array);
} else {
mt_srand($seed);
shuffle($array);
mt_srand();
}
return $array;
}
/**
* Sort the array using the given callback or "dot" notation.
*
* @param array $array
* @param callable|array|string|null $callback
* @return array
*/
public static function sort($array, $callback = null)
{
return Collection::make($array)->sortBy($callback)->all();
}
/**
* Sort the array in descending order using the given callback or "dot" notation.
*
* @param array $array
* @param callable|array|string|null $callback
* @return array
*/
public static function sortDesc($array, $callback = null)
{
return Collection::make($array)->sortByDesc($callback)->all();
}
/**
* Recursively sort an array by keys and values.
*
* @param array $array
* @param int $options
* @param bool $descending
* @return array
*/
public static function sortRecursive($array, $options = SORT_REGULAR, $descending = false)
{
foreach ($array as &$value) {
if (is_array($value)) {
$value = static::sortRecursive($value, $options, $descending);
}
}
if (static::isAssoc($array)) {
$descending
? krsort($array, $options)
: ksort($array, $options);
} else {
$descending
? rsort($array, $options)
: sort($array, $options);
}
return $array;
}
/**
* Conditionally compile classes from an array into a CSS class list.
*
* @param array $array
* @return string
*/
public static function toCssClasses($array)
{
$classList = static::wrap($array);
$classes = [];
foreach ($classList as $class => $constraint) {
if (is_numeric($class)) {
$classes[] = $constraint;
} elseif ($constraint) {
$classes[] = $class;
}
}
return implode(' ', $classes);
}
/**
* Conditionally compile styles from an array into a style list.
*
* @param array $array
* @return string
*/
public static function toCssStyles($array)
{
$styleList = static::wrap($array);
$styles = [];
foreach ($styleList as $class => $constraint) {
if (is_numeric($class)) {
$styles[] = Str::finish($constraint, ';');
} elseif ($constraint) {
$styles[] = Str::finish($class, ';');
}
}
return implode(' ', $styles);
}
/**
* Filter the array using the given callback.
*
* @param array $array
* @param callable $callback
* @return array
*/
public static function where($array, callable $callback)
{
return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH);
}
/**
* Filter items where the value is not null.
*
* @param array $array
* @return array
*/
public static function whereNotNull($array)
{
return static::where($array, fn ($value) => ! is_null($value));
}
/**
* If the given value is not an array and not null, wrap it in one.
*
* @param mixed $value
* @return array
*/
public static function wrap($value)
{
if (is_null($value)) {
return [];
}
return is_array($value) ? $value : [$value];
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,63 @@
<?php
namespace Illuminate\Support;
/**
* @mixin \Illuminate\Support\Enumerable
*/
class HigherOrderCollectionProxy
{
/**
* The collection being operated on.
*
* @var \Illuminate\Support\Enumerable
*/
protected $collection;
/**
* The method being proxied.
*
* @var string
*/
protected $method;
/**
* Create a new proxy instance.
*
* @param \Illuminate\Support\Enumerable $collection
* @param string $method
* @return void
*/
public function __construct(Enumerable $collection, $method)
{
$this->method = $method;
$this->collection = $collection;
}
/**
* Proxy accessing an attribute onto the collection items.
*
* @param string $key
* @return mixed
*/
public function __get($key)
{
return $this->collection->{$this->method}(function ($value) use ($key) {
return is_array($value) ? $value[$key] : $value->{$key};
});
}
/**
* Proxy a method call onto the collection items.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
return $this->collection->{$this->method}(function ($value) use ($method, $parameters) {
return $value->{$method}(...$parameters);
});
}
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Illuminate\Support;
use RuntimeException;
class ItemNotFoundException extends RuntimeException
{
}

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Taylor Otwell
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.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
<?php
namespace Illuminate\Support;
use RuntimeException;
class MultipleItemsFoundException extends RuntimeException
{
/**
* The number of items found.
*
* @var int
*/
public $count;
/**
* Create a new exception instance.
*
* @param int $count
* @param int $code
* @param \Throwable|null $previous
* @return void
*/
public function __construct($count, $code = 0, $previous = null)
{
$this->count = $count;
parent::__construct("$count items were found.", $code, $previous);
}
/**
* Get the number of items found.
*
* @return int
*/
public function getCount()
{
return $this->count;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,42 @@
{
"name": "illuminate/collections",
"description": "The Illuminate Collections package.",
"license": "MIT",
"homepage": "https://laravel.com",
"support": {
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"require": {
"php": "^8.0.2",
"illuminate/conditionable": "^9.0",
"illuminate/contracts": "^9.0",
"illuminate/macroable": "^9.0"
},
"autoload": {
"psr-4": {
"Illuminate\\Support\\": ""
},
"files": [
"helpers.php"
]
},
"extra": {
"branch-alias": {
"dev-master": "9.x-dev"
}
},
"suggest": {
"symfony/var-dumper": "Required to use the dump method (^6.0)."
},
"config": {
"sort-packages": true
},
"minimum-stability": "dev"
}

View File

@@ -0,0 +1,190 @@
<?php
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
if (! function_exists('collect')) {
/**
* Create a collection from the given value.
*
* @template TKey of array-key
* @template TValue
*
* @param \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>|null $value
* @return \Illuminate\Support\Collection<TKey, TValue>
*/
function collect($value = [])
{
return new Collection($value);
}
}
if (! function_exists('data_fill')) {
/**
* Fill in data where it's missing.
*
* @param mixed $target
* @param string|array $key
* @param mixed $value
* @return mixed
*/
function data_fill(&$target, $key, $value)
{
return data_set($target, $key, $value, false);
}
}
if (! function_exists('data_get')) {
/**
* Get an item from an array or object using "dot" notation.
*
* @param mixed $target
* @param string|array|int|null $key
* @param mixed $default
* @return mixed
*/
function data_get($target, $key, $default = null)
{
if (is_null($key)) {
return $target;
}
$key = is_array($key) ? $key : explode('.', $key);
foreach ($key as $i => $segment) {
unset($key[$i]);
if (is_null($segment)) {
return $target;
}
if ($segment === '*') {
if ($target instanceof Collection) {
$target = $target->all();
} elseif (! is_iterable($target)) {
return value($default);
}
$result = [];
foreach ($target as $item) {
$result[] = data_get($item, $key);
}
return in_array('*', $key) ? Arr::collapse($result) : $result;
}
if (Arr::accessible($target) && Arr::exists($target, $segment)) {
$target = $target[$segment];
} elseif (is_object($target) && isset($target->{$segment})) {
$target = $target->{$segment};
} else {
return value($default);
}
}
return $target;
}
}
if (! function_exists('data_set')) {
/**
* Set an item on an array or object using dot notation.
*
* @param mixed $target
* @param string|array $key
* @param mixed $value
* @param bool $overwrite
* @return mixed
*/
function data_set(&$target, $key, $value, $overwrite = true)
{
$segments = is_array($key) ? $key : explode('.', $key);
if (($segment = array_shift($segments)) === '*') {
if (! Arr::accessible($target)) {
$target = [];
}
if ($segments) {
foreach ($target as &$inner) {
data_set($inner, $segments, $value, $overwrite);
}
} elseif ($overwrite) {
foreach ($target as &$inner) {
$inner = $value;
}
}
} elseif (Arr::accessible($target)) {
if ($segments) {
if (! Arr::exists($target, $segment)) {
$target[$segment] = [];
}
data_set($target[$segment], $segments, $value, $overwrite);
} elseif ($overwrite || ! Arr::exists($target, $segment)) {
$target[$segment] = $value;
}
} elseif (is_object($target)) {
if ($segments) {
if (! isset($target->{$segment})) {
$target->{$segment} = [];
}
data_set($target->{$segment}, $segments, $value, $overwrite);
} elseif ($overwrite || ! isset($target->{$segment})) {
$target->{$segment} = $value;
}
} else {
$target = [];
if ($segments) {
data_set($target[$segment], $segments, $value, $overwrite);
} elseif ($overwrite) {
$target[$segment] = $value;
}
}
return $target;
}
}
if (! function_exists('head')) {
/**
* Get the first element of an array. Useful for method chaining.
*
* @param array $array
* @return mixed
*/
function head($array)
{
return reset($array);
}
}
if (! function_exists('last')) {
/**
* Get the last element from an array.
*
* @param array $array
* @return mixed
*/
function last($array)
{
return end($array);
}
}
if (! function_exists('value')) {
/**
* Return the default value of the given value.
*
* @param mixed $value
* @param mixed ...$args
* @return mixed
*/
function value($value, ...$args)
{
return $value instanceof Closure ? $value(...$args) : $value;
}
}

View File

@@ -0,0 +1,109 @@
<?php
namespace Illuminate\Support;
class HigherOrderWhenProxy
{
/**
* The target being conditionally operated on.
*
* @var mixed
*/
protected $target;
/**
* The condition for proxying.
*
* @var bool
*/
protected $condition;
/**
* Indicates whether the proxy has a condition.
*
* @var bool
*/
protected $hasCondition = false;
/**
* Determine whether the condition should be negated.
*
* @var bool
*/
protected $negateConditionOnCapture;
/**
* Create a new proxy instance.
*
* @param mixed $target
* @return void
*/
public function __construct($target)
{
$this->target = $target;
}
/**
* Set the condition on the proxy.
*
* @param bool $condition
* @return $this
*/
public function condition($condition)
{
[$this->condition, $this->hasCondition] = [$condition, true];
return $this;
}
/**
* Indicate that the condition should be negated.
*
* @return $this
*/
public function negateConditionOnCapture()
{
$this->negateConditionOnCapture = true;
return $this;
}
/**
* Proxy accessing an attribute onto the target.
*
* @param string $key
* @return mixed
*/
public function __get($key)
{
if (! $this->hasCondition) {
$condition = $this->target->{$key};
return $this->condition($this->negateConditionOnCapture ? ! $condition : $condition);
}
return $this->condition
? $this->target->{$key}
: $this->target;
}
/**
* Proxy a method call on the target.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
if (! $this->hasCondition) {
$condition = $this->target->{$method}(...$parameters);
return $this->condition($this->negateConditionOnCapture ? ! $condition : $condition);
}
return $this->condition
? $this->target->{$method}(...$parameters)
: $this->target;
}
}

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Taylor Otwell
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.

View File

@@ -0,0 +1,73 @@
<?php
namespace Illuminate\Support\Traits;
use Closure;
use Illuminate\Support\HigherOrderWhenProxy;
trait Conditionable
{
/**
* Apply the callback if the given "value" is (or resolves to) truthy.
*
* @template TWhenParameter
* @template TWhenReturnType
*
* @param (\Closure($this): TWhenParameter)|TWhenParameter|null $value
* @param (callable($this, TWhenParameter): TWhenReturnType)|null $callback
* @param (callable($this, TWhenParameter): TWhenReturnType)|null $default
* @return $this|TWhenReturnType
*/
public function when($value = null, callable $callback = null, callable $default = null)
{
$value = $value instanceof Closure ? $value($this) : $value;
if (func_num_args() === 0) {
return new HigherOrderWhenProxy($this);
}
if (func_num_args() === 1) {
return (new HigherOrderWhenProxy($this))->condition($value);
}
if ($value) {
return $callback($this, $value) ?? $this;
} elseif ($default) {
return $default($this, $value) ?? $this;
}
return $this;
}
/**
* Apply the callback if the given "value" is (or resolves to) falsy.
*
* @template TUnlessParameter
* @template TUnlessReturnType
*
* @param (\Closure($this): TUnlessParameter)|TUnlessParameter|null $value
* @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $callback
* @param (callable($this, TUnlessParameter): TUnlessReturnType)|null $default
* @return $this|TUnlessReturnType
*/
public function unless($value = null, callable $callback = null, callable $default = null)
{
$value = $value instanceof Closure ? $value($this) : $value;
if (func_num_args() === 0) {
return (new HigherOrderWhenProxy($this))->negateConditionOnCapture();
}
if (func_num_args() === 1) {
return (new HigherOrderWhenProxy($this))->condition(! $value);
}
if (! $value) {
return $callback($this, $value) ?? $this;
} elseif ($default) {
return $default($this, $value) ?? $this;
}
return $this;
}
}

View File

@@ -0,0 +1,33 @@
{
"name": "illuminate/conditionable",
"description": "The Illuminate Conditionable package.",
"license": "MIT",
"homepage": "https://laravel.com",
"support": {
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"require": {
"php": "^8.0.2"
},
"autoload": {
"psr-4": {
"Illuminate\\Support\\": ""
}
},
"extra": {
"branch-alias": {
"dev-master": "9.x-dev"
}
},
"config": {
"sort-packages": true
},
"minimum-stability": "dev"
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Illuminate\Contracts\Auth\Access;
interface Authorizable
{
/**
* Determine if the entity has a given ability.
*
* @param iterable|string $abilities
* @param array|mixed $arguments
* @return bool
*/
public function can($abilities, $arguments = []);
}

View File

@@ -0,0 +1,150 @@
<?php
namespace Illuminate\Contracts\Auth\Access;
interface Gate
{
/**
* Determine if a given ability has been defined.
*
* @param string $ability
* @return bool
*/
public function has($ability);
/**
* Define a new ability.
*
* @param string $ability
* @param callable|string $callback
* @return $this
*/
public function define($ability, $callback);
/**
* Define abilities for a resource.
*
* @param string $name
* @param string $class
* @param array|null $abilities
* @return $this
*/
public function resource($name, $class, array $abilities = null);
/**
* Define a policy class for a given class type.
*
* @param string $class
* @param string $policy
* @return $this
*/
public function policy($class, $policy);
/**
* Register a callback to run before all Gate checks.
*
* @param callable $callback
* @return $this
*/
public function before(callable $callback);
/**
* Register a callback to run after all Gate checks.
*
* @param callable $callback
* @return $this
*/
public function after(callable $callback);
/**
* Determine if the given ability should be granted for the current user.
*
* @param string $ability
* @param array|mixed $arguments
* @return bool
*/
public function allows($ability, $arguments = []);
/**
* Determine if the given ability should be denied for the current user.
*
* @param string $ability
* @param array|mixed $arguments
* @return bool
*/
public function denies($ability, $arguments = []);
/**
* Determine if all of the given abilities should be granted for the current user.
*
* @param iterable|string $abilities
* @param array|mixed $arguments
* @return bool
*/
public function check($abilities, $arguments = []);
/**
* Determine if any one of the given abilities should be granted for the current user.
*
* @param iterable|string $abilities
* @param array|mixed $arguments
* @return bool
*/
public function any($abilities, $arguments = []);
/**
* Determine if the given ability should be granted for the current user.
*
* @param string $ability
* @param array|mixed $arguments
* @return \Illuminate\Auth\Access\Response
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function authorize($ability, $arguments = []);
/**
* Inspect the user for the given ability.
*
* @param string $ability
* @param array|mixed $arguments
* @return \Illuminate\Auth\Access\Response
*/
public function inspect($ability, $arguments = []);
/**
* Get the raw result from the authorization callback.
*
* @param string $ability
* @param array|mixed $arguments
* @return mixed
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function raw($ability, $arguments = []);
/**
* Get a policy instance for a given class.
*
* @param object|string $class
* @return mixed
*
* @throws \InvalidArgumentException
*/
public function getPolicyFor($class);
/**
* Get a guard instance for the given user.
*
* @param \Illuminate\Contracts\Auth\Authenticatable|mixed $user
* @return static
*/
public function forUser($user);
/**
* Get all of the defined abilities.
*
* @return array
*/
public function abilities();
}

View File

@@ -0,0 +1,49 @@
<?php
namespace Illuminate\Contracts\Auth;
interface Authenticatable
{
/**
* Get the name of the unique identifier for the user.
*
* @return string
*/
public function getAuthIdentifierName();
/**
* Get the unique identifier for the user.
*
* @return mixed
*/
public function getAuthIdentifier();
/**
* Get the password for the user.
*
* @return string
*/
public function getAuthPassword();
/**
* Get the token value for the "remember me" session.
*
* @return string
*/
public function getRememberToken();
/**
* Set the token value for the "remember me" session.
*
* @param string $value
* @return void
*/
public function setRememberToken($value);
/**
* Get the column name for the "remember me" token.
*
* @return string
*/
public function getRememberTokenName();
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Illuminate\Contracts\Auth;
interface CanResetPassword
{
/**
* Get the e-mail address where password reset links are sent.
*
* @return string
*/
public function getEmailForPasswordReset();
/**
* Send the password reset notification.
*
* @param string $token
* @return void
*/
public function sendPasswordResetNotification($token);
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Illuminate\Contracts\Auth;
interface Factory
{
/**
* Get a guard instance by name.
*
* @param string|null $name
* @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard
*/
public function guard($name = null);
/**
* Set the default guard the factory should serve.
*
* @param string $name
* @return void
*/
public function shouldUse($name);
}

View File

@@ -0,0 +1,57 @@
<?php
namespace Illuminate\Contracts\Auth;
interface Guard
{
/**
* Determine if the current user is authenticated.
*
* @return bool
*/
public function check();
/**
* Determine if the current user is a guest.
*
* @return bool
*/
public function guest();
/**
* Get the currently authenticated user.
*
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function user();
/**
* Get the ID for the currently authenticated user.
*
* @return int|string|null
*/
public function id();
/**
* Validate a user's credentials.
*
* @param array $credentials
* @return bool
*/
public function validate(array $credentials = []);
/**
* Determine if the guard has a user instance.
*
* @return bool
*/
public function hasUser();
/**
* Set the current user.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @return void
*/
public function setUser(Authenticatable $user);
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Illuminate\Contracts\Auth\Middleware;
interface AuthenticatesRequests
{
//
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Illuminate\Contracts\Auth;
interface MustVerifyEmail
{
/**
* Determine if the user has verified their email address.
*
* @return bool
*/
public function hasVerifiedEmail();
/**
* Mark the given user's email as verified.
*
* @return bool
*/
public function markEmailAsVerified();
/**
* Send the email verification notification.
*
* @return void
*/
public function sendEmailVerificationNotification();
/**
* Get the email address that should be used for verification.
*
* @return string
*/
public function getEmailForVerification();
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Illuminate\Contracts\Auth;
use Closure;
interface PasswordBroker
{
/**
* Constant representing a successfully sent reminder.
*
* @var string
*/
const RESET_LINK_SENT = 'passwords.sent';
/**
* Constant representing a successfully reset password.
*
* @var string
*/
const PASSWORD_RESET = 'passwords.reset';
/**
* Constant representing the user not found response.
*
* @var string
*/
const INVALID_USER = 'passwords.user';
/**
* Constant representing an invalid token.
*
* @var string
*/
const INVALID_TOKEN = 'passwords.token';
/**
* Constant representing a throttled reset attempt.
*
* @var string
*/
const RESET_THROTTLED = 'passwords.throttled';
/**
* Send a password reset link to a user.
*
* @param array $credentials
* @param \Closure|null $callback
* @return string
*/
public function sendResetLink(array $credentials, Closure $callback = null);
/**
* Reset the password for the given token.
*
* @param array $credentials
* @param \Closure $callback
* @return mixed
*/
public function reset(array $credentials, Closure $callback);
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Illuminate\Contracts\Auth;
interface PasswordBrokerFactory
{
/**
* Get a password broker instance by name.
*
* @param string|null $name
* @return \Illuminate\Contracts\Auth\PasswordBroker
*/
public function broker($name = null);
}

View File

@@ -0,0 +1,63 @@
<?php
namespace Illuminate\Contracts\Auth;
interface StatefulGuard extends Guard
{
/**
* Attempt to authenticate a user using the given credentials.
*
* @param array $credentials
* @param bool $remember
* @return bool
*/
public function attempt(array $credentials = [], $remember = false);
/**
* Log a user into the application without sessions or cookies.
*
* @param array $credentials
* @return bool
*/
public function once(array $credentials = []);
/**
* Log a user into the application.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param bool $remember
* @return void
*/
public function login(Authenticatable $user, $remember = false);
/**
* Log the given user ID into the application.
*
* @param mixed $id
* @param bool $remember
* @return \Illuminate\Contracts\Auth\Authenticatable|bool
*/
public function loginUsingId($id, $remember = false);
/**
* Log the given user ID into the application without sessions or cookies.
*
* @param mixed $id
* @return \Illuminate\Contracts\Auth\Authenticatable|bool
*/
public function onceUsingId($id);
/**
* Determine if the user was authenticated via "remember me" cookie.
*
* @return bool
*/
public function viaRemember();
/**
* Log the user out of the application.
*
* @return void
*/
public function logout();
}

View File

@@ -0,0 +1,24 @@
<?php
namespace Illuminate\Contracts\Auth;
interface SupportsBasicAuth
{
/**
* Attempt to authenticate using HTTP Basic Auth.
*
* @param string $field
* @param array $extraConditions
* @return \Symfony\Component\HttpFoundation\Response|null
*/
public function basic($field = 'email', $extraConditions = []);
/**
* Perform a stateless HTTP Basic login attempt.
*
* @param string $field
* @param array $extraConditions
* @return \Symfony\Component\HttpFoundation\Response|null
*/
public function onceBasic($field = 'email', $extraConditions = []);
}

View File

@@ -0,0 +1,49 @@
<?php
namespace Illuminate\Contracts\Auth;
interface UserProvider
{
/**
* Retrieve a user by their unique identifier.
*
* @param mixed $identifier
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveById($identifier);
/**
* Retrieve a user by their unique identifier and "remember me" token.
*
* @param mixed $identifier
* @param string $token
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByToken($identifier, $token);
/**
* Update the "remember me" token for the given user in storage.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param string $token
* @return void
*/
public function updateRememberToken(Authenticatable $user, $token);
/**
* Retrieve a user by the given credentials.
*
* @param array $credentials
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByCredentials(array $credentials);
/**
* Validate a user against the given credentials.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param array $credentials
* @return bool
*/
public function validateCredentials(Authenticatable $user, array $credentials);
}

View File

@@ -0,0 +1,35 @@
<?php
namespace Illuminate\Contracts\Broadcasting;
interface Broadcaster
{
/**
* Authenticate the incoming request for a given channel.
*
* @param \Illuminate\Http\Request $request
* @return mixed
*/
public function auth($request);
/**
* Return the valid authentication response.
*
* @param \Illuminate\Http\Request $request
* @param mixed $result
* @return mixed
*/
public function validAuthenticationResponse($request, $result);
/**
* Broadcast the given event.
*
* @param array $channels
* @param string $event
* @param array $payload
* @return void
*
* @throws \Illuminate\Broadcasting\BroadcastException
*/
public function broadcast(array $channels, $event, array $payload = []);
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Illuminate\Contracts\Broadcasting;
interface Factory
{
/**
* Get a broadcaster implementation by name.
*
* @param string|null $name
* @return \Illuminate\Contracts\Broadcasting\Broadcaster
*/
public function connection($name = null);
}

View File

@@ -0,0 +1,20 @@
<?php
namespace Illuminate\Contracts\Broadcasting;
interface HasBroadcastChannel
{
/**
* Get the broadcast channel route definition that is associated with the given entity.
*
* @return string
*/
public function broadcastChannelRoute();
/**
* Get the broadcast channel name that is associated with the given entity.
*
* @return string
*/
public function broadcastChannel();
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Illuminate\Contracts\Broadcasting;
interface ShouldBeUnique
{
//
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Illuminate\Contracts\Broadcasting;
interface ShouldBroadcast
{
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|\Illuminate\Broadcasting\Channel[]|string[]|string
*/
public function broadcastOn();
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Illuminate\Contracts\Broadcasting;
interface ShouldBroadcastNow extends ShouldBroadcast
{
//
}

View File

@@ -0,0 +1,66 @@
<?php
namespace Illuminate\Contracts\Bus;
interface Dispatcher
{
/**
* Dispatch a command to its appropriate handler.
*
* @param mixed $command
* @return mixed
*/
public function dispatch($command);
/**
* Dispatch a command to its appropriate handler in the current process.
*
* Queueable jobs will be dispatched to the "sync" queue.
*
* @param mixed $command
* @param mixed $handler
* @return mixed
*/
public function dispatchSync($command, $handler = null);
/**
* Dispatch a command to its appropriate handler in the current process.
*
* @param mixed $command
* @param mixed $handler
* @return mixed
*/
public function dispatchNow($command, $handler = null);
/**
* Determine if the given command has a handler.
*
* @param mixed $command
* @return bool
*/
public function hasCommandHandler($command);
/**
* Retrieve the handler for a command.
*
* @param mixed $command
* @return bool|mixed
*/
public function getCommandHandler($command);
/**
* Set the pipes commands should be piped through before dispatching.
*
* @param array $pipes
* @return $this
*/
public function pipeThrough(array $pipes);
/**
* Map a command to a handler.
*
* @param array $map
* @return $this
*/
public function map(array $map);
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Illuminate\Contracts\Bus;
interface QueueingDispatcher extends Dispatcher
{
/**
* Attempt to find the batch with the given ID.
*
* @param string $batchId
* @return \Illuminate\Bus\Batch|null
*/
public function findBatch(string $batchId);
/**
* Create a new batch of queueable jobs.
*
* @param \Illuminate\Support\Collection|array $jobs
* @return \Illuminate\Bus\PendingBatch
*/
public function batch($jobs);
/**
* Dispatch a command to its appropriate handler behind a queue.
*
* @param mixed $command
* @return mixed
*/
public function dispatchToQueue($command);
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Illuminate\Contracts\Cache;
interface Factory
{
/**
* Get a cache store instance by name.
*
* @param string|null $name
* @return \Illuminate\Contracts\Cache\Repository
*/
public function store($name = null);
}

View File

@@ -0,0 +1,44 @@
<?php
namespace Illuminate\Contracts\Cache;
interface Lock
{
/**
* Attempt to acquire the lock.
*
* @param callable|null $callback
* @return mixed
*/
public function get($callback = null);
/**
* Attempt to acquire the lock for the given number of seconds.
*
* @param int $seconds
* @param callable|null $callback
* @return mixed
*/
public function block($seconds, $callback = null);
/**
* Release the lock.
*
* @return bool
*/
public function release();
/**
* Returns the current owner of the lock.
*
* @return string
*/
public function owner();
/**
* Releases this lock in disregard of ownership.
*
* @return void
*/
public function forceRelease();
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Illuminate\Contracts\Cache;
interface LockProvider
{
/**
* Get a lock instance.
*
* @param string $name
* @param int $seconds
* @param string|null $owner
* @return \Illuminate\Contracts\Cache\Lock
*/
public function lock($name, $seconds = 0, $owner = null);
/**
* Restore a lock instance using the owner identifier.
*
* @param string $name
* @param string $owner
* @return \Illuminate\Contracts\Cache\Lock
*/
public function restoreLock($name, $owner);
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Illuminate\Contracts\Cache;
use Exception;
class LockTimeoutException extends Exception
{
//
}

View File

@@ -0,0 +1,116 @@
<?php
namespace Illuminate\Contracts\Cache;
use Closure;
use Psr\SimpleCache\CacheInterface;
interface Repository extends CacheInterface
{
/**
* Retrieve an item from the cache and delete it.
*
* @template TCacheValue
*
* @param array|string $key
* @param TCacheValue|(\Closure(): TCacheValue) $default
* @return (TCacheValue is null ? mixed : TCacheValue)
*/
public function pull($key, $default = null);
/**
* Store an item in the cache.
*
* @param string $key
* @param mixed $value
* @param \DateTimeInterface|\DateInterval|int|null $ttl
* @return bool
*/
public function put($key, $value, $ttl = null);
/**
* Store an item in the cache if the key does not exist.
*
* @param string $key
* @param mixed $value
* @param \DateTimeInterface|\DateInterval|int|null $ttl
* @return bool
*/
public function add($key, $value, $ttl = null);
/**
* Increment the value of an item in the cache.
*
* @param string $key
* @param mixed $value
* @return int|bool
*/
public function increment($key, $value = 1);
/**
* Decrement the value of an item in the cache.
*
* @param string $key
* @param mixed $value
* @return int|bool
*/
public function decrement($key, $value = 1);
/**
* Store an item in the cache indefinitely.
*
* @param string $key
* @param mixed $value
* @return bool
*/
public function forever($key, $value);
/**
* Get an item from the cache, or execute the given Closure and store the result.
*
* @template TCacheValue
*
* @param string $key
* @param \DateTimeInterface|\DateInterval|int|null $ttl
* @param \Closure(): TCacheValue $callback
* @return TCacheValue
*/
public function remember($key, $ttl, Closure $callback);
/**
* Get an item from the cache, or execute the given Closure and store the result forever.
*
* @template TCacheValue
*
* @param string $key
* @param \Closure(): TCacheValue $callback
* @return TCacheValue
*/
public function sear($key, Closure $callback);
/**
* Get an item from the cache, or execute the given Closure and store the result forever.
*
* @template TCacheValue
*
* @param string $key
* @param \Closure(): TCacheValue $callback
* @return TCacheValue
*/
public function rememberForever($key, Closure $callback);
/**
* Remove an item from the cache.
*
* @param string $key
* @return bool
*/
public function forget($key);
/**
* Get the cache store implementation.
*
* @return \Illuminate\Contracts\Cache\Store
*/
public function getStore();
}

View File

@@ -0,0 +1,92 @@
<?php
namespace Illuminate\Contracts\Cache;
interface Store
{
/**
* Retrieve an item from the cache by key.
*
* @param string|array $key
* @return mixed
*/
public function get($key);
/**
* Retrieve multiple items from the cache by key.
*
* Items not found in the cache will have a null value.
*
* @param array $keys
* @return array
*/
public function many(array $keys);
/**
* Store an item in the cache for a given number of seconds.
*
* @param string $key
* @param mixed $value
* @param int $seconds
* @return bool
*/
public function put($key, $value, $seconds);
/**
* Store multiple items in the cache for a given number of seconds.
*
* @param array $values
* @param int $seconds
* @return bool
*/
public function putMany(array $values, $seconds);
/**
* Increment the value of an item in the cache.
*
* @param string $key
* @param mixed $value
* @return int|bool
*/
public function increment($key, $value = 1);
/**
* Decrement the value of an item in the cache.
*
* @param string $key
* @param mixed $value
* @return int|bool
*/
public function decrement($key, $value = 1);
/**
* Store an item in the cache indefinitely.
*
* @param string $key
* @param mixed $value
* @return bool
*/
public function forever($key, $value);
/**
* Remove an item from the cache.
*
* @param string $key
* @return bool
*/
public function forget($key);
/**
* Remove all items from the cache.
*
* @return bool
*/
public function flush();
/**
* Get the cache key prefix.
*
* @return string
*/
public function getPrefix();
}

View File

@@ -0,0 +1,57 @@
<?php
namespace Illuminate\Contracts\Config;
interface Repository
{
/**
* Determine if the given configuration value exists.
*
* @param string $key
* @return bool
*/
public function has($key);
/**
* Get the specified configuration value.
*
* @param array|string $key
* @param mixed $default
* @return mixed
*/
public function get($key, $default = null);
/**
* Get all of the configuration items for the application.
*
* @return array
*/
public function all();
/**
* Set a given configuration value.
*
* @param array|string $key
* @param mixed $value
* @return void
*/
public function set($key, $value = null);
/**
* Prepend a value onto an array configuration value.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function prepend($key, $value);
/**
* Push a value onto an array configuration value.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function push($key, $value);
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Illuminate\Contracts\Console;
interface Application
{
/**
* Run an Artisan console command by name.
*
* @param string $command
* @param array $parameters
* @param \Symfony\Component\Console\Output\OutputInterface|null $outputBuffer
* @return int
*/
public function call($command, array $parameters = [], $outputBuffer = null);
/**
* Get the output from the last command.
*
* @return string
*/
public function output();
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Illuminate\Contracts\Console;
interface Isolatable
{
//
}

View File

@@ -0,0 +1,64 @@
<?php
namespace Illuminate\Contracts\Console;
interface Kernel
{
/**
* Bootstrap the application for artisan commands.
*
* @return void
*/
public function bootstrap();
/**
* Handle an incoming console command.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface|null $output
* @return int
*/
public function handle($input, $output = null);
/**
* Run an Artisan console command by name.
*
* @param string $command
* @param array $parameters
* @param \Symfony\Component\Console\Output\OutputInterface|null $outputBuffer
* @return int
*/
public function call($command, array $parameters = [], $outputBuffer = null);
/**
* Queue an Artisan console command by name.
*
* @param string $command
* @param array $parameters
* @return \Illuminate\Foundation\Bus\PendingDispatch
*/
public function queue($command, array $parameters = []);
/**
* Get all of the commands registered with the console.
*
* @return array
*/
public function all();
/**
* Get the output for the last run command.
*
* @return string
*/
public function output();
/**
* Terminate the application.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param int $status
* @return void
*/
public function terminate($input, $status);
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Illuminate\Contracts\Console;
interface PromptsForMissingInput
{
//
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Illuminate\Contracts\Container;
use Exception;
use Psr\Container\ContainerExceptionInterface;
class BindingResolutionException extends Exception implements ContainerExceptionInterface
{
//
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Illuminate\Contracts\Container;
use Exception;
use Psr\Container\ContainerExceptionInterface;
class CircularDependencyException extends Exception implements ContainerExceptionInterface
{
//
}

View File

@@ -0,0 +1,210 @@
<?php
namespace Illuminate\Contracts\Container;
use Closure;
use Psr\Container\ContainerInterface;
interface Container extends ContainerInterface
{
/**
* Determine if the given abstract type has been bound.
*
* @param string $abstract
* @return bool
*/
public function bound($abstract);
/**
* Alias a type to a different name.
*
* @param string $abstract
* @param string $alias
* @return void
*
* @throws \LogicException
*/
public function alias($abstract, $alias);
/**
* Assign a set of tags to a given binding.
*
* @param array|string $abstracts
* @param array|mixed ...$tags
* @return void
*/
public function tag($abstracts, $tags);
/**
* Resolve all of the bindings for a given tag.
*
* @param string $tag
* @return iterable
*/
public function tagged($tag);
/**
* Register a binding with the container.
*
* @param string $abstract
* @param \Closure|string|null $concrete
* @param bool $shared
* @return void
*/
public function bind($abstract, $concrete = null, $shared = false);
/**
* Register a binding if it hasn't already been registered.
*
* @param string $abstract
* @param \Closure|string|null $concrete
* @param bool $shared
* @return void
*/
public function bindIf($abstract, $concrete = null, $shared = false);
/**
* Register a shared binding in the container.
*
* @param string $abstract
* @param \Closure|string|null $concrete
* @return void
*/
public function singleton($abstract, $concrete = null);
/**
* Register a shared binding if it hasn't already been registered.
*
* @param string $abstract
* @param \Closure|string|null $concrete
* @return void
*/
public function singletonIf($abstract, $concrete = null);
/**
* Register a scoped binding in the container.
*
* @param string $abstract
* @param \Closure|string|null $concrete
* @return void
*/
public function scoped($abstract, $concrete = null);
/**
* Register a scoped binding if it hasn't already been registered.
*
* @param string $abstract
* @param \Closure|string|null $concrete
* @return void
*/
public function scopedIf($abstract, $concrete = null);
/**
* "Extend" an abstract type in the container.
*
* @param string $abstract
* @param \Closure $closure
* @return void
*
* @throws \InvalidArgumentException
*/
public function extend($abstract, Closure $closure);
/**
* Register an existing instance as shared in the container.
*
* @param string $abstract
* @param mixed $instance
* @return mixed
*/
public function instance($abstract, $instance);
/**
* Add a contextual binding to the container.
*
* @param string $concrete
* @param string $abstract
* @param \Closure|string $implementation
* @return void
*/
public function addContextualBinding($concrete, $abstract, $implementation);
/**
* Define a contextual binding.
*
* @param string|array $concrete
* @return \Illuminate\Contracts\Container\ContextualBindingBuilder
*/
public function when($concrete);
/**
* Get a closure to resolve the given type from the container.
*
* @param string $abstract
* @return \Closure
*/
public function factory($abstract);
/**
* Flush the container of all bindings and resolved instances.
*
* @return void
*/
public function flush();
/**
* Resolve the given type from the container.
*
* @param string $abstract
* @param array $parameters
* @return mixed
*
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function make($abstract, array $parameters = []);
/**
* Call the given Closure / class@method and inject its dependencies.
*
* @param callable|string $callback
* @param array $parameters
* @param string|null $defaultMethod
* @return mixed
*/
public function call($callback, array $parameters = [], $defaultMethod = null);
/**
* Determine if the given abstract type has been resolved.
*
* @param string $abstract
* @return bool
*/
public function resolved($abstract);
/**
* Register a new before resolving callback.
*
* @param \Closure|string $abstract
* @param \Closure|null $callback
* @return void
*/
public function beforeResolving($abstract, Closure $callback = null);
/**
* Register a new resolving callback.
*
* @param \Closure|string $abstract
* @param \Closure|null $callback
* @return void
*/
public function resolving($abstract, Closure $callback = null);
/**
* Register a new after resolving callback.
*
* @param \Closure|string $abstract
* @param \Closure|null $callback
* @return void
*/
public function afterResolving($abstract, Closure $callback = null);
}

View File

@@ -0,0 +1,39 @@
<?php
namespace Illuminate\Contracts\Container;
interface ContextualBindingBuilder
{
/**
* Define the abstract target that depends on the context.
*
* @param string $abstract
* @return $this
*/
public function needs($abstract);
/**
* Define the implementation for the contextual binding.
*
* @param \Closure|string|array $implementation
* @return void
*/
public function give($implementation);
/**
* Define tagged services to be used as the implementation for the contextual binding.
*
* @param string $tag
* @return void
*/
public function giveTagged($tag);
/**
* Specify the configuration item to bind as a primitive.
*
* @param string $key
* @param mixed $default
* @return void
*/
public function giveConfig($key, $default = null);
}

View File

@@ -0,0 +1,47 @@
<?php
namespace Illuminate\Contracts\Cookie;
interface Factory
{
/**
* Create a new cookie instance.
*
* @param string $name
* @param string $value
* @param int $minutes
* @param string|null $path
* @param string|null $domain
* @param bool|null $secure
* @param bool $httpOnly
* @param bool $raw
* @param string|null $sameSite
* @return \Symfony\Component\HttpFoundation\Cookie
*/
public function make($name, $value, $minutes = 0, $path = null, $domain = null, $secure = null, $httpOnly = true, $raw = false, $sameSite = null);
/**
* Create a cookie that lasts "forever" (five years).
*
* @param string $name
* @param string $value
* @param string|null $path
* @param string|null $domain
* @param bool|null $secure
* @param bool $httpOnly
* @param bool $raw
* @param string|null $sameSite
* @return \Symfony\Component\HttpFoundation\Cookie
*/
public function forever($name, $value, $path = null, $domain = null, $secure = null, $httpOnly = true, $raw = false, $sameSite = null);
/**
* Expire the given cookie.
*
* @param string $name
* @param string|null $path
* @param string|null $domain
* @return \Symfony\Component\HttpFoundation\Cookie
*/
public function forget($name, $path = null, $domain = null);
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Illuminate\Contracts\Cookie;
interface QueueingFactory extends Factory
{
/**
* Queue a cookie to send with the next response.
*
* @param mixed ...$parameters
* @return void
*/
public function queue(...$parameters);
/**
* Remove a cookie from the queue.
*
* @param string $name
* @param string|null $path
* @return void
*/
public function unqueue($name, $path = null);
/**
* Get the cookies which have been queued for the next request.
*
* @return array
*/
public function getQueuedCookies();
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Illuminate\Contracts\Database\Eloquent;
use Illuminate\Contracts\Database\Query\Builder as BaseContract;
/**
* This interface is intentionally empty and exists to improve IDE support.
*
* @mixin \Illuminate\Database\Eloquent\Builder
*/
interface Builder extends BaseContract
{
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Illuminate\Contracts\Database\Eloquent;
interface Castable
{
/**
* Get the name of the caster class to use when casting from / to this cast target.
*
* @param array $arguments
* @return class-string<CastsAttributes|CastsInboundAttributes>|CastsAttributes|CastsInboundAttributes
*/
public static function castUsing(array $arguments);
}

View File

@@ -0,0 +1,32 @@
<?php
namespace Illuminate\Contracts\Database\Eloquent;
/**
* @template TGet
* @template TSet
*/
interface CastsAttributes
{
/**
* Transform the attribute from the underlying model values.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value
* @param array $attributes
* @return TGet|null
*/
public function get($model, string $key, $value, array $attributes);
/**
* Transform the attribute to its underlying model values.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param TSet|null $value
* @param array $attributes
* @return mixed
*/
public function set($model, string $key, $value, array $attributes);
}

View File

@@ -0,0 +1,17 @@
<?php
namespace Illuminate\Contracts\Database\Eloquent;
interface CastsInboundAttributes
{
/**
* Transform the attribute to its underlying model values.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value
* @param array $attributes
* @return mixed
*/
public function set($model, string $key, $value, array $attributes);
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Illuminate\Contracts\Database\Eloquent;
interface DeviatesCastableAttributes
{
/**
* Increment the attribute.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value
* @param array $attributes
* @return mixed
*/
public function increment($model, string $key, $value, array $attributes);
/**
* Decrement the attribute.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value
* @param array $attributes
* @return mixed
*/
public function decrement($model, string $key, $value, array $attributes);
}

View File

@@ -0,0 +1,17 @@
<?php
namespace Illuminate\Contracts\Database\Eloquent;
interface SerializesCastableAttributes
{
/**
* Serialize the attribute when converting the model to an array.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value
* @param array $attributes
* @return mixed
*/
public function serialize($model, string $key, $value, array $attributes);
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Illuminate\Contracts\Database\Eloquent;
interface SupportsPartialRelations
{
/**
* Indicate that the relation is a single result of a larger one-to-many relationship.
*
* @param string|null $column
* @param string|\Closure|null $aggregate
* @param string $relation
* @return $this
*/
public function ofMany($column = 'id', $aggregate = 'MAX', $relation = null);
/**
* Determine whether the relationship is a one-of-many relationship.
*
* @return bool
*/
public function isOneOfMany();
/**
* Get the one of many inner join subselect query builder instance.
*
* @return \Illuminate\Database\Eloquent\Builder|void
*/
public function getOneOfManySubQuery();
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Illuminate\Contracts\Database\Events;
interface MigrationEvent
{
//
}

View File

@@ -0,0 +1,73 @@
<?php
namespace Illuminate\Contracts\Database;
class ModelIdentifier
{
/**
* The class name of the model.
*
* @var string
*/
public $class;
/**
* The unique identifier of the model.
*
* This may be either a single ID or an array of IDs.
*
* @var mixed
*/
public $id;
/**
* The relationships loaded on the model.
*
* @var array
*/
public $relations;
/**
* The connection name of the model.
*
* @var string|null
*/
public $connection;
/**
* The class name of the model collection.
*
* @var string|null
*/
public $collectionClass;
/**
* Create a new model identifier.
*
* @param string $class
* @param mixed $id
* @param array $relations
* @param mixed $connection
* @return void
*/
public function __construct($class, $id, array $relations, $connection)
{
$this->id = $id;
$this->class = $class;
$this->relations = $relations;
$this->connection = $connection;
}
/**
* Specify the collection class that should be used when serializing / restoring collections.
*
* @param string|null $collectionClass
* @return $this
*/
public function useCollectionClass(?string $collectionClass)
{
$this->collectionClass = $collectionClass;
return $this;
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace Illuminate\Contracts\Database\Query;
/**
* This interface is intentionally empty and exists to improve IDE support.
*
* @mixin \Illuminate\Database\Query\Builder
*/
interface Builder
{
}

View File

@@ -0,0 +1,48 @@
<?php
namespace Illuminate\Contracts\Debug;
use Throwable;
interface ExceptionHandler
{
/**
* Report or log an exception.
*
* @param \Throwable $e
* @return void
*
* @throws \Throwable
*/
public function report(Throwable $e);
/**
* Determine if the exception should be reported.
*
* @param \Throwable $e
* @return bool
*/
public function shouldReport(Throwable $e);
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Throwable $e
* @return \Symfony\Component\HttpFoundation\Response
*
* @throws \Throwable
*/
public function render($request, Throwable $e);
/**
* Render an exception to the console.
*
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @param \Throwable $e
* @return void
*
* @internal This method is not meant to be used or overwritten outside the framework.
*/
public function renderForConsole($output, Throwable $e);
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Illuminate\Contracts\Encryption;
use RuntimeException;
class DecryptException extends RuntimeException
{
//
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Illuminate\Contracts\Encryption;
use RuntimeException;
class EncryptException extends RuntimeException
{
//
}

View File

@@ -0,0 +1,35 @@
<?php
namespace Illuminate\Contracts\Encryption;
interface Encrypter
{
/**
* Encrypt the given value.
*
* @param mixed $value
* @param bool $serialize
* @return string
*
* @throws \Illuminate\Contracts\Encryption\EncryptException
*/
public function encrypt($value, $serialize = true);
/**
* Decrypt the given value.
*
* @param string $payload
* @param bool $unserialize
* @return mixed
*
* @throws \Illuminate\Contracts\Encryption\DecryptException
*/
public function decrypt($payload, $unserialize = true);
/**
* Get the encryption key that the encrypter is currently using.
*
* @return string
*/
public function getKey();
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Illuminate\Contracts\Encryption;
interface StringEncrypter
{
/**
* Encrypt a string without serialization.
*
* @param string $value
* @return string
*
* @throws \Illuminate\Contracts\Encryption\EncryptException
*/
public function encryptString($value);
/**
* Decrypt the given string without unserialization.
*
* @param string $payload
* @return string
*
* @throws \Illuminate\Contracts\Encryption\DecryptException
*/
public function decryptString($payload);
}

View File

@@ -0,0 +1,82 @@
<?php
namespace Illuminate\Contracts\Events;
interface Dispatcher
{
/**
* Register an event listener with the dispatcher.
*
* @param \Closure|string|array $events
* @param \Closure|string|array|null $listener
* @return void
*/
public function listen($events, $listener = null);
/**
* Determine if a given event has listeners.
*
* @param string $eventName
* @return bool
*/
public function hasListeners($eventName);
/**
* Register an event subscriber with the dispatcher.
*
* @param object|string $subscriber
* @return void
*/
public function subscribe($subscriber);
/**
* Dispatch an event until the first non-null response is returned.
*
* @param string|object $event
* @param mixed $payload
* @return array|null
*/
public function until($event, $payload = []);
/**
* Dispatch an event and call the listeners.
*
* @param string|object $event
* @param mixed $payload
* @param bool $halt
* @return array|null
*/
public function dispatch($event, $payload = [], $halt = false);
/**
* Register an event and payload to be fired later.
*
* @param string $event
* @param array $payload
* @return void
*/
public function push($event, $payload = []);
/**
* Flush a set of pushed events.
*
* @param string $event
* @return void
*/
public function flush($event);
/**
* Remove a set of listeners from the dispatcher.
*
* @param string $event
* @return void
*/
public function forget($event);
/**
* Forget all of the queued listeners.
*
* @return void
*/
public function forgetPushed();
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Illuminate\Contracts\Filesystem;
interface Cloud extends Filesystem
{
/**
* Get the URL for the file at the given path.
*
* @param string $path
* @return string
*/
public function url($path);
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Illuminate\Contracts\Filesystem;
interface Factory
{
/**
* Get a filesystem implementation.
*
* @param string|null $name
* @return \Illuminate\Contracts\Filesystem\Filesystem
*/
public function disk($name = null);
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Illuminate\Contracts\Filesystem;
use Exception;
class FileNotFoundException extends Exception
{
//
}

View File

@@ -0,0 +1,191 @@
<?php
namespace Illuminate\Contracts\Filesystem;
interface Filesystem
{
/**
* The public visibility setting.
*
* @var string
*/
const VISIBILITY_PUBLIC = 'public';
/**
* The private visibility setting.
*
* @var string
*/
const VISIBILITY_PRIVATE = 'private';
/**
* Determine if a file exists.
*
* @param string $path
* @return bool
*/
public function exists($path);
/**
* Get the contents of a file.
*
* @param string $path
* @return string|null
*/
public function get($path);
/**
* Get a resource to read the file.
*
* @param string $path
* @return resource|null The path resource or null on failure.
*/
public function readStream($path);
/**
* Write the contents of a file.
*
* @param string $path
* @param string|resource $contents
* @param mixed $options
* @return bool
*/
public function put($path, $contents, $options = []);
/**
* Write a new file using a stream.
*
* @param string $path
* @param resource $resource
* @param array $options
* @return bool
*/
public function writeStream($path, $resource, array $options = []);
/**
* Get the visibility for the given path.
*
* @param string $path
* @return string
*/
public function getVisibility($path);
/**
* Set the visibility for the given path.
*
* @param string $path
* @param string $visibility
* @return bool
*/
public function setVisibility($path, $visibility);
/**
* Prepend to a file.
*
* @param string $path
* @param string $data
* @return bool
*/
public function prepend($path, $data);
/**
* Append to a file.
*
* @param string $path
* @param string $data
* @return bool
*/
public function append($path, $data);
/**
* Delete the file at a given path.
*
* @param string|array $paths
* @return bool
*/
public function delete($paths);
/**
* Copy a file to a new location.
*
* @param string $from
* @param string $to
* @return bool
*/
public function copy($from, $to);
/**
* Move a file to a new location.
*
* @param string $from
* @param string $to
* @return bool
*/
public function move($from, $to);
/**
* Get the file size of a given file.
*
* @param string $path
* @return int
*/
public function size($path);
/**
* Get the file's last modification time.
*
* @param string $path
* @return int
*/
public function lastModified($path);
/**
* Get an array of all files in a directory.
*
* @param string|null $directory
* @param bool $recursive
* @return array
*/
public function files($directory = null, $recursive = false);
/**
* Get all of the files from the given directory (recursive).
*
* @param string|null $directory
* @return array
*/
public function allFiles($directory = null);
/**
* Get all of the directories within a given directory.
*
* @param string|null $directory
* @param bool $recursive
* @return array
*/
public function directories($directory = null, $recursive = false);
/**
* Get all (recursive) of the directories within a given directory.
*
* @param string|null $directory
* @return array
*/
public function allDirectories($directory = null);
/**
* Create a directory.
*
* @param string $path
* @return bool
*/
public function makeDirectory($path);
/**
* Recursively delete a directory.
*
* @param string $directory
* @return bool
*/
public function deleteDirectory($directory);
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Illuminate\Contracts\Filesystem;
use Exception;
class LockTimeoutException extends Exception
{
//
}

View File

@@ -0,0 +1,231 @@
<?php
namespace Illuminate\Contracts\Foundation;
use Illuminate\Contracts\Container\Container;
interface Application extends Container
{
/**
* Get the version number of the application.
*
* @return string
*/
public function version();
/**
* Get the base path of the Laravel installation.
*
* @param string $path
* @return string
*/
public function basePath($path = '');
/**
* Get the path to the bootstrap directory.
*
* @param string $path
* @return string
*/
public function bootstrapPath($path = '');
/**
* Get the path to the application configuration files.
*
* @param string $path
* @return string
*/
public function configPath($path = '');
/**
* Get the path to the database directory.
*
* @param string $path
* @return string
*/
public function databasePath($path = '');
/**
* Get the path to the resources directory.
*
* @param string $path
* @return string
*/
public function resourcePath($path = '');
/**
* Get the path to the storage directory.
*
* @param string $path
* @return string
*/
public function storagePath($path = '');
/**
* Get or check the current application environment.
*
* @param string|array ...$environments
* @return string|bool
*/
public function environment(...$environments);
/**
* Determine if the application is running in the console.
*
* @return bool
*/
public function runningInConsole();
/**
* Determine if the application is running unit tests.
*
* @return bool
*/
public function runningUnitTests();
/**
* Get an instance of the maintenance mode manager implementation.
*
* @return \Illuminate\Contracts\Foundation\MaintenanceMode
*/
public function maintenanceMode();
/**
* Determine if the application is currently down for maintenance.
*
* @return bool
*/
public function isDownForMaintenance();
/**
* Register all of the configured providers.
*
* @return void
*/
public function registerConfiguredProviders();
/**
* Register a service provider with the application.
*
* @param \Illuminate\Support\ServiceProvider|string $provider
* @param bool $force
* @return \Illuminate\Support\ServiceProvider
*/
public function register($provider, $force = false);
/**
* Register a deferred provider and service.
*
* @param string $provider
* @param string|null $service
* @return void
*/
public function registerDeferredProvider($provider, $service = null);
/**
* Resolve a service provider instance from the class name.
*
* @param string $provider
* @return \Illuminate\Support\ServiceProvider
*/
public function resolveProvider($provider);
/**
* Boot the application's service providers.
*
* @return void
*/
public function boot();
/**
* Register a new boot listener.
*
* @param callable $callback
* @return void
*/
public function booting($callback);
/**
* Register a new "booted" listener.
*
* @param callable $callback
* @return void
*/
public function booted($callback);
/**
* Run the given array of bootstrap classes.
*
* @param array $bootstrappers
* @return void
*/
public function bootstrapWith(array $bootstrappers);
/**
* Get the current application locale.
*
* @return string
*/
public function getLocale();
/**
* Get the application namespace.
*
* @return string
*
* @throws \RuntimeException
*/
public function getNamespace();
/**
* Get the registered service provider instances if any exist.
*
* @param \Illuminate\Support\ServiceProvider|string $provider
* @return array
*/
public function getProviders($provider);
/**
* Determine if the application has been bootstrapped before.
*
* @return bool
*/
public function hasBeenBootstrapped();
/**
* Load and boot all of the remaining deferred providers.
*
* @return void
*/
public function loadDeferredProviders();
/**
* Set the current application locale.
*
* @param string $locale
* @return void
*/
public function setLocale($locale);
/**
* Determine if middleware has been disabled for the application.
*
* @return bool
*/
public function shouldSkipMiddleware();
/**
* Register a terminating callback with the application.
*
* @param callable|string $callback
* @return \Illuminate\Contracts\Foundation\Application
*/
public function terminating($callback);
/**
* Terminate the application.
*
* @return void
*/
public function terminate();
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Illuminate\Contracts\Foundation;
interface CachesConfiguration
{
/**
* Determine if the application configuration is cached.
*
* @return bool
*/
public function configurationIsCached();
/**
* Get the path to the configuration cache file.
*
* @return string
*/
public function getCachedConfigPath();
/**
* Get the path to the cached services.php file.
*
* @return string
*/
public function getCachedServicesPath();
}

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