I have a page that does load images from mysql db - but they don't go to the anchor. The first page is listings that just has text, and the second shows image(s) for those. After refresh the category page will go to the anchored link, but I've been told that I need to have the image width and height in order for the page to know what it has to jump to. Getimagesize was suggested as a possible fix. I've been reading on this for the past three hours and just don't know how to get it into what I need.

Here's a snippet from the listings page that has the text link

echo "<a href='category.php?cid=".$row['category_id']."#advertiser_".$row['advertiser_id']."'>";

And here's the category page

<?php 
   
   //make sure there is a valid category id passed
   $found = false;
   $category = array();
   
   $catSql = "select * from category where category_id = '".$_GET['cid']."'";
   $result = mysql_query($catSql);
   if(mysql_num_rows($result) > 0){
      $found = true;
      $category = mysql_fetch_array($result);
   }
   

   if($found){
      
      $sql = "select * from advertisers a left join category c using(category_id) WHERE ";
      $sql .= " c.category_id = '".$_GET['cid'] . "' and a.visible = 1 order by a.advertiser_name asc ";
   
      $result = @mysql_query($sql);
      //PRINT OUT THE CATEGORY TITLE
      echo "<h1>".stripslashes($category['category_name'])."</h1>";
      
      //LOOP THROUGH THE RESULT SET AND PRINT OUT THE IMAGES
      while($row = mysql_fetch_array($result)){
         
         //PUT EACH ADVERTISER IN A SEPARATE DIV THAT CAN BE USED FOR STYLING
         echo "<div>";
         
         //PRINT OUT THE ANCHOR FOR THE RECORD
         echo "<a name='product_".$row['product_id']."' />\n";
         
         //PRINT OUT THE FIRST IMAGE IF IT EXISTS
         if(trim($row['img1']) != "" && file_exists($row['img1']))
            echo '<img src="' . $row['img1'] . '" alt="' . stripslashes($row['advertiser_name']) . '" id="advertiser_' . $row['advertiser_id'] . '" />';		
			echo "<br>";
			echo "<a href='listings.php'>Back to Listings</a>";
			echo "<br>";
         
         //A SECOND IMAGE EXISTS.  SPIT OUT A BREAK AND DISPLAY THE IMAGE   
         if(trim($row['img2']) != "" && file_exists($row['img2'])){
            echo "<br>";
            echo '<img src="' . $row['img2'] . '" alt="' . stripslashes($row['advertiser_name']) . '" id="advertiser_' . $row['advertiser_id'] . '" />';
			echo "<br>";
         }   
         
         echo "</div>"; 
      }
   }
   else{
      //put an error message here
      ?>
         you screwed up - please try again
      <?
   }
?>

Can someone please help show me where to insert getimagesize into the above code and a brief explanation on using?

thanks

Member Avatar for langsor

getimagesize() works on an image file and not raw image data (like that returned from your database), so the easiest approach is to call it on the images before they're inserted into the database and have table-fields in the database to store the width, height, and mime-type of the inserted images.

You can also find some good info in the php documentation discussions
http://us2.php.net/manual/en/function.getimagesize.php

When I run getimagesize on a gif file I get this print_r output // commented by me

Array
(
    [0] => 80    // width
    [1] => 100   // height
    [2] => 1     // image type (gif)
    [3] => width="80" height="100"
    [bits] => 7
    [channels] => 3
    [mime] => image/gif
)

So getimagesize returns an array (part indexed, part associative) which provides all the data about the given image file.

Hope this helps

P.S. Search for boshka at gmail dot com on the above documentation page for a possible way to get the image data after the image has been loaded into the database ...

Thanks, langsor. I'll see if I can figure all that out. I can certainly add the fields to the db - since I'm still in testing I only have about 30 images to work out. I had seen some people using the function to resize, but I just need to tell the page what's going on. At least, I hope that will work.

Donna

Member Avatar for langsor

Hi Donna,

Get image size is one of the GD image library functions but alone will not resize an image.

You could always scale the image in the html, but this is not efficient for bandwidth optimization ... otherwise you will want to use other methods of the GD library -- some of which can be pretty tricky to figure out.

I point you to the official PHP documentation and discussions of these methods
http://us2.php.net/manual/en/ref.image.php

If you want to tackle this stuff, I would first Google ...
php tutorial imagecreatefromjpeg
(function ref: http://us2.php.net/manual/en/function.imagecreatefromjpeg.php)
-or-
php tutorial imagecreatefrompng
(function ref: http://us2.php.net/manual/en/function.imagecreatefrompng.php)
as a place to start ...

Hope this helps and good luck

Thanks, langsor. I don't have to scale or resize - the images will be 100% of whatever they are. I just need to have the width and height in the img tag so the browser knows what to expect.

Donna

Member Avatar for langsor

I've been playing with inserting images and image data into a database, and then publishing the images back to html -- this has been entertaining and a little tricky.

The trick when publishing the image back to an html <img> tag is that you must either make a temporary image file and load that image path -- or call the php file that gets the image from the database, as if it were the image file. The second option makes extracting the image height, width, mime-type, etc from the database a two-query operation.

The reason for this is, if you try to load the raw image binary data directly into the <img> tag src="" attribute, you get binary-string data displayed on your html page, not an image. And you also have to set the header-type for the image, but the header has already been set as "text/html" for the html page ... so you're out of luck here.

Looking at the second approach -- calling the php file as an image path

print_image.php

<?php
$id = $_GET['id'];
$conn = myslq_connect( 'localhost', 'user', 'password' );
mysql_query( "USE `test`" );
$result = mysql_query( "SELECT `data`, `mime` FROM `images` WHERE `id`='$id'" );

if ( mysql_num_rows( $result ) ) {
  $img = mysql_fetch_object( $result );
  header( "Content-type: $img->mime" );
  print $img->data;
} else {
  header( 'Content-type: image/gif' );
  print file_get_contents( 'path_to/images/not_found.gif' );
}
?>

This type of thing works great, until you want to know more about your image within the html file.

<body>
<?php
print "<img src=\"print_image.php?id=3\" width=\"\" height=\"\" alt=\"\" />";
// we have no database values for image-type, width, height, caption, etc ...
?>
</body>

My approach was to create an image database class ...

This is not a database abstraction layer, so you still need to connect to the database,
select your 'images' table, and search for which image you want to select for you
image-object using SQL queries outside of the image-object created by the class

And in this class when you select an image, it creates a temp file of that image
and makes the path to that file available as a property of the image-object.

I don't have any garbage-collection for these temp images worked into the class
but since there are really only three types of images used in html, there will only
ever be three temp images on the server at a given time ... once the browser loads
the image, it displays it from memory and the temp image can be overwritten without
issue -- assuming there aren't multiple image calls at the same time to the database.

It's an imperfect solution, but illustrates one approach to this situation.

An alternate approach would be to give each temp file a random name (no namespace
conflicts
) and then implement some garbage cleanup routine on a cron-job or similar.

db_image.php

<?php
class DB_Image {
  public function __construct ( $conn = NULL ) {
    // $conn must be a database connection link resource
    // with administrative privelages to add tables ...
    // built around MySql databases, but easily modified
    if ( $conn ) {
      $this->connect( $conn );
    }
  }
  
  public function select ( $id ) {
    @mysql_free_result( $this->result );
    // for multiple results, or more sophistocated searches, perform your
    // search and proccess the images one at a time within a loop block
    // calling this function foreach unique `id` in your query results.
    $this->result = mysql_query( "SELECT * FROM `images` WHERE `id`='$id'", $this->conn );
    if ( $count = mysql_num_rows( $this->result ) ) {
      // populate image properties for object access
      // *** feel free to eliminate redundancy and/or
      //     use the naming conventions you prefer ***
      $image = mysql_fetch_object( $this->result );
      $this->id = $id;
      $this->data = base64_decode( $image->data );
      $this->raw = $this->data;               // redundant
      $this->binary = $this->data;            // redundant
      $this->name = $image->name;
      $this->capt = $image->caption;
      $this->caption = $image->caption;       // redundant
      $this->mime = $image->mime;
      $this->mime_type = $image->mime;        // redundant
      $this->type = $image->type;
      $this->ext = $image->type;              // redundant
      $this->extension = $image->type;        // redundant
      $this->atts = $image->attributes;
      $this->attributes = $image->attributes; // redundant
      $this->width = $image->width;
      $this->height = $image->height;
      $this->length = $image->length;
      $this->content_length = $image->length; // redundant
      $this->created = $image->created;
      $this->inserted = $image->inserted;
      $this->accessed = $image->accessed;
      $this->path = "temp.$this->type";
      file_put_contents( $this->path, $this->data );
      $accessed =  date( 'Y-m-d G:i:s', time() );
      mysql_query( "UPDATE `images` SET `accessed`='$accessed' WHERE `id`='$id'", $this->conn );
    } else {
      print( "No results for image id: $id" ); // remove for production
    }
    return $count;
  }
  
  public function insert ( $path, $name = NULL, $caption = NULL ) {
    if ( file_exists( $path ) && $info = getimagesize( $path ) ) {
      $data = base64_encode( file_get_contents( $path ) );
      $name = addslashes( $name );
      $caption = addslashes( $caption );
      $mime = $info['mime'];
      switch( $info[2] ) {
        case 1: $type = 'gif'; break;
        case 2: $type = 'jpg'; break;
        case 3: $type = 'png'; break;
        // view all types here: 
        // http://us.php.net/manual/en/function.exif-imagetype.php
      }
      $attributes = $info[3];
      $width = $info[0];
      $height = $info[1];
      $length = filesize( $path );
      $created = date( 'Y-m-d G:i:s', filemtime( $path ) );
      $inserted =  date( 'Y-m-d G:i:s', time() );
      $accessed =  date( 'Y-m-d G:i:s', time() );
      $result = mysql_query( "INSERT INTO `images` VALUES ( 
        NULL, '$data', '$name', '$caption', '$mime', '$type', '$attributes',
        $width, $height, $length, '$created', '$inserted', '$accessed' )", 
      $this->conn ) or die( "Could not make images table: ".mysql_error() );
      return mysql_insert_id( $this->conn );
    } else {
      print( "Could not find image at path: $path" ); // remove for production
      return FALSE;
    }
  }
  
  public function connect ( $conn ) {
    if ( $conn ) {
      $exists = FALSE;
      $this->conn = $conn;
    } else {
      die( "Please connect to your database" );
    }
    // test for and/or create images table
    $result = mysql_query( "SELECT DATABASE()", $conn ) 
      or die ( "No database selected: ".mysql_error() );
    $dbase = mysql_result( $result, 0 );
    mysql_free_result( $result );
    $result = mysql_list_tables( $dbase, $conn );
    $count = mysql_num_rows( $result );
    for ( $i = 0; $i < $count; $i ++ ) {
      if ( mysql_tablename( $result, $i ) == 'images' ) {
        $exists = TRUE;
      }
    }
    mysql_free_result( $result );
    if ( $exists ) {
      $this->dbase = $dbase;
    } else {
      $exists = $this->create_table();
    }
    return $exists;
  }
  
  protected function create_table () {
    mysql_query( "CREATE TABLE IF NOT EXISTS `images` ( 
      `id` INT(255) UNSIGNED NOT NULL AUTO_INCREMENT, 
      `data` MEDIUMBLOB NOT NULL,
      `name` VARCHAR(255) DEFAULT NULL,
      `caption` VARCHAR(255) DEFAULT NULL,
      `mime` VARCHAR(255) NOT NULL,
      `type` VARCHAR(255) NOT NULL,
      `attributes` VARCHAR(255) NOT NULL,
      `width` TINYINT UNSIGNED NOT NULL,
      `height` TINYINT UNSIGNED NOT NULL,
      `length` MEDIUMINT UNSIGNED NOT NULL,
      `created` DATETIME,
      `inserted` DATETIME,
      `accessed` DATETIME,
      PRIMARY KEY(`id`) )" ) 
    or die( "Could not make images table: ".mysql_error() );
    return TRUE;
  }
  
  public function __destruct () {
    @mysql_close( $this->conn );
  }
}
?>

Here we control the structure of the 'images' table in order to interact with it effectively within the class.


Following are some basic test routines illustrating the image class, and for the 'images' table

<?php

require_once 'db_image.php';

$link = mysql_connect( 'localhost', 'root', 'TopSecret' );
mysql_query( "USE `test`" );

//mysql_query( "DROP TABLE IF EXISTS `images`" ); // development

$img = new DB_Image(); 
$img->connect( $link );
// or pass on instantiation ...
//$img = new DB_Image( $link );

$id = $img->insert( 'my_image.gif', 'file_name', 'My Image Caption' ); // returns insert-id
// or omit or NULL values for optional arguments
//$id = $img->insert( 'my_image.gif', NULL, 'My Image Caption' );
//$id = $img->insert( 'my_image.gif', 'file_name' );
//$id = $img->insert( 'my_image.gif' );

$img->select( $id ); // pass insert-id (primary-key)
// or select by known id-interger
//$img->select( 3 );

?>
<html>
<head>
  <title>DB_Image Class Example</title>
</head>
<body>
<?php
// PRINT IMAGE TO FILE EXAMPLE
//file_put_contents( "path_to/images/$img->name.$img->type", $img->data );
//file_put_contents( "path_to/images/my_name.$img->type", $img->data );

// PRINT IMAGE TO HTML EXAMPLE
print "<img src=\"$img->path\" $img->atts alt=\"$img->caption\" /><br />\n";

// PRINT AVAILABLE PROPERTIES
print "<p><strong>All availabe image-object properties</strong><br />\n";
foreach ( $img as $key => $value ) {
  if ( $key != 'conn' &&     // database resource
       $key != 'result' &&   // database resource
       $key != 'data' &&     // image raw data
       $key != 'raw' &&      // alias of data
       $key != 'binary' ) {  // alias of data
    print "$key :: $value<br />\n";
  }
}
print '<br /></p>';


// EXPOSE TABLE STRUCTURE
print "<p><strong>Database 'images' table structure</strong>\n";
expose_db( $link, 'test' );
function expose_db ( $conn, $dbase ) {
  if ( $conn ) {
    mysql_query( "USE $dbase" );
    $tables = mysql_query( "SHOW TABLES" );
    while ( $table = mysql_fetch_assoc( $tables ) ) {
      $key = key( $table );
      print "<br>\nTable => ".$table[$key]."<br>\n";
      $fields = mysql_query( "DESCRIBE ".$table[$key] );
      while ( $field = mysql_fetch_assoc( $fields ) ) {
        foreach ( $field as $name => $value ) {
          if ( $value ) {
            print $name .' => '. $value .' :: ';
          }
        }
        print "<br>\n";
      }
    }
  } else {
    die( 'No connection available' );
  }
}
print '</p>';
?>
</body>
</html>

That's it ... okay, it is an understatement for everything I stuffed into one post, but hopefully this will be useful to you, at least as an example of the various approaches.

See attached for all files used in this example ...

Ciao

:-)

Member Avatar for langsor

I don't have any garbage-collection for these temp images worked into the class
but since there are really only three types of images used in html, there will only
ever be three temp images on the server at a given time ... once the browser loads
the image, it displays it from memory and the temp image can be overwritten without
issue -- assuming there aren't multiple image calls at the same time to the database.

It's an imperfect solution, but illustrates one approach to this situation.

An alternate approach would be to give each temp file a random name (no namespace
conflicts
) and then implement some garbage cleanup routine on a cron-job or similar.

Seems I can't leave well enough alone ... ;-)

I decided that the possibility of namespace collisions was more than I could sleep at night, so put together a little garbage collection method for the DB_Image class.

To include the method add and change the original class as follows ...

// REPLACE THE CURRENT LINE IN THE insert METHOD WITH THIS ONE
  // $this->path = "temp.$this->type";
      $this->path = $this->make_temp();

  // ADD THESE TO THE BOTTOM OF THE CLASS DEFINITION
  public function make_temp () {
    $temp = 'temp'; // name for temp directory
    if ( !$exists = is_dir( $temp ) ) {
      $exists = mkdir( $temp, 0777, TRUE );
    }
    $this->tmp_eval = ( $exists ) ? "$temp/" : '.';
    $this->tmp_path = str_replace( '.', '', $this->tmp_eval );
    $tmp_file = tempnam( $this->tmp_eval, strtoupper( $this->type ) );
    return $this->tmp_path.basename( $tmp_file );
  }
  
  protected function handle_garbage () {
    $life = 30; // minimum lifetime for temp files in seconds 
    if ( $dir = opendir( $this->tmp_eval ) ) {
      while ( ( $file = readdir( $dir ) ) !== FALSE ) {
        $tmp_file = $this->tmp_path.$file;
        if ( is_file( $tmp_file ) && strpos( $tmp_file, '.tmp' ) > 0 ) {
          if ( time() > ( filemtime( $tmp_file ) + $life ) ) {
            @unlink( $tmp_file );
          }
        }
      }
      closedir( $dir );
    }
  }

  // REPLACE THE OLD __destruct METHOD WITH THIS ONE
  public function __destruct () {
    @mysql_close( $this->conn );
    $this->handle_garbage();
  }

I honestly don't know if anyone is still tuned-in to this thread, but I had fun making this stuff and learned a lot doing it and will likely use it myself in the near future ... and hopefully someone else gets something from it too.

:-)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.