-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/PROTOCOL.md b/PROTOCOL.md
new file mode 100755
index 0000000..38411be
--- /dev/null
+++ b/PROTOCOL.md
@@ -0,0 +1,32 @@
+# PROTOCOL
+
+## Protocol extensions
+As the server has to tell whether the client supports protocol extensions, the values of package 254 and 255 have been adjusted.
+Package 255 now contains "Ogar" in ASCII (1332175218) while package 254 contains the version number. When modifying the protocol,
+only new features can be implemented. Also, the client must be compatible with older versions of the server.
+
+## Changes
+Please document any changes introduced here. Direction has to be either `S2C` (server to client) or `C2S`.
+
+### Version 1
+
+
+| Direction | ID | Value | Description|
+| :------------ |:---------------| :-----|:----|
+|C2S | 254 | 1 | Version number|
+|C2S | 255 | 1332175218 | String "Ogar" - Tells the server how to use the modified protocol|
+|S2C | 48 | behaves like #49 | Leaderboard without numbers|
+|C2S | 99 | flags (uint8) [1], message | For in-game chat, each char is in Uint16 |
+|S2C | 99 | flags (uint8) [1], r (uint8), g (uint8), b (uint8), nick, '\0', message, '\0' | same as above |
+
+ [1] If flags has the 2, 4, or 8 bit set, an offset of 4, 8, or 16 bytes follows before any other data. Until these additional
+ bytes are used, just skip them.
+
+Hint : to use Packet 48, make sure the packet ID in case 48 of Ogar/src/packet/UpdateLeaderboard.js is adjusted like this:
+```
+view.setUint8(0, this.packetLB, true);
+```
+You can also use https://github.com/m-byte/Ogar, which already has this feature enabled.
+
+### Version 2
+TODO: We could add chat functionality in this version. That way, only one websocket server would be needed.
diff --git a/README.md b/README.md
old mode 100644
new mode 100755
index b79306b..065cb7a
--- a/README.md
+++ b/README.md
@@ -1,6 +1,70 @@
# agar-clone
-clone of agar.io
-You can use nginx to deploy it on your server.
+## Contents
+ - [Introduction](#introduction)
+ - [Setup](#setup)
+ - [Test and Known Issues](#test-and-known-issues)
+ - [FAQ](#faq)
+ - [Protocol Extensions](#protocol-extensions)
+ - [Contributions](#contributions)
+ - [Disclaimer](#disclaimer)
+## Introduction
+
+This is a clone of agar.io. In this project we aim to acheive the following.
+
+- [x] Hack main_out.js and make the variables and function names readable. Now most of the variable and function name should make sense.
+- [x] Add uploading custom skins features (Done)
+- [x] Add [in-game chat](https://cloud.githubusercontent.com/assets/5158896/8327532/c41e94fa-1a9b-11e5-87cc-f42b5f6ef2df.png) feature. (Done)
+- [x] Add mobile device support (Done)
+- [x] Support multi-server feature (Done in Cigar)
+
+##Setup
+
+Copy all files to a server with PHP support (e.g. LEMP/LAMP). To check whether your server supports PHP, please read [this tutorial](http://www.cyberciti.biz/faq/how-do-i-test-php-installation-with-a-phpinfo-page/).
+Once everything is set up, open index.html in your browser. If everything is working well, go to the next section to use your own Ogar server.
+
+### Support Your Server
Replace the CONNECTION_URL with your own ip and port in main_out.js
+
+### Upload Custom Skins
+The upload module does two things. The first is to upload a skin onto skins folder. The second is that the client request the server to run checkdir.php every 15 seconds to check what skins are uploaded and add them into knownNameDict. Then the skins can be loaded.
+
+To make this feature work, you need to give upload.php priviliage to read skins folder.
+
+
+```
+chmod 777 skins
+```
+
+will make it work.
+
+
+
+## Test and Known Issues
+
+This client has been tested on LEMP stack on OS X 10.10 and Ubuntu 14.04 with server side [Ogar](https://github.com/vram4/Ogar).
+
+It is known that some of the variables and function names still make no sense, we are working on that.
+
+## FAQ
+### Can agar-clone connect to the official server?
+No, agar-clone is not intended to be used with the official server. You will have to use it with [Ogar](https://github.com/forairan/Ogar) or [Cigar](https://github.com/m-byte/Cigar).
+
+### How can I use the chat feature?
+Currently, only [Cigar](https://github.com/m-byte/Cigar) supports the chat protocol. If you know of another server supporting the extended protocol, feel free to [let us know](https://github.com/Eureka22/agar-clone/issues).
+
+## Protocol extensions
+As the server has to tell whether the client supports protocol extensions, the values of package 254 and 255 have been adjusted.
+Package 255 now contains "Ogar" in ASCII (1332175218) while package 254 contains the version number. When modifying the protocol,
+only new features can be implemented. Also, the client must remain compatible with older versions of the server.
+
+Original protocol can be found [here](https://github.com/vram4/Agar.io-Protocol). Changes to the protocol have to be [documented](PROTOCOL.md).
+
+## Contributions
+
+Pull Request are welcome.
+
+## Disclaimer
+
+Note that the aim of this repo is to study agar.io client, understand the mechanism and find potential improvements. It is worth pointing out that hosting a third-party agar client is against the [Terms](http://agar.io/terms.txt) of Agario and not recommended by the owner of this repo. Please think twice before hosting the client and do it at your own risk. :)
diff --git a/Vector2.js b/Vector2.js
new file mode 100755
index 0000000..a9f403f
--- /dev/null
+++ b/Vector2.js
@@ -0,0 +1,121 @@
+var Vector2 = function(x, y) {
+ this.x = x || 0;
+ this.y = y || 0;
+};
+Vector2.prototype = {
+ reset: function(x, y) {
+ this.x = x;
+ this.y = y;
+ return this;
+ },
+ toString: function(decPlaces) {
+ decPlaces = decPlaces || 3;
+ var scalar = Math.pow(10, decPlaces);
+ return "[" + Math.round(this.x * scalar) / scalar + ", " + Math.round (this.y * scalar) / scalar + "]";
+ },
+ clone: function() {
+ return new Vector2(this.x, this.y);
+ },
+ copyTo: function(v) {
+ v.x = this.x;
+ v.y = this.y;
+ },
+ copyFrom: function(v) {
+ this.x = v.x;
+ this.y = v.y;
+ },
+ magnitude: function() {
+ return Math.sqrt((this.x * this.x) + (this.y * this.y));
+ },
+ magnitudeSquared: function() {
+ return (this.x * this.x) + (this.y * this.y);
+ },
+ normalise: function() {
+ var m = this.magnitude();
+ this.x = this.x / m;
+ this.y = this.y / m;
+ return this;
+ },
+ reverse: function() {
+ this.x =- this.x;
+ this.y =- this.y;
+ return this;
+ },
+ plusEq: function(v) {
+ this.x += v.x;
+ this.y += v.y;
+ return this;
+ },
+ plusNew: function(v) {
+ return new Vector2(this.x + v.x, this.y + v.y);
+ },
+ minusEq: function(v) {
+ this.x -= v.x;
+ this.y -= v.y;
+ return this;
+ },
+ minusNew: function(v) {
+ return new Vector2(this.x - v.x, this.y - v.y);
+ },
+ multiplyEq: function(scalar) {
+ this.x*=scalar;
+ this.y*=scalar;
+ return this;
+ },
+ multiplyNew: function(scalar) {
+ var returnvec = this.clone();
+ return returnvec.multiplyEq(scalar);
+ },
+ divideEq: function(scalar) {
+ this.x/=scalar;
+ this.y/=scalar;
+ return this;
+ },
+ divideNew: function(scalar) {
+ var returnvec = this.clone();
+ return returnvec.divideEq(scalar);
+ },
+ dot: function(v) {
+ return (this.x * v.x) + (this.y * v.y);
+ },
+ angle: function(useRadians) {
+ return Math.atan2(this.y, this.x) * (useRadians ? 1 : Vector2Const.TO_DEGREES);
+ },
+ rotate: function(angle, useRadians) {
+ var cosRY = Math.cos(angle * (useRadians ? 1 : Vector2Const.TO_RADIANS));
+ var sinRY = Math.sin(angle * (useRadians ? 1 : Vector2Const.TO_RADIANS));
+ Vector2Const.temp.copyFrom(this);
+ this.x = (Vector2Const.temp.x * cosRY) - (Vector2Const.temp.y * sinRY);
+ this.y = (Vector2Const.temp.x * sinRY) + (Vector2Const.temp.y * cosRY);
+ return this;
+ },
+ equals: function(v) {
+ return ((this.x == v.x) && (this.y == v.x));
+ },
+ isCloseTo: function(v, tolerance) {
+ if (this.equals(v))
+ return true;
+ Vector2Const.temp.copyFrom(this);
+ Vector2Const.temp.minusEq(v);
+ return (Vector2Const.temp.magnitudeSquared() < tolerance * tolerance);
+ },
+ rotateAroundPoint: function(point, angle, useRadians) {
+ Vector2Const.temp.copyFrom(this);
+ Vector2Const.temp.minusEq(point);
+ Vector2Const.temp.rotate(angle, useRadians);
+ Vector2Const.temp.plusEq(point);
+ this.copyFrom(Vector2Const.temp);
+ },
+ isMagLessThan: function(distance) {
+ return (this.magnitudeSquared() < distance * distance);
+ },
+ isMagGreaterThan: function(distance) {
+ return (this.magnitudeSquared() > distance * distance);
+ }
+};
+Vector2Const = {
+ TO_DEGREES: 180 / Math.PI,
+ TO_RADIANS: Math.PI / 180,
+ temp: new Vector2()
+};
+
diff --git a/changelog.html b/changelog.html
new file mode 100644
index 0000000..a205cb5
--- /dev/null
+++ b/changelog.html
@@ -0,0 +1,21 @@
+
+changes are recorded in this document
+
+
+
+
+
+
+日常更新(June 22):
+
+
+1.
+更新了客户端,请大家帮忙测试,如果有问题请告诉我。考完试增加更多特性请期待。
+
+
+2. 更新了"部落模式", 如果使用[部落名]用户名 例如"[526a]李小花","[ee]Richard
+Song" 之类的id, 会使用中括号里的名字作为皮肤, 玩家可以上传皮肤。
+预告: 近期将开启皮肤图片库功能,另外上传和背景色相同的图片将会被禁止。
+
+
+
diff --git a/feed.png b/feed.png
new file mode 100644
index 0000000..d12531a
Binary files /dev/null and b/feed.png differ
diff --git a/gallery/img.php b/gallery/img.php
new file mode 100755
index 0000000..8947946
--- /dev/null
+++ b/gallery/img.php
@@ -0,0 +1,814 @@
+
+*/
+
+/*
+$sizeLimits = array(
+ "100x100",
+ "150x150",
+);
+
+error_reporting(E_ALL);
+ini_set("display_errors", 1);
+*/
+
+// check to see if GD function exist
+if(!function_exists('imagecreatetruecolor')) {
+ displayError('GD Library Error: imagecreatetruecolor does not exist - please contact your webhost and ask them to install the GD library');
+}
+
+define ('CACHE_SIZE', 250); // number of files to store before clearing cache
+define ('CACHE_CLEAR', 5); // maximum number of files to delete on each cache clear
+define ('VERSION', '1.14'); // version number (to force a cache refresh)
+define ('DIRECTORY_CACHE', './cache'); // cache directory
+define ('DIRECTORY_TEMP', './temp'); // temp directory
+
+if (function_exists('imagefilter') && defined('IMG_FILTER_NEGATE')) {
+ $imageFilters = array(
+ "1" => array(IMG_FILTER_NEGATE, 0),
+ "2" => array(IMG_FILTER_GRAYSCALE, 0),
+ "3" => array(IMG_FILTER_BRIGHTNESS, 1),
+ "4" => array(IMG_FILTER_CONTRAST, 1),
+ "5" => array(IMG_FILTER_COLORIZE, 4),
+ "6" => array(IMG_FILTER_EDGEDETECT, 0),
+ "7" => array(IMG_FILTER_EMBOSS, 0),
+ "8" => array(IMG_FILTER_GAUSSIAN_BLUR, 0),
+ "9" => array(IMG_FILTER_SELECTIVE_BLUR, 0),
+ "10" => array(IMG_FILTER_MEAN_REMOVAL, 0),
+ "11" => array(IMG_FILTER_SMOOTH, 0),
+ );
+}
+
+// sort out image source
+$src = get_request("src", "");
+if($src == '' || strlen($src) <= 3) {
+ displayError ('no image specified');
+}
+
+// clean params before use
+$src = cleanSource($src);
+// last modified time (for caching)
+$lastModified = filemtime($src);
+
+// get properties
+$new_width = preg_replace("/[^0-9]+/", '', get_request('w', 0));
+$new_height = preg_replace("/[^0-9]+/", '', get_request('h', 0));
+$zoom_crop = preg_replace("/[^0-9]+/", '', get_request('zc', 1));
+$quality = preg_replace("/[^0-9]+/", '', get_request('q', 80));
+$filters = get_request('f', '');
+$align = get_request ('a', 'c');
+$sharpen = get_request('s', 0);
+
+if ($new_width == 0 && $new_height == 0) {
+ $new_width = 100;
+ $new_height = 100;
+}
+
+// get mime type of src
+$mime_type = mime_type($src);
+
+// check to see if this image is in the cache already
+check_cache ($mime_type);
+
+// if not in cache then clear some space and generate a new file
+cleanCache();
+
+ini_set('memory_limit', '50M');
+
+// make sure that the src is gif/jpg/png
+if(!valid_src_mime_type($mime_type)) {
+ displayError('Invalid src mime type: ' . $mime_type);
+}
+
+if(strlen($src) && file_exists($src)) {
+
+ // open the existing image
+ $image = open_image($mime_type, $src);
+ if($image === false) {
+ displayError('Unable to open image : ' . $src);
+ }
+
+ // Get original width and height
+ $width = imagesx($image);
+ $height = imagesy($image);
+
+ // generate new w/h if not provided
+ if( $new_width && !$new_height ) {
+
+ $new_height = $height * ( $new_width / $width );
+
+ } elseif($new_height && !$new_width) {
+
+ $new_width = $width * ( $new_height / $height );
+
+ } elseif(!$new_width && !$new_height) {
+
+ $new_width = $width;
+ $new_height = $height;
+
+ }
+
+
+
+ // create a new true color image
+ $canvas = imagecreatetruecolor( $new_width, $new_height );
+ imagealphablending($canvas, false);
+ // Create a new transparent color for image
+ $color = imagecolorallocatealpha($canvas, 0, 0, 0, 127);
+ // Completely fill the background of the new image with allocated color.
+ imagefill($canvas, 0, 0, $color);
+ // Restore transparency blending
+ imagesavealpha($canvas, true);
+
+ if( $zoom_crop ) {
+
+ $src_x = $src_y = 0;
+ $src_w = $width;
+ $src_h = $height;
+
+ $cmp_x = $width / $new_width;
+ $cmp_y = $height / $new_height;
+
+ // calculate x or y coordinate and width or height of source
+
+ if ( $cmp_x > $cmp_y ) {
+
+ $src_w = round( ( $width / $cmp_x * $cmp_y ) );
+ $src_x = round( ( $width - ( $width / $cmp_x * $cmp_y ) ) / 2 );
+
+ } elseif ( $cmp_y > $cmp_x ) {
+
+ $src_h = round( ( $height / $cmp_y * $cmp_x ) );
+ $src_y = round( ( $height - ( $height / $cmp_y * $cmp_x ) ) / 2 );
+
+ }
+
+ // positional cropping!
+
+ switch ($align) {
+
+ case 't':
+
+ case 'tl':
+
+ case 'lr':
+
+ case 'tr':
+
+ case 'rt':
+
+ $src_y = 0;
+ break;
+
+
+
+ case 'b':
+
+ case 'bl':
+
+ case 'lb':
+
+ case 'br':
+
+ case 'rb':
+
+ $src_y = $height - $src_h;
+ break;
+
+
+
+ case 'l':
+
+ case 'tl':
+
+ case 'lt':
+
+ case 'bl':
+
+ case 'lb':
+
+ $src_x = 0;
+ break;
+
+ case 'r':
+
+ case 'tr':
+
+ case 'rt':
+
+ case 'br':
+
+ case 'rb':
+
+ $src_x = $width - $new_width;
+ $src_x = $width - $src_w;
+
+ break;
+
+ default:
+ break;
+ }
+
+
+ imagecopyresampled( $canvas, $image, 0, 0, $src_x, $src_y, $new_width, $new_height, $src_w, $src_h );
+
+ } else {
+
+ // copy and resize part of an image with resampling
+ imagecopyresampled( $canvas, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height );
+
+ }
+
+ if ($filters != '' && function_exists('imagefilter') && defined('IMG_FILTER_NEGATE')) {
+ // apply filters to image
+ $filterList = explode("|", $filters);
+ foreach($filterList as $fl) {
+ $filterSettings = explode(",", $fl);
+ if(isset($imageFilters[$filterSettings[0]])) {
+
+ for($i = 0; $i < 4; $i ++) {
+ if(!isset($filterSettings[$i])) {
+ $filterSettings[$i] = null;
+ }
+ }
+
+ switch($imageFilters[$filterSettings[0]][1]) {
+
+ case 1:
+
+ imagefilter($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1]);
+ break;
+
+ case 2:
+
+ imagefilter($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2]);
+ break;
+
+ case 3:
+
+ imagefilter($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3]);
+ break;
+
+ default:
+
+ imagefilter($canvas, $imageFilters[$filterSettings[0]][0]);
+ break;
+
+ }
+ }
+ }
+ }
+
+ if ($sharpen > 0 && function_exists('imageconvolution')) {
+
+ $sharpenMatrix = array(
+ array(-1,-1,-1),
+ array(-1,16,-1),
+ array(-1,-1,-1),
+ );
+ $divisor = 8;
+ $offset = 0;
+
+ imageconvolution($canvas, $sharpenMatrix, $divisor, $offset);
+
+ }
+
+ // output image to browser based on mime type
+ show_image($mime_type, $canvas);
+
+ // remove image from memory
+ imagedestroy($canvas);
+
+} else {
+
+ if (strlen($src)) {
+ displayError ('image ' . $src . ' not found');
+ } else {
+ displayError ('no source specified');
+ }
+
+}
+
+/**
+ *
+ */
+function show_image($mime_type, $image_resized) {
+
+ global $quality;
+
+ // check to see if we can write to the cache directory
+ $is_writable = 0;
+ $cache_file_name = DIRECTORY_CACHE . '/' . get_cache_file();
+
+ if (touch($cache_file_name)) {
+
+ // give 666 permissions so that the developer
+ // can overwrite web server user
+ chmod ($cache_file_name, 0666);
+ $is_writable = 1;
+
+ } else {
+
+ $cache_file_name = NULL;
+ header ('Content-type: ' . $mime_type);
+
+ }
+
+ switch ($mime_type) {
+
+ case 'image/jpeg':
+ imagejpeg($image_resized, $cache_file_name, $quality);
+ break;
+
+ default :
+ $quality = floor ($quality * 0.09);
+ imagepng($image_resized, $cache_file_name, $quality);
+
+ }
+
+ if ($is_writable) {
+ show_cache_file ($mime_type);
+ }
+
+ imagedestroy ($image_resized);
+
+ displayError ('error showing image');
+
+}
+
+/**
+ *
+ */
+function get_request( $property, $default = 0 ) {
+
+ if( isset($_REQUEST[$property]) ) {
+
+ return $_REQUEST[$property];
+
+ } else {
+
+ return $default;
+
+ }
+
+}
+
+/**
+ *
+ */
+function open_image($mime_type, $src) {
+
+ $mime_type = strtolower($mime_type);
+
+ if (stristr ($mime_type, 'gif')) {
+
+ $image = imagecreatefromgif($src);
+
+ } elseif (stristr($mime_type, 'jpeg')) {
+
+ @ini_set ('gd.jpeg_ignore_warning', 1);
+ $image = imagecreatefromjpeg($src);
+
+ } elseif (stristr ($mime_type, 'png')) {
+
+ $image = imagecreatefrompng($src);
+
+ }
+
+ return $image;
+
+}
+
+/**
+ * clean out old files from the cache
+ * you can change the number of files to store and to delete per loop in the defines at the top of the code
+ */
+function cleanCache() {
+
+ $files = glob("cache/*", GLOB_BRACE);
+
+ if (count($files) > 0) {
+
+ $yesterday = time() - (24 * 60 * 60);
+
+ usort($files, 'filemtime_compare');
+ $i = 0;
+
+ if (count($files) > CACHE_SIZE) {
+
+ foreach ($files as $file) {
+
+ $i ++;
+
+ if ($i >= CACHE_CLEAR) {
+ return;
+ }
+
+ if (@filemtime($file) > $yesterday) {
+ return;
+ }
+
+ if (file_exists($file)) {
+ unlink($file);
+ }
+
+ }
+
+ }
+
+ }
+
+}
+
+
+/**
+ * compare the file time of two files
+ */
+function filemtime_compare($a, $b) {
+
+ return filemtime($a) - filemtime($b);
+
+}
+
+
+/**
+ * determine the file mime type
+ */
+function mime_type($file) {
+
+ if (stristr(PHP_OS, 'WIN')) {
+ $os = 'WIN';
+ } else {
+ $os = PHP_OS;
+ }
+
+ $mime_type = '';
+
+ if (function_exists('mime_content_type') && $os != 'WIN') {
+ $mime_type = mime_content_type($file);
+ }
+
+ // use PECL fileinfo to determine mime type
+ if (!valid_src_mime_type($mime_type)) {
+ if (function_exists('finfo_open')) {
+ $finfo = @finfo_open(FILEINFO_MIME);
+ if ($finfo != '') {
+ $mime_type = finfo_file($finfo, $file);
+ finfo_close($finfo);
+ }
+ }
+ }
+
+ // try to determine mime type by using unix file command
+ // this should not be executed on windows
+ if (!valid_src_mime_type($mime_type) && $os != "WIN") {
+ if (preg_match("/FreeBSD|FREEBSD|LINUX/", $os)) {
+ $mime_type = trim(@shell_exec('file -bi ' . escapeshellarg($file)));
+ }
+ }
+
+ // use file's extension to determine mime type
+ if (!valid_src_mime_type($mime_type)) {
+
+ // set defaults
+ $mime_type = 'image/png';
+ // file details
+ $fileDetails = pathinfo($file);
+ $ext = strtolower($fileDetails["extension"]);
+ // mime types
+ $types = array(
+ 'jpg' => 'image/jpeg',
+ 'jpeg' => 'image/jpeg',
+ 'png' => 'image/png',
+ 'gif' => 'image/gif'
+ );
+
+ if (strlen($ext) && strlen($types[$ext])) {
+ $mime_type = $types[$ext];
+ }
+
+ }
+
+ return $mime_type;
+
+}
+
+
+/**
+ *
+ */
+function valid_src_mime_type($mime_type) {
+
+ if (preg_match("/jpg|jpeg|gif|png/i", $mime_type)) {
+ return true;
+ }
+
+ return false;
+
+}
+
+
+/**
+ *
+ */
+function check_cache ($mime_type) {
+
+ // make sure cache dir exists
+ if (!file_exists(DIRECTORY_CACHE)) {
+ // give 777 permissions so that developer can overwrite
+ // files created by web server user
+ mkdir(DIRECTORY_CACHE);
+ chmod(DIRECTORY_CACHE, 0777);
+ }
+
+ show_cache_file ($mime_type);
+
+}
+
+
+/**
+ *
+ */
+function show_cache_file ($mime_type) {
+
+ $cache_file = DIRECTORY_CACHE . '/' . get_cache_file();
+
+ if (file_exists($cache_file)) {
+
+ $gmdate_mod = gmdate("D, d M Y H:i:s", filemtime($cache_file));
+
+ if(! strstr($gmdate_mod, "GMT")) {
+ $gmdate_mod .= " GMT";
+ }
+
+ if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])) {
+
+ // check for updates
+ $if_modified_since = preg_replace ("/;.*$/", "", $_SERVER["HTTP_IF_MODIFIED_SINCE"]);
+
+ if ($if_modified_since == $gmdate_mod) {
+ header("HTTP/1.1 304 Not Modified");
+ die();
+ }
+
+
+
+
+ }
+
+ $fileSize = filesize ($cache_file);
+
+ $buffer = file_get_contents($cache_file);
+
+ ob_get_clean();
+ ob_start();
+
+
+
+ header ('Last-Modified: ' . $gmdate_mod);
+ header ('Cache-Control: max-age=9999, must-revalidate');
+ header ('Expires: ' . $gmdate_mod);
+ header ('Accept-Ranges: bytes');
+ header ('Content-Type: ' . $mime_type);
+ header ('Content-Length: ' . $fileSize);
+
+ echo $buffer;
+ $sContents = ob_get_contents();
+ ob_end_clean();
+ echo $sContents;
+ }
+
+}
+
+
+/**
+ *
+ */
+function get_cache_file() {
+
+ global $lastModified;
+ static $cache_file;
+
+ if (!$cache_file) {
+ $cachename = $_SERVER['QUERY_STRING'] . VERSION . $lastModified;
+ $cache_file = md5($cachename) . '.png';
+ }
+
+ return $cache_file;
+
+}
+
+
+/**
+ * check to if the url is valid or not
+ */
+function valid_extension ($ext) {
+
+ if (preg_match("/jpg|jpeg|png|gif/i", $ext)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+
+}
+
+
+/**
+ *
+ */
+function checkExternal ($src) {
+
+ $allowedSites = array(
+ 'flickr.com',
+ 'picasa.com',
+ 'blogger.com',
+ 'wordpress.com',
+ 'img.youtube.com',
+ );
+
+ if (preg_match('/http:\/\//', $src) == true) {
+
+ $url_info = parse_url ($src);
+
+ $isAllowedSite = false;
+ foreach ($allowedSites as $site) {
+ $site = '/' . addslashes($site) . '/';
+ if (preg_match($site, $url_info['host']) == true) {
+ $isAllowedSite = true;
+ }
+ }
+
+ if ($isAllowedSite) {
+
+ $fileDetails = pathinfo($src);
+ $ext = strtolower($fileDetails['extension']);
+
+ $filename = md5($src);
+ $local_filepath = DIRECTORY_TEMP . '/' . $filename . '.' . $ext;
+
+ if (!file_exists($local_filepath)) {
+
+ if (function_exists('curl_init')) {
+
+ $fh = fopen($local_filepath, 'w');
+ $ch = curl_init($src);
+
+ curl_setopt($ch, CURLOPT_URL, $src);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
+ curl_setopt($ch, CURLOPT_HEADER, 0);
+ curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0');
+ curl_setopt($ch, CURLOPT_FILE, $fh);
+
+ if (curl_exec($ch) === FALSE) {
+ if (file_exists($local_filepath)) {
+ unlink($local_filepath);
+ }
+ displayError('error reading file ' . $src . ' from remote host: ' . curl_error($ch));
+ }
+
+ curl_close($ch);
+ fclose($fh);
+
+ } else {
+
+ if (!$img = file_get_contents($src)) {
+ displayError('remote file for ' . $src . ' can not be accessed. It is likely that the file permissions are restricted');
+ }
+
+ if (file_put_contents($local_filepath, $img) == FALSE) {
+ displayError('error writing temporary file');
+ }
+
+ }
+
+ if (!file_exists($local_filepath)) {
+ displayError('local file for ' . $src . ' can not be created');
+ }
+
+ }
+
+ $src = $local_filepath;
+
+ } else {
+
+ displayError('remote host "' . $url_info['host'] . '" not allowed');
+
+ }
+
+ }
+
+ return $src;
+
+}
+
+
+/**
+ * tidy up the image source url
+ */
+function cleanSource($src) {
+
+ $host = str_replace('www.', '', $_SERVER['HTTP_HOST']);
+ $regex = "/^((ht|f)tp(s|):\/\/)(www\.|)" . $host . "/i";
+
+ $src = preg_replace ($regex, '', $src);
+ $src = strip_tags ($src);
+ $src = checkExternal ($src);
+
+ // remove slash from start of string
+ if (strpos($src, '/') === 0) {
+ $src = substr ($src, -(strlen($src) - 1));
+ }
+
+ // don't allow users the ability to use '../'
+ // in order to gain access to files below document root
+ $src = preg_replace("/\.\.+\//", "", $src);
+
+ // get path to image on file system
+ $src = get_document_root($src) . '/' . $src;
+
+ return $src;
+
+}
+
+
+/**
+ *
+ */
+function get_document_root ($src) {
+
+ // check for unix servers
+ if(file_exists($_SERVER['DOCUMENT_ROOT'] . '/' . $src)) {
+ return $_SERVER['DOCUMENT_ROOT'];
+ }
+
+ // check from script filename (to get all directories to timthumb location)
+ $parts = array_diff(explode('/', $_SERVER['SCRIPT_FILENAME']), explode('/', $_SERVER['DOCUMENT_ROOT']));
+ $path = $_SERVER['DOCUMENT_ROOT'];
+ foreach ($parts as $part) {
+ $path .= '/' . $part;
+ if (file_exists($path . '/' . $src)) {
+ return $path;
+ }
+ }
+
+ // the relative paths below are useful if timthumb is moved outside of document root
+ // specifically if installed in wordpress themes like mimbo pro:
+ // /wp-content/themes/mimbopro/scripts/timthumb.php
+ $paths = array(
+ ".",
+ "..",
+ "../..",
+ "../../..",
+ "../../../..",
+ "../../../../.."
+ );
+
+ foreach ($paths as $path) {
+ if(file_exists($path . '/' . $src)) {
+ return $path;
+ }
+ }
+
+ // special check for microsoft servers
+ if (!isset($_SERVER['DOCUMENT_ROOT'])) {
+ $path = str_replace("/", "\\", $_SERVER['ORIG_PATH_INFO']);
+ $path = str_replace($path, "", $_SERVER['SCRIPT_FILENAME']);
+
+ if (file_exists($path . '/' . $src)) {
+ return $path;
+ }
+ }
+
+ displayError('file not found ' . $src);
+
+}
+
+
+/**
+ * generic error message
+ */
+function displayError ($errorString = '') {
+
+ header('HTTP/1.1 400 Bad Request');
+ echo '
' . $errorString . ' TimThumb version : ' . VERSION . '
';
+ die();
+
+}
+?>
+?>
\ No newline at end of file
diff --git a/gallery/index.php b/gallery/index.php
new file mode 100755
index 0000000..087c7d5
--- /dev/null
+++ b/gallery/index.php
@@ -0,0 +1,73 @@
+
+
+
+
+Gallery from Folder Demo
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/uploads.html b/uploads.html
new file mode 100644
index 0000000..3bb8723
--- /dev/null
+++ b/uploads.html
@@ -0,0 +1,10 @@
+
+
+
+
+ upload avatar picture, for example, if your name is foo in the game, name your file as foo.png (less than 2M, currently only english is supported, use png), your avatar will appear
+
+
+
+
+
diff --git a/uploads.php b/uploads.php
new file mode 100644
index 0000000..704f864
--- /dev/null
+++ b/uploads.php
@@ -0,0 +1,63 @@
+ 500000) {
+ echo "Sorry, your file is too large.";
+ $uploadOk = 0;
+}
+// Allow certain file formats
+if($imageFileType != "png" ) {
+ echo "Sorry, only PNG files are allowed.";
+ $uploadOk = 0;
+
+
+}
+
+
+if(preg_match('/^[a-zA-Z0-9-]+$/', $filname_without_ext)) {
+ // .. upload
+} else {
+ echo 'The file "' . $file . '"was not uploaded. The file can only contain "A-Z", "a-z", "0-9" and "-". ';
+ $uploadOk = 0;
+}
+
+
+// Check if $uploadOk is set to 0 by an error
+if ($uploadOk == 0) {
+ echo "Sorry, your file was not uploaded.";
+// if everything is ok, try to upload file
+} else {
+ if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
+ echo "The file ". basename( $_FILES["fileToUpload"]["name"]). " has been uploaded.";
+ } else {
+ echo "Sorry, there was an error uploading your file.";
+ }
+
+
+
+}
+
+echo "Go Back";
+?>