在新项目里面,打算写一个服务端的缓存机制,像用户这种被几乎大部分请求都查询的,就可以放在缓存里面。本来打算用redis,后来想,反正我的项目不会很大,用redis还是用memcahced都不是问题,而且目前来说,根本不存在技术选型的问题,都是开发一块琢磨一块。
你看我最近的博客就知道,我在用slim开发一个投票系统的后端api,所以这篇文章自然是要在slim去讲怎么用。不过其实Illuminate\Cache是一个模块,所以任何项目里面都是可以用的,不限框架,自己写一个php都可以引进来用。下面就开始详解怎么实现:
环境的搭建
本来我打算一上来就代码,三两下结束的,但是我发现,这样没多大意义,特别是刚开始接触使用composer的同学,要面临的问题特别多。我一开始也以为可以很快搞定,结果也躺了两个坑。我是在本地的ubuntu下开发,所以下面的安装、配置相关命令都是ubuntu下的,其他linux版本也有对于的安装,熟悉linux的话,应该不是问题。
安装memcached
memcached和memcache是两个不同的服务,虽然它们接口都是一样的,但是memcached使用的更多。其实这两者在数据库层面没有什么关系,主要搞混的地方是:它们是两个不同的php扩展。memcache这个扩展功能比较老,现在更多的我们会使用采用了新接口的memeched这个扩展。所以,实际上,安装memcached是两个过程,一个是安装memcache数据库,另一个是安装php的memcached扩展。
sudo apt install memcached
这样就把数据库安装上了,可以使用service memcached restart
来重启服务。
接下来就是安装php的memcached扩展。
安装php扩展
从理论上讲,我们只需要去官网把memcached这个扩展下载下来,启动phpize,编译,make install一下就可以了。但是其实并不这么简单。
当memcache数据库服务器运行起来之后,它其实是一个服务端程序,你需要一个客户端去连接它,操作它。按理来说,php的memcached扩展就是个客户端,连上去就好了啊。但是,在这之前,你必须安装mamcache的开发库。在ubuntu上安装:
sudo apt install libmemcache-dev
在其他linux上是不是这个包名不是很清楚,总之可以尝试libmemcached、devel等这些单词,总会有一个可以安装上。安装了lib dev之后,才能编译下载好的memcached。
接下来就是编译安装了,进到解压出来的目录里面:
phpize./configuremakesudo make install
这样就算编译安装好了,扩展模块会在你的php模块目录下。但是你还需要编辑php.ini,把扩展添加进去:
extension=memcached.so
把这一行加入到php.ini中有很多extension的地方。保存之后,要重启httpd,ubuntu上是apache2。重启之后,就可以在php代码中new Memcached()
了。这个类具体怎么用,可以看上面那个链接,阅读官方文档。
使用Illuminate\Cache实现缓存
Illuminate\Cache是Illuminate开发的一个模块,里面包含了各种类型的cache类,当然了,每一个类的使用,都依赖对应的缓存机制,其中大部分也像上面一样,要么你需要安装,要么需要配置,总之,不是说拿来就可以立即用,而需要提前将环境搭建好。
安装Illuminate\Cache
通过composer进行安装是现在php开发最流行的模块安装方式,如果你还在处于以前那种下载后把文件require的开发模式,那么应该考虑一下升级一下自己的开发理念。
composer require illuminate/cache
在你的项目目录下运行上面的安装命令,就可以把这个模块安装到vendor目录中,而且composer实现了自动加载,也就是说你可以在你的php文件中通过use命令,直接使用这个类。
实现代码
作为slim的新粉,必须重度实践slim的开发理念。slim真的是太赞了,虽然它不像其他php框架一样,提供一整套的数据库、缓存、文件上传等等功能。但是它提供了最最最核心的request和response的router,这就够了,用router以及它的中间件思想,就可以实现任意的服务。现在很少用php开发大型的应用了,特别是web已经被node霸占了,slim这种微框架拿过来就开始开发,为了一个非常小的功能开发一个服务,需要的其他功能通过composer安装,这种思想兼职是我迄今为止遇到过的最好的php开发实践了。
当然,这篇文章不是为了夸slim,回到主题,实现缓存。既然不是为了slim,那么直接用slim的router开始好了。代码的大致框架:
require 'vendor/autoload.php';require 'cache.php'; $app = new \Slim\App($app_config); $app->get('/cache', 'CacheController:cache'); $app->run();
这就是index.php了,你会把它丢到网站的根目录下,准备访问/cache这个uri来测试代码是否生效,而cache这个路由,会写在cache.php里面。CacheController这个类会在cache.php中去定义。接下来就来看下cache.php:
use Illuminate\Cache\MemcachedConnector as Connector; use Illuminate\Cache\MemcachedStore as Cache; class CacheController { private $cache; function __constructor() { $config = [ 'memcached' => [ 'host' => '127.0.0.1', 'port' => 11211, 'weight' => 100, ], ]; $connector = new Connector(); $connect = $connector->connect($config); $this->cache = new Cache($connect); // 你现在已经实例化了一个cache,利用MemcacheStore的api想干嘛干嘛吧 } }
上面极其简单的实现了一个$cache,你可以在后面的代码里面保存、获取了。注意,保存使用->put方法,而不是set方法,这也是个坑。
说到这里,不得不说包括laravel的很多文档都写的很不友好,用文档工具生成一下就ok了,你自己去慢慢研究。在上面connect这个点上我就被坑了一下,一开始以为直接在new的时候把config传进去就好了,试了几次才去看源码,才知道要调用connect方法,config是传给connect方法的。所以,这里也表达一下我的看法,看文档固然是一件好事,但是有的时候反不如直接看代码来的清楚,现在的项目代码写的都比较优雅,读起来很轻松,直接看代码不仅知道有哪些接口,而且还可以知道传的参数是什么类型,看源码,不骗你。
实战案例:输入验证码
上面实现了连接到memcache,接下来,我们就直接使用Illuminate\Cache的接口来实现一个缓存的使用场景:输入验证码。之所以使用缓存来实现,是因为部分设备不支持session,而且特别是手机客户端和api之间的交互,不携带cookie,只能通过一些明码来实现。验证码是两个步骤:产生码,验证码。所以也可以很好的作为一个案例来演示。
首先,产生一个码。这个码不会发文本给用户,只会放在服务端,发给用户的,是一个识别号id,这个识别号id就是缓存号,通过它可以从memcache里面取出对应的验证码。现在来产生这个id和码:
// 在CacheController里面添加一个新方法cache function cache($req, $res, $args) { $id = mt_rand(1000, 9999); $code = mt_rand(1000, 9999); $this->cache->put($id, $code, 3); // 3是指保留3分钟,这里比较坑,不能以秒来计算 // 接下来把id告诉用户 return $res->withJson(['id' => $id]); }
这样用户就可以在客户端接收到一个id号,这个id号不是验证码的code,而是一张票,他得凭票取码,但是他只能取到一张验证码的图片,而不是真的验证码。下面就写一个方法,用来显示一张图片:
function img($reg, $res, $args) { $id = $args['id']; // 这个需要在路由中配置,下面讲 $code = $this->cache->get($id); // 下面做一些判断,以防验证码过期之类的 // 用php输出图片就不在这里给代码了,比较复杂,也可以用composer下载包来实现 }
用户要看到这个图片,必须通过url,所以,你得在最前面的index.php里面加一个路由:
$app->get('/img/{id}', 'CacheController:img');
这样用户才能通过一个url得到图片。他看到图片后,就可以输入图片里面包含的验证码,输入后提交到一个新的地址进行验证:
$app->post('/check', 'CacheController:check');
这里我们改用了post方法提交数据。用户需要提交id和自己输入的验证码。我们在自己的方法里这样写:
function check($req, $res, $args) { $post_data = $req->getParsedBody(); $id = $post_data['id']; $code = $post_data['code']; $very_code = $this->cache->get($id); // 你现在有了$code(用户post过来的)和$very_code(通过用户post的id获取的缓存值),可以用来比较,并做出回应了 }
这样,一个关于验证码的逻辑就实现了,而且正好利用了本文实现的memcache缓存方法。
如果你有什么不懂的地方,可以在下方留言,如果你对slim感兴趣,可以和我一起探讨,如果你想做前端方面的实践,也可以和我一起探讨。
2017-04-27 5521 cache, illuminate, memcache, slim