Skip to content

Clan Crest read from database in PHP

Featured Replies

<?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

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

  • Author
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.

Create an account or sign in to comment

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.