国内怎么captcha测试
Things That Drive Us Nuts
驱使我们坚果的东西
Have you noticed the use of the reCaptcha feature at EE and other web sites? It wants you to read and retype something that looks like this.
Insanity! It's not EE's fault - that's just the way reCaptcha works. But it is a far cry from a good user experience.您是否注意到EE和其他网站上使用了reCaptcha功能? 它希望您阅读并重新输入类似以下内容的内容。 疯狂! 这不是EE的错-这只是reCaptcha的工作方式。 但这与良好的用户体验相去甚远。
This article is about how to apply some sanity in the CAPTCHA process. It does not have to cause eyestrain for your clients, and it will likely be nearly as secure as the agonizing and unreadable stuff that reCaptcha cranks out. In the process of creating an image-based CAPTCHA test, we will learn something about PHP image manipulation.
本文介绍如何在验证码过程中应用一些理智的方法。 它不必引起客户的视线疲劳,它的安全性几乎可以与reCaptcha激起的痛苦而难以理解的东西一样安全。 在创建基于图像的CAPTCHA测试的过程中,我们将学习有关PHP图像操作的知识。
Anti-Spam and Anti-'Bot Tools (Power to the People)
反垃圾邮件和反僵尸工具(人民力量)
The term CAPTCHA is "sort of" an acronym. It stands for Completely Automated Public Test (to tell) Computers and Humans Apart. The theory is fairly simple. Your server-side script gives the client a test that a human can pass easily but a computer cannot readily understand. You can read more about the theory and implementations here, and in the Wikipedia.
术语CAPTCHA是“某种”缩写。 它代表“完全自动化的公共测试(告诉)计算机和人类分开”。 这个理论很简单。 您的服务器端脚本为客户端提供了一个测试,测试人员可以轻松通过,但计算机无法轻松理解。 您可以在此处和Wikipedia中阅读有关理论和实现的更多信息。
http://en.wikipedia.org/wiki/CAPTCHA
http://en.wikipedia.org/wiki/CAPTCHA
Invisible CAPTCHA
隐形验证码
A "honeypot" is a form element that should not be filled in when a human completes the form. You can give a form input control a tempting name, like "email" and style the input with CSS to make it invisible on the browser. If the form contains any data in the tempting input field, you can discard the request, since this would not have come from a human being.
“蜜罐”是一个表单元素,当人类完成表单时不应填写。 您可以为表单输入控件提供一个诱人的名称,例如“电子邮件”,并使用CSS设置输入样式,以使其在浏览器中不可见。 如果表单在诱人的输入字段中包含任何数据,则可以丢弃该请求,因为这不是来自人的。
<?php // RAY_honeypot.php
error_reporting(E_ALL);
// DEMONSTRATE A HONEYPOT CAPTCHA TEST
// IF THE FORM HAS BEEN FILLED IN
if (!empty($_POST))
{
// IF THE HONEYPOT HAS BEEN FILLED IN
if (!empty($_POST['email'])) trigger_error("BE GONE, ATTACK BOT!", E_USER_ERROR);
// PROCESS THE REST OF THE FORM DATA HERE
var_dump($_POST);
}
// CREATE THE FORM
$form = <<<EOD
<style type="text/css">
.honey {
display:none;
}
</style>
<form method="post">
<input name="email" class="honey" />
<input name="thing" />
<input type="submit" />
</form>
EOD;
echo $form;
Minimalist CAPTCHA
极简主义验证码
One step up from an invisible CAPTCHA might be a checkbox that says, "Check this box to prove you're a human." Not very deep, but arguably effective in a limited way. And there is this from the endearing "A Word a Day" site.
Another simple design pattern is a form field that has a value filled in. The web page asks the human to clear the field before submitting the form. Visually Based CAPTCHA Test一个不可见的验证码可能会比以前高出一个复选框,上面写着:“选中此框以证明您是人。” 不是很深,但是可以说是有限的有效。 而这是来自“ A Word a Day ”网站的。
另一个简单的设计模式是填写值的表单字段。网页要求人员在提交表单之前清除该字段。 基于视觉的CAPTCHA测试To reduce the risk of automated registration, the Craftsy web site uses a simple visual CAPTCHA. The client is asked what animal is shown. Craftsy may find the 1:4 ratio of possibilities acceptable; statistically speaking, an attack 'bot could be right about the animal 25% of the time. If Craftsy couples its CAPTCHA with some kind of email verification this is probably acceptable protection.
At a slightly higher level, when there is common knowledge in a community, you might ask the client to enter the name of, for example, the school mascot. The server-side verification for these tests is very simple, usually only a single if() statement.为了降低自动注册的风险,Crafsy网站使用了一个简单的可视CAPTCHA。 询问客户显示了什么动物。 狡猾的人可能会发现1:4的可能性是可以接受的; 从统计学上讲,“攻击机器人”可能有25%的时间是正确的。 如果Craftsy将其验证码与某种电子邮件验证结合使用,则这可能是可以接受的保护措施。 在较高的层次上,如果社区中有常识,您可能会要求客户输入例如学校吉祥物的名称。 这些测试的服务器端验证非常简单,通常只有一个if()语句。
A CAPTCHA Test with Simple Arithmetic
简单算术验证码
You can copy this script, put it on your server and run it to see the effect. The script chooses two numbers at random, then chooses among several possible arithmetic operations to produce a CAPTCHA test that writes out an English-language simple math problem. The client experience in this structure is very similar to the CAPTCHA test on the comment feature of the PHP.net web site. It is easy to implement and easy for the client to use, but for a 'bot to readily defeat it, there would be a lot of programming required. The web site would use the getQuestion() method in the HTML form script, and would use the testAnswer() method in the action= script. Give it a try, and if it's good enough for your work, enjoy it. And if you feel you need greater obscurity, read on below for the image-based CAPTCHA tests.
您可以复制此脚本,将其放在服务器上并运行它以查看效果。 该脚本会随机选择两个数字,然后从几个可能的算术运算中进行选择,以产生一个可以写出英语简单数学问题的CAPTCHA测试。 这种结构的客户体验与PHP.net网站的注释功能上的CAPTCHA测试非常相似。 它易于实现且易于客户端使用,但是要使“机器人”轻松击败它,将需要进行大量编程。 该网站将使用getQuestion()方法在HTML表单脚本,将使用testAnswer()方法在行动=脚本。 尝试一下,如果对您的工作足够好,请尽情享受。 并且,如果您觉得需要更多的知识,请在下面阅读基于图像的CAPTCHA测试。
<?php // RAY_captcha_class.php
error_reporting(E_ALL);
// DEPENDS ON THE PHP SESSION
session_start();
echo '<pre>';
Class CAPTCHA
{
// NULL CONSTRUCTOR
public function __construct() { }
// RETURN A CAPTCHA QUESTION IN THE FORM OF A STRING
public function getQuestion()
{
// NUMBER NAMES CONVENIENTLY INDEXED BY VALUES
$nums = array
( 'Zero'
, 'One'
, 'Two'
, 'Three'
, 'Four'
, 'Five'
, 'Six'
, 'Seven'
, 'Eight'
, 'Nine'
, 'Ten'
, 'Eleven'
, 'Twelve'
, 'Thirteen'
, 'Fourteen'
, 'Fifteen'
, 'Sixteen'
, 'Seventeen'
, 'Eighteen'
)
;
// THE UPPER LIMIT FOR ANSWERS
$max = count($nums) - 1;
// A PLACE TO HOLD THE QUESTIONS
$ops = array();
// SOME RANDOM NUMBERS AND A RANDOM OPERATION
while (count($ops) < 6)
{
// CHOOSE TWO RANDOM NUMBERS WITHIN THE RANGE
$num1 = rand(0, $max);
$num2 = rand(0, $max);
// COLLECT SOME OPERATIONS THAT GENERATE USEFUL VALUES
$ans = $num1 + $num2;
if ($ans <= $max) $ops[] = "What is $nums[$num1] Plus $nums[$num2]?|$ans";
$ans = $num1 * $num2;
if ($ans <= $max) $ops[] = "What is $nums[$num1] Times $nums[$num2]?|$ans";
$ans = $num1 - $num2;
if ($ans >= 0) $ops[] = "What is $nums[$num1] Minus $nums[$num2]?|$ans";
$ans = $num2 - $num1;
if ($ans >= 0) $ops[] = "What is $nums[$num2] Minus $nums[$num1]?|$ans";
if ($num2)
{
if ( ($num1 % $num2) == 0 )
{
$ans = $num1 / $num2;
$ops[] = "What is $nums[$num1] Divided By $nums[$num2]?|$ans";
}
}
if ($num1)
{
if ( ($num2 % $num1) == 0 )
{
$ans = $num2 / $num1;
$ops[] = "What is $nums[$num2] Divided By $nums[$num1]?|$ans";
}
}
// COLLECT MIN/MAX TESTS
if ($num1 < $num2)
{
$ops[] = "What is MIN ($nums[$num1], $nums[$num2])?|$num1";
$ops[] = "What is MAX ($nums[$num1], $nums[$num2])?|$num2";
}
if ($num1 > $num2)
{
$ops[] = "What is MAX ($nums[$num1], $nums[$num2])?|$num1";
$ops[] = "What is MIN ($nums[$num1], $nums[$num2])?|$num2";
}
}
// CHOOSE THE QUESTION AND ANSWER
shuffle($ops);
$qry = array_pop($ops);
$arr = explode('|', $qry);
// SAVE THE QUESTION AND BOTH ANSWERS
$_SESSION['CAPTCHA_qry'] = $arr[0];
$_SESSION['CAPTCHA_int'] = $arr[1];
$_SESSION['CAPTCHA_ans'] = $nums[$arr[1]];
// RETURN THE QUESTION STRING
return $arr[0];
}
// RELY ON THE SUPERGLOBAL VARIABLES ONLY
public function testAnswer()
{
// NORMALIZE AND COMPARE THE ANSWER
$ans = isset($_POST['CAPTCHA_ans']) ? trim(strtoupper($_POST['CAPTCHA_ans'])) : '?';
$ses = isset($_SESSION['CAPTCHA_ans']) ? trim(strtoupper($_SESSION['CAPTCHA_ans'])): '??';
$int = isset($_SESSION['CAPTCHA_int']) ? $_SESSION['CAPTCHA_int'] : '???';
if ( ($ans != $ses) && ($ans != $int) ) return FALSE;
return TRUE;
}
}
// USE CASE
$x = new CAPTCHA;
// IF THE ANSWER HAS BEEN POSTED
if (!empty($_POST))
{
// CALL THE METHOD TO TEST THE ANSWER
if ($x->testAnswer())
{
echo "Yes! {$_SESSION['CAPTCHA_ans']} is correct. You passed the CAPTCHA test";
}
else echo "<b>No!</b> {$_SESSION['CAPTCHA_qry']} Not {$_POST['CAPTCHA_ans']}, but {$_SESSION['CAPTCHA_ans']}";
}
// GET A NEW CAPTCHA QUESTION
$question = $x->getQuestion();
// CREATE THE FORM WITH THE CAPTCHA QUESTION
$form = <<<ENDFORM
<form method="post">
$question
<input name="CAPTCHA_ans" autocomplete="off" />
<input type="submit" value="Try CAPTCHA" />
</form>
ENDFORM;
echo $form;
A Character-based CAPTCHA Test using AJAX to hide the CAPTCHA string
使用AJAX隐藏CAPTCHA字符串的基于字符的CAPTCHA测试
It would not make much sense to put the CAPTCHA string into the HTML document where it could be discovered by a 'bot and used to submit the form. This is the equivalent of the "form token," a security measure that was tried as a defense against Cross-Site Request Forgeries. The theory is that a script will generate and store a token that is unique to each HTML form. When the form is submitted, the token that is returned is expected to match the token that was sent with the form. The problem is that the 'bot can simply copy the token out of the form and submit it along with the request of the attack data. So we need a sturdier defense against HTML scraping. Note: if you're using a traditional CSRF token, you might want to take a look at this article that shows some sturdier defenses against a variety of attacks.
将CAPTCHA字符串放入HTML文档中(由“机器人”发现该字符串并用于提交表单)没有多大意义。 这相当于“表单令牌”,它是一种安全措施,曾被用来防御跨站请求伪造 。 从理论上讲,脚本将生成并存储每个HTML表单唯一的令牌。 提交表单后,返回的令牌应与表单发送的令牌匹配。 问题在于,“机器人”可以简单地从表单中复制令牌,然后将其与攻击数据的请求一起提交。 因此,我们需要针对HTML抓取的更严格的防御措施。 注意:如果您使用的是传统的CSRF令牌,则可能需要看一下这篇文章,该文章显示了针对各种攻击的更严格的防御措施。
If you're willing to accept that your clients must have JavaScript and Cookies to use your site, then we can use an AJAX strategy to obscure the CAPTCHA string. (If you're not already familiar with AJAX and jQuery, you might want to read this article). In this example we use two PHP scripts. One of them is called via an AJAX request at the time the client page is created. It returns the CAPTCHA string to the client browser and simultaneously stores a case-sensitive CAPTCHA string in the PHP session. The session_write_close() function is called to ensure that the session data is stored for use by the CAPTCHA validation script.
如果您愿意接受客户必须具有JavaScript和Cookies才能使用您的网站,那么我们可以使用AJAX策略来掩盖CAPTCHA字符串。 (如果您还不熟悉AJAX和jQuery,则可能需要阅读本文 )。 在此示例中,我们使用两个PHP脚本。 创建客户端页面时,通过AJAX请求调用其中之一。 它将CAPTCHA字符串返回到客户端浏览器,并同时在PHP会话中存储区分大小写的CAPTCHA字符串。 调用session_write_close()函数以确保存储会话数据以供CAPTCHA验证脚本使用。
<?php // demo/ajax_captcha_server.php
error_reporting(E_ALL);
// FUNCTION TO MAKE A RANDOM STRING
function random_string($length=5)
{
// POSSIBLE PERMUATIONS http://www.mathwords.com/p/permutation_formula.htm
// pow($length,strlen($alpha)); = 32*31*30*29*28 = 24,165,120 IF LENGTH IS 5
// 1...5...10...15...20...25...30......
$alpha = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
$array = str_split($alpha);
$randy = NULL;
while(strlen($randy) < $length)
{
// CHOOSE A LETTER AT RANDOM, USE IT AND REMOVE IT
$point = mt_rand(0, count($array)-1);
$randy .= $array[$point];
unset($array[$point]);
$array = array_values($array);
}
return $randy;
}
// CREATE AND SAVE THE STRING
session_start();
$_SESSION['captcha'] = random_string();
// RETURN THE STRING TO THE BROWSER
echo $_SESSION['captcha'];
// END OF TASK
session_write_close();
The second part is the client form. It uses JavaScript (jQuery) to dynamically load the CAPTCHA string into a browser element that is visible to the human, but not visible to web-scraping 'bots. For convenience, this example combines the action script at the top with the HTML form script at the bottom, into one script file.
第二部分是客户表格。 它使用JavaScript(jQuery)将CAPTCHA字符串动态加载到浏览器元素中,该元素对于人类是可见的,但对于抓取网络的“ bot”则不可见。 为了方便起见,此示例将顶部的操作脚本与底部HTML 表单脚本组合到一个脚本文件中。
<?php // demo/ajax_captcha_client.php
error_reporting(E_ALL);
// ALWAYS START THE SESSION ON EVERY PAGE LOAD
session_start();
// IF THERE IS A POST-METHOD REQUEST
if (!empty($_POST))
{
// TEST TO SEE IF THE USER-ENTERED CAPTCHA MATCHES THE STORED CAPTCHA
if ($_POST['captcha'] == $_SESSION['captcha'])
{
echo 'SUCCESS! ' . $_SESSION['captcha'];
}
else
{
echo 'FAIL. POST: ' . $_POST['captcha'] . ' vs SESSION: ' . $_SESSION['captcha'];
}
}
// GENERATE THE FORM
$htm = <<<EOD
<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8" />
<title>Ajax Captcha Example Using jQuery</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
$(document).ready(function(){
$.get("ajax_captcha_server.php", function(response){
$("#secret").html(response);
});
});
</script>
</head>
<body>
<form method="post">
Enter <span id="secret"></span> here:
<input name="captcha" autofocus autocomplete="off" />
<input type="submit" />
</form>
</body>
</html>
EOD;
echo $htm;
Google Upgrades reCaptcha to V2
Google将reCaptcha升级到V2
In 2014 it became obvious that character recognition programs had advanced to the point that they could recognize and decipher the letters in the original reCaptcha images, so reCaptcha was effectively defeated as an anti-spam tool. At the same time, Google was working on AI applications that sought to recognize and identify elements in pictures. Fortuitously, Google decided to use its AI research to create a new reCaptcha V2. Today, we can use the Google reCaptcha V2 to protect our pages. Go to the link and let Google walk you through the process. It's very easy, cut-and-paste. https://www.google.com/recaptcha/intro/
在2014年,很明显,字符识别程序已经发展到可以识别和破译原始reCaptcha图像中字母的程度,因此reCaptcha被有效地击败为反垃圾邮件工具。 同时,谷歌正在研究旨在识别和识别图片元素的AI应用程序。 幸运的是,Google决定利用其AI研究成果来创建新的reCaptcha V2 。 今天,我们可以使用Google reCaptcha V2保护我们的页面。 转到链接,让Google引导您完成整个过程。 剪切粘贴很简单。 https://www.google.com/recaptcha/intro/
When you visit the reCaptcha pages you will get a choice of invisible reCaptcha or reCaptcha V2. These notes pertain to V2. I chose V2 over the invisible reCaptcha because you become responsible for the flowdown of terms and conditions if you use an invisible Google service. You must notify the client, obtain their consent to use invisible form elements, etc. It seemed like it might be a little bit off-putting.
当您访问reCaptcha页面时,您将选择不可见的reCaptcha或reCaptcha V2。 这些说明与V2有关。 我选择V2而不是看不见的reCaptcha,因为如果您使用不可见的Google服务,您将负责条款和条件的流转。 您必须通知客户,征得他们的同意才能使用不可见的表单元素,等等。这似乎有点令人反感。
To use reCaptcha V2 you must get a pair of keys from Google. One is public and one is private. Both are associated with your domain, and they cover requests from any part of your domain. For my demonstration, the keys are designated to iconoun.com, and they cover http://iconoun.com, https://www.iconoun.com, https://iconoun.com/demo/, etc.
要使用reCaptcha V2,您必须从Google获得一对密钥。 一种是公开的,一种是私有的。 两者都与您的域相关联,并且涵盖了您域中任何部分的请求。 对于我的演示中,键指定iconoun.com,和它们覆盖http://iconoun.com,https://www.iconoun.com,https://iconoun.com/demo/等。
To activate reCaptcha for a form, you add a one-line <div> to the form. Easy!
要激活表单的reCaptcha,您可以在表单中添加一行<div>。 简单!
Install the code snippet below on your server. You can insert your own keys in the appropriate places and run the script; other than JSON there are no outside dependencies (JSON requires UTF-8). The behavior is illustrated below the code snippet.
在您的服务器上安装以下代码段。 您可以在适当的位置插入自己的密钥并运行脚本。 除了JSON外,没有任何外部依赖项(JSON需要UTF-8)。 该行为在代码段下方进行了说明。
<?php // demo/recaptcha_demo.php
/**
* https://www.experts-exchange.com/questions/29021437/Google-Recaptcha.html
*
* https://www.google.com/recaptcha/intro/
* https://media.giphy.com/media/fyc0IZqqFxspW/giphy.gif
*/
error_reporting(E_ALL);
// MAKE SURE THAT PHP WORKS WITH UTF-8
mb_internal_encoding('UTF-8');
mb_regex_encoding('UTF-8');
// SET THE reCaptcha KEYS AND VERIFICATION URL (GET YOUR OWN KEYS FROM GOOGLE)
$site_key = '???';
$secret_key = '???';
$verify_url = 'https://www.google.com/recaptcha/api/siteverify';
// IF THERE IS A REQUEST FROM OUR WEB PAGE
if (!empty($_POST))
{
// BUILD THE REQUEST STRING FOR OUR CALL TO GOOGLE
$query_arr = array
( 'secret' => $secret_key
, 'response' => $_POST['g-recaptcha-response']
, 'remoteip' => $_SERVER['REMOTE_ADDR']
)
;
$query_str = http_build_query($query_arr);
// THIS MUST BE A POST-METHOD REQUEST TO GOOGLE
$opts = array
( 'http' => array
( 'method' => 'POST'
, 'header' => 'Content-type: application/x-www-form-urlencoded'
, 'content' => $query_str
)
)
;
// MAKE THE POST REQUEST TO GOOGLE
$context = stream_context_create($opts);
$g_result = file_get_contents($verify_url, FALSE, $context);
// EXAMINE THE GOOGLE RESPONSE
$g_result = json_decode($g_result);
if ($g_result->success == 'true')
{
echo $_POST['email'] . " IS NOT A ROBOT :-)";
}
else
{
echo 'SORRY, YOU SMELL LIKE A ROBOT. REQUEST DISCARDED';
}
exit;
}
// CREATE OUR WEB PAGE IN HTML5 FORMAT, USING HEREDOC SYNTAX
$htm = <<<HTML5
<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>HTML5 Page With Google reCaptcha in UTF-8 Encoding</title>
<script src='https://www.google.com/recaptcha/api.js'></script>
</head>
<body>
<noscript>Your browsing experience will be much better with JavaScript enabled!</noscript>
<form method="post">
<div class="g-recaptcha" data-sitekey="$site_key"></div>
Enter your email: <input name="email" />
<br>
<input type="submit" />
</form>
</body>
</html>
HTML5;
// RENDER THE WEB PAGE
echo $htm;
When the form is first presented to the client, there is a checkbox
第一次向客户展示表单时,会有一个复选框

When the client checks the "I'm not a robot" box, a visual selection menu appears over the top of the form
当客户选中“我不是机器人”框时,表单上方会出现一个视觉选择菜单
Once the client has followed the instructions, a "verify" button appears
客户按照说明进行操作后,将出现“验证”按钮
Upon clicking the "verify" button, Google will assess the client's ability to follow the visual instructions. This process may be repeated for one or two more image tests, but it's generally easy and unobtrusive. When the client completes the visual exercises, Google injects g-recaptcha-response into the form, removes the visual overlay, and allows the form to be completed and submitted.
点击“验证”按钮后,Google会评估客户遵循视觉指示的能力。 对于一个或两个以上的图像测试,可以重复此过程,但这通常很容易且不会引起干扰。 客户完成视觉练习后,Google会将g-recaptcha-response注入表单,删除视觉覆盖,并允许表单完成并提交。
In the action script, you will find the g-recaptcha-response element in $_POST. Following the guidance in the code snippet above, you POST this response back to Google and Google returns a JSON string telling you if the client successfully passed the visual tests. If the "success" value is not "true" you can discard the request.
在操作脚本中,您将在$ _POST中找到g-recaptcha-response元素。 按照上面的代码片段中的指导,您将此响应发回到Google,然后Google返回一个JSON字符串,告诉您客户端是否成功通过了视觉测试。 如果“成功”值不是“ true”,则可以放弃该请求。
An Image-based CAPTCHA Test
基于图像的验证码测试
You can use PHP to create an image-based CAPTCHA test of your own. Our image-based CAPTCHA test will use a similar strategy -- to ask the client to enter a random 5-character string of letters and numbers. To begin, we need a function to generate the character string. This code snippet will do the job.
您可以使用PHP创建自己的基于图像的CAPTCHA测试。 我们基于图像的CAPTCHA测试将使用类似的策略-要求客户输入由5个字母和数字组成的随机字符串。 首先,我们需要一个函数来生成字符串。 此代码段将完成此工作。
<?php // RAY_EE_captcha_sanity.php
error_reporting(E_ALL);
// FUNCTION TO MAKE A RANDOM STRING
function random_string($length=5)
{
// POSSIBLE PERMUATIONS http://www.mathwords.com/p/permutation_formula.htm
// pow($length,strlen($alpha)); = 32*31*30*29*28 = 24,165,120 IF LENGTH IS 5
// 1...5...10...15...20...25...30......
$alpha = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
$array = str_split($alpha);
$randy = NULL;
while(strlen($randy) < $length)
{
// CHOOSE A LETTER AT RANDOM, USE IT AND REMOVE IT
$point = mt_rand(0, count($array)-1);
$randy .= $array[$point];
unset($array[$point]);
$array = array_values($array);
}
return $randy;
}
// TEST THE FUNCTION
echo random_string();
A couple of notes about the random_string() function. No character can be used more than once because we are planning to use the characters as array keys in our script that generates the images. Associative arrays can only have one value per key. That is why we remove each character as we choose it, and reset the array before choosing the next character. By doing this we ensure that the five characters are unique.
关于random_string()函数的几点说明。 不能多次使用任何字符,因为我们计划在生成图像的脚本中将字符用作数组键。 关联数组每个键只能有一个值。 这就是为什么我们在选择每个字符时都将其删除,然后在选择下一个字符之前重置数组。 通过这样做,我们确保五个字符是唯一的。
The length of the $alpha string has a great effect on the number of possible combinations. Making a longer string would be easy to do - just add the lower case characters and the special characters. But the alphabet we have already generates millions of different strings, and that seems like enough to me. If you're willing to live with only 863,040 combinations you can make the string four characters! The string length represents a trade-off between security and convenience.
$ alpha字符串的长度对可能的组合数量有很大的影响。 制作更长的字符串很容易-只需添加小写字符和特殊字符即可。 但是我们已经产生了数百万个不同的字符串的字母表,这对我来说似乎足够了。 如果您只愿意使用863,040个组合,则可以将字符串设置为四个字符! 字符串长度表示安全性和便利性之间的折衷。
You can also see that we intentionally left some characters out of our alphabet including O (oh), 0 (zero), I (eye) and 1 (one) because these characters can be visually confusing. If lower case letters are added to the mix it makes sense to omit l (ell) in addition to the others. Depending on the font you choose for the CAPTCHA string, it may make sense to omit 2 (two) and Z (zee) as well as S (ess) and 5 (five) and possibly 8 (eight).
您还可以看到,我们故意在字母中遗漏了一些字符,包括O (哦), 0 (零), I (眼睛)和1 (一),因为这些字符可能会造成视觉混乱。 如果将小写字母添加到混音中,则除其他字母外还可以省略l (ell)。 根据您为CAPTCHA字符串选择的字体,可能会省略2 (两个)和Z (zee), S (ess)和5 (5)以及可能的8 (八个)。
Creating an Image-Driven CAPTCHA Test
创建图像驱动的CAPTCHA测试
We also need a script that can generate an image of the random five-character string. We use an image instead of the actual characters because automation can readily detect the letters and numbers, and copy them into the form. This would defeat the effort to tell humans and computers apart. While some OCR programs can recognize the characters inside an image, they can often be confounded if we distort the image a little bit. We can use the PHP image functions to read in standard images of the characters and apply some distortion. In PHP the image functions are available if PHP is compiled with the bundled version of the GD library. Most modern PHP installations will include the GD library.
我们还需要一个可以生成随机五字符字符串图像的脚本。 我们使用图像代替实际字符,因为自动化可以轻松地检测字母和数字,并将其复制到表单中。 这将使区分人类和计算机的努力失败。 尽管某些OCR程序可以识别图像中的字符,但是如果我们稍微扭曲图像,它们通常会变得混乱。 我们可以使用PHP图像功能读取字符的标准图像并施加一些失真。 在PHP中,如果PHP是使用GD库的捆绑版本编译的,则图像功能可用。 大多数现代PHP安装将包括GD库。
Some Things That Did Not Work Very Well
有些事情效果不佳
I experimented with letting PHP generate the text, using ImageString(). The first CAPTCHA images looked something like this, and I felt that the images might be too easy to decode.
Next I tried adding some colorization and image distortion. It worked, but even the largest letters that ImageString() created seemed too small to me, and some of the rotations made some of the letters visually confusing. As a person of limited vision (in many senses of the term) I wanted larger letters, so I created my own alphabet images using the Georgia font. I made two-color black and white images of each letter. The attached PSD file (with layers for each letter) was my original file. Using Photoshop I saved each letter individually into its own PNG. Taken together, the entire collection of PNG images is less than 100KB. They look like this.
我尝试过使用ImageString()使PHP生成文本。 第一个CAPTCHA图像看起来像这样,我觉得这些图像可能太容易解码了。 接下来,我尝试添加一些着色和图像失真。 它起作用了,但是即使ImageString()创建的最大字母对我来说似乎也太小了,并且某些旋转使某些字母在视觉上令人困惑。
作为一个视力有限的人(从某种意义上来说,我是一个名词),我想要较大的字母,因此我使用Georgia字体创建了自己的字母图像。 我为每个字母制作了两个彩色的黑白图像。 附件的PSD文件(每个字母带有图层)是我的原始文件。 使用Photoshop,我将每个字母分别保存到自己的PNG中。 两者合计,PNG图像的整个集合小于100KB。 他们看起来像这样。 创建自动测试脚本Working with PHP image manipulation functions is complicated stuff, and it stands to reason that we will need to do a lot of testing. Anything we can do that makes the testing faster and easier makes sense. The first script we want to write is the test script that creates a CAPTCHA-protected form. To do that, our script generates the CAPTCHA string and stores it in the $_SESSION array. Then it creates the HTML form. In this script we combine the form script and the action script into one script file. The action script is the first part of this script file.
使用PHP图像操作功能是一件很复杂的事情,这是我们需要进行大量测试的理由。 我们可以做的任何事情都可以使测试变得更快,更容易。 我们要编写的第一个脚本是创建受CAPTCHA保护的表单的测试脚本。 为此,我们的脚本将生成CAPTCHA字符串并将其存储在$ _SESSION数组中。 然后,它创建HTML表单。 在此脚本中,我们将表单脚本和操作脚本组合到一个脚本文件中。 操作脚本是此脚本文件的第一部分。
There are three essential elements to testing the CAPTCHA response from the client. First, was the form posted (line 10)? Second, is there a CAPTCHA string in the session array (line 13)? Third, does the client input match the CAPTCHA string (line 16)? If these three tests are satisfied, we can process the form input (line 19). If either the second or third test fail, we do not process the form input and instead issue a message to the client (lines 24 or 29).
测试客户端的验证码响应包含三个基本元素。 首先,表格是否已张贴(第10行)? 第二,会话数组中是否存在CAPTCHA字符串(第13行)? 第三,客户端输入是否匹配CAPTCHA字符串(第16行)? 如果满足这三个测试,我们可以处理表单输入(第19行)。 如果第二个或第三个测试失败,我们将不处理表单输入,而是向客户端发出消息(第24或29行)。
If the form was not posted at all, we just skip the action part of this script and instead run the part that generates the CAPTCHA string and calls the image generator (lines 35-47).
如果根本没有发布该表单,则只需跳过此脚本的action部分,而是运行生成CAPTCHA字符串并调用图像生成器的部分(第35-47行)。
As you read this script over, note the use of strtoupper(). This has the effect of normalizing the client input to upper case and normalizing the CAPTCHA string to upper case. In other words, the entire process is made case-insensitive. The test script looks like this.
在阅读此脚本时,请注意strtoupper()的使用。 这具有将客户端输入标准化为大写并将CAPTCHA字符串标准化为大写的效果。 换句话说,整个过程不区分大小写。 测试脚本如下所示。
<?php // RAY_EE_captcha_sanity_in_action.php
error_reporting(E_ALL);
// REQUIRED FOR CARRYING THE RANDOM CAPTCHA STRING
session_start();
// IF ANYTHING WAS POSTED
if (!empty($_POST))
{
// IF THERE IS A CAPTCHA STRING IN THE SESSION ARRAY
if (isset($_SESSION["captcha"]))
{
// IF THE STRINGS MATCH (CASE-INSENSITIVE)
if (strtoupper($_POST["typed"]) == $_SESSION["captcha"])
{
// WE CAN NOW PROCESS THE FORM INPUT
echo "SUCCESS!";
}
else
{
// MIGHT WANT TO MAKE THIS USER-FRIENDLY
echo 'SECURITY CODE NUMBER DID NOT MATCH';
}
}
else
{
echo 'SECURITY CODE NUMBER IS MISSING - MAYBE THE SESSION TIMED OUT?';
}
}
// END OF PHP ACTION SCRIPT - PUT UP THE FORM
// STORE THE RANDOM STRING IN THE SESSION FOR USE BY THE IMAGE GENERATOR
$_SESSION["captcha"] = strtoupper(random_string());
$form = <<<FORM
<form method="post">
Type the security code you see below:
<input name="typed" type="text" autocomplete="off" />
<input type="submit" />
</form>
<img src="RAY_EE_captcha_sanity_image.php" />
FORM;
echo $form;
// FUNCTION TO MAKE A RANDOM STRING
function random_string($length=5)
{
// POSSIBLE PERMUATIONS http://www.mathwords.com/p/permutation_formula.htm
// pow($length,strlen($alpha)); = 32*31*30*29*28 = 24,165,120 IF LENGTH IS 5
// 1...5...10...15...20...25...30......
$alpha = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
$array = str_split($alpha);
$randy = NULL;
while(strlen($randy) < $length)
{
// CHOOSE A LETTER AT RANDOM, USE IT AND REMOVE IT
$point = mt_rand(0, count($array)-1);
$randy .= $array[$point];
unset($array[$point]);
$array = array_values($array);
}
return $randy;
}
Turning a Character String into an Image
将字符串转换为图像
Now we are ready to begin developing the CAPTCHA image generator using the alphabet of PNG images. The strategy is to create images of letters and numbers that are rotated and distorted in ways that would be able to confuse an OCR program, but would still be readable to humans.
现在,我们准备开始使用PNG图像字母开发CAPTCHA图像生成器。 该策略是创建字母和数字的图像,这些图像的旋转和变形会混淆OCR程序,但仍可被人类阅读。
Image manipulation in PHP requires some depth of understanding about the various image functions and they can be complicated things to remember, so to make an easy reference we put the man page URLs into the script comments near the top at lines 5-17.
PHP中的图像操作需要对各种图像功能有一定的了解,并且它们可能很复杂,需要记住,因此为了便于参考,我们将手册页URL放在脚本注释的顶部5-17行附近。
Script initialization occurs at the top in lines 20-35. Since we are working with predefined image files, we need to know their size and the URL path, and we need to know what alphanumeric characters to put into the image.
脚本初始化发生在第20-35行的顶部。 由于我们正在使用预定义的图像文件,因此我们需要知道它们的大小和URL路径,并且需要知道要在图像中放入哪些字母数字字符。
Beginning on line 39 we process each character one at a time. You can choose whether you like colorful letters or black and white letters. That choice is made in the $rgb array assigned in lines 41-54. You can omit one of these definitions.
从第39行开始,我们一次处理每个字符。 您可以选择喜欢彩色字母还是黑白字母。 在第41-54行分配的$ rgb数组中进行选择。 您可以忽略这些定义之一。
We select the foreground and background color at random (lines 57-59). We can do this because the colors in the $rgb array are of strong contrasts.
我们随机选择前景色和背景色(第57-59行)。 我们可以这样做是因为$ rgb数组中的颜色具有强烈的对比度。
We load the alphanumeric image into a PHP image resource (line 62) and assign our chosen foreground and background colors to the image (lines 64-82). This algorithm merits some discussion.
我们将字母数字图像加载到PHP图像资源中(第62行),并将我们选择的前景色和背景色分配给该图像(第64-82行)。 该算法值得一些讨论。
Assigning Colors to Paletted Images
为调色板图像分配颜色
You may be familiar with the RGB color notation. The values for red, green or blue range from zero for no output to 255 for maximum output. These values give the amount of on-screen brightness for each of these three color elements. In round numbers, there are 16 million possible colors in the RGB "spectrum" and that is usually far more than the actual number of colors in any given image. Paletted images achieve a relatively small size by keeping a numeric record of which colors are actually present in the image, and associating the RGB values with a "color index" for each pixel.
您可能熟悉RGB颜色表示法。 红色,绿色或蓝色的值范围从零(无输出)到255(最大输出)。 这些值给出了这三种颜色元素各自的屏幕亮度。 在整数中,RGB“光谱”中有1600万种可能的颜色,通常远远超过任何给定图像中的实际颜色数。 调色板图像通过保持数字记录实际在图像中实际存在的颜色以及将RGB值与每个像素的“颜色索引”相关联来实现相对较小的尺寸。
We know that we are working with a paletted two-color image because we created the PNG files that represent the characters in our alphabet. But we do not necessarily know what the palette positions or values are. So we make a diagonal pass across the image, starting in the upper left-hand corner and ending in the lower right-hand corner (lines 64-72). By sampling the pixels this way we know that the first pixel we find at position 0,0 will be the background color, and the only other color we detect will be the foreground color. For each pixel we sample, we assign the color index to $dot using the PHP function ImageColorAt(). Then we place the color index into the $colors array using the color index as both the array key and the array value. This causes identical color indexes to overwrite each other. At the end of this loop we have an array giving all of the unique color indexes in the image, which in our case is only two colors.
我们知道我们正在处理调色板的两色图像,因为我们创建了代表字母中字符的PNG文件。 但是我们不一定知道调色板的位置或值是什么。 因此,我们从图像的左上角开始到图像的右下角(第64-72行)对角线穿过图像。 通过以这种方式采样像素,我们知道在位置0,0处找到的第一个像素将是背景色,而我们检测到的唯一其他颜色将是前景色。 对于我们采样的每个像素,我们使用PHP函数ImageColorAt()将颜色索引分配给$ dot 。 然后,使用颜色索引作为数组键和数组值,将颜色索引放入$ colors数组中。 这将导致相同的颜色索引相互覆盖。 在此循环的最后,我们有一个数组,给出了图像中所有唯一的颜色索引,在我们的例子中,只有两个颜色。
In PHP, a good rule of thumb is that you always assign the background color first, and we do that using our randomly chosen colors (line 78). We also save this background color for later use when we twist the letters. Then we assign the foreground color and the process of semi-random image colorization is complete for this character.
在PHP中,一个好的经验法则是,您总是总是先分配背景色,然后使用随机选择的颜色(第78行)进行分配。 我们还保存了背景色,以备以后扭曲字母时使用。 然后,我们指定前景色,此字符的半随机图像着色过程完成。
Rotating and Distorting the Character Images
旋转和扭曲角色图像
Next we want to twist the character, so we choose a random amount of rotation and a random direction (lines 85-89). Then we apply the ImageRotate() function. This process creates a new image resource that will be bigger than the original image and we will have to deal with that later.
接下来,我们要扭曲角色,因此我们选择了随机的旋转量和随机的方向(第85-89行)。 然后,我们应用ImageRotate()函数。 此过程将创建一个新的图像资源,该资源将大于原始图像,我们将在以后进行处理。
At this point we can apply ImageFilter() effects to the twisted letter. You might experiment with these - it is more art than science. I found that the IMAGE_FILTER_EMBOSS produced an effect that looked good. I also left some of the other code in this script in the form of comments at lines 103-106. You might try activating these lines to see how the other image filters work.
此时,我们可以将ImageFilter()效果应用于扭曲的字母。 您可能会尝试这些-它是艺术而非科学。 我发现IMAGE_FILTER_EMBOSS产生了看起来不错的效果。 我还在第103-106行以注释的形式在脚本中留下了其他一些代码。 您可以尝试激活这些行以查看其他图像过滤器的工作方式。
Copying, Resizing and Recentering a Rotated Image
复制,调整大小和重新定位旋转的图像
Next we need to recenter the image in the 60x60 pixel size, but since we have used random rotations, we do not know what size the rotated image has assumed. However we do know that the part of the rotated image we want to keep is in the middle. So we can take the new larger dimensions and subtract the original smaller $size and divide by 2 (lines 109-110). This will give us both the X and Y offset into the rotated image. When we copy from this offset and keep $size pixels in each dimension we will get the part of the image we want to keep and we will discard the excess background area.
接下来,我们需要将图像重新调整为60x60像素大小,但是由于我们使用了随机旋转,因此我们不知道旋转图像所假定的大小。 但是,我们确实知道要保留的旋转图像部分位于中间。 因此,我们可以采用新的较大尺寸并减去原始的较小$ size并除以2(第109-110行)。 这将使我们在旋转图像中获得X和Y偏移。 当我们从该偏移量进行复制并在每个尺寸中保留$ size像素时,我们将获得要保留的图像部分,并将丢弃多余的背景区域。
We create a new image resource, reusing the character's position in the $images array (line 111), assign a background color (line 112) and copy the center of the twisted letter into the image resource (line 114-124).
我们创建一个新的图像资源,重新使用字符在$ images数组中的位置(第111行),分配背景色(第112行),然后将扭曲字母的中心复制到该图像资源中(第114-124行)。
This process is repeated for each of the letters or numbers in the CAPTCHA string. At the end of this loop we have an array of twisted and distorted images of the characters. We need to copy the characters into a single image for browser display.
对CAPTCHA字符串中的每个字母或数字重复此过程。 在循环的最后,我们得到了一系列扭曲和扭曲的字符图像。 我们需要将字符复制到单个图像中以供浏览器显示。
Bringing the Character Images Together for Browser Display
将字符图像集中在一起以供浏览器显示
Getting the final image output size is easy - it is the number of letters multiplied by the width (line 128). Because we are going to do some later processing with transparency, we use ImageSaveAlpha() to set the appropriate flags in the $out image resource (line 129). Then we copy each of the letters from the $images array into the $out image.
获取最终图像输出大小很容易-它是字母数乘以宽度(第128行)。 因为稍后将进行透明处理,所以我们使用ImageSaveAlpha()在$ out图像资源中设置适当的标志(第129行)。 然后,我们将每个字母从$ images数组复制到$ out图像中。
Working with Transparent Pixels
使用透明像素
The next part of the process is entirely optional - again a question more of art than science - and I left the code in this script to show how to handle some of the issues related to image transparency. It is not entirely intuitive.
该过程的下一部分是完全可选的-再次是艺术而不是科学的问题-我在脚本中保留了代码以显示如何处理与图像透明度有关的一些问题。 这不是完全直观的。
Our goal here is to speckle the image with transparency. This will allow a contrasting background color to show through the CAPTCHA image when it is rendered by the browser. To do that we must tell the image resource what color will be considered transparent. First, we shut off alpha blending (line 150) then choose the color we will make transparent and the degree of transparency (line 151). The transparency value of 127 is 100% transparent. The speckling process is done one pixel at a time (line 160) in a semi-random method by the code in lines 152-165. Finally we turn the alpha blending back on (line 166) and the pixels we filled with the value of $speck are made transparent. Our image is complete.
我们的目标是使图像具有透明度。 当浏览器呈现CAPTCHA图像时,这将允许通过对比色显示背景色。 为此,我们必须告诉图像资源什么颜色将被视为透明的。 首先,我们关闭Alpha混合(第150行),然后选择将使颜色透明的颜色和透明度(第151行)。 透明度值127是100%透明的。 用半随机方法通过行152-165中的代码一次完成一个像素的斑点处理(行160)。 最后,重新打开Alpha混合功能(第166行),并用$ speck值填充的像素变为透明。 我们的形象是完整的。
The last step is to write the image into the browser output stream (line 168, et seq).
最后一步是将图像写入浏览器输出流(第168行等)。
<?php // RAY_EE_captcha_sanity_image.php
error_reporting(E_ALL);
// GENERATES A PICTURE OF A CHARACTER STRING INTO THE BROWSER OUTPUT
// MAN PAGE http://php.net/manual/en/function.imagecreatefrompng.php
// MAN PAGE http://php.net/manual/en/function.imagecolorat.php
// MAN PAGE http://php.net/manual/en/function.imagecolorset.php
// MAN PAGE http://php.net/manual/en/function.imagerotate.php
// MAN PAGE http://php.net/manual/en/function.imagefilter.php
// MAN PAGE http://php.net/manual/en/function.imagesx.php
// MAN PAGE http://php.net/manual/en/function.imagecreatetruecolor.php
// MAN PAGE http://php.net/manual/en/function.imagecopy.php
// MAN PAGE http://php.net/manual/en/function.imagesavealpha.php
// MAN PAGE http://php.net/manual/en/function.imagealphablending.php
// MAN PAGE http://php.net/manual/en/function.imagecolorallocatealpha.php
// MAN PAGE http://php.net/manual/en/function.imagepng.php
// REQUIRED FOR CARRYING THE CAPTCHA STRING
session_start();
// SOURCE IMAGES MUST BE SQUARE, CENTERED AND THIS SIZE
$size = 60;
// PATH TO THE COLLECTION OF LETTER IMAGES
$path = 'RAY_EE_images/EE_captcha_sanity_';
// ACQUIRE THE CAPTCHA STRING
$letters = $_SESSION["captcha"];
if (!$letters) die('UNABLE TO LOCATE THE CAPTCHA STRING IN THE SESSION ARRAY');
// ARRAY POSITIONS FOR EACH LETTER IN THE CAPTCHA TEXT
$images = array();
$bgcolors = array();
// PROCESS EACH LETTER ONE AT A TIME
$letters = str_split($letters);
foreach ($letters as $ltr)
{
// CHOOSE COLORFUL LETTERS
$rgb = array
( array( 'r' => 255, 'g' => 0, 'b' => 0 ) // RED
, array( 'r' => 0, 'g' => 255, 'b' => 0 ) // GREEN
, array( 'r' => 0, 'g' => 0, 'b' => 255 ) // BLUE
)
;
// CHOOSE GRAY-SCALE LETTERS
$rgb = array
( array( 'r' => 0, 'g' => 0, 'b' => 0 ) // BLACK
, array( 'r' => 255, 'g' => 255, 'b' => 255 ) // WHITE
)
;
// MAKE A RANDOM SELECTION OF BACKGROUND AND FOREGROUND
shuffle($rgb);
$bgc = array_pop($rgb);
$fgc = array_pop($rgb);
// CREATE THE IMAGE RESOURCE FOR THIS LETTER
$images[$ltr] = imageCreateFromPNG($path . $ltr . '.png');
// GET THE PALETTE INDEXES FOR THE TWO COLOR IMAGE
$pixel = 0;
$colors = array();
while ($pixel < $size)
{
$dot = imageColorAt($images[$ltr], $pixel, $pixel);
$colors[$dot] = $dot;
$pixel++;
}
// POSITION ZERO IS BG, POSITION ONE IS THE LETTER
$colors = array_values($colors);
// ASSIGN THE BACKGROUND COLOR
imageColorSet($images[$ltr], $colors[0], $bgc['r'], $bgc['g'], $bgc['b']);
$bgcolors[$ltr] = $colors[0];
// ASSIGN THE FOREGROUND COLOR
imageColorSet($images[$ltr], $colors[1], $fgc['r'], $fgc['g'], $fgc['b']);
// CREATE RANDOM ROTATION VALUES (DEGREES ARE ANTI-CLOCKWISE)
$twist = rand(15,40);
if (rand(0,1))
{
$twist = 360 - $twist;
}
// ROTATE THE IMAGE - CREATES NEW IMAGE RESOURCES
$twisted[$ltr]
= imageRotate
( $images[$ltr] // STARTING IMAGE RESOURCE
, $twist // ROTATION ANGLE
, $bgcolors[$ltr] // BACKGROUND COLOR
)
;
// DAMAGE THE IMAGE A LITTLE BIT TO HAMPER THE OCR-BOTS
imageFilter($twisted[$ltr], IMG_FILTER_EMBOSS);
// FOR A WHITE BACKGROUND, USE GRAY-SCALE LETTERS AND ACTIVATE THESE LINES
// imageFilter($twisted[$ltr], IMG_FILTER_MEAN_REMOVAL);
// imageFilter($twisted[$ltr], IMG_FILTER_BRIGHTNESS, 128);
// imageFilter($twisted[$ltr], IMG_FILTER_CONTRAST, -128);
// GET THE NEW DIMENSIONS AFTER ROTATION AND RECENTER THE IMAGE
$imagesx = imagesX($twisted[$ltr]) - $size;
$imagesx = floor($imagesx / 2);
$images[$ltr] = imageCreateTrueColor($size, $size);
imageColorSet($images[$ltr], $colors[0], $bgc['r'], $bgc['g'], $bgc['b']);
imageCopy
( $images[$ltr] // DESTINATION IMAGE RESOURCE
, $twisted[$ltr] // SOURCE IMAGE RESOURCE
, 0 // DESTINATION X-COORDINATE
, 0 // DESTINATION Y-COORDINATE
, $imagesx // SOURCE X-COORDINATE
, $imagesx // SOURCE Y-COORDINATE
, $size // WIDTH OF SOURCE
, $size // HEIGHT OF SOURCE
)
;
}
// COMPUTE THE SIZE OF THE FINAL OUTPUT IMAGE
$out = imageCreateTrueColor( (count($letters) * $size), $size);
imageSaveAlpha($out, TRUE);
// COPY THE LETTERS INTO THE OUTPUT IMAGE
$x = 0;
foreach ($images as $ltr => $img)
{
imageCopy
( $out // DESTINATION IMAGE RESOURCE
, $img // SOURCE IMAGE RESOURCE
, $x // DESTINATION X-COORDINATE
, 0 // DESTINATION Y-COORDINATE
, 0 // SOURCE X-COORDINATE
, 0 // SOURCE Y-COORDINATE
, $size // WIDTH OF SOURCE
, $size // HEIGHT OF SOURCE
)
;
$x += $size;
}
// SPECKLE THE IMAGE WITH TRANSPARENCY
imageAlphaBlending($out, FALSE);
$speck = imageColorAllocateAlpha($out, 255, 255, 255, 127);
$x = imagesX($out)-1;
$y = imagesY($out)-1;
$w = rand(0,1);
$h = rand(0,1);
while ($w < $x)
{
while ($h < $y)
{
imageSetPixel($out, $w, $h, $speck);
$h += rand(2,4);
}
$w += 2;
$h = rand(0,1);
}
imageAlphaBlending($out, TRUE);
// SEND THE IMAGE INTO THE BROWSER OUTPUT STREAM
header('Content-type: image/png');
imagePNG($out);
imageDestroy($out);
How Does It Look?
看起来如何?
Here is what our new CAPTCHA images will look like, depending on whether we chose the color or the grayscale values in the $rgb array.
A Word About Accessibility这是我们新的CAPTCHA图像的外观,具体取决于我们在$ rgb数组中选择了颜色还是灰度值。
关于可访问性For clients of poor vision or those using screen readers, CAPTCHA tests can pose real problems. A way around this issue is to create an audio CAPTCHA. Each letter and number of the $alpha array can be made to correspond to an audio file telling the character in an unambiguous way. The audio CAPTCHA script could play each of the audio files. These files would use the radio alphabet to disambiguate similar-sounding letters and numbers. As an example, the audio version of our colorful CAPTCHA image might say this: Five, M as in Mike, D as in Delta, L as in Lima, Three.
对于视力不佳的客户或使用屏幕阅读器的客户,CAPTCHA测试会带来真正的问题。 解决此问题的一种方法是创建音频验证码。 $ alpha数组的每个字母和数字都可以对应一个音频文件,以明确的方式告诉字符。 音频CAPTCHA脚本可以播放每个音频文件。 这些文件将使用无线电字母来消除相似发音的字母和数字的歧义。 例如,我们彩色CAPTCHA图像的音频版本可能会这样说: 五,在Mike中是M,在三角洲中是D,在利马中是L,三 。
The FAA approved radio alphabet uses the following expressions.
FAA批准的无线电字母使用以下表达式。
$alphabet_array["A"] = "Alfa";
$alphabet_array["B"] = "Bravo";
$alphabet_array["C"] = "Charlie";
$alphabet_array["D"] = "Delta";
$alphabet_array["E"] = "Echo";
$alphabet_array["F"] = "Foxtrot";
$alphabet_array["G"] = "Golf";
$alphabet_array["H"] = "Hotel";
$alphabet_array["I"] = "India";
$alphabet_array["J"] = "Juliette";
$alphabet_array["K"] = "Kilo";
$alphabet_array["L"] = "Lima";
$alphabet_array["M"] = "Mike";
$alphabet_array["N"] = "November";
$alphabet_array["O"] = "Oskar";
$alphabet_array["P"] = "Papa";
$alphabet_array["Q"] = "Quebec";
$alphabet_array["R"] = "Romeo";
$alphabet_array["S"] = "Sierra";
$alphabet_array["T"] = "Tango";
$alphabet_array["U"] = "Uniform";
$alphabet_array["V"] = "Viktor";
$alphabet_array["W"] = "Whiskey";
$alphabet_array["X"] = "Xray";
$alphabet_array["Y"] = "Yankee";
$alphabet_array["Z"] = "Zulu";
$alphabet_array["0"] = "Zero";
$alphabet_array["1"] = "One";
$alphabet_array["2"] = "Two";
$alphabet_array["3"] = "Three";
$alphabet_array["4"] = "Four";
$alphabet_array["5"] = "Five";
$alphabet_array["6"] = "Six";
$alphabet_array["7"] = "Seven";
$alphabet_array["8"] = "Eight";
$alphabet_array["9"] = "Niner";
Summary
摘要
With a little bit of programming and 32 stored PNG files we have freed ourselves from dependency on a foreign web service and given our clients a secure form that is easier on the eyes. These scripts can be installed on your server and used as-is to duplicate what you see here. The attached PSD file contains one layer for each of the letters. You can open it in Photoshop or similar drawing programs, render each layer visible one at a time, and save the file as a PNG, named in such a way that each image file matches a character in our alphabet string. Be sure to coordinate the file path with the expected $path in the image generator script (line 27).
通过一些编程和32个存储的PNG文件,我们摆脱了对外部Web服务的依赖,并为我们的客户提供了一种更容易使用的安全格式。 这些脚本可以安装在服务器上,并按原样使用以复制此处看到的内容。 附件的PSD文件为每个字母包含一层。 您可以在Photoshop或类似的绘图程序中将其打开,一次使每一层都可见,然后将文件另存为PNG,其命名方式应使每个图像文件都与我们的字母字符串中的一个字符匹配。 确保在图像生成器脚本(第27行)中将文件路径与预期的$ path进行协调。
The PSD File with the Letters in Layers
带有分层字母的PSD文件
Just for Fun - the Worst Captcha Ever
只是为了好玩-有史以来最差的验证码
Addendum
附录
This article from Mollom reports that software able to decode reCaptcha is at hand (Late 2013). And this article from Yahoo reports that Google can decode its own reCatpcha (Spring 2014). And this New York Times article (late 2016) shows the advances in machine learning and artificial intelligence that are upon us today. These technological advances may make it better to create your own CAPTCHA tests which will have a smaller footprint than reCaptcha, and will be less likely to attract the unwanted attention of an army of hackers.
来自Mollom的这篇文章报道说,能够解码reCaptcha的软件即将到来(2013年末)。 雅虎的这篇文章报道说,谷歌可以解码自己的reCatpcha(2014年Spring)。 纽约时报 (2016年末)的这篇文章展示了当今我们在机器学习和人工智能方面的进步。 这些技术进步可能使您更好地创建自己的CAPTCHA测试,该测试的占地面积比reCaptcha小,并且不太可能引起黑客大军的不必要关注。
Please give us your feedback!
请给我们您的反馈意见!
If you found this article helpful, please click the "thumb's up" button below. Doing so lets the E-E community know what is valuable for E-E members and helps provide direction for future articles. If you have questions or comments, please add them. Thanks!
如果您发现本文有帮助,请单击下面的“竖起大拇指”按钮。 这样做可以使EE社区了解对EE成员有价值的内容,并为将来的文章提供指导。 如果您有任何问题或意见,请添加。 谢谢!
国内怎么captcha测试