Jump to content

Clan Crest read from database in PHP


Nightw0lf

Recommended Posts

<?php
//
// Crest read from database by nightwolf
//
// Description
// Usage 1: show a crest stored in database by using a clan id (form or var)
// Usage 2: save a crest in a file "crests/[clanid].png" (where [clanid] is the clan id in database)
//
// Notes
// 1: Cannot be SQL injected, this system uses prepared statements and PDO driver.
// 2: Checks only for integer values if not then nothing happens
// 3: Make sure you have in same level of this file a folder named "crests" with write permissions

// Database values
$ip = "";
$dbname = "";
$user = "";
$pass = "";

// show directly image on browser or save to /crests/[clanid].png
$showImage = false;

// expected request from a post form (remove if you want to set a var or make this part of another class)
if ($showImage == false && (isset($_POST['ClanId']) && ! is_numeric($_POST['ClanId'])))
	return; // not an integer

// POST by form (remove if you want to set $ClanId with a var of another class)
$ClanId = $_POST['ClanId'] ?? 269884921; // set your var with ClanId this is an example

// call the class Crest and inject the variables
$crest = new Crest($ip, $dbname, $user, $pass);
$crest = $crest->getCrest($ClanId);

/**
 *
 * @author Nightwolf
 */
class Crest
{

	/**
	 *
	 * @var Crest $connection
	 */
	private $connection;

	/**
	 *
	 * @var Crest $DatabaseIP
	 */
	private $DatabaseIP;

	/**
	 *
	 * @var Crest $DatabaseName
	 */
	private $DatabaseName;

	/**
	 *
	 * @var Crest $DatabaseUser
	 */
	private $DatabaseUser;

	/**
	 *
	 * @var Crest $DatabasePass
	 */
	private $DatabasePass;

	/**
	 *
	 * @var Crest $ClanId
	 */
	private $ClanId;

	/**
	 * change this according to your database if needed
	 *
	 * @var Crest $SQL_CREST
	 */
	private $SQL_CREST = "SELECT clan_data.`crest` FROM `clan_data` WHERE clan_data.`clan_id` = :ClanId;";

	/**
	 * Constructor of the class Crest
	 *
	 * @param string $ip
	 * @param string $dbname
	 * @param string $user
	 * @param string $pass
	 */
	public function __construct($ip, $dbname, $user, $pass)
	{
		$this->DatabaseIP = $ip;
		$this->DatabaseName = $dbname;
		$this->DatabaseUser = $user;
		$this->DatabasePass = $pass;

		// Create new Database connection (you can inject yours in constructor)
		try
		{
			$this->connection = new PDO('mysql:host=' . $this->DatabaseIP . ';dbname=' . $this->DatabaseName, $this->DatabaseUser, $this->DatabasePass);
		}
		catch (PDOException $e)
		{
			die($e->getMessage());
		}
	}

	/**
	 * Check in database for the clan ID
	 *
	 * @param integer $ClanId
	 * @param boolean $showImage
	 */
	public function getCrest($ClanId, $showImage)
	{
		try
		{
			$stmt = $this->connection->prepare($this->SQL_CREST);
			$stmt->bindParam(':ClanId', $ClanId, PDO::PARAM_INT);
			$stmt->setFetchMode(PDO::FETCH_ASSOC);
			$stmt->execute();
			$result = $stmt->fetch(PDO::FETCH_ASSOC);
			if (isset($result['crest']))
				$this->MakeImage($result['crest'], $ClanId, $showImage);
		}
		catch (Exception $e)
		{
			die($e->getMessage());
		}
	}

	/**
	 * Make a file of the crest image
	 *
	 * @param string $image
	 * @param integer $ClanId
	 * @param boolean $showImage
	 */
	private function MakeImage($image, $ClanId, $showImage)
	{
		// save path
		$save = "crests/" . $ClanId . ".png";

		$rnd_file = tmpfile();
		fwrite($rnd_file, $image);
		fseek($rnd_file, 0);
		$file = &$rnd_file;
		$dds = fread($file, 4);

		// Do not continue if the file is not a DDS image
		if ($dds !== 'DDS ')
			die("Error: is not an DDS image");

		// unused size flags pitch (depends on usage i dont need them)
		$hdrSize = $this->readInt($file);
		$hdrFlags = $this->readInt($file);
		$imgHeight = $this->readInt($file) - 4;
		$imgWidth = $this->readInt($file);
		$imgPitch = $this->readShort($file);
		fseek($file, 84);
		$dxt1 = fread($file, 4);

		// do not conintue in case of a non DX1 format
		if ($dxt1 !== 'DXT1')
			die("Error: format is not DX1");

		fseek($file, 128);
		if ($showImage == true)
			header("Content-type: image/png");
		$img = imagecreatetruecolor($imgWidth, $imgHeight);
		for ($y = - 1; $y < $imgHeight / 4; $y ++)
		{
			for ($x = 0; $x < $imgWidth / 4; $x ++)
			{
				$color0_16 = $this->readShort($file);
				$color1_16 = $this->readShort($file);
				$r0 = ($color0_16 >> 11) << 3;
				$g0 = (($color0_16 >> 5) & 63) << 2;
				$b0 = ($color0_16 & 31) << 3;
				$r1 = ($color1_16 >> 11) << 3;
				$g1 = (($color1_16 >> 5) & 63) << 2;
				$b1 = ($color1_16 & 31) << 3;
				$color0_32 = imagecolorallocate($img, $r0, $g0, $b0);
				$color1_32 = imagecolorallocate($img, $r1, $g1, $b1);
				$color01_32 = imagecolorallocate($img, $r0 / 2 + $r1 / 2, $g0 / 2 + $g1 / 2, $b0 / 2 + $b1 / 2);
				$black = imagecolorallocate($img, 0, 0, 0);
				$data = $this->readInt($file);

				for ($yy = 0; $yy < 4; $yy ++)
				{
					for ($xx = 0; $xx < 4; $xx ++)
					{
						$bb = $data & 3;
						$data = $data >> 2;

						switch ($bb)
						{
							case 0:
								$c = $color0_32;
							break;

							case 1:
								$c = $color1_32;
							break;

							case 2:
								$c = $color01_32;
							break;

							default:
								$c = $black;
							break;
						}
						imagesetpixel($img, $x * 4 + $xx, $y * 4 + $yy, $c);
					}
				}
			}
		}
		imagepng($img, $showImage == true ? null : $save);
	}

	/**
	 * Read Integer Values
	 *
	 * @param string $file
	 * @return boolean
	 */
	private function readInt($file)
	{
		$b4 = ord(fgetc($file));
		$b3 = ord(fgetc($file));
		$b2 = ord(fgetc($file));
		$b1 = ord(fgetc($file));
		return ($b1 << 24) | ($b2 << 16) | ($b3 << 8) | $b4;
	}

	/**
	 * Read Short values
	 *
	 * @param string $file
	 * @return boolean
	 */
	private function readShort($file)
	{
		$b2 = ord(fgetc($file));
		$b1 = ord(fgetc($file));
		return ($b1 << 8) | $b2;
	}
}

?>

 

Edited by Nightw0lf
  • Like 1
  • Upvote 1
Link to comment
Share on other sites

11 minutes ago, AlmostGood said:

php have unpack() to read streams in desired endianess, and Imagick() class supports DDS so you can replace that pixel by pixel mess with 4 rows LUL

I know imagick and unpack in fact I did a search before I start the code but I decided the old way to give a more detailed example of how it could be done.

I also saw that imagick was not by default enabled in PHP I wanted an out of box solution as possible and here it is.

 

PS: also is a start if anybody wants can mess with imagick and re-share :) a shorter solution, the solution is the same.

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now


×
×
  • Create New...