Skip to content

Instantly share code, notes, and snippets.

@MineTheCube
Last active September 1, 2016 18:26
Show Gist options
  • Save MineTheCube/f244b1933e755ac39d2a52b1d377542c to your computer and use it in GitHub Desktop.
Save MineTheCube/f244b1933e755ac39d2a52b1d377542c to your computer and use it in GitHub Desktop.
Display head of player from his username or uuid using MojangAPI (github project)
<?php
/**
* Informations
* --------------------------------------
*
* This script use MojangAPI to display head of player from his username or uuid
*
* Parameters:
* user = username or UUID
* size = size in pixels, optional
*
* E.g.: /head.php?user=Notch
* E.g.: /head.php?user=069a79f4-44e9-4726-a5be-fca90e38aaf5&size=200
*
* Please check the configuration below to ensure everything will work
*/
/* Configuration
--------------------------------------*/
// debug = true : in case of errors we print them
// debug = false : if we have errors we print default steve avatar instead
define('DEBUG', true);
// How many seconds skin is cached
define('CACHE_TIMEOUT', 86400);
// Default size of avatar if not provided
define('DEFAULT_SIZE', 100);
// Minimum size allowed
define('MINIMUM_SIZE', 10);
// And maximum size allowed
define('MAXIMUM_SIZE', 300);
// Where database should be
define('DATABASE_LOCATION', __DIR__ . '/cache/skins.sqlite');
// And where MojangApi is located
define('MOJANGAPI_LOCATION', __DIR__ . '/libraries/mojang-api.class.php');
// If we try to download MojangAPI if missing
define('AUTO_INSTALL', true);
/* White page ?
* Uncomment these 2 lines
--------------------------------------*/
// error_reporting(E_ALL);
// ini_set('display_errors', true);
/* URL Rewriting
--------------------------------------*/
/* If you want nice urls like: /head/Notch/100, create a file named ".htaccess" in the same directory with this:
# --------- .htaccess ---------
RewriteEngine on
# If you have 500 internal errors, remove the # and put the current directory from this line:
# RewriteBase /current-directory/
# Redirect "/head/Notch/100", "head/Notch" or "head/Notch.png" to the script
# So url is "/head/<username or uuid>/<size>", with size and .png extension being optional
RewriteRule ^head/([^/]+?)(?:/([^/]+?))?/?(?:\.png)?$ head.php?user=$1&size=$2 [L]
# --------- end of file ---------
*/
// ------------------------------------------------------------------------------------- //
// YOU DON'T NEED TO READ BELOW, IT IS ONLY SCRIPT AND PROCESSING PART //
// ------------------------------------------------------------------------------------- //
/* Requirements
--------------------------------------*/
// Check PDO Sqlite
if (!function_exists('extension_loaded') or !extension_loaded('pdo_sqlite')) {
echo '<h2>Installation required</h2>';
echo 'The extension <b>pdo_sqlite</b> is not enabled. '
. 'Contact your webhost or enable it yourself to use this script. '
. 'More informations can be found <a href="http://php.net/manual/ref.pdo-sqlite.php" target="_blank">here</a>.';
exit;
}
// Check Mojang API class
if (!is_file(MOJANGAPI_LOCATION)) {
// Try to download it
$parentFolder = dirname(MOJANGAPI_LOCATION);
$parentOfParent = dirname($parentFolder);
if (AUTO_INSTALL === true and is_dir($parentOfParent)) {
$mojangApi = @file_get_contents('https://raw.githubusercontent.com/MineTheCube/MojangAPI/master/mojang-api.class.php');
if (strlen($mojangApi) > 20000) {
if (!is_dir($parentFolder)) mkdir($parentFolder);
file_put_contents(MOJANGAPI_LOCATION, $mojangApi);
}
}
// MojangAPI is still missing
if (!is_file(MOJANGAPI_LOCATION)) {
echo '<h2>Installation required</h2>';
echo 'You need to <a href="https://github.com/MineTheCube/MojangAPI" target="_blank">download <b>mojang-api.class.php</b></a>'
. ' in the following folder: <b>' . htmlentities(str_replace('\\', '/', dirname(DATABASE_LOCATION))) . '/</b>';
exit;
}
}
// Check database
if (!is_dir(dirname(DATABASE_LOCATION))) {
// Try to create folder
if (AUTO_INSTALL === true) {
$parentFolder = dirname(DATABASE_LOCATION);
$parentOfParent = dirname($parentFolder);
if (AUTO_INSTALL === true and is_dir($parentOfParent)) {
mkdir($parentFolder);
}
}
// Folder still not created
if (!is_dir(dirname(DATABASE_LOCATION))) {
echo '<h2>Installation required</h2>';
echo 'You need to create the following folder: <b>' . htmlentities(str_replace('\\', '/', dirname(DATABASE_LOCATION))) . '/</b>';
exit;
}
}
/* Initialization
--------------------------------------*/
// Require MojangAPI
require_once MOJANGAPI_LOCATION;
// Get query parameters
// User can be either username or UUID
$user = !empty($_GET['user']) ? (string) $_GET['user'] : null;
$size = !empty($_GET['size']) ? (int) $_GET['size'] : DEFAULT_SIZE;
// Start database connection
try {
// We'll create a new database
$initDatabase = !is_file(DATABASE_LOCATION);
// Ensure we have write access
if ($initDatabase) chmod(dirname(DATABASE_LOCATION), 0755);
// Try to connect
$pdo = new PDO('sqlite:' . DATABASE_LOCATION, null, null, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
// And ensure we can write to it
if ($initDatabase) chmod(DATABASE_LOCATION, 0666);
} catch (PDOException $e) {
// Nope, giving up here..
echo '<h2>Cannot connect to database</h2>';
echo 'The following error happened when trying to connect to sqlite database:';
echo '<pre>' . $e->getMessage() . '</pre>';
exit;
}
// Create table if missing
$pdo->exec('CREATE TABLE IF NOT EXISTS cache (username TEXT NOT NULL, uuid TEXT NOT NULL, skin TEXT NOT NULL, time INTEGER NOT NULL)');
// Delete old skin data
$time = time() - CACHE_TIMEOUT;
$stmt = $pdo->prepare('DELETE FROM cache WHERE time < ?');
$stmt->execute(array($time));
// One out 20 requests, we do a VACUUM to free unused space
if (rand(0, 20) === 0) $pdo->exec('VACUUM');
$errors = array();
/* Verify parameters
--------------------------------------*/
// Ensure size is correct
if ($size >= MINIMUM_SIZE and $size <= MAXIMUM_SIZE) {
if (MojangAPI::isValidUuid($user)) {
// We have a correct UUID
$uuid = MojangAPI::minifyUuid($user);
$username = null;
$field = 'uuid';
$value = $uuid;
} else if (MojangAPI::isValidUsername($user)) {
// We have a correct username
$username = $user;
$uuid = null;
$field = 'username';
$value = strtolower($username);
} else {
$errors[] = 'No valid UUID or username given';
}
/* Get skin
--------------------------------------*/
// We have both field and value defined
if (isset($field) and isset($value)) {
$skin = null;
$stmt = $pdo->prepare('SELECT skin FROM cache WHERE ' . $field . ' = ?');
$stmt->execute(array($value));
$result = $stmt->fetch();
// If no cache available
if (empty($result)) {
// Let's fetch the uuid or username missing
if (!empty($uuid)) {
$username = MojangAPI::getUsername($uuid);
} else {
$profile = MojangAPI::getProfile($username);
if (!empty($profile)) {
$username = $profile['name'];
$uuid = $profile['id'];
}
}
// We should have both now
if (!empty($username) and !empty($uuid)) {
// Fetch the skin from Mojang's server
$skin = MojangAPI::getSkin($uuid);
// User exists but hasn't a skin
if (is_null($skin)) {
$skin = MojangAPI::isAlex($uuid) ? MojangAPI::getAlexSkin() : MojangAPI::getSteveSkin();
}
if (!empty($skin)) {
// Cache result
$stmt = $pdo->prepare('INSERT INTO cache VALUES(?, ?, ?, ?)');
$stmt->execute(array(strtolower($username), $uuid, base64_encode($skin), time()));
} else {
$errors[] = 'Cannot get skin from Mojang';
}
} else {
$errors[] = 'Cannot get UUID or username from Mojang';
}
} else {
// Get from cache
$skin = base64_decode($result['skin']);
}
/* Display it
--------------------------------------*/
if (!empty($skin)) {
// Get head from skin
$head = MojangAPI::getPlayerHeadFromSkin($skin, $size);
// Print it with browser caching
MojangAPI::printImage($head, CACHE_TIMEOUT);
exit;
}
}
} else {
// Going to default size
$size = DEFAULT_SIZE;
$errors[] = 'Invalid size';
}
/* An error happened
--------------------------------------*/
if (DEBUG === true) {
// Display errors
echo '<h2>Something went wrong</h2>';
echo '<ul><li>';
echo implode('</li><li>', $errors);
echo '</li></ul>';
} else {
// If we have an uuid, it may be alex
$head = (!empty($uuid) and MojangAPI::isAlex($uuid)) ? MojangAPI::getAlexHead($size) : MojangAPI::getSteveHead($size);
// Display default skin, with 15min caching
MojangAPI::printImage($head, 900);
}
// Exit to ensure nothing will be displayed after the image
exit;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment