Simple captcha php script not displaying text on image - php

I was hoping to get in touch with someone on a situation that I cannot find the solution to anywhere.
I am trying to create a captcha on my website using php and although I was able to create an image and create the random captcha text.
I am unable to over lay the two. Here is my code:
<?PHP
session_start();
function generateRandomString($length = 10) {
$letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
$len = strlen($letters);
$letter = $letters[rand(0, $len - 1)];
$text_color = imagecolorallocate($image, 0, 0, 0);
$word = "";
for ($i = 0; $i < 6; $i++) {
$letter = $letters[rand(0, $len - 1)];
imagestring($image, 7, 5 + ($i * 30), 20, $letter, $text_color);
$word .= $letter;
}
$_SESSION['captcha_string'] = $word;
}
function security_image(){
// $code = isset($_SESSION['captcha']) ? $_SESSION['captcha'] : generate_code();
//$font = 'content/fonts/comic.ttf';
$width = '110';
$height = '20';
$font_size = $height * 0.75;
// $image = #imagecreate($width, $height) or die('GD not installed');
global $image;
$image = imagecreatetruecolor($width, $height) or die("Cannot Initialize new GD image stream");
$background_color = imagecolorallocate($image, 255, 255, 255);
imagefilledrectangle($image,0,0,200,50,$background_color);
$line_color = imagecolorallocate($image, 64,64,64);
for($i=0;$i<10;$i++) {
imageline($image,0,rand()%50,200,rand()%50,$line_color);
}
$pixel_color = imagecolorallocate($image, 0,0,255);
for($i=0;$i<1000;$i++) {
imagesetpixel($image,rand()%200,rand()%50,$pixel_color);
}
//$textbox = imagettfbbox($font_size, 0, $font, $code);
//$textbox = imagettfbbox($font_size, 0, $randomString);
$x = ($width - $textbox[4]) / 2;
$y = ($height - $textbox[5]) / 2;
// imagettftext($image, $font_size, 0, $x, $y, $text_color, $font , $code);
imagettftext($image, $font_size, 0, $x, $y, $text_color , $word);
$images = glob("*.png");
foreach ($images as $image_to_delete) {
#unlink($image_to_delete);
}
imagepng($image, "image" . $_SESSION['count'] . ".png");
header('Content-Type: image/png');
imagepng($image);
imagedestroy($image);
}
security_image();
?>
I have no idea what I’m doing wrong. I’ve spent over 10 hours on this “display text” issue. I don’t understand and I am desperate for help. I even downloaded working captcha version from other resources that break once I upload it to my server. I have no idea whats going on. At first I thought there was something wrong with my server but the fact that I can even create the pixels, lines image means that it is at least working.
Please help!!!! 
UPDATE---------------------------------------------
Thank you for your suggestions. Here is the edited code. I'm still getting the same issue.
<?PHP
session_start();
function security_image(){
global $image;
// $code = isset($_SESSION['captcha']) ? $_SESSION['captcha'] : generate_code();
$font = 'content/fonts/comic.ttf';
$width = '110';
$height = '20';
$font_size = $height * 0.75;
$image = imagecreatetruecolor($width, $height) or die("Cannot Initialize new GD image stream");
$background_color = imagecolorallocate($image, 255, 255, 255);
imagefilledrectangle($image,0,0,200,50,$background_color);
$line_color = imagecolorallocate($image, 64,64,64);
for($i=0;$i<10;$i++) {
imageline($image,0,rand()%50,200,rand()%50,$line_color);
}
$pixel_color = imagecolorallocate($image, 0,0,255);
for($i=0;$i<1000;$i++) {
imagesetpixel($image,rand()%200,rand()%50,$pixel_color);
}
$letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
$len = strlen($letters);
$letter = $letters[rand(0, $len - 1)];
$text_color = imagecolorallocate($image, 0, 0, 0);
$word = "";
for ($i = 0; $i < 6; $i++) {
$letter = $letters[rand(0, $len - 1)];
imagestring($image, 7, 5 + ($i * 30), 20, $letter, $text_color);
$word .= $letter;
}
$_SESSION['captcha_string'] = $word;
/*texbox unitinitialized (removed for the sake of just showing the word size doesnt matter)
$x = ($width - $textbox[4]) / 2;
$y = ($height - $textbox[5]) / 2;
*/
$x = ($width) / 2;
$y = ($height) / 2;
imagettftext($image,$font, 4, $x, $y, $word);
header('Content-Type: image/png');
imagepng($image);
imagedestroy($image);
}
security_image();?>
i made some suggested changes but the code seems to still do the same thing. Just display the lines and pixels as expected but the text still is missing... ?

There are some several "errors" in your functions, let's fix them:
In generateRandomString()
generateRandomString($length = 10)
$lenght is not used its scope.
$text_color = imagecolorallocate($image, 0, 0, 0);
$image is uninitialized
In security_image() function:
$textbox is uninitialized
$text_color and $word is uninitialized.
And Wrong parameter count for imagettftext() You add 7 parameters, and forget the font file parameter.

found the problem. using this:
http://php.net/manual/en/function.imagettftext.php
i was able to see that the font location was incorrect. using the example on that page and editing it to my needs worked.

Related

Make sure imagepng has written the file on the server

I have a function which adds text under a existing qr-code image.
In some cases the return is faster than the server has written the image on the filesystem, so that other function got issues.
How can I make sure that everything is done before I return the path to the image?
At the moment I am trying to use a while-loop, but I am also really unhappy with it. That causes also timeouts and crashes on my server (no idea why).
function addTextToQrCode($oldImage, $text)
{
$newImage = $oldImage;
$newImage = str_replace(".png", "_original.png", $newImage);
copy($oldImage, $newImage);
$image = imagecreatefrompng($oldImage);
$black = imagecolorallocate($image, 0, 0, 0);
$fontSize = 20;
$textWidth = imagefontwidth($fontSize) * strlen($text);
$textHeight = imagefontheight($fontSize);
$x = imagesx($image) / 2 - $textWidth / 2;
$y = imagesy($image) - $textHeight - 3;
imagestring($image, 5, $x, $y, $text, $black);
$filePath = "/qrCodes/qrcode".$text.'.png';
imagepng($image, $filePath);
while(!$this->checkIfNewQrCodeIsOnFileSystem($filePath)){
$this->checkIfNewQrCodeIsOnFileSystem($filePath);
}
return $filePath;
}
function checkIfNewQrCodeIsOnFileSystem($filePath) {
if (file_exists($filePath)) {
return true;
} else {
return false;
}
}
Check only imagepng(). The solution i would prefer.
function addTextToQrCode($oldImage, $text)
{
$newImage = $oldImage;
$newImage = str_replace(".png", "_original.png", $newImage);
copy($oldImage, $newImage);
$image = imagecreatefrompng($oldImage);
$black = imagecolorallocate($image, 0, 0, 0);
$fontSize = 20;
$textWidth = imagefontwidth($fontSize) * strlen($text);
$textHeight = imagefontheight($fontSize);
$x = imagesx($image) / 2 - $textWidth / 2;
$y = imagesy($image) - $textHeight - 3;
imagestring($image, 5, $x, $y, $text, $black);
$filePath = "/qrCodes/qrcode".$text.'.png';
if (imagepng($image, $filePath) === true) {
return $filePath;
}
}

Try a simple captcha in CI4

I want to implement a simple captcha in ci4, I try to search a sample code in google and then copas it. But when run the code get result like this. Please help what wrong in my code ?
My controller is :
private function captcha()
{
$i = 0;
$imgHeight = 80;
$imgWidth = 250;
$randTotal = 7;
$randomDots = 50;
$randomLines = 25;
$font = realpath('./fonts/monofont.ttf');
$random = '';
$captTextColor = "0x142864";
$noiseColor = "0x142864";
$fontSize = $imgHeight * 0.65;
$random = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz0123456789'), 0,
$randTotal);
$image = #imagecreate($imgWidth, $imgHeight);
$arrTextColor = $this->hexToRGB($captTextColor);
$arrNoiseColor = $this->hexToRGB($noiseColor);
$bgColor = imagecolorallocate($image, 255, 255, 255);
$captTextColor = imagecolorallocate($image, $arrTextColor['red'], $arrTextColor['green'], $arrTextColor['blue']);
$imgNoiseColor = imagecolorallocate($image, $arrNoiseColor['red'], $arrNoiseColor['green'], $arrNoiseColor['blue']);
// Cetak titik acak di latar belakang gambar
for ($i = 0; $i < $randomDots; $i++) {
imagefilledellipse($image, mt_rand(0, $imgWidth), mt_rand(0, $imgHeight), 2, 3, $imgNoiseColor);
}
// Cetak garis acak di latar belakang gambar
for ($i = 0; $i < $randomLines; $i++) {
imageline(
$image,
mt_rand(0, $imgWidth),
mt_rand(0, $imgHeight),
mt_rand(0, $imgWidth),
mt_rand(0, $imgHeight),
$imgNoiseColor
);
}
// Cetak kotak teks dan tambahkan 6 kode huruf captcha
$textBox = imagettfbbox($fontSize, 0, $font, $random);
$x = ($imgWidth - $textBox[4]) / 2;
$y = ($imgHeight - $textBox[5]) / 2;
$_SESSION['captcha'] = $random;
// imagettftext($image, $fontSize, 0, $x, $y, $captTextColor, $font, $random);
imagettftext($image, $fontSize, 0, $x, $y, $captTextColor, $font, $random);
header('Content-Type: image/jpeg');
imagejpeg($image, null, null);
imagedestroy($image);
}
Thank you
Thank you.
Try adding the exit; command after the imagedestroy($image); line

php gd vertical text an image

I would like to put on a picture in vertical text in PHP:
function scrivi($scrivi, $p) {
$imgResource = imagecreatefromjpeg($p);
$textcolor = imagecolorallocate($imgResource, 255, 255, 255);
$fontPath = "st.ttf";
$fontSize = "18";
$rotation = "270"; // counter-clockwise rotation
$text = "this is a text";
$textCoords = imagettfbbox($fontSize, $rotation, $fontPath, $text);
$x = 36;
$y = 36;
imagettftext($imgResource, $fontSize, $rotation, $x, $y, $textcolor, $fontPath, $text);
unlink($p);
imagejpeg($imgResource, $p, 100);
imagedestroy($imgResource);
}
It works well only that I would like that the letters are turned this is an example using the function
Instead I would like to
an idea could be to wrap each letter
All you really need to do is split the text into an array, loop it, then offset the y by the height + leading of the font character:
function scrivi($p,$text)
{
$imgResource = imagecreatefromjpeg($p);
$textcolor = imagecolorallocate($imgResource, 255,255, 255);
$fontPath = __DIR__."/st.ttf";
$fontSize = "18";
$x = 36 ;
$y = 36;
foreach(str_split($text) as $char) {
$textCoords = imagettfbbox($fontSize, 0, $fontPath, $char);
imagettftext($imgResource, $fontSize, 0, $x, $y, $textcolor,$fontPath,$char);
$y += 24;
}
unlink($p);
imagejpeg($imgResource,$p,100);
imagedestroy($imgResource);
}
scrivi('http://imgtops.sourceforge.net/bakeoff/bw.jpg',"Cats are great");
Gives you:
(Image credit: http://imgtops.sourceforge.net/bakeoff/)

Resize image size according to size of text

The PHP code below generates text as a dynamically created image, how would I be able to get the image to only be as large as the text? Thanks.
<?php
header('Content-Type: image/jpeg');
$text='Test';
$img = imageCreate(200,200);
imagecolorallocate($img, 255, 255, 255);
$textColor = imagecolorallocate($img, 0, 0, 0);
imagefttext($img, 15, 0, 0, 55, $textColor, 'bgtbt.ttf', $text);
imagejpeg($img);
imagedestroy($img);
?>
UPDATE 1: I found the answer here with the example of the original poster - Creating IMage from Text in PHP - how can I make multiline?
UPDATE 2: Martin Geisler's version also works well
When using a TrueType font, you use the imageftbbox function to obtain the bounding box for a string typeset with your font. The bounding box gives the offsets from the base-point to the four corners in the rectangle occupied by the text. So if you store the bounding box in $bb and use imagefttext to put text at ($x, $y), then the corners will have these coordinates:
($x + $bb[6], $y + $bb[7]) ($x + $bb[4], $y + $bb[5])
+-------+
| Hello |
+-------+
($x + $bb[0], $y + $bb[1]) ($x + $bb[2], $y + $bb[3])
That tells us that we want an image width of ($x + $bb[2]) - ($x + $bb[6]) = $bb[2] - $bb[6] and similarly an image height of $bb[3] - $bb[7]. The text should then be rendered at coordinates (-$bb[6], -$bb[7]) inside that picture since we want to have
(0, 0) = ($x + $bb[6], $y + $bb[7]) ==> $x = -$bb[6] and $y = -$bb[7]
You can try it out with this code. Put it into a file called img.php and browse to img.php?q=Hello to test:
<?php
header("Content-type: image/png");
$q = $_REQUEST['q'];
$font = "Impact.ttf";
$size = 30;
$bbox = imageftbbox($size, 0, $font, $q);
$width = $bbox[2] - $bbox[6];
$height = $bbox[3] - $bbox[7];
$im = imagecreatetruecolor($width, $height);
$green = imagecolorallocate($im, 60, 240, 60);
imagefttext($im, $size, 0, -$bbox[6], -$bbox[7], $green, $font, $q);
imagepng($im);
imagedestroy($im);
?>
If you use the bitmap fonts instead, then look at the imagefontwidth and imagefontheight functions.
#Martin Geisler's answer is almost correct, but I couldn't get my text to fit completely inside the image. I tried this instead, which works perfectly!
From the PHP Manual's User Contributed Notes:
$text = "<?php echo \"hello, world\"; ?>";
$font = "./arial.ttf";
$size = "60";
$bbox = imagettfbbox($size, 0, $font, $text);
$width = abs($bbox[2] - $bbox[0]);
$height = abs($bbox[7] - $bbox[1]);
$image = imagecreatetruecolor($width, $height);
$bgcolor = imagecolorallocate($image, 255, 255, 255);
$color = imagecolorallocate($image, 0, 0, 0);
$x = $bbox[0] + ($width / 2) - ($bbox[4] / 2);
$y = $bbox[1] + ($height / 2) - ($bbox[5] / 2);
imagefilledrectangle($image, 0, 0, $width - 1, $height - 1, $bgcolor);
imagettftext($image, $size, 0, $x, $y, $color, $font, $text);
$last_pixel= imagecolorat($image, 0, 0);
for ($j = 0; $j < $height; $j++)
{
for ($i = 0; $i < $width; $i++)
{
if (isset($blank_left) && $i >= $blank_left)
{
break;
}
if (imagecolorat($image, $i, $j) !== $last_pixel)
{
if (!isset($blank_top))
{
$blank_top = $j;
}
$blank_left = $i;
break;
}
$last_pixel = imagecolorat($image, $i, $j);
}
}
$x -= $blank_left;
$y -= $blank_top;
imagefilledrectangle($image, 0, 0, $width - 1, $height - 1, $bgcolor);
imagettftext($image, $size, 0, $x, $y, $color, $font, $text);
header('Content-type: image/png');
imagepng($image);
imagedestroy($image);

Creating IMage from Text in PHP - how can I make multiline?

I have a script that generates images from text using PHP. It's working fine except that I would like it to generate multiline text as well with differing colors. How can it be done using PHP, GD and Freetype? Below is the code I use to generate single line text images.
$textval = 'This is some text to be an image';
$textcolor = '666666';
$font="arial.ttf";
$size = 9;
$padding= 1;
$bgcolor= "ffffff";
$transparent = 0;
$antialias = 0;
$fontfile = $fontpath.$font;
$box= imageftbbox( $size, 0, $fontfile, $textval, array());
$boxwidth= $box[4];
$boxheight= abs($box[3]) + abs($box[5]);
$width= $boxwidth + ($padding*2) + 1;
$height= $boxheight + ($padding) + 0;
$textx= $padding;
$texty= ($boxheight - abs($box[3])) + $padding;
// create the image
$png= imagecreate($width, $height);
$color = str_replace("#","",$bgcolor);
$red = hexdec(substr($bgcolor,0,2));
$green = hexdec(substr($bgcolor,2,2));
$blue = hexdec(substr($bgcolor,4,2));
$bg = imagecolorallocate($png, $red, $green, $blue);
$color = str_replace("#","",$textcolor);
$red = hexdec(substr($textcolor,0,2));
$green = hexdec(substr($textcolor,2,2));
$blue = hexdec(substr($textcolor,4,2));
$tx = imagecolorallocate($png, $red, $green, $blue);
imagettftext( $png, $size, 0, $textx, $texty, $tx, $fontfile, $textval );
header("content-type: image/jpeg");
imagejpeg($png);
imagedestroy($png);
exit;
Add this function to wrap the text before it goes into your function.
function wrap($fontSize, $angle, $fontFace, $string, $width){
$ret = "";
$arr = explode(' ', $string);
foreach ( $arr as $word ){
$teststring = $ret.' '.$word;
$testbox = imagettfbbox($fontSize, $angle, $fontFace, $teststring);
if ( $testbox[2] > $width ){
$ret.=($ret==""?"":"\n").$word;
} else {
$ret.=($ret==""?"":' ').$word;
}
}
return $ret;
}
Source: http://www.php.net/imagettftext

Categories