经常要做到分享到其他网站的情况,新浪,renren,qq空间,豆瓣等等
如果不好好设计,就会变得越来越乱
这里简述一下我的设计过程,以及如何解决
由于最先只涉及到新浪微博,所以上来下载新浪的sdk,绑定的时候,取sina的登陆url然后设置个回调地址,将token存到数据库
分享的时候,从数据库中去得token,然后调sdk的update将内容分享到新浪微博,ok,好像没什么问题
过了几天,问题来了,由于新浪微博的接口不稳定,有时候时间反应过慢,导致分享的时候会卡在那儿,造成并发太多,且影响用户体验
解决方案,将分享的数据插入队列,然后后台启动job,每几秒跑一次,这玩意不需要什么实时性,所以这问题解决
第二天,老板说要支持腾讯微博,ok,下载sdk,同样获取qq的登陆url,token存数据库,。。。。。,每次if判断,如果是这样就这样调sdk,如果是那样就那样调sdk,每次,如分享,取信息,等,全部按照sdk的步骤来一遍,ok,it works
if($type=='sina') {
new sina_xxx ($token);
sina.update()
} else if($type=='qq') { qq_xxx::init(xxx,xxx); qq_xxx::pub };
大量的if else ,有的第三方异常,就再特殊处理,全写在这个地方,很长,很丑陋
,but,it works
第三天,老板说,把renren豆瓣,都加上,用if来判断,又臭又长来了,,,大量重复代码,忍不了了,要优化,,,如何优化?
我们知道,分享到第三方,需要提供三个接口,1.获取登陆地址 2.获取用户资料 3.用登陆之后回调的参数获取token 4.用token进行内容分享,我们是否可以搞个类,然后只要传一个type,比如sina,就给我们一个api对象,然后把参数传进去,而且没歌种类的参数全部相同呢?当然可以,先顶一个sina的类,这个类需要完成几个接口,ok,接口,,如下:
interface Share_Interface {
/**
* 获取跳转认证的地址
* */
public function get_auth_url();
/**
* 分享文字内容
* @param String $text 文字
* */
public function share($text);
/**
* 分享带图内容
* @param String $text 文字
* @param Url_String $pic 图片地址
* */
public function share_pic($text,$pic);
/**
* 获取用户信息
* @return array('name'=>'text','pic'=>'http://www.reco.cn/111.jpg');
* */
public function get_user_info();
/**
* 通过数据库存储的token信息进行认证
* @param array $data user_token的一条记录
* */
public function auth_by_data($data);
/**
* 通过第三方回跳穿过的参数进行认证
* @param array $params 回调的,第三方传过来的参数
* @return array 返回的参数,可直接用来插入到user_token表
* */
public function auth_by_params($params);
}
很好,那么对几个第三方网站一个一个来进行实现,实现的时候,发现几个方法是可以共用的,有几个是必须要实现的,ok,咱们来个抽象类
<?php
abstract class Share_Abstract {
public $config;
public $return_url;
public $token;
public $share_user_id;
abstract public function get_type();
public function __construct() {
$this->config = RSF::get_instance()->get_config($this->get_type(),'share');
$this->return_url = $this->config['return_url'];
}
public function set_return_url($url){
$this->return_url = $url;
}
public function get_return_url(){
return $this->return_url;
}
public function set_token_uid($token,$uid) {
$this->token = $token;
$this->share_user_id = $uid;
}
public function get_share_user_id() {
return $this->share_user_id;
}
public function auth_by_data($data) {
$this->share_user_id = $data['share_user_id'];
$this->token = $data['token'];
$this->extend_data = json_decode($data['extend_data'],true);
}
}
实现sina的接口,就要集成,和完成这些接口了
class Share_Sina_Interface extends Share_Abstract implements Share_Interface {
public function get_type() {
return 'sina';
}
public function get_auth_url() {
$sina_auth = new Share_Sina_Auth($this->config['WB_AKEY'],$this->config['WB_SKEY']);
$return_url = $this->get_return_url();
$auth_url = $sina_auth->getAuthorizeURL($return_url);
return $auth_url;
}
public function share($text){
}
public function share_pic($text,$pic){
}
public function get_user_info(){
$pub = new Share_Sina_Publish($this->config['WB_AKEY'],$this->config['WB_SKEY'],$this->token);
$info = $pub->show_user_by_id($this->share_user_id);
return array('name'=>$info['name'],'pic'=>$info['avatar_large']);
}
public function auth_by_data($data) {
$this->share_user_id = $data['share_user_id'];
$this->token = $data['token'];
}
/**
* 通过传过来的参数进行认证,获取token,等
* 返回的数据用于插入token表
* */
public function auth_by_params($params){
$code = $params['code'];
$sina_auth = new Share_Sina_Auth($this->config['WB_AKEY'],$this->config['WB_SKEY']);
$data = array('code' => $code, 'redirect_uri' => $this->get_return_url());
$response_data = $sina_auth -> getAccessToken('code', $data);
$this->token = $response_data['access_token'];
$this->share_user_id = $response_data['uid'];
$data = array(
'token'=>$response_data['access_token'],
'share_user_id'=>$response_data['uid'],
'share_type'=>'sina',
'expires_in'=>$response_data['expires_in'],
'fresh_time'=>time(),
'extend_data'=>''
);
return $data;
}
}
同样,其它的类似实现
调的时候,还是要if(xxx=sina) { new xxx_interface()}
不够完美,ok,很明显,来个工厂
<?php
class Share_Factory {
public static function create($type) {
$type = ucfirst($type);
$api_name = 'Share_'.$type.'_Interface';
rsf_require_class($api_name);
if(class_exists($api_name)){
$api = new $api_name();
return $api;
}
}
}
这样只要
Share_Factory::create('sina')
很漂亮有木有?php的优化完成,
第四天,老板又说话,要加第三方登录功能,我想当然,传递不用回调地址给第三方,然后获取昵称和头像,写进数据库,so easy,实现的时候发现一个严重的问题,有些第三方的回调地址必须填写和你注册时候填写的一摸一样,加个参数都不行,代表的就是豆瓣,腾讯微博,
解决方案,每次需要登录第三方的时候,用window.open弹窗,同时这只一个js全局函数,弹窗验证完毕后,再用js的opener对象来执行这个函数,获取到的参数用base_64加密给js,然后js负责跳转,ok,同域名下完美解决,
但是如果是个二级域名下,那么窗口就没有权限执行,opener的函数,咋办?
解决方案,如果发现没有权限,可以用try{}catch(){}来判断,自动将这些参数,提交给二级域名,进行跳转,然后再来执行opener的函数,完美解决
所有的运行效果,可以来我们的网站观察 www.reco.cn