I have built a contact form using CakePHP following the tutorial at http://snook.ca/archives/cakephp/contact_form_cakephp
But would like to add a spam protector where the user is presented with a 5 letter character word such as BB42A that is random and the user has to type in before they can submit the form.
I have done some Googling but haven't found anything suitable online.
Any suggestions? Thanks
The one at the bottom of here is quite good: http://mattbrett.com/portfolio/hire/
I would suggest using an existing CAPTCHA library or service rather than rolling your own. No sense re-inventing the wheel.
One of the best is reCAPTCHA. Here's a good tutorial on implementing reCAPTCHA in Cake.
you can use actice/passive captchas with simple math questions like 2+3
http://www.dereuromark.de/2010/08/09/how-to-implement-captchas-properly/
how secure it needs to be is your decision. for most sites this is more than enough.
Actually - one of easiest ways I found to beat spambots was to have a hidden field in every contact form; and usually spambots would fill it whereas humans, as they can't see it, wouldn't be able to.
Try adding to your view:
//call it something along the lines of 'name' or 'email', and the
//real form field 'x1' or 'x2' etc
$this-Form->input('aformfield', array('class' => 'aformfield');
Make sure you hide it in your css:
.aformfield{display:none;}
In the controller before you send the email, check to see if the hidden field is filled:
if(!empty($this->data['Model']['aformfield'])){
$this->Session->setFlash('You shouldn\'t be able to fill out a hidden field');
$this->redirect($this->referrer());
}
It's not bullet proof and I'm sure spambots will ifnd a way around it but it's a good place to start if you don't want to do captcha's.
What you need is called captcha.
Google search for cakePHP + captcha should come up with some cakePHP plugins. I don't develop in cakePHP, so I can't tell more.
You can, of course, make your own captcha and then integrate it in your website.
To keep it short:
Generate a random string;
create an image with this string
(imagecreate function on php.net);
save the string as session
variable;
compare what user submitted with what's saved in session.
Code:
<?php
session_start();
function rand_str($length = 6,
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890')
{
$chars_length = (strlen($chars) - 1);
$string = $chars{rand(0, $chars_length)};
// Generate random string
for ($i = 1; $i < $length; $i = strlen($string))
{
// Grab a random character from list
$r = $chars{rand(0, $chars_length)};
// Make sure the same two characters don't appear next to each other
if ($r != $string{$i - 1}) $string .= $r;
}
return $string;
}
header("Content-Type: image/png");
$im = #imagecreate(100, 40) or die("Cannot Initialize new GD image stream");
$background_color = imagecolorallocate($im, 0, 0, 0); // black
$text_color = imagecolorallocate($im, 255, 255,255); // white
$random_string = rand_str();
$_SESSION['captcha'] = $random_string;
imagestring($im, 5, 5, 5, $random_string, $text_color);
imagepng($im);
imagedestroy($im);
?>
Related
I am currently utilising FPDF for the first time and everything works great so far in Chrome, Firefox, Safari, Mobile Chrome, Mobile Safari but both Internet Explorer and Microsoft Edge give me issues.
I have a page where a user can fill in a form with their own company name and adress information.
They are also required to upload their company logo.
I use FPDF combined with FPDI for the use of templates/PDFs
Our designers made the PDF in InDesign and that is all good.
I start by declaring a new FPDI and importing in the base PDF (it has 8 pages) as the first source and template.
The first 5 pages in the PDF are as followed
Cover 1
Cover 2
Cover 3
Cover 4
Cover 5
In my HTML form I have a select input where the user can choose between the five.
Which I then pick up in PHP and load the correct page as follow:
$pdf = new FPDI();
$pagecount = $pdf->setSourceFile('../pdf/source-brochure.pdf');
// Add the Cover
$tplCover = $pdf->importPage($cover_versie, '/MediaBox');
$pdf->addPage();
$pdf->useTemplate($tplCover, 0, 0, 210);
$pdf->Image($newFile, $baseOffsetX, $baseOffsetY);
$cover_versie; // Outputs the integer 1, 2, 3, 4 or 5 for the covers
$newFile; // Is the uploaded logo resised and uploaded to the server
The logo is resized and edited through a php script
Now the 5th option is a custom cover where the user can upload their own cover image to the form (this input field is shown when Cover 5 is chosen)
So in my Switch Statement where I check which cover the user has chosen I have this following code:
if ($custimg->uploaded) {
$custimg->image_resize = true;
$custimg->image_x = 741;
$custimg->image_y = 792;
$custimg->image_ratio = true;
$custimg->image_ratio_fill = true;
$custimg->image_ratio_crop = 'TL';
$custimg->image_ratio_no_zoom_in = false;
$custimg->image_ratio_no_zoom_out = false;
$custimg->image_convert = 'png';
$custimg->process('uploads/');
if ($custimg->processed) {
$customcoverimage = $custimg->file_dst_pathname;
$custimg->clean();
}
}
The rest of the form is not required and fall back using ternary operators like so:
$filename = (!empty($companyname)) ? $companyname : time();
So after the cover is chosen and done I add the 6th page from the source PDF which is a Spread page and requires no edits so I import that as the new page:
// Add the content of the brochure
$tplContent = $pdf->importPage(6, '/MediaBox');
$pdf->addPage('L', 'A4');
$pdf->useTemplate($tplContent, 0, 0, 297);
Alright nothing too hard here.
Next up is the last page.
For this I also have a input select option in my form.
There are 2 flavors to choose from.
// Add the Back
$tplBack = $pdf->importPage($achter_versie, '/MediaBox');
$pdf->addPage();
$pdf->useTemplate($tplBack, 0, 0, 210);
$achter_versie; // Outputs the integer 7 or 8 based on the chosen back
Now here we get a little tricky.
On the last page there is a spot where I need to loop through 5 checkboxes in the form to see which sponsors the company uses and output their respective logo's next to eachother:
So I first count the amount of checkboxes are checked.
I get the values of the checkboxes in a loop and through a for loop I add the logo's (which are uploaded to a default folder) to the page:
// Get the checkbox values
if ($nrofkeurmerken != 1) {
for ($x1 = 0; $x1 <= $nrofkeurmerken-1; $x1++) {
$brandBaseX = 10;
$baseImgWidth = 29.897916667;
if ($keurmerken[$x1] != 'eigen') {
$keurmerkname[] = "../img/keurmerken/logo-" . $keurmerken[$x1] . ".png";
$pdf->Image($keurmerkname[$x1], $brandBaseX + ($baseImgWidth * $x1) + 5, 270);
} else {
$keurimg = new upload($_FILES['keurmerkfile']);
if ($keurimg->uploaded) {
$keurimg->image_resize = true;
$keurimg->image_x = 113;
$keurimg->image_y = 71;
$keurimg->image_ratio = true;
$keurimg->image_ratio_no_zoom_in = true;
$keurimg->image_ratio_no_zoom_out = false;
$keurimg->image_convert = 'png';
$keurimg->process('uploads/');
if ($keurimg->processed) {
$customkeurmerkimage = $keurimg->file_dst_pathname;
$pdf->Image($customkeurmerkimage, $brandBaseX + ($baseImgWidth * $x1) + 5, 270);
$keurimg->clean();
}
}
}
}
} else if ($nrofkeurmerken == 1) {
$brandBaseX = 10;
$baseImgWidth = 29.897916667;
$keurmerkname = "../img/keurmerken/logo-snf.png";
$pdf->Image($keurmerkname, $brandBaseX + ($baseImgWidth * 0) + 5, 270);
}
Now In All modern browsers (except IE11 and MS Edge) this works.
But both IE11 and Edge have the error that the PDF does not start with %PDF
At first my error was incorrect type of file but I added the
header('Content-type: application/pdf');
which solved that problem.
If anyone understands this that would be awesome haha.
Thanks for the time to look though!
I have a basic math question that the user has to answer before they can send an email:
$first_num = rand(1, 4);
$second_num = rand(1, 4);
$send = #$_POST['send'];
if($send){
//The user's answer from the input box
$answer = #$_POST["answer"];
if($answer == $first_num + $second_num) {
//Do stuff
}
else {
$error_message = "You answered the question wrong!";
}
}
I answer the question correctly (unless my first grade math is off!) yet it says I have the question wrong. I am not sure what the issue is but I imagine it is something to do with the fact that php executes immediately when the page is loaded and so new numbers are generated as soon as the user presses the submit button? Or am I way off? If that is the case, what can be done to solve this?
The problem is that you are setting your values every time your script is called. So when you post your form, two new values are set and they are likely not the same values as when you called the script the first time to show the form.
You should store your variables in a session and retrieve these values when you process your post request.
Something like:
session_start();
if (!isset($_SESSION['numbers']))
{
$_SESSION['numbers']['first'] = rand(1, 4);
$_SESSION['numbers']['second'] = rand(1, 4);
}
...
if ($answer == $_SESSION['numbers']['first'] + $_SESSION['numbers']['second']) {
//Do stuff
/**
unset the variables after successfully processing the form so that
you will get new ones next time you open the form
*/
unset($_SESSION['numbers']);
...
Note that you will need to use the session variables everywhere where you are using your own variables right now.
You should include the two numbers as hidden form inputs in your HTML, and then do the math with the entries in your $_POST array.
Make your code start like this instead:
$first_num = $_POST["first_num"];
$second_num = $_POST["second_num"];
Okay im using a snippet I found on google to take a users uploaded image and put it in my directory under Content
But Im worried about duplicates so I was going have it upload the image as a Random number
well here is my code you can probably understand what im going for through it anyways
<label for="file">Profile Pic:</label> <input type="file" name="ProfilePic" id="ProfilePic" /><br />
<input type="submit" name="submit" value="Submit" />
$ProfilePicName = $_FILES["ProfilePic"]["name"];
$ProfilePicType = $_FILES["ProfilePic"]["type"];
$ProfilePicSize = $_FILES["ProfilePic"]["size"];
$ProfilePicTemp = $_FILES["ProfilePic"]["tmp_name"];
$ProfilePicError = $_FILES["ProfilePic"]["error"];
$RandomAccountNumber = mt_rand(1, 99999);
echo $RandomAccountNumber;
move_uploaded_file($ProfilePicTemp, "Content/".$RandomAccountNumber.$ProfilePicType);
And then basicly after all this Im going try to get it to put that random number in my database
Someone gave me a new snippet that looks like it will do what I want but now the file isnt making it all the way to my directory
$RandomAccountNumber = uniqid();
echo $RandomAccountNumber;
move_uploaded_file($ProfilePicName,"Content/".$RandomAccountNumber);
try using the php uniqid method to generate the unique id you need
http://php.net/manual/en/function.uniqid.php
$RandomAccountNumber = uniqid();
move_uploaded_file($ProfilePicTemp, "Content/" . $RandomAccountNumber);
When I upload images, I usually save it as the sha1() of the image's contents (sha1_file()). That way, you get two birds with one stone: You'll never (if you do, go fill out the closest lottery) get duplicate file names, AND, you'll prevent duplicate images (because duplicate images would have the same checksum).
Then, you have a database to sort out which image is which, and correctly display them to the user.
This is what I use when uploading pictures: a combination of session_id(), time() and a random string:
$rand = genRandomString();
$final_filename = $rand."_".session_id()."_".time();
function genRandomString()
{
$length = 5;
$characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWZYZ";
$real_string_length = strlen($characters) ;
$string="id";
for ($p = 0; $p < $length; $p++)
{
$string .= $characters[mt_rand(0, $real_string_length-1)];
}
return strtolower($string);
}
I hope this help.
random != unique
No matter what method you use to generate a 'random' file name you're probably going to want to do this to avoid collisions.
$path = '/path/to/directory/';
do {
$filename = some_function();
} while( file_exists($path.$filename) );
It's not super-necessary, but if you're just looking for peace of mind in case of a one-in-a-million filename collision then those couple extra lines will do the trick.
One of my favorite Coding Horror articles addresses why this approach is dumber than it looks, and you should use something like uniqid instead of mt_rand(1, 99999);...
I searched Google and Stackoverflow but could not find the answer. Probably it is because I am searching for the wrong question. Without the right question, it’s hard to get the right answers. So I hope someone can help me.
I have created a top 20 list where people can rank their favourite website (I know it is not that original, but I do it to learn php)
Websites can be added to a database and are sorted based on votes. Each website has its own unique ID in the database, name and position.
What I cannot figure out is how to do the following.
Next to the list displayed show a get code button. This button will create a code for an image file that can be display on any website. For example:
<img src="http://www.example.com/counter.php?id=47"/>
or even better
<img src="http://www.example.com/47.gif"/>
To do this I need to make a php code, that can take the id and turn it into a nice image file and there I am stuck. I have seen twitter, feedburner, Technorati and over 100 other websites do this, but I cannot find out how.
I found this code that fakes feedburner, but I cannot figure out how to turn it into what I need.
<?php
//Send a generated image to the browser
create_image();
exit();
function create_image(){
//Create the image resource
$image = imagecreatefromgif('image.gif');
//Create text color
$brown = ImageColorAllocate($image, 0, 0, 0);
//Check for the get parameters
if (isset($_GET['count']) && is_numeric($_GET['count']))
$rank = $_GET['count'];
else
$rank = 20;
// Some Alignment Calculations
$bbox = imagettfbbox(8.5, 1,'verdana.ttf', $rank);
$xcorr = 0 + $bbox[2]; $xcorr = 31 - $xcorr;
//Add the number in brown color to the image
imagettftext($image,8.5,0,$xcorr,16,$brown,'verdana.ttf',$rank);
//Tell the browser what kind of file is come in
header("Content-Type: image/gif");
imagegif($image);
//Free up resources
ImageDestroy($image);}?>
Based on
www.mygeekpal.com/how-to-fake-your-feedburner-subscribers/
Using the above code and naming it counter.php I can fetch the position from the database and create
<img src='http://www.example.com/counter.php?count=".$array ['position']."' />
This takes the positon of a website from the database ($array has already been made to fetch) and creates an image with the position nr.
Works fine, but once the postion changes based on user ratings, the image will not show the correct data.
I hope someone can help. Thank you.
Summery
Basically what I am try to make is something that will show the most recent data, based on the ranking of the website. Just like showing the number of twitter followers, for example http://twittercounter.com/counter/?username=labnol or feedburner followers on http://feeds.feedburner.com/~fc/labnol
Both are images that show a number based on information in a database. But I want to create my own image, based on the rank of the website in the database.
Looking at your code it should update everytime the page is reloaded. Clear your browser cache.
If this fails i would check from where it is getting the Get['count'] data which im assuming is the Rank number of the site.
Can you check that the Get['Count'] data is updating as it should ?
Im not sure using an ARRAY in the URL is a good idea, why not use Sessions ?
This link might be of interest.
Sorry i have not been of more help.
This is what I have so far (I cannot edit this question from this computer, due to different cookies).
This is based on the help from
How to fetch data from database and display it in PHP?
thanks to
https://stackoverflow.com/users/353790/robertpitt
This seems to work
<?php
//Connect to DB
$db = mysql_connect("localhst","user","pass") or die("Database Error");
mysql_select_db("db_name",$db);
//Get ID from request
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
//Check id is valid
if($id > 0)
{
//Query the DB
$resource = mysql_query("SELECT * FROM domains WHERE id = " . $id);
if($resource === false)
{
die("Database Error");
}
if(mysql_num_rows($resource) == 0)
{
die("No User Exists");
}
$user = mysql_fetch_assoc($resource);
}
$img_number = imagecreate(110,24);
$image = imagecreatefromgif('image.gif');
$backcolor = imagecolorallocate($img_number,254,46,212);
$textcolor = imagecolorallocate($image, 0, 0, 0);
imagefill($image,0,0,$backcolor);
$number = $user['position'];
Imagestring($image,9,26,4,$number,$textcolor);
header("Content-Type: image/gif");
imagegif($image);
ImageDestroy($image);
?>
I'm using the following code to create a captcha on my site, but when I try to read the value back from the session, it is always the previous captcha value.
<?php
session_start();
$captchaStr = md5(microtime() * mktime());
$captchaStr = substr($captchaStr,0,5);
$_SESSION["captcha"] = $captchaStr;
$captcha = imagecreatefrompng("../images/captcha.png");
$black = imagecolorallocate($captcha, 154, 32, 242);
$line = imagecolorallocate($captcha, 233, 239, 239);
// Draw lines
imageline($captcha, 0, 0, 39, 29, $line);
imageline($captcha, 40, 0, 64, 29, $line);
// Add captcha text
imagestring($captcha, 5, 20, 10, $_SESSION["captcha"], $black);
header("Content-type: image/png");
imagepng($captcha);
?>
Does anyone have any ideas why this is and how to fix it?
Cheers
I'm guessing you're trying to read back the captcha value from the page that contains the captcha value, something like this:
<?php session_start(); ?>
<img src="/lib/captcha.php" />
<?php echo "Captcha is: ", $_SESSION['captcha'] ?>
This would never work. PHP locks the session file by default, so your captcha script can not run until the above container page completes execution. As well, since the captcha is being fetched as a seperate call, the user's browser has to initiate a call back to the server to fetch the image. This will take on the order of seconds to complete, while the container page will be done within microseconds.
In other words, the captcha generator script will very likely NEVER start running until after the container script has completed, which means the container script will never see the new captcha string in the session file.