SmartWiki簡介請閱讀: http://www.cnblogs.com/lifeil/p/6113323.html
因為SmartWiki的演示站點部署在阿里雲上,阿里雲有一個128M免費的Memcache服務,剛開始按照Memcached的配置方式配置完後,發現Laravel報錯,查看日誌報錯位置是addServer出錯,連不上阿里雲的Memcache。
很無奈,於是安裝阿里雲的手冊寫了一個腳本放到伺服器上,結果可以連接,也可以寫入。
阿里雲提供的腳本如下:
<?<span style="color: #000000">php </span><span style="color: #800080">$connect</span> = <span style="color: #0000ff">new</span> Memcached; <span style="color: #008000">//</span><span style="color: #008000">声明一个新的memcached链接</span> <span style="color: #800080">$connect</span>->setOption(Memcached::OPT_COMPRESSION, <span style="color: #0000ff">false</span>); <span style="color: #008000">//</span><span style="color: #008000">关闭压缩功能</span> <span style="color: #800080">$connect</span>->setOption(Memcached::OPT_BINARY_PROTOCOL, <span style="color: #0000ff">true</span>); <span style="color: #008000">//</span><span style="color: #008000">使用binary二进制协议</span> <span style="color: #800080">$connect</span>->addServer('00000000.ocs.aliyuncs.com', 11211); <span style="color: #008000">//</span><span style="color: #008000">添加OCS实例地址及端口号 //$connect->setSaslAuthData('aaaaaaaaaa, 'password'); //设置OCS帐号密码进行鉴权,如已开启免密码功能,则无需此步骤</span> <span style="color: #800080">$connect</span>->set("hello", "world"<span style="color: #000000">); </span><span style="color: #0000ff">echo</span> 'hello: ',<span style="color: #800080">$connect</span>->get("hello"<span style="color: #000000">); </span><span style="color: #008080">print_r</span>( <span style="color: #800080">$connect</span>-><span style="color: #000000">getVersion()); </span><span style="color: #800080">$connect</span>->quit();
翻閱laravel的Memcached驅動,在 /vendor/laravel/framework/src/Illuminate/Cache/MemcachedConnector.php 中建立Memcached物件的程式碼如下:
<span style="color: #0000ff">public</span> <span style="color: #0000ff">function</span> connect(<span style="color: #0000ff">array</span> <span style="color: #800080">$servers</span><span style="color: #000000">) { </span><span style="color: #800080">$memcached</span> = <span style="color: #800080">$this</span>-><span style="color: #000000">getMemcached(); </span><span style="color: #008000">//</span><span style="color: #008000"> For each server in the array, we'll just extract the configuration and add // the server to the Memcached connection. Once we have added all of these // servers we'll verify the connection is successful and return it back.</span> <span style="color: #0000ff">foreach</span> (<span style="color: #800080">$servers</span> <span style="color: #0000ff">as</span> <span style="color: #800080">$server</span><span style="color: #000000">) { </span><span style="color: #800080">$memcached</span>-><span style="color: #000000">addServer( </span><span style="color: #800080">$server</span>['host'], <span style="color: #800080">$server</span>['port'], <span style="color: #800080">$server</span>['weight'<span style="color: #000000">] ); } </span><span style="color: #800080">$memcachedStatus</span> = <span style="color: #800080">$memcached</span>-><span style="color: #000000">getVersion(); </span><span style="color: #0000ff">if</span> (! <span style="color: #008080">is_array</span>(<span style="color: #800080">$memcachedStatus</span><span style="color: #000000">)) { </span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> RuntimeException('No Memcached servers added.'<span style="color: #000000">); } </span><span style="color: #0000ff">if</span> (<span style="color: #008080">in_array</span>('255.255.255', <span style="color: #800080">$memcachedStatus</span>) && <span style="color: #008080">count</span>(<span style="color: #008080">array_unique</span>(<span style="color: #800080">$memcachedStatus</span>)) === 1<span style="color: #000000">) { </span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> RuntimeException('Could not establish Memcached connection.'<span style="color: #000000">); } </span><span style="color: #0000ff">return</span> <span style="color: #800080">$memcached</span><span style="color: #000000">; }</span>
可以看到laravel的Memcached沒有設定setOption方法的選項,只包含最簡連接建立,緊接著就呼叫getVersion來測試是否連通。而阿里雲的示範程式碼是設定了關閉壓縮和使用binary二進位協定的選項的。
沒辦法只能自己來擴充Memcached的功能實作自訂選項。 laravel中擴充快取可以使用Cache::extend來擴充。擴充程式碼如下:
Cache::extend('MemcachedExtend', <span style="color: #0000ff">function</span> (<span style="color: #800080">$app</span><span style="color: #000000">) { </span><span style="color: #800080">$memcached</span> = <span style="color: #800080">$this</span>->createMemcached(<span style="color: #800080">$app</span><span style="color: #000000">); </span><span style="color: #008000">//</span><span style="color: #008000"> 从配置文件中读取缓存前缀</span> <span style="color: #800080">$prefix</span> = <span style="color: #800080">$app</span>['config']['cache.prefix'<span style="color: #000000">]; </span><span style="color: #008000">//</span><span style="color: #008000"> 创建 MemcachedStore 对象</span> <span style="color: #800080">$store</span> = <span style="color: #0000ff">new</span> MemcachedStore(<span style="color: #800080">$memcached</span>, <span style="color: #800080">$prefix</span><span style="color: #000000">); </span><span style="color: #008000">//</span><span style="color: #008000"> 创建 Repository 对象,并返回</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> Repository(<span style="color: #800080">$store</span><span style="color: #000000">); });</span>
<span style="color: #008000">/*</span><span style="color: #008000">* * 创建Memcached对象 * @param $app * @return mixed </span><span style="color: #008000">*/</span> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">function</span> createMemcached(<span style="color: #800080">$app</span><span style="color: #000000">) { </span><span style="color: #008000">//</span><span style="color: #008000"> 从配置文件中读取 Memcached 服务器配置</span> <span style="color: #800080">$servers</span> = <span style="color: #800080">$app</span>['config']['cache.stores.MemcachedExtend.servers'<span style="color: #000000">]; </span><span style="color: #008000">//</span><span style="color: #008000"> 利用 Illuminate\Cache\MemcachedConnector 类来创建新的 Memcached 对象</span> <span style="color: #800080">$memcached</span> = <span style="color: #0000ff">new</span><span style="color: #000000"> \Memcached; </span><span style="color: #0000ff">foreach</span> (<span style="color: #800080">$servers</span> <span style="color: #0000ff">as</span> <span style="color: #800080">$server</span><span style="color: #000000">) { </span><span style="color: #800080">$memcached</span>-><span style="color: #000000">addServer( </span><span style="color: #800080">$server</span>['host'], <span style="color: #800080">$server</span>['port'], <span style="color: #800080">$server</span>['weight'<span style="color: #000000">] ); } </span><span style="color: #008000">//</span><span style="color: #008000"> 如果服务器上的 PHP Memcached 扩展支持 SASL 认证</span> <span style="color: #0000ff">if</span> (<span style="color: #008080">ini_get</span>('memcached.use_sasl') && <span style="color: #0000ff">isset</span>(<span style="color: #800080">$app</span>['config']['cache.storess.MemcachedExtend.memcached_user']) && <span style="color: #0000ff">isset</span>(<span style="color: #800080">$app</span>['config']['cache.storess.MemcachedExtend.memcached_pass'<span style="color: #000000">])) { </span><span style="color: #008000">//</span><span style="color: #008000"> 从配置文件中读取 sasl 认证用户名</span> <span style="color: #800080">$user</span> = <span style="color: #800080">$app</span>['config']['cache.storess.MemcachedExtend.memcached_user'<span style="color: #000000">]; </span><span style="color: #008000">//</span><span style="color: #008000"> 从配置文件中读取 sasl 认证密码</span> <span style="color: #800080">$pass</span> = <span style="color: #800080">$app</span>['config']['cache.storess.MemcachedExtend.memcached_pass'<span style="color: #000000">]; </span><span style="color: #008000">//</span><span style="color: #008000"> 指定用于 sasl 认证的账号密码</span> <span style="color: #800080">$memcached</span>->setSaslAuthData(<span style="color: #800080">$user</span>, <span style="color: #800080">$pass</span><span style="color: #000000">); } </span><span style="color: #008000">//</span><span style="color: #008000">扩展</span> <span style="color: #0000ff">if</span> (<span style="color: #0000ff">isset</span>(<span style="color: #800080">$app</span>['config']['cache.stores.MemcachedExtend.options'<span style="color: #000000">])) { </span><span style="color: #0000ff">foreach</span> (<span style="color: #800080">$app</span>['config']['cache.stores.MemcachedExtend.options'] <span style="color: #0000ff">as</span> <span style="color: #800080">$key</span> => <span style="color: #800080">$option</span><span style="color: #000000">) { </span><span style="color: #800080">$memcached</span>->setOption(<span style="color: #800080">$key</span>, <span style="color: #800080">$option</span><span style="color: #000000">); } } </span><span style="color: #800080">$memcachedStatus</span> = <span style="color: #800080">$memcached</span>-><span style="color: #000000">getVersion(); </span><span style="color: #0000ff">if</span> (! <span style="color: #008080">is_array</span>(<span style="color: #800080">$memcachedStatus</span><span style="color: #000000">)) { </span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> RuntimeException('No Memcached servers added.'<span style="color: #000000">); } </span><span style="color: #0000ff">if</span> (<span style="color: #008080">in_array</span>('255.255.255', <span style="color: #800080">$memcachedStatus</span>) && <span style="color: #008080">count</span>(<span style="color: #008080">array_unique</span>(<span style="color: #800080">$memcachedStatus</span>)) === 1<span style="color: #000000">) { </span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> RuntimeException('Could not establish Memcached connection.'<span style="color: #000000">); } </span><span style="color: #0000ff">return</span> <span style="color: #800080">$memcached</span><span style="color: #000000">; }</span>
網路上有流傳的laravel快取擴充的文章,其中對設定讀取在5.2以上版本不適用。
快取擴充後的程式碼是需要建立一個ServiceProvider來註冊服務提供者。服務提供者是Laravel應用程式啟動的中心,你自己的應用程式以及所有Laravel的核心服務都是透過服務提供者啟動。
但是,我們所謂的「啟動」指的是什麼?通常,這意味著註冊事物,包括註冊服務容器綁定、事件監聽器、中間件甚至路由。服務提供者是應用程式配置的中心。
如果你打開Laravel自帶的config/app.php文件,將會看到一個providers數組,這裡就是應用所要加載的所有服務提供者類,當然,其中很多是延遲加載的,也就是說不是每次請求都會被加載,只有真的用到它們的時候才會加載。
所有的服務提供者都繼承自IlluminateSupportServiceProvider類別。服務提供者大多包含兩種方法: register 和 boot 。在register方法中,你唯一要做的事情就是綁事物到服務容器,不要嘗試在其中註冊事件監聽器,路由或任何其它功能。
透過Artisan指令make:provider可以簡單產生一個新的提供者:
php artisan <span style="color: #0000ff">make</span>:provider MemcachedExtendServiceProvider
所有服務提供者都是透過設定檔config/app.php註冊,該檔案包含了一個列出所有服務提供者名字的providers數組,預設情況下,其中列出了所有核心服務提供者,這些服務提供者啟動Laravel核心元件,例如郵件、佇列、快取等等。
要註冊自己的服務提供者,只需要將其追加到該數組中即可:
<span style="color: #800000">'</span><span style="color: #800000">providers</span><span style="color: #800000">'</span> =><span style="color: #000000"> [ SmartWiki\Providers\MemcachedExtendServiceProvider::class </span><span style="color: #008000">//</span><span style="color: #008000">在providers节点添加实现的provider</span> ]
同時在config/cache.php中設定Memcached設定:
'MemcachedExtend' =><span style="color: #000000"> [ </span>'driver' => 'MemcachedExtend', 'servers' =><span style="color: #000000"> [ [ </span>'host' => env('MEMCACHED_EXTEND_HOST', '127.0.0.1'), 'port' => env('MEMCACHED_EXTEND_PORT', 11211), 'weight' => 100,<span style="color: #000000"> ]</span>,<span style="color: #000000"> ]</span>, 'options' =><span style="color: #000000"> [ \Memcached</span>::OPT_BINARY_PROTOCOL => <span style="color: #0000ff">true</span>,<span style="color: #000000"> \Memcached</span>::OPT_COMPRESSION => <span style="color: #0000ff">false</span><span style="color: #000000"> ] ]</span>
如果需要把Session也儲存到我們擴充的快取中還需要呼叫Session::extend來擴充我們的Session儲存:
Session::extend('MemcachedExtend',<span style="color: #0000ff">function</span> (<span style="color: #800080">$app</span><span style="color: #000000">){ </span><span style="color: #800080">$memcached</span> = <span style="color: #800080">$this</span>->createMemcached(<span style="color: #800080">$app</span><span style="color: #000000">); </span><span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> MemcachedSessionHandler(<span style="color: #800080">$memcached</span><span style="color: #000000">); });</span>
之後再.env中就可以配置我們擴充後的快取了。完整程式碼如下:
<?<span style="color: #000000">php namespace SmartWiki\Providers; </span><span style="color: #0000ff">use</span><span style="color: #000000"> Illuminate\Cache\Repository; </span><span style="color: #0000ff">use</span><span style="color: #000000"> Illuminate\Cache\MemcachedStore; </span><span style="color: #0000ff">use</span><span style="color: #000000"> Illuminate\Support\ServiceProvider; </span><span style="color: #0000ff">use</span><span style="color: #000000"> Cache; </span><span style="color: #0000ff">use</span><span style="color: #000000"> Session; </span><span style="color: #0000ff">use</span><span style="color: #000000"> Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcachedSessionHandler; </span><span style="color: #0000ff">use</span><span style="color: #000000"> RuntimeException; </span><span style="color: #0000ff">class</span> MemcachedExtendServiceProvider <span style="color: #0000ff">extends</span><span style="color: #000000"> ServiceProvider { </span><span style="color: #008000">/*</span><span style="color: #008000">* * Bootstrap the application services. * * @return void </span><span style="color: #008000">*/</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">function</span><span style="color: #000000"> boot() { Cache</span>::extend('MemcachedExtend', <span style="color: #0000ff">function</span> (<span style="color: #800080">$app</span><span style="color: #000000">) { </span><span style="color: #800080">$memcached</span> = <span style="color: #800080">$this</span>->createMemcached(<span style="color: #800080">$app</span><span style="color: #000000">); </span><span style="color: #008000">//</span><span style="color: #008000"> 从配置文件中读取缓存前缀</span> <span style="color: #800080">$prefix</span> = <span style="color: #800080">$app</span>['config']['cache.prefix'<span style="color: #000000">]; </span><span style="color: #008000">//</span><span style="color: #008000"> 创建 MemcachedStore 对象</span> <span style="color: #800080">$store</span> = <span style="color: #0000ff">new</span> MemcachedStore(<span style="color: #800080">$memcached</span>, <span style="color: #800080">$prefix</span><span style="color: #000000">); </span><span style="color: #008000">//</span><span style="color: #008000"> 创建 Repository 对象,并返回</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> Repository(<span style="color: #800080">$store</span><span style="color: #000000">); }); Session</span>::extend('MemcachedExtend',<span style="color: #0000ff">function</span> (<span style="color: #800080">$app</span><span style="color: #000000">){ </span><span style="color: #800080">$memcached</span> = <span style="color: #800080">$this</span>->createMemcached(<span style="color: #800080">$app</span><span style="color: #000000">); </span><span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> MemcachedSessionHandler(<span style="color: #800080">$memcached</span><span style="color: #000000">); }); } </span><span style="color: #008000">/*</span><span style="color: #008000">* * Register the application services. * * @return void </span><span style="color: #008000">*/</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">function</span><span style="color: #000000"> register() { </span><span style="color: #008000">// </span><span style="color: #000000"> } </span><span style="color: #008000">/*</span><span style="color: #008000">* * 创建Memcached对象 * @param $app * @return mixed </span><span style="color: #008000">*/</span> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">function</span> createMemcached(<span style="color: #800080">$app</span><span style="color: #000000">) { </span><span style="color: #008000">//</span><span style="color: #008000"> 从配置文件中读取 Memcached 服务器配置</span> <span style="color: #800080">$servers</span> = <span style="color: #800080">$app</span>['config']['cache.stores.MemcachedExtend.servers'<span style="color: #000000">]; </span><span style="color: #008000">//</span><span style="color: #008000"> 利用 Illuminate\Cache\MemcachedConnector 类来创建新的 Memcached 对象</span> <span style="color: #800080">$memcached</span> = <span style="color: #0000ff">new</span><span style="color: #000000"> \Memcached; </span><span style="color: #0000ff">foreach</span> (<span style="color: #800080">$servers</span> <span style="color: #0000ff">as</span> <span style="color: #800080">$server</span><span style="color: #000000">) { </span><span style="color: #800080">$memcached</span>-><span style="color: #000000">addServer( </span><span style="color: #800080">$server</span>['host'], <span style="color: #800080">$server</span>['port'], <span style="color: #800080">$server</span>['weight'<span style="color: #000000">] ); } </span><span style="color: #008000">//</span><span style="color: #008000"> 如果服务器上的 PHP Memcached 扩展支持 SASL 认证</span> <span style="color: #0000ff">if</span> (<span style="color: #008080">ini_get</span>('memcached.use_sasl') && <span style="color: #0000ff">isset</span>(<span style="color: #800080">$app</span>['config']['cache.storess.MemcachedExtend.memcached_user']) && <span style="color: #0000ff">isset</span>(<span style="color: #800080">$app</span>['config']['cache.storess.MemcachedExtend.memcached_pass'<span style="color: #000000">])) { </span><span style="color: #008000">//</span><span style="color: #008000"> 从配置文件中读取 sasl 认证用户名</span> <span style="color: #800080">$user</span> = <span style="color: #800080">$app</span>['config']['cache.storess.MemcachedExtend.memcached_user'<span style="color: #000000">]; </span><span style="color: #008000">//</span><span style="color: #008000"> 从配置文件中读取 sasl 认证密码</span> <span style="color: #800080">$pass</span> = <span style="color: #800080">$app</span>['config']['cache.storess.MemcachedExtend.memcached_pass'<span style="color: #000000">]; </span><span style="color: #008000">//</span><span style="color: #008000"> 指定用于 sasl 认证的账号密码</span> <span style="color: #800080">$memcached</span>->setSaslAuthData(<span style="color: #800080">$user</span>, <span style="color: #800080">$pass</span><span style="color: #000000">); } </span><span style="color: #008000">//</span><span style="color: #008000">扩展</span> <span style="color: #0000ff">if</span> (<span style="color: #0000ff">isset</span>(<span style="color: #800080">$app</span>['config']['cache.stores.MemcachedExtend.options'<span style="color: #000000">])) { </span><span style="color: #0000ff">foreach</span> (<span style="color: #800080">$app</span>['config']['cache.stores.MemcachedExtend.options'] <span style="color: #0000ff">as</span> <span style="color: #800080">$key</span> => <span style="color: #800080">$option</span><span style="color: #000000">) { </span><span style="color: #800080">$memcached</span>->setOption(<span style="color: #800080">$key</span>, <span style="color: #800080">$option</span><span style="color: #000000">); } } </span><span style="color: #800080">$memcachedStatus</span> = <span style="color: #800080">$memcached</span>-><span style="color: #000000">getVersion(); </span><span style="color: #0000ff">if</span> (! <span style="color: #008080">is_array</span>(<span style="color: #800080">$memcachedStatus</span><span style="color: #000000">)) { </span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> RuntimeException('No Memcached servers added.'<span style="color: #000000">); } </span><span style="color: #0000ff">if</span> (<span style="color: #008080">in_array</span>('255.255.255', <span style="color: #800080">$memcachedStatus</span>) && <span style="color: #008080">count</span>(<span style="color: #008080">array_unique</span>(<span style="color: #800080">$memcachedStatus</span>)) === 1<span style="color: #000000">) { </span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> RuntimeException('Could not establish Memcached connection.'<span style="color: #000000">); } </span><span style="color: #0000ff">return</span> <span style="color: #800080">$memcached</span><span style="color: #000000">; } }</span>
SmartWiki官網: https://www.iminho.me
SmartWiki原始碼: https://github.com/lifei6671/SmartWiki