php版微信实现公众号菜单添加删除操作
为了以最快方式调试新菜单功能,就用Debug方式去生成新菜单。请参数微信教程2的 wechat-json类。导入该文件后,我们用Debug方式生成一个新菜单:
if (isset($argc) && $argc >= 1 && $argv[0] == __FILE__) {
$client = new WechatJSON(array(
WechatJSON::APP_ID => 'wx78acfe8023sfsd4d51',
WechatJSON::APP_SECRET => '9ba3476db1ffsfsf512e0b22f630fa',
));
$res = $client->call('/menu/create',array (
'button' => array(
array (
'name' => '扫码',
'sub_button' => array(
array(
'name' => '扫码不提示',
'type' => 'scancode_push',
'key' => 'rselfmenu_0_0',
'sub_button' =>array ()
),
array(
'name' => '扫码带提示',
'type' => 'scancode_waitmsg',
'key' => 'rselfmenu_0_1',
'sub_button' =>array ()
),
),
),
array(
'name' => '发图',
'sub_button' => array(
array(
'name' => '系统拍照发图',
'type' => 'pic_sysphoto',
'key' => 'rselfmenu_1_0',
'sub_button' => array()
),
array(
'name' => '拍照或者相册发图',
'type' => 'pic_photo_or_album',
'key' => 'rselfmenu_1_1',
'sub_button' => array()
),
array(
'name' => '微信相册发图',
'type' => 'pic_weixin',
'key' => 'rselfmenu_1_2',
'sub_button' => array()
),
)
),
array(
'name' => '发送位置',
'type' => 'location_select',
'key' => 'rselfmenu_2_0'
)
)
)
, WechatJSON::JSON);
if (!$res) {
var_dump($client->_error);
}
var_export($res);
}
执行后,取消关注再关注,让新菜单生效!
效果图:
测试结果如下:
scancode_push事件:
array (
'tousername' => 'gh_e2a2b3bd35ff',
'fromusername' => 'on0eVjnYStxkCSaaCamYCpMZDmwA',
'createtime' => '1411629272',
'msgtype' => 'event',
'event' => 'scancode_push',
'eventkey' => '6',
'scancodeinfo' =>
SimpleXMLElement::__set_state(array(
'ScanType' => 'qrcode',
'ScanResult' => 'http://www.baidu.com/',
)),
array (
'tousername' => 'gh_e2a2b3bd35ff',
'fromusername' => 'on0eVjnYStxkCSaaCamYCpMZDmwA',
'createtime' => '1411629475',
'msgtype' => 'event',
'event' => 'scancode_push',
'eventkey' => '6',
'scancodeinfo' =>
SimpleXMLElement::__set_state(array(
'ScanType' => 'qrcode/EAN_13',
'ScanResult' => '6925082946487',
'EventKey' =>
SimpleXMLElement::__set_state(array(
)),
)),
)
上面是在菜单上点击《扫码不提示》后的log,有两种情况出现,第一种是如果你扫的是二维码是URL,它就会跳转到网页(注包括服务号生成的二维码),第二种是如果你扫的是条形码,就会跳转到搜索到该商品的详细信息,也就是大家常用的查价格。
scancode_waitmsg事件:
array (
'tousername' => 'gh_e2a2b3bd35ff',
'fromusername' => 'on0eVjnYStxkCSaaCamYCpMZDmwA',
'createtime' => '1411629302',
'msgtype' => 'event',
'event' => 'scancode_waitmsg',
'eventkey' => '6',
'scancodeinfo' =>
SimpleXMLElement::__set_state(array(
'ScanType' => 'qrcode',
'ScanResult' => 'http://www.111cn.net/',
)),
上面是点击菜单《扫码提示》后的log,推送XML跟scancode_push时差不多,但它不会跳转到网址或者商品信息。博主认为,这有利于后台取得scancodeinfo的信息来进一步处理!打个比方,自己自定义二维码信息,然后截取处理。类似于原服务号的参数二维码。
注意,以上两个菜单扫描事件和微信APP的扫一扫,是有区别的。具体你看事件就能看出来,scan事件!
pic_sysphoto事件、pic_photo_or_album事件和pic_weixin事件
array (
'tousername' => 'gh_e2a2b3bd35ff',
'fromusername' => 'on0eVjnYStxkCSaaCamYCpMZDmwA',
'createtime' => '1411627313',
'msgtype' => 'image',
'picurl' => 'http://mmbiz.qpic.cn/mmbiz/L8zbjcLqNFvEZ4dne4MGQQGR8xuHk4KhEk3icghU6a4bFTXnP2oeicr5VaBVJa10w4MYOOEia4udqicT5fdtAADHYg/0',
'msgid' => '6062893143676022221',
'mediaid' => 'i7hYOlSXbUCaC7Z9Elx4WpBqQq37-hR0El5w-frPfD5WCdBC7x46DPO6HL7zMfgd',
)
上面是点《发图》后,三个子菜单选择或者拍好,发图后的log信息,从图中我们看到事件是推过来了image,其他信息,相信大家都知道是什么,不解释。
location_select事件:
array (
'tousername' => 'gh_e2a2b3bd35ff',
'fromusername' => 'on0eVjnYStxkCSaaCamYCpMZDmwA',
'createtime' => '1411627424',
'msgtype' => 'event',
'event' => 'location_select',
'eventkey' => '6',
'sendlocationinfo' =>
SimpleXMLElement::__set_state(array(
'Location_X' => '23',
'Location_Y' => '113',
'Scale' => '15',
'Label' =>
SimpleXMLElement::__set_state(array(
)),
'Poiname' =>
SimpleXMLElement::__set_state(array(
)),
)),
)
上面是点击菜单《发送位置》后的log,我们可以看出事件是location_select,不像发图那样变成image,最有价值的信息是我们要取的sendlocationinfo里的
用户授权也是高级接口那部分内容,只是把它独立出来,这样让整个微信框架条理清晰些,但我们用它首先要在微信后台设置OA2的URL,这里的URL和教程一的有所不同。它是不带http://开头的域名。
首先登陆你的微信后台找到《开发者中心》:
点击修改填入我们的域名如下格式:
好了,最基本要点的OA2要求搞好,下面我们用个WechatAuth类生成一个OA2的URL格式,然后再从服务号里,以链接或者菜单又或者图文,跳到微信内置的WEB里就实现了我们取openid或者授权取用户消息!
例子代码生成snsapi_base或者snsapi_userinfo:
$auth = new WechatAuth(array(
WechatAuth::APP_ID => 'wx32259fc5sd5aac12B',
WechatAuth::APP_SECRET => '7ef73d3c56fcd0d984862ff217d2c648',
));
$url = $auth->getLoginUrl(array(
'redirect_uri' => 'http://www.demo.com/wp/ken',
'scope' => 'snsapi_userinfo' //snsapi_base
));
echo $url;
执行后,我们会得到如下OA2的URL:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx32259fc5d5aac13d&redirect_uri=http%3A%2F%2Fwww.demo.com%2Fwp%2Fken&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirects
然后我们在服务号里以刚才说到的菜单好,链接好 点击转到微信内置的浏览器里,如果你的scope方式为snsapi_userinfo时会弹出授权界面,base时不会弹默认执行后会返回openid:
好了,OA2无非就是让我们生成特定格式的URL,让我们点过去取openid或者用户信息(无论是否关注了你的服务号,只要确认授权),可以运用本站微信的实例有相关OA2的运用或者留言给我!
WechatAuth类:
<?php
/**
* 微信 OAuth2.0授权接口
* Class WechatAuth
*/
class WechatAuth {
const
JSON = 'json',
POST = 'post',
GET = 'get',
APP_ID = 'appid',
APP_SECRET = 'secret',
API_URL_PREFIX = 'https://api.weixin.qq.com/sns';
public
$_error_number = 0,
$_error,
$_APPID,
$_APPSECRET;
protected
$_cache = array(),
$_options,
$_openid,
$_access_token,
$_refresh_token,
$_timeout = 30;
static protected
$_instance;
/**
* 单例模式
* @param array $options
* @return WechatAuth
*/
static public function getInstance(array $options = array()) {
if (empty(self::$_instance)) {
self::$_instance = new WechatAuth($options);
}
return self::$_instance;
}
/**
* @param array $options {WechatAuth::APP_ID:"", WechatAuth::APP_SECRET:""}
*/
public function __construct(array $options = array()) {
$this->_options = array(
'timeout' => $this->_timeout,
);
$_options = array_merge($this->_options, $options);
$this->_APPID = $_options['appid'];
$this->_APPSECRET = $_options['secret'];
$this->_timeout = $_options['timeout'];
}
/**
* 提交请求
* @param $url
* @param array $params
* @param string $type Webchat_API::POST|Webchat_API::GET
* @return bool|mixed
*/
public function request($url, $params = array(), $type = self::POST) {
$ch = curl_init();
if ($type == self::GET) {
$url = $url.'?'.http_build_query($params);
}
curl_setopt_array($ch, array(
CURLOPT_URL => $url,
CURLOPT_TIMEOUT => $this->_timeout,
CURLOPT_USERAGENT => 'wordpress_wechat_client/0.1.'.rand(1,6),
CURLOPT_HEADER => 0,
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_SSL_VERIFYPEER => 0,
CURLOPT_SSLVERSION => 3,
// CURLOPT_VERBOSE => 1,
));
if ($type == self::POST) {
curl_setopt($ch, CURLOPT_PORT, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
}
if ($type == self::JSON) {
//微信的破接口竟然不支持unicode转义符,违反JSON协定,只能把JSON字符中的unicode转回来
$data = preg_replace('/\\\\u([a-f0-9]{4})/e', "json_decode('\"$0\"', 1)", json_encode($params));
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
}
$res = curl_exec($ch);
$this->_error_number = curl_errno($ch);
$this->_error = curl_error($ch);
curl_close($ch);
if ($this->_error_number) {
return false;
}
return $this->parseResult($res);
}
/**
* 处理返回结果
* @param $res
* @return bool|mixed
*/
protected function parseResult($res) {
$res = json_decode($res, true);
if (!empty($res)) {
if (isset($res['errcode']) && $res['errcode']) {
$this->_error_number = $res['errcode'];
$this->_error = $res['errmsg'];
return false;
}
return $res;
}
return false;
}
/**
* 获取当前URL
* @return string
*/
static public function getCurrentUrl() {
$pageURL = 'http';
if (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") {
$pageURL .= "s";
}
$pageURL .= "://";
if (isset($_SERVER['SERVER_PORT']) && $_SERVER["SERVER_PORT"] != "80") {
$pageURL .= $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"] . $_SERVER["REQUEST_URI"];
} else {
if(isset($_SERVER["SERVER_NAME"]) && isset($_SERVER["REQUEST_URI"]))
$pageURL .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
}
return $pageURL;
}
/**
* 获取访问token
* @param bool $refresh 是否强制刷新
* @return bool|mixed
*/
public function getAuthAccessToken($refresh = false) {
$code = isset($_GET['code']) ? $_GET['code'] : '';
$state = isset($_GET['state']) ? $_GET['state'] : '';
$cache = $this->cache('auth_access_token');
if ($cache && ! $refresh) {
return array('access_token' => $cache, 'code' => $code, 'state' => $state);
}
$res = $this->request(self::API_URL_PREFIX.'/oauth2/access_token', array(
self::APP_ID => $this->_APPID,
self::APP_SECRET => $this->_APPSECRET,
'code' => $code,
'grant_type' => 'authorization_code',
), self::GET);
if ($res) {
$this->cache('auth_access_token', $res['access_token']);
$this->cache('auth_refresh_token', $res['refresh_token']);
$this->cache('auth_openid', $res['openid']);
} else {
if ($this->_error_number == 42001) {
return $this->refreshAccessToken();
}
}
return array('access_token' => $res['access_token'], 'code' => $code, 'state' => $state);
}
/**
* 刷新访问token
* @return mixed
*/
public function refreshAccessToken() {
$code = isset($_GET['code']) ? $_GET['code'] : '';
$state = isset($_GET['state']) ? $_GET['state'] : '';
$cache = $this->cache('auth_refresh_token');
if ($cache) {
$this->_refresh_token = $cache;
}
$res = $this->request(self::API_URL_PREFIX.'/oauth2/refresh_token', array(
self::APP_ID => $this->_APPID,
'refresh_token' => $this->_refresh_token,
'grant_type' => 'refresh_token',
), self::GET);
if ($res) {
$this->cache('auth_access_token', $res['access_token']);
$this->cache('auth_refresh_token', $res['refresh_token']);
$this->cache('auth_openid', $res['openid']);
}
return array('access_token' => $res['access_token'], 'code' => $code, 'state' => $state);
}
/**
* 获取用户信息
* @param bool $refresh 是否强制刷新
* @return bool|mixed
*/
public function getUserInfo($refresh = false) {
$this->_access_token = $this->getAuthAccessToken($refresh);
$cache = $this->cache('auth_openid');
if ($cache) {
$this->_openid = $cache;
}
$res = $this->request(self::API_URL_PREFIX.'/userinfo', array(
'access_token' => $this->_access_token,
'openid' => $this->_openid,
), self::GET);
if ($res) {
return $res;
}
return false;
}
/**
* 获取用户授权地址
* @param array $options
* @return string
*/
public function getLoginUrl($options = array()) {
$_options = array(
self::APP_ID => $this->_APPID,
'redirect_uri' => self::getCurrentUrl(),
'response_type' => 'code',
'scope' => 'snsapi_base', //snsapi_base | snsapi_userinfo
'state' => 'STATE',
);
$params = array_merge($_options, $options);
return 'https://open.weixin.qq.com/connect/oauth2/authorize?'.http_build_query($params).'#wechat_redirects';
}
/**
* 缓存接口Session实现
* @param $key 缓存索引key
* @param null $value 缓存值
* @return bool|mixed
*/
public function cache($key, $value = null) {
if (!session_id()) {
session_start();
}
if (empty($value)) {
if (isset($_SESSION[$key])) {
return $_SESSION[$key];
}
return false;
}
$_SESSION[$key] = $value;
return false;
}
}
为了方便调试用CLI方式作测试,记得代码中替换你的appid和appsecret:
比如我们想取公众号的组数据:
if (isset($argc) && $argc >= 1 && $argv[0] == __FILE__) {
$client = new WechatJSON(array(
WechatJSON::APP_ID => 'wx78acfe8257asDb1',
WechatJSON::APP_SECRET => '9ba3476db1ff75654aBceae0b20fb9',
));
$res = $client->call('/groups/get');
if (!$res) {
var_dump($client->_error);
}
var_dump($res);
}
如下图所示:
又或者我们生成菜单:
if (isset($argc) && $argc >= 1 && $argv[0] == __FILE__) {
$client = new WechatJSON(array(
WechatJSON::APP_ID => 'wx78acfe8257asDb1',
WechatJSON::APP_SECRET => '9ba3476db1ff75654aBceae0b20fb9',
));
$res = $client->call('/menu/create', array(
'button' => array(
array(
'type' => 'click',
'name' => '测试铵钮',
'key' => 'test_btn'
),array(
'type' => 'view',
'name' => '测试跳转',
'url' => 'http://www.baidu.com'
))
),WechatJSON::JSON);
if (!$res) {
var_dump($client->_error);
}
var_dump($res);
}
成功后返回OK如下图:
其他接口可以大家可以自己自由获取或者提交POST GET等这里不熬述了!有问题留言
微信高级接口API 类:
<?php
/**
* 微信 高级接口API Class WechatJSON
*/
class WechatJSON {
const
QR_SCENE = 'QR_SCENE',
QR_LIMIT_SCENE = 'QR_LIMIT_SCENE',
IMAGE = 'image',
VOICE = 'voice',
VIDEO = 'video',
NEWS = 'news',
MPNEWS = 'mpnews',
THUMB = 'thumb',
API_URL_PREFIX = 'https://api.weixin.qq.com/cgi-bin',
AUTH_API_URL = 'https://api.weixin.qq.com/sns/oauth2/access_token',
AUTH_URL = 'https://open.weixin.qq.com/connect/oauth2/authorize',
PAY_URL = 'https://api.weixin.qq.com/pay',
APP_ID = 'appid',
APP_SECRET = 'secret',
TIMEOUT = 'timeout',
JSON = 'json',
POST = 'post',
GET = 'get',
API_TYPE_CGI = 'cgi',
API_TYPE_PAY = 'pay';
public
$_error_number = 0,
$_error,
$_APPID,
$_APPSECRET;
protected
$_cache = array(),
$_options,
$_auth_access_token,
$_access_token,
$_timeout = 30;
static protected
$_no_need_token_apis = array(
'/showqrcode',
),
$_instance;
/**
* 单例模式
* @param array $options
* @return Wechat_API
*/
static public function getInstance(array $options = array()) {
if (empty(self::$_instance)) {
self::$_instance = new self ($options);
}
return self::$_instance;
}
/**
* @param array $options {Wechat_API::APP_ID:"", Wechat_API::APP_SECRET:"", Wechat_API::TIMEOUT:""}
*/
public function __construct(array $options = array()) {
$this->_options = array(
'timeout' => $this->_timeout,
);
$_options = array_merge($this->_options, $options);
$this->_APPID = $_options['appid'];
$this->_APPSECRET = $_options['secret'];
$this->_timeout = $_options['timeout'];
}
/**
* 提交请求
* @param $url
* @param array $params
* @param string $type Wechat_API::POST|Wechat_API::GET
* @return bool|mixed
*/
public function request($url, $params = array(), $type = self::POST, $format_result = true) {
$ch = curl_init();
if ($type == self::GET) {
$url = $url.'?'.http_build_query($params);
}
curl_setopt_array($ch, array(
CURLOPT_URL => $url,
CURLOPT_TIMEOUT => $this->_timeout,
CURLOPT_USERAGENT => 'wordpress_wechat_client/0.1.'.rand(1,6),
CURLOPT_HEADER => 0,
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_SSL_VERIFYPEER => 0,
CURLOPT_SSLVERSION => 3,
// CURLOPT_VERBOSE => 1,
));
if ($type == self::POST) {
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
}
if ($type == self::JSON) {
//微信的破接口竟然不支持unicode转义符,违反JSON协定,只能把JSON字符中的unicode转回来
$data = preg_replace('/\\\\u([a-f0-9]{4})/e', "json_decode('\"$0\"', 1)", json_encode($params));
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
}
$res = curl_exec($ch);
$this->_error_number = curl_errno($ch);
$this->_error = curl_error($ch);
curl_close($ch);
if ($this->_error_number) {
return false;
}
return ($format_result ? $this->parseResult($res) : $res);
}
/**
* 处理返回结果
* @param $res
* @return bool|mixed
*/
protected function parseResult($res) {
$res = json_decode($res, true);
if (!empty($res)) {
if (isset($res['errcode']) && $res['errcode']) {
$this->_error_number = $res['errcode'];
$this->_error = $res['errmsg'];
return false;
}
return $res;
}
return false;
}
public function getAccessToken() {
$cache = $this->cache($this->_APPID.':'.'access_token');
if ($cache) {
return $cache;
}
$res = $this->request(self::API_URL_PREFIX.'/token', array(
'grant_type' => 'client_credential',
self::APP_ID => $this->_APPID,
self::APP_SECRET => $this->_APPSECRET,
), self::GET);
if ($res) {
$this->cache($this->_APPID.':'.'access_token', $res['access_token']);
return $res['access_token'];
}
return false;
}
/**
* 预留缓存接口 (强烈建议实现此接口,用于缓存access_token,每次查询会节省很多时间)
* @param $key 缓存索引key
* @param null $value 缓存值
* @param int $timeout 缓存超时时间
* @return bool|mixed
*/
public function cache($key, $value = null, $timeout = 7200) {
if (!session_id()) {
session_start();
}
if (empty($value)) {
if (isset($_SESSION[$key])) {
return $_SESSION[$key];
}
return false;
}
$_SESSION[$key] = $value;
return false;
}
/**
* 调用具体的接口 注意:使用创建数据时使用Wechat_API::JSON
* @param $api_name REST规格接口名称
* @param array $params 接口参数
* @param string $type Wechat_API::GET|Wechat_API::POST|Wechat_API::JSON
* @return bool|mixed
*/
public function call($api_name, $params = array(), $type = self::GET, $api_type = self::API_TYPE_CGI) {
if($api_type == self::API_TYPE_PAY) {
$url = self::PAY_URL.$api_name;
} else {
$url = self::API_URL_PREFIX.$api_name;
}
if (in_array($api_name, self::$_no_need_token_apis)) {
$res = $this->request($url, $params, $type);
if ($res) {
return $res;
}
}
$this->_access_token = $this->getAccessToken();
if ($this->_access_token) {
if ($type == self::JSON) {
$url = $url.'?access_token='.$this->_access_token;
} else {
$params['access_token'] = $this->_access_token;
}
$res = $this->request($url, $params, $type);
if ($res) {
return $res;
}
}
return false;
}
/**
* 生成二维码
*
* @param int $scene_id 场景ID 临时二维码int32 | 永久二维码 < 1000
* @param string $type 二维码类型 Wechat_API::QR_LIMIT_SCENE | Wechat_API::QR_SCENE 临时二维码|永久二维码
* @return bool|mixed
*/
public function GetQrCode($scene_id = 0, $type = self::QR_LIMIT_SCENE) {
$res = $this->call('/qrcode/create', array(
'expire_seconds' => 1800,
'action_name' => $type,
'action_info' => array(
'scene' => array(
'scene_id' => $scene_id,
)
)
), self::JSON);
if ($res && isset($res['ticket'])) {
$res = $this->request('https://mp.weixin.qq.com/cgi-bin/showqrcode', array(
'ticket' => $res['ticket'],
), self::GET, false);
if ($res) {
return $res;
}
}
return false;
}
public function MediaUpload($file_full_path, $type = self::THUMB) {
$this->_access_token = $this->getAccessToken();
$res = false;
if ($this->_access_token) {
$url = 'http://file.api.weixin.qq.com/cgi-bin/media/upload?';
$url = $url.'access_token='.$this->_access_token.'&type='.$type;
$res = $this->request($url, array(
'media' => '@'.$file_full_path,
), self::POST);
}
return $res;
}
public function GetMedia($media_id) {
$this->_access_token = $this->getAccessToken();
if ($this->_access_token) {
$res = $this->request('http://file.api.weixin.qq.com/cgi-bin/media/get', array(
'access_token' => $this->_access_token,
'media_id' => $media_id,
), self::GET, false);
if ($res) {
$res_json = json_decode($res, 1);
if (!$res_json) {
return $res;
}
$this->_error_number = $res_json['errcode'];
$this->_error = $res_json['errmsg'];
}
}
return false;
}
}
短网址的实现原理就是有一个数据表会配置文件将短网址和实际网址进行对应,当请求某个短网址时,程序跳转到对应的实际网址上去,从而实现网址的访问。
方案1:PHP+MySQl实现短网址的生成和读取
常规的方案我们将生成好的短网址和原网址对应到一张数据表中,然后供读取使用。我们先来看如何生成唯一的短网址。
//生成短网址
function code62($x){
$show='';
while($x>0){
$s=$x % 62;
if ($s>35){
$s=chr($s+61);
}elseif($s>9&&$s<=35){
$s=chr($s+55);
}
$show.=$s;
$x=floor($x/62);
}
return $show;
}
function shorturl($url){
$url=crc32($url);
$result=sprintf("%u",$url);
return code62($result);
}
echo shorturl('http://www.111cn.net/');
//1EeIv2
使用以上PHP代码可以生成唯一的6位的短网址,然后我们将生成的短网址与原网址一起写入到MySQL表中,插入数据库的代码这里我就不写了,这是PHP基础。
接着,我们有一个link.php用来接收读取url并实现真实跳转。
include_once('connect.php'); //连接数据库
$url = $_GET['url'];
if(isset($url) && !empty($url)){
$sql = "select url from shorturl where codeid='$url'";
$query = mysql_query($sql);
if($row=mysql_fetch_array($query)){
$real_url = $row['url'];
header('Location: ' . $real_url);
}else{
header('HTTP/1.0 404 Not Found');
echo 'Unknown link.';
}
}else{
header('HTTP/1.0 404 Not Found');
echo 'Unknown link.';
}
代码中,如果得到短网址对应的真实url,会使用header跳转到真实的页面上去,否则返回404代码。这样我们可以使用如: http://yourdomain/link.php?url=xxx来实现短网址访问。
继续,我们使用URL rewrite即重写功能来实现诸如可以通过地址:http://yourdomain/xxx 来访问。
以下是rewrite规则:
#Apache规则:
RewriteRule ^/(.*)$ /link.php?url=$1 [L]
#如果使用nginx,规则这样写:
rewrite ^/(.*)$ /link.php?url=$1 last;
方案2:PHP+ini实现短网址技术
对于方案1使用数据库的做法好处就是操作方便,而大量短网址查询需要做优化。而方案2则放弃数据库,使用ini配置,我们将短网址和真实网址配置在ini文件中,PHP直接通过parse_ini_file()读取ini文件,几行代码就可以实现短网址的跳转。
links.ini文件像这样配置:
baidu = https://www.baidu.com/
qq = http://www.qq.com/
hw = http://www.111cn.net/
dm = http://m.111cn.net
而index.php的代码可以这样写:
$links = parse_ini_file('links.ini');
if(isset($_GET['l']) && array_key_exists($_GET['l'], $links)){
header('Location: ' . $links[$_GET['l']]);
}
else{
header('HTTP/1.0 404 Not Found');
echo 'Unknown link.';
}
当然,我们还需要配置下rewrite规则。
#Apache规则:
RewriteRule ^/(.*)$ /index.php?l=$1 [L]
#如果使用nginx,规则这样写:
rewrite ^/(.*)$ /index.php?l=$1 last;
相关文章
- 下面小编来给大家演示几个php操作zip文件的实例,我们可以读取zip包中指定文件与删除zip包中指定文件,下面来给大这介绍一下。 从zip压缩文件中提取文件 代...2016-11-25
- 本文实例讲述了jQuery实现非常实用漂亮的select下拉菜单选择效果。分享给大家供大家参考,具体如下:先来看如下运行效果截图:在线演示地址如下:http://demo.jb51.net/js/2015/js-select-chose-style-menu-codes/具体代码如...2015-11-08
- 复制代码 代码如下: <td> <a href="/member/life/edit_ppt/<?php echo $v->id;?>" class="btn">编辑</a> <a href="javascript:;" onclick="if(confirm('您确定删除这条记录?')){location.href='/member/life/d...2014-06-07
- 本文实例讲述了JS基于Mootools实现的个性菜单效果代码。分享给大家供大家参考,具体如下:这里演示基于Mootools做的带动画的垂直型菜单,是一个初学者写的,用来学习Mootools的使用有帮助,下载时请注意要将外部引用的mootools...2015-10-23
- 本文实例讲述了JS实现的简洁纵向滑动菜单(滑动门)效果。分享给大家供大家参考,具体如下:这是一款纵向布局的CSS+JavaScript滑动门代码,相当简洁的手法来实现,如果对颜色不满意,你可以试着自己修改CSS代码,这个滑动门将每一...2015-10-21
- 本文实例讲述了jQuery实现有动画淡出效果的二级折叠菜单代码。分享给大家供大家参考,具体如下:这里介绍jQuery实现有动画淡出效果的二级折叠菜单代码,相当不错,因考虑功能的实现,所以没有怎么美化,不过这样也好,可以给大家更...2015-10-21
- 伪造跨站请求介绍伪造跨站请求比较难以防范,而且危害巨大,攻击者可以通过这种方式恶作剧,发spam信息,删除数据等等。...2013-10-01
- 这篇文章主要为大家详细介绍了jQuery实现下拉菜单滑动效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-08-09
Centos中彻底删除Mysql(rpm、yum安装的情况)
我用的centos6,mysql让我整出了各种问题,我想重装一个全新的mysql,yum remove mysql-server mysql之后再install并不能得到一个干净的mysql,原来的/etc/my.cnf依然没变,datadir里面的数据已没有任何变化,手动删除/etc/my.cn...2015-03-15- 数据库中的数据删除会分为两种:物理删除 和 逻辑删除,接下来通过本文给大家介绍MyBatis-Plus的物理删除和逻辑删除使用场景分析,感兴趣的朋友一起看看吧...2021-09-25
- 本文实例讲述了jQuery实现可关闭固定于底(顶)部的工具条菜单效果。分享给大家供大家参考,具体如下:这是一款可关闭始终在页面底部的工具条菜单,浮动在页面顶部的大家见的比较多了,本款从形式上来说与其它的没什么差别,只是浮...2015-11-08
- 二级联动下拉菜单选择应用在在很多地方,比如说省市下拉联动,商品大小类下拉选择联动。本文将通过实例讲解使用jQuery+PHP+MySQL来实现大小分类二级下拉联动效果。 实现效果:当选择大类时,小类下拉框里的选项内容也随着改...2015-10-30
- 本文主要对介绍利用Vue.js 的递归组件,实现了一个最基本的树形菜单。具有很好的参考价值,下面就跟着小编一起来看下吧...2017-01-09
- 这篇文章主要介绍了mybatis-plus getOne和逻辑删除,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-08-26
- 由于业务需要,要求实现树形菜单,且菜单数据由后台返回,下面这篇文章主要给大家介绍了关于js如何构造elementUI树状菜单的数据结构的相关资料,需要的朋友可以参考下...2021-05-13
- 这是一款精美的多级下拉菜单美化,可以完美替代“select”来实现下拉菜单的效果。而且支持多级菜单,有加载等待效果,有层级分类展示。复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "ht...2015-03-15
- 这篇文章主要为大家详细介绍了jquery插件实现悬浮的菜单,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-04-23
- 这篇文章主要介绍了C# 复制与删除文件的实现方法的相关资料,希望通过本文能帮助到大家,让大家理解掌握这部分内容,需要的朋友可以参考下...2020-06-25
- 最近由于项目的需要,需要动态的添加和删除table中的tr,感觉用JS可以实现,但是在网上找了一下,单纯的自己写JS,感觉太麻烦,而且也不好维护。于是想到了最近学的jQuery。这篇文章给大家用实例介绍了jQuery动态添加与删除tr行的方法,有需要的朋友们可以参考借鉴。...2016-10-20
- 这篇文章主要为大家详细介绍了js实现上传文件添加和删除文件选择框 ,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2016-10-25