My issue is I am not sure how to type the code to increment trainADistance by trainAMPM and decrease trainBDistance by trainBMPM in the do loop while having each text appended to the list. Each minute is supposed to be appended individually with text += "Minute " + i + " Train A Position: "+ parseFloat(trainADistance).toFixed(2) + " miles" + "Train B Position: " + parseFloat(trainBDistance).toFixed(2);. An example is listed below. Any help would be appreciated.
What the function is supposed to do?
The function I have been attempting to create is supposed to allow the user to input three variables trainAMPH, trainBMPH and distanceApart. When the inputs are submitted, the function function calculateTrains() is supposed to calculate trainAMPH, trainBMPH into miles per minute trainAMPM and trainBMPM. There is a do-while loop in place to increment the minutesi , increment trainADistance by trainAMPM and decrease trainBDistance by trainBMPM. trainBDistance is supposed to contain the same value as distanceApart. The loop continues while(trainADistance < trainBDistance) and is supposed to append text into a list until the loop is broken. An example is listed below.
This is an example of what is supposed to be appended to to the list with inputs 70 for train A, 60 for train B and 260 for distance
• Minute 1 Train A Position: 1.17 miles Train B Position: 259.00 miles
• Minute 2 Train A Position: 2.33 miles Train B Position: 258.00 miles
• Minute 3 Train A Position: 3.50 miles Train B Position: 257.00 miles
• Minute 4 Train A Position: 4.67 miles Train B Position: 256.00 miles
• Minute 5 Train A Position: 5.83 miles Train B Position: 255.00 miles
My Code
<script>
function calculateTrains(){
let trainAMPH= document.getElementById("trainAMPH").value;
let trainBMPH= document.getElementById("trainBMPH").value;
let distanceApart = trainBDistance = document.getElementById("distanceApart").value;
let list = document.getElementById("list");
//calculates MPH into MPM(miles per minute)
trainAMPM = (trainAMPH / 60);
trainBMPM = (trainBMPH / 60);
let trainADistance = 0;
let text = "";
let i = 0;
let li = "";
// do that increments the minutes and Train A/Train B's current position
d do{
text += "Minute " + i + " Train A Position: "+ parseFloat(trainADistance).toFixed(2) + " miles" + "Train B Position: " + parseFloat(trainBDistance).toFixed(2);
i++;
trainADistance += parseFloat(trainAMPM);
trainBDistance -= parseFloat(trainBMPM);
li = document.createElement("li");
}
// while loop tht continues while Train A distance is less than Train B distance
while(trainADistance < trainBDistance)
//adds "text" variable listed in do while loop to list
li.innerHTML = text;
list.appendChild(li);
// documents the amount of minutes to the "results" div
document.getElementById("results").innerHTML = "The two trains met after " + i + "minutes.";
}
</script>
<body>
<form id="myForm">
<label>Train A's Speed</label>
<input id="trainAMPH" type="number" value="" placeholder="MPH">
<label>Train B's Speed</label>
<input id="trainBMPH" type="number" value="" placeholder="MPH" >
<label>Distance between Eastford and Westford</label>
<input id="distanceApart" type="number" value=""placeholder="Miles">
<input type ="button" value="Submit Values" onclick="calculateTrains()">
<ul id = "list"></ul>
<div id="results"></div>
</form>
</body>
There were some issue with the code, I have made the necessary changes. Please go through the in-line comments that I have added in order to understand what were the mistakes and how they can be fixed.
The code is working now, please use the below snippet to run and see it's output. Do make sure to see my comments. Goodluck!
function calculateTrains() {
let trainAMPH = +document.getElementById("trainAMPH").value;
let trainBMPH = +document.getElementById("trainBMPH").value;
let distanceApart, trainBDistance;
//The input you retrieve using .value will be a string, convert it to Number using + to use toFixed
distanceApart = trainBDistance = +document.getElementById("distanceApart")
.value;
let list = document.getElementById("list");
//calculates MPH into MPM(miles per minute)
trainAMPM = trainAMPH / 60;
trainBMPM = trainBMPH / 60;
let trainADistance = 0;
let i = 1;
let text = "";
// do that increments the minutes and Train A/Train B's current position
do {
//don't use text+=, you don't want to append, you want each <li> to be on a separate line
text =
"Minute " +
i +
" Train A Position: " +
trainADistance.toFixed(2) +
" miles" +
"Train B Position: " +
trainBDistance.toFixed(2);
//create list item using template literals
let li = `<li>${text}</li>`;
//use insertAdjaventHTML( ) function to append the above created literal to list <ul>
list.insertAdjacentHTML("beforeend", li);
//increment i
i++;
//do the train A and train B distance calculations
//without these calculations, your while exit condition from below will never be met,
//making it an infinite while loop
trainADistance += trainAMPM;
trainBDistance -= trainBMPM;
} while (
// while loop tht continues while Train A distance is less than Train B distance
trainADistance < trainBDistance
);
//don't use innerHTML to append text, innerHTML is to append HTML string like '<div> hello <div>'
//instead use textContent or innerText properties
document.getElementById("results").textContent =
"The two trains met after " + i + "minutes.";
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<body>
<form id="myForm">
<label>Train A's Speed</label>
<input id="trainAMPH" type="number" value="" placeholder="MPH" />
<label>Train B's Speed</label>
<input id="trainBMPH" type="number" value="" placeholder="MPH" />
<label>Distance between Eastford and Westford</label>
<input id="distanceApart" type="number" value="" placeholder="Miles" />
<input
type="button"
value="Submit Values"
onclick="calculateTrains()"
/>
<ul id="list"></ul>
<div id="results"></div>
</form>
</body>
<script src="script.js"></script>
</body>
</html>
the reason why trainBDistance.toFixed(2) isn't recognized as a function is because when call document.getElementById("distanceApart").value the data type is string u need to parseInt or parseFloat that value first. You condition is while(trainADistance < trainBDistance) so you need to increment trainADistance as you said.
This might help.
function calculateTrains(){
let trainAMPH= document.getElementById("trainAMPH").value;
let trainBMPH= document.getElementById("trainBMPH").value;
let distanceApart = trainBDistance = parseInt( document.getElementById("distanceApart").value );
let list = document.getElementById("list");
list.innerHTML = ''; //empty the list
//calculates MPH into MPM(miles per minute)
trainAMPM = (trainAMPH / 60);
trainBMPM = (trainBMPH / 60);
let trainADistance = 0;
let i = 0;
// do that increments the minutes and Train A/Train B's current position
do{
let text = "Minute " + i + " Train A Position: "+ trainADistance.toFixed(2) + " miles" + " Train B Position: " + trainBDistance.toFixed(2);
//adds "text" variable listed in do while loop to list
let li = document.createElement("li");
li.innerHTML = text;
list.appendChild(li);
i++;
trainADistance += trainAMPM; //increment trainADistance by trainAMPM
trainBDistance -= trainBMPM; //decrease trainBDistance by trainBMPM
}while(trainADistance < trainBDistance)
// while loop tht continues while Train A distance is less than Train B distance
// documents the amount of minutes to the "results" div
document.getElementById("results").innerHTML = "The two trains met after " + i + "minutes.";
}
You may wanna change you script to as follows:
<script>
function calculateTrains(){
let trainAMPH= document.getElementById("trainAMPH").value;
let trainBMPH= document.getElementById("trainBMPH").value;
let distanceApart = trainBDistance = document.getElementById("distanceApart").value;
let list = document.getElementById("list");
trainAMPM = (trainAMPH / 60);
trainBMPM = (trainBMPH / 60);
let trainADistance = 0;
let text = "";
let i = 0;
do{
i++;
trainADistance+=trainAMPM
trainBDistance-=trainBMPM
let li = document.createElement('li')
li.textContent="Minute " + i + " Train A Position: "+ parseFloat(trainADistance).toFixed(2) + " miles" + "Train B Position: " + parseFloat(trainBDistance).toFixed(2)
document.getElementById('list').appendChild(li)
}while(trainADistance<=trainBDistance)
}
</script>
My script gets furniture prices & details from a Google spreadsheet and brings it into a Google docs add-on, this shows a sidebar where you select the range of furniture and spits out prices into the sidebar with an input field for the quantity once you hit generate invoice on the sidebar it then populates the Google doc table with the unit code, name, price, and quantity.
It's all working except for the first iteration of unitCode unitName unitPrice etc has undefined before it says the unitCode, unitPrice, unitName etc. Sorry about the mess of code it's very much a work in progress and hasn't been tidied or sample code really removed.
Also I feel like there's probably a much easier way to achieve what im trying to do, probably with just using G sheets itself so definitely open to suggestions.
Thanks in advance.
Photo of how undefined shows
Heres the HTML that sends to the GS file
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
<!-- The CSS package above applies Google styling to buttons and other elements. -->
<style>
.units {
margin-top:20px;
width:100%;
}
</style>
</head>
<body>
<div class="sidebar branding-below">
<label>Client Name</label>
<input type="text" name="client_name" id="client_name"><br>
<label>Client Phone</label>
<input type="text" name="client_phone" id="client_phone"><br>
<label>Client Email</label>
<input type="text" name="client_email" id="client_email"><br>
<!-- Multiple Radios -->
<div class="form-group">
<label class="col-md-4 control-label" for="furntype">Furniture Type</label>
<div class="col-md-4">
<div class="radio">
<label for="furntype-0">
<input type="radio" name="furntype" id="furntype-0" value="0" checked="checked">
6S
</label>
</div>
<div class="radio">
<label for="furntype-1">
<input type="radio" name="furntype" id="furntype-1" value="1">
6S Compact
</label>
</div>
</div>
</div>
<span id="theFurnType"></span>
<form>
</form>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
/**
* On document load, assign click handlers to each button and try to load the
* user's origin and destination language preferences if previously set.
*/
$(function() {
$('input:radio').click(function() {
var sheetDataz = google.script.run
.withFailureHandler(function(err){
console.error("error occured", err);
})
.withSuccessHandler(function(res){
var tab = '<div class="units"><div >';
var price = res[2];
var theUnitCode = res[0];
$.each(res[1], function(index, value){
var aPrice = price[index];
var thePrice = parseFloat(aPrice).toFixed(2);
var unitCode = theUnitCode[index];
tab += '<span>'+value+'</span><input type="text" class="unit" unitcode="'+unitCode+'" unitname="'+value+'" id="'+index+'" price="'+thePrice+'" value="0" style="float:right; width:40px;"><hr>';
});
tab += '<br><button type="button" id="doInvoice">Create Invoice</button></div>';
$('#theFurnType').html(tab);
$('#doInvoice').click(replaceIt);
}).getSheetData($(this).val());
});
function replaceIt() {
var client_name = $('#client_name').val();
var client_phone = $('#client_phone').val();
var client_email = $('#client_email').val();
var acr = client_name.match(/\b(\w)/g);
var invoice_num = acr.join('');
var date = GetTodayDate();
var invoice_num = invoice_num+'_'+date;
var theUnits = {};
$('.unit').each(function() {
theUnits.unitQuantity += $(this).val()+',';
theUnits.unitPrice += $(this).attr("price")+',';
theUnits.unitName += $(this).attr("unitname")+',';
theUnits.unitCode += $(this).attr("unitcode")+',';
});
google.script.run.doReplace(client_name,client_phone,client_email,invoice_num,date,theUnits);
}
});
function GetTodayDate() {
var tdate = new Date();
var dd = tdate.getDate(); //yields day
var MM = tdate.getMonth(); //yields month
var yyyy = tdate.getFullYear(); //yields year
var currentDate= dd + "-" +( MM+1) + "-" + yyyy;
return currentDate;
}
</script>
</body>
</html>
Heres the GS file
/**
* #NotOnlyCurrentDoc
*
* The above comment directs Apps Script to limit the scope of file
* access for this add-on. It specifies that this add-on will only
* attempt to read or modify the files in which the add-on is used,
* and not all of the user's files. The authorization request message
* presented to users will reflect this limited scope.
*/
/**
* Creates a menu entry in the Google Docs UI when the document is opened.
* This method is only used by the regular add-on, and is never called by
* the mobile add-on version.
*
* #param {object} e The event parameter for a simple onOpen trigger. To
* determine which authorization mode (ScriptApp.AuthMode) the trigger is
* running in, inspect e.authMode.
*/
function onOpen(e) {
DocumentApp.getUi().createAddonMenu()
.addItem('Start', 'showSidebar')
.addToUi();
}
/**
* Runs when the add-on is installed.
* This method is only used by the regular add-on, and is never called by
* the mobile add-on version.
*
* #param {object} e The event parameter for a simple onInstall trigger. To
* determine which authorization mode (ScriptApp.AuthMode) the trigger is
* running in, inspect e.authMode. (In practice, onInstall triggers always
* run in AuthMode.FULL, but onOpen triggers may be AuthMode.LIMITED or
* AuthMode.NONE.)
*/
function onInstall(e) {
onOpen(e);
}
/**
* Opens a sidebar in the document containing the add-on's user interface.
* This method is only used by the regular add-on, and is never called by
* the mobile add-on version.
*/
function showSidebar() {
var ui = HtmlService.createHtmlOutputFromFile('sidebar')
.setTitle('Infinity Invoice Generator');
DocumentApp.getUi().showSidebar(ui);
}
/**
* Gets the text the user has selected. If there is no selection,
* this function displays an error message.
*
* #return {Array.<string>} The selected text.
*/
function getSheetData(furnType) {
var ss = SpreadsheetApp.openById('1jLpJ35Szy6R3DDVVuOmi0Cw462ukI2DWzHG6VxYWd1g');
var sheets = ss.getSheets();
if(furnType == 0) {
var ranges = [sheets[0].getRange('A2:A11').getValues(), sheets[0].getRange('B2:B11').getValues(), sheets[0].getRange('H2:H11').getValues()];
}
if(furnType == 1) {
var ranges = [sheets[1].getRange('A2:A10').getValues(), sheets[1].getRange('B2:B10').getValues(), sheets[1].getRange('H2:H10').getValues()];
}
return ranges;
}
function doReplace(client_name,client_phone,client_email,invoice_num,date,theUnits) {
var body = DocumentApp.getActiveDocument().getBody();
var tables = body.getTables();
var table = tables[2];
var unitQuantity = theUnits.unitQuantity.split(',');
var unitCode = theUnits.unitCode.split(',');
var unitName = theUnits.unitName.split(',');
var unitPrice = theUnits.unitPrice.split(',');
var style1 = {};
style1[DocumentApp.Attribute.FONT_FAMILY] = 'Arial';
style1[DocumentApp.Attribute.FONT_SIZE] = 12;
style1[DocumentApp.Attribute.BOLD] = true;
style1[DocumentApp.Attribute.BACKGROUND_COLOR] = '#D9D9D9';
style1[DocumentApp.Attribute.FOREGROUND_COLOR] = '#000000';
var style2 = {};
style2[DocumentApp.Attribute.FONT_FAMILY] = 'Arial';
style2[DocumentApp.Attribute.FONT_SIZE] = 12;
style2[DocumentApp.Attribute.BOLD] = false;
style2[DocumentApp.Attribute.BACKGROUND_COLOR] = '#F3F3F3';
style2[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = 'CENTER';
style2[DocumentApp.Attribute.FOREGROUND_COLOR] = '#000000';
var i;
for (i = 0; i < unitQuantity.length; i++) {
var tr = table.appendTableRow();
var td = tr.appendTableCell(''+unitCode[i]+'').setAttributes(style1);
var td = tr.appendTableCell(''+unitName[i]+'').setAttributes(style2);
var td = tr.appendTableCell(''+unitPrice[i]+'').setAttributes(style2);
var td = tr.appendTableCell(''+unitQuantity[i]+'').setAttributes(style2);
}
body.replaceText("{{ClientName}}", client_name);
body.replaceText("{{ClientPhone}}", client_phone);
body.replaceText("{{ClientEmail}}", client_email);
body.replaceText("{{InvoiceNumber}}", invoice_num);
body.replaceText("{{CurrentDate}}", date);
}
Proble is with replaceIt function, specifically the way you are building theUnits object. Initialize each property within object with empty string and that will fix the issue:
function replaceIt() {
var client_name = $('#client_name').val();
var client_phone = $('#client_phone').val();
var client_email = $('#client_email').val();
var acr = client_name.match(/\b(\w)/g);
var invoice_num = acr.join('');
var date = GetTodayDate();
var invoice_num = invoice_num + '_' + date;
var theUnits = {
unitQuantity: "",
unitPrice: "",
unitName: "",
unitCode: ""
};
$('.unit').each(function() {
theUnits.unitQuantity += $(this).val() + ',';
theUnits.unitPrice += $(this).attr("price") + ',';
theUnits.unitName += $(this).attr("unitname") + ',';
theUnits.unitCode += $(this).attr("unitcode") + ',';
});
google.script.run.doReplace(client_name, client_phone, client_email, invoice_num, date, theUnits);
}
How to create simple javascript/jquery client side captcha?
Why don't you use reCAPTCHA ? It's free, very efficient, and provides accessibility functionnalities.
It can be done with HTML and a simple JavaScript code. Have a look at this:
function Captcha(){
var alpha = new Array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'0','1','2','3','4','5','6','7','8','9');
var i;
for (i=0;i<6;i++){
var a = alpha[Math.floor(Math.random() * alpha.length)];
var b = alpha[Math.floor(Math.random() * alpha.length)];
var c = alpha[Math.floor(Math.random() * alpha.length)];
var d = alpha[Math.floor(Math.random() * alpha.length)];
var e = alpha[Math.floor(Math.random() * alpha.length)];
var f = alpha[Math.floor(Math.random() * alpha.length)];
var g = alpha[Math.floor(Math.random() * alpha.length)];
}
var code = a + ' ' + b + ' ' + ' ' + c + ' ' + d + ' ' + e + ' '+ f + ' ' + g;
document.getElementById("mainCaptcha").innerHTML = code
document.getElementById("mainCaptcha").value = code
}
function ValidCaptcha(){
var string1 = removeSpaces(document.getElementById('mainCaptcha').value);
var string2 = removeSpaces(document.getElementById('txtInput').value);
if (string1 == string2){
return true;
}else{
return false;
}
}
function removeSpaces(string){
return string.split(' ').join('');
}
.capt{
background-color:grey;
width: 300px;
height:100px;
}
#mainCaptcha{
position: relative;
left : 60px;
top: 5px;
}
#refresh{
position:relative;
left:230px;
width:30px;
height:30px;
bottom:45px;
background-image: url(rpt.jpg);
}
#txtInput, #Button1{
position: relative;
left:40px;
bottom: 40px;
}
<link rel="stylesheet" type="text/css" href="estilo.css" />
<script type="text/javascript" src="script.js"></script>
<body onload="Captcha();">
<div class="capt">
<h2 type="text" id="mainCaptcha"></h2>
<p><input type="button" id="refresh" onclick="Captcha();"/></p> <input type="text" id="txtInput"/>
<input id="Button1" type="button" value="Check" onclick="alert(ValidCaptcha());"/>
</div>
</body>
here you are ;)
var captchaText;
$(function() {
var pre = $('#captcha');
captchaText = pre.text();
pre.text('');
var lines = ['', '', '', '', '']
for (var ixLetter = 0; ixLetter < captchaText.length; ixLetter++) {
var letter = captchaText.substr(ixLetter, 1);
var letterLines = letters[letter];
for (var ix = 0; ix < 5; ix++) {
lines[ix] = lines[ix] + ' ' + letterLines[ix];
}
}
for (var ix = 0; ix < 5; ix++) {
pre.append(lines[ix] + '\n');
}
});
function check() {
if ($('#captchaCheck').val() == captchaText) {
alert('you are probably human');
} else {
alert('you probably made a mistake. Don\'t worry. To err is also human.');
}
}
var letters = {
h: [
'HH HH',
'HH HH',
'HHHHHH',
'HH HH',
'HH HH'
],
i: [
'II',
'II',
'II',
'II',
'II'
]
// etc
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<pre id="captcha">hi</pre> Please type what you see: <input id="captchaCheck" /> <input type="button" value="Check" onclick="check()" />
I agree with all the comments that client side captcha is fundamentally flawed, and I don't know know tough the hurdles have to be to mitigate any amount of spam...
To get an impression of what you're up against, though, check xRumer and GSA in action: YouTube: xEvil vs GSA Captcha Breaker
The software is also able to gather and decipher artificial intelligence such as security questions (i.e. what is 2+2?) often used by forums upon registration. Since the latest version of XRumer, the software is capable of collecting such security questions from multiple sources and is much more effective in defeating them.
wikipedia.org/wiki/XRumer
References:
How do spambots work? - Webmasters Stack Exchange (2010!)
BotDetect: Pure JavaScript CAPTCHA Validation Problems
So, caveats aside, here's a trivial alternative using HTML5 validation that's probably as ineffective as the other posts here! Presumably spambots would just add formnovalidate before submission, and would identify a honeypot field.
<form class="input">
<label for="number" class="title">
What is three plus four?
</label>
<br>
<input
name="number"
required="required"
pattern="(7|seven)"
oninvalid="this.setCustomValidity('Sorry, please enter the correct answer')"
oninput="this.setCustomValidity('')"
>
<!-- Bonus honeypot field, hidden from the user. The server should discard this response if it contains any input -->
<input name="decoy" style="display: none;" />
<input type="submit">
</form>
Client-Side captchas do not provide the protection a server-generated captcha would because the server can not check if the solved captcha is solved correctly.
That is not possible.
You could create something that looks like a CAPTCHA, but it would only run when it's not needed, i.e. when the page is shown in a browser. When it's needed it won't run, as the program trying to break in won't run the client side script.
function Captcha(){
var alpha = new Array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'0','1','2','3','4','5','6','7','8','9');
var i;
for (i=0;i<6;i++){
var a = alpha[Math.floor(Math.random() * alpha.length)];
var b = alpha[Math.floor(Math.random() * alpha.length)];
var c = alpha[Math.floor(Math.random() * alpha.length)];
var d = alpha[Math.floor(Math.random() * alpha.length)];
var e = alpha[Math.floor(Math.random() * alpha.length)];
var f = alpha[Math.floor(Math.random() * alpha.length)];
var g = alpha[Math.floor(Math.random() * alpha.length)];
}
var code = a + ' ' + b + ' ' + ' ' + c + ' ' + d + ' ' + e + ' '+ f + ' ' + g;
document.getElementById("mainCaptcha").innerHTML = code
document.getElementById("mainCaptcha").value = code
}
function ValidCaptcha(){
var string1 = removeSpaces(document.getElementById('mainCaptcha').value);
var string2 = removeSpaces(document.getElementById('txtInput').value);
if (string1 == string2){
return true;
}else{
return false;
}
}
function removeSpaces(string){
return string.split(' ').join('');
}
<h1 This works pretty well. </h1>
if your purpose is to simply deflect most bots, you might be able to get away with a simple script that chooses 2 numbers at random and asks user to add them.
Try this:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script>
/* created dynamically by server when preparing the page */
// f function is on server and not known by bot and is random per result
// maybe bcrypt with a unique salt per request
var encodedResult = "f('X')";
var serverRenderedPositionSequence = [
[0,0],
[10,10],
[20,20],
[30,30],
[40,40],
[50,50],
[60,60],
[70,70],
[80,80],
[90,90],
[100,100],
[100,100],
[100,100],
[100,100],
[100,100],
[100,0],
[90,10],
[80,20],
[70,30],
[60,40],
[50,50],
[40,60],
[30,70],
[20,80],
[10,90],
[0,100]
];
window.index = 0;
window.move=function(but){
but.style.left = (serverRenderedPositionSequence[window.index][0]+"px");
but.style.top = (serverRenderedPositionSequence[window.index][1]+"px");
window.index++;
if(window.index<serverRenderedPositionSequence.length)
{
setTimeout(function(){
window.move(but);
},125);
}
}
window.onload=function(){
var but = document.getElementById("decoy-button");
window.index=0;
window.move(but);
};
function post()
{
// do something with
var xhrData= {
encodedResult:encodedResult,
result:document.getElementById('result').value
};
var postXhr=function(){ /* HTTP POST */}
// server checks if decoded "encoded result" is equal to the result (X here)
postXhr(xhrData);
}
</script>
</head>
<body>
<input id="result" type="text" value="Enter the message you see" />
<input id="test" onclick="post()" type="button" value="Post" />
<input id="decoy-button" type="button" value=" click me bot" style="width:0px;padding:0;position:absolute; left:0px; top:0px;" />
<input id="secret" type="button" onclick="window.index=0;move( document.getElementById('decoy-button'))" value="repeat sequence" />
</body>
</html>
Then the server would only use bcrypt to check if result is true.
Since the pattern matching requires dynamically observing the screen, it would cause some bots to fail. These would fail:
bots that click to post button immediately
bots that don't run javascript
bots that mis-click the decoy buttons
bots that can't understand the leap between coordinates in the sequence
for example when drawing X, it leaps from bot-right to top-right effectively drawing a vertical line on imaginary plane which may trick some bots easily
bots that use OCR with "fixed" screenshot timings
To further obfuscate any "canvas" hack, the server could add quick random bursts (with decreased latency between leaps) into the sequence such that resulting image would look unrecognizable but human will see what it writes between those random bursts.
To add one more depth, you can ask a math problem like
1+1
instead of just string.
But, when a bot memoizes the encoded result and re-sends it, the security is broken. So, have a "session" for client and not send any encoded result. Just the randomized sequence and check for result only by server-side. Of course the session also costs database time/space but at least website admin/editor does not see spam on the control panel of website.
please try this
<script type="text/javascript">
$('#submitcapt').click(function(){
var captval = "This will not do nothing";
$.ajax({
type : "POST",
url : "externals/reCaptcha/ajaxaction.php",
data : {loadval:captval},
success : function( msg ) {
if(msg=="1"){
}else{
}
}
})
});
</script>
In ajaxaction.php please put the following code
<?php
session_start();
$val=$_POST['loadval'];
$message= $_SESSION['random_number'];
if($val==$message) {
echo "1";
}else{
echo "2";
}
?>
$(document).ready(function() {
DrawCaptcha();
});
function refreshCap() {
DrawCaptcha();
}
function DrawCaptcha() {
var a = Math.ceil(Math.random() * 10) + '';
var b = Math.ceil(Math.random() * 10) + '';
var c = Math.ceil(Math.random() * 10) + '';
var d = Math.ceil(Math.random() * 10) + '';
var e = Math.ceil(Math.random() * 10) + '';
var f = Math.ceil(Math.random() * 10) + '';
var g = Math.ceil(Math.random() * 10) + '';
var code = a + ' ' + b + ' ' + ' ' + c + ' ' + d + ' ' + e + ' ' + f + ' ' + g;
var test = document.getElementById("ContentPlaceHolder1_txtCapcha").value = code;
alert(test);
}
function ValidCaptcha() {
var str1 = removeSpaces(document.getElementById('ContentPlaceHolder1_txtCapcha').value);
var str2 = removeSpaces(document.getElementById('ContentPlaceHolder1_txtinputCapcha').value);
if (str1 != str2) {
alert("Properly enter the Security code.");
document.getElementById('ContentPlaceHolder1_txtinputCapcha').focus() return false;
}
}
function removeSpaces(string) {
return string.split(' ').join('');
}