编辑PHP文件app/Exceptions/Handler.php内容如下:
代码如下 | 复制代码 |
public function render($request, Exception $e) if ($e instanceof ModelNotFoundException) { if($e instanceof \Symfony\Component\Debug\Exception\FatalErrorException return parent::render($request, $e); |
然后编辑自定义错误页面对应视图文件errors.default.blade.php。
验证码(Captcha)开源软件了,我们可以利用它结合Laravel 5生成验证码了,并且它在不断的更新算法比较难破解了,下面来看一篇Captcha为Laravel 5 应用生成验证码例子具体如下。1、安装
我们通过 Composer 安装 Captcha 扩展包:
composer require mews/captcha
注:Windows中使用该扩展包还需要安装 GD2 扩展(在php.ini中取消php_gd2.dll前面的注释)。
2、配置
使用Captcha服务提供者之前还需要在config/app.php中注册服务提供者:
'providers' => [
// ...
Mews\Captcha\CaptchaServiceProvider::class,
]
同时注册下相应门面:
'aliases' => [
// ...
'Captcha' => Mews\Captcha\Facades\Captcha::class,
]
如果要使用自定义的配置,还可以发布配置文件到config目录:
$ php artisan vendor:publish
编辑新生成的captcha.php:
return [
'default' => [
'length' => 5,
'width' => 120,
'height' => 36,
'quality' => 90,
],
// ...
];
3、使用示例
// app/Http/routes.php
Route::any('captcha-test', function()
{
if (Request::getMethod() == 'POST')
{
$rules = ['captcha' => 'required|captcha'];
$validator = Validator::make(Input::all(), $rules);
if ($validator->fails())
{
echo '<p style="color: #ff0000;">Incorrect!</p>';
}
else
{
echo '<p style="color: #00ff30;">Matched :)</p>';
}
}
$form = '<form method="post" action="captcha-test">';
$form .= '<input type="hidden" name="_token" value="' . csrf_token() . '">';
$form .= '<p>' . captcha_img() . '</p>';
$form .= '<p><input type="text" name="captcha"></p>';
$form .= '<p><button type="submit" name="check">Check</button></p>';
$form .= '</form>';
return $form;
});
显示效果如下:
如果要返回原生图片,可以调用这个函数:
captcha();
或者
Captcha::create();
如果要返回URL:
captcha_src();
或者
Captcha::src();
如果要返回HTML:
captcha_img();
我们这个示例中使用的就是这个函数,或者调用Captcha门面上的方法:
Captcha::img();
要使用配置文件captcha.php中不同的配置项,可以这样调用:
captcha_img('flat');
Captcha::img('inverse');
注意:
在laravel 5.2中这个包会出现验证码怎么也无法验证成功的问题,因为5.2采用了middleware分组,并没有使用全局中间件导致这个包没有启用session导致上述问题。解决办法:在
vendor/mews/captcha/src/CaptchaServiceProvider.php
29行的
this->app['router']->get('captcha/{config?}', '\Mews\Captcha\CaptchaController@getCaptcha')
后面添加
->middleware('web');
确认你的web中间件分组内有StartSession中间件。另外你也可以添加5.2新特性频率限制到后面
->middleware('throttle:60,1')
以防止恶意攻击。
公众号菜单添加删除如果是单号可以直接登录后台操作了,但如果我们开了开发接口那么这个菜单的操作也必须通过接口来实现了,下面我们来看一篇关于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;
}
}