<?php
// $Header: /cvsroot/tikiwiki/tiki/lib/imagegals/imagegallib.php,v 1.45.2.39 2006/08/10 10:04:31 toggg Exp $

//this script may only be included - so its better to die if called directly.
if (strpos($_SERVER["SCRIPT_NAME"],basename(__FILE__)) !== false) {
  header("location: index.php");
  exit;
}

class ImageGalsLib extends TikiLib {
	function ImageGalsLib($db) {
		# this is probably uneeded now
		if (!$db) {
			die ("Invalid db object passed to ImagegalLib constructor");
		}

		$this->db = $db;
		$exts=get_loaded_extensions();

		// Which GD Version do we have?
		if (in_array('gd',$exts)) {
			$this->havegd = true;

			if (function_exists("gd_info")) {
				$this->gdinfo = gd_info();

				preg_match("/[0-9]+\.[0-9]+/", $this->gdinfo["GD Version"], $gdversiontmp);
				$this->gdversion = $gdversiontmp[0];
			} else {
				//next try
				ob_start();

				phpinfo (INFO_MODULES);

				if (preg_match('/GD Version.*2.0/', ob_get_contents())) {
					$this->gdversion = "2.0";
				} else {
					// I have no experience ... maybe someone knows better
					$this->gdversion = "1.0";
				}

				$this->gdinfo["JPG Support"] = preg_match('/JPG Support.*enabled/', ob_get_contents());
				$this->gdinfo["PNG Support"] = preg_match('/PNG Support.*enabled/', ob_get_contents());
				$this->gdinfo["GIF Create Support"] = preg_match('/GIF Create Support.*enabled/', ob_get_contents());
				$this->gdinfo["WBMP Support"] = preg_match('/WBMP Support.*enabled/', ob_get_contents());
				$this->gdinfo["XBM Support"] = preg_match('/XBM Support.*enabled/', ob_get_contents());
				ob_end_clean();
			}
		} else {
			$this->havegd = false;
		}

		// Do we have the imagick PECL module?
		// Module can be downloaded at http://pecl.php.net/package/imagick
		if (in_array('imagick',$exts)) {
			$this->haveimagick = true;
		} else {
			$this->haveimagick = false;
		}

		//what shall we use?

		//$this->uselib = "gd";
		$this->uselib = $this->get_preference('gal_use_lib', 'gd');

		if ($this->uselib == "imagick") {
			$this->canrotate = true;
		} else {
			$this->canrotate = false;
		}

		//Fallback to GD
		if ($this->uselib == "imagick" && $this->haveimagick == false) {
			$this->uselib = "gd";

			$this->set_preference('gal_use_lib', 'gd');
		}

		// get variables to determine if we can upload and how many data
		// we can upload
		$this->file_uploads=ini_get('file_uploads');
		$this->upload_max_filesize=ini_get('upload_max_filesize');
		$this->post_max_size=ini_get('post_max_size');
		if($this->file_uploads==0) {
		   $this->max_img_upload_size=0;
		} else {

		   }

	}

	function max_img_upload_size() {
	   $this->upload_max_filesize=$this->return_bytes($this->upload_max_filesize);
	   $this->post_max_size=$this->return_bytes($this->post_max_size);
	   if($this->file_uploads==0) {
	      return(0);
	   } else {
	      return(($this->post_max_size > $this->upload_max_filesize) ? $this->post_max_size : $this->upload_max_filesize);
	   }
	}



	// from php manual. one of the rare circumstances where
	// a break in the switch-case is not needed
        function return_bytes($val) {
          $val = trim($val);
          $last = strtolower($val{strlen($val)-1});
          switch($last) {

          // The 'G' modifier is available since PHP 5.1.0
            case 'g':
              $val *= 1024;
            case 'm':
              $val *= 1024;
            case 'k':
              $val *= 1024;
          }

          return $val;
        }

	// Features
	function canrotate() {
		return $this->canrotate;
	}
	//
	// Wrappers
	//
	function validhandle() {
		if (isset($this->imagehandle)) {
			if ($this->uselib == "imagick") {
				// seems not to work in imagick 0.95 aahrgh
				if (imagick_iserror($this->imagehandle))
					return false;

				return true;
			} else if ($this->uselib == "gd") {
				if (imagesx($this->imagehandle) == 0)
					return false;

				return true;
			}
		}

		return false;
	}

	function readimagefromstring() {
		if (!isset($this->image)) {
			return false;
		}

		//avoid error messages
		if (isset($this->filetype)) {
			if (!$this->issupported($this->filetype)) {
				return false;
			}
		}

		if ($this->uselib == "imagick") {
			$this->imagehandle = imagick_blob2image($this->image);
		} else if ($this->uselib == "gd") {
			$this->imagehandle = imagecreatefromstring($this->image);
		}
	}

	function writeimagetostring() {
		if ($this->uselib == "imagick") {
			$this->image = imagick_image2blob($this->imagehandle);
		} else if ($this->uselib == "gd") {
			ob_start();

			imagejpeg ($this->imagehandle);
			$this->image = ob_get_contents();
			ob_end_clean();
		}
	}

	function readimagefromfile($fname) {
		@$fp = fopen($fname, "rb");

		if ($fp) {
			$size = filesize($fname);

			$this->image = fread($fp, $size);
			fclose ($fp);
			// convert to imagehandle to be able to check if its 
			// valid image data
			$this->readimagefromstring();
			// check if imagehandle is a image:
			return($this->validhandle());
		} else {
			return false;
		}
	}

	// for piping out a image
	function pipeimage($fname) {
		$fp = fopen($fname, "rb");

		$size = filesize($fname);
		$this->image = fread($fp, $size);
		fclose ($fp);
		$this->readimagefromstring();

		if($this->validhandle()) echo $data;
	}

	//Get sizes. Image must be loaded before
	function getimageinfo() {
		if ($this->uselib == "imagick") {
			$this->filetype = imagick_getmimetype($this->imagehandle);

			$this->xsize = imagick_getwidth($this->imagehandle);
			$this->ysize = imagick_getheight($this->imagehandle);
		} else if ($this->uselib == "gd") {
			$this->xsize = imagesx($this->imagehandle);

			$this->ysize = imagesy($this->imagehandle);
		}
	}

	//Repair Image info. Is called if someone inserts unsupported images (like gif)
	//and switches to imagick
	function repairimageinfo() {
		if (!isset($this->imageId))
			die();

		if (!$this->issupported($this->filetype))
			die();

		$this->getimageinfo();
		//update
		$query = "update `tiki_images_data` set `xsize`=? , `ysize`=? where `imageId`=? and `type`=?";
		$this->query($query,array((int)$this->xsize,(int)$this->ysize,(int)$this->imageId,$this->type));
	}

	// GD can only get the mimetype from the file
	function getfileinfo($fname) {
		$this->filesize = filesize($fname);

		if ($this->uselib == "imagick") {
		} else if ($this->uselib == "gd") {
			unset ($this->filetype);

			$imageinfo = getimagesize($fname);

			if ($imageinfo["0"] > 0 && $imageinfo["1"] > 0 && $imageinfo["2"] > 0) {
				if ($this->gdversion >= 2.0) {
					$this->filetype = $imageinfo["mime"];
				} else {
					$mimetypes = array(
						"1" => "gif",
						"2" => "jpg",
						"3" => "png",
						"4" => "swf",
						"5" => "psd",
						"6" => "bmp",
						"7" => "tiff",
						"8" => "tiff",
						"9" => "jpc",
						"10" => "jp2",
						"11" => "jpx",
						"12" => "jb2",
						"13" => "swc",
						"14" => "iff"
					);

					$this->filetype = "image/" . $mimetypes[$imageinfo["2"]];
				}
			}
		}
	}

	// resize Image
	function resizeImage($newx, $newy) {
		if (!isset($this->imagehandle)) {
			$this->readimagefromstring();
		}

		if (!isset($this->xsize)) {
			$this->getimageinfo();
		}

		if ($this->xsize * $this->ysize == 0)
			$this->repairimageinfo();

		if ($this->uselib == "imagick") {
			if (!imagick_scale($this->imagehandle, $newx, $newy, "!")) {
				$reason = imagick_failedreason($handle);

				$description = imagick_faileddescription($handle);
				// todo: Build in error handler in imagegallib
				exit;
			}
		} else if ($this->uselib == "gd") {
			if ($this->gdversion >= 2.0) {
				$t = imagecreatetruecolor($newx, $newy);

				imagecopyresampled($t, $this->imagehandle, 0, 0, 0, 0, $newx, $newy, $this->xsize, $this->ysize);
			} else {
				$t = imagecreate($newx, $newy);

				$this->ImageCopyResampleBicubic($t, $this->imagehandle, 0, 0, 0, 0, $newx, $newy, $this->xsize, $this->ysize);
			}

			$this->imagehandle = $t;
		}

		// fill $this->image for writing or output
		$this->writeimagetostring();
		// reget sizes
		$this->getimageinfo();
		//set new sizes
		$this->xsize = $newx;
		$this->ysize = $newy;
		return true;
	}

	// rescale Image, almost the same as resize, but keeps apect ratio
	// bbx and bby give the boundary box
	function rescaleImage($bbx, $bby) {
		if (!$bbx || !$bby)
			return true;
		if (!isset($this->imagehandle)) {
			$this->readimagefromstring();
		}
		if (!isset($this->xsize)) {
			$this->getimageinfo();
		}

		if ($this->xsize * $this->ysize == 0)
			$this->repairimageinfo();

		if ($this->xsize > $this->ysize) {
			$tscale = ((int)$this->xsize / $bbx);
		} else {
			$tscale = ((int)$this->ysize / $bby);
		}

		$newx = round($this->xsize / $tscale);
		$newy = round($this->ysize / $tscale);
		return $this->resizeImage($newx, $newy);
	}

	function rotateimage($angle) {
		if ($this->uselib == "imagick") {
			//Imagick and GD have different opinion what is 90 degree. right or left?
			imagick_rotate($this->imagehandle, -$angle);
		} else if ($this->uselib == "gd") {
			if ($this->gdversion > 2.0) { //I know, it's PHP <= 4.3.0. It destroys images if u try to rotate them
				$this->imagehandle = imagerotate($this->imagehandle, $angle, 0);
			}
		}

		// update the $this->image
		$this->writeimagetostring();
		//get new sizex,sizey
		$this->oldxsize = $this->xsize;
		$this->oldysize = $this->ysize;
		$this->getimageinfo();
	}

	// function to determine supported image types
	// imagick has no function to get the supported image types
	function issupported($imagetype) {
		if ($this->uselib == "imagick") {
			//imagick can read everything ... we assume
			return true;
		} else if ( $this->uselib == "gd" &&
		    $this->havegd == true )
		{
			switch (strtolower($imagetype)) {
			case 'jpeg':
			case 'pjpeg':
			case 'jpg':
			case 'image/jpeg':
			case 'image/pjpeg':
			case 'image/jpg':
				return ($this->gdinfo["JPG Support"]);

				break;

			case 'png':
			case 'image/png':
				return ($this->gdinfo["PNG Support"]);

				break;

			case 'gif':
			case 'image/gif':
				return ($this->gdinfo["GIF Create Support"]);

				break;

			case 'bmp':
			case 'image/bmp':
				return ($this->gdinfo["WBMP Support"]);

				break;

			case 'xbm':
			case 'image/xbm':
				return ($this->gdinfo["XBM Support"]);

				break;

			default:
				return false;

				break;
			}
		} else {
		    return false;
		}
	}

	// Batch image uploads todo
	function process_batch_image_upload($galleryId, $file, $user) {
		global $gal_match_regex;

		global $gal_nmatch_regex;
		global $gal_use_db;
		global $gal_use_dir;
		global $tmpDir;
		$numimages = 0;
		include_once ('lib/pclzip.lib.php');
		$archive = new PclZip($file);
		// Read Archive contents
		$ziplist = $archive->listContent();

		if (!$ziplist)
			return (false); // Archive invalid

		for ($i = 0; $i < sizeof($ziplist); $i++) {
			$file = $ziplist["$i"]["filename"];

			if (!$ziplist["$i"]["folder"]) {
				//copied
				$gal_info = $this->get_gallery($galleryId);

				$upl = 1;

				if (!empty($gal_match_regex)) {
					if (!preg_match("/$gal_match_regex/", $file, $reqs))
						$upl = 0;
				}

				if (!empty($gal_nmatch_regex)) {
					if (preg_match("/$gal_nmatch_regex/", $file, $reqs))
						$upl = 0;
				}
				//extract file
				$archive->extractByIndex($ziplist["$i"]["index"],
					$tmpDir, dirname($file)); //extract and remove (dangerous) pathname
				$file = basename($file);

				//unset variables
				unset ($this->filetype);
				unset ($this->xsize);
				unset ($this->ysize);

				//determine filetype and dimensions
				$this->getfileinfo($tmpDir . "/" . $file);
				
				$foo=explode(".",$file);
				$exp=end($foo);
				// read image and delete it after
				$this->readimagefromfile($tmpDir . "/" . $file);
				unlink ($tmpDir . "/" . $file);

				if ($this->issupported($exp)) {
					// convert to handle
					$this->readimagefromstring();

					if ($this->validhandle()) {
						$this->getimageinfo();
					}
				}

				//if there is no mimetype, we don't got a image
				if (isset($this->filetype)) {
					if (!isset($this->xsize)) {
						$this->xsize = $this->ysize = 0;
					}

					$imageId = $this->insert_image($galleryId, $file,
						'', $file, $this->filetype, $this->image, $this->filesize, $this->xsize, $this->ysize, $user, '', '');

					$numimages++;
				}
			}
		}

		return $numimages;
	}

	function add_image_hit($id) {
		global $count_admin_pvs;

		global $user;

		if ($count_admin_pvs == 'y' || $user != 'admin') {
			$query = "update `tiki_images` set `hits`=`hits`+1 where `imageId`=?";

			$result = $this->query($query,array((int)$id));
		}

		global $feature_score;
		if ($feature_score == 'y') {
		    $this->score_event($user, 'igallery_see_img', $id);
		    $query = "select `user` from `tiki_images` where `imageId`=?";
		    $owner = $this->getOne($query, array((int)$id));
		    $this->score_event($owner, 'igallery_img_seen', "$user:$id");
		}

		return true;
	}

	function add_gallery_hit($id) {
		global $count_admin_pvs;

		global $user;

		if ($count_admin_pvs == 'y' || $user != 'admin') {
			$query = "update `tiki_galleries` set `hits`=`hits`+1 where `galleryId`=?";

			$result = $this->query($query,array((int) $id));
		}

		global $feature_score;
		if ($feature_score == 'y') {
		    $this->score_event($user, 'igallery_see', $id);
		    $query = "select `user` from `tiki_galleries` where `galleryId`=?";
		    $owner = $this->getOne($query, array((int)$id));
		    $this->score_event($owner, 'igallery_seen', "$user:$id");
		}

		return true;
	}

	function ImageCopyResampleBicubic(&$dst_img, &$src_img, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h)
	// port to PHP by John Jensen July 10 2001 (updated 4/21/02) -- original code (in C, for the PHP GD Module) by jernberg@fairytale.se////
		{
		$palsize = ImageColorsTotal($src_img);

		for ($i = 0; $i < $palsize; $i++) { // get palette.
			$colors = ImageColorsForIndex($src_img, $i);

			ImageColorAllocate($dst_img, $colors['red'], $colors['green'], $colors['blue']);
		}

		$scaleX = ($src_w - 1) / $dst_w;
		$scaleY = ($src_h - 1) / $dst_h;
		$scaleX2 = (int)($scaleX / 2);
		$scaleY2 = (int)($scaleY / 2);

		for ($j = $src_y; $j < $dst_h; $j++) {
			$sY = (int)($j * $scaleY);

			$y13 = $sY + $scaleY2;

			for ($i = $src_x; $i < $dst_w; $i++) {
				$sX = (int)($i * $scaleX);

				$x34 = $sX + $scaleX2;
				$color1 = ImageColorsForIndex($src_img, ImageColorAt($src_img, $sX, $y13));
				$color2 = ImageColorsForIndex($src_img, ImageColorAt($src_img, $sX, $sY));
				$color3 = ImageColorsForIndex($src_img, ImageColorAt($src_img, $x34, $y13));
				$color4 = ImageColorsForIndex($src_img, ImageColorAt($src_img, $x34, $sY));
				$red = ($color1['red'] + $color2['red'] + $color3['red'] + $color4['red']) / 4;
				$green = ($color1['green'] + $color2['green'] + $color3['green'] + $color4['green']) / 4;
				$blue = ($color1['blue'] + $color2['blue'] + $color3['blue'] + $color4['blue']) / 4;
				ImageSetPixel($dst_img, $i + $dst_x - $src_x, $j + $dst_y - $src_y, ImageColorClosest($dst_img, $red, $green, $blue));
			}
		}
	}

	function store_image_data($overwrite = false) {
		global $gal_use_dir;

		global $gal_use_db;

		$size = strlen($this->image);
		$fhash = "";

		if ($gal_use_db == 'y') {
			// Prepare to store data in database
		} else {
			// Store data in directory
			switch ($this->type) {
			case 't':
				$ext = ".thumb";

				break;

			case 's':
				$ext = ".scaled_" . $this->xsize . "x" . $this->ysize;

				break;

			case 'b':
				// for future use
				$ext = ".backup";

				break;

			default:
				$ext = '';
			}

			$fhash = $this->path . $ext; //Path+extension
			@$fw = fopen($gal_use_dir . $fhash, "wb");

			if (!$fw) {
				return false;
			}

			fwrite($fw, $this->image);
			fclose ($fw);
			$data = '';
		}

		$this->filename = $this->xsize . "x" . $this->ysize . "_" . $this->name; // rebuild filename for downloading images
		// insert data
		$fn = $this->filename;

		if ($overwrite) {
			//overwrites all except the colums of the primary key
			//if there is no oldxsize, we use xsize
			if (!isset($this->oldxsize)) {
				$this->oldxsize = $this->xsize;

				$this->oldysize = $this->ysize;
			}

			$query = "update `tiki_images_data` set `filetype`=?,
				`filename`=?,`data`=?,
				`filesize`=? ,`xsize`=?, 
				`ysize`=?
			where
			`imageId`=? and `type`=? and
			`xsize`=? and `ysize`=?";
			 $bindvars=array($this->filetype,$this->filename,($gal_use_db == 'y')?$this->image:'',(int)$size,(int)$this->xsize,(int)$this->ysize,(int)$this->imageId,$this->type,(int)$this->oldxsize,(int)$this->oldysize);
		} else {
			$query = "insert into `tiki_images_data`(`imageId`,`xsize`,`ysize`,
                                `type`,`filesize`,`filetype`,`filename`,`data`)
                        values (?,?,?,?,?,?,?,?)";
			$bindvars=array((int)$this->imageId,(int)$this->xsize,(int)$this->ysize,$this->type,(int)$size,$this->filetype,$this->filename,($gal_use_db == 'y')?$this->image:'');
		}

		$result = $this->query($query,$bindvars);
		return true;
	}

	function rebuild_image($imageid, $itype, $xsize, $ysize=0) {
		$galid = $this->get_gallery_from_image($imageid);
		if($ysize==0) {
			$ysize=$xsize;
		}

		//we don't rebuild original images
		if ($itype == 'o')
			return false;

		//if it is a scaled image, test the gallery settings
		if ($itype == 's') {
			$scaleinfo = $this->get_gallery_scale_info($galid);

			$hasscale = false;

			while (list($num, $sci) = each($scaleinfo)) {
				if ((($sci['scale'] == $xsize) && ($sci['scale'] >= $ysize)) || 
				    (($sci['scale'] == $ysize) && ($sci['scale'] >= $xsize))) {
					$hasscale = true;

					$newx = $sci['scale'];
					$newy = $sci['scale'];
				}
			}

			if (!$hasscale)
				return false;
		}

		// now we can start rebuilding the image
		global $gal_use_dir;
		global $gal_use_db;
		//if(!function_exists("ImageCreateFromString")) return false;
		#get image and other infos
		$this->get_image($imageid);
		$galinfo = $this->get_gallery_info($galid);

		// determine new size
		if ($itype == 't') {
			$newx = $galinfo["thumbSizeX"];

			$newy = $galinfo["thumbSizeY"];
		}

		// do it
		if ($this->issupported($this->filetype)) {
			if (!$this->rescaleImage($newx, $newy)) {
				die;
			}
		} else {
			// filetype is not supported, but we store the data
			// assiming newx,newy as new size
			$this->xsize = $newx;

			$this->ysize = $newy;
		}

		// we always rescale to jpegs.
		$t_type = 'image/jpeg';

		// some more infos
		$filename = $this->filename; // filename of original image
		$this->type = $itype;

		//store
		$this->store_image_data();

		//return new size
		$newsize["xsize"] = $this->xsize;
		$newsize["ysize"] = $this->ysize;
		return $newsize;
	}

	function rebuild_thumbnails($galleryId) {
		global $gal_use_dir;

		global $gal_use_db;

		// rewritten by flo
		$query = "select `imageId`, `path` from `tiki_images` where `galleryId`=?";
		$result = $this->query($query,array((int)$galleryId));

		while ($res = $result->fetchRow()) {
			$query2 = "delete from `tiki_images_data` where `imageId`=? and `type`=?";

			$result2 = $this->query($query2,array((int)$res["imageId"],'t'));

			if (strlen($res["path"]) > 0) {
				$ftn = $gal_use_dir . $res["path"] . ".thumb";

				if (file_exists($ftn)) {
					unlink ($ftn);
				}
			}
		}

		return true;
	}

  function rebuild_scales($galleryId, $imageId = -1) {
    // doesn't really rebuild, it deletes the scales and thumbs for 
    // automatic rebuild
    // give either a galleryId for rebuild complete gallery or
    // a imageId for a image rebuild
    global $gal_use_dir;
    if ($imageId == -1) {
      //gallery mode
      //mysql does'nt have subqueries. Bad.
      $bindvars=array();
      $query1 = "select `imageId`,`path` from `tiki_images`";
      if($galleryId>-1) { // if galleryid == -1 then all galleries
        $query1 .= ' where `galleryId`=?';
        $bindvars=array((int)$galleryId);
      }

      $result1 = $this->query($query1,$bindvars);

      while ($res = $result1->fetchRow()) {
        $query2 = 'select `xsize`,`ysize`,`type` from `tiki_images_data` where `imageId`=? and not (`type`=?)';
        $query3 = "delete from `tiki_images_data` where `imageId`=? and not (`type`=?)";
        $bindvars2=array((int)$res["imageId"],'o');

        $result2 = $this->query($query2,$bindvars2);
        while($res2=$result2->fetchRow()) {
          if(!empty($res['path'])) {
            if($res2['type']=='s') { $ext = ".scaled_" . $res2['xsize'] . "x" . $res2['ysize'];}
            if($res2['type']=='t') { $ext = ".thumb";}
            if($res2['type']=='s' || $res2['type']=='t') { // in case we add other types later
              @unlink($gal_use_dir.$res['path'].$ext );
            }
          }
        }
        // delete images_data entries
        $result3 = $this->query($query3,$bindvars2);
      }
    } else {
      //image mode
      $query = "delete from `tiki_images_data` where `ImageId`=? and not `type`=?";

      $result = $this->query($query,array((int)$ImageId,'o'));
    }
  }

	function edit_image($id, $name, $description,$lat=NULL,$lon=NULL) {
		$name = strip_tags($name);

		$description = strip_tags($description);
		$query = "update `tiki_images` set `name`=?, `description`=?, `lat`=?, `lon`=? where `imageId` = ?";
		$result = $this->query($query,array($name,$description,$lat,$lon,(int)$id));
		return true;
	}

	function insert_image($galleryId, $name, $description, $filename, $filetype, &$data, $size, $xsize, $ysize, $user, $t_data, $t_type ,$lat=NULL, $lon=NULL) {
		global $gal_use_db;

		global $gal_use_dir;
		$name = strip_tags($name);
		$description = strip_tags($description);
		if ($t_data && is_string($t_data)) {
			$t_data = array('data' => $t_data, 'xsize' => 0, 'ysize' => 0);
		}
		$now = date("U");
		$path = '';

		if ($gal_use_db == 'y') {
			// Prepare to store data in database
		} else {
			// Store data in directory
			$fhash = md5(uniqid($filename));

			@$fw = fopen($gal_use_dir . $fhash, "wb");

			if (!$fw) {
				return false;
			}

			fwrite($fw, $data);
			fclose ($fw);

			if ($t_data) {
				@$fw = fopen($gal_use_dir . $fhash . '.thumb', "wb");

				if (!$fw) {
					return false;
				}

				fwrite($fw, $t_data['data']);
				fclose ($fw);
				$t_data = '';
			}

			$data = '';
			$path = $fhash;
		}

		$query = "insert into `tiki_images`(`galleryId`,`name`,`description`,`user`,`created`,`hits`,`path`,`lat`,`lon`)
                          values(?,?,?,?,?,?,?,?,?)";
		$result = $this->query($query,array((int)$galleryId,$name,$description,$user,(int)$now,0,$path,$lat,$lon));
		$query = "select max(`imageId`) from `tiki_images` where `created`=?";
		$imageId = $this->getOne($query,array((int)$now));
		// insert data
		$this->blob_encode($data);
		$query = "insert into `tiki_images_data`(`imageId`,`xsize`,`ysize`,
                                `type`,`filesize`,`filetype`,`filename`,`data`)
                        values (?,?,?,?,?,?,?,?)";
		$result = $this->query($query,array((int)$imageId,(int)$xsize,(int)$ysize,'o',(int)$size,$filetype,$filename,$data));

		// insert thumb
		if ($t_data) {
			$this->blob_encode($t_data['data']);
			$query = "insert into `tiki_images_data`(`imageId`,`xsize`,`ysize`,
                                `type`,`filesize`,`filetype`,`filename`,`data`)
                        values (?,?,?,?,?,?,?,?)";

			$result = $this->query($query,array((int)$imageId,(int)$t_data['xsize'],(int)$t_data['ysize'],'t',(int)$size,$t_type,$filename,$t_data['data']));
		}

		$query = "update `tiki_galleries` set `lastModif`=? where `galleryId`=?";
		$result = $this->query($query,array((int)$now,(int)$galleryId));

		global $feature_score;
		if ($feature_score == 'y') {
		    $this->score_event($user, 'igallery_new_img');
		}

		return $imageId;
	}

	function rotate_image($id, $angle) {
		//get image
		global $gal_use_dir;

		global $gal_use_db;
		$this->get_image($id);

		$this->rotateimage($angle);
		$this->store_image_data(true);
		// delete all scaled images. Will be rebuild when requested
		$query = "delete from `tiki_images_data` where `imageId`=? and `type` !=?";
		$result = $this->query($query,array((int)$id,'o'));
	}

	function rotate_right_image($id) {
		$this->rotate_image($id, 270);
	}

	function rotate_left_image($id) {
		$this->rotate_image($id, 90);
	}

	function remove_image($id) {
		global $gal_use_dir;

		$path = $this->getOne("select `path` from `tiki_images` where `imageId`=?",array($id));

		if ($path) {
			@unlink ($gal_use_dir . $path);

			@unlink ($gal_use_dir . $path . '.thumb');
		  // remove scaled images
		  $query = "select i.`path`, d.`xsize`, d.`ysize` from `tiki_images` i, `tiki_images_data` d where i.`imageId`=d.`imageId` and i.`imageId`=? and d.`type`=?";
		  $result=$this->query($query,array($id,'s'));
		  while($res = $result->fetchRow()) {
                    @unlink ($gal_use_dir . $path . '.scaled_'.$res['xsize'].'x'.$res['ysize']);
		  }
		}

		$query = "delete from `tiki_images` where `imageId`=?";
		$result = $this->query($query,array((int)$id));
		$query = "delete from `tiki_images_data` where `imageId`=?";
		$result = $this->query($query,array((int)$id));
		$this->remove_object('image', $id);
		return true;
	}

	function get_images($offset, $maxRecords, $sort_mode, $find, $galleryId = -1) {

		if ($find) {
			$findesc = '%' . $find . '%';

			$mid = " and (`name` like ? or `description` like ?)";
			$bindvars=array('o',$findesc,$findesc);
		} else {
			$mid = "";
			$bindvars=array('o');
		}

		$midcant = "";
		$cantvars=array();
		if ($galleryId != -1 && is_numeric($galleryId)) {
			$mid .= " and i.`galleryId`=? ";
			$bindvars[]=(int) $galleryId;
			$midcant = "where `galleryId`=? ";
			$cantvars[]=(int) $galleryId;
		} else if ($galleryId == -1) {//don't show system gallery
			$mid .= 'and i.`galleryId`!=? ';
			$bindvars[] = 0;
		}

		$query = "select i.`path` ,i.`imageId`,i.`name`,i.`description`,i.`created`,
                d.`filename`,d.`filesize`,d.`xsize`,d.`ysize`,
                i.`user`,i.`hits`
                from `tiki_images` i , `tiki_images_data` d
                 where i.`imageId`=d.`imageId`
                 and d.`type`=?
                $mid
                order by ".$this->convert_sortmode($sort_mode);
		$result = $this->query($query,$bindvars,$maxRecords,$offset);
		$ret = array();

		while ($res = $result->fetchRow()) {
			$ret[] = $res;
		}

		$retval = array();
		$retval["data"] = $ret;
		$query_cant = "select count(*) from `tiki_images` $midcant";
		$cant = $this->getOne($query_cant,$cantvars);
		$retval["cant"] = $cant;
		return $retval;
	}

        function get_subgalleries($offset, $maxRecords, $sort_mode, $find, $galleryId = -1) {
		
		if ($sort_mode == '')
			$sort_mode = 'name_asc';
		else		//filesize is for listing images. equivalent is numimages
			$sort_mode=preg_replace('/(filesize_)/','numimages_',$sort_mode);

                if ($find) {
                        $findesc = '%' . $find . '%';

                        $mid = " and (`name` like ? or `description` like ?)";
                        $bindvars=array($galleryId,$findesc,$findesc);
                } else {
                        $mid = "";
                        $bindvars=array($galleryId);
                }

                $query = "select g.`galleryId`,g.`name`,g.`description`,
	       		g.`created`,g.`lastModif`,g.`visible`,g.`theme`,g.`user`,
       			g.`hits`,g.`maxRows`,g.`rowImages`,g.`thumbSizeX`,
	 		g.`thumbSizeY`,g.`public`,g.`sortorder`,g.`sortdirection`,
			g.`galleryimage`,g.`parentgallery`,count(i.`imageId`) as numimages
			from `tiki_galleries` g, `tiki_images` i
			where i.`galleryId`=g.`galleryId` and
                 	`parentgallery`=? $mid group by 
			g.`galleryId`, g.`name`,g.`description`,
			g.`created`,g.`lastModif`,g.`visible`,g.`theme`,g.`user`,
			g.`hits`,g.`maxRows`,g.`rowImages`,g.`thumbSizeX`,
			g.`thumbSizeY`,g.`public`,g.`sortorder`,g.`sortdirection`,
			g.`galleryimage`,g.`parentgallery`
                order by ".$this->convert_sortmode($sort_mode);
                $result = $this->query($query,$bindvars,$maxRecords,$offset);
                $ret = array();

                while ($res = $result->fetchRow()) {
			// get the number of the gallery representation image
			$res['imageId']=$this->get_gallery_image($res['galleryId'],$res['galleryimage']);
                        $ret[] = $res;
                }

                $retval = array();
                $retval["data"] = $ret;
                $query_cant = "select count(*) from `tiki_galleries` where `parentgallery`=? $mid";
                $cant = $this->getOne($query_cant,$bindvars);
                $retval["cant"] = $cant;
                return $retval;
        }


	function get_gallery_image($galleryId,$rule='',$sort_mode = '') {
		$query='select `imageId` from `tiki_images` where `galleryId`=? order by ';
		$bindvars=array($galleryId);
		switch($rule) {
			case 'firstu':
				// first uploaded
				$query.=$this->convert_sortmode('created_asc');
				$imageId=$this->getOne($query,$bindvars);
				break;
			case 'lastu':
				// last uploaded
				$query.=$this->convert_sortmode('created_desc');
				$imageId=$this->getOne($query,$bindvars);
				break;
			case 'all':
			case 'first':
			    if (!$sort_mode) {
    				// first image in default gallery sortorder
    				$query2='select `sortorder`,`sortdirection` from `tiki_galleries` where `galleryId`=?';
    				$result=$this->query($query2,$bindvars);
    				$res = $result->fetchRow();
    				$sort_mode=$res['sortorder'].'_'.$res['sortdirection'];
				}
				$query.=$this->convert_sortmode($sort_mode);
				if ($rule != 'all') {
    				$imageId=$this->getOne($query,$bindvars);
    				break;
				}
				$result=$this->query($query,$bindvars);
				$imageId=array();
    			while ($res = $result->fetchRow()) {
    				$imageId[]=reset($res);
    			}
				break;
			case 'last':
			    if ($sort_mode) {
			        $invsor = explode('_', $sort_mode);
			        $sort_mode = $invsor[0] . '_' . ($invsor[1] == 'asc' ? 'desc' : 'asc');
			    } else {
    				// last image in default gallery sortorder
    				$query2='select `sortorder`,`sortdirection` from `tiki_galleries` where `galleryId`=?';
    				$result=$this->query($query2,$bindvars);
    				$res = $result->fetchRow();
    				if($res['sortdirection'] == 'asc') {
    					$res['sortdirection']='desc';
    				} else {
    					$res['sortdirection']='asc';
    				}
    				$sort_mode=$res['sortorder'].'_'.$res['sortdirection'];
				}
				$query.=$this->convert_sortmode($sort_mode);
				$imageId=$this->getOne($query,$bindvars);
				break;
			case 'random':
				//random image of gallery
				$ret=$this->get_random_image($galleryId);
				$imageId=$ret['imageId'];
				break;
			case 'default':
				//check gallery settings and re-run this function
				$query='select `galleryimage` from `tiki_galleries` where `galleryId`=?';
				$rule=$this->getOne($query,array($galleryId));
				$imageId=$this->get_gallery_image($galleryId,$rule);
				break;
			default:
				// imageId is listed in gallery settings
				if (is_numeric($rule)) {
					$imageId=(int) $rule;
				} else {
					// unknown.
					$imageId=-1;
				}
				break;
			}
			return($imageId);
	}

	function get_first_image($sort_mode, $find, $galleryId = -1) {

		if ($find) {
			$findesc = '%' . $find . '%';

			$mid = " and (`name` like ? or `description` like ?)";
			$bindvars=array('o',$findesc,$findesc);
		} else {
			$mid = "";
			$bindvars=array('o');
		}

		$midcant = "";
		$cantvars=array();

		if ($galleryId != -1 && is_numeric($galleryId)) {
			$mid .= " and i.`galleryId`=? ";
			$bindvars[]=(int)$galleryId;
			$midcant = "where `galleryId`=? ";
			$cantvars[]=(int)$galleryId;
		}

		$query = "select i.`imageId`
                from `tiki_images` i , `tiki_images_data` d
                 where i.`imageId`=d.`imageId`
                 and d.`type`=?
                $mid
                order by ".$this->convert_sortmode($sort_mode);
		$result = $this->query($query,$bindvars,1,0);
		$res = $result->fetchRow();
		return $res['imageId'];
	}

	function get_last_image($sort_mode, $find, $galleryId = -1) {
		if (strstr($sort_mode, 'asc')) {
			$sort_mode = str_replace('asc', 'desc', $sort_mode);
		} else {
			$sort_mode = str_replace('desc', 'asc', $sort_mode);
		}

		if ($find) {
			$findesc = '%' . $find . '%';

			$mid = " and (`name` like ? or `description` like ?)";
			$bindvars=array('o',$findesc,$findesc);
		} else {
			$mid = "";
			$bindvars=array('o');
		}

		$midcant = "";
		$cantvars=array();

		if ($galleryId != -1 && is_numeric($galleryId)) {
                        $mid .= " and i.`galleryId`=? ";
                        $bindvars[]=(int)$galleryId;
                        $midcant = "where `galleryId`=? ";
                        $cantvars[]=(int)$galleryId;
		}

		$query = "select i.`imageId`
                from `tiki_images` i , `tiki_images_data` d
                 where i.`imageId`=d.`imageId`
                 and d.`type`=?
                $mid
                order by ".$this->convert_sortmode($sort_mode);
		$result = $this->query($query,$bindvars,1,0);
		$res = $result->fetchRow();
		return $res['imageId'];
	}

	function list_images($offset, $maxRecords, $sort_mode, $find, $galleryId = -1) {
		return $this->get_images($offset, $maxRecords, $sort_mode, $find, $galleryId);
	}

    function get_random_image($galleryId = -1) {
	$whgal = "";
	$bindvars = array();
	if (((int)$galleryId) != -1) {
	    $whgal = " where `galleryId`=? ";
	    $bindvars[] = (int) $galleryId;
	}

	$query = "select count(*) from `tiki_images` $whgal";
	$cant = $this->getOne($query,$bindvars);
	$ret = array();

	if ($cant) {
	    $pick = rand(0, $cant - 1);

	    $query = "select `imageId` ,`galleryId`,`name` from `tiki_images` $whgal";
	    $result = $this->query($query,$bindvars,1,$pick);
	    $res = $result->fetchRow();
	    $ret["galleryId"] = $res["galleryId"];
	    $ret["imageId"] = $res["imageId"];
	    $ret["name"] = $res["name"];
	    $query = "select `name`  from `tiki_galleries` where `galleryId` = ?";
	    $ret["gallery"] = $this->getOne($query,array((int)$res["galleryId"]));
	} else {
	    $ret["galleryId"] = 0;

	    $ret["imageId"] = 0;
	    $ret["name"] = tra("No image yet, sorry.");
	}

	return ($ret);
    }

	function list_galleries($offset = 0, $maxRecords = -1, $sort_mode = 'name_desc', $user, $find=false) {
	    // If $user is admin then get ALL galleries, if not only user galleries are shown
	    global $tiki_p_admin_galleries;

	    $old_sort_mode = '';

	    if (in_array($sort_mode, array(
			    'images_desc',
			    'images_asc'
			    ))) {
		$old_offset = $offset;

		$old_maxRecords = $maxRecords;
		$old_sort_mode = $sort_mode;
		$sort_mode = 'name_desc';
		$offset = 0;
		$maxRecords = -1;
	    }

	    // If the user is not admin then select `it` 's own galleries or public galleries
	    if (($tiki_p_admin_galleries == 'y') or ($user == 'admin')) {
		$whuser = "";
		$bindvars=array();
	    } else {
		$whuser = "where g.`user`=? or g.public=?";
		$bindvars=array($user,'y');
	    }

	    if ($find) {
		$findesc = '%' . $find . '%';

		if (empty($whuser)) {
		    $whuser = "where g.`name` like ? or g.`description` like ?";
		    $bindvars=array($findesc,$findesc);
		} else {
		    $whuser .= " and g.`name` like ? or g.`description` like ?";
		    $bindvars[]=$findesc;
		    $bindvars[]=$findesc;
		}
	    }

	    // If sort mode is versions then offset is 0, maxRecords is -1 (again) and sort_mode is nil
	    // If sort mode is links then offset is 0, maxRecords is -1 (again) and sort_mode is nil
	    // If sort mode is backlinks then offset is 0, maxRecords is -1 (again) and sort_mode is nil
	    $query = "select g.*, a.`name` as parentgalleryName from `tiki_galleries` g left join `tiki_galleries` a on g.`parentgallery` = a.`galleryId` $whuser order by ".$this->convert_sortmode($sort_mode);
	    $query_cant = "select count(*) from `tiki_galleries` g $whuser";
	    $result = $this->query($query,$bindvars,$maxRecords,$offset);
	    $cant = $this->getOne($query_cant,$bindvars);
	    $ret = array();

	    while ($res = $result->fetchRow()) {

		$add = TRUE;
		global $feature_categories;
		global $userlib;
		global $user;
		global $tiki_p_admin;

		if ($tiki_p_admin != 'y' && $userlib->object_has_one_permission($res['galleryId'], 'image gallery')) {
		    // gallery permissions override category permissions
		    if (!$userlib->object_has_permission($user, $res['galleryId'], 'image gallery', 'tiki_p_view_image_gallery')) {
			$add = FALSE;
		    }
		} elseif ($tiki_p_admin != 'y' && $feature_categories == 'y') {
		    // no forum permissions so now we check category permissions
		    global $categlib;
		    if (!is_object($categlib)) {
			include_once('lib/categories/categlib.php');
		    }
		    unset($tiki_p_view_categories); // unset this var in case it was set previously
		    $perms_array = $categlib->get_object_categories_perms($user, 'image gallery', $res['galleryId']);
		    if ($perms_array) {
			$is_categorized = TRUE;
			foreach ($perms_array as $perm => $value) {
			    $$perm = $value;
			}
		    } else {
			$is_categorized = FALSE;
		    }

		    if ($is_categorized && isset($tiki_p_view_categories) && $tiki_p_view_categories != 'y') {
			$add = FALSE;
		    }
		}

		if ($add) {
		    $res['images'] = $this->getOne("select count(*) from `tiki_images` where `galleryId`=?",array($res['galleryId']));
		    $ret[] = $res;
		}
	    }

	    if ($old_sort_mode == 'images_asc') {
		usort($ret, 'compare_images');
	    }

	    if ($old_sort_mode == 'images_desc') {
		usort($ret, 'r_compare_images');
	    }

	    if (in_array($old_sort_mode, array(
			    'images_desc',
			    'images_asc'
			    ))) {
		$ret = array_slice($ret, $old_offset, $old_maxRecords);
	    }

	    $retval = array();
	    $retval["data"] = $ret;
	    $retval["cant"] = $cant;
	    return $retval;
	}

	function list_visible_galleries($offset = 0, $maxRecords = -1, $sort_mode = 'name_desc', $user, $find) {
	    global $tiki_p_admin_galleries, $tikilib;
	    // If $user is admin then get ALL galleries, if not only user galleries are shown

	    $old_sort_mode = '';

	    if (in_array($sort_mode, array(
			    'images desc',
			    'images asc'
			    ))) {
		$old_offset = $offset;

		$old_maxRecords = $maxRecords;
		$old_sort_mode = $sort_mode;
		$sort_mode = 'user desc';
		$offset = 0;
		$maxRecords = -1;
	    }

	    // If the user is not admin then select `it` 's own galleries or public galleries
	    if (($user != 'admin') and ($tiki_p_admin_galleries != 'y')) {
		$whuser = "and `user`=? or `public`=?";
		$bindvars=array('y',$user,'y');
	    } else {
		$whuser = "";
		$bindvars=array('y');
	    }

	    if ($find) {
		$findesc = '%' . $find . '%';

		if (empty($whuser)) {
		    $whuser = " and (`name` like ? or `description` like ?)";
		    $bindvars=array('y',$findesc,$findesc);
		} else {
		    $whuser .= " and (`name` like ? or `description` like ?)";
		    $bindvars[]=$findesc;
		    $bindvars[]=$findesc;
		}
	    }

	    // If sort mode is versions then offset is 0, maxRecords is -1 (again) and sort_mode is nil
	    // If sort mode is links then offset is 0, maxRecords is -1 (again) and sort_mode is nil
	    // If sort mode is backlinks then offset is 0, maxRecords is -1 (again) and sort_mode is nil
	    $query = "select * from `tiki_galleries` where `visible`=? $whuser order by ".$this->convert_sortmode($sort_mode);
	    $query_cant = "select count(*) from `tiki_galleries` where `visible`=? $whuser";
	    $result = $this->query($query,$bindvars,$maxRecords,$offset);
	    $cant = $this->getOne($query_cant,$bindvars);
	    $ret = array();

	    while ($res = $result->fetchRow()) {
		if (!$tikilib->user_has_perm_on_object($user, $res['galleryId'], 'image gallery', 'tiki_p_view_image_gallery')) {
			continue;
		}
		$aux = array();

		$aux["name"] = $res["name"];
		$gid = $res["galleryId"];
		$aux["visible"] = $res["visible"];
		$aux["id"] = $gid;
		$aux["galleryId"] = $res["galleryId"];
		$aux["description"] = $res["description"];
		$aux["created"] = $res["created"];
		$aux["lastModif"] = $res["lastModif"];
		$aux["user"] = $res["user"];
		$aux["hits"] = $res["hits"];
		$aux["public"] = $res["public"];
		$aux["theme"] = $res["theme"];
		$aux["geographic"] = $res["geographic"];
		$aux["images"] = $this->getOne("select count(*) from `tiki_images` where `galleryId`=?",array($gid));
		$ret[] = $aux;
	    }

	    if ($old_sort_mode == 'images asc') {
		usort($ret, 'compare_images');
	    }

	    if ($old_sort_mode == 'images desc') {
		usort($ret, 'r_compare_images');
	    }

	    if (in_array($old_sort_mode, array(
			    'images desc',
			    'images asc'
			    ))) {
		$ret = array_slice($ret, $old_offset, $old_maxRecords);
	    }

	    $retval = array();
	    $retval["data"] = $ret;
	    $retval["cant"] = $cant;
	    return $retval;
	}

    function get_gallery($id) {
	$query = "select * from `tiki_galleries` where `galleryId`=?";
	$result = $this->query($query,array((int) $id));
	$res = $result->fetchRow();
	return $res;
    }

	function get_gallery_owner($galleryId) {
		$query = "select `user` from `tiki_galleries` where `galleryId`=?";

		$user = $this->getOne($query,array((int)$galleryId));
		return $user;
	}

	function get_gallery_from_image($imageid) {
		$query = "select `galleryId` from `tiki_images` where `imageId`=?";

		$galid = $this->getOne($query,array((int)$imageid));
		return $galid;
	}

	function move_image($imgId, $galId) {
		$query = "update `tiki_images` set `galleryId`=? where `imageId`=?";

		$result = $this->query($query,array((int)$galId,(int)$imgId));
		return true;
	}

	function get_image_info($id, $itype = 'o', $xsize = 0, $ysize = 0) {
		// code may be merged with get_image
		$mid = "";

		if ($xsize != 0 && $ysize == 0) {
			// bounding box
			$ysize=$xsize;
		} 

		if ($xsize != 0 && $ysize != 0) {
			$bindvars=array((int)$id,$itype,(int)$xsize,(int)$ysize);
			if($xsize == $ysize) {
				// we don't know yet.
				$mid = "and (d.`xsize` = ? or d.`ysize` = ?) order by `xysize` desc";
			} else {
				$mid = 'and d.`xsize` = ? and d.`ysize` = ?';
			}
		}
		
		if(!@is_array($bindvars)) {
			$bindvars=array((int)$id,$itype);
		}

		$query = "select i.`imageId`, i.`galleryId`, i.`name`,
                     i.`description`, i.`created`, i.`user`,
                     i.`hits`, i.`path`, i.`lat`, i.`lon`,
                     d.`xsize`,d.`ysize`,d.`type`,d.`filesize`,
                     d.`filetype`,d.`filename`,d.`xsize` * d.`ysize` as `xysize`
                 from `tiki_images` i, `tiki_images_data` d where
                     i.`imageId`=? and d.`imageId`=i.`imageId`
                     and d.`type`=?
                     $mid";
		$result = $this->query($query,$bindvars,1);
		$res = $result->fetchRow();
		return $res;
	}

	// Add an option to establish Image size (x,y)
	function get_image($id, $itype = 'o', $xsize = 0, $ysize = 0) {
		global $gal_use_db;

		global $gal_use_dir;
		$mid = "";

		if ($itype == 't') {
			$galid = $this->get_gallery_from_image($id);

			$galinfo = $this->get_gallery_info($galid);
			$xsize = $galinfo["thumbSizeX"];
			$ysize = $galinfo["thumbSizeY"];
		}

		if ($xsize != 0 && $ysize == 0) {
			// first parameter (xsize) represents a scale
			// so we select a bounding box
			$ysize=$xsize;
		} 

		if ($xsize != 0 && $ysize != 0) {
			if ($ysize == $xsize) {
				// we don't know yet.
				$mid = "and (d.`xsize`=? or d.`ysize`=?) order by `xysize` desc ";
				$bindvars=array((int)$id,$itype,(int)$xsize,(int)$ysize);
			} else {
				//exact match
				$mid = "and d.`xsize`=? and d.`ysize`=? ";
				$bindvars=array((int)$id,$itype,(int)$xsize,(int)$ysize);
			}
		}

		
		
		if(!@is_array($bindvars)) {
			$bindvars=array((int)$id,$itype);
		}

		$query = "select i.`imageId`, i.`galleryId`, i.`name`,
                     i.`description`, i.`created`, i.`user`,
                     i.`hits`, i.`path`,i.`lat`, i.`lon`,
                     d.`xsize`,d.`ysize`,d.`type`,d.`filesize`,
                     d.`filetype`,d.`filename`,d.`data`,
		     d.`xsize` * d.`ysize` as `xysize`, d.`etag`
                 from `tiki_images` i, `tiki_images_data` d where
                     i.`imageId`=? and d.`imageId`=i.`imageId`
                     and d.`type`=?
                     $mid";


		$result = $this->query($query,$bindvars,1);
		
		if ($result===false || $result===null) {
			die;
		}
		
		$res = $result->fetchRow();		

		$this->imageId = $res["imageId"];
		$this->galleryId = $res["galleryId"];
		$this->name = $res["name"];
		$this->description = $res["description"];
		$this->lat = $res["lat"];
		$this->lon = $res["lon"];
		$this->created = $res["created"];
		$this->user = $res["user"];
		$this->hits = $res["hits"];
		$this->path = $res["path"];
		$this->xsize = $res["xsize"];
		$this->ysize = $res["ysize"];
		$this->type = $res["type"];
		$this->filesize = $res["filesize"];
		$this->filetype = $res["filetype"];
		$this->filename = $res["filename"];
		$this->etag= $res["etag"];

		# build scaled images or thumb if not available
		if ($itype != 'o' && !isset($this->imageId)) {
			if ($newsize = $this->rebuild_image($id, $itype, $xsize, $ysize)) {
				return $this->get_image($id, $itype, $newsize["xsize"], $newsize["ysize"]);
			}
		}

		// get image data from fs
		if (strlen($res["data"]) < 3) { // this is needed by postgres, because it inserts '' in the data field
			switch ($itype) {
			case 't':
				$ext = ".thumb";

				break;

			case 's':
				$ext = ".scaled_" . $res["xsize"] . "x" . $res["ysize"];

				break;

			case 'b':
				// for future use
				$ext = ".backup";

				break;

			default:
				$ext = '';
			}

			// If the image was a .gif then the thumbnail has 0 bytes if the thumbnail
			// is empty then use the full image as thumbnail
			//  if($ext==".thumb" && filesize($gal_use_dir.$res["path"].$ext)==0 ) {
			//   $ext='';
			//}
			$this->readimagefromfile($gal_use_dir . $res["path"] . $ext);
		} else {
			$this->image = $res["data"];
		}

		if (!isset($this->imagehandle))
			$this->readimagefromstring();

		// etag checks
		if($this->etag=='') {
		   $this->add_etag();
		}

		return $res;
	}

   function add_etag() {
      // stores md5 based etag in the tables
      // this function assumes that the $this->imageId and other
      // are loaded before (through $this->get_image() or similar)
      if(isset($this->image)) {//avoid broken images through warning
        $etag=md5($this->image);
        $query='update `tiki_images_data` set `etag`=? where `imageId`=? and `xsize`=? and `ysize`=? and `type`=?';
        $bindvars=array($etag,(int) $this->imageId,(int) $this->xsize,(int) $this->ysize,$this->type);
        $this->query($query,$bindvars);
      }

   }

   function get_etag($id, $itype = 'o', $xsize = 0, $ysize = 0) {
      // used to get the etag of a image. This function can be called
      // before we load the image into memory to check if the browser
      // has the image cached.
       $mid = "";

       if ($itype == 't') {
	       $galid = $this->get_gallery_from_image($id);

	       $galinfo = $this->get_gallery_info($galid);
	       $xsize = $galinfo["thumbSizeX"];
	       $ysize = $galinfo["thumbSizeY"];
       }

       if ($xsize != 0 && $ysize == 0) {
	       // first parameter (xsize) represents a scale
	       // so we select a bounding box
	       $ysize=$xsize;
       }

       if ($xsize != 0 && $ysize != 0) {
	       if ($ysize == $xsize) {
		       // we don't know yet.
		       $mid = "and (d.`xsize`=? or d.`ysize`=?) order by `xysize` desc ";
		       $bindvars=array((int)$id,$itype,(int)$xsize,(int)$ysize);
	       } else {
		       //exact match
		       $mid = "and d.`xsize`=? and d.`ysize`=? ";
		       $bindvars=array((int)$id,$itype,(int)$xsize,(int)$ysize);
	       }
       }

       if(!@is_array($bindvars)) {
	       $bindvars=array((int)$id,$itype);
       }

       $query = "select d.`xsize` * d.`ysize` as `xysize`, d.`etag`
	from `tiki_images_data` d where d.`imageId`=? and d.`type`=?
	    $mid";

       $result = $this->query($query,$bindvars,1);

       if ($result===false || $result===null) {
	       return(false);
       }

       $res = $result->fetchRow();
       $this->etag=$res["etag"];

       return($res["etag"]);
    }


   function get_imageid_byname($name) {
	
		$bindvars=array($name);

		$query = "select `imageId` from `tiki_images` 
						where `name` like ?";

		$result = $this->query($query,$bindvars,1);
		$res = $result->fetchRow(); 
		
		return($res["imageId"]);
			  
   }

	function get_image_thumb($id) {
		return $this->get_image($id, 't');
	}

	function replace_gallery($galleryId, $name, $description, $theme, $user, $maxRows, $rowImages, $thumbSizeX, $thumbSizeY, $public, $visible = 'y', $sortorder='created', $sortdirection='desc', $galleryimage='first',$parentgallery=-1,$showname='y',$showimageid='n',$showdescription='n',$showcreated='n',$showuser='n',$showhits='y',$showxysize='y',$showfilesize='n',$showfilename='n',$defaultscale='o',$geographic	= 'n') {
		// if the user is admin or the user is the same user and the gallery exists then replace if not then
		// create the gallary if the name is unused.
		$name = strip_tags($name);

		$description = strip_tags($description);
		$now = date("U");

		// check if the gallery already exists. if yes: do update, if no: update it
		if ($galleryId<1)
		$galleryId = $this->getOne("select `galleryId` from `tiki_galleries` where `name`=? and `parentgallery`=?",array($name,$parentgallery));

		if ($galleryId > 0) {
			//$res = $result->fetchRow();
			//if( ($user == 'admin') || ($res["user"]==$user) ) {
			$query = "update `tiki_galleries` set `name`=?,`visible`=?, `geographic`=?,`maxRows`=? , `rowImages`=?, 
                `thumbSizeX`=?, `thumbSizeY`=?, `description`=?, `theme`=?,
                `lastModif`=?, `public`=?, `sortorder`=?, `sortdirection`=?, `galleryimage`=?,
		`parentgallery`=?,`showname`=?,`showimageid`=?,`showdescription`=?,
		`showcreated`=?,`showuser`=?,`showhits`=?,`showxysize`=?,`showfilesize`=?,
		`showfilename`=?,`defaultscale`=?, `user`=?
	       	where `galleryId`=?";

			$result = $this->query($query,array($name,$visible,$geographic,(int)$maxRows,(int)$rowImages,(int)$thumbSizeX,(int)$thumbSizeY,$description,$theme,(int)$now,$public,$sortorder,$sortdirection,$galleryimage,(int)$parentgallery,$showname,$showimageid,$showdescription,$showcreated,$showuser,$showhits,$showxysize,$showfilesize,$showfilename,$defaultscale,$user,(int)$galleryId));
		} else {
			// Create a new record
			$query = "insert into `tiki_galleries`(`name`,`description`,`theme`,`created`,`user`,`lastModif`,`maxRows`,`rowImages`,`thumbSizeX`,`thumbSizeY`,`public`,`hits`,`visible`,`sortorder`,`sortdirection`,`galleryimage`,`parentgallery`,`showname`,`showimageid`,`showdescription`,`showcreated`,`showuser`,`showhits`,`showxysize`,`showfilesize`,`showfilename`,`defaultscale`,`geographic`) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
			$bindvars=array($name,$description,$theme,(int) $now,$user,(int) $now,(int) $maxRows,(int) $rowImages,(int) $thumbSizeX,(int) $thumbSizeY,$public,0,$visible,$sortorder,$sortdirection,$galleryimage,(int)$parentgallery,$showname,$showimageid,$showdescription,$showcreated,$showuser,$showhits,$showxysize,$showfilesize,$showfilename,$defaultscale,$geographic);
			$result = $this->query($query,$bindvars);
			$galleryId = $this->getOne("select max(`galleryId`) from `tiki_galleries` where `name`=? and `created`=?",array($name,(int) $now));

			global $feature_score;
			if ($feature_score == 'y') {
			    $this->score_event($user, 'igallery_new');
			}
		}

		return $galleryId;
	}

	function add_gallery_scale($galleryId, $scale) {
		$query = "insert into `tiki_galleries_scales`(`galleryId`,`scale`)
            values(?,?)";

		$result = $this->query($query,array((int)$galleryId,(int)$scale));
	}

	function remove_gallery_scale($galleryId, $scale= 0) {
                $mid = "";
                $bindvars=array((int) $galleryId);
                if ($scale != 0) {
                        $mid = " and `scale`=? ";
                        $bindvars[]=(int) $scale;
                }
                $query = "delete from `tiki_galleries_scales` where
            `galleryId`=? $mid";
                $result = $this->query($query,$bindvars);
        }

	function remove_gallery($id) {
		global $gal_use_dir;

		$query = "select `imageId`,path from `tiki_images` where `galleryId`=?";
		$result = $this->query($query,array((int) $id));

		while ($res = $result->fetchRow()) {
			$path = $res["path"];

			$query2 = "select `xsize`,`ysize`,`type` from `tiki_images_data` where `imageId`=?";
			$result2 = $this->query($query2,array((int)$res["imageId"]));

			while ($res2 = $result2->fetchRow()) {
				switch ($res2["type"]) {
				case 't':
					$ext = ".thumb";

					break;

				case 's':
					$ext = ".scaled_" . $res2["xsize"] . "x" . $res2["ysize"];

					break;

				case 'b':
					// for future use
					$ext = ".backup";

					break;

				default:
					$ext = '';
				}

				if ($path) {
					@unlink ($gal_use_dir . $path . $ext);
				}
			}

			$query3 = "delete from `tiki_images_data` where `imageId`=?";
			$result3 = $this->query($query3,array((int)$res["imageId"]));

			$this->remove_object('image', $res["imageId"]);
		}

		$query = "delete from `tiki_galleries` where `galleryId`=?";
		$result = $this->query($query,array((int) $id));
		$query = "delete from `tiki_images` where `galleryId`=?";
		$result = $this->query($query,array((int) $id));
		$this->remove_gallery_scale($id);
		$this->remove_object('image gallery', $id);
		return true;
	}

	function get_gallery_info($id) {
		// alias for get_gallery
		return $this->get_gallery($id);
	}

	function get_gallery_scale_info($id) {
		$query = "select * from `tiki_galleries_scales` where `galleryId`=?
              order by `scale` asc";

		$result = $this->query($query,array((int) $id));
		$resa = array();

		while ($res = $result->fetchRow()) {
			$resa[] = $res;
		}

		return $resa;
	}

	function get_gallery_next_scale($id, $scale= 0) {
		$query = "select * from `tiki_galleries_scales` where `galleryId`=?
              and `scale` > ? order by `scale` asc";
		$result = $this->query($query,array((int) $id,(int) $scale));
		$res = $result->fetchRow();
		return $res;
	}

	function get_gallery_default_scale($id) {
		$query = "select `defaultscale` from `tiki_galleries` where `galleryId`=?";
		$ret=$this->getOne($query,array((int) $id));
		return $ret;
	}

	function get_gallery_prevnext_scale($id,$currentscale) {
		$ret=array();
		$bindvars=array((int) $id, (int) $currentscale);
		$query = 'select `scale` from `tiki_galleries_scales` where `galleryId`=? ';
		$query2 =$query.'and `scale`>? order by `scale` asc';
		$ret['nextscale']=$this->getOne($query2,$bindvars);
		$query2 =$query.'and `scale`<? order by `scale` desc';
		$ret['prevscale']=$this->getOne($query2,$bindvars);
		if($ret['nextscale']) {
			$ret['nexttype']='s';
		} else {
			$ret['nexttype']='o';
		}
		if($ret['prevscale']) {
			$ret['prevtype']='s';
		} else {
			$ret['prevtype']='o';
		}
		return($ret);
	}

	//Capture Images from wiki, blogs, ....
	function capture_images($data) {
		global $tmpDir;
		global $tikilib;
		$cacheimages = $this->get_preference("cacheimages", 'y');

		if ($cacheimages != 'y')
			return $data;

		preg_match_all("/src=\"([^\"]+)\"/", $data, $reqs1);
		preg_match_all("/src=\'([^\']+)\'/", $data, $reqs2);
		preg_match_all("/src=([A-Za-z0-9\:\?\=\/\\\.\-\_]+)\}/", $data, $reqs3);
		preg_match_all("/src=([A-Za-z0-9\:\?\=\/\\\.\-\_]+) /", $data, $reqs4);
		$merge = array_merge($reqs1[1], $reqs2[1], $reqs3[1], $reqs4[1]);
		$merge = array_unique($merge);
		//print_r($merge);
		// Now for each element in the array capture the image and
		// if the capture was successful then change the reference to the
		// internal image
		$page_data = $data;

		foreach ($merge as $img) {
			// This prevents caching images
			if (!strstr($img, "show_image.php") && !strstr($img, "nocache") && @getimagesize($img)) {
				//print("Procesando: $img<br />");
				@$fp = fopen($img, "r");

				if ($fp) {
					$data = '';

					while (!feof($fp)) {
						$data .= fread($fp, 4096);
					}

					//print("Imagen leida:".strlen($data)." bytes<br />");
					fclose ($fp);

					if (strlen($data) > 0) {
						$url_info = parse_url($img);

						$pinfo = pathinfo($url_info["path"]);
						$type = "image/" . $pinfo["extension"];
						$name = $pinfo["basename"];
						$size = strlen($data);
						$url = $img;

						if (function_exists("ImageCreateFromString") && (!strstr($type, "gif"))) {
							$img = imagecreatefromstring($data);

							$size_x = imagesx($img);
							$size_y = imagesy($img);
							// Fix the ratio values for system gallery
							$gal_info["thumbSizeX"] = 90;
							$gal_info["thumbSizeY"] = 90;

							if ($size_x > $size_y)
								$tscale = ((int)$size_x / $gal_info["thumbSizeX"]);
							else
								$tscale = ((int)$size_y / $gal_info["thumbSizeY"]);

							$tw = ((int)($size_x / $tscale));
							$ty = ((int)($size_y / $tscale));

							if (chkgd2()) {
								$t = imagecreatetruecolor($tw, $ty);

								imagecopyresampled($t, $img, 0, 0, 0, 0, $tw, $ty, $size_x, $size_y);
							} else {
								$t = imagecreate($tw, $ty);

								$this->ImageCopyResampleBicubic($t, $img, 0, 0, 0, 0, $tw, $ty, $size_x, $size_y);
							}

							// CHECK IF THIS TEMP IS WRITEABLE OR CHANGE THE PATH TO A WRITEABLE DIRECTORY
							//$tmpfname = 'temp.jpg';
							//$tmpfname = tempnam("/tmp", "img");
							$tmpfname = tempnam($tmpDir, "img");
							imagejpeg($t, $tmpfname);
							// Now read the information
							$fp = fopen($tmpfname, "rb");
							$t_data = fread($fp, filesize($tmpfname));
							fclose ($fp);
							unlink ($tmpfname);
							$t_pinfo = pathinfo($tmpfname);
							$t_type = $t_pinfo["extension"];
							$t_type = 'image/' . $t_type;

							$imageId = $this->insert_image(0, '', '', $name, $type, $data, $size, $size_x, $size_y, 'admin', $t_data, $t_type);
						//print("Imagen generada en $imageId<br />");
						} else {
							//print("No GD detected generating image without thumbnail<br />");
							$imageId = $this->insert_image(0, '', '', $name, $type, $data, $size, 100, 100, 'admin', '', '');
						//print("Imagen en $imageId<br />");
						}

						// Now change it!
						//print("Changing $url to imageId: $imageId");
						$uri = parse_url($_SERVER["REQUEST_URI"]);
						$path = str_replace("tiki-editpage", "show_image", $uri["path"]);
						$path = str_replace("tiki-edit_article", "show_image", $path);
						$page_data = str_replace($url, $tikilib->httpPrefix(). $path . '?id=' . $imageId, $page_data);
					} // if strlen
				} // if $fp
			}
		} // foreach
		return $page_data;
	}
	function get_one_image_from_disk($userfile, $galleryId=0, $name='', $description='') {
		global $tmpDir, $user;
		$ret = array();
		if (is_uploaded_file($_FILES[$userfile]['tmp_name'])) {
			$file_name = $_FILES[$userfile]['name'];
			$ret['filename'] = $file_name;
			if (!empty($gal_match_regex) && !preg_match("/$gal_match_regex/", $file_name, $reqs)) {
				$ret['msg'] = tra('Invalid imagename (using filters for filenames)');
				return $ret;
			}
			if (!empty($gal_nmatch_regex) && preg_match("/$gal_nmatch_regex/", $file_name, $reqs)) {
				$ret['msg'] = tra('Invalid imagename (using filters for filenames)');
				return $ret;
			}
			$type = $_FILES[$userfile]['type'];
			$size = $_FILES[$userfile]['size'];
			$file_tmp_name = $_FILES[$userfile]['tmp_name'];
			$tmp_dest = $tmpDir . '/' . $file_name.'.tmp'; // add .tmp to not overwrite existing files (like index.php)
			if (!move_uploaded_file($file_tmp_name, $tmp_dest)) {
				$ret['msg'] = tra('Errors detected');
				@unlink($tmp_dest);
				return $ret;
			}
			$fp = fopen($tmp_dest, "rb");
			$ret['data'] = fread($fp, filesize($tmp_dest));
			fclose ($fp);
			$imginfo = @getimagesize($tmp_dest);
			unlink($tmp_dest);
			if (!$ret['data'] || !$imginfo) {
				$ret['msg'] = tra('Errors detected');
				return $ret;
			}
			if (!$galleryId) { // was called just to get and check the file
				$ret['xsize'] = $imginfo[0];
				$ret['ysize'] = $imginfo[1];
				$ret['filetype'] = $type;
				$ret['filesize'] = $size;
				return $ret;
			}
			if ($name == '')
				$name = $file_name;
			if (($imageId = $this->insert_image($galleryId, $name, $description, $file_name, $type, $ret['data'], $size, 0, 0, $user, '', ''))===false) {
				$ret['msg'] = tra('Upload was not successful');
			} else {
				$ret['imageId'] = $imageId;
			}
		} else {
			$ret['msg'] = tra('Upload was not successful');
			$ret['filename'] = $_FILES[$userfile]['tmp_name'];
		}
		unset($ret['data']);
		return $ret;
	}

  // function to move images from one store to another (fs to db or db to fs)
  function move_image_store($imageId,$direction='to_fs')
  {
    global $gal_use_db;
    global $gal_use_dir;
    $this->clear_class_vars(); //cleanup
    
    if($direction!='to_fs' && $direction!='to_db') {
      return(false);
    }
    
    // get the storage location
    $query='select `path` from `tiki_images` where `imageId`=?';
    $path=$this->getOne($query,array($imageId),false);
    if($path===false) { // imageId not found
      return(false);
    }
    
    if((empty($path) && $direction=='to_fs') || (!empty($path) && $direction=='to_db')) {
      // move image
      // load image
      $this->get_image($imageId);
      $query='update `tiki_images` set `path`=? where `imageId`=?';
      if($direction=='to_fs') {
   $this->path=md5(uniqid($this->filename));
        // store_image data did already overwrite the "data" field in tiki_images_data
        $this->query($query,array($this->path,$imageId));
      }
      // write image
      $this->store_image_data(true);
      if($direction=='to_db') {
        // remove image in fs 
        if(!@unlink($gal_use_dir.$this->path)) {
          $errstr="unlink failed";
        }
        $this->query($query,array('',$imageId));
      }
      return(1);

    }
    return(0);
  } 

  function move_gallery_store($galId,$direction='to_fs')
  {
    $met=ini_get('max_execution_time');
    $st=time();
    $n=0;
    $errors=0;
    $timeout=false;
    if($direction!='to_fs' && $direction!='to_db') {
      return(false);
    }
    
    // remove all scales. They will be rebuild on access
    $this->rebuild_scales($galId);
    
    // move images store
    if($galId==-1) {
      $query='select `imageId` from `tiki_images`';
      $result=$this->query($query,array());
    } else {
      $query='select `imageId` from `tiki_images` where `galleryId`=?';
      $result=$this->query($query,array($galId));
    }
    while ($res = $result->fetchRow()) {
      $r=$this->move_image_store($res['imageId'],$direction);
      if($r!==false) {
        $n+=$r;
      } else {
  $errors++; 
      }
      if($met-time()+$st < 3) { // avoid timeouts so that we dont end with broken images
   $timeout=true;
   break;
      }
    }
    $resultarray=array('moved_images'=>$n,'timeout'=>$timeout,'errors'=>$errors);
    return($resultarray);
  } 

  function clear_class_vars()
  { // function to clear loaded data. Usable for mass changes
     unset($this->imageId);
     unset($this->galleryId);
     unset($this->name);
     unset($this->description);
     unset($this->lat);
     unset($this->lon);
     unset($this->created);
     unset($this->user); 
     unset($this->hits);
     unset($this->path);
     unset($this->xsize);
     unset($this->oldxsize);
     unset($this->ysize);
     unset($this->oldysize);
     unset($this->type);
     unset($this->filesize);
     unset($this->filetype);
     unset($this->filename);
     unset($this->etag);
     unset($this->image);
  }
  /* compute the ratio the image $xsize,$size must have to go in the box */
  function ratio($xsize, $ysize, $xbox=0, $ybox=0) {
	if (empty($xbox) && empty($ybox))
		return 1;
	if ($xsize <= $xbox && $ysize <= $ybox)
		return 1;
	if (empty($xbox)) {
		return $ybox/xsize;
	} else {
		$t = $xbox/$xsize;
		if (!empty($ybox)) {
			return $t;
		} else {
			return min($t, $ybox/$ysize);
		}
	}
  }

}
global $dbTiki;
global $imagegallib;
$imagegallib = new ImageGalsLib($dbTiki);

?>
