Commit f28b9f19 by 冷斌

init

parent bd760e55

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/vendor/adbario/php-dot-notation" />
<excludeFolder url="file://$MODULE_DIR$/vendor/alibabacloud/client" />
<excludeFolder url="file://$MODULE_DIR$/vendor/aliyuncs/oss-sdk-php" />
<excludeFolder url="file://$MODULE_DIR$/vendor/baidubce/bce-sdk-php" />
<excludeFolder url="file://$MODULE_DIR$/vendor/clagiordano/weblibs-configmanager" />
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/danielstjules/stringy" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/cache" />
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzle/guzzle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/guzzle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/promises" />
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/psr7" />
<excludeFolder url="file://$MODULE_DIR$/vendor/markbaker/complex" />
<excludeFolder url="file://$MODULE_DIR$/vendor/monolog/monolog" />
<excludeFolder url="file://$MODULE_DIR$/vendor/mtdowling/jmespath.php" />
<excludeFolder url="file://$MODULE_DIR$/vendor/nelexa/zip" />
<excludeFolder url="file://$MODULE_DIR$/vendor/obs/esdk-obs-php" />
<excludeFolder url="file://$MODULE_DIR$/vendor/overtrue/socialite" />
<excludeFolder url="file://$MODULE_DIR$/vendor/overtrue/wechat" />
<excludeFolder url="file://$MODULE_DIR$/vendor/paragonie/random_compat" />
<excludeFolder url="file://$MODULE_DIR$/vendor/pclzip/pclzip" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpoffice/common" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpoffice/phpspreadsheet" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpoffice/phpword" />
<excludeFolder url="file://$MODULE_DIR$/vendor/pimple/pimple" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/container" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-message" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/log" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/simple-cache" />
<excludeFolder url="file://$MODULE_DIR$/vendor/qiniu/php-sdk" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/event-dispatcher" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-foundation" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-mbstring" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php70" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/psr-http-message-bridge" />
<excludeFolder url="file://$MODULE_DIR$/vendor/zendframework/zend-escaper" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/eduline.iml" filepath="$PROJECT_DIR$/.idea/eduline.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="$PROJECT_DIR$/addons/theme/stv1/_static/js/webcam" vcs="Git" />
<mapping directory="$PROJECT_DIR$/core/OpenSociax/Api/Youtu" vcs="Git" />
</component>
</project>
\ No newline at end of file
<?php
namespace Console;
use eduline\Console;
use eduline\console\Command;
use eduline\console\Input;
use eduline\console\input\Option;
use eduline\console\Output;
use Eduline\Process;
class Crond extends Command
{
/**
* 配置命令信息
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2018-08-15
* @return [type] [description]
*/
protected function configure()
{
$this->setName('crond')
->addOption('name', null, Option::VALUE_OPTIONAL, 'set command name,call console', null)
->setDescription('crond');
}
/**
* 执行命令入口
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2018-08-15
* @param Input $input [description]
* @param Output $output [description]
* @return [type] [description]
*/
protected function execute(Input $input, Output $output)
{
/* 永不超时 */
ini_set('max_execution_time', 0);
$name = $input->getOption('name');
if ($name !== null) {
return $this->executeCmd($name);
}
$time = time();
$exe_method = [];
// 直接引入配置文件
$config = require_once CONF_PATH . '/' . 'crond.inc.php';
$crond_list = $config['crond'];
$sys_crond_timer = $config['crond_time'];
foreach ($sys_crond_timer as $format) {
$key = date($format, ceil($time));
if (is_array(@$crond_list[$key])) {
$exe_method = array_merge($exe_method, $crond_list[$key]);
}
}
// 存在方法时
if (!empty($exe_method)) {
foreach ($exe_method as $method) {
// 是否执行命令
if (strpos($method, "cmd::") !== false) {
@list($action, $cmd) = explode("::", $method);
// // 获取参数
// preg_match_all('/(--\w+([\s+=]\w+)?)/', $cmd, $matches);
// $params = [];
// if ($matches[1]) {
// $params = $matches[1];
// $cmd = stristr($cmd, ' ', true);
// }
// 执行命令
// $this->executeCmd($cmd, $params);
$this->executeCmd($cmd);
continue;
} else if (strpos($method, '::') !== false) {
@list($className, $function) = explode("::", $method);
$class = new $className;
} else {
$class = new $method;
$function = 'fire';
}
if (!is_callable([$class, $function])) {
//方法不存在的话就跳过不执行
$output->writeln("<error>" . $method . " not exists.</error>");
continue;
}
call_user_func([$class, $function]);
}
}
}
// *
// * 执行CMD命令
// * @Author Martinsun<syh@sunyonghong.com>
// * @DateTime 2018-08-15
// * @param [type] $cmd [description]
// * @param [type] $params [description]
// * @return [type] [description]
// protected function executeCmd($cmd, $params = [])
// {
// return Console::call($cmd, $params);
// }
protected function executeCmd($cmd)
{
$workerCommand = '"' . PHP_BINARY . '" eduline ' . $cmd;
$commandRootPath = defined('ROOT_PATH') ? ROOT_PATH : dirname($_SERVER['argv'][0]);
$process = new Process($workerCommand . '', $commandRootPath, null, null, 60);
$process->run();
}
}
<?php
namespace Job\notify;
use Eduline\Queue;
use Eduline\queue\Job;
class Check
{
/**
* 计划任务
* @Author 亓官雨树<lucky.max@foxmail.com>
* @DateTime 2018-10-12
* @param integer $limit [description]
* @param [type] $is_del [description]
* @return [type] [description]
*/
public function fire()
{
//
$conf_time = model('Xdata')->get('live_AdminConfig:baseConfig');
$is_notify_open = $conf_time['is_notify_open'];
file_put_contents(LOG_PATH.'live_notify.txt', json_encode($conf_time));
if($is_notify_open){
// 获取即将开课的直播信息
$time = time();
$atime = time() + $conf_time['notify_time']*60;
$map['is_del'] = 0;
$map['is_active'] = 1;
$map['startDate'] = [['lt', $atime], ['gt', $time], 'and'];
//获取即将开始的直播课时id
$lids = M('zy_live_thirdparty')->where($map)->getField('id,live_id');
if ($lids) {
foreach ($lids as $tid => $lid) { // $tid课时id,$lid课程id
// $uids = M('zy_live_notified')->where(['lid'=>$tid])->getField('uid,uid');
// $uids = implode(',', $uids);
// 查询订购该课程的学员uid和phone以及课程名称
$prefix = C('DB_PREFIX');
$userOrder = M('zy_order_live as l')->join('join '.$prefix.'user AS u ON u.uid = l.uid')->join(' join '.$prefix.'zy_video AS v ON v.id = l.live_id')->where(['l.live_id' => $lid])->field('u.uid,phone,v.video_title')->findAll();
$userInfo = [];
// 重组数组并去重
foreach ($userOrder as $k => $u) {
$userInfo[$u['uid']]['phone'] = $u['phone'];
$userInfo[$u['uid']]['title'] = $u['video_title'];
$userInfo[$u['uid']]['url'] = '/live/' . $lid . '.html';
}
// 去除已发送该课时提醒的用户
foreach ($userInfo as $uid => $val) {
// 避免讲师临时修改开播时间
// $startDate = M('zy_live_thirdparty')->where(['id'=>$tid])->getField('id,startDate');
// $exist = M('zy_live_notified')->where(['tid'=>$tid, 'uid'=>$uid, 'startDate'=>$startDate])->count();
$exist = M('zy_live_notified')->where(['tid'=>$tid, 'uid'=>$uid])->count();
if($exist){
unset($userInfo[$uid]);
}else{
$startDate = M('zy_live_thirdparty')->where(['id'=>$tid])->getField('startDate');
// $add['startDate'] = $startDate;
$add['tid'] = $tid;
$add['uid'] = $uid;
$add['ctime'] = time();
// 添加直播课提醒记录
M('zy_live_notified')->add($add);
// 加入邮件发送队列
Queue::push('Job\notify\Send', [
'to' => $uid,
'phone' => $val['phone'],
'title' => $val['title'],
// 'url' => $val['url'],
'stop_time' => $startDate,
// 'stop_time' => time()+60*$conf_time['notify_time'],// 停止推送时间
'status' => [
'notify_message' => 0,
'sms' => 0,
'wx_notes' => 0,
],
], 'notify');
}
}
}
}
}
}
}
<?php
namespace Job\notify;
use EasyWeChat\Foundation\Application;
use Eduline\Queue;
use Eduline\queue\Job;
use Library\Sms\Service as SmsService;
class Send
{
/**
* 队列执行方法
* @Author 亓官雨树<lucky.max@foxmail.com>
* @DateTime 2018-10-12
* @param integer $limit [description]
* @param [type] $is_del [description]
* @return [type] [description]
*/
public function fire(Job $obj, $data)
{
// 检测时间是否过期
if($data['stop_time'] && $data['stop_time'] <= time()){
$obj->delete();
return true;
}
$status = $data['status'];
array_walk($status, function ($v, $key) use (&$status, $data) {
if ($v === 1) {
return true;
}
$fun = 'send' . parse_name($key, 1);
// 调用对应的方法进行消息处理
if (is_callable([$this, $fun]) && $this->$fun($data)) {
$status[$key] = 1;
}
});
if (!in_array(0, $status)) {
// 如果都发送完成,则删除任务
$obj->delete();
} else if ($obj->attempts() > 3) {
// 当前任务失败次数超过3次,判定为任务失败
$obj->delete();
} else {
// 更新状态
$data['status'] = $status;
$obj->setRawBodyData($data);
// 延迟30秒重发
$obj->release(30);
}
}
/**
* 发送站内信
* @Author 亓官雨树<lucky.max@foxmail.com>
* @DateTime 2018-10-26
* @param [type] $data [description]
* @return [type] [description]
*/
private function sendNotifyMessage($data)
{
$uid = $data['to'];
$title = $data['title'];
$url = $data['url'];
$conf = model('Notify')->getNode('live_notify');
$s['uid'] = $uid;
$s['node'] = $conf['node'];
$s['appname'] = $conf['appname'];
$s['title'] = $conf['title_key'];
$shor = ['{live_title}','{live_url}'];
$repl = [$title,$url];
$s['body'] = str_replace($shor,$repl,$conf['content_key']);
$exist = M('notify_message')->where($s)->count();
if (!$exist) {
$s['ctime'] = time();
$s['is_read'] = 0;
$exist = M('notify_message')->add($s);
}
return $exist ? true : false;
// $live_data['live_title'] = $data['title'];
// $live_data['live_url'] = $data['url'];
// $send_notify = model('Notify')->sendNotify($data['to'], 'live_notify', $live_data, '');
// return $send_notify ? true : false;
}
/**
* 发送短信
* @Author 亓官雨树<lucky.max@foxmail.com>
* @DateTime 2018-10-26
* @param [type] $data [description]
* @return [type] [description]
*/
private function sendSms($data)
{
$smsConfig = model('Xdata')->get('admin_Config:sms');
// 推送开关
if (!$smsConfig['live_notice']) {
return true;
}
$phone = $data['phone'];
// $url = $data['url'];
if(!$phone){
return true;
}
$title = $data['title'];
$sendres = SmsService::send($phone,[
'title' => $title
],'notify');
return $sendres ? true : false;
}
/**
* 发送微信通知
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2018-10-26
* @param [type] $data [description]
* @return [type] [description]
*/
private function sendWxNotes($data)
{
$noteConfig = model('Xdata')->get('admin_Config:wxNotes');
// 推送开关
if (!$noteConfig['message_push']) {
return true;
}
$uid = $data['to'];
$title = "《" . $data['title'] . '》';
$noteHtml = "【直播开课通知】 \n\n ";
$noteHtml .= "你购买的课程: ".$title."即将开课,请使用电脑登录网站学习。";
// 检测是否有APP下载地址
$appConfig = model("Xdata")->get('admin_Config:appConfig');
if($appConfig['download_url'] || $appConfig['download_url_ios']){
$noteHtml .= "\n\n 你也可以点击以下链接下载APP学习: \n\n";
$appConfig['download_url'] && $noteHtml .= "☞☞ Android 版本: ".$appConfig['download_url']." \n\n";
$appConfig['download_url_ios'] && $noteHtml .= "☞☞ iPhone 版本: ".$appConfig['download_url_ios'];
}
try {
$noteConfig = model('Xdata')->get('admin_Config:wxNotes');
if ($noteConfig['message_push']) {
// 获取用户的Openid
$openid = M('user_openid')->where(['uid' => $uid, 'type' => 1])->getField('open_id');
if(!$openid){
return true;
}
// 开启了消息通知
$config = model('Xdata')->get('admin_Config:weixin');
$options = [
'debug' => false,
'app_id' => $config['app_id'],
'secret' => $config['secret'],
'token' => $config['token'],
];
// 安全模式
if ($config['aes_key']) {
$options['aes_key'] = $config['aes_key'];
}
$app = new Application($options);
// 发送一个客服消息
$staff = $app->staff;
$staff->message($noteHtml)->to($openid)->send();
}
} catch (\Exception $e) {
return false;
}
return true;
}
}
<?php
namespace Job\office;
use Eduline\queue\Job;
use Library\BaiduDoc\services\DocService;
use Eduline\Queue;
class ToBaiduDoc
{
protected $ext = [
'doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'vsd', 'pot', 'pps', 'rtf', 'wps', 'et', 'dps', 'pdf', 'txt', 'epub',
];
public function fire(Job $obj, $data)
{
try {
// 第一步上传
$doc = new DocService();
$doc->upload($data);
// 第二步创建文档
$response = $doc->registerWithBos($data);
if (!$response['documentId']) {
throw new \Exception('create document failed.');
}
// 创建文档成功,等待转码后通知回调
$documentId = $response['documentId'];
// 定时查询
$_data = array_merge($data, ['documentId' => $documentId]);
// 加入队列任务,任务优先级调高一级
Queue::push('Job\office\ToBaiduDocStatus', $_data, 'upload', 1);
} catch (\Exception $e) {
// 更新状态
$saveData = [
'transcoding_status' => 0,
'duration' => '00:00:00',
'filesize' => 0,
'video_address' => '',
];
// 查询是否存在
if (M('zy_video_data')->where(['videokey' => $data['key']])->count() < 1) {
// 存储数据
$transcoding_data = [
'transcoding_file_key' => $data['key'],
'transcoding_info' => json_encode($saveData),
];
M('transcoding')->add($transcoding_data);
} else {
M('zy_video_data')->where(['videokey' => $data['key']])->save($saveData);
}
}
// @unlink($data['file']);
$obj->delete();
}
}
<?php
namespace Job\office;
use Eduline\queue\Job;
use Library\BaiduDoc\services\DocService;
class ToBaiduDocStatus
{
public function fire(Job $obj, $data)
{
try {
$doc = new DocService();
$info = $doc->get($data['documentId']);
if (!$info || !in_array($info['status'], ['PUBLISHED', 'FAILED'])) {
throw new \Exception('document status is ' . $info['status']);
}
// 是否转码成功了
$status = $info['status'] == 'PUBLISHED' ? 1 : 0;
// 更新状态
$saveData = [
'transcoding_status' => $status,
'videokey' => $data['documentId'],
'video_type' => 5,
'video_address' => $data['documentId'].'.'.$info['format'],
];
// 查询是否存在
if (M('zy_video_data')->where(['videokey' => $data['key']])->count() < 1) {
$transcoding_data = [
'transcoding_file_key' => $data['key'],
'transcoding_info' => json_encode($saveData),
];
if (M('transcoding')->where(['transcoding_file_key' => $data['key']])->count() < 1) {
// 存储数据
M('transcoding')->add($transcoding_data);
} else {
// 修改数据
M('transcoding')->where(['transcoding_file_key' => $data['key']])->save($transcoding_data);
}
} else {
M('zy_video_data')->where(['videokey' => $data['key']])->save($saveData);
}
$obj->delete();
} catch (\Exception $e) {
// 重新发布
$obj->release(60);
}
}
}
<?php
namespace Job\office;
use Eduline\Queue;
use Eduline\queue\Job;
class ToPdf
{
protected $ext = [
'wp', 'sword', 'excel', 'ppt', 'xls', 'xlsx', 'doc', 'docx', 'pptx', 'txt',
];
public function fire(Job $obj, $data)
{
if (!is_file($data['file'])) {
// 删除本次任务
$obj->delete();
if (M('zy_video_data')->where(['transcoding_status' => 2, 'videokey' => $data['key']])->count() < 1) {
return true;
}
// 更新状态
$saveData = [
'transcoding_status' => 0,
'duration' => '00:00:00',
'filesize' => 0,
'video_address' => '',
];
// 查询是否存在
if (M('zy_video_data')->where(['videokey' => $data['key']])->count() < 1) {
// 存储数据
$transcoding_data = [
'transcoding_file_key' => $data['key'],
'transcoding_info' => json_encode($saveData),
];
M('transcoding')->add($transcoding_data);
} else {
M('zy_video_data')->where(['videokey' => $data['key']])->save($saveData);
}
return true;
}
// 查询是否存在文件
$progress = 0;
if (is_file($data['out_file'])) {
$progress = 100;
}
// 如果没有处理
if ($progress == 0) {
// 执行命令,添加进度报告
$log_file = $data['out_file'] . '.log';
$fpos = $data['fpos'] . ' -progress ' . $log_file;
if (IS_WIN) {
pclose(popen('start /wait /B ' . $fpos, 'r'));
} else {
$cmd = 'PATH=$PATH unoconv -l -f pdf ' . $data['file'] . '> /dev/null';
exec($cmd);
}
// 查询是否处理完成
if (is_file($data['out_file'])) {
$progress = 100;
}
}
if ($progress >= 100) {
// 删除本次任务
$obj->delete();
// 加入上传队列
Queue::push('Job\upload\Office', $data, 'upload');
return true;
} elseif ($obj->attempts() > 10) {
// 当前任务失败次数超过10次,判定为任务失败
$obj->delete();
// 查询是否存在
if (M('zy_video_data')->where(['videokey' => $data['key']])->count() < 1) {
// 存储数据
$transcoding_data = [
'transcoding_file_key' => $data['key'],
'transcoding_info' => json_encode([
'transcoding_status' => 0,
]),
];
$status = M('transcoding')->add($transcoding_data);
} else {
$status = M('zy_video_data')->where(['videokey' => $data['key']])->save(['transcoding_status' => 0]);
}
} else {
// 重新发布
$obj->release();
}
}
}
<?php
namespace Job\order;
class Invalid
{
/**]
*运行服务,系统服务自动运行
* 订单处理-失效订单
*/
public function fire()
{
$map['term'] = ['neq', '0'];
$map['pay_status'] = 3;
$map['time_limit'] = ['elt', time()];
M('zy_order_course')->where($map)->save(['pay_status' => 7]);
M('zy_order_live')->where($map)->save(['pay_status' => 7]);
}
}
<?php
namespace Job\sysNotify;
use Eduline\Queue;
use Eduline\queue\Job;
class Send
{
/**
* 队列执行方法
* @Author 亓官雨树<lucky.max@foxmail.com>
* @DateTime 2019-05-21
* @param integer $limit [description]
* @param [type] $is_del [description]
* @return [type] [description]
*/
public function fire(Job $obj, $data)
{
$group_id = $data['group_id'];
$limit = $data['user_limit']*$data['limit'] . ',' . $data['limit'];
$content = $data['content'];
if($group_id){
// 指定用户组
$userList = M('user')->join(' u INNER JOIN (SELECT `uid` FROM `' . C('DB_PREFIX') . 'user_group_link` WHERE `user_group_id` = ' . $group_id . ' ORDER BY `uid` LIMIT ' . $limit . ' ) AS g ON u.uid = g.uid AND u.is_del = 0')->field('u.uid,u.uname,u.email')->select();
}else{
// 全站用户
$userList = model('User')->field('uid,uname,email')->where('is_del = 0')->limit($limit)->findAll();
}
// 设置sql语句
$msg_sql = "INSERT INTO " . C('DB_PREFIX') . "notify_message (uid, node, appname, title, body, ctime, is_read) VALUES ";
// $email_sql = "INSERT INTO " . C('DB_PREFIX') . "notify_email (uid, node, appname, email, is_send, title, body, ctime, sendtime) VALUES ";
$msg_sql_arr = array();
// $email_sql_arr = array();
// 设置变量
$ctime = time();
foreach ($userList as $v) {
$avatar = model('Avatar')->init($v['uid'])->getUserAvatar();
// 替换数据内容
$search = array('{uname}', '{uavatar}');
$replace = array($v['uname'], $avatar['avatar_original']);
$body = str_replace($search, $replace, $content);
// 发私信
$msg_sql_arr[] = "('" . $v['uid'] . "', 'sys_notify', 'public', '', '" . $body . "', '" . $ctime . "', '0')";
// 发邮件
// $email_sql_arr[] = "('" . $v['uid'] . "', 'sys_notify', 'public', '" . $v['email'] . "', '0', '系统群发消息', '" . $body . "', '" . $time . "', '0')";
unset($body);
}
// 添加通知
$msg_sql .= implode(',', $msg_sql_arr);
D()->execute($msg_sql);
// 添加邮件
// $email_sql .= implode(',', $email_sql_arr);
// D()->execute($email_sql);
$obj->delete();
return ture;
}
}
<?php
namespace Job\upload;
use Eduline\queue\Job;
use Job\upload\BaseUpload;
use Library\Upload\UploadCloud as Upload;
class Audio extends BaseUpload
{
/**
* 执行方法
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2018-07-29
* @return [type] [description]
*/
public function fire(Job $obj, $data)
{
// 跟文件
$filePath = $data['out_file'];
// 文件不存在,删除队列
if (!file_exists($filePath)) {
$obj->delete();
if (M('zy_video_data')->where(['transcoding_status' => 2, 'videokey' => $data['key']])->count() < 1) {
return true;
}
// 更新状态
$saveData = [
'transcoding_status' => 0,
'duration' => '00:00:00',
'filesize' => 0,
'video_address' => '',
];
// 查询是否存在
if (M('zy_video_data')->where(['videokey' => $data['key']])->count() < 1) {
// 存储数据
$transcoding_data = [
'transcoding_file_key' => $data['key'],
'transcoding_info' => json_encode($saveData),
];
M('transcoding')->add($transcoding_data);
} else {
M('zy_video_data')->where(['videokey' => $data['key']])->save($saveData);
}
return true;
}
$filesize = filesize($filePath);
// 储存空间识别
$video_type = M('zy_video_data')->where(['videokey' => $data['key']])->getField('video_type');
if (!is_numeric($video_type)) {
// 超过30次失败 直接删除
$obj->attempts() > 30 ? $obj->delete() : $obj->release(60);
return true;
}
// 当前允许: 本地 阿里云 七牛
$upload_room = $this->getUploadRoom($video_type);
if ($upload_room > 0) {
// 如果不是本地,则执行上传方法
$upload = new Upload($upload_room, false);
// 文件上传
$is_upload = $upload->putFile($filePath, basename($filePath));
} else {
$is_upload = true;
}
// 是否全部上传完成
if (!$is_upload) {
// 任务重新发布
$obj->release(60);
return false;
}
// 更新队列处理结果
$this->uploadData($data, $filePath, $upload_room, $filesize);
// 删除生成的附件
$_files = glob(str_replace('.' . $data['ext'], '.*', $filePath));
foreach ($_files as $file) {
// 如果为本地,则保留MP3文件
if ($upload_room == 0 && substr(strrchr($file, '.'), 1) == 'mp3') {
continue;
}
@unlink($file);
}
// 删除转码过程中生成的转码文件
$dirname = dirname($filePath);
$basename = basename($filePath, '.' . $data['ext']);
// 删除所有日志
$logs = glob($dirname . DS . $basename . '.*.log');
array_walk($logs, function ($del) {
@unlink($del);
});
$obj->delete();
return true;
}
/**
* 保存数据信息
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2018-07-30
* @param [type] $data [description]
* @param [type] $filePath [description]
* @return [type] [description]
*/
public function uploadData($data, $filePath, $upload_room, $filesize)
{
// 时长
$old_file = $filePath;
if (IS_WIN) {
ob_start();
$cmd = "ffmpeg -i " . $old_file . ' 2>&1';
passthru($cmd);
$info = ob_get_contents();
ob_end_clean();
if (preg_match("/Duration: (.*?), start: (.*?), bitrate: (\d*) kb\/s/", $info, $match)) {
$time = [$match[1]]; //播放时间
}
} else {
$cmd = "ffmpeg -i " . $old_file . " 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//";
exec($cmd, $time);
}
$time = explode(":", $time[0]);
$time_s = $time[0] * 3600 + $time[1] * 60 + round($time[2]); //转化为秒
$duration = $this->secToTime($time_s);
// 更新状态
$saveData = [
'transcoding_status' => 1,
'videokey' => basename($filePath),
'duration' => $duration,
'filesize' => $filesize,
'video_address' => '',
];
// 如果是本地
if ($upload_room == '0') {
$attachInfo = model('Attach')->getAttachById($data['key']);
$oldfile = str_replace(SITE_PATH, '', UPLOAD_PATH) . '/' . $attachInfo['save_path'] . $attachInfo['save_name'];
$saveData['video_address'] = str_replace(basename($oldfile), $saveData['videokey'], $oldfile);
}else{
@unlink($old_file);
}
// 查询是否存在
if (M('zy_video_data')->where(['videokey' => $data['key']])->count() < 1) {
// 存储数据
$transcoding_data = [
'transcoding_file_key' => $data['key'],
'transcoding_info' => json_encode($saveData),
];
$status = M('transcoding')->add($transcoding_data);
} else {
$status = M('zy_video_data')->where(['videokey' => $data['key']])->save($saveData);
}
return $status ? true : false;
}
/**
* 格式化时间
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2018-07-30
* @param [type] $times [description]
* @return [type] [description]
*/
public function secToTime($times)
{
$result = '00:00:00';
if ($times > 0) {
$hour = floor($times / 3600);
if ($hour < 10) {
$hour = "0" . $hour;
}
$minute = floor(($times - 3600 * $hour) / 60);
if ($minute < 10) {
$minute = "0" . $minute;
}
$second = floor((($times - 3600 * $hour) - 60 * $minute) % 60);
if ($second < 10) {
$second = "0" . $second;
}
$result = $hour . ':' . $minute . ':' . $second;
}
return $result;
}
}
<?php
namespace Job\upload;
use Eduline\queue\Job;
use Library\Upload\UploadCloud as Upload;
class BaseUpload
{
/**
* 定义可选储存类型
* @var array
*/
protected $video_types = [
'0' => '本地',
'1' => '七牛云储存',
'2' => '阿里云OSS',
'6' => '华为云OBS',
'7' => '保利威VDO',
];
/**
* 获取储存空间
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-06-02
* @param string|ingeter $video_type 当前设置的储存类型
* @return string 最终分配到的储存空间
*/
public function getUploadRoom($video_type)
{
return in_array($video_type, array_keys($this->video_types)) ? $video_type : getAppConfig('upload_room', 'basic');
}
}
<?php
namespace Job\upload;
use Eduline\queue\Job;
use Job\upload\BaseUpload;
use Library\Upload\UploadCloud as Upload;
class File extends BaseUpload
{
/**
* 储存上传后回调数据
* @var array
*/
protected $upload_data;
/**
* 执行方法
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2018-07-29
* @return [type] [description]
*/
public function fire(Job $obj, $data)
{
// 跟文件
$filePath = $data['file'];
// 文件不存在,删除队列
if (!file_exists($filePath)) {
// 已经上传完成,且已经处理,此任务重复
$obj->delete();
return true;
}
// 获取当前视频上传的储存空间
$video_type = M('zy_video_data')->where(['videokey' => $data['key']])->getField('video_type');
if (!is_numeric($video_type)) {
// 超过30次失败 直接删除
$obj->attempts() > 30 ? $obj->delete() : $obj->release(60);
return true;
}
$is_upload = false;
// 当前允许: 本地 阿里云 七牛,否则默认配置
$upload_room = $this->getUploadRoom($video_type);
if ($upload_room > 0) {
// 如果不是本地,则执行上传方法
$upload = new Upload($upload_room, false);
// 文件上传
$is_upload = $upload->putFile($filePath, basename($filePath));
if ($is_upload !== false && is_array($is_upload)) {
$this->upload_data = $is_upload;
$is_upload = true;
}
} else {
$is_upload = true;
}
// 是否全部上传完成
if (!$is_upload) {
// 任务重新发布
$obj->release(60);
return false;
}
// 更新队列处理结果
$status = $this->uploadData($data, $upload_room);
// 已经上传完毕,删除上传任务
if ($status) {
// 删除源文件
if ($upload_room != 0) {
model('Attach')->deleteAttach($data['key'], true);
}
$obj->delete();
return true;
}
}
/**
* 保存数据信息
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-04-25
* @param [type] $data [description]
* @param [type] $upload_room [description]
* @return [type] [description]
*/
public function uploadData($data, $upload_room)
{
// 源文件
$old_file = $data['file'];
//如果upload_room为7,videokey为上传的视频id
if ($upload_room == 7) {
$videokey = $this->upload_data['vid'];
} else {
$videokey = basename($old_file);
}
// 更新状态
$saveData = [
'transcoding_status' => 1,
'videokey' => $videokey,
'filesize' => filesize($old_file),
'video_address' => '',
];
if(in_array(strtolower($data['ext']),['avi','mp4','wmv','mov','mkv','flv','f4v','m4v','rmvb','3gp','rm','ts','dat','mts','vob','mpeg'])){
if (IS_WIN) {
ob_start();
$cmd = "ffmpeg -i " . $old_file . ' 2>&1';
passthru($cmd);
$info = ob_get_contents();
ob_end_clean();
if (preg_match("/Duration: (.*?), start: (.*?), bitrate: (\d*) kb\/s/", $info, $match)) {
$time = [$match[1]]; //播放时间
}
} else {
$cmd = "ffmpeg -i " . $old_file . " 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//";
exec($cmd, $time);
}
$time = explode(":", $time[0]);
$time_s = $time[0] * 3600 + $time[1] * 60 + round($time[2]); //转化为秒
$duration = $this->secToTime($time_s);
$saveData['duration'] = $duration;
}
// 如果是本地
if ($upload_room == '0') {
$attachInfo = model('Attach')->getAttachById($data['key']);
$oldfile = str_replace(SITE_PATH, '', UPLOAD_PATH) . '/' . $attachInfo['save_path'] . $attachInfo['save_name'];
$saveData['video_address'] = $oldfile;
}
// 查询是否存在
if (M('zy_video_data')->where(['videokey' => $data['key']])->count() < 1) {
// 存储数据
$transcoding_data = [
'transcoding_file_key' => $data['key'],
'transcoding_info' => json_encode($saveData),
];
$status = M('transcoding')->add($transcoding_data);
} else {
$status = M('zy_video_data')->where(['videokey' => $data['key']])->save($saveData);
}
return $status ? true : false;
}
/**
* 格式化时间
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2018-07-30
* @param [type] $times [description]
* @return [type] [description]
*/
public function secToTime($times)
{
$result = '00:00:00';
if ($times > 0) {
$hour = floor($times / 3600);
if ($hour < 10) {
$hour = "0" . $hour;
}
$minute = floor(($times - 3600 * $hour) / 60);
if ($minute < 10) {
$minute = "0" . $minute;
}
$second = floor((($times - 3600 * $hour) - 60 * $minute) % 60);
if ($second < 10) {
$second = "0" . $second;
}
$result = $hour . ':' . $minute . ':' . $second;
}
return $result;
}
}
<?php
namespace Job\upload;
use Eduline\queue\Job;
use Job\upload\BaseUpload;
use Library\Upload\UploadCloud as Upload;
class Office extends BaseUpload
{
/**
* 执行方法
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2018-07-29
* @return [type] [description]
*/
public function fire(Job $obj, $data)
{
// 文件
$filePath = $data['out_file'] ?: $data['file'];
// 文件不存在,删除队列
if (!file_exists($filePath)) {
$obj->delete();
if (M('zy_video_data')->where(['transcoding_status' => 2, 'videokey' => $data['key']])->count() < 1) {
return true;
}
// 更新状态
$saveData = [
'transcoding_status' => 0,
'duration' => '00:00:00',
'filesize' => 0,
'video_address' => '',
];
// 查询是否存在
if (M('zy_video_data')->where(['videokey' => $data['key']])->count() < 1) {
// 存储数据
$transcoding_data = [
'transcoding_file_key' => $data['key'],
'transcoding_info' => json_encode($saveData),
];
M('transcoding')->add($transcoding_data);
} else {
M('zy_video_data')->where(['videokey' => $data['key']])->save($saveData);
}
return true;
}
// 获取当前视频上传的储存空间
$video_type = M('zy_video_data')->where(['videokey' => $data['key']])->getField('video_type');
if (!is_numeric($video_type)) {
// 超过30次失败 直接删除
$obj->attempts() > 30 ? $obj->delete() : $obj->release(60);
return true;
}
// 当前允许: 本地 阿里云 七牛
$upload_room = $this->getUploadRoom($video_type);
if ($upload_room > 0) {
// 如果不是本地,则执行上传方法
$upload = new Upload($upload_room, true);
// 文件上传
$is_upload = $upload->putFile($filePath, basename($filePath));
} else {
$is_upload = true;
}
// 是否全部上传完成
if (!$is_upload) {
// 任务重新发布
$obj->release(60);
return false;
}
// 更新队列处理结果
$this->uploadData($data, $filePath, $upload_room);
// 删除生成的附件
if (substr(strrchr($data['file'], '.'), 1) != 'pdf') {
@unlink($data['file']);
}
// $_files = glob(str_replace('.' . $data['ext'], '.*', $filePath));
// foreach ($_files as $file) {
// // 如果为本地,则保留文件
// if ($upload_room == 0 && substr(strrchr($file, '.'), 1) == 'pdf') {
// continue;
// }
// @unlink($file);
// }
$obj->delete();
return true;
}
/**
* 保存数据信息
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2018-07-30
* @param [type] $data [description]
* @param [type] $filePath [description]
* @return [type] [description]
*/
public function uploadData($data, $filePath, $upload_room)
{
// 更新状态
$saveData = [
'transcoding_status' => 1,
'videokey' => basename($filePath),
'video_address' => '',
];
// 如果是本地
if ($upload_room == '0') {
$attachInfo = model('Attach')->getAttachById($data['key']);
$oldfile = str_replace(SITE_PATH, '', UPLOAD_PATH) . '/' . $attachInfo['save_path'] . $attachInfo['save_name'];
$saveData['video_address'] = str_replace(basename($oldfile), $saveData['videokey'], $oldfile);
}
// 查询是否存在
if (M('zy_video_data')->where(['videokey' => $data['key']])->count() < 1) {
// 存储数据
$transcoding_data = [
'transcoding_file_key' => $data['key'],
'transcoding_info' => json_encode($saveData),
];
$status = M('transcoding')->add($transcoding_data);
} else {
$status = M('zy_video_data')->where(['videokey' => $data['key']])->save($saveData);
}
return $status ? true : false;
}
}
<?php
namespace Job\upload;
use Eduline\queue\Job;
use Job\upload\BaseUpload;
use Library\Upload\UploadCloud as Upload;
class Video extends BaseUpload
{
/**
* 执行方法
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2018-07-29
* @return [type] [description]
*/
public function fire(Job $obj, $data)
{
// 跟文件
$filePath = $data['out_file'];
$extension = $data['ext'];
// 是否跳过上传
$skip_upload = false;
// 文件不存在,删除队列
if (!file_exists($filePath) && is_file($filePath . '.log')) {
// 可能为上传成功,但最终处理失败
$skip_upload = true;
} elseif (!file_exists($filePath)) {
// 已经上传完成,且已经处理,此任务重复
$obj->delete();
if (M('zy_video_data')->where(['transcoding_status' => 2, 'videokey' => $data['key']])->count() < 1) {
return true;
}
// 更新状态
$saveData = [
'transcoding_status' => 0,
'duration' => '00:00:00',
'filesize' => 0,
'video_address' => '',
];
// 查询是否存在
if (M('zy_video_data')->where(['videokey' => $data['key']])->count() < 1) {
// 存储数据
$transcoding_data = [
'transcoding_file_key' => $data['key'],
'transcoding_info' => json_encode($saveData),
];
M('transcoding')->add($transcoding_data);
} else {
M('zy_video_data')->where(['videokey' => $data['key']])->save($saveData);
}
return true;
}
if (!$skip_upload) {
$fileList = [];
if ($extension == 'm3u8') {
// 获取文件列表
$fileList = glob(str_replace('.m3u8', '-*.ts', $filePath));
}
// 上传文件
$fileList['bast_file'] = $filePath;
// 获取当前视频上传的储存空间
$video_type = M('zy_video_data')->where(['videokey' => $data['key']])->getField('video_type');
if (!is_numeric($video_type)) {
// 超过30次失败 直接删除
$obj->attempts() > 30 ? $obj->delete() : $obj->release(60);
return true;
}
$upload_room = $this->getUploadRoom($video_type);
if ($upload_room > 0) {
// 如果不是本地,则执行上传方法
$upload = new Upload($upload_room, true);
// 多文件上传
$fileList = $upload->putFiles($fileList, $extension);
}
} else {
$fileList = [];
}
// 是否全部上传完成
if ($upload_room > 0 && count($fileList) > 0) {
// 任务重新发布
$obj->release(60);
return false;
}
// 更新队列处理结果
$this->uploadData($data, $filePath, $upload_room);
// 删除原附件
model('Attach')->deleteAttach($data['key'], true);
// 删除转码过程中生成的转码文件
$dirname = dirname($filePath);
$basename = basename($filePath, '.' . $data['ext']);
// 删除相关附件
$dels = glob($dirname . DS . $basename . '.*');
foreach ($dels as $file) {
// 如果为本地,则保留m3u8文件以及切片文件
if ($upload_room == 0 && substr(strrchr($file, '.'), 1) == 'm3u8') {
continue;
}
@unlink($file);
}
// 删除所有日志
$logs = glob($dirname . DS . $basename . '.*.log');
array_walk($logs, function ($del) {
@unlink($del);
});
$obj->delete();
return true;
}
/**
* 格式化时间
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2018-07-30
* @param [type] $times [description]
* @return [type] [description]
*/
public function secToTime($times)
{
$result = '00:00:00';
if ($times > 0) {
$hour = floor($times / 3600);
if ($hour < 10) {
$hour = "0" . $hour;
}
$minute = floor(($times - 3600 * $hour) / 60);
if ($minute < 10) {
$minute = "0" . $minute;
}
$second = floor((($times - 3600 * $hour) - 60 * $minute) % 60);
if ($second < 10) {
$second = "0" . $second;
}
$result = $hour . ':' . $minute . ':' . $second;
}
return $result;
}
/**
* 保存数据信息
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2018-07-30
* @param [type] $data [description]
* @param [type] $filePath [description]
* @return [type] [description]
*/
public function uploadData($data, $filePath, $upload_room)
{
// 时长
$old_file = str_replace('.m3u8', '.mp4', $filePath);
if (IS_WIN) {
ob_start();
$cmd = "ffmpeg -i " . $old_file . ' 2>&1';
passthru($cmd);
$info = ob_get_contents();
ob_end_clean();
if (preg_match("/Duration: (.*?), start: (.*?), bitrate: (\d*) kb\/s/", $info, $match)) {
$time = [$match[1]]; //播放时间
}
} else {
$cmd = "ffmpeg -i " . $old_file . " 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//";
exec($cmd, $time);
}
$time = explode(":", $time[0]);
$time_s = $time[0] * 3600 + $time[1] * 60 + round($time[2]); //转化为秒
$duration = $this->secToTime($time_s);
// 更新状态
$saveData = [
'transcoding_status' => 1,
'videokey' => basename($filePath),
'duration' => $duration,
'filesize' => filesize($old_file),
'video_address' => '',
];
// 如果是本地
if ($upload_room == '0') {
$attachInfo = model('Attach')->getAttachById($data['key']);
$oldfile = str_replace(SITE_PATH, '', UPLOAD_PATH) . '/' . $attachInfo['save_path'] . $attachInfo['save_name'];
$saveData['video_address'] = str_replace(basename($oldfile), $saveData['videokey'], $oldfile);
}
// 查询是否存在
if (M('zy_video_data')->where(['videokey' => $data['key']])->count() < 1) {
// 存储数据
$transcoding_data = [
'transcoding_file_key' => $data['key'],
'transcoding_info' => json_encode($saveData),
];
$status = M('transcoding')->add($transcoding_data);
} else {
$status = M('zy_video_data')->where(['videokey' => $data['key']])->save($saveData);
}
return $status ? true : false;
}
}
<?php
namespace Job\video;
class Progress
{
/**
* 计算转码进度
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2018-07-29
* @param [type] $old_file [description]
* @param [type] $new_file [description]
* @return [type] [description]
*/
public static function getProgress($old_file, $new_file)
{
// 进度报告地址
$log_file = $new_file.'.log';
if(is_file($log_file)){
$log = file_get_contents($log_file);
// 从报告中检测是否存在处理完成字段
if(preg_match('/progress=end/',$log)){
return 100;
}
// 从进度报告中获取已经处理的时间
preg_match_all('/out_time=(\d{2}:\d{2}:\d{2})/',$log,$match);
if($match[1]){
$haddleTime = [end($match[1])];
}
}else{
// 从命令中获取
if (IS_WIN) {
ob_start();
$cmd = "ffmpeg -i " . $new_file . ' 2>&1';
passthru($cmd);
$info2 = ob_get_contents();
ob_end_clean();
if (preg_match("/Duration: (.*?), start: (.*?), bitrate: (\d*) kb\/s/", $info2, $match)) {
$haddleTime = [$match[1]]; //播放时间
}
} else {
$cmd2 = 'PATH=$PATH' . " ffmpeg -i " . $new_file . " 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//";
exec($cmd2, $haddleTime);
}
}
// 从命令中获取原视频长度
if (IS_WIN) {
ob_start();
$cmd = "ffmpeg -i " . $old_file . ' 2>&1';
passthru($cmd);
$info1 = ob_get_contents();
ob_end_clean();
if (preg_match("/Duration: (.*?), start: (.*?), bitrate: (\d*) kb\/s/", $info1, $match)) {
$totalTime = [$match[1]]; //播放时间
}
} else {
$cmd = 'PATH=$PATH' . " ffmpeg -i " . $old_file . " 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//";
exec($cmd, $totalTime);
}
$totalTime = explode(":", $totalTime[0]);
$totalTime_ss = $totalTime[0] * 3600 + $totalTime[1] * 60 + round($totalTime[2]); //转化为秒
$haddleTime = explode(":", $haddleTime[0]);
$haddleTime_ss = $haddleTime[0] * 3600 + $haddleTime[1] * 60 + round($haddleTime[2]); //转化为秒
if ($totalTime_ss == 0 || $haddleTime_ss == 0) {
$progress = 0;
}else{
$progress = ($haddleTime_ss / $totalTime_ss) * 100;
}
// 允许存在写入时间误差趋于1.
return $progress >= 99 ? 100 : $progress;
}
/**
* 等待获取文件进度
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2018-08-03
* @param [type] $old_file [description]
* @param [type] $new_file [description]
* @return [type] [description]
*/
public static function getWaitProgress($old_file, $new_file)
{
// 最大执行5次
$maxCount = 5;
$runCount = 0;
$last_progress = 0;
while ($runCount <= $maxCount) {
// 每隔6秒获取一次
sleep(6);
$progress = self::getProgress($old_file, $new_file);
// 没有处理进度
if (!$progress || $progress == $last_progress) {
$runCount++;
} elseif ($progress >= 100) {
break;
} else {
$runCount = 0;
$last_progress == $progress;
}
}
return $progress;
}
}
<?php
namespace Job\video;
use Eduline\Queue;
use Eduline\queue\Job;
use Job\video\Progress;
class Segment
{
public function fire(Job $obj, $data)
{
if (!is_file($data['file'])) {
// 删除本次任务
$obj->delete();
if (M('zy_video_data')->where(['transcoding_status' => 2, 'videokey' => $data['key']])->count() < 1) {
return true;
}
// 更新状态
$saveData = [
'transcoding_status' => 0,
'duration' => '00:00:00',
'filesize' => 0,
'video_address' => '',
];
// 查询是否存在
if (M('zy_video_data')->where(['videokey' => $data['key']])->count() < 1) {
// 存储数据
$transcoding_data = [
'transcoding_file_key' => $data['key'],
'transcoding_info' => json_encode($saveData),
];
M('transcoding')->add($transcoding_data);
} else {
M('zy_video_data')->where(['videokey' => $data['key']])->save($saveData);
}
return true;
}
// 查询进度,防止重复执行
$progress = Progress::getProgress($data['file'], $data['out_file']);
// 如果没有处理
if ($progress == 0) {
// 执行命令,添加进度报告
$log_file = $data['out_file'] . '.log';
$fpos = $data['fpos'] . ' -progress ' . $log_file;
if (IS_WIN) {
pclose(popen('start /wait /B ' . $fpos, 'r'));
} else {
$cmd = 'PATH=$PATH ' . $fpos . ' >/dev/null >/dev/null 2>/var/log/ffmpeg.log';
exec($cmd);
}
// 获取最新处理进度
$progress = Progress::getProgress($data['file'], $data['out_file']);
}
// 尝试重新获取
if ($progress < 100) {
$progress = Progress::getWaitProgress($data['file'], $data['out_file']);
}
if ($progress >= 100) {
// 删除本次任务
$obj->delete();
// 这是切片的最后异步,如果处理完成,则需要更改状态为0,并加入上传队列
Queue::push('Job\upload\Video', $data, 'upload');
return true;
} elseif ($obj->attempts() > 10) {
// 当前任务失败次数超过10次,判定为任务失败
$obj->delete();
// 查询是否存在
if (M('zy_video_data')->where(['videokey' => $data['key']])->count() < 1) {
// 存储数据
$transcoding_data = [
'transcoding_file_key' => $data['key'],
'transcoding_info' => json_encode([
'transcoding_status' => 0,
]),
];
$status = M('transcoding')->add($transcoding_data);
} else {
$status = M('zy_video_data')->where(['videokey' => $data['key']])->save(['transcoding_status' => 0]);
}
} else {
// 重新发布
$obj->release();
}
}
}
<?php
namespace Job\video;
use Eduline\Queue;
use Eduline\queue\Job;
use Job\video\Progress;
class ToMp4
{
public function fire(Job $obj, $data)
{
if (!is_file($data['file'])) {
// 删除本次任务
$obj->delete();
if (M('zy_video_data')->where(['transcoding_status' => 2, 'videokey' => $data['key']])->count() < 1) {
return true;
}
// 更新状态
$saveData = [
'transcoding_status' => 0,
'duration' => '00:00:00',
'filesize' => 0,
'video_address' => '',
];
// 查询是否存在
if (M('zy_video_data')->where(['videokey' => $data['key']])->count() < 1) {
// 存储数据
$transcoding_data = [
'transcoding_file_key' => $data['key'],
'transcoding_info' => json_encode($saveData),
];
M('transcoding')->add($transcoding_data);
} else {
M('zy_video_data')->where(['videokey' => $data['key']])->save($saveData);
}
return true;
}
// 查询进度,防止重复执行
$progress = Progress::getProgress($data['file'], $data['out_file']);
// 如果没有处理
if ($progress == 0) {
// 执行命令,添加进度报告
$log_file = $data['out_file'] . '.log';
$fpos = $data['fpos'] . ' -progress ' . $log_file;
if (IS_WIN) {
pclose(popen('start /wait /B ' . $fpos, 'r'));
} else {
// $cmd = 'PATH=$PATH ' . $fpos . ' >/dev/null >/dev/null 2>/var/log/ffmpeg.log &';
$cmd = 'PATH=$PATH ' . $fpos . ' >/dev/null >/dev/null 2>/var/log/ffmpeg.log';
exec($cmd);
}
// 获取最新处理进度
$progress = Progress::getProgress($data['file'], $data['out_file']);
}
// 尝试重新获取
if ($progress < 100) {
$progress = Progress::getWaitProgress($data['file'], $data['out_file']);
}
if ($progress >= 100) {
// 删除本次任务
$obj->delete();
// 下一步进行转码为ts
$new_outfile = str_replace('.mp4', '.ts', $data['out_file']);
// 转为ts
// $fpos = 'ffmpeg -y -i ' . $data['out_file'] . ' -vcodec copy -acodec copy -vbsf h264_mp4toannexb ' . $new_outfile;
$fpos = 'ffmpeg -y -i ' . $data['out_file'] . ' -c:v copy -c:a copy ' . $new_outfile;
$_data = array_merge($data, ['file' => $data['out_file'], 'out_file' => $new_outfile, 'ext' => 'ts', 'fpos' => $fpos]);
// 加入队列任务,任务优先级调高一级
Queue::push('Job\video\ToTs', $_data, 'video', 1);
return true;
} elseif ($obj->attempts() > 10) {
// 当前任务失败次数超过10次,判定为任务失败
$obj->delete();
// 查询是否存在
if (M('zy_video_data')->where(['videokey' => $data['key']])->count() < 1) {
// 存储数据
$transcoding_data = [
'transcoding_file_key' => $data['key'],
'transcoding_info' => json_encode([
'transcoding_status' => 0,
]),
];
$status = M('transcoding')->add($transcoding_data);
} else {
$status = M('zy_video_data')->where(['videokey' => $data['key']])->save(['transcoding_status' => 0]);
}
} else {
// 重新发布
$obj->release();
}
}
}
<?php
namespace Job\video;
use Eduline\Queue;
use Eduline\queue\Job;
use Job\video\Progress;
use Library\Mcrypt\McryptECB;
class ToTs
{
public function fire(Job $obj, $data)
{
if (!is_file($data['file'])) {
// 删除本次任务
$obj->delete();
if (M('zy_video_data')->where(['transcoding_status' => 2, 'videokey' => $data['key']])->count() < 1) {
return true;
}
// 更新状态
$saveData = [
'transcoding_status' => 0,
'duration' => '00:00:00',
'filesize' => 0,
'video_address' => '',
];
// 查询是否存在
if (M('zy_video_data')->where(['videokey' => $data['key']])->count() < 1) {
// 存储数据
$transcoding_data = [
'transcoding_file_key' => $data['key'],
'transcoding_info' => json_encode($saveData),
];
M('transcoding')->add($transcoding_data);
} else {
M('zy_video_data')->where(['videokey' => $data['key']])->save($saveData);
}
return true;
}
// 查询进度,防止重复执行
$progress = Progress::getProgress($data['file'], $data['out_file']);
// 如果没有处理
if ($progress == 0) {
// 执行命令,添加进度报告
$log_file = $data['out_file'] . '.log';
$fpos = $data['fpos'] . ' -progress ' . $log_file;
if (IS_WIN) {
pclose(popen('start /wait /B ' . $fpos, 'r'));
} else {
$cmd = 'PATH=$PATH ' . $fpos . ' >/dev/null >/dev/null 2>/var/log/ffmpeg.log';
exec($cmd);
}
// 获取最新处理进度
$progress = Progress::getProgress($data['file'], $data['out_file']);
}
// 尝试重新获取
if ($progress < 100) {
$progress = Progress::getWaitProgress($data['file'], $data['out_file']);
}
if ($progress >= 100) {
// 删除本次任务
$obj->delete();
// 下一步进行切片
$new_outfile = str_replace('.ts', '', $data['out_file']);
$fpos = 'ffmpeg -y -i ' . $data['out_file'];
$options = $this->getConfigFpos($data, $fpos);
if ($options['hls_enc']) {
// 开启了加密
$fpos = $options['fpos'] . ' -vsync 0 -max_muxing_queue_size 9999 -hls_time 10 -hls_list_size 0 -hls_enc 1 -hls_segment_filename "' . $new_outfile . '-%03d.ts" ' . $new_outfile . '.m3u8';
} else {
// 未开启加密
// $fpos = $options['fpos'] . ' -f segment -segment_list ' . $new_outfile . '.m3u8 -segment_time 10 ' . $new_outfile . '-%03d.ts';
$fpos = $options['fpos'] . ' -vsync 0 -max_muxing_queue_size 9999 -hls_time 10 -hls_list_size 0 -hls_enc 0 -hls_segment_filename "' . $new_outfile . '-%03d.ts" ' . $new_outfile . '.m3u8';
}
$fpos = str_replace('\\', '/', $fpos);
// 加入队列,切片,任务优先级调高一级
$_data = array_merge($data, ['file' => $data['out_file'], 'out_file' => $new_outfile . '.m3u8', 'ext' => 'm3u8', 'fpos' => $fpos]);
Queue::push('Job\video\Segment', $_data, 'video', 2);
return true;
} elseif ($obj->attempts() > 10) {
// 当前任务失败次数超过10次,判定为任务失败
$obj->delete();
// 查询是否存在
if (M('zy_video_data')->where(['videokey' => $data['key']])->count() < 1) {
// 存储数据
$transcoding_data = [
'transcoding_file_key' => $data['key'],
'transcoding_info' => json_encode([
'transcoding_status' => 0,
]),
];
$status = M('transcoding')->add($transcoding_data);
} else {
$status = M('zy_video_data')->where(['videokey' => $data['key']])->save(['transcoding_status' => 0]);
}
} else {
// 重新发布
$obj->release();
}
}
/**
* 获取处理命令附加参数
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2018-08-18
* @param [type] $fpos [description]
* @return [type] [description]
*/
protected function getConfigFpos($data, $fpos)
{
$config = model('Xdata')->get('classroom_AdminConfig:basic');
// 是否设置了水印
if ($config['water_open'] == 1 && $config['water_image']) {
// 图片是否存在
$water = model('Attach')->getAttachById($config['water_image']);
$water_file = UPLOAD_PATH . DS . $water['save_path'] . $water['save_name'];
if (is_file($water_file)) {
// 水印位置
$water_postion = $config['water_postion'] ?: 'NorthWest';
// 替换位置参数
switch ($water_postion) {
case 'SouthWest':
// 左下角
$water_postion = 'x=10:y=main_h-overlay_h';
break;
case 'NorthEast':
// 右上角
$water_postion = 'x=main_w-overlay_w:y=10';
break;
case 'SouthEast':
// 右下角
$water_postion = 'x=main_w-overlay_w:y=main_h-overlay_h';
break;
case 'NorthWest':
default:
//左上角
$water_postion = 'x=10:y=10';
break;
}
// 水印图片缩放比例 宽:高
// $water_size = '100:40';
// @list($width, $height, $type, $attr) = getimagesize($water_file);
// $water_size = (intval($width) && intval($height)) ? $width . ':' . $height : $water_size;
// 水印是否为gif图片
if (($water['type'] == 'image/gif')) {
// 如果为gif图片,此处需要添加附加处理命令
$fpos .= '-ignore_loop 0 -i ' . $water_file;
// 含义:使用filter_complex参数使动态水印图片附着在原视频上,且动态图片一直循环
// $fpos .= ' -filter_complex "[1:v]scale=' . $water_size . '[water];[0:v][water]overlay=shortest=1:' . $water_postion . '"';
$fpos .= ' -filter_complex "[0:v][1:v]overlay=shortest=1:' . $water_postion . '"';
} else {
// 含义:使用filter_complex参数使静态图片附着在原视频上
// $fpos .= ' -i ' . $water_file . ' -filter_complex "[1:v]scale=' . $water_size . '[water];[0:v][water]overlay=' . $water_postion . '"';
$fpos .= ' -i ' . $water_file . ' -filter_complex "[0:v][1:v]overlay=' . $water_postion . '"';
}
}
}
// 是否启用了分辨率转换
if ($config['is_transcoding']) {
$size = $config['transcoding_rate'] ?: '';
$size && $fpos .= ' -s ' . $size;
}
// 是否启用了加密
$hls_enc = 0;
if ($config['hls_enc']) {
$hls_enc = 1;
$fpos = $fpos . ' ' . $this->getHlsFpos($data);
}
return ['hls_enc' => $hls_enc, 'fpos' => $fpos];
}
/**
* 返回hls参数
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2018-08-21
* @param [type] $data [description]
* @return [type] [description]
*/
protected function getHlsFpos($data)
{
$filename = basename($data['out_file'], '.ts');
$time = time();
$hls_key = substr(md5($filename . ':' . $time), 0, 16);
$token = McryptECB::encrypt($filename . ':' . $time);
$iv = md5($time);
$_fpos = ' -hls_enc_key "' . $hls_key . '" -hls_enc_iv "' . $iv . '" -hls_enc_key_url "' . $data['website'] . '/getVideoKey/' . $token . '"';
return $_fpos;
}
}
<?php
namespace Library\BaiduAiFace;
use Eduline\ThirdService;
use Library\BaiduAiFace\exception\ConfigException;
use Library\BaiduAiFace\exception\FileNotFoundException;
use Library\BaiduAiFace\exception\ResponseException;
/**
* 百度人脸识别服务入口
*/
class Service
{
/**
* 读取的base64文件
* @var array
*/
protected static $base64file = [];
/**
* 当前操作的驱动
* @var null
*/
protected static $adapter = null;
/**
* 图片类型
* @var string
*/
protected static $imageType = 'BASE64';
/**
* 可信度最低值 [0-100],推荐80
* @var integer
*/
protected static $matchThreshold = 80;
/**
* 设置打过去操作的驱动
* @return $adapter
*/
final public static function setAdapter()
{
if (is_null(static::$adapter)) {
// 获取配置
$config = model("Xdata")->get("admin_Config:baiduaiface");
if (!$config) {
throw new ConfigException("请检测配置");
}
// 导入库
$third = new ThirdService();
$third->setPath('BaiduAiFace')->import('AipFace', [], '.php', true);
static::$adapter = new \AipFace($config['APPID'], $config['API_KEY'], $config['SECRET_KEY']);
}
return static::$adapter;
}
/**
* 获取当前操作的驱动
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-10-25
* @return
*/
final public static function getAdapter()
{
return static::setAdapter();
}
/**
* 读取文件的base64数据
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-10-25
* @param string|integer $attach_id 附件ID
* @return string
*/
public static function readFileToBase64($attach_id)
{
if (!isset(static::$base64file[$attach_id])) {
$attach = model('Attach')->getAttachById($attach_id);
$filepath = $attach ? UPLOAD_PATH . '/' . $attach['save_path'] . $attach['save_name'] : null;
if ($filepath && is_file($filepath)) {
$file_data = file_get_contents($filepath);
static::$base64file[$attach_id] = base64_encode($file_data);
} else {
throw new FileNotFoundException($attach_id . ' attach_id not found.');
}
}
return static::$base64file[$attach_id];
}
/**
* 添加人脸
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-10-25
* @param [type] $userId [description]
* @param [type] $groupId [description]
* @param string|integer $attach_id 附件ID
* @return
*/
public static function addUser($userId, $groupId = 'user', $attach_id)
{
$image = static::readFileToBase64($attach_id);
$response = static::getAdapter()->addUser($image, static::$imageType, $groupId, $userId);
return static::haddleResponse($response);
}
/**
* 获取绑定的用户ID
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-10-25
* @param string|integer $attach_id 附件ID
* @return
*/
public static function getBindUserId($attach_id, $groupId = 'user')
{
$image = static::readFileToBase64($attach_id);
$response = static::getAdapter()->search($image, static::$imageType, $groupId, ['match_threshold' => static::$matchThreshold]);
try {
$result = static::haddleResponse($response);
return $result['user_list'][0]['user_id'];
} catch (ResponseException $e) {
return 0;
}
}
/**
* 人脸认证
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-10-25
* @param string|integer $attach_id 附件ID
* @param string|integer $userId 本系统的用户ID
* @param string|integer $groupId 分配的用户组
* @return
*/
public static function faceverify($attach_id, $userId, $groupId = 'user')
{
$image = static::readFileToBase64($attach_id);
$response = static::getAdapter()->search($image, static::$imageType, $groupId, ['match_threshold' => static::$matchThreshold, 'user_id' => $userId]);
try {
$result = static::haddleResponse($response);
return $result['user_list'][0];
} catch (ResponseException $e) {
return false;
}
}
/**
* 获取用户信息
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-10-25
* @param string|integer $userId 本系统的用户ID
* @param string|integer $groupId 分配的用户组
* @return
*/
public static function getUser($userId, $groupId = 'user')
{
$result = static::getAdapter()->getUser($userId, $groupId);
return static::haddleResponse($result);
}
/**
* 检测某个用户是否存在于某个组
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-10-25
* @param string|integer $userId 本系统的用户ID
* @param string|integer $groupId 分配的用户组
* @return boolean
*/
public static function isExistUser($userId, $groupId = 'user')
{
try {
static::getUser($userId, $groupId);
return true;
} catch (ResponseException $e) {
return false;
}
}
/**
* 根据用户ID,检测人脸状态
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-10-25
* @param string|integer $userId 本系统的用户ID
* @return integer 1:已经完成 2:需要上传更多的人脸 0:不存在该人脸信息
*/
public static function getUserIdFaceStatus($userId, $groupId = 'user')
{
$response = static::getAdapter()->faceGetlist($userId, $groupId);
try {
$result = static::haddleResponse($response);
if (count($result['face_list']) < 2) {
return 2;
}
return 1;
} catch (ResponseException $e) {
return 0;
}
}
/**
* 处理返回结果
* @Author MartinSun<syh@sunyonghong.com>
* @DateTime 2017-11-17
* @param array $res 接口返回的数据
* @return array|\ResponseException
*/
private static function haddleResponse($res)
{
if ($res['error_code'] == 0) {
return $res['result'];
}
throw new ResponseException($res['error_msg'], $res['error_code']);
}
}
<?php
namespace Library\BaiduAiFace\exception;
class BaseException extends \Exception
{
protected $error_type = '系统出错';
public function getError()
{
return "错误类型:" . $this->error_type . ' 错误信息:' . $this->getMessage();
}
}
<?php
namespace Library\BaiduAiFace\exception;
use Library\BaiduAiFace\exception\BaseException;
class ConfigException extends BaseException
{
protected $error_type = '配置未指定或不合法';
}
<?php
namespace Library\BaiduAiFace\exception;
use Library\BaiduAiFace\exception\BaseException;
class FileNotFoundException extends BaseException
{
protected $error_type = '附件不存在';
}
<?php
namespace Library\BaiduAiFace\exception;
use Library\BaiduAiFace\exception\BaseException;
class ResponseException extends BaseException
{
protected $error_type = '返回错误信息';
}
<?php
namespace Library\BaiduDoc\services;
use BaiduBce\Services\Bos\BosClient;
use GuzzleHttp\Client;
use Library\BaiduDoc\utils\DateUtil;
use Library\BaiduDoc\utils\HttpUtil;
class DocService
{
protected $config;
protected $host = 'doc.bj.baidubce.com';
protected $timestamp;
protected $expirationInSeconds = 60;
public function __construct()
{
HttpUtil::__init();
// date_default_timezone_get('');
$this->timestamp = new \DateTime();
// 加载配置
$this->config = model('Xdata')->get('classroom_AdminConfig:baidudoc');
}
/**
* 注册文档
* @return array|\Psr\Http\Message\StreamInterface
*/
public function register()
{
// >> first: get authorization
$method = 'POST';
$uri = '/v2/document';
$params = ['register' => ''];
$now = $this->timestamp->setTimezone(DateUtil::$UTC_TIMEZONE);
$date = DateUtil::formatAlternateIso8601Date($now);
$authorization = $this->getAuthorization($method, $this->host, $uri, $params, $date, $this->expirationInSeconds);
// >> second: create header and body information for http request
$url = "https://{$this->host}{$uri}?register";
$head = [
"Content-Type" => "application/json",
"Authorization" => $authorization,
"x-bce-date" => $date,
];
$body = [
'title' => time(),
'format' => 'doc',
];
$client = new Client();
$response = $client->request($method, $url, [
'body' => json_encode($body),
'headers' => $head,
]);
$body = $response->getBody()->getContents();
return $body;
}
/**
* 从储存空间里发布
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-04-22
* @return [type] [description]
*/
public function registerWithBos($data)
{
$method = 'POST';
$uri = '/v2/document';
$params = ['source' => 'bos'];
$now = $this->timestamp->setTimezone(DateUtil::$UTC_TIMEZONE);
$date = DateUtil::formatAlternateIso8601Date($now);
$authorization = $this->getAuthorization($method, $this->host, $uri, $params, $date, $this->expirationInSeconds);
// >> second: create header and body information for http request
$url = "https://{$this->host}{$uri}?source=bos";
$head = [
"Content-Type" => "application/json",
"Authorization" => $authorization,
"x-bce-date" => $date,
];
$filepath = $data['file'];
$body = [
'bucket' => $this->config['bucket'],
'object' => $data['ext'] . '/' . basename($filepath),
'title' => basename($filepath),
'format' => $data['ext'],
'access' => 'PRIVATE',
];
$client = new Client();
$response = $client->request($method, $url, [
'body' => json_encode($body),
'headers' => $head,
]);
$body = $response->getBody()->getContents();
return json_decode($body,true);
}
/**
* 上传文件到储存空间
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-04-22
* @return [type] [description]
*/
public function upload($data)
{
$filepath = $data['file'];
if (!is_file($filepath)) {
return false;
}
$config = [
'credentials' => [
'accessKeyId' => $this->config['ak'],
'secretAccessKey' => $this->config['sk'],
],
'endpoint' => 'bj.bcebos.com',
];
$client = new BosClient($config);
$uploadpath = $data['ext'] . '/' . basename($filepath);
return $client->putObjectFromFile($this->config['bucket'], $uploadpath, $filepath);
}
/**
* 获取文档信息
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-04-23
* @return [type] [description]
*/
public function get($documentId)
{
$method = 'GET';
$uri = '/v2/document/'.$documentId;
$params = ['https' => 'true'];
$now = $this->timestamp->setTimezone(DateUtil::$UTC_TIMEZONE);
$date = DateUtil::formatAlternateIso8601Date($now);
$authorization = $this->getAuthorization($method, $this->host, $uri, $params, $date, $this->expirationInSeconds);
// >> second: create header and body information for http request
$url = "https://{$this->host}{$uri}?https=true";
$head = [
"Content-Type" => "application/json",
"Authorization" => $authorization,
"x-bce-date" => $date,
];
$client = new Client();
$response = $client->request($method, $url, [
'headers' => $head,
]);
$body = $response->getBody()->getContents();
return json_decode($body,true);
}
/**
* 阅读文档
* @return array|\Psr\Http\Message\StreamInterface
*/
public function read($documentId)
{
// >> first: get authorization
$method = 'GET';
$uri = '/v2/document/' . $documentId;
$params = ['read' => ''];
$this->expirationInSeconds = 3600;
$now = $this->timestamp->setTimezone(DateUtil::$UTC_TIMEZONE);
$date = DateUtil::formatAlternateIso8601Date($now);
$authorization = $this->getAuthorization($method, $this->host, $uri, $params, $date, $this->expirationInSeconds);
// >> second: create header and body information for http request
$url = "http://{$this->host}{$uri}?read";
$head = [
"Content-Type" => "application/json",
"Authorization" => $authorization,
"x-bce-date" => $date,
];
$client = new Client();
$response = $client->request($method, $url, [
'headers' => $head,
]);
$body = $response->getBody()->getContents();
return json_decode($body,true);
}
/**
* 阅读文档
* @return array|\Psr\Http\Message\StreamInterface
*/
public function createNotify($documentId)
{
// >> first: get authorization
$method = 'GET';
$uri = '/v2/notification';
$params = [];
$now = $this->timestamp->setTimezone(DateUtil::$UTC_TIMEZONE);
$date = DateUtil::formatAlternateIso8601Date($now);
$authorization = $this->getAuthorization($method, $this->host, $uri, $params, $date, $this->expirationInSeconds);
// >> second: create header and body information for http request
$url = "http://{$this->host}{$uri}";
$head = [
"Content-Type" => "application/json",
"Authorization" => $authorization,
"x-bce-date" => $date,
];
$client = new Client();
$response = $client->request($method, $url, [
'body'=>json_encode([
'name'=>'eduline_t_doc'
]),
'headers' => $head,
]);
$body = $response->getBody()->getContents();
return json_decode($body,true);
}
// 获取认证字符串
protected function getAuthorization($method, $host, $uri, $params, $date, $expirationInSeconds)
{
$authStringPrefix = "bce-auth-v1/{$this->config['ak']}/{$date}/{$expirationInSeconds}";
$signingKey = hash_hmac('SHA256', $authStringPrefix, $this->config['sk']);
$canonicalHeader1 = "host;x-bce-date";
$canonicalHeader2 = "host:{$host}\n" . "x-bce-date:" . urlencode($date);
$httpUtil = new HttpUtil();
$canonicalString = $httpUtil->getCanonicalQueryString($params);
$canonicalUri = $httpUtil->getCanonicalURIPath($uri);
$method = strtoupper($method);
$canonicalRequest = "{$method}\n{$canonicalUri}\n{$canonicalString}\n{$canonicalHeader2}";
$signature = hash_hmac('SHA256', $canonicalRequest, $signingKey);
$authorization = "bce-auth-v1/{$this->config['ak']}/{$date}/{$expirationInSeconds}/{$canonicalHeader1}/{$signature}";
return $authorization;
}
}
<?php
namespace Library\BaiduDoc\utils;
/**
* Utilities for parsing and formatting dates.
*
* <p>
* Note that this class doesn't use static methods because of the
* synchronization issues with SimpleDateFormat. This lets synchronization be
* done on a per-object level, instead of on a per-class level.
*/
class DateUtil
{
/**
* Alternate ISO 8601 format without fractional seconds
*/
const ALTERNATE_ISO8601_DATE_FORMAT = "Y-m-d\TH:i:s\Z";
/**
* @var \DateTimeZone The UTC timezone object.
*/
public static $UTC_TIMEZONE;
/**
* Initialize $UTC_TIMEZONE
*/
public static function __init()
{
DateUtil::$UTC_TIMEZONE = new \DateTimeZone("UTC");
}
/**
* Parses the specified date string as an ISO 8601 date and returns the Date
* object.
*
* @param $dateString string The date string to parse.
* @return \DateTime The parsed Date object.
* @throws \Exception If the date string could not be parsed.
*/
public static function parseAlternateIso8601Date($dateString)
{
return \DateTime::createFromFormat(
DateUtil::ALTERNATE_ISO8601_DATE_FORMAT,
$dateString,
DateUtil::$UTC_TIMEZONE
);
}
/**
* Formats the specified date as an ISO 8601 string.
*
* @param $datetime \DateTime The date to format.
* @return string The ISO 8601 string representing the specified date.
*/
public static function formatAlternateIso8601Date($datetime)
{
return $datetime->format(DateUtil::ALTERNATE_ISO8601_DATE_FORMAT);
}
/**
* Parses the specified date string as an RFC 822 date and returns the Date object.
*
* @param $dateString string The date string to parse.
* @return \DateTime The parsed Date object.
* @throws \Exception If the date string could not be parsed.
*/
public static function parseRfc822Date($dateString)
{
return \DateTime::createFromFormat(
\DateTime::RFC822,
$dateString,
DateUtil::$UTC_TIMEZONE
);
}
/**
* Formats the specified date as an RFC 822 string.
*
* @param $datetime \DateTime The date to format.
* @return string The RFC 822 string representing the specified date.
*/
public static function formatRfc822Date($datetime)
{
return $datetime->format(\DateTime::RFC822);
}
}
DateUtil::__init();
\ No newline at end of file
<?php
namespace Library\BaiduDoc\utils;
class HttpUtil
{
// 根据RFC 3986,除了:
// 1.大小写英文字符
// 2.阿拉伯数字
// 3.点'.'、波浪线'~'、减号'-'以及下划线'_'
// 以外都要编码
public static $PERCENT_ENCODED_STRINGS;
//填充编码数组
public static function __init()
{
HttpUtil::$PERCENT_ENCODED_STRINGS = array();
for ($i = 0; $i < 256; ++$i) {
HttpUtil::$PERCENT_ENCODED_STRINGS[$i] = sprintf("%%%02X", $i);
}
//a-z不编码
foreach (range('a', 'z') as $ch) {
HttpUtil::$PERCENT_ENCODED_STRINGS[ord($ch)] = $ch;
}
//A-Z不编码
foreach (range('A', 'Z') as $ch) {
HttpUtil::$PERCENT_ENCODED_STRINGS[ord($ch)] = $ch;
}
//0-9不编码
foreach (range('0', '9') as $ch) {
HttpUtil::$PERCENT_ENCODED_STRINGS[ord($ch)] = $ch;
}
//以下4个字符不编码
HttpUtil::$PERCENT_ENCODED_STRINGS[ord('-')] = '-';
HttpUtil::$PERCENT_ENCODED_STRINGS[ord('.')] = '.';
HttpUtil::$PERCENT_ENCODED_STRINGS[ord('_')] = '_';
HttpUtil::$PERCENT_ENCODED_STRINGS[ord('~')] = '~';
}
//在uri编码中不能对'/'编码
public static function urlEncodeExceptSlash($path)
{
return str_replace("%2F", "/", HttpUtil::urlEncode($path));
}
//使用编码数组编码
public static function urlEncode($value)
{
$result = '';
for ($i = 0; $i < strlen($value); ++$i) {
$result .= HttpUtil::$PERCENT_ENCODED_STRINGS[ord($value[$i])];
}
return $result;
}
//生成标准化QueryString
public static function getCanonicalQueryString(array $parameters)
{
//没有参数,直接返回空串
if (count($parameters) == 0) {
return '';
}
$parameterStrings = array();
foreach ($parameters as $k => $v) {
//跳过Authorization字段
if (strcasecmp('Authorization', $k) == 0) {
continue;
}
if (!isset($k)) {
throw new \InvalidArgumentException(
"parameter key should not be null"
);
}
if (isset($v)) {
//对于有值的,编码后放在=号两边
$parameterStrings[] = HttpUtil::urlEncode($k)
. '=' . HttpUtil::urlEncode((string) $v);
} else {
//对于没有值的,只将key编码后放在=号的左边,右边留空
$parameterStrings[] = HttpUtil::urlEncode($k) . '=';
}
}
//按照字典序排序
sort($parameterStrings);
//使用'&'符号连接它们
return implode('&', $parameterStrings);
}
//生成标准化uri
public static function getCanonicalURIPath($path)
{
//空路径设置为'/'
if (empty($path)) {
return '/';
} else {
//所有的uri必须以'/'开头
if ($path[0] == '/') {
return HttpUtil::urlEncodeExceptSlash($path);
} else {
return '/' . HttpUtil::urlEncodeExceptSlash($path);
}
}
}
//生成标准化http请求头串
public static function getCanonicalHeaders($headers)
{
//如果没有headers,则返回空串
if (count($headers) == 0) {
return '';
}
$headerStrings = array();
foreach ($headers as $k => $v) {
//跳过key为null的
if ($k === null) {
continue;
}
//如果value为null,则赋值为空串
if ($v === null) {
$v = '';
}
//trim后再encode,之后使用':'号连接起来
$headerStrings[] = HttpUtil::urlEncode(strtolower(trim($k))) . ':' . HttpUtil::urlEncode(trim($v));
}
//字典序排序
sort($headerStrings);
//用'\n'把它们连接起来
return implode("\n", $headerStrings);
}
}
<?php
namespace Library\Cache;
use Eduline\Cache;
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
defined('THINK_PATH') or exit();
/**
* Apc缓存驱动
* @category Extend
* @package Extend
* @subpackage Driver.Cache
* @author liu21st <liu21st@gmail.com>
*/
class CacheApc extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
public function __construct($options=array()) {
if(!function_exists('apc_cache_info')) {
throw_exception('不支持'.':Apc');
}
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
N('cache_read',1);
return apc_fetch($this->options['prefix'].$name);
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolen
*/
public function set($name, $value, $expire = null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$name = $this->options['prefix'].$name;
if($result = apc_store($name, $value, $expire)) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
}
return $result;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolen
*/
public function rm($name) {
return apc_delete($this->options['prefix'].$name);
}
/**
* 清除缓存
* @access public
* @return boolen
*/
public function clear() {
return apc_clear_cache();
}
}
\ No newline at end of file
<?php
class CacheBae extends Cache {
static $_cache;
private $_handler;
/**
+----------------------------------------------------------
* 架构函数
+----------------------------------------------------------
* @access public
+----------------------------------------------------------
*/
public function __construct($options='') {
if(!empty($options)) {
$this->options = $options;
}
$this->options['expire'] = isset($options['expire'])?$options['expire']:C('DATA_CACHE_TIME');
$this->options['length'] = isset($options['length'])?$options['length']:0;
$this->options['queque'] = 'bae';
$this->init();
}
/**
+----------------------------------------------------------
* 初始化检查
+----------------------------------------------------------
* @access private
+----------------------------------------------------------
* @return boolen
+----------------------------------------------------------
*/
private function init() {
$this->_handler = new BaeMemcache();
$this->connected = true;
}
/**
+----------------------------------------------------------
* 是否连接
+----------------------------------------------------------
* @access public
+----------------------------------------------------------
* @return boolen
+----------------------------------------------------------
*/
private function isConnected() {
return $this->connected;
}
/**
+----------------------------------------------------------
* 读取缓存
+----------------------------------------------------------
* @access public
+----------------------------------------------------------
* @param string $name 缓存变量名
+----------------------------------------------------------
* @return mixed
+----------------------------------------------------------
*/
public function get($name) {
N('cache_read',1);
$content = $this->_handler->get($name);
if(false !== $content ){
if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
$content = substr($content,0,-1); //remvoe \0 in the end
}
if(C('DATA_CACHE_CHECK')) {//开启数据校验
$check = substr($content,0, 32);
$content = substr($content,32);
if($check != md5($content)) {//校验错误
return false;
}
}
if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
//启用数据压缩
$content = gzuncompress($content);
}
$content = unserialize($content);
return $content;
}
else {
return false;
}
}
/**
+----------------------------------------------------------
* 写入缓存
+----------------------------------------------------------
* @access public
+----------------------------------------------------------
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param int $expire 有效时间 0为永久
+----------------------------------------------------------
* @return boolen
+----------------------------------------------------------
*/
public function set($name,$value,$expire=null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$data = serialize($value);
if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
//数据压缩
// $data = gzcompress($data,3);
$data = gzencode($data) . "\0";
}
if(C('DATA_CACHE_CHECK')) {//开启数据校验
$check = md5($data);
}else {
$check = '';
}
$data = $check.$data;
$result = $this->_handler->set($name,$data,0,intval($expire));
if($result) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return true;
}else {
return false;
}
}
/**
+----------------------------------------------------------
* 删除缓存
+----------------------------------------------------------
* @access public
+----------------------------------------------------------
* @param string $name 缓存变量名
+----------------------------------------------------------
* @return boolen
+----------------------------------------------------------
*/
public function rm($name) {
return $this->_handler->delete($name);
}
static function queueSet($name,$value)
{
$h = new BaeMemcache();
if ( $h->set($name,$value) ){
self::$_cache = array($name => $value);
}
}
static function queueGet($name)
{
if(isset(self::$_cache[$name]))
return self::$_cache[$name];
$h = new BaeMemcache();
$r = $h->get($name);
if ( false === $r ){
return false;
}
self::$_cache[$name] = $r;
return $r;
}
}
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
defined('THINK_PATH') or exit();
/**
* 数据库方式缓存驱动
* CREATE TABLE think_cache (
* cachekey varchar(255) NOT NULL,
* expire int(11) NOT NULL,
* data blob,
* datacrc int(32),
* UNIQUE KEY `cachekey` (`cachekey`)
* );
* @category Extend
* @package Extend
* @subpackage Driver.Cache
* @author liu21st <liu21st@gmail.com>
*/
class CacheDb extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
public function __construct($options=array()) {
if(empty($options)) {
$options = array (
'table' => C('DATA_CACHE_TABLE'),
);
}
$this->options = $options;
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
import('Db');
$this->handler = DB::getInstance();
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
$name = $this->options['prefix'].addslashes($name);
N('cache_read',1);
$result = $this->handler->query('SELECT `data`,`datacrc` FROM `'.$this->options['table'].'` WHERE `cachekey`=\''.$name.'\' AND (`expire` =0 OR `expire`>'.time().') LIMIT 0,1');
if(false !== $result ) {
$result = $result[0];
if(C('DATA_CACHE_CHECK')) {//开启数据校验
if($result['datacrc'] != md5($result['data'])) {//校验错误
return false;
}
}
$content = $result['data'];
if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
//启用数据压缩
$content = gzuncompress($content);
}
$content = unserialize($content);
return $content;
}
else {
return false;
}
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolen
*/
public function set($name, $value,$expire=null) {
$data = serialize($value);
$name = $this->options['prefix'].addslashes($name);
N('cache_write',1);
if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
//数据压缩
$data = gzcompress($data,3);
}
if(C('DATA_CACHE_CHECK')) {//开启数据校验
$crc = md5($data);
}else {
$crc = '';
}
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$expire = ($expire==0)?0: (time()+$expire) ;//缓存有效期为0表示永久缓存
$result = $this->handler->query('select `cachekey` from `'.$this->options['table'].'` where `cachekey`=\''.$name.'\' limit 0,1');
if(!empty($result) ) {
//更新记录
$result = $this->handler->execute('UPDATE '.$this->options['table'].' SET data=\''.$data.'\' ,datacrc=\''.$crc.'\',expire='.$expire.' WHERE `cachekey`=\''.$name.'\'');
}else {
//新增记录
$result = $this->handler->execute('INSERT INTO '.$this->options['table'].' (`cachekey`,`data`,`datacrc`,`expire`) VALUES (\''.$name.'\',\''.$data.'\',\''.$crc.'\','.$expire.')');
}
if($result) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return true;
}else {
return false;
}
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolen
*/
public function rm($name) {
$name = $this->options['prefix'].addslashes($name);
return $this->handler->execute('DELETE FROM `'.$this->options['table'].'` WHERE `cachekey`=\''.$name.'\'');
}
/**
* 清除缓存
* @access public
* @return boolen
*/
public function clear() {
return $this->handler->execute('TRUNCATE TABLE `'.$this->options['table'].'`');
}
}
\ No newline at end of file
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
defined('THINK_PATH') or exit();
/**
* Eaccelerator缓存驱动
* @category Extend
* @package Extend
* @subpackage Driver.Cache
* @author liu21st <liu21st@gmail.com>
*/
class CacheEaccelerator extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
public function __construct($options=array()) {
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
N('cache_read',1);
return eaccelerator_get($this->options['prefix'].$name);
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolen
*/
public function set($name, $value, $expire = null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$name = $this->options['prefix'].$name;
eaccelerator_lock($name);
if(eaccelerator_put($name, $value, $expire)) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return true;
}
return false;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolen
*/
public function rm($name) {
return eaccelerator_rm($this->options['prefix'].$name);
}
/**
* 清除缓存
* @access public
* @return boolen
*/
public function clear() {
return eaccelerator_clean();
}
}
\ No newline at end of file
<?php
namespace Library\Cache;
use Eduline\Cache;
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
defined('THINK_PATH') or exit();
/**
* 文件类型缓存类
* @category Think
* @package Think
* @subpackage Driver.Cache
* @author liu21st <liu21st@gmail.com>
*/
class CacheFile extends Cache {
/**
* 架构函数
* @access public
*/
public function __construct($options=array()) {
if(!empty($options)) {
$this->options = $options;
}
$this->options['temp'] = !empty($options['temp'])? $options['temp'] : C('DATA_CACHE_PATH');
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
if(substr($this->options['temp'], -1) != '/') $this->options['temp'] .= '/';
$this->init();
}
/**
* 初始化检查
* @access private
* @return boolen
*/
private function init() {
$stat = @stat($this->options['temp']);
$dir_perms = $stat['mode'] & 0007777; // Get the permission bits.
$file_perms = $dir_perms & 0000777; // Remove execute bits for files.
// // 创建项目缓存目录
// if (!is_dir($this->options['temp'])) {
// if (! mkdir($this->options['temp']))
// return false;
// chmod($this->options['temp'], $dir_perms);
// }
}
/**
* 取得变量的存储文件名
* @access private
* @param string $name 缓存变量名
* @return string
*/
private function filename($name) {
$name = md5($name);
if(C('DATA_CACHE_SUBDIR')) {
// 使用子目录
$dir ='';
for($i=0;$i<C('DATA_PATH_LEVEL');$i++) {
$dir .= $name{$i}.'/';
}
if(!is_dir($this->options['temp'].$dir)) {
mkdir($this->options['temp'].$dir,0777,true);
}
$filename = $dir.$this->options['prefix'].$name.'.php';
}else{
$filename = $this->options['prefix'].$name.'.php';
}
return $this->options['temp'].$filename;
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
$filename = $this->filename($name);
if (!is_file($filename)) {
return false;
}
N('cache_read',1);
$content = file_get_contents($filename);
if( false !== $content) {
$expire = (int)substr($content,8, 12);
if($expire != 0 && time() > filemtime($filename) + $expire) {
//缓存过期删除缓存文件
unlink($filename);
return false;
}
if(C('DATA_CACHE_CHECK')) {//开启数据校验
$check = substr($content,20, 32);
$content = substr($content,52, -3);
if($check != md5($content)) {//校验错误
return false;
}
}else {
$content = substr($content,20, -3);
}
if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
//启用数据压缩
$content = gzuncompress($content);
}
$content = unserialize($content);
return $content;
}
else {
return false;
}
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param int $expire 有效时间 0为永久
* @return boolen
*/
public function set($name,$value,$expire=null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$filename = $this->filename($name);
$data = serialize($value);
if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
//数据压缩
$data = gzcompress($data,3);
}
if(C('DATA_CACHE_CHECK')) {//开启数据校验
$check = md5($data);
}else {
$check = '';
}
$data = "<?php\n//".sprintf('%012d',$expire).$check.$data."\n?>";
$result = file_put_contents($filename,$data);
if($result) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
clearstatcache();
return true;
}else {
return false;
}
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolen
*/
public function rm($name) {
if(file_exists($this->filename($name)))
return unlink($this->filename($name));
}
/**
* 清除缓存
* @access public
* @param string $name 缓存变量名
* @return boolen
*/
public function clear() {
$path = $this->options['temp'];
if ( $dir = opendir( $path ) ) {
while ( $file = readdir( $dir ) ) {
$check = is_dir( $file );
if ( !$check )
unlink( $path . $file );
}
closedir( $dir );
return true;
}
}
}
\ No newline at end of file
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
defined('THINK_PATH') or exit();
/**
* Memcache缓存驱动
* @category Extend
* @package Extend
* @subpackage Driver.Cache
* @author liu21st <liu21st@gmail.com>
*/
class CacheMemcache extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
function __construct($options=array()) {
if ( !extension_loaded('memcache') ) {
throw_exception('不支持'.':memcache');
}
if(empty($options)) {
$options = array (
'host' => C('MEMCACHE_HOST') ? C('MEMCACHE_HOST') : '127.0.0.1',
'port' => C('MEMCACHE_PORT') ? C('MEMCACHE_PORT') : 11211,
'timeout' => C('DATA_CACHE_TIMEOUT') ? C('DATA_CACHE_TIMEOUT') : false,
'persistent' => false,
);
}
$this->options = $options;
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
$func = $options['persistent'] ? 'pconnect' : 'connect';
$this->handler = new Memcache;
$options['timeout'] === false ?
$this->handler->$func($options['host'], $options['port']) :
$this->handler->$func($options['host'], $options['port'], $options['timeout']);
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
N('cache_read',1);
return $this->handler->get($this->options['prefix'].$name);
}
/**
* 批量读取缓存
* @access public
* @param string $prefix 缓存前缀
* @return mixed
*/
public function getMulti( $prefix , $key ){
N('cache_read',1);
foreach( $key as $k=>$v ){
$namelist[] = $this->options['prefix'].$prefix.$v;
}
$result = $this->handler->get ( $namelist );
foreach ( $result as $k=>$v){
$k = str_replace( $this->options['prefix'].$prefix , '', $k );
$data[ $k ] = $v;
}
unset( $result );
return $data;
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolen
*/
public function set($name, $value, $expire = null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$name = $this->options['prefix'].$name;
if($this->handler->set($name, $value, 0, $expire)) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return true;
}
return false;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolen
*/
public function rm($name, $ttl = false) {
$name = $this->options['prefix'].$name;
return $ttl === false ?
$this->handler->delete($name) :
$this->handler->delete($name, $ttl);
}
/**
* 清除缓存
* @access public
* @return boolen
*/
public function clear() {
return $this->handler->flush();
}
}
\ No newline at end of file
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
defined('THINK_PATH') or exit();
/**
* Redis缓存驱动
* 要求安装phpredis扩展:https://github.com/nicolasff/phpredis
* @category Extend
* @package Extend
* @subpackage Driver.Cache
* @author 尘缘 <130775@qq.com>
*/
class CacheRedis extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
public function __construct($options=array()) {
if ( !extension_loaded('redis') ) {
throw_exception('不支持'.':redis');
}
if(empty($options)) {
$options = array (
'host' => C('REDIS_HOST') ? C('REDIS_HOST') : '127.0.0.1',
'port' => C('REDIS_PORT') ? C('REDIS_PORT') : 6379,
'timeout' => C('DATA_CACHE_TIMEOUT') ? C('DATA_CACHE_TIMEOUT') : false,
'persistent' => false,
);
}
$this->options = $options;
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
$func = $options['persistent'] ? 'pconnect' : 'connect';
$this->handler = new Redis;
$options['timeout'] === false ?
$this->handler->$func($options['host'], $options['port']) :
$this->handler->$func($options['host'], $options['port'], $options['timeout']);
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
N('cache_read',1);
return $this->handler->get($this->options['prefix'].$name);
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolen
*/
public function set($name, $value, $expire = null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$name = $this->options['prefix'].$name;
if(is_int($expire)) {
$result = $this->handler->setex($name, $expire, $value);
}else{
$result = $this->handler->set($name, $value);
}
if($result && $this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return $result;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolen
*/
public function rm($name) {
return $this->handler->delete($this->options['prefix'].$name);
}
/**
* 清除缓存
* @access public
* @return boolen
*/
public function clear() {
return $this->handler->flushDB();
}
}
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
defined('THINK_PATH') or exit();
/**
* Wincache缓存驱动
* @category Extend
* @package Extend
* @subpackage Driver.Cache
* @author liu21st <liu21st@gmail.com>
*/
class CacheWincache extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
public function __construct($options=array()) {
if ( !function_exists('wincache_ucache_info') ) {
throw_exception('不支持'.':WinCache');
}
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
N('cache_read',1);
$name = $this->options['prefix'].$name;
return wincache_ucache_exists($name)? wincache_ucache_get($name) : false;
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolen
*/
public function set($name, $value,$expire=null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$name = $this->options['prefix'].$name;
if(wincache_ucache_set($name, $value, $expire)) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return true;
}
return false;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolen
*/
public function rm($name) {
return wincache_ucache_delete($this->options['prefix'].$name);
}
/**
* 清除缓存
* @access public
* @return boolen
*/
public function clear() {
return wincache_ucache_clear();
}
}
\ No newline at end of file
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
defined('THINK_PATH') or exit();
/**
* Xcache缓存驱动
* @category Extend
* @package Extend
* @subpackage Driver.Cache
* @author liu21st <liu21st@gmail.com>
*/
class CacheXcache extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
public function __construct($options=array()) {
if ( !function_exists('xcache_info') ) {
throw_exception('不支持'.':Xcache');
}
$this->options['expire'] = isset($options['expire'])?$options['expire']:C('DATA_CACHE_TIME');
$this->options['prefix'] = isset($options['prefix'])?$options['prefix']:C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])?$options['length']:0;
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
N('cache_read',1);
$name = $this->options['prefix'].$name;
if (xcache_isset($name)) {
return xcache_get($name);
}
return false;
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolen
*/
public function set($name, $value,$expire=null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'] ;
}
$name = $this->options['prefix'].$name;
if(xcache_set($name, $value, $expire)) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return true;
}
return false;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolen
*/
public function rm($name) {
return xcache_unset($this->options['prefix'].$name);
}
/**
* 清除缓存
* @access public
* @return boolen
*/
public function clear() {
return xcache_clear_cache(XC_TYPE_VAR, 0);
}
}
\ No newline at end of file
<?php
namespace Library\Mcrypt;
/**
* Mcrypt_ECB 加密,兼容支持多端
*/
class McryptECB
{
public static $time;
/**
* 加密方法
* @Author MartinSun<syh@sunyonghong.com>
* @DateTime 2018-01-17
* @param string $str 待加密字符串
* @return string
*/
public static function encrypt($str, $key = null)
{
// 设置加密key
if ($key === null) {
$key = C('SECURE_CODE');
}
$key_length = strlen($key);
if ($key_length < 16) {
$key = str_pad($key, 16, "0", STR_PAD_LEFT);
} elseif ($key_length > 16) {
$key = substr($key, 0, 16);
}
//加密数据 RIJNDAEL_128
$str = trim($str);
// $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND);
self::$time = time();
// $encrypt_str = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, self::$time . '|' . $str, MCRYPT_MODE_ECB, $iv);
$str = self::$time . '|' . $str;
$size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$str = self::pkcs5_pad($str, $size);
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$encrypt_str = mcrypt_generic($td, $str);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
// $data = $this->base64url_encode($data);
// return $data;
return str_replace(['+', '/'], ['-', '_'], base64_encode($encrypt_str));
}
/**
* 解密方法
* @Author MartinSun<syh@sunyonghong.com>
* @DateTime 2018-01-17
* @param string $str 待解密字符串
* @return string
*/
public static function decrypt($str, $key = null)
{
if ($key === null) {
$key = C('SECURE_CODE');
}
$key_length = strlen($key);
if ($key_length < 16) {
$key = str_pad($key, 16 - $key_length, "0", STR_PAD_LEFT);
} elseif ($key_length > 16) {
$key = substr($key, 0, 16);
}
//AES, 128 模式加密数据 CBC
$str = base64_decode(str_replace(['-', '_'], ['+', '/'], $str));
// $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND);
// $encrypt_str = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_ECB, $iv);
//
$encrypt_str = mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
//$sKey,
$key,
//base64_decode($sStr),
$str,
//$sStr,
MCRYPT_MODE_ECB
);
// $encrypt_str = trim($encrypt_str);
$dec_s = strlen($encrypt_str);
$padding = ord($encrypt_str[$dec_s - 1]);
$encrypt_str = substr($encrypt_str, 0, -$padding);
//return $decrypted;
@list($time, $encrypt_str) = explode('|', $encrypt_str);
return $encrypt_str;
}
public static function pkcs5_pad($text, $blocksize)
{
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
/*
* 去掉填充的字符
*/
public static function trimEnd($text)
{
$len = strlen($text);
$c = $text[$len - 1];
if (ord($c) == 0) {
return rtrim($text, $c);
}
if (ord($c) < $len) {
for ($i = $len - ord($c); $i < $len; $i++) {
if ($text[$i] != $c) {
return $text;
}
}
return substr($text, 0, $len - ord($c));
}
return $text;
}
}
<?php
namespace Library\Pay;
use Library\Pay\interfaces\PayInterface;
class Service
{
protected static $serviceNames = [
'wxpay' => 'Wx',
'alipay' => 'Ali',
];
/**
* 储存当前服务接口
* @var null
*/
protected static $service = null;
/**
* 初始化实例
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-06-02
* @param string $service_type 类型
* @param string $service_name 服务商名称
*/
protected static function _initService($service_type, $service_name,$from ='web')
{
if (!self::isService() && array_key_exists($service_name, self::$serviceNames)) {
$service_class = 'Library\\Pay\\services\\' . strtolower($service_type) . '\\' . ucfirst(self::$serviceNames[$service_name]) . 'pay';
if (class_exists($service_class)) {
$service = new $service_class();
// 调用短信初始化方法
$service->init($from);
self::$service = $service;
} else {
self::$service = null;
}
}
}
/**
* 检测当前接口服务类是否可用
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-06-02
* @return boolean [description]
*/
public static function isService()
{
return self::$service instanceof PayInterface;
}
/**
* 获取服务
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-06-17
* @param string $service_type 类型
* @param string $service_name 服务商名称
* @return
*/
public static function getService($service_type, $service_name,$from = 'web')
{
if (!self::isService()) {
self::_initService($service_type, $service_name,$from);
}
return self::$service;
}
/**
* 提交请求
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-06-17
* @param array $post_data 提交数据
* @param string $service_type 类型
* @param string $service_name 服务商名称
* @param string $from 来源,可选'web':使用公众平台商户,'app':使用APP商户
* @return boolean|response object
*/
public static function send($post_data, $service_type, $service_name,$from = 'web')
{
if (!$service_type || !$service_name) {
return false;
}
try {
$service = self::getService($service_type, $service_name,$from);
return $service->pay($post_data);
} catch (\Exception $e) {
return false;
}
}
}
<?php
namespace Library\Pay\interfaces;
/**
* 短信接口类
*/
interface PayInterface
{
/**
* 初始化方法 用于初始化配置
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-06-14
* @return [type] [description]
*/
public function init();
public function pay(array $post_data);
}
<?php
namespace Library\Pay\resolver;
use Library\Pay\interfaces\PayInterface;
/**
* 短信接口类
*/
abstract class PayResolver implements PayInterface
{
/**
* 配置信息
* @var array
*/
protected $config = [];
/**
* 获取配置
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-06-02
* @param string $name 配置名称
* @param any $default 默认值
* @return string|null
*/
public function getConfig($name = null,$default = null)
{
if ($name !== null) {
return isset($this->config[$name]) ? $this->config[$name] : $default;
}
return $this->config;
}
/**
* 设置配置信息
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-06-02
* @param string|array $name 配置名称或数组批量配置
*/
public function setConfig($name, $value = null)
{
if (is_array($name)) {
$this->config = array_merge($this->config, $name);
} else {
$this->config[$name] = $value;
}
}
}
<?php
namespace Library\Pay\services\merchant;
use Eduline\ThirdService;
use Library\Pay\resolver\PayResolver;
/**
* 阿里云短信服务
*/
class Alipay extends PayResolver
{
private $aop;
private $request;
/**
* 初始化配置
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-06-02
* @return [type] [description]
*/
public function init()
{
// 初始化配置
$this->setConfig('sign_type', strtoupper('RSA2'));
$conf = unserialize(M('system_data')->where("`list`='admin_Config' AND `key`='alipay'")->getField('value'));
$this->setConfig([
'app_id' => $conf['app_id'],
'private_key_path' => $conf['private_key'],
'ali_public_key_path' => $conf['public_key'],
]);
//初始化类
$thirdService = new \Eduline\ThirdService();
$thirdService->setPath('pay/alipay');
$thirdService->import('AopClient', ['request.AlipayFundTransToaccountTransferRequest']);
$aop = new \AopClient();
$aop->appId = $this->getConfig('app_id');
$aop->rsaPrivateKey = $this->getConfig('private_key_path');
$aop->format = "json";
$aop->charset = "UTF-8";
$aop->apiVersion = '1.0';
$aop->signType = $this->getConfig('sign_type', strtoupper('RSA2'));
$aop->alipayrsaPublicKey = $this->getConfig('ali_public_key_path');
$this->aop = $aop;
$this->request = new \AlipayFundTransToaccountTransferRequest();
}
/**
* 发送接口
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-06-02
* @param [type] $phoneNumbers [description]
* @param string $code [description]
* @param [type] $config [description]
* @return [type] [description]
*/
public function pay(array $post_data)
{
// 获取转账测试开关
$tpay_switch = model('Xdata')->get("admin_Config:payConfig");
if ($tpay_switch['swn_switch']) {
$post_data['amount'] = '0.1'; //(string)测试转账金额
}
try {
$post_data['subject'] = mStr($post_data['subject'], 20); //防止参数过长
$post_data['body'] = mStr($post_data['body'], 20); //防止参数过长
$this->request->setBizContent(json_encode($post_data));
$result = $this->aop->execute($this->request);
// 获取返回状态
$responseNode = 'alipay_fund_trans_toaccount_transfer_response';
$resultCode = $result->$responseNode->code;
if (!empty($resultCode) && $resultCode == 10000) {
return $result->$responseNode;
}
} catch (\Exception $e) {
}
return false;
}
}
<?php
namespace Library\Pay\services\merchant;
use EasyWeChat\Foundation\Application;
use Library\Pay\resolver\PayResolver;
/**
* 阿里云短信服务
*/
class Wxpay extends PayResolver
{
private $app;
private $request;
/**
* 初始化配置
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-06-02
* @return [type] [description]
*/
public function init($from = 'web')
{
// 初始化配置
$this->app = new Application($this->getWxpayConfig($from));
$this->request = $this->app->merchant_pay;
}
/**
* 发送接口
* @Author Martinsun<syh@sunyonghong.com>
* @DateTime 2019-06-02
* @param [type] $phoneNumbers [description]
* @param string $code [description]
* @param [type] $config [description]
* @return [type] [description]
*/
public function pay(array $post_data)
{
// $wx_config = model('Xdata')->get('admin_Config:weixin');
// 获取转账测试开关
$tpay_switch = model('Xdata')->get("admin_Config:payConfig");
if ($tpay_switch['swn_switch']) {
$post_data['amount'] = 30; //单位为分
}
$post_data['spbill_create_ip'] = get_client_ip();
try {
$result = $this->request->send($post_data);
$result = $result->toArray();
if ($result['result_code'] == 'SUCCESS') {
return $result;
}
} catch (\Exception $e) {
}
return false;
}
/**
* 获取微信支付配置
*/
private function getWxpayConfig($from)
{
$pageKeyData = model('Xdata')->get('admin_Config:wxpay');
// 非web类型,使用APP商户信息
if ($from == 'app') {
$pageKeyData['apiclient_cert'] = array_filter(explode('|', $pageKeyData['apiclient_cert_ids']))[1];
$pageKeyData['apiclient_key'] = array_filter(explode('|', $pageKeyData['apiclient_key_ids']))[1];
$apiclient_cert = model('Attach')->getFilePath($pageKeyData['apiclient_cert']);
$apiclient_key = model('Attach')->getFilePath($pageKeyData['apiclient_key']);
$options = [
'app_id' => "{$pageKeyData['APPID']}",
// ...
// payment
'payment' => [
'merchant_id' => $pageKeyData['MCHID'], //商户号
'key' => $pageKeyData['KEY'], //md5加密key
'cert_path' => $apiclient_cert, // 私钥: 绝对路径!!!!
'key_path' => $apiclient_key, // 公钥: 绝对路径!!!!
],
];
} else {
$pageKeyData['mp_apiclient_cert'] = array_filter(explode('|', $pageKeyData['mp_apiclient_cert_ids']))[1];
$pageKeyData['mp_apiclient_key'] = array_filter(explode('|', $pageKeyData['mp_apiclient_key_ids']))[1];
$mp_apiclient_cert = model('Attach')->getFilePath($pageKeyData['mp_apiclient_cert']);
$mp_apiclient_key = model('Attach')->getFilePath($pageKeyData['mp_apiclient_key']);
$options = [
'app_id' => "{$pageKeyData['mp_appid']}",
// ...
// payment
'payment' => [
'merchant_id' => $pageKeyData['mp_mchid'], //商户号
'key' => $pageKeyData['mp_api_key'], //md5加密key
'cert_path' => $mp_apiclient_cert, // 私钥: 绝对路径!!!!
'key_path' => $mp_apiclient_key, // 公钥: 绝对路径!!!!
],
];
}
return $options;
}
}
<?php
namespace Library\Phpthumb;
/**
* PhpThumb Library Definition File
*
* This file contains the definitions for the PhpThumb class.
*
* PHP Version 5 with GD 2.0+
* PhpThumb : PHP Thumb Library <http://phpthumb.gxdlabs.com>
* Copyright (c) 2009, Ian Selby/Gen X Design
*
* Author(s): Ian Selby <ian@gen-x-design.com>
*
* Licensed under the MIT License
* Redistributions of files must retain the above copyright notice.
*
* @author Ian Selby <ian@gen-x-design.com>
* @copyright Copyright (c) 2009 Gen X Design
* @link http://phpthumb.gxdlabs.com
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
* @version 3.0
* @package PhpThumb
* @filesource
*/
/**
* PhpThumb Object
*
* This singleton object is essentially a function library that helps with core validation
* and loading of the core classes and plugins. There isn't really any need to access it directly,
* unless you're developing a plugin and need to take advantage of any of the functionality contained
* within.
*
* If you're not familiar with singleton patterns, here's how you get an instance of this class (since you
* can't create one via the new keyword):
* <code>$pt = PhpThumb::getInstance();</code>
*
* It's that simple! Outside of that, there's no need to modify anything within this class, unless you're doing
* some crazy customization... then knock yourself out! :)
*
* @package PhpThumb
* @subpackage Core
*/
class PhpThumb
{
/**
* Instance of self
*
* @var object PhpThumb
*/
protected static $_instance;
/**
* The plugin registry
*
* This is where all plugins to be loaded are stored. Data about the plugin is
* provided, and currently consists of:
* - loaded: true/false
* - implementation: gd/imagick/both
*
* @var array
*/
protected $_registry;
/**
* What implementations are available
*
* This stores what implementations are available based on the loaded
* extensions in PHP, NOT whether or not the class files are present.
*
* @var array
*/
protected $_implementations;
/**
* Returns an instance of self
*
* This is the usual singleton function that returns / instantiates the object
*
* @return PhpThumb
*/
public static function getInstance ()
{
if(!(self::$_instance instanceof self))
{
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Class constructor
*
* Initializes all the variables, and does some preliminary validation / checking of stuff
*
*/
private function __construct ()
{
$this->_registry = array();
$this->_implementations = array('gd' => false, 'imagick' => false);
$this->getImplementations();
}
/**
* Finds out what implementations are available
*
* This function loops over $this->_implementations and validates that the required extensions are loaded.
*
* I had planned on attempting to load them dynamically via dl(), but that would provide more overhead than I
* was comfortable with (and would probably fail 99% of the time anyway)
*
*/
private function getImplementations ()
{
foreach($this->_implementations as $extension => $loaded)
{
if($loaded)
{
continue;
}
if(extension_loaded($extension))
{
$this->_implementations[$extension] = true;
}
}
}
/**
* Returns whether or not $implementation is valid (available)
*
* If 'all' is passed, true is only returned if ALL implementations are available.
*
* You can also pass 'n/a', which always returns true
*
* @return bool
* @param string $implementation
*/
public function isValidImplementation ($implementation)
{
if ($implementation == 'n/a')
{
return true;
}
if ($implementation == 'all')
{
foreach ($this->_implementations as $imp => $value)
{
if ($value == false)
{
return false;
}
}
return true;
}
if (array_key_exists($implementation, $this->_implementations))
{
return $this->_implementations[$implementation];
}
return false;
}
/**
* Registers a plugin in the registry
*
* Adds a plugin to the registry if it isn't already loaded, and if the provided
* implementation is valid. Note that you can pass the following special keywords
* for implementation:
* - all - Requires that all implementations be available
* - n/a - Doesn't require any implementation
*
* When a plugin is added to the registry, it's added as a key on $this->_registry with the value
* being an array containing the following keys:
* - loaded - whether or not the plugin has been "loaded" into the core class
* - implementation - what implementation this plugin is valid for
*
* @return bool
* @param string $pluginName
* @param string $implementation
*/
public function registerPlugin ($pluginName, $implementation)
{
if (!array_key_exists($pluginName, $this->_registry) && $this->isValidImplementation($implementation))
{
$this->_registry[$pluginName] = array('loaded' => false, 'implementation' => $implementation);
return true;
}
return false;
}
/**
* Loads all the plugins in $pluginPath
*
* All this function does is include all files inside the $pluginPath directory. The plugins themselves
* will not be added to the registry unless you've properly added the code to do so inside your plugin file.
*
* @param string $pluginPath
*/
public function loadPlugins ($pluginPath)
{
// strip the trailing slash if present
if (substr($pluginPath, strlen($pluginPath) - 1, 1) == '/')
{
$pluginPath = substr($pluginPath, 0, strlen($pluginPath) - 1);
}
if ($handle = opendir($pluginPath))
{
while (false !== ($file = readdir($handle)))
{
if ($file == '.' || $file == '..' || $file == '.svn')
{
continue;
}
include_once($pluginPath . '/' . $file);
}
}
}
/**
* Returns the plugin registry for the supplied implementation
*
* @return array
* @param string $implementation
*/
public function getPluginRegistry ($implementation)
{
$returnArray = array();
foreach ($this->_registry as $plugin => $meta)
{
if ($meta['implementation'] == 'n/a' || $meta['implementation'] == $implementation)
{
$returnArray[$plugin] = $meta;
}
}
return $returnArray;
}
}
# PHP Thumb
PHP Thumb is a light-weight image manipulation library
aimed at thumbnail generation. It features the ability to
resize by width, height, and percentage, create custom crops,
or square crops from the center, and rotate the image. You can
also easily add custom functionality to the library through plugins.
It also features the ability to perform multiple manipulations per
instance (also known as chaining), without the need to save and
re-initialize the class with every manipulation.
More information and documentation is available at the project's
homepage: [http://phpthumb.gxdlabs.com](http://phpthumb.gxdlabs.com)
<?php
namespace Library\Phpthumb;
/**
* PhpThumb Base Class Definition File
*
* This file contains the definition for the ThumbBase object
*
* PHP Version 5 with GD 2.0+
* PhpThumb : PHP Thumb Library <http://phpthumb.gxdlabs.com>
* Copyright (c) 2009, Ian Selby/Gen X Design
*
* Author(s): Ian Selby <ian@gen-x-design.com>
*
* Licensed under the MIT License
* Redistributions of files must retain the above copyright notice.
*
* @author Ian Selby <ian@gen-x-design.com>
* @copyright Copyright (c) 2009 Gen X Design
* @link http://phpthumb.gxdlabs.com
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
* @version 3.0
* @package PhpThumb
* @filesource
*/
/**
* ThumbBase Class Definition
*
* This is the base class that all implementations must extend. It contains the
* core variables and functionality common to all implementations, as well as the functions that
* allow plugins to augment those classes.
*
* @package PhpThumb
* @subpackage Core
*/
abstract class ThumbBase
{
/**
* All imported objects
*
* An array of imported plugin objects
*
* @var array
*/
protected $imported;
/**
* All imported object functions
*
* An array of all methods added to this class by imported plugin objects
*
* @var array
*/
protected $importedFunctions;
/**
* The last error message raised
*
* @var string
*/
protected $errorMessage;
/**
* Whether or not the current instance has any errors
*
* @var bool
*/
protected $hasError;
/**
* The name of the file we're manipulating
*
* This must include the path to the file (absolute paths recommended)
*
* @var string
*/
protected $fileName;
/**
* What the file format is (mime-type)
*
* @var string
*/
protected $format;
/**
* Whether or not the image is hosted remotely
*
* @var bool
*/
protected $remoteImage;
/**
* Whether or not the current image is an actual file, or the raw file data
*
* By "raw file data" it's meant that we're actually passing the result of something
* like file_get_contents() or perhaps from a database blob
*
* @var bool
*/
protected $isDataStream;
/**
* Class constructor
*
* @return ThumbBase
*/
public function __construct ($fileName, $isDataStream = false)
{
$this->imported = array();
$this->importedFunctions = array();
$this->errorMessage = null;
$this->hasError = false;
$this->fileName = $fileName;
$this->remoteImage = false;
$this->isDataStream = $isDataStream;
$this->fileExistsAndReadable();
}
/**
* Imports plugins in $registry to the class
*
* @param array $registry
*/
public function importPlugins ($registry)
{
foreach ($registry as $plugin => $meta)
{
$this->imports($plugin);
}
}
/**
* Imports a plugin
*
* This is where all the plugins magic happens! This function "loads" the plugin functions, making them available as
* methods on the class.
*
* @param string $object The name of the object to import / "load"
*/
protected function imports ($object)
{
// the new object to import
$className = 'Library\\Phpthumb\\ThumbPlugins\\'.$object;
echo $className;
$newImport = new $className();
// the name of the new object (class name)
$importName = get_class($newImport);
// the new functions to import
$importFunctions = get_class_methods($newImport);
// add the object to the registry
array_push($this->imported, array($importName, $newImport));
// add the methods to the registry
foreach ($importFunctions as $key => $functionName)
{
$this->importedFunctions[$functionName] = &$newImport;
}
}
/**
* Checks to see if $this->fileName exists and is readable
*
*/
protected function fileExistsAndReadable ()
{
if ($this->isDataStream === true)
{
return;
}
if (stristr($this->fileName, 'http://') !== false)
{
$this->remoteImage = true;
return;
}
if (!file_exists($this->fileName))
{
$this->triggerError('Image file not found: ' . $this->fileName);
}
elseif (!is_readable($this->fileName))
{
$this->triggerError('Image file not readable: ' . $this->fileName);
}
}
/**
* Sets $this->errorMessage to $errorMessage and throws an exception
*
* Also sets $this->hasError to true, so even if the exceptions are caught, we don't
* attempt to proceed with any other functions
*
* @param string $errorMessage
*/
protected function triggerError ($errorMessage)
{
$this->hasError = true;
$this->errorMessage = $errorMessage;
throw new \Exception ($errorMessage);
}
/**
* Calls plugin / imported functions
*
* This is also where a fair amount of plugins magaic happens. This magic method is called whenever an "undefined" class
* method is called in code, and we use that to call an imported function.
*
* You should NEVER EVER EVER invoke this function manually. The universe will implode if you do... seriously ;)
*
* @param string $method
* @param array $args
*/
public function __call ($method, $args)
{
if( array_key_exists($method, $this->importedFunctions))
{
$args[] = $this;
return call_user_func_array(array($this->importedFunctions[$method], $method), $args);
}
throw new BadMethodCallException ('Call to undefined method/class function: ' . $method);
}
/**
* Returns $imported.
* @see ThumbBase::$imported
* @return array
*/
public function getImported ()
{
return $this->imported;
}
/**
* Returns $importedFunctions.
* @see ThumbBase::$importedFunctions
* @return array
*/
public function getImportedFunctions ()
{
return $this->importedFunctions;
}
/**
* Returns $errorMessage.
*
* @see ThumbBase::$errorMessage
*/
public function getErrorMessage ()
{
return $this->errorMessage;
}
/**
* Sets $errorMessage.
*
* @param object $errorMessage
* @see ThumbBase::$errorMessage
*/
public function setErrorMessage ($errorMessage)
{
$this->errorMessage = $errorMessage;
}
/**
* Returns $fileName.
*
* @see ThumbBase::$fileName
*/
public function getFileName ()
{
return $this->fileName;
}
/**
* Sets $fileName.
*
* @param object $fileName
* @see ThumbBase::$fileName
*/
public function setFileName ($fileName)
{
$this->fileName = $fileName;
}
/**
* Returns $format.
*
* @see ThumbBase::$format
*/
public function getFormat ()
{
return $this->format;
}
/**
* Sets $format.
*
* @param object $format
* @see ThumbBase::$format
*/
public function setFormat ($format)
{
$this->format = $format;
}
/**
* Returns $hasError.
*
* @see ThumbBase::$hasError
*/
public function getHasError ()
{
return $this->hasError;
}
/**
* Sets $hasError.
*
* @param object $hasError
* @see ThumbBase::$hasError
*/
public function setHasError ($hasError)
{
$this->hasError = $hasError;
}
}
<?php
namespace Library\Phpthumb;
use Library\Phpthumb\PhpThumb;
/**
* PhpThumb Library Definition File
*
* This file contains the definitions for the PhpThumbFactory class.
* It also includes the other required base class files.
*
* If you've got some auto-loading magic going on elsewhere in your code, feel free to
* remove the include_once statements at the beginning of this file... just make sure that
* these files get included one way or another in your code.
*
* PHP Version 5 with GD 2.0+
* PhpThumb : PHP Thumb Library <http://phpthumb.gxdlabs.com>
* Copyright (c) 2009, Ian Selby/Gen X Design
*
* Author(s): Ian Selby <ian@gen-x-design.com>
*
* Licensed under the MIT License
* Redistributions of files must retain the above copyright notice.
*
* @author Ian Selby <ian@gen-x-design.com>
* @copyright Copyright (c) 2009 Gen X Design
* @link http://phpthumb.gxdlabs.com
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
* @version 3.0
* @package PhpThumb
* @filesource
*/
// define some useful constants
define('THUMBLIB_BASE_PATH', dirname(__FILE__));
// define('THUMBLIB_PLUGIN_PATH', THUMBLIB_BASE_PATH . '/ThumbPlugins/');
define('DEFAULT_THUMBLIB_IMPLEMENTATION', 'gd');
/**
* PhpThumbFactory Object
*
* This class is responsible for making sure everything is set up and initialized properly,
* and returning the appropriate thumbnail class instance. It is the only recommended way
* of using this library, and if you try and circumvent it, the sky will fall on your head :)
*
* Basic use is easy enough. First, make sure all the settings meet your needs and environment...
* these are the static variables defined at the beginning of the class.
*
* Once that's all set, usage is pretty easy. You can simply do something like:
* <code>$thumb = PhpThumbFactory::create('/path/to/file.png');</code>
*
* Refer to the documentation for the create function for more information
*
* @package PhpThumb
* @subpackage Core
*/
class ThumbLib
{
/**
* Which implemenation of the class should be used by default
*
* Currently, valid options are:
* - imagick
* - gd
*
* These are defined in the implementation map variable, inside the create function
*
* @var string
*/
public static $defaultImplemenation = DEFAULT_THUMBLIB_IMPLEMENTATION;
/**
* Where the plugins can be loaded from
*
* Note, it's important that this path is properly defined. It is very likely that you'll
* have to change this, as the assumption here is based on a relative path.
*
* @var string
*/
// public static $pluginPath = THUMBLIB_PLUGIN_PATH;
/**
* Factory Function
*
* This function returns the correct thumbnail object, augmented with any appropriate plugins.
* It does so by doing the following:
* - Getting an instance of PhpThumb
* - Loading plugins
* - Validating the default implemenation
* - Returning the desired default implementation if possible
* - Returning the GD implemenation if the default isn't available
* - Throwing an exception if no required libraries are present
*
* @return GdThumb
* @uses PhpThumb
* @param string $filename The path and file to load [optional]
*/
public static function create($filename = null, $options = array(), $isDataStream = false)
{
// map our implementation to their class names
$implementationMap = array
(
'imagick' => 'ImagickThumb',
'gd' => 'GdThumb',
);
// grab an instance of PhpThumb
$pt = PhpThumb::getInstance();
// load the plugins
// $pt->loadPlugins(self::$pluginPath);
$toReturn = null;
$implementation = self::$defaultImplemenation;
// attempt to load the default implementation
if ($pt->isValidImplementation(self::$defaultImplemenation)) {
$imp = $implementationMap[self::$defaultImplemenation];
$className = 'Library\\Phpthumb\\'.$imp;
$toReturn = new $className($filename, $options, $isDataStream);
}
// load the gd implementation if default failed
else if ($pt->isValidImplementation('gd')) {
$imp = $implementationMap['gd'];
$implementation = 'gd';
$className = 'Library\\Phpthumb\\'.$imp;
$toReturn = new $className($filename, $options, $isDataStream);
}
// throw an exception if we can't load
else {
throw new Exception('You must have either the GD or iMagick extension loaded to use this library');
}
$registry = $pt->getPluginRegistry($implementation);
$toReturn->importPlugins($registry);
return $toReturn;
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment