uploadHandle = array('AliOssForTypecho_Plugin', 'uploadHandle');
Typecho_Plugin::factory('Widget_Upload')->modifyHandle = array('AliOssForTypecho_Plugin', 'modifyHandle');
Typecho_Plugin::factory('Widget_Upload')->deleteHandle = array('AliOssForTypecho_Plugin', 'deleteHandle');
Typecho_Plugin::factory('Widget_Upload')->attachmentHandle = array('AliOssForTypecho_Plugin', 'attachmentHandle');
Typecho_Plugin::factory('Widget_Upload')->attachmentDataHandle = array('AliOssForTypecho_Plugin', 'attachmentDataHandle');
return _t('启用成功,请进行相应设置!');
}
/**
* 禁用插件方法,如果禁用失败,直接抛出异常
*
* @static
* @access public
* @return void
* @throws Typecho_Plugin_Exception
*/
public static function deactivate(){}
/**
* 获取插件配置面板
*
* @access public
* @param Typecho_Widget_Helper_Form $form 配置面板
* @return void
*/
public static function config(Typecho_Widget_Helper_Form $form)
{
$upload_root = Typecho_Common::url(defined('__TYPECHO_UPLOAD_DIR__') ? __TYPECHO_UPLOAD_DIR__ : self::UPLOAD_DIR,
defined('__TYPECHO_UPLOAD_ROOT_DIR__') ? __TYPECHO_UPLOAD_ROOT_DIR__ : __TYPECHO_ROOT_DIR__);
$log_name = $upload_root . self::LOG_SUFFIX . 'error.log';
if (is_writable($upload_root) && is_writable($upload_root . self::LOG_SUFFIX) && is_writable($log_name)) {
$log_content = '恭喜!暂无错误日志产生,请继续保持维护,加油~';
$log_color = '#009900';
if (file_exists($log_name)) {
$handle = fopen($log_name, "r");
$content = fread($handle, filesize($log_name));
if ($content) {
$log_content = $content;
$log_color = '#dd0000';
}
fclose($handle);
}
} else {
$log_content = '!!!注意!!!
当前网站上传目录无写入权限,无法记录日志!
请给路径 '.$upload_root.' 赋予写入权限';
$log_color = '#f00000';
}
$des = new Typecho_Widget_Helper_Form_Element_Text('des', NULL, '', _t('插件使用说明'),
'
- 插件更新于2020年6月25号。
- 插件基于aliyun-oss-php-sdk Release 2.3.1开发,
若以后SDK开发包更新导致插件不可用,请到 我的博客^-^获取新版本插件,如果我还用typecho、阿里云OSS就会更新。
- 若开启“在服务器保留备份”功能,请注意:
1)请赋予以下目录写权限:'.$upload_root.'
2)当文件成功上传到OSS,但保存到服务器失败时,插件不会报错,这将导致当前文件在服务器上没有备份,但是会在此插件页面显示日志,请定期查阅并清理。
3)运行在云应用引擎上的站点“在服务器保留备份”选项无效。
- 旧版本Typecho存在无法上传大写扩展名文件的bug,请更新Typecho程序。
- 如有问题或建议请到 我的博客https://www.droomo.top/AliOssForTypecho.html 留言
以下是本插件产生的错误日志,请定期查看并处理:
');
$form->addInput($des);
$buketName = new Typecho_Widget_Helper_Form_Element_Text('bucketName', NULL, null,
_t('Bucket名称'), _t('请填写Buket名称'));
$form->addInput($buketName->addRule('required', _t('必须填写Bucket名称')));
$accessKeyId = new Typecho_Widget_Helper_Form_Element_Text('accessKeyId', NULL, null,
_t('ACCESS KEY ID'), _t('请填写ACCESS KEY ID'));
$form->addInput($accessKeyId->addRule('required', _t('必须填写ACCESS KEY ID')));
$accessKeySecret = new Typecho_Widget_Helper_Form_Element_Text('accessKeySecret', NULL, null,
_t('ACCESS KEY SECRET'), _t('请填写请填写ACCESS KEY SECRET'));
$form->addInput($accessKeySecret->addRule('required', _t('必须填写ACCESS_KEY')));
$endPoint = new Typecho_Widget_Helper_Form_Element_Select('endPoint',
array(
"oss-cn-hangzhou" => "华东1(杭州)oss-cn-hangzhou",
"oss-cn-shanghai" => "华东2(上海)oss-cn-shanghai",
"oss-cn-qingdao" => "华北1(青岛)oss-cn-qingdao",
"oss-cn-beijing" => "华北2(北京)oss-cn-beijing",
"oss-cn-zhangjiakou" => "华北3(张家口)oss-cn-zhangjiakou",
"oss-cn-huhehaote" => "华北5(呼和浩特)oss-cn-huhehaote",
"oss-cn-wulanchabu" => "华北6(乌兰察布)oss-cn-wulanchabu",
"oss-cn-shenzhen" => "华南1(深圳)oss-cn-shenzhen",
"oss-cn-heyuan" => "华南2(河源)oss-cn-heyuan",
"oss-cn-chengdu" => "西南1(成都)oss-cn-chengdu",
"oss-cn-hongkong" => "中国(香港)oss-cn-hongkong",
"oss-us-west-1" => "美国西部1(硅谷)oss-us-west-1",
"oss-us-east-1" => "美国东部1(弗吉尼亚)oss-us-east-1",
"oss-ap-southeast-1" =>"亚太东南1(新加坡)oss-ap-southeast-1",
"oss-ap-southeast-2" =>"亚太东南2(悉尼)oss-ap-southeast-2",
"oss-ap-southeast-3" =>"亚太东南3(吉隆坡)oss-ap-southeast-3",
"oss-ap-southeast-5" =>"亚太东南5(雅加达)oss-ap-southeast-5",
"oss-ap-northeast-1" =>"亚太东北1(日本)oss-ap-northeast-1",
"oss-ap-south-1" => "亚太南部1(孟买)oss-ap-south-1",
"oss-eu-central-1" => "欧洲中部1(法兰克福)oss-eu-central-1",
"oss-eu-west-1" => "英国(伦敦)oss-eu-west-1",
"oss-me-east-1" => "中东东部1(迪拜)oss-me-east-1",
"other" => '自定义'
),
'oss-cn-qingdao',
_t('区域选择(若区域不在列表中则选择自定义,然后填写区域)'), '');
$form->addInput($endPoint);
$endPointType = new Typecho_Widget_Helper_Form_Element_Select('endPointType',
array(
".aliyuncs.com" => '外网',
"-internal.aliyuncs.com" => '内网',
),
'.aliyuncs.com', '',
'在你了解两种连接方式的不同作用的情况下修改此选项');
$form->addInput($endPointType);
$otherEndPoint = new Typecho_Widget_Helper_Form_Element_Text('otherEndPoint', NULL, '',
'', '
填写全部Endpoint地址,通常以\'.aliyuncs.com\'或\'-internal.aliyuncs.com\'结尾。开头不包含http://,结尾不包含"/"。
例如"oss-cn-qingdao.aliyuncs.com"');
$form->addInput($otherEndPoint);
$userDir = new Typecho_Widget_Helper_Form_Element_Text('userDir', NULL, 'typecho/',
_t('要储存的路径'), _t('请填写文件储存的路径(相对OSS根目录),以字母或数字开头,以"/"结尾。留空则上传到根目录。'));
$form->addInput($userDir);
$cdnUrl = new Typecho_Widget_Helper_Form_Element_Text('cdnUrl', NULL, '',
_t('自定义(CDN)域名'), '请填写自定义域名,留空则使用外网Endpoint访问,以http://或https://开头,以"/"结尾');
$form->addInput($cdnUrl);
$ifLoaclSave = new Typecho_Widget_Helper_Form_Element_Radio('ifLoaclSave', array( "1" => '保留', "0" => '不保留' ), "1",
_t('在服务器保留备份'), _t('是否在服务器保留备份'));
$form->addInput($ifLoaclSave);
echo '';
}
/**
* 个人用户的配置面板
*
* @access public
* @param Typecho_Widget_Helper_Form $form
* @return void
*/
public static function personalConfig(Typecho_Widget_Helper_Form $form){}
/**
* 上传文件处理函数
*
* @access public
* @param array $file 上传的文件
* @return mixed
*/
public static function uploadHandle($file)
{
if (empty($file['name'])) {
return FALSE;
}
$ext = self::getExtentionName($file['name']);
if (!self::checkFileType($ext)) {
return FALSE;
}
if (isset($file['tmp_name'])) {
$content = file_get_contents($file['tmp_name']);
} else if (isset($file['bytes'])) {
$content = $file['bytes'];
} else {
return FALSE;
}
$options = Typecho_Widget::widget('Widget_Options');
$user_dir = $options->plugin('AliOssForTypecho')->userDir;
$bucket_name = $options->plugin('AliOssForTypecho')->bucketName;
$end_point = 'http://' . (($options->plugin('AliOssForTypecho')->endPoint === "other") ?
$options->plugin('AliOssForTypecho')->otherEndPoint :
$options->plugin('AliOssForTypecho')->endPoint . $options->plugin('AliOssForTypecho')->endPointType);
$access_id = $options->plugin('AliOssForTypecho')->accessKeyId;
$access_key = $options->plugin('AliOssForTypecho')->accessKeySecret;
try {
$oss_client = new OssClient($access_id, $access_key, $end_point);
} catch (Exception $e) {
return FALSE;
}
$save_on_server = $options->plugin('AliOssForTypecho')->ifLoaclSave;
$file_origin_name = self::getSafeName($file['name']);
$relative_path = date('Y/m/d/');
$remote_file_name = $user_dir . $relative_path . $file_origin_name;
if ($save_on_server === "1" && !Typecho_Common::isAppEngine()) {
$upload_root = Typecho_Common::url(defined('__TYPECHO_UPLOAD_DIR__') ? __TYPECHO_UPLOAD_DIR__ : self::UPLOAD_DIR,
defined('__TYPECHO_UPLOAD_ROOT_DIR__') ? __TYPECHO_UPLOAD_ROOT_DIR__ : __TYPECHO_ROOT_DIR__);
$local_file_name = $upload_root . $relative_path . $file_origin_name;
try{
$exist_on_oss = $oss_client->doesObjectExist($bucket_name, $remote_file_name);
$exist_on_server = file_exists($local_file_name);
} catch(OssException $e) {
return false;
}
if ($exist_on_oss || $exist_on_server) {
// find a name neither exist on oss nor the server
$pathinfo = pathinfo($file_origin_name);
for ($i = 1;; $i++) {
$file_origin_name = $pathinfo['filename'] . '(' . strval($i) . ').' . self::getExtentionName($file_origin_name);
$remote_file_name = $user_dir . $relative_path . $file_origin_name;
$local_file_name = $upload_root . $relative_path . $file_origin_name;
try{
$exist_on_oss = $oss_client->doesObjectExist($bucket_name, $remote_file_name);
$exist_on_server = file_exists($local_file_name);
} catch(OssException $e) {
return false;
}
if ($exist_on_oss || $exist_on_server) {
} else {
break;
}
}
}
} else {
try{
$exist_on_oss = $oss_client->doesObjectExist($bucket_name, $remote_file_name);
} catch(OssException $e) {
return false;
}
if ($exist_on_oss || $exist_on_server) {
// find a name not exist on oss
$pathinfo = pathinfo($file_origin_name);
for ($i = 1;; $i++) {
$file_origin_name = $pathinfo['filename'] . '(' . strval($i) . ').' . self::getExtentionName($file_origin_name);
$remote_file_name = $user_dir . $relative_path . $file_origin_name;
try{
$exist_on_oss = $oss_client->doesObjectExist($bucket_name, $remote_file_name);
} catch(OssException $e) {
return false;
}
if (!$exist_on_oss) {
break;
}
}
}
}
try{
$ali_response = $oss_client->putObject($bucket_name, $remote_file_name, $content);
} catch(OssException $e) {
return false;
}
if (200 != $ali_response['info']['http_code']) {
return FALSE;
} else {
$object_url = $ali_response['info']["url"];
if ($save_on_server === "1" && !Typecho_Common::isAppEngine()) {
$file_dir_name = dirname($local_file_name);
$dir_exist = false;
if (is_dir($file_dir_name)) {
$dir_exist = true;
} else {
if (self::makeUploadDir($file_dir_name)) {
$dir_exist = true;
}
}
$error_log_path = $upload_root . self::LOG_SUFFIX;
if ($dir_exist) {
if (!file_put_contents($local_file_name, $content)) {
return false;
}
} else {
return false;
$error = '错误:创建目录失败' . "\r\n" .
'创建路径:' . $localPath . "\r\n" .
'远程文件:' . $object_url . "\r\n" .
'时间:' . date('Y-m-d h:i:sa') . "\r\n\r\n";
error_log($error, 3, $error_log_path . "error.log");
}
}
return array(
'name' => $file_origin_name,
'path' => $remote_file_name,
'size' => intval($ali_response['oss-requestheaders']['Content-Length']),
'type' => $ext,
'mime' => $ali_response['oss-requestheaders']['Content-Type']
);
}
}
/**
* 修改文件处理函数
*
* @access public
* @param array $content 老文件
* @param array $file 新上传的文件
* @return mixed
*/
public static function modifyHandle($content, $file)
{
if (empty($file['name'])) {
return false;
}
$options = Typecho_Widget::widget('Widget_Options');
$userDir = $options->plugin('AliOssForTypecho')->userDir;
$bucket_name = $options->plugin('AliOssForTypecho')->bucketName;
$end_point = 'http://' . (($options->plugin('AliOssForTypecho')->endPoint === "other") ?
$options->plugin('AliOssForTypecho')->otherEndPoint :
$options->plugin('AliOssForTypecho')->endPoint . $options->plugin('AliOssForTypecho')->endPointType);
$access_id = $options->plugin('AliOssForTypecho')->accessKeyId;
$access_key = $options->plugin('AliOssForTypecho')->accessKeySecret;
$ext = self::getExtentionName($file['name']);
if ($content['attachment']->type != $ext) {
return false;
}
$path = $content['attachment']->path;
$object_name = $userDir . $path;
if (isset($file['tmp_name'])) {
$newContent = file_get_contents($file['tmp_name']);
} else if (isset($file['bytes'])) {
$newContent = $file['bytes'];
} else {
return false;
}
try {
$oss_client = new OssClient($access_id, $access_key, $end_point);
} catch (Exception $e) {
throw new Exception( $e->getMessage());
}
$ali_response = $oss_client->putObject($bucket_name, $object_name, $newContent);
if (200 != $ali_response['info']['http_code']) {
return FALSE;
} else {
$object_url = $ali_response["info"]["url"];
$ifLoaclSave = $options->plugin('AliOssForTypecho')->ifLoaclSave;
if ($ifLoaclSave === "1" && !Typecho_Common::isAppEngine()) {
$upload_root = Typecho_Common::url(defined('__TYPECHO_UPLOAD_DIR__') ? __TYPECHO_UPLOAD_DIR__ : self::UPLOAD_DIR,
defined('__TYPECHO_UPLOAD_ROOT_DIR__') ? __TYPECHO_UPLOAD_ROOT_DIR__ : __TYPECHO_ROOT_DIR__);
$localFile = $upload_root . $path;
$localPath = dirname($localFile);
$mkdirSuccess = TRUE;
if (!is_dir($localPath)) {
if (!self::makeUploadDir($localPath)) {
$mkdirSuccess = FALSE;
}
}
if ($mkdirSuccess) {
$deleteLacalFileSuccess = unlink($localFile);
if (!$deleteLacalFileSuccess) {
$error_log_path = $upload_root . self::LOG_SUFFIX;
if (!is_dir($error_log_path)) {
self::makeUploadDir($error_log_path);
}
$error = '错误:删除文件失败导致无法修改文件' . "\r\n" .
'文件:' . $localFile . "\r\n" .
'远程文件:' . $object_url . "\r\n" .
'时间:' . date('Y-m-d h:i:sa') . "\r\n\r\n";
error_log($error, 3, $error_log_path . "error.log");
} else {
if (file_put_contents($localFile, $newContent)) {
} else {
$error = '错误:保存文件失败' . "\r\n" .
'远程文件:' . $object_url . "\r\n" .
'时间:' . date('Y-m-d h:i:sa') . "\r\n\r\n";
error_log($error, 3, $error_log_path . "error.log");
}
}
} else {
$error = '错误:创建目录失败' . "\r\n" .
'创建路径:' . $localPath . "\r\n" .
'远程文件:' . $object_url . "\r\n" .
'时间:' . date('Y-m-d h:i:sa') . "\r\n\r\n";
error_log($error, 3, $error_log_path . "error.log");
}
}
}
return array(
'name' => $content['attachment']->name,
'path' => $path,
'size' => intval($ali_response['oss-requestheaders']['Content-Length']),
'type' => $ext,
'mime' => $ali_response['oss-requestheaders']['Content-Type']
);
}
/**
* 删除文件
*
* @access public
* @param array $content 文件相关信息
* @return string
*/
public static function deleteHandle(array $content)
{
$options = Typecho_Widget::widget('Widget_Options');
$userDir = $options->plugin('AliOssForTypecho')->userDir;
$bucket_name = $options->plugin('AliOssForTypecho')->bucketName;
$end_point = 'http://' . (($options->plugin('AliOssForTypecho')->endPoint === "other") ?
$options->plugin('AliOssForTypecho')->otherEndPoint :
$options->plugin('AliOssForTypecho')->endPoint . $options->plugin('AliOssForTypecho')->endPointType);
$access_id = $options->plugin('AliOssForTypecho')->accessKeyId;
$access_key = $options->plugin('AliOssForTypecho')->accessKeySecret;
try {
$oss_client = new OssClient($access_id, $access_key, $end_point);
} catch (Exception $e) {
throw new Exception( $e->getMessage());
}
$path = $content['attachment']->path;
$object_name = $userDir . $path;
$ali_response = $oss_client->deleteObject($bucket_name, $object_name);
$ifLoaclSave = $options->plugin('AliOssForTypecho')->ifLoaclSave;
if ($ifLoaclSave === "1" && !Typecho_Common::isAppEngine()) {
$upload_root = Typecho_Common::url(defined('__TYPECHO_UPLOAD_DIR__') ? __TYPECHO_UPLOAD_DIR__ : self::UPLOAD_DIR,
defined('__TYPECHO_UPLOAD_ROOT_DIR__') ? __TYPECHO_UPLOAD_ROOT_DIR__ : __TYPECHO_ROOT_DIR__);
$localPath = $upload_root . $path;
$deleteLacalFileSuccess = unlink($localPath);
if (!$deleteLacalFileSuccess) {
$error_log_path = $localPath . self::LOG_SUFFIX;
if (!is_dir($error_log_path)) {
self::makeUploadDir($error_log_path);
}
$error = '错误:删除文件失败' . "\r\n" .
'文件:' . $localPath . "\r\n" .
'时间:' . date('Y-m-d h:i:sa') . "\r\n\r\n";
error_log($error, 3, $error_log_path . "error.log");
}
}
return ($ali_response['info']['http_code'] === 204);
}
/**
* 获取实际文件绝对访问路径
*
* @access public
* @param array $content 文件相关信息
* @return string
*/
public static function attachmentHandle(array $content) {
$options = Typecho_Widget::widget('Widget_Options');
$cdnUrl = $options->plugin('AliOssForTypecho')->cdnUrl;
if ($cdnUrl == '') {
$bucket_name = $options->plugin('AliOssForTypecho')->bucketName;
$end_point = ($options->plugin('AliOssForTypecho')->endPoint === "other") ?
$options->plugin('AliOssForTypecho')->otherEndPoint :
$options->plugin('AliOssForTypecho')->endPoint;
return 'https://' . $bucket_name . '.' . $end_point . '.aliyuncs.com/' . $content['attachment']->path;
} else {
return $cdnUrl . $content['attachment']->path;
}
}
/**
* 获取实际文件数据
*
* @access public
* @param array $content
* @return string
*/
public static function attachmentDataHandle(array $content)
{
return file_get_contents(self::attachmentHandle($content));
}
/**
* 检查文件名
*
* @access private
* @param string $ext 扩展名
* @return boolean
*/
private static function checkFileType($ext)
{
$options = Typecho_Widget::widget('Widget_Options');
return in_array($ext, $options->allowedAttachmentTypes);
}
/**
* 创建上传路径
*
* @access private
* @param string $path 路径
* @return boolean
*/
private static function makeUploadDir($path)
{
$path = preg_replace("/\\\+/", '/', $path);
$current = rtrim($path, '/');
$last = $current;
while (!is_dir($current) && false !== strpos($path, '/'))
{
$last = $current;
$current = dirname($current);
}
if ($last == $current)
{
return true;
}
if (!@mkdir($last))
{
return false;
}
$stat = @stat($last);
$perms = $stat['mode'] & 0007777;
@chmod($last, $perms);
return self::makeUploadDir($path);
}
/**
* 获取安全的文件名
*
* @param string $name
* @static
* @access private
* @return string
*/
private static function getSafeName(&$name)
{
$name = str_replace(array('"', '<', '>'), '', $name);
$name = str_replace('\\', '/', $name);
$name = false === strpos($name, '/') ? ('a' . $name) : str_replace('/', '/a', $name);
$info = pathinfo($name);
$name = substr($info['basename'], 1);
return $name;
}
private static function getExtentionName(&$name)
{
$info = pathinfo($name);
return isset($info['extension']) ? strtolower($info['extension']) : '';
}
}