From 212c0d676791245689b5716b10135664f0983a2e Mon Sep 17 00:00:00 2001 From: printempw Date: Fri, 5 Feb 2016 15:56:17 +0800 Subject: [PATCH] supported skin storage for both steve and alex model --- admin/index.php | 11 ++- ajax.php | 35 +++++-- assets/css/user.style.css | 5 +- assets/js/admin.utils.js | 16 +++- assets/js/user.utils.js | 187 +++++++++++++++++++++----------------- get.php | 9 +- includes/user.class.php | 80 +++++++++------- includes/utils.class.php | 12 ++- user/index.php | 16 +++- user/preview.php | 2 +- 10 files changed, 229 insertions(+), 144 deletions(-) diff --git a/admin/index.php b/admin/index.php index d1d0ede8..25d92e8b 100644 --- a/admin/index.php +++ b/admin/index.php @@ -3,7 +3,7 @@ * @Author: prpr * @Date: 2016-02-03 14:39:50 * @Last Modified by: prpr - * @Last Modified time: 2016-02-04 23:45:06 + * @Last Modified time: 2016-02-05 15:52:39 */ session_start(); @@ -83,13 +83,14 @@ if (isset($_SESSION['uname'])) { - '; ?> - '; ?> + '; ?> + '; ?> + '; ?> - Skin + Skin Cape - Model + Model () diff --git a/ajax.php b/ajax.php index b1da2cea..bcc4f497 100644 --- a/ajax.php +++ b/ajax.php @@ -3,7 +3,7 @@ * @Author: printempw * @Date: 2016-01-16 23:01:33 * @Last Modified by: prpr - * @Last Modified time: 2016-02-04 18:48:30 + * @Last Modified time: 2016-02-05 15:35:31 * * - login, register, logout * - upload, change, delete @@ -20,7 +20,12 @@ require "$dir/includes/autoload.inc.php"; database::checkConfig(); if (isset($_POST['uname'])) { - $user = new user($_POST['uname']); + $uname = $_POST['uname']; + if (user::checkValidUname($uname)) { + $user = new user($_POST['uname']); + } else { + utils::raise(1, 'Invalid username. Only letters, numbers and _ is allowed.'); + } } else { utils::raise('1', 'Empty username.'); } @@ -29,7 +34,6 @@ $json = null; /** * Handle requests from index.php - * @var [type] */ if ($action == "login") { if (checkPost()) { @@ -59,7 +63,7 @@ if ($action == "login") { } else { $ip = $_SERVER['REMOTE_ADDR']; } - // If amout of registered accounts of IP is more than allowed mounts, + // If amount of registered accounts of IP is more than allowed mounts, // then reject the registration. if ($user->db->getNumRows('ip', $ip) < REGS_PER_IP) { // use once md5 to encrypt password @@ -99,7 +103,8 @@ if ($action == "upload") { if (utils::getValue('token', $_SESSION) == $user->getToken()) { if (checkFile()) { if ($file = utils::getValue('skin_file', $_FILES)) { - if ($user->setTexture('skin', $file)) { + $model = (isset($_GET['model']) && $_GET['model'] == "steve") ? "steve" : "alex"; + if ($user->setTexture($model, $file)) { $json['skin']['errno'] = 0; $json['skin']['msg'] = "Skin uploaded successfully."; } else { @@ -121,14 +126,15 @@ if ($action == "upload") { $json['errno'] = 1; $json['msg'] = "Invalid token."; } -} else if ($action == "logout") { - if (utils::getValue('token', $_SESSION)) { - session_destroy(); +} else if ($action == "model") { + if (utils::getValue('token', $_SESSION) == $user->getToken()) { + $new_model = ($user->getPreference() == "default") ? "slim" : "default"; + $user->setPreference($new_model); $json['errno'] = 0; - $json['msg'] = 'Session destroyed.'; + $json['msg'] = "Preferred model successfully changed to ".$user->getPreference()."."; } else { $json['errno'] = 1; - $json['msg'] = 'No available session.'; + $json['msg'] = "Invalid token."; } } @@ -221,6 +227,15 @@ if ($action == "change") { $json['errno'] = 1; $json['msg'] = "Invalid token."; } +} else if ($action == "logout") { + if (utils::getValue('token', $_SESSION)) { + session_destroy(); + $json['errno'] = 0; + $json['msg'] = 'Session destroyed.'; + } else { + $json['errno'] = 1; + $json['msg'] = 'No available session.'; + } } if (!$action) { diff --git a/assets/css/user.style.css b/assets/css/user.style.css index 33e498b2..69b86e89 100644 --- a/assets/css/user.style.css +++ b/assets/css/user.style.css @@ -2,7 +2,7 @@ * @Author: prpr * @Date: 2016-01-21 19:12:06 * @Last Modified by: prpr -* @Last Modified time: 2016-02-05 11:16:53 +* @Last Modified time: 2016-02-05 15:13:00 */ .home-menu-blur { @@ -100,3 +100,6 @@ input[type=radio] { .container { position: initial !important; } +#skinpreview > p { + margin: 20px 0; +} diff --git a/assets/js/admin.utils.js b/assets/js/admin.utils.js index 1116f79e..386bd619 100644 --- a/assets/js/admin.utils.js +++ b/assets/js/admin.utils.js @@ -2,11 +2,23 @@ * @Author: prpr * @Date: 2016-02-04 16:48:42 * @Last Modified by: prpr -* @Last Modified time: 2016-02-04 18:27:44 +* @Last Modified time: 2016-02-05 15:52:32 */ 'use strict'; +function uploadSkin(uname) { + Ply.dialog("confirm", { + text: "Which model do you want to change?", + ok: "Steve", + cancel: "Alex" + }).done(function(){ + uploadTexture(uname, 'steve'); + }).fail(function(){ + uploadTexture(uname, 'alex'); + }); +} + function uploadTexture(uname, type) { var ply = new Ply({ el: '

Upload new '+type+':

'+ @@ -31,7 +43,7 @@ function uploadTexture(uname, type) { location.reload(); }); } else { - showAlert("Error when uploading cape:\n" + json.msg); + showAlert("Error when uploading texture:\n" + json.msg); } } }); diff --git a/assets/js/user.utils.js b/assets/js/user.utils.js index d76bb66b..fcbfebbb 100644 --- a/assets/js/user.utils.js +++ b/assets/js/user.utils.js @@ -2,115 +2,134 @@ * @Author: prpr * @Date: 2016-01-21 13:56:40 * @Last Modified by: prpr -* @Last Modified time: 2016-02-05 11:38:39 +* @Last Modified time: 2016-02-05 15:35:02 */ 'use strict'; -$("body").on("change", "#skininput", function(){ - var files = $("#skininput").prop("files"); - handleFiles(files, "skin"); +$('body').on('change', '#skininput', function(){ + var files = $('#skininput').prop('files'); + handleFiles(files, 'skin'); }); -$("body").on("change", "#capeinput", function(){ - var files = $("#capeinput").prop("files"); - handleFiles(files, "cape"); +$('body').on('change', '#capeinput', function(){ + var files = $('#capeinput').prop('files'); + handleFiles(files, 'cape'); }); +// Real-time preview function handleFiles(files, type) { - if(files.length > 0) { - var file = files[0]; - if(file.type === 'image/png') { - var fr = new FileReader(); - fr.onload = function (e) { - var img = new Image(); - img.onload = function () { - if (type == "skin") { - MSP.changeSkin(img.src); - } else { - MSP.changeCape(img.src); - } - }; - img.onerror = function () { - showMsg("alert-danger", "Error: Not an image or unknown file format"); - }; - img.src = this.result; - }; - fr.readAsDataURL(file); - } else { - showMsg("alert-danger", "Error: This is not a PNG image!"); - } - } + if(files.length > 0) { + var file = files[0]; + if(file.type === "image/png") { + var fr = new FileReader(); + fr.onload = function (e) { + var img = new Image(); + img.onload = function () { + if (type == "skin") { + MSP.changeSkin(img.src); + } else { + MSP.changeCape(img.src); + } + }; + img.onerror = function () { + showMsg("alert-danger", "Error: Not an image or unknown file format"); + }; + img.src = this.result; + }; + fr.readAsDataURL(file); + } else { + showMsg("alert-danger", "Error: This is not a PNG image!"); + } + } }; function init3dCanvas() { - if ($(window).width() < 800) { - var canvas = MSP.get3dSkinCanvas($('#skinpreview').width(), $('#skinpreview').width()); - $("#skinpreview").append($(canvas).prop("id", "canvas3d")); - } else { - var canvas = MSP.get3dSkinCanvas(400, 400); - $("#skinpreview").append($(canvas).prop("id", "canvas3d")); - } + if ($(window).width() < 800) { + var canvas = MSP.get3dSkinCanvas($('#skinpreview').width(), $('#skinpreview').width()); + $("#skinpreview").append($(canvas).prop("id", "canvas3d")); + } else { + var canvas = MSP.get3dSkinCanvas(400, 400); + $("#skinpreview").append($(canvas).prop("id", "canvas3d")); + } } -$(document).ready(function(){ - init3dCanvas(); -}); - -$(window).resize(function(){ - init3dCanvas(); -}); +$(document).ready(init3dCanvas); +// Auto resize canvas to fit responsive design +$(window).resize(init3dCanvas); +// Change 3D preview status $("[title='Movements']").click(function(){ - MSP.setStatus("movements", !MSP.getStatus("movements")); + MSP.setStatus("movements", !MSP.getStatus("movements")); }); - $("[title='Running']").click(function(){ - MSP.setStatus("running", !MSP.getStatus("running")); + MSP.setStatus("running", !MSP.getStatus("running")); }); - $("[title='Rotation']").click(function(){ - MSP.setStatus("rotation", !MSP.getStatus("rotation")); + MSP.setStatus("rotation", !MSP.getStatus("rotation")); }); function show2dPreview() { - $('#canvas3d').remove(); - $("#skinpreview").html($('

Skin for Steve model:

').append($('').css('float', 'right').attr('src', '../skin/admin.png'))); + $('#canvas3d').remove(); + $("#skinpreview").html($('

Skin for Steve model:

').append($('').css('float', 'right').attr('src', '../skin/'+docCookies.getItem('uname')+'-steve.png'))); + $("#skinpreview").append($('

Skin for Alex model:

').append($('').css('float', 'right').attr('src', '../skin/'+docCookies.getItem('uname')+'-alex.png'))); + $("#skinpreview").append($('

Cape:

').append($('').css('float', 'right').attr('src', '../cape/'+docCookies.getItem('uname')+'.png'))); } $("#upload").click(function(){ - var skin_file = $("#skininput").get(0).files[0]; - var cape_file = $("#capeinput").get(0).files[0]; - var form_data = new FormData(); - if (skin_file) form_data.append('skin_file', skin_file); - if (cape_file) form_data.append('cape_file', cape_file); - if (skin_file || cape_file) { - $.ajax({ - type: 'POST', - url: '../ajax.php?action=upload', - contentType: false, - dataType: "json", - data: form_data, - processData: false, - beforeSend: function() { - showMsg("alert-info", "Uploading..."); - }, - success: function(json) { - console.log(json); - if (json.skin.errno == 0 && json.cape.errno == 0) { - showMsg("alert-success", "Successfully uploaded."); - } - if (json.skin.errno != 0) { - showMsg("alert-danger", "Error when uploading skin:\n"+json.skin.msg); - } - if (json.cape.errno != 0) { - showMsg("alert-danger", "Error when uploading cape:\n"+json.cape.msg); - } - } - }); - } else { - showMsg("alert-warning", "No input file selected"); - } + var model = $('#model-steve').prop('checked') ? "steve" : "alex"; + var skin_file = $('#skininput').get(0).files[0]; + var cape_file = $('#capeinput').get(0).files[0]; + var form_data = new FormData(); + if (skin_file) form_data.append('skin_file', skin_file); + if (cape_file) form_data.append('cape_file', cape_file); + form_data.append('uname', docCookies.getItem('uname')); + // Ajax file upload + if (skin_file || cape_file) { + $.ajax({ + type: 'POST', + url: '../ajax.php?action=upload&model='+model, + contentType: false, + dataType: "json", + data: form_data, + processData: false, + beforeSend: function() { + showMsg('alert-info', 'Uploading...'); + }, + success: function(json) { + console.log(json); + if (json.skin.errno == 0 && json.cape.errno == 0) { + showMsg('alert-success', 'Successfully uploaded.'); + } + if (json.skin.errno != 0) { + showMsg('alert-danger', 'Error when uploading skin:\n'+json.skin.msg); + } + if (json.cape.errno != 0) { + showMsg('alert-danger', 'Error when uploading cape:\n'+json.cape.msg); + } + } + }); + } else { + showMsg('alert-warning', 'No input file selected'); + } }); - +function changeModel(uname) { + showAlert("Sure to change?", function(){ + $.ajax({ + type: "POST", + url: "../ajax.php?action=model", + data: { "uname": docCookies.getItem('uname') }, + dataType: "json", + success: function(json) { + if (json.errno == 0) { + showAlert(json.msg, function(){ + location.reload(); + }); + } else { + showAlert(json.msg); + } + } + }); + }); +} diff --git a/get.php b/get.php index 38bbbad4..f2f7c4ed 100644 --- a/get.php +++ b/get.php @@ -3,7 +3,7 @@ * @Author: prpr * @Date: 2016-02-02 20:56:42 * @Last Modified by: prpr - * @Last Modified time: 2016-02-04 22:06:20 + * @Last Modified time: 2016-02-05 14:51:26 * * All textures requests of legacy link will be handle here. */ @@ -18,10 +18,15 @@ if (isset($_GET['type']) && isset($_GET['uname'])) { $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) : null; if ($_GET['type'] == "skin" || $_GET['type'] == "cape") { + $model = (isset($_GET['model']) && $_GET['model'] == "steve") ? "steve" : "alex"; if ($if_modified_since >= $user->getLastModified()) { header('HTTP/1.0 304 Not Modified'); } else { - echo $user->getBinaryTexture($_GET['type']); + if ($_GET['type'] == "cape") { + echo $user->getBinaryTexture('cape'); + } else { + echo $user->getBinaryTexture($model); + } } } else if ($_GET['type'] == "json") { if (isset($_GET['api'])) { diff --git a/includes/user.class.php b/includes/user.class.php index f25bb602..a078e13d 100644 --- a/includes/user.class.php +++ b/includes/user.class.php @@ -3,7 +3,7 @@ * @Author: printempw * @Date: 2016-01-16 23:01:33 * @Last Modified by: prpr - * @Last Modified time: 2016-02-04 20:38:42 + * @Last Modified time: 2016-02-05 15:11:35 */ class user @@ -37,6 +37,10 @@ class user } } + public static function checkValidUname($uname) { + return preg_match("([A-Za-z0-9_\-]+)", $uname); + } + public static function checkValidPwd($passwd) { if (strlen($passwd) > 16 || strlen($passwd) < 5) { utils::raise(1, 'Illegal password. Password length should be in 5~16.'); @@ -55,32 +59,33 @@ class user } public function register($passwd, $ip) { - if ($this->db->insert(array( - "uname" => $this->uname, - "passwd" => $passwd, - "ip" => $ip - ))) - { - return true; - } else { - return false; - } + return $this->db->insert(array( + "uname" => $this->uname, + "passwd" => $passwd, + "ip" => $ip + )); } public function unRegister() { - if ($this->getTexture('skin') != "") - utils::remove("./textures/".$this->getTexture('skin')); - if ($this->getTexture('skin') != "") + if ($this->getTexture('steve') != "") + utils::remove("./textures/".$this->getTexture('steve')); + if ($this->getTexture('alex') != "") + utils::remove("./textures/".$this->getTexture('alex')); + if ($this->getTexture('cape') != "") utils::remove("./textures/".$this->getTexture('cape')); return $this->db->delete($this->uname); } + /** + * Get textures of user + * @param string $type steve|alex|cape + * @return string sha256-hash of texture file + */ public function getTexture($type) { - if ($type == "skin") { - return $this->db->select('username', $this->uname)['skin_hash']; - } else if ($type == "cape") { - return $this->db->select('username', $this->uname)['cape_hash']; - } + if ($type == "skin") + $type = ($this->getPreference() == "default") ? "steve" : "alex"; + if ($type == "steve" | $type == "alex" | $type == "cape") + return $this->db->select('username', $this->uname)['hash_'.$type]; return false; } @@ -88,9 +93,9 @@ class user $filename = "./textures/".$this->getTexture($type); if (file_exists($filename)) { header('Content-Type: image/png'); + // Cache friendly header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $this->getLastModified()).' GMT'); - $data = fread(fopen($filename, 'r'), filesize($filename)); - return $data; + return utils::fread($filename); } else { utils::raise(-1, 'Texture no longer exists.'); } @@ -98,21 +103,19 @@ class user public function setTexture($type, $file) { $hash = utils::upload($file); - if ($type == "skin") { - // remove the original texture first - if ($this->getTexture('skin') != "") - utils::remove("./textures/".$this->getTexture('skin')); - $this->updateLastModified(); - return $this->db->update($this->uname, 'skin_hash', $hash); - } else if ($type == "cape") { - if ($this->getTexture('cape') != "") - utils::remove("./textures/".$this->getTexture('cape')); - $this->updateLastModified(); - return $this->db->update($this->uname, 'cape_hash', $hash); - } + // Remove the original texture first + if ($this->getTexture($type) != "") + utils::remove("./textures/".$this->getTexture($type)); + $this->updateLastModified(); + if ($type == "steve" | $type == "alex" | $type == "cape") + return $this->db->update($this->uname, 'hash_'.$type, $hash); return false; } + /** + * Set preferred model + * @param string $type, 'slim' or 'default' + */ public function setPreference($type) { return $this->db->update($this->uname, 'preference', $type); } @@ -121,9 +124,15 @@ class user return $this->db->select('username', $this->uname)['preference']; } + /** + * Get JSON profile + * @param int $api_type, which API to use, 0 for CustomSkinAPI, 1 for UniSkinAPI + * @return string, user profile in json format + */ public function getJsonProfile($api_type) { header('Content-type: application/json'); if ($this->is_registered) { + // Support both CustomSkinLoader API & UniSkinAPI if ($api_type == 0 || $api_type == 1) { $json[($api_type == 0) ? 'username' : 'player_name'] = $this->uname; $model = $this->getPreference(); @@ -132,8 +141,9 @@ class user $json['last_update'] = $this->getLastModified(); $json['model_preference'] = [$model, $sec_model]; } - $json['skins'][$model] = $this->getTexture('skin'); - $json['skins'][$sec_model] = $this->getTexture('skin'); + // Skins dict order by preference model + $json['skins'][$model] = $this->getTexture($model == "default" ? "steve" : "alex"); + $json['skins'][$sec_model] = $this->getTexture($sec_model == "default" ? "steve" : "alex"); $json['cape'] = $this->getTexture('cape'); } else { utils::raise(-1, 'Configuration error. Non-supported API_TYPE.'); diff --git a/includes/utils.class.php b/includes/utils.class.php index b416ae7f..a842508c 100644 --- a/includes/utils.class.php +++ b/includes/utils.class.php @@ -3,7 +3,7 @@ * @Author: printempw * @Date: 2016-01-16 23:01:33 * @Last Modified by: prpr - * @Last Modified time: 2016-02-04 23:43:07 + * @Last Modified time: 2016-02-05 13:27:43 */ class utils @@ -36,6 +36,16 @@ class utils return $hash; } + /** + * Read a file and return bin data + * + * @param string $filename + * @return resource, binary data + */ + public static function fread($filename) { + return fread(fopen($filename, 'r'), filesize($filename)); + } + /** * Remove a file * diff --git a/user/index.php b/user/index.php index 00906d2f..1cf2695e 100644 --- a/user/index.php +++ b/user/index.php @@ -71,9 +71,9 @@ if (isset($_SESSION['uname'])) {

Select a cape:


- My skin fits on the classic Steve player model. +
- My skin fits on the new Alex player model. +

2D Preview @@ -81,6 +81,12 @@ if (isset($_SESSION['uname'])) { +
+
Change Preferred Model
+
+

Your preference model is getPreference(); ?>. Change?

+
+
@@ -104,5 +110,9 @@ if (isset($_SESSION['uname'])) { - +getTexture('alex') && ($user->getTexture('steve') == "")) {?> + + diff --git a/user/preview.php b/user/preview.php index e27af970..c6e2cd48 100644 --- a/user/preview.php +++ b/user/preview.php @@ -3,7 +3,7 @@ * @Author: prpr * @Date: 2016-02-04 19:37:21 * @Last Modified by: prpr - * @Last Modified time: 2016-02-04 22:43:15 + * @Last Modified time: 2016-02-05 15:02:52 */ ?>