参考的http://beebole.com/blog/erlang/how-to-implement-captcha-in-erlang-web-application/,移到cowboy,修改了下;废话不多说,直接贴代码
注意,需要cowboy版本1.0.1
需要imagemagick
sudo apt-get install imagemagick
mac
brew install imagemagick
mac下如果使用convert命令找不到字体,则需要安装下这个
brew install ghostscript
创建工程
rebar-creator create-app testCaptcha
testCaptcha_app
-module(testCaptcha_app). -behaviour(application). -export([start/2, stop/1]). -define(C_ACCEPTORS, 100). start(_StartType, _StartArgs) -> simple_captcha_ets:init(), application:start(crypto), application:start(cowlib), application:start(ranch), application:start(cowboy), Routes = route_helper:get_routes(), Dispatch = cowboy_router:compile(Routes), Port = 8080, TransOpts = [{port, Port}], ProtoOpts = [{env, [{dispatch, Dispatch}]}], cowboy:start_http(http, ?C_ACCEPTORS, TransOpts, ProtoOpts). stop(_State) -> simple_captcha_ets:destroy(), ok.
route_helper
-module(route_helper). -export([get_routes/0]). get_routes() -> [ {'_', [ {"/captcha", captcha_handler, []}, {"/captcha_check", captcha_check_handler, []} ]} ].
simple_captcha
-module(simple_captcha). -export([create/0,check/2]). create() -> CryptKey = mochihex:to_hex(crypto:rand_bytes(16)), Code = generate_rand(5), FileName = lists:flatmap(fun(Item) -> integer_to_list(Item) end, tuple_to_list(now())), File = io_lib:format("/tmp/~s.png",[FileName]), Cmd = io_lib:format("convert -background 'none' -fill '#222222' -size 175 -gravity Center -wave 5x100 -swirl 50 -font DejaVu-Serif-Book -pointsize 28 label:~s -draw 'Bezier 10,40 50,35 100,35 150,35 200,50 250,35 300,35' ~s", [Code, File]), os:cmd(Cmd), {ok, BinPng} = file:read_file(File), file:delete(File), simple_captcha_ets:insert(Code,CryptKey), {erlang:list_to_bitstring(CryptKey),BinPng}. check(CryptKeyBitString,CodeBitString) -> CryptKey = erlang:bitstring_to_list(CryptKeyBitString), Code = erlang:bitstring_to_list(CodeBitString), CryptKeyFromEts = simple_captcha_ets:find(Code), case string:equal(CryptKeyFromEts,CryptKey) of true -> simple_captcha_ets:remove(code), true; _ -> false end. %private generate_rand(Length) -> Now = now(), random:seed(element(1, Now), element(2, Now), element(3, Now)), lists:foldl(fun(_I, Acc) -> [do_rand(0) | Acc] end, [], lists:seq(1, Length)). do_rand(R) when R > 46, R < 58; R > 64, R < 91; R > 96 -> R; do_rand(_R) -> do_rand(47 + random:uniform(75)).
simple_captcha_ets
-module(simple_captcha_ets). -export([init/0,insert/2,find/1,remove/1,destroy/0]). init()-> TableName = ets:new(simple_captcha, [public,named_table]), {ok, TableName}. insert(Key,Value) -> ets:insert(simple_captcha, {Key, Value}), ok. find(Key) -> Result = ( try ets:lookup_element(simple_captcha, Key, 2) of Value -> Value catch _:_ -> "" end ), Result. remove(Key) -> try ets:delete(simple_captcha, Key) catch _:_ -> ok end. destroy()-> try ets:delete(simple_captcha) catch _:_ -> ok end.
mochihex
自己下载
captcha_handler
-module(captcha_handler). -export([init/3]). -export([handle/2]). -export([terminate/3]). init(_Transport, Req, []) -> {ok, Req, undefined}. handle(Req, State) -> %CryptKey用于验证的时候用,需本地保存,CapCode为用户提交的数据 %simple_captcha:check(CryptKey, CapCode) {CryptKey,BinPng} = simple_captcha:create(), Req2 = cowboy_req:set_resp_cookie(<<"cap">>, CryptKey, [{path, <<"/">>}], Req), {ok, Req3} = cowboy_req:reply(200, [{<<"content-type">>, <<"image/png">>}],BinPng, Req2), {ok, Req3, State}. terminate(_Reason, _Req, _State) -> ok.
captcha_check_handler
-module(captcha_check_handler). -export([init/3]). -export([handle/2]). -export([terminate/3]). init(_Transport, Req, []) -> {ok, Req, undefined}. handle(Req, State) -> {CryptKey,_} = cowboy_req:cookie(<<"cap">>, Req,<<"">>), {ok, PostVals, Req2} = cowboy_req:body_qs(Req), CaptchaCode = proplists:get_value(<<"captchaCode">>, PostVals), case simple_captcha:check(CryptKey, CaptchaCode) of true -> {ok, Req3} = cowboy_req:reply(200, [{<<"content-type">>, <<"text/html">>}],<<"ok">>, Req2), {ok, Req3, State}; _ -> {ok, Req3} = cowboy_req:reply(200, [{<<"content-type">>, <<"text/html">>}],<<"error">>, Req2), {ok, Req3, State} end. terminate(_Reason, _Req, _State) -> ok.
rebar.config
% -*- erlang -*- {erl_opts, [debug_info]}. {deps, [ {cowboy,".*", {git, "https://github.com/ninenines/cowboy", {tag,"1.0.1"}}} ]}. {cover_enabled, true}. {eunit_opts, [verbose, {report,{eunit_surefire,[{dir,"."}]}}]}. {sub_dirs, ["apps/testCaptcha", "rel"]}.
run.sh
#!/bin/sh rebar clean; rebar compile; erl -pa apps/*/ebin deps/*/ebin -eval "application:start(testCaptcha)."
captcha_test.html
<img src="http://127.0.0.1:8080/captcha" width="100" height="100"> <form action="http://127.0.0.1:8080/captcha_check" method="post"> <p>captcha<input type="text" name="captchaCode" /></p> <input type="submit" value="Submit" /> </form>
收工