Click to See Complete Forum and Search --> : Few classes i did this week..


redrage
12-14-2007, 04:29 PM
I've written a few classes to help me make the adjustment to OOP in PHP and also get away from me being used to writing in PHP3 and 4 functions which have been depreciated along time ago.

Just realized this is a really long post, sorry, but i did cut out a lot of the junk that is not used if that helps.

The idea eventually is to have them replace my current code on my latest popular web site :) and it is terrible.

The first is a basic image handler with 3 functions, one to get the dimensions and filesize, one to get the image type and another to resize the image. once all the functions of the site are completely done, i was thinking about adding watermarking and such to this class.

class imageHandler

class imageHandler
{

// get the width(x),height(y) and filesize of an image
function sizeofImage ($pathtoImage)
{
$s = getimagesize($pathtoImage);
$size['x'] = $s[0];
$size['y'] = $s[1];
$size['filesize'] = filesize($pathtoImage);

return $size;
}


// get the image type by reading the first line of the file
// and looking for image markers.
// there are better ways of doing this but my version of PHP is lacking
// the correct options.
function typeofImage ($pathtoImage)
{
$fp = fopen($pathtoImage,"r");
$data = fread($fp,1024);
fclose($fp);
if (eregi("PNG",$data))
{
$type = "image/png";
#} else if(eregi("JFIF",$data)) {
} else if (strstr($data,"JFIF")) {
$type = "image/jpeg";
} else if(eregi("GIF",$data)) {
$type = "image/gif";
} else {
$type = "not found";
}
return $type;
}

// resize an image from source file to destination file to a specified width(x)
function resizeImage($source,$dest,$x)
{

// get the sizes and type of the image
$size = $this->sizeofImage($source);
$type = $this->typeofImage($source);

// set the new height(y) of image
$y = (int) (($x / $size['x']) * $size['y']);

// create the image area
$imageDest = imagecreatetruecolor($x, $y);

// check the type of image so we know what to do next
if($type === "image/jpeg")
{
$imageOrg = imagecreatefromjpeg($source);
imagecopyresampled($imageDest, $imageOrg, 0, 0, 0, 0, $x, $y, $size['x'], $size['y']);
imagejpeg($imageDest,$dest,'100') or die("Could not make image");
} else if($type === "image/png") {
$imageOrg = imagecreatefrompng($source);
imagecopyresampled($imageDest, $imageOrg, 0, 0, 0, 0, $x, $y, $size['x'], $size['y']);
imagepng($imageDest,$dest,'100') or die("Could not make image");
} else if($type === "image/gif") {
$imageOrg = imagecreatefromgif($source);
imagecopyresampled($imageDest, $imageOrg, 0, 0, 0, 0, $x, $y, $size['x'], $size['y']);
imagepng($imageDest,$dest,'100') or die("Could not make image");
}

// remove image from memory...
// god i wish i could just remove images from my memory.
// imagine how nice it would be not to have to have that mental
// picture of that guy getting his head stuck up that elephants arse
// or that mental image of your parents doing the nasty in the kitchen
// with your best friends cousin when you came home when practice was
// done early. God please give me an imagedestroy() for my brain!!!
// Amen.
imagedestroy($imageDest);

return TRUE;
}
}


the next class stores an image, now currently i use a database but i figured i would write one for normal files too (since i was bored anyway). if thumbnail is set to yes (defaults to no) then call imageHandlers resize function and safe the thumbnail.

class imageStorage

class imageStorage
{

// uploadedFile: the uploaded file tmp name
// dest: where to save the image, any writeable directory
// thumb: whether to generate a thumbnail or not. (default: No, set to Yes for a 100px wide thumbnail)
function storeasFile($uploadedFile,$dest,$thumb="No")
{

// quick security check.
#if(!is_uploaded_file($uploadedFile)) {
# die ("File not uploaded by this script.\n<br>Possible Hack attempt, This session has been logged.\n");
# // note, it really hasn't... yet
#}
// move the image to the destination
move_uploaded_file($uploadedFile,$dest);

// if Thumb is set run the thumbnail generation from imagehandler class
if($thumb !== "No")
{

// create thumbnail name I think theres an easier way to do this with regex
// but i'm too tired to care right now, and this works
$pinfo = pathinfo($dest);
$fileExten = "." . $pinfo[extension];
$thumbname = ereg_replace($fileExten,"_thmb".$fileExten,$dest);
// create and save the thumb nail
$ih = new imageHandler();
$ih->resizeImage($dest,$thumbname,'100');
}


}



// Config file: See sample_db_config.php
// source: the uploaded file tmp name
// dest: in this case the only thing this is used for is the filename
// thumb: whether to generate a thumbnail or not. (default: No, set to Yes for a 100px wide thumbnail)
// you can add columns to the insert just make sure you look at the sample_db_config.php
function storeinDB($dbConfigFile,$source,$dest,$thumb="No")
{

// setting up the data to put into the databas
$ipaddy = $_SERVER['REMOTE_ADDR'];
$filename = $dest;

$ih = new imageHandler();
$filetype = $ih->typeofImage($source);
$size = $ih->sizeofImage($source);
$filesize = $size['filesize'];


require($dbConfigFile);
$db = MYSQL_CONNECT($server,$user,$pass) or die(mysql_error());
mysql_select_db($database) or die(mysql_error());

// setting up data for the image
#$image = mysql_real_escape_string(fread(fopen($source,"r"),$filesize));
$image = mysql_real_escape_string(file_get_contents($source,FILE_BINARY));

//setup data for the thumbnail
if ($thumb !== "No")
{
// create the thumbnail, setup the string
$pinfo = pathinfo($dest);
$fileExten = "." . $pinfo[extension];
$thumbname = ereg_replace($fileExten,"_thmb".$fileExten,$dest);
$ih->resizeImage($source,'/tmp/'.$thumbname,'100');
$thumb = mysql_real_escape_string(file_get_contents('/tmp/'.$thumbname,FILE_BINARY));

} else if($thumb ==="No") {
$thumb = ""; // no more thumbs.. kinda like diVinci
}

// Connect to database (using the config file) and upload the image.

$sql="INSERT INTO $table (ipaddy,filename,filesize,filetype,thumb,image) VALUES ('$ipaddy','$filename','$filesize','$filetype','$thumb','$image')";
$result=mysql_query($sql) or die ("Could not insert data: " . mysql_error());
mysql_close($db);

return TRUE;
}

}


the last is galleryHandler, this allows you to show the thumbnails on a page. Works great for the Database cause pagination was so easy but for files i'm stuck. I may say screw it and not use that option because I don't feel like figureing it out :-) if you have an idea on how i should do it yell. But i really don't care cause I like the database storage better.

class galleryHandler

class galleryHandler
{



// figures out how many pages to set up based on total images in table (in the config) and number per page
function getNumberPages ($dbConfigFile,$perpage)
{
// connect to mysql, retrieve the id field and then count the results
require($dbConfigFile);
$db = MYSQL_CONNECT($server,$user,$pass) or die(mysql_error());
mysql_select_db($database) or die(mysql_error());
$numRows = mysql_num_rows(mysql_query("SELECT id FROM $table",$db));

return $numPages = ceil($numRows / $perpage);
}


// display the thumb nails

function displayDBThumbs ($dbConfigFile,$start,$perpage)
{

require($dbConfigFile);
$db = MYSQL_CONNECT($server,$user,$pass) or die(mysql_error());
mysql_select_db($database) or die(mysql_error());
$sql = "SELECT id,filename,filesize FROM ". $table . " LIMIT " . $start . "," . $perpage;
$result=mysql_query($sql,$db) or die (mysql_error());

while ($myrow=mysql_fetch_array($result))
{
echo "<img src=viewthumb.php?id=" . $myrow['id'] . "&cat=". $table . ">";

}
}


// config file as usual, number of thumbs to show per page and
// the url to show the pages on. (usually $PHP_SELF)
function createDBLinks($dbConfigFile,$perpage,$url)
{
$numPages = $this->getNumberPages ($dbConfigFile,$perpage);
$next =0;
for ($i=1; $i<=$numPages; $i++)
{
echo "<a href=" . $url . "?start=" . $next . ">" . $i . "</a> ";
$next = $next + $perpage;
}
}




function getFileThumbs($directory)
{

$dh = opendir($directory) or die("Could not open directory");
while (($file = readdir($dh)) !== false)
{
if (ereg("_thmb",$file))
{
$thmbArray[] = $file;
}


}
return $thmbArray;
}

function displayFileThumbs($directory,$start,$perpage,$thmbArray)
{
$show = array_slice($thmbArray,0,$perpage);

foreach ($show as $show)
{
echo "<img src=" . $show . ">";
}
}
}



Thanks for any feed back and improvements!

Joe

NogDog
12-15-2007, 06:50 AM
I noticed that in many of the methods throughout those classes you have the same/similar code for connecting to the database. This should be waving a flag at you saying that you need a separate class to handle that stuff. You can then pass that database object to your image classes for them to use, and avoid reconnecting to the database every time one of those image methods is called. Stripped down example:

DB.class.php:

class DB
{
var $dbConnx; // DB connection resource id

// constructor
function DB($dbConfigFile)
{
require($dbConfigFile);
$this->dbConnx = MYSQL_CONNECT($server,$user,$pass) or die(mysql_error());
mysql_select_db($database) or die(mysql_error());
}
}

Generic.class.php:

class Generic
{
var $db; // DB object

// constructor
function Generic($db)
{
$this->db = $db;
}

// sample method
function sample()
{
$query = "SELECT * FROM table";
$result = mysql_query($query, $this->db->dbConnx);
}
}

Usage:

require_once 'DB.class.php';
require_once 'Generic.class.php';
$db = new DB('path/to/config/file');
$gen = new Generic($db);
$gen->sample();

This is a simplistic example, and ultimately you might move more of the database functionality in the database class, so that all your image method would do is pass the desired query string to a query function in the database class. It might then return a query result object (from a query result object class, of course!) with methods for extracting and manipulating the query results. The point here is to help you start thinking in terms of objects instead of in terms of procedures and functions.

And, if you are using PHP 5 there are more things you can do. For instance, you can ensure that a DB object is passed as the parameter to the Generic constructor with "type hinting":

function Generic(DB $db) {

redrage
12-15-2007, 11:02 AM
You are right I should do something with the DB connections. I'll work on that next week.

the only trick is that different Galleries where to have different tables and the quickest (programing wise) way i thought to do it was to have a separate config file for each. You got me rethinking this approach. Instead of making a new connection every freaking time. make one connection and instead of passing the db config, just pass the table name.

Less connections good :)

Thank you i'm sure that will help a lot.

Horizon88
12-16-2007, 03:35 PM
I'd also like to note that in the image class you do lots of type checking using large if/elseif statements, you could possibly drop those into a switch statement to make it a bit neater and easier to maintain, but they work either way.

bradgrafelman
12-17-2007, 01:40 AM
Not only is eregi() a deprecated function, and not only do you not even need a regular-expression-matching function, but there is a better way to determine the type of an image (among other things, such as verifying it's a valid image) that you use just a few lines above it: getimagesize().

$thumbname = ereg_replace($fileExten,"_thmb".$fileExten,$dest);Again, no need to use a (deprecated!) regular expression function here... str_replace() will do just fine.

else if($thumb ==="No") {
$thumb = ""; // no more thumbs.. kinda like diVinci
}If the end result is to set it to an empty string (presumably so that "No" isn't stored in SQL and that an empty string makes more sense) then why use "No" as a default value in the first place? Seems like it'd save you a step if you simply start with a default value of an empty string.

or die ("Could not insert data: " . mysql_error());I'm assuming you're going to change all instances of this when actually using this code? If not... you should; using mysql_error() in a production environment is a definite no-no. Instead, consider logging debug info via error_log() or your own custom error handler.

Also, throughout the galleryHandler class you output (very) invalid HTML - might want to clean that up and run an example of this script through an HTML validator (http://validator.w3.org).

if (ereg("_thmb",$file))Again, same deal as above with the unnecessary use of a (deprecated) regexp function; strstr() or stristr() should suffice here.

Weedpacket
12-17-2007, 02:38 AM
while (($file = readdir($dh)) !== false)
{
if (ereg("_thmb",$file))
{
$thmbArray[] = $file;
}


} That could probably be reduced to a single call to glob. Failing that, scandir.

bradgrafelman
12-17-2007, 02:42 AM
Weedpacket's definitely got a good suggestion (not that you ever don't, Weedpacket :p); using glob() would eliminiate the need to use strstr/stristr() that I mentioned in my post (with glob, you can list only files matching *_thmb.*).

redrage
12-17-2007, 02:05 PM
GREAT thanks for all the responses :-)

I used function sizeofImage ($pathtoImage) basically to put it into an array to make my mind grasp it easier since it is all right there.
I may end up renaming the function to something like imageInfo and adding the image type in there. One of the goals is to make all the
information tidy so i can grab it easy in one shot.

did not realize ereg() was depreciated. bummer i use it A LOT in my scripts. time for a change...

function storeasFile($uploadedFile,$dest,$thumb="No")

sets $thumb to 'No' by default unless it is set as something else. If it is no then just insert nothing, other wise run the resize.
Maybe I should change that to NULL?

I learned the hard way about giving out to much info in the errors :-) but since I wanted to get opinions before i made it live and i'm still tweaking a bit (now a lot hehe) i didn't remove them.

Ya the html needs cleaned but my first goal was to get it to out put.. once that is done then i can do whatever I want to it :)

oh wow! glob() is cool! When i get back to working on the file portion (if i do) then that will be on top of my list :-)

as my daddy always said, you don't know what you don't know. well now i don't know less, thanks peoples!

bubblenut
12-24-2007, 02:35 PM
Although I would agree that it is not appropriate here, neither eregi nor any of the other POSIX regular expression functions are deprecated.

laserlight
12-24-2007, 02:44 PM
Although I would agree that it is not appropriate here, neither eregi nor any of the other POSIX regular expression functions are deprecated.
Not at the moment, but the PHP manual has been subtly recommending the PCRE functions over their POSIX equivalents for quite awhile, and it is clear from a PHP developers' meeting (http://www.php.net/~derick/meeting-notes.html#move-ereg-to-pecl) that PHP's preference is heading towards a heavy PCRE bias. Consequently, the POSIX regex functions are effectively deprecated.

bradgrafelman
12-24-2007, 06:47 PM
Not to mention the possible security vulnerability when using the POSIX regext functions as pointed out in this (http://www.php.net/manual/en/ref.regex.php#74258) user-contributed note.

Combine that with the fact that the PCRE functions are better, faster, more fully-featured than the POSIX ones... eh, they're close enough to being 'deprecated' in my mind. :p

Weedpacket
12-25-2007, 05:12 AM
Just as an observation: why not an Image object; one that contains not only the path to the file, but has properties for all the associated metadata (which might be stored or generated on request)?

Rather than a class that really just contains a bunch of functions that you pass strings to (as it stands there's no difference between the method call "imageHandler::sizeofImage()" except that the method hasn't been declared static; and a globally-scoped function imageHandler_sizeofImage() beyond the fact that the latter has a slightly shorter name.