This commit is contained in:
Gitea
2022-01-24 10:43:35 +08:00
commit 15dfc6576b
786 changed files with 219240 additions and 0 deletions

214
core/basic/Basic.php Normal file
View File

@@ -0,0 +1,214 @@
<?php
/**
* @copyright (C)2016-2099 Hnaoyun Inc.
* @author XingMeng
* @email hnxsh@foxmail.com
* @date 2017年11月4日
* 系统基础类
*/
namespace core\basic;
class Basic
{
protected static $models = array();
// 实现类文件自动加载
public static function autoLoad($className)
{
if (substr($className, 0, 4) == 'core') { // 框架类文件命名空间转换
$class_file = CORE_PATH . '/' . str_replace('\\', '/', substr($className, 5)) . '.php';
} elseif (substr($className, 0, 3) == 'app') { // 应用类文件命名空间转换
$class_file = APP_PATH . '/' . str_replace('\\', '/', substr($className, 4)) . '.php';
} elseif (strpos($className, '\\')) { // 如果带有命名空间,使用全路径载入
$class_file = ROOT_PATH . '/' . str_replace('\\', '/', $className) . '.php';
} else { // 默认载入内核基础目录下文件
$class_file = CORE_PATH . '/basic/' . $className . '.php';
}
if (! file_exists($class_file)) {
error('自动加载类文件时发生错误,类名【' . $className . '】,文件:【' . $class_file . '】');
}
require $class_file;
}
// 自定义错误函数
public static function errorHandler($errno, $errstr, $errfile, $errline)
{
if (! (error_reporting() & $errno)) {
// 如果这个错误类型没有包含在error_reporting里如加了@的错误则不报告
return;
}
switch ($errno) {
case E_ERROR:
$err_level = 'ERROR';
break;
case E_WARNING:
$err_level = 'WARNING';
break;
case E_PARSE:
$err_level = 'PARSE';
break;
case E_NOTICE:
$err_level = 'NOTICE';
break;
case E_RECOVERABLE_ERROR:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_USER_ERROR:
$err_level = 'FATAL ERROR';
break;
default:
$err_level = 'UNKNOW';
break;
}
$info = "<h3>$err_level:</h3>\n";
$info .= "<p><b>Code:</b> $errno;</p>\n";
$info .= "<p><b>Desc:</b> $errstr;</p>\n";
$info .= "<p><b>File:</b> $errfile;</p>\n";
$info .= "<p><b>Line:</b> $errline;</p>\n";
if ($err_level == 'WARNING' || $err_level == 'NOTICE') {
echo $info;
} else {
error($info);
}
}
// 异常捕获
public static function exceptionHandler($exception)
{
error("程序运行异常: " . $exception->getMessage() . ",位置:" . $exception->getFile() . ',第' . $exception->getLine() . '行。');
}
// 致命错误捕获
public static function shutdownFunction()
{
$error = error_get_last();
define('E_FATAL', E_ERROR | E_RECOVERABLE_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR);
if ($error && ($error["type"] === ($error["type"] & E_FATAL))) {
$errno = $error["type"];
$errstr = $error["message"];
$errfile = $error["file"];
$errline = $error["line"];
self::errorHandler($errno, $errstr, $errfile, $errline);
}
}
// 会话处理程序设置
public static function setSessionHandler()
{
if (ini_get('session.auto_start')) {
return;
}
// 配置会话安全参数
session_name('PbootSystem');
ini_set("session.use_trans_sid", 0);
ini_set("session.use_cookies", 1);
ini_set("session.use_only_cookies", 1);
session_set_cookie_params(0, SITE_DIR . '/', null, null, true);
switch (Config::get('session.handler')) {
case 'memcache':
if (! extension_loaded('memcache'))
error('PHP运行环境未安装memcache.dll扩展');
ini_set("session.save_handler", "memcache");
ini_set("session.save_path", Config::get('seesion.path'));
break;
default:
if (Config::get('session_in_sitepath')) {
$save_path = RUN_PATH . '/session/';
if (! check_dir($save_path, true))
error('设置的会话目录创建失败!' . $save_path);
ini_set("session.save_handler", "files");
$depth = 1;
ini_set("session.save_path", $depth . ';' . $save_path);
if (! is_dir($save_path . '/0/0') || ! is_dir($save_path . '/v/v')) {
create_session_dir($save_path, $depth);
}
}
break;
}
}
// 实例化模型
public static function createModel($name = null, $new = false)
{
// 自动同名模型控制器
if (! $name)
$name = C;
// 获取类名
if (strpos($name, '.') !== false) {
$path = explode('.', $name);
$class_name = '\\app\\' . $path[0] . '\\model';
$len = count($path);
for ($i = 1; $i < $len - 1; $i ++) {
$class_name .= '\\' . $path[$i];
}
$class_name .= '\\' . ucfirst($path[$i]) . 'Model';
} else {
$class_name = '\\app\\' . M . '\\model\\' . ucfirst($name) . 'Model';
}
// 根据需要实例化
$key = md5($class_name);
if (! isset(self::$models[$key]) || $new) {
self::$models[$key] = new $class_name();
}
return self::$models[$key];
}
// 创建数据接口
public static function createApi($args = null)
{
// 直接调用方式
if (! is_array($args)) {
$args = func_get_args();
}
// 分离参数
$name = $args[0];
unset($args[0]);
$param = $args;
// 如果只是传递了方法,则自动完善模块及模型控制器
if (strpos($name, '.') === false) {
$name = M . '.' . C . '.' . $name;
}
$path = explode('.', $name); // 第一个为模块 $path[0],倒数第二个为模型$path[$i],倒数第一个为方法$path[$i+1]
$class_name = '\\app\\' . $path[0] . '\\model';
$len = count($path);
for ($i = 1; $i < $len - 2; $i ++) {
$class_name .= '\\' . $path[$i];
}
$class_name .= '\\' . ucfirst($path[$i]) . 'Model';
$key = md5($class_name);
if (isset(self::$models[$key])) {
$model = self::$models[$key];
} else {
$model = new $class_name();
self::$models[$key] = $model;
}
// 调取接口方法
if (is_array($param)) {
$rs = call_user_func_array(array(
$model,
$path[$i + 1]
), $param);
}
// 返回结果,如果不是json数据则转换
if (! ! $return = json_decode($rs)) {
return $rs;
} else {
return json_encode($rs);
}
}
}

57
core/basic/Cache.php Normal file
View File

@@ -0,0 +1,57 @@
<?php
/**
* @copyright (C)2016-2099 Hnaoyun Inc.
* @author XingMeng
* @email hnxsh@foxmail.com
* @date 2017年10月24日
* 缓存统一调用类
*/
namespace core\basic;
use core\basic\Config;
use core\cache\Memcache;
class Cache
{
// 获取缓存实例
protected static function getCacheInstance()
{
switch (Config::get('cache.handler')) {
case 'memcache':
$instance = Memcache::getInstance();
break;
default:
$instance = Memcache::getInstance();
}
return $instance;
}
// 写入缓存
public static function set($key, $value)
{
$cache = self::getCacheInstance();
return $cache->set($key, $value);
}
// 读取缓存
public static function get($key)
{
$cache = self::getCacheInstance();
return $cache->get($key);
}
// 删除缓存
public static function delete($key)
{
$cache = self::getCacheInstance();
return $cache->delete($key);
}
// 清理缓存
public static function flush()
{
$cache = self::getCacheInstance();
return $cache->flush();
}
}

137
core/basic/Check.php Normal file
View File

@@ -0,0 +1,137 @@
<?php
/**
* @copyright (C)2016-2099 Hnaoyun Inc.
* @author XingMeng
* @email hnxsh@foxmail.com
* @date 2016年11月6日
* 系统环境检查类
*/
namespace core\basic;
use core\basic\Config;
class Check
{
// 启动应用检查
public static function checkApp()
{
if (! is_dir(APP_PATH)) {
error('您的系统文件无法正常读取,请检查是否上传完整!');
}
// 判断自动转换状态
if (function_exists("get_magic_quotes_gpc") && get_magic_quotes_gpc()) {
error('您的服务器环境PHP.ini中magic_quotes_gpc配置为On状态会导致数据存储异常请设置为Off状态或切换为更高版本PHP。');
}
// 判断目录列表函数
if (! function_exists('scandir')) {
error('您的服务器环境PHP.ini配置中已经禁用scandir函数会导致无法正常读取配置及模板文件请先去除。');
}
// 检查gd扩展
if (! extension_loaded('gd')) {
error('您的服务器环境不支持gd扩展,将无法使用验证码!');
}
// 检查mbstring扩展
if (! extension_loaded('mbstring')) {
error('您的服务器环境不支持mbstring扩展请先安装并启用');
}
// 检查curl扩展
if (! extension_loaded('curl')) {
error('您的服务器环境不支持curl扩展请先安装并启用');
}
}
// 检查PHP版本
public static function checkPHP()
{
if (PHP_VERSION < '5.3') {
error('您服务器的PHP版本太低本程序要求版本不小于 5.3');
}
}
// 检查mysqli扩展库
public static function checkMysqli()
{
if (! extension_loaded('mysqli')) {
error('您的服务器环境不支持mysqli扩展,将无法正常使用数据库!');
}
}
// 检查curl扩展库
public static function checkCurl()
{
if (! extension_loaded('curl')) {
error('您的服务器环境不支持curl扩展,将无法使用API模式');
}
}
// 目录路径检查,不存在时根据配置文件选择是否自动创建
public static function checkBasicDir()
{
if (Config::get('debug')) {
check_dir(APP_PATH, true);
check_dir(APP_PATH . '/common', true);
check_dir(CONF_PATH, true);
}
// 目录权限判断
if (! check_dir(RUN_PATH, true)) {
error('缓存目录创建失败,可能写入权限不足!' . RUN_PATH);
}
if (! check_dir(DOC_PATH . STATIC_DIR . '/upload', true)) {
error('上传目录创建失败,可能写入权限不足!' . DOC_PATH . STATIC_DIR . '/upload');
}
}
// 检查系统默认首页的文件是否存在,不存在进行自动创建
public static function checkAppFile()
{
$apps = Config::get('public_app', true);
check_dir(APP_CONTROLLER_PATH, true);
check_file(CONF_PATH . '/config.php', true, "<?php \r\n return array(\r\n\t //'控制项'=>'值' 以分号,分割\r\n);");
check_file(APP_CONTROLLER_PATH . '/IndexController.php', true, "<?php \r\r namespace app\\" . M . "\\controller;\r\r use core\\basic\\Controller; \r\r class IndexController extends Controller{\r\r\tpublic function index(){\r\t\t\$this->display('index.html');\r\t} \r\r}");
check_file(APP_PATH . '/common/' . ucfirst(M) . 'Controller.php', true, "<?php \r\rnamespace app\\common;\r\ruse core\\basic\\Controller; \r\rclass " . ucfirst(M) . "Controller extends Controller{ \r\r}");
// check_file(APP_PATH . '/common/' . ucfirst(M) . 'Model.php', true, "<?php \r\rnamespace app\\common;\r\ruse core\\basic\\Model; \r\rclass " . ucfirst(M) . "Model extends Model{ \r\r}");
}
// 检查客户端浏览器是否被允许,在同时设置黑白名单时,黑名单具有优先级更高,在设置了白名单时,将只允许白名单访问
public static function checkBs()
{
$allow_bs = Config::get('access_rule.allow_bs', true);
$deny_bs = Config::get('access_rule.deny_bs', true);
// 都未设置时,直接通过
if (! $allow_bs && ! $deny_bs)
return true;
// 客户端使用的系统
$user_bs = get_user_bs();
// 如果在黑名单则直接拒绝
if (in_array($user_bs, $deny_bs)) {
error('本站点设置了不允许' . $user_bs . '内核浏览器访问,请使用其它版本IE、火狐、谷歌等国产浏览器请使用极速模式');
} elseif ($allow_bs && ! in_array($user_bs, $allow_bs)) {
error('本站点设置了只允许' . implode(',', $allow_bs) . '内核浏览器访问,请使用这些浏览器!');
}
}
// 检查客户端操作系统是否被允许,在同时设置黑白名单时,黑名单具有优先级更高,在设置了白名单时,将只允许白名单访问
public static function checkOs()
{
$allow_os = Config::get('access_rule.allow_os', true);
$deny_os = Config::get('access_rule.deny_os', true);
// 都未设置时,直接通过
if (! $allow_os && ! $deny_os)
return true;
// 客户端使用的系统
$user_os = get_user_os();
// 如果在黑名单则直接拒绝
if (in_array($user_os, $deny_os)) {
error('本站点设置了不允许' . $user_os . '访问,请使用其它操作系统!');
} elseif ($allow_os && ! in_array($user_os, $allow_os)) {
error('本站点设置了只允许' . implode(',', $allow_os) . '访问,请使用这些操作系统!');
}
}
}

174
core/basic/Config.php Normal file
View File

@@ -0,0 +1,174 @@
<?php
/**
* @copyright (C)2016-2099 Hnaoyun Inc.
* @author XingMeng
* @email hnxsh@foxmail.com
* @date 2017年10月15日
* 配置信息读取类
*/
namespace core\basic;
class Config
{
// 存储配置信息
protected static $configs;
// 直接获取配置参数
public static function get($item = null, $array = false)
{
// 自动载入配置文件
if (! isset(self::$configs)) {
self::$configs = self::loadConfig();
}
// 返回全部配置
if ($item === null) {
return self::$configs;
}
$items = explode('.', $item);
if (isset(self::$configs[$items[0]])) {
$value = self::$configs[$items[0]];
} else {
return null;
}
$items_len = count($items);
for ($i = 1; $i < $items_len; $i ++) {
if (isset($value[$items[$i]])) {
$value = $value[$items[$i]];
} else {
return null;
}
}
// 强制返回数据为数组形式
if ($array && ! is_array($value)) {
if ($value) {
$value = explode(',', $value);
$value = array_map('trim', $value); // 去空格
} else {
$value = array();
}
}
return $value;
}
// 写入配置文件
public static function set($itemName, array $data, $multistage = false, $assign = true)
{
if ($data) {
$path = RUN_PATH . '/config/' . $itemName . '.php';
// 是否使用多级
if ($multistage) {
// 如果获取到配置信息,执行合并
if (! ! $configs = self::get($itemName)) {
$data = mult_array_merge($configs, $data);
}
$config[$itemName] = $data;
} else {
$config = $data;
}
// 写入
if (check_file($path, true)) {
$result = file_put_contents($path, "<?php\nreturn " . var_export($config, true) . ";");
if ($assign) { // 缓存后是否注入配置
self::assign($path);
}
return $result;
} else {
return false;
}
}
}
// 载入配置文件
private static function loadConfig()
{
// 载入配置惯性文件
if (file_exists(CORE_PATH . '/convention.php')) {
$configs = require CORE_PATH . '/convention.php';
} else {
die('系统框架文件丢失,惯性配置文件不存在!');
}
// 载入用户主配置文件
if (file_exists(CONF_PATH . '/config.php')) {
$config = require CONF_PATH . '/config.php';
$configs = mult_array_merge($configs, $config);
}
// 载入用户数据库配置文件
if (file_exists(CONF_PATH . '/database.php')) {
$config = require CONF_PATH . '/database.php';
$configs = mult_array_merge($configs, $config);
}
// 载入用户路由配置文件
if (file_exists(CONF_PATH . '/route.php')) {
$config = require CONF_PATH . '/route.php';
$configs = mult_array_merge($configs, $config);
}
// 载入扩展的配置文件
$ext_path = CONF_PATH . '/ext';
if (is_dir($ext_path) && function_exists('scandir')) {
$files = scandir($ext_path);
for ($i = 0; $i < count($files); $i ++) {
$file = $ext_path . '/' . $files[$i];
if (is_file($file)) {
$config = require $file;
$configs = mult_array_merge($configs, $config);
}
}
}
// 载入系统路由文件
if (file_exists(APP_PATH . '/common/route.php')) {
$config = require APP_PATH . '/common/route.php';
$configs = mult_array_merge($configs, $config);
}
// 载入应用版本文件
if (file_exists(APP_PATH . '/common/version.php')) {
$config = require APP_PATH . '/common/version.php';
$configs = mult_array_merge($configs, $config);
}
// 载入系统配置缓存
if (file_exists(RUN_PATH . '/config/' . md5('config') . '.php')) {
$config = require RUN_PATH . '/config/' . md5('config') . '.php';
$configs = mult_array_merge($configs, $config);
}
// 载入区域配置缓存
if (file_exists(RUN_PATH . '/config/' . md5('area') . '.php')) {
$config = require RUN_PATH . '/config/' . md5('area') . '.php';
$configs = mult_array_merge($configs, $config);
}
// 清理缓冲区避免配置文件出现Bom时影响显示
@ob_clean();
return $configs;
}
// 配置文件注入
public static function assign($filePath)
{
if (! file_exists($filePath)) {
return;
}
$assign_config = require $filePath;
if (! is_array($assign_config))
return;
if (self::$configs) {
$configs = mult_array_merge(self::$configs, $assign_config);
} else {
$configs = $assign_config;
}
self::$configs = $configs;
return true;
}
}

117
core/basic/Controller.php Normal file
View File

@@ -0,0 +1,117 @@
<?php
/**
* @copyright (C)2016-2099 Hnaoyun Inc.
* @author XingMeng
* @email hnxsh@foxmail.com
* @date 2016年11月6日
* 应用控制基类
*/
namespace core\basic;
use core\view\View;
use core\view\Paging;
class Controller
{
// 显示模板
final protected function display($file)
{
$view = View::getInstance();
$content = $view->parser($file);
$content = $this->runtime($content);
echo $this->gzip($content);
exit();
}
// 解析模板
final protected function parser($file)
{
$view = View::getInstance();
return $view->parser($file);
}
// 缓存页面内容,默认直接显示内容可传递第二参数false返回内容
final protected function cache($content, $display = true)
{
$view = View::getInstance();
if (Config::get('tpl_html_cache')) {
$content = str_replace('{pboot:runtime}', 'Cached at ' . date('Y-m-d H:i:s'), $content);
} else {
$content = $this->runtime($content);
}
$view->cache($content); // 压缩前缓存
$content = $this->gzip($content);
if ($display) {
echo $content;
exit();
} else {
return $content;
}
}
// 设置视图主题
final protected function setTheme($themeName)
{
$view = View::getInstance();
$view->assign('theme', $themeName);
}
// 变量注入接口
final protected function assign($var, $value)
{
$view = View::getInstance();
$view->assign($var, $value);
}
// 变量获取接口
final protected function getVar($var)
{
$view = View::getInstance();
return $view->getVar($var);
}
// 手动生成分页信息,返回限制语句
final protected function page($tatal, $morePageStr = false)
{
$page = Paging::getInstance();
return $page->limit($tatal, $morePageStr);
}
// 获取配置信息
final protected function config($item = null, $array = false)
{
return Config::get($item, $array);
}
// 缓存配置信息
final protected function setConfig($itemName, array $data)
{
return Config::set($itemName, $data);
}
// 写入日志信息
final protected function log($content, $level = "info")
{
Log::write($content, $level);
}
// 解析运行时间标签
private function runtime($content)
{
return str_replace('{pboot:runtime}', 'Processed in ' . round(microtime(true) - START_TIME, 6) . ' second(s).', $content);
}
// 压缩内容
private function gzip($content)
{
if (Config::get('gzip') && ! headers_sent() && extension_loaded("zlib") && strstr($_SERVER["HTTP_ACCEPT_ENCODING"], "gzip")) {
$content = gzencode($content, 6);
header("Content-Encoding: gzip");
header("Vary: Accept-Encoding");
header("Content-Length: " . strlen($content));
}
return $content;
}
}

37
core/basic/Db.php Normal file
View File

@@ -0,0 +1,37 @@
<?php
/**
* @copyright (C)2016-2099 Hnaoyun Inc.
* @author XingMeng
* @email hnxsh@foxmail.com
* @date 2017年11月1日
* 数据库快速操作类
*/
namespace core\basic;
use core\basic\Model;
class Db
{
// 对象方式动态调用数据库操作方法
public function __call($methed, $args)
{
$model = new Model();
$result = call_user_func_array(array(
$model,
$methed
), $args);
return $result;
}
// 静态方式动态调用数据库操作方法
public static function __callstatic($methed, $args)
{
$model = new Model();
$result = call_user_func_array(array(
$model,
$methed
), $args);
return $result;
}
}

10
core/basic/Kernel.php Normal file

File diff suppressed because one or more lines are too long

70
core/basic/Log.php Normal file
View File

@@ -0,0 +1,70 @@
<?php
/**
* @copyright (C)2016-2099 Hnaoyun Inc.
* @author XingMeng
* @email hnxsh@foxmail.com
* @date 2017年10月24日
* 日志统一调用类
*/
namespace core\basic;
use core\log\LogText;
use core\log\LogDb;
class Log
{
// 获取缓存实例
protected static function getLogInstance()
{
switch (Config::get('log_record_type')) {
case 'text':
$instance = LogText::getInstance();
break;
case 'db':
$instance = LogDb::getInstance();
break;
default:
$instance = LogText::getInstance();
}
return $instance;
}
/**
* 日志写入
*
* @param string $content
* 日志内容
* @param string $level
* 内容级别
*/
public static function write($content, $level = "info", $username = null)
{
$log = self::getLogInstance();
$log->write($content, $level, $username);
}
/**
* 错误日志快速写入error级别
*
* @param string $content
* 日志内容
*/
public static function error($content)
{
$log = self::getLogInstance();
$log->error($content);
}
/**
* 基础日志快速写入, info级别
*
* @param string $content
* 日志内容
*/
public static function info($content)
{
$log = self::getLogInstance();
$log->info($content);
}
}

1435
core/basic/Model.php Normal file

File diff suppressed because it is too large Load Diff

56
core/basic/Response.php Normal file
View File

@@ -0,0 +1,56 @@
<?php
/**
* @copyright (C)2016-2099 Hnaoyun Inc.
* @author XingMeng
* @email hnxsh@foxmail.com
* @date 2017年11月5日
* 内容输出类
*/
namespace core\basic;
class Response
{
// 根据配置文件选择
public static function handle($data)
{
if (Config::get('return_data_type') == 'html') {
print_r($data);
} else {
if (array_key_exists('code', $data)) {
$code = $data['code'];
unset($data['code']);
self::json($code, $data);
} else {
self::json(1, $data);
}
}
}
// 服务端API返回JSON数据
public static function json($code, $data, $tourl = null)
{
@ob_clean();
$output['code'] = $code ?: 0;
$output['data'] = $data ?: array();
$output['tourl'] = $tourl ?: "";
if (defined('ROWTOTAL')) {
$output['rowtotal'] = ROWTOTAL;
} else {
if (is_array($data) || is_object($data)) {
$output['rowtotal'] = count($data);
} else {
$output['rowtotal'] = 1;
}
}
if (PHP_VERSION >= 5.4) { // 中文不编码 5.4+
$option = JSON_UNESCAPED_UNICODE;
} else {
$option = JSON_HEX_TAG;
}
echo json_encode($output, $option);
exit();
}
}

545
core/basic/Smtp.php Normal file
View File

@@ -0,0 +1,545 @@
<?php
/**
* @copyright (C)2016-2099 Hnaoyun Inc.
* @author XingMeng
* @email hnxsh@foxmail.com
* @date 2018年3月21日
* 邮件发送类
*/
namespace core\basic;
class Smtp
{
// 邮件传输代理服务器地址
protected $sendServer;
// 邮件传输代理服务器端口
protected $port;
// 是否是安全连接
protected $isSecurity;
// 邮件传输代理用户名
protected $userName;
// 邮件传输代理密码
protected $password;
// 发件人
protected $from;
// 收件人
protected $to = array();
// 抄送
protected $cc = array();
// 秘密抄送
protected $bcc = array();
// 主题
protected $subject;
// 邮件正文
protected $body;
// 附件
protected $attachment = array();
// 调试模式
protected $debug;
// 错误信息
protected $errorMessage;
// 资源句柄
protected $socket;
/**
* 设置邮件传输代理,默认为安全链接
*
* @param string $server
* 代理服务器的ip或者域名
* @param string $username
* 认证账号
* @param string $password
* 认证密码
* @param int $port
* 代理服务器的端口smtp默认25号端口
* @param boolean $isSecurity
* 到服务器的连接是否为安全连接默认false
* @return boolean
*/
public function __construct($server = "", $username = "", $password = "", $port = 465, $isSecurity = true, $debug = false)
{
if ($server) {
$this->sendServer = $server;
$this->port = $port;
$this->isSecurity = $isSecurity ? true : false;
$this->debug = $debug;
$this->userName = empty($username) ? "" : base64_encode($username);
$this->password = empty($password) ? "" : base64_encode($password);
$this->from = $username;
} else {
$smtp = Config::get();
$this->sendServer = $smtp['smtp_server'];
$this->port = $smtp['smtp_port'];
$this->isSecurity = $smtp['smtp_ssl'] ? true : false;
$this->debug = $debug;
$this->userName = base64_encode($smtp['smtp_username']);
$this->password = base64_encode($smtp['smtp_password']);
$this->from = $smtp['smtp_username'];
}
return true;
}
/**
* 设置收件人,多个收件人,调用多次或用逗号隔开.
*
* @param string $to
* 收件人地址
* @return boolean
*/
public function setReceiver($to)
{
if (strpos($to, ',')) {
$this->to = explode(',', $to);
} else {
$this->to[] = $to;
}
return true;
}
/**
* 设置抄送,多个抄送,调用多次或用逗号隔开.
*
* @param string $cc
* 抄送地址
* @return boolean
*/
public function setCc($cc)
{
if (strpos($cc, ',')) {
$this->cc = explode(',', $cc);
} else {
$this->cc[] = $cc;
}
return true;
}
/**
* 设置秘密抄送,多个秘密抄送,调用多次或用逗号隔开.
*
* @param string $bcc
* 秘密抄送地址
* @return boolean
*/
public function setBcc($bcc)
{
if (strpos($bcc, ',')) {
$this->bcc = explode(',', $bcc);
} else {
$this->bcc[] = $bcc;
}
return true;
}
/**
* 设置邮件附件,多个附件,调用多次
*
* @param string $file
* 文件地址
* @return boolean
*/
public function addAttachment($file)
{
if (! file_exists($file)) {
$this->errorMessage = "file " . $file . " does not exist.";
return false;
}
$this->attachment[] = $file;
return true;
}
/**
* 设置邮件信息
*
* @param string $body
* 邮件主题
* @param string $subject
* 邮件主体内容可以是纯文本也可是是HTML文本
* @return boolean
*/
public function setMail($subject, $body)
{
$this->subject = base64_encode($subject);
$this->body = base64_encode($body);
return true;
}
/**
* 发送邮件
*
* @return boolean
*/
public function sendMail($to = '', $subject = '', $body = '')
{
if ($to) {
$this->setReceiver($to);
$this->setMail($subject, $body);
}
$command = $this->getCommand();
if (! $this->socket($this->isSecurity)) {
return false;
}
foreach ($command as $value) {
$result = $this->sendCommand($value[0], $value[1]);
if ($result) {
continue;
} else {
return false;
}
}
// 关闭连接
$this->close();
return true;
}
/**
* 返回错误信息
*
* @return string
*/
public function error()
{
if (! isset($this->errorMessage)) {
$this->errorMessage = "";
}
return $this->errorMessage;
}
/**
* 返回mail命令
*
* @access protected
* @return array
*/
protected function getCommand()
{
$separator = "----=_Part_" . md5($this->from . time()) . uniqid(); // 分隔符
$command = array(
array(
"HELO sendmail\r\n",
250
)
);
if (! empty($this->userName)) {
$command[] = array(
"AUTH LOGIN\r\n",
334
);
$command[] = array(
$this->userName . "\r\n",
334
);
$command[] = array(
$this->password . "\r\n",
235
);
}
// 设置发件人
$command[] = array(
"MAIL FROM: <" . $this->from . ">\r\n",
250
);
$header = "FROM: <" . $this->from . ">\r\n";
// 设置收件人
if (! empty($this->to)) {
$count = count($this->to);
if ($count == 1) {
$command[] = array(
"RCPT TO: <" . $this->to[0] . ">\r\n",
250
);
$header .= "TO: <" . $this->to[0] . ">\r\n";
} else {
for ($i = 0; $i < $count; $i ++) {
$command[] = array(
"RCPT TO: <" . $this->to[$i] . ">\r\n",
250
);
if ($i == 0) {
$header .= "TO: <" . $this->to[$i] . ">";
} elseif ($i + 1 == $count) {
$header .= ",<" . $this->to[$i] . ">\r\n";
} else {
$header .= ",<" . $this->to[$i] . ">";
}
}
}
}
// 设置抄送
if (! empty($this->cc)) {
$count = count($this->cc);
if ($count == 1) {
$command[] = array(
"RCPT TO: <" . $this->cc[0] . ">\r\n",
250
);
$header .= "CC: <" . $this->cc[0] . ">\r\n";
} else {
for ($i = 0; $i < $count; $i ++) {
$command[] = array(
"RCPT TO: <" . $this->cc[$i] . ">\r\n",
250
);
if ($i == 0) {
$header .= "CC: <" . $this->cc[$i] . ">";
} elseif ($i + 1 == $count) {
$header .= ",<" . $this->cc[$i] . ">\r\n";
} else {
$header .= ",<" . $this->cc[$i] . ">";
}
}
}
}
// 设置秘密抄送
if (! empty($this->bcc)) {
$count = count($this->bcc);
if ($count == 1) {
$command[] = array(
"RCPT TO: <" . $this->bcc[0] . ">\r\n",
250
);
$header .= "BCC: <" . $this->bcc[0] . ">\r\n";
} else {
for ($i = 0; $i < $count; $i ++) {
$command[] = array(
"RCPT TO: <" . $this->bcc[$i] . ">\r\n",
250
);
if ($i == 0) {
$header .= "BCC: <" . $this->bcc[$i] . ">";
} elseif ($i + 1 == $count) {
$header .= ",<" . $this->bcc[$i] . ">\r\n";
} else {
$header .= ",<" . $this->bcc[$i] . ">";
}
}
}
}
// 主题
$header .= "Subject: =?UTF-8?B?" . $this->subject . "?=\r\n";
if (isset($this->attachment)) {
// 含有附件的邮件头需要声明成这个
$header .= "Content-Type: multipart/mixed;\r\n";
} elseif (false) {
// 邮件体含有图片资源的,且包含的图片在邮件内部时声明成这个,如果是引用的远程图片,就不需要了
$header .= "Content-Type: multipart/related;\r\n";
} else {
// html或者纯文本的邮件声明成这个
$header .= "Content-Type: multipart/alternative;\r\n";
}
// 邮件头分隔符
$header .= "\t" . 'boundary="' . $separator . '"';
$header .= "\r\nMIME-Version: 1.0\r\n";
// 这里开始是邮件的body部分body部分分成几段发送
$header .= "\r\n--" . $separator . "\r\n";
$header .= "Content-Type:text/html; charset=utf-8\r\n";
$header .= "Content-Transfer-Encoding: base64\r\n\r\n";
$header .= $this->body . "\r\n";
$header .= "--" . $separator . "\r\n";
// 加入附件
if (! empty($this->attachment)) {
$count = count($this->attachment);
for ($i = 0; $i < $count; $i ++) {
$header .= "\r\n--" . $separator . "\r\n";
$header .= "Content-Type: " . $this->getMIMEType($this->attachment[$i]) . '; name="=?UTF-8?B?' . base64_encode(basename($this->attachment[$i])) . '?="' . "\r\n";
$header .= "Content-Transfer-Encoding: base64\r\n";
$header .= 'Content-Disposition: attachment; filename="=?UTF-8?B?' . base64_encode(basename($this->attachment[$i])) . '?="' . "\r\n";
$header .= "\r\n";
$header .= $this->readFile($this->attachment[$i]);
$header .= "\r\n--" . $separator . "\r\n";
}
}
// 结束邮件数据发送
$header .= "\r\n.\r\n";
$command[] = array(
"DATA\r\n",
354
);
$command[] = array(
$header,
250
);
$command[] = array(
"QUIT\r\n",
221
);
return $command;
}
/**
* 发送命令
*
* @param string $command
* 发送到服务器的smtp命令
* @param int $code
* 期望服务器返回的响应吗
* @return boolean
*/
protected function sendCommand($command, $code)
{
if ($this->debug) {
echo 'Send command:' . $command . ',expected code:' . $code . '<br />';
}
try {
if (fwrite($this->socket, $command)) {
// 当邮件内容分多次发送时,没有$code服务器没有返回
if (empty($code)) {
return true;
}
// 读取服务器返回
$data = trim(fread($this->socket, 1024));
if (! mb_check_encoding($data, 'utf-8')) {
$data = iconv('gbk', 'utf-8', $data);
}
if ($this->debug) {
echo 'response:' . $data . '<br /><br />';
}
if ($data) {
$pattern = "/^" . $code . "+?/";
if (preg_match($pattern, $data)) {
return true;
} else {
$this->errorMessage = $data;
return false;
}
} else {
return false;
}
} else {
$this->errorMessage = "Error: " . $command . " send failed";
return false;
}
} catch (\Exception $e) {
$this->errorMessage = "Error:" . $e->getMessage();
}
}
/**
* 读取附件文件内容返回base64编码后的文件内容
*
* @param string $file
* 文件
* @return mixed
*/
protected function readFile($file)
{
if (file_exists($file)) {
$file_obj = file_get_contents($file);
return base64_encode($file_obj);
} else {
$this->errorMessage = "file " . $file . " dose not exist";
return false;
}
}
/**
* 获取附件MIME类型
*
* @param string $file
* 文件
* @return mixed
*/
protected function getMIMEType($file)
{
if (file_exists($file)) {
$mime = mime_content_type($file);
return $mime;
} else {
return false;
}
}
/**
* 建立到服务器的网络连接
*
* @return boolean
*/
protected function socket($ssl = true)
{
if ($ssl && ! extension_loaded('openssl')) {
$this->errorMessage = '服务器未启用openssl扩展无法使用加密方式发送邮件';
return false;
}
if (function_exists('stream_socket_client')) {
if (! function_exists('stream_socket_enable_crypto')) {
$this->errorMessage = '服务器已经禁用stream_socket_enable_crypto函数无法发送邮件';
return false;
}
if (! function_exists('stream_set_blocking')) {
$this->errorMessage = '服务器已经禁用stream_set_blocking函数无法发送邮件';
return false;
}
// 建立连接
$remoteAddr = "tcp://" . $this->sendServer . ":" . $this->port;
$this->socket = stream_socket_client($remoteAddr, $errno, $errstr, 30);
if (! $this->socket) {
$this->errorMessage = $errstr;
return false;
}
// 设置加密方式
$crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
$crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
$crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
}
stream_socket_enable_crypto($this->socket, $ssl, $crypto_method);
} elseif (function_exists('fsockopen')) {
if ($ssl) {
$remoteAddr = "ssl://" . $this->sendServer;
} else {
$remoteAddr = "tcp://" . $this->sendServer;
}
$this->socket = fsockopen($remoteAddr, $this->port, $errno, $errstr, 30);
if (! $this->socket) {
$this->errorMessage = $errstr;
return false;
}
} else {
$this->errorMessage = '服务器已经禁用stream_socket_client和fsockopen函数请至少开启一个才能发送邮件';
return false;
}
stream_set_blocking($this->socket, 1); // 设置阻塞模式
$str = fread($this->socket, 1024);
if (! preg_match("/220+?/", $str)) {
$this->errorMessage = $str;
return false;
}
return true;
}
/**
* 关闭安全socket
*
* @return boolean
*/
protected function close()
{
if (isset($this->socket) && is_object($this->socket)) {
stream_socket_shutdown($this->socket, STREAM_SHUT_WR);
return true;
}
$this->errorMessage = "No resource can to be close";
return false;
}
}

156
core/basic/Url.php Normal file
View File

@@ -0,0 +1,156 @@
<?php
/**
* @copyright (C)2016-2099 Hnaoyun Inc.
* @author XingMeng
* @email hnxsh@foxmail.com
* @date 2017年11月6日
* 生成指定模块下控制器方法的跳转路径
*/
namespace core\basic;
class Url
{
// 存储已经生成过的地址信息
private static $urls = array();
// 接收控制器方法完整访问路径,如:/home/Index/index /模块/控制器/方法/.. 路径,生成可访问地址
public static function get($path, $suffix = null)
{
if (strpos($path, 'http') === 0 || ! $path) {
return $path;
}
$path = trim_slash($path); // 去除两端斜线
if (! isset(self::$urls[$path])) {
$path_arr = explode('/', $path); // 地址数组
if ($suffix && Config::get('app_url_type') == 2 && strrpos(strtolower($_SERVER["SCRIPT_NAME"]), 'index.php') !== false) {
$url_ext = Config::get('url_rule_suffix'); // 伪静态文件形式
} elseif (Config::get('app_url_type') == 1 || Config::get('app_url_type') == 2) {
$url_ext = '/'; // pathinfo目录形式
} else {
$url_ext = '';
}
// 路由处理
if (! ! $routes = Config::get('url_route')) {
foreach ($routes as $key => $value) {
// 去除两端斜线
$value = trim_slash($value);
$key = trim_slash($key);
// 替换原来正则为替换内容
if (preg_match_all('/\(.*?\)/', $key, $source)) {
foreach ($source[0] as $kk => $vk) {
$key = str_replace($vk, '$' . ($kk + 1), $key);
}
}
// 替换原来替换内容为正则
if (preg_match_all('/\$([0-9]+)/', $value, $destination)) {
foreach ($destination[1] as $kv => $vv) {
$value = str_replace($destination[0][$kv], $source[0][$vv - 1], $value);
}
}
// 执行匹配替换
if (preg_match('{' . $value . '$}i', $path)) {
$path = preg_replace('{' . $value . '$}i', $key, $path);
} elseif (preg_match('{' . $value . '\/}i', $path)) {
$path = preg_replace('{' . $value . '\/}i', $key . '/', $path);
}
}
}
// 域名绑定处理匹配
$cut_str = '';
if (! ! $domains = Config::get('app_domain_bind')) {
foreach ($domains as $key => $value) {
$value = trim_slash($value); // 去除两端斜线
if (strpos($path, $value . '/') === 0) {
$cut_str = $value;
$server_name = get_http_host();
if ($server_name != $key) { // 绑定的域名与当前域名不一致时,添加主机地址
$host = is_https() ? 'https://' . $key : 'http://' . $key;
} else {
$host = '';
}
break;
}
}
}
// 入口文件绑定匹配
if (defined('URL_BIND') && $path_arr[0] == M) {
$cut_str = trim_slash(URL_BIND);
}
// 执行URL简化
if ($cut_str) {
$path = substr($path, strlen($cut_str) + 1);
}
// 保存处理过的地址
if ($path) {
self::$urls[$path] = $host . url_index_path() . '/' . $path . $url_ext;
} else {
self::$urls[$path] = $host . url_index_path(); // 获取根路径前置地址
}
}
return self::$urls[$path];
}
// 生成前端地址
public static function home($path, $suffix = null, $qs = null)
{
if (! isset(self::$urls[md5($path . $suffix . $qs)])) {
$url_rule_type = Config::get('url_rule_type') ?: 3;
$url_rule_suffix = Config::get('url_rule_suffix') ?: '.html';
if ($suffix === true) {
$suffix = $url_rule_suffix;
} elseif ($suffix === false) {
$suffix = '';
} else {
$suffix = '/';
}
$path = trim($path, '/');
// 去除默认模块及控制器部分
$path = str_replace('home/Index/', '', $path);
if (! $path) {
if ($url_rule_type == 1) {
$link = SITE_INDEX_DIR . '/index.php';
} elseif ($url_rule_type == 2) {
$link = SITE_INDEX_DIR;
} else {
$link = SITE_INDEX_DIR . '/?';
}
} else {
switch ($url_rule_type) {
case '1': // 普通模式
$qs = $qs ? "?" . $qs : '';
$link = SITE_INDEX_DIR . '/index.php' . '/' . $path . $suffix . $qs;
break;
case '2': // 伪静态模式
$qs = $qs ? "?" . $qs : '';
$link = SITE_INDEX_DIR . '/' . $path . $suffix . $qs;
break;
case '3': // 兼容模式
$qs = $qs ? "&" . $qs : '';
$link = SITE_INDEX_DIR . '/?' . $path . $suffix . $qs;
break;
default:
error('地址模式设置错误,请登录后台重新设置!');
}
}
self::$urls[md5($path . $suffix . $qs)] = $link;
}
return self::$urls[md5($path . $suffix . $qs)];
}
}