commit 56db58f650531a22494261fca7b2b765992f4adf Author: VirtuBrick <139835327+VirtuBrick@users.noreply.github.com> Date: Sat Jan 20 11:51:59 2024 -0500 first commit diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..cc095d7 --- /dev/null +++ b/.htaccess @@ -0,0 +1,43 @@ +ErrorDocument 404 /core/views/error/notfound.php +ErrorDocument 403 /core/views/error/notfound.php + +RewriteEngine On +RewriteRule ^user/dashboard/?(.*)$ /core/views/user/dashboard.php [L] +RewriteRule ^user/settings/?(.*)$ /core/views/user/settings.php [L] +RewriteRule ^user/messages/?(.*)$ /core/views/user/messages.php [L] +RewriteRule ^blog/?(.*)$ /core/views/blog/main.php [L] +RewriteRule ^user/online/?(.*)$ /core/views/online.php [L] +RewriteRule ^users/([^/]+)/?$ /core/views/users.php?term=$1 [L,QSA] +RewriteRule ^users/?(.*)$ /core/views/users.php [L] +RewriteRule ^admin/ban/?(.*)$ /core/views/admin/ban.php [L] +RewriteRule ^admin/reports/?(.*)$ /core/views/admin/reports.php [L] +RewriteRule ^admin/statistics/?(.*)$ /core/views/admin/statistics.php [L] +RewriteRule ^admin/assets/?(.*)$ /core/views/admin/assets.php [L] +RewriteRule ^admin/unban/?(.*)$ /core/views/admin/unban.php [L] +RewriteRule ^admin/newHat/?(.*)$ /core/views/admin/newHat.php [L] +RewriteRule ^admin/rewardPostie/?(.*)$ /core/views/admin/rewardPostie.php [L] +RewriteRule ^admin/prune/?(.*)$ /core/views/admin/prune.php [L] +RewriteRule ^admin/?(.*)$ /core/views/admin/main.php [L] +RewriteRule ^groups/search/([^/]+)/?$ /core/views/user/groups/search.php?term=$1 [L,QSA] +RewriteRule ^groups/search/?(.*)$ /core/views/user/groups/search.php [L] +RewriteRule ^groups/create/?(.*)$ /core/views/user/groups/create.php [L] +RewriteRule ^groups/view/([^/]+)/?$ /core/views/user/groups/view.php?id=$1 [L,QSA] +RewriteRule ^groups/admin/([^/]+)/?$ /core/views/user/groups/admin.php?id=$1 [L,QSA] +RewriteRule ^groups/?(.*)$ /core/views/user/groups/main.php [L] +RewriteRule ^user/character/?(.*)$ /core/views/user/character.php [L] +RewriteRule ^user/logout/?(.*)$ /core/views/user/logout.php [L] +RewriteRule ^forum/?(.*)$ /core/views/forum/index.php [L] +RewriteRule ^games/new/?(.*)$ /core/views/games/new.php [L] +RewriteRule ^games/view/([^/]+)/?$ /core/views/games/view.php?id=$1 [L,QSA] +RewriteRule ^games/?(.*)$ /core/views/games/main.php [L] +RewriteRule ^account/suspended?(.*)$ /core/views/user/security/banned.php [L] +RewriteRule ^account/resetpassword/([^/]+)/([^/]+)/?$ /core/views/user/security/resetpassword.php?userid=$1&key=$2 [L,QSA] +RewriteRule ^account/verification/email?(.*)$ /core/views/user/security/verifyEmail.php [L] +RewriteRule ^account/verification/twostepauth?(.*)$ /core/views/user/security/twostepauth.php [L] +RewriteRule ^catalog/?$ /core/views/catalog/main.php [L] +RewriteRule ^catalog/upload/?$ /core/views/catalog/upload.php [L] +RewriteRule ^catalog/item/([^/]+)/?$ /core/views/catalog/item.php?id=$1 [L,QSA] +RewriteRule ^user/profile/([^/]+)/?$ /core/views/user/profile.php?username=$1 [L,QSA] +RewriteRule ^friends/?$ /core/views/friends/main.php [L] +RewriteRule ^friends/requests/?$ /core/views/friends/requests.php [L] +RewriteRule ^friends/show/([^/]+)/?$ /core/views/friends/show.php?id=$1 [L,QSA] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..32aaae2 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +### Graphictoria Website +This is what used to be Graphictoria 4's website. Keep in mind that the code is quite disgusting. This in no way represents how I develop websites nowadays. diff --git a/core/func/api/account/getNotifications.php b/core/func/api/account/getNotifications.php new file mode 100644 index 0000000..577e96e --- /dev/null +++ b/core/func/api/account/getNotifications.php @@ -0,0 +1,10 @@ + diff --git a/core/func/api/account/liftBan.php b/core/func/api/account/liftBan.php new file mode 100644 index 0000000..a3a0293 --- /dev/null +++ b/core/func/api/account/liftBan.php @@ -0,0 +1,40 @@ + 1440) { + security::liftBan(); + }else{ + security::returnLiftError(); + } + } + if ($GLOBALS['userTable']['bantype'] == 3) { + if ($timeSince > 10080) { + security::liftBan(); + }else{ + security::returnLiftError(); + } + } + if ($GLOBALS['userTable']['bantype'] == 4) { + if ($timeSince > 43200) { + security::liftBan(); + }else{ + security::returnLiftError(); + } + } + }else{ + die("error"); + } + }else{ + die("error"); + } +?> \ No newline at end of file diff --git a/core/func/api/admin/get/getAssets.php b/core/func/api/admin/get/getAssets.php new file mode 100644 index 0000000..fbd6b2d --- /dev/null +++ b/core/func/api/admin/get/getAssets.php @@ -0,0 +1,30 @@ +prepare("SELECT * FROM catalog WHERE approved = 0 AND declined = 0;"); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo '

There are no pending assets to approve at this moment.

'; + } + $count = 0; + foreach($stmt as $result) { + $itemName = htmlentities($result['name'], ENT_QUOTES, "UTF-8"); + if (strlen($itemName) > 16) { + $itemName = substr($itemName, 0, 7) . '...'; + } + echo '
'.$itemName.'
'; + $creator = $result['creator_uid']; + $stmt = $dbcon->prepare("SELECT username FROM users WHERE id=:id;"); + $stmt->bindParam(':id', $creator, PDO::PARAM_INT); + $stmt->execute(); + $result2 = $stmt->fetch(PDO::FETCH_ASSOC); + $username = $result2['username']; + echo '
Type : '.$result['type'].'
Uploaded by '.$username.'
'; + } +?> \ No newline at end of file diff --git a/core/func/api/admin/post/approveAsset.php b/core/func/api/admin/post/approveAsset.php new file mode 100644 index 0000000..14bb195 --- /dev/null +++ b/core/func/api/admin/post/approveAsset.php @@ -0,0 +1,70 @@ +prepare("SELECT * FROM catalog WHERE id=:id;"); + $stmt->bindParam(':id', $itemID, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'error'; + exit; + } + + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $assetID = $result['assetid']; + $type = $result['type']; + $creatorID = $result['creator_uid']; + $assetName = $result['name']; + + if ($result['approved'] == 0 and $result['declined'] == 0) { + $stmt = $GLOBALS['dbcon']->prepare("UPDATE catalog SET approved = 1 WHERE id=:id"); + $stmt->bindParam(':id', $itemID, PDO::PARAM_INT); + $stmt->execute(); + + if ($type == "shirts" or $type == "pants" or $type == "tshirts") { + $query = "INSERT INTO renders (`render_id`, `type`) VALUES (:id, :dbtype);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $assetID, PDO::PARAM_INT); + $stmt->bindParam(':dbtype', $type, PDO::PARAM_STR); + $stmt->execute(); + } + + if ($type != "decals") { + $query = "INSERT INTO ownedItems (`uid`, `catalogid`, `type`) VALUES (:uid, :catid, :type);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $creatorID, PDO::PARAM_INT); + $stmt->bindParam(':catid', $itemID, PDO::PARAM_INT); + $stmt->bindParam(':type', $type, PDO::PARAM_STR); + $stmt->execute(); + } + + if ($type != "decals") { + $message = 'Your asset named '.$assetName.' has been approved and can be seen in the catalog. You also have received the item in your inventory. Your item can be found at https://xdiscuss.net/catalog/item/'.$itemID; + }else{ + $message = 'Your asset named '.$assetName.' has been approved and can be seen in the catalog. Your item can be found at https://xdiscuss.net/catalog/item/'.$itemID; + } + + $title = 'Asset Approval result for '.$assetName; + $query = "INSERT INTO messages (`recv_uid`, `sender_uid`, `title`, `content`) VALUES (:userId2, 10370, :title, :msg);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':userId2', $creatorID, PDO::PARAM_INT); + $stmt->bindParam(':msg', $message, PDO::PARAM_STR); + $stmt->bindParam(':title', $title, PDO::PARAM_STR); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'error'; + } + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/admin/post/banUser.php b/core/func/api/admin/post/banUser.php new file mode 100644 index 0000000..b7ff944 --- /dev/null +++ b/core/func/api/admin/post/banUser.php @@ -0,0 +1,104 @@ + 5) die("invalid-duration"); + + if (strtolower($username) == strtolower($GLOBALS['userTable']['username'])) { + echo 'can-not-ban-yourself'; + exit; + } + + if (strlen($banReason) > 512) { + echo 'reason-too-long'; + exit; + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT id, rank, banned, email, username FROM users WHERE username=:uname;"); + $stmt->bindParam(':uname', $username, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'no-user'; + exit; + } + + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $email = $result['email']; + $udb = $result['username']; + if ($GLOBALS['userTable']['rank'] == 1) { + if ($result['rank'] == 1) { + echo 'can-not-ban-user'; + exit; + } + }else{ + if ($result['rank'] > 0) { + echo 'can-not-ban-user'; + exit; + } + } + + if ($result['banned'] == 1) { + echo 'user-already-banned'; + exit; + } + + $query = "UPDATE `users` SET `banned`=1 WHERE `username`=:uname;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uname', $username, PDO::PARAM_STR); + $stmt->execute(); + + $query = "UPDATE `users` SET `bantype`=:type WHERE `username`=:uname;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uname', $username, PDO::PARAM_STR); + $stmt->bindParam(':type', $duration, PDO::PARAM_STR); + $stmt->execute(); + + $query = "UPDATE `users` SET `banreason`=:reason WHERE `username`=:uname;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uname', $username, PDO::PARAM_STR); + $stmt->bindParam(':reason', $banReason, PDO::PARAM_STR); + $stmt->execute(); + + $query = "UPDATE `users` SET `bantime`=NOW() WHERE `username`=:uname;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uname', $username, PDO::PARAM_STR); + $stmt->execute(); + + // Get userID + $query = "SELECT id FROM users WHERE username = :uname"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uname', $username, PDO::PARAM_STR); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $userID = $result['id']; + + $query = "INSERT INTO `banlogs` (`banned_by_uid`, `banned_by_uname`, `banned_uid`, `banned_uname`, `reason`, `bantype`) VALUES (:bannedbyuid, :bannedbyuname, :banneduid, :banneduname, :reason, :bantype);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':bannedbyuid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':bannedbyuname', $GLOBALS['userTable']['username'], PDO::PARAM_STR); + $stmt->bindParam(':banneduid', $userID, PDO::PARAM_INT); + $stmt->bindParam(':banneduname', $username, PDO::PARAM_STR); + $stmt->bindParam(':reason', $banReason, PDO::PARAM_STR); + $stmt->bindParam(':bantype', $duration, PDO::PARAM_INT); + $stmt->execute(); + + context::sendDiscordMessage(":first_place: ".$GLOBALS['userTable']['username']." has banned **".$username."** for reason **".$banReason."** (banType=".$duration.")"); + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/admin/post/denyAsset.php b/core/func/api/admin/post/denyAsset.php new file mode 100644 index 0000000..9f5ff5e --- /dev/null +++ b/core/func/api/admin/post/denyAsset.php @@ -0,0 +1,52 @@ +prepare("SELECT * FROM catalog WHERE id=:id;"); + $stmt->bindParam(':id', $itemID, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $assetID = $result['assetid']; + $type = $result['type']; + $creatorID = $result['creator_uid']; + $assetName = $result['name']; + $fileHash = $result['fileHash']; + + if ($result['approved'] == 0 and $result['declined'] == 0) { + $stmt = $GLOBALS['dbcon']->prepare("UPDATE catalog SET declined = 1 WHERE id=:id"); + $stmt->bindParam(':id', $itemID, PDO::PARAM_INT); + $stmt->execute(); + + if ($result['type'] == "tshirts" || $result['type'] == "shirts" || $result['type'] == "pants" || $result['type'] == "decals") { + @unlink($_SERVER['DOCUMENT_ROOT'].'/data/assets/uploads/'.$result['fileHash']); + } + + $query = "INSERT INTO badHashes (`hash`) VALUES (:hash);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':hash', $fileHash, PDO::PARAM_STR); + $stmt->execute(); + + $message = 'Your asset named '.$assetName.' has been denied because it violated our rules. You have not been refunded.'; + $title = 'Asset Approval result for '.$assetName; + $query = "INSERT INTO messages (`recv_uid`, `sender_uid`, `title`, `content`) VALUES (:userId2, 10370, :title, :msg);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':userId2', $creatorID, PDO::PARAM_INT); + $stmt->bindParam(':msg', $message, PDO::PARAM_STR); + $stmt->bindParam(':title', $title, PDO::PARAM_STR); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'error'; + } + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/admin/post/newHat.php b/core/func/api/admin/post/newHat.php new file mode 100644 index 0000000..0f60322 --- /dev/null +++ b/core/func/api/admin/post/newHat.php @@ -0,0 +1,154 @@ + 50) { + echo 'name-too-long'; + exit; + } + + if (strlen($datafileName) > 50) { + echo 'datafilename-too-long'; + exit; + } + + if (strlen($hatDescription) > 128) { + echo 'description-too-long'; + exit; + } + // Validate some things like, force price to be an integer and such + if ($isBuyable != "true" && $isBuyable != "false") { + echo 'illegal-buyable'; + exit; + } + + if ($isBuyable != "false") { + $buyable = 1; + }else{ + $buyable = 0; + } + + if ($rbxasset != "false") { + $rbxassetv = 1; + }else{ + $rbxassetv = 0; + } + + if (is_numeric($hatPrice) == false && $hatPrice != 0 || $hatPrice < 1) die("price-too-low"); + + // Check if the datafile name is in use (if this fails, there are several other checks in place) + $stmt = $GLOBALS['dbcon']->prepare("SELECT id FROM catalog WHERE datafile=:dfile"); + $stmt->bindParam(':dfile', $datafileName, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + echo 'datafile-mesh-already-exists'; + exit; + } + + // Now move on to the files part, where the upload happens + // Check if the meshfile is a text file as meshes are pretty much text files + $finfo = finfo_open(FILEINFO_MIME_TYPE); + $mime = finfo_file($finfo, $_FILES['meshFile']['tmp_name']); + if ($mime != "text/plain") { + echo 'meshfile-illegalFileType'; + exit; + } + + // Move the file if it is a text/mesh file. + $uploadDirectory_meshFile = $_SERVER['DOCUMENT_ROOT'].'/data/assets/hats/mesh/'; + $uploadDirectory_modelFile = $_SERVER['DOCUMENT_ROOT'].'/data/assets/hats/models/'; + $uploadDirectory_textureFile = $_SERVER['DOCUMENT_ROOT'].'/data/assets/hats/texture/'; + if (!file_exists($uploadDirectory_meshFile.$datafileName)) { + if (!move_uploaded_file($_FILES["meshFile"]["tmp_name"], $uploadDirectory_meshFile.$datafileName)) { + echo 'file-upload-error'; + exit; + } + }else{ + echo 'datafile-mesh-already-exists'; + exit; + } + + // Parse the XML file (or model file) + if (!file_exists($uploadDirectory_modelFile.$datafileName)) { + $XMLFile = fopen($uploadDirectory_modelFile.$datafileName, "w") or die("file-upload-error"); + fwrite($XMLFile, $xmlContent); + fclose($XMLFile); + }else{ + echo 'datafile-mesh-already-exists'; + exit; + } + + // Now parse the texture file + $check = @getimagesize($_FILES["textureFile"]["tmp_name"]); + if (!$check) { + echo 'texture-illegalFileType'; + exit; + } + + $imageFileType = pathinfo($_FILES['textureFile']["name"], PATHINFO_EXTENSION); + $finfo = finfo_open(FILEINFO_MIME_TYPE); + $mime = finfo_file($finfo, $_FILES['textureFile']['tmp_name']); + if ($imageFileType != "jpg" && $imageFileType != "JPG" && $imageFileType != "png" && $imageFileType != "PNG" && $imageFileType != "jpeg" && $imageFileType != "JPEG" && $mime != "image/png" && $mime != "image/jpeg") { + echo 'texture-illegalFileType'; + exit; + } + + if (exif_imagetype($_FILES['textureFile']['tmp_name']) != IMAGETYPE_PNG && exif_imagetype($_FILES['textureFile']['tmp_name']) != IMAGETYPE_JPEG) { + echo 'texture-illegalFileType'; + exit; + } + + if (!file_exists($uploadDirectory_textureFile .$datafileName)) { + if (!move_uploaded_file($_FILES["textureFile"]["tmp_name"], $uploadDirectory_textureFile.$datafileName)) { + echo 'file-upload-error'; + exit; + } + }else{ + echo 'datafile-mesh-already-exists'; + exit; + } + + // It looks like we've come this far, that we can finally add the hat to the catalog and render its image. + $stmt = $dbcon->prepare("INSERT INTO catalog (`price`, `creator_uid`, `name`, `description`, `type`, `approved`, `datafile`, `buyable`, `rbxasset`) VALUES (:price, :user, :name, :description, 'hats', 1, :datafile, :buyable, :rbxasset);"); + $stmt->bindParam(':user', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':price', $hatPrice, PDO::PARAM_INT); + $stmt->bindParam(':name', $hatName, PDO::PARAM_STR); + $stmt->bindParam(':description', $hatDescription, PDO::PARAM_STR); + $stmt->bindParam(':datafile', $datafileName, PDO::PARAM_STR); + $stmt->bindParam(':buyable', $buyable, PDO::PARAM_INT); + $stmt->bindParam(':rbxasset', $rbxassetv, PDO::PARAM_INT); + $stmt->execute(); + + $query = "INSERT INTO renders (`render_id`, `type`) VALUES (:id, 'hats');"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $datafileName, PDO::PARAM_INT); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'no-file'; + } +?> \ No newline at end of file diff --git a/core/func/api/admin/post/prunePosts.php b/core/func/api/admin/post/prunePosts.php new file mode 100644 index 0000000..8a11bf4 --- /dev/null +++ b/core/func/api/admin/post/prunePosts.php @@ -0,0 +1,161 @@ +prepare("SELECT id, rank, banned FROM users WHERE username=:uname;"); + $stmt->bindParam(':uname', $username, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'no-user'; + exit; + } + + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($GLOBALS['userTable']['rank'] == 1) { + if ($result['rank'] == 1) { + echo 'can-not-prune-user'; + exit; + } + }else{ + if ($result['rank'] > 0) { + echo 'can-not-prune-user'; + exit; + } + } + + $userID = $result['id']; + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET posts = 0 WHERE id=:id;"); + $stmt->bindParam(':id', $userID, PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM topics WHERE author_uid = :uid"); + $stmt->bindParam(':uid', $userID, PDO::PARAM_STR); + $stmt->execute(); + foreach($stmt as $result) { + $postID = $result['id']; + $forumId = $result['forumId']; + $stmt = $GLOBALS['dbcon']->prepare("DELETE FROM topics WHERE id = :id"); + $stmt->bindParam(':id', $postID, PDO::PARAM_STR); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("DELETE FROM replies WHERE postId = :id"); + $stmt->bindParam(':id', $postID, PDO::PARAM_STR); + $stmt->execute(); + + $query = "SELECT id FROM topics WHERE forumId=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $forumId, PDO::PARAM_INT); + $stmt->execute(); + $total = $stmt->rowCount(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE forums SET posts = :posts WHERE id=:id;"); + $stmt->bindParam(':id', $forumId, PDO::PARAM_INT); + $stmt->bindParam(':posts', $total, PDO::PARAM_INT); + $stmt->execute(); + + $query = "SELECT id FROM replies WHERE forumId=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $forumId, PDO::PARAM_INT); + $stmt->execute(); + $total = $stmt->rowCount(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE forums SET replies = :posts WHERE id=:id;"); + $stmt->bindParam(':id', $forumId, PDO::PARAM_INT); + $stmt->bindParam(':posts', $total, PDO::PARAM_INT); + $stmt->execute(); + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT id, postId, forumId FROM replies WHERE author_uid = :uid"); + $stmt->bindParam(':uid', $userID, PDO::PARAM_INT); + $stmt->execute(); + foreach($stmt as $result) { + $replyID = $result['id']; + $postID = $result['postId']; + $forumId = $result['forumId']; + $stmt = $GLOBALS['dbcon']->prepare("DELETE FROM replies WHERE id = :id;"); + $stmt->bindParam(':id', $replyID, PDO::PARAM_STR); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("SELECT post_time FROM replies WHERE postId = :id ORDER BY id DESC LIMIT 1;"); + $stmt->bindParam(':id', $postID, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $postTime = $result['post_time']; + + if ($stmt->rowCount() > 0) { + $query = "UPDATE `topics` SET `lastActivity`=:date WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $postID, PDO::PARAM_INT); + $stmt->bindParam(':date', $postTime, PDO::PARAM_STR); + $stmt->execute(); + }else{ + $stmt = $GLOBALS['dbcon']->prepare("SELECT postTime FROM topics WHERE id = :id;"); + $stmt->bindParam(':id', $postID, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $OPPostTime = $result['postTime']; + + $query = "UPDATE `topics` SET `lastActivity`=:date WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $postID, PDO::PARAM_INT); + $stmt->bindParam(':date', $OPPostTime , PDO::PARAM_STR); + $stmt->execute(); + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM replies WHERE postId = :id;"); + $stmt->bindParam(':id', $postID, PDO::PARAM_INT); + $stmt->execute(); + $replyCount = $stmt->rowCount(); + + $query = "UPDATE `topics` SET `replies`=:rCount WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $postID, PDO::PARAM_INT); + $stmt->bindParam(':rCount', $replyCount , PDO::PARAM_STR); + $stmt->execute(); + + $query = "SELECT * FROM topics WHERE forumId=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $forumId, PDO::PARAM_INT); + $stmt->execute(); + $total = $stmt->rowCount(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE forums SET posts = :posts WHERE id=:id;"); + $stmt->bindParam(':id', $forumId, PDO::PARAM_INT); + $stmt->bindParam(':posts', $total, PDO::PARAM_INT); + $stmt->execute(); + + $query = "SELECT * FROM replies WHERE forumId=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $forumId, PDO::PARAM_INT); + $stmt->execute(); + $total = $stmt->rowCount(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE forums SET replies = :posts WHERE id=:id;"); + $stmt->bindParam(':id', $forumId, PDO::PARAM_INT); + $stmt->bindParam(':posts', $total, PDO::PARAM_INT); + $stmt->execute(); + } + + context::sendDiscordMessage($GLOBALS['userTable']['username'].' has pruned the posts of user **'.$username.'**'); + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/admin/post/rewardPostie.php b/core/func/api/admin/post/rewardPostie.php new file mode 100644 index 0000000..1ff13f9 --- /dev/null +++ b/core/func/api/admin/post/rewardPostie.php @@ -0,0 +1,61 @@ +prepare("SELECT id, rank, banned, lastAward2, posties FROM users WHERE username=:uname;"); + $stmt->bindParam(':uname', $username, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'no-user'; + exit; + } + + $result = $stmt->fetch(PDO::FETCH_ASSOC); + // Rate limiting + $timeSince = round(abs(strtotime(date('Y-m-d H:i:s')) - strtotime($result['lastAward2'])) / 60,2); + if ($timeSince < 5) { + echo 'can-not-reward-user'; + exit; + } + + $newPosties = $result['posties']+10; + + $query = "UPDATE `users` SET `posties`=:newPosties WHERE `username`=:uname;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':newPosties', $newPosties, PDO::PARAM_STR); + $stmt->bindParam(':uname', $username, PDO::PARAM_STR); + $stmt->execute(); + + $query = "UPDATE `users` SET `lastAward2`=NOW() WHERE `username`=:uname;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uname', $username, PDO::PARAM_STR); + $stmt->execute(); + + context::sendDiscordMessage($GLOBALS['userTable']['username'].' has awarded 10 posties to user **'.$username.'**'); + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/admin/post/unbanUser.php b/core/func/api/admin/post/unbanUser.php new file mode 100644 index 0000000..c958bb0 --- /dev/null +++ b/core/func/api/admin/post/unbanUser.php @@ -0,0 +1,66 @@ +prepare("SELECT id, rank, banned FROM users WHERE username=:uname;"); + $stmt->bindParam(':uname', $username, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'no-user'; + exit; + } + + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($GLOBALS['userTable']['rank'] == 1) { + if ($result['rank'] == 1) { + echo 'can-not-unban-user'; + exit; + } + }else{ + if ($result['rank'] > 0) { + echo 'can-not-unban-user'; + exit; + } + } + + if ($result['banned'] == 0) { + echo 'user-not-banned'; + exit; + } + + $query = "UPDATE `users` SET `banned`=0 WHERE `username`=:uname;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uname', $username, PDO::PARAM_STR); + $stmt->execute(); + + $query = "UPDATE `users` SET `bantype`=0 WHERE `username`=:uname;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uname', $username, PDO::PARAM_STR); + $stmt->execute(); + + $query = "UPDATE `users` SET `banreason`=NULL WHERE `username`=:uname;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uname', $username, PDO::PARAM_STR); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/auth/changeEmailVerify.php b/core/func/api/auth/changeEmailVerify.php new file mode 100644 index 0000000..36ff0b7 --- /dev/null +++ b/core/func/api/auth/changeEmailVerify.php @@ -0,0 +1,68 @@ + 128) die("inc-email"); + if (!filter_var($newEmail, FILTER_VALIDATE_EMAIL)) die("inc-email"); + $domain = substr($newEmail, strpos($newEmail, '@') + 1); + if (checkdnsrr($domain) == false) die("inc-email"); + $from_time = strtotime($GLOBALS['userTable']['lastUpload']); + $to_time = strtotime(context::getCurrentTime()); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince < 60) die("rate-limit"); + + // Email domain whitelist, to stop disposable and fake emails. + $good_emails = array('@outlook', '@protonmail.com', '@xdiscuss.net', '@roblox.com', '@icloud.com', '@protonmail.ch', '@google.com', + "@yahoo.com.br", "@hotmail.com.br", "@outlook.com.br", "@uol.com.br", "@bol.com.br", "@terra.com.br", "@ig.com.br", "@itelefonica.com.br", "@r7.com", "@zipmail.com.br", "@globo.com", "@globomail.com", "@oi.com.br", + "@yahoo.com.mx", "@live.com.mx", "@hotmail.es", "@hotmail.com.mx", "@prodigy.net.mx", + "@hotmail.com.ar", "@live.com.ar", "@yahoo.com.ar", "@fibertel.com.ar", "@speedy.com.ar", "@arnet.com.ar", + "@hotmail.be", "@live.be", "@skynet.be", "@voo.be", "@tvcablenet.be", "@telenet.be", + "@mail.ru", "@rambler.ru", "@yandex.ru", "@ya.ru", "@list.ru", + "@gmx.de", "@hotmail.de", "@live.de", "@online.de", "@t-online.de", "@web.de", "@yahoo.de", + "@hotmail.fr", "@live.fr", "@laposte.net", "@yahoo.fr", "@wanadoo.fr", "@orange.fr", "@gmx.fr", "@sfr.fr", "@neuf.fr", "@free.fr", + "@sina.com", "@qq.com", "@naver.com", "@hanmail.net", "@daum.net", "@nate.com", "@yahoo.co.jp", "@yahoo.co.kr", "@yahoo.co.id", "@yahoo.co.in", "@yahoo.com.sg", "@yahoo.com.ph", + "@btinternet.com", "@virginmedia.com", "@blueyonder.co.uk", "@freeserve.co.uk", "@live.co.uk", + "@ntlworld.com", "@o2.co.uk", "@orange.net", "@sky.com", "@talktalk.co.uk", "@tiscali.co.uk", + "@virgin.net", "@wanadoo.co.uk", "@bt.com", "@bellsouth.net", "@charter.net", "@cox.net", "@earthlink.net", "@juno.com", + "@email.com", "@games.com", "@gmx.net", "@hush.com", "@hushmail.com", "@icloud.com", "@inbox.com", + "@lavabit.com", "@love.com", "@outlook.com", "@pobox.com", "@rocketmail.com", + "@safe-mail.net", "@wow.com", "@ygm.com", "@ymail.com", "@zoho.com", "@fastmail.fm", + "@yandex.com","@iname.com", "@aol.com", "@att.net", "@comcast.net", "@facebook.com", "@gmail.com", "@gmx.com", "@googlemail.com", + "@google.com", "@hotmail.com", "@hotmail.co.uk", "@mac.com", "@me.com", "@mail.com", "@msn.com", + "@live.com", "@sbcglobal.net", "@verizon.net", "@yahoo.com", "@yahoo.co.uk" + ); + + if (!context::contains(strtolower($newEmail), $good_emails)) die("unknown-email"); + $auth_hash = crypt($currentPassword, $GLOBALS['userTable']['password_salt']); + if ($GLOBALS['userTable']['password'] != md5($currentPassword) and $auth_hash != $GLOBALS['userTable']['password_hash']) die("inc-password"); + + $stmt = $dbcon->prepare("SELECT email FROM users WHERE email = :email;"); + $stmt->bindParam(':email', $newEmail, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() > 0) die("email-in-use"); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET email = :email WHERE id = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':email', $newEmail, PDO::PARAM_STR); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET lastUpload = NOW() WHERE id = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET emailcodeTime = NULL WHERE id = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/auth/forgot.php b/core/func/api/auth/forgot.php new file mode 100644 index 0000000..e1fd37a --- /dev/null +++ b/core/func/api/auth/forgot.php @@ -0,0 +1,85 @@ +prepare("SELECT id, username, email FROM users WHERE username = :username OR email = :email;"); + $stmt->bindParam(':username', $username, PDO::PARAM_STR); + $stmt->bindParam(':email', $username, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'no-user'; + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $userID = $result['id']; + $username = $result['username']; + $email = $result['email']; + + $query = "SELECT * FROM pwdreset WHERE ip = :ip LIMIT 1;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':ip', $IP, PDO::PARAM_STR); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($stmt->rowCount() > 0) { + $currentTime = date('Y-m-d H:i:s'); + $to_time = strtotime($currentTime); + $from_time = strtotime($result['date']); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince < 5) { + echo 'rate-limit'; + exit; + } + } + + // If IP is changed. + $query = "SELECT * FROM passwordresets WHERE userId = :uid LIMIT 1;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $userID, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($stmt->rowCount() > 0) { + $currentTime = date('Y-m-d H:i:s'); + $to_time = strtotime($currentTime); + $from_time = strtotime($result['date']); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince < 5) { + echo 'rate-limit'; + exit; + }else{ + // Delete every other request + $stmt = $dbcon->prepare("DELETE FROM passwordresets WHERE userId = :uid"); + $stmt->bindParam(':uid', $userID, PDO::PARAM_INT); + $stmt->execute(); + } + } + + $stmt = $dbcon->prepare("DELETE FROM pwdreset WHERE ip = :ip"); + $stmt->bindParam(':ip', $IP, PDO::PARAM_STR); + $stmt->execute(); + + $stmt = $dbcon->prepare("INSERT INTO `pwdreset` (`ip`) VALUES (:ip);"); + $stmt->bindParam(':ip', $IP, PDO::PARAM_STR); + $stmt->execute(); + + $key = context::random_str(256); + $stmt = $dbcon->prepare("INSERT INTO `passwordresets` (`userId`, `key`) VALUES (:uid, :key);"); + $stmt->bindParam(':uid', $userID, PDO::PARAM_INT); + $stmt->bindParam(':key', $key, PDO::PARAM_STR); + $stmt->execute(); + + mailHandler::sendMail('Hello '.$username.'! You can reset your password at https://xdiscuss.net/account/resetpassword/'.$userID.'/'.$key.' if you did not request this, you can ignore this.

Graphictoria
Please know that this message was generated automatically, do not reply to this. If you need help, send a message to support@xdiscuss.net.', "Hello ".$username."! You can reset your password at https://xdiscuss.net/account/resetpassword/".$userID."/".$key." if you did not request this, you can ignore this.", $email, "Graphictoria Password Reset", $username); + + echo 'success'; + }else{ + echo 'error'; + exit; + } +?> \ No newline at end of file diff --git a/core/func/api/auth/login.php b/core/func/api/auth/login.php new file mode 100644 index 0000000..b0c5095 --- /dev/null +++ b/core/func/api/auth/login.php @@ -0,0 +1,234 @@ +prepare($query); + $stmt->bindParam(':ip', $IP, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() == 1) { + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($result['count'] == 3) { + $from_time = strtotime($result['time']); + $to_time = strtotime(context::getCurrentTime()); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince < 2) { + echo 'rate-limit'; + exit; + } + } + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT id, password_salt, password, password_hash, registerIP, passwordVersion, rank, posts, username FROM users WHERE username = :username OR email = :email;"); + $stmt->bindParam(':username', $username, PDO::PARAM_STR); + $stmt->bindParam(':email', $username, PDO::PARAM_STR); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($stmt->rowCount() == 0) { + echo 'no-user'; + exit; + } + + $auth_hash = crypt($password, $result['password_salt']); + if ($auth_hash == $result['password_hash']) { + if ($result['registerIP'] == NULL) { + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET registerIP = :ip WHERE id = :id;"); + $stmt->bindParam(':id', $result['id'], PDO::PARAM_INT); + $stmt->bindParam(':ip', $IP, PDO::PARAM_STR); + $stmt->execute(); + } + + $form_code = md5(uniqid()); + $aid = context::random_str(128); + $location = $_SERVER["HTTP_CF_IPCOUNTRY"]; + $stmt = $GLOBALS['dbcon']->prepare('INSERT INTO `sessions` (`userId`, `sessionId`, `csrfToken`, `useragent`, `location`) VALUES (:userId, :sid, :csrf, :useragent, :location);'); + $stmt->bindParam(':userId', $result['id'], PDO::PARAM_INT); + $stmt->bindParam(':sid', $aid, PDO::PARAM_STR); + $stmt->bindParam(':csrf', $form_code, PDO::PARAM_STR); + $stmt->bindParam(':useragent', $_SERVER['HTTP_USER_AGENT'], PDO::PARAM_STR); + $stmt->bindParam(':location', $location, PDO::PARAM_STR); + $stmt->execute(); + + if (isset($_COOKIE['auth_uid']) || isset($_COOKIE['a_id'])) { + setcookie('auth_uid', "", time() - 3600); + setcookie('a_id', "", time() - 3600); + } + + setcookie("auth_uid", $result['id'], time() + (86400 * 30), "/", ".xdiscuss.net", false, true); + setcookie("a_id", $aid, time() + (86400 * 30), "/", ".xdiscuss.net", false, true); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET lastIP = :ip WHERE id = :id;"); + $stmt->bindParam(':id', $result['id'], PDO::PARAM_INT); + $stmt->bindParam(':ip', $IP, PDO::PARAM_STR); + $stmt->execute(); + + $key = sha1($form_code); + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET gameKey = :key WHERE id = :id;"); + $stmt->bindParam(':id', $result['id'], PDO::PARAM_INT); + $stmt->bindParam(':key', $key, PDO::PARAM_STR); + $stmt->execute(); + + // Award badges + if ($result['rank'] == 1) { + // Check if the admin badge is owned + $stmt = $GLOBALS['dbcon']->prepare("SELECT id FROM badges WHERE uid = :uid AND badgeId = 2"); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + // Award badge + $query = "INSERT INTO badges (`uid`, `badgeId`) VALUES (:uid, 2);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + } + + // Check if the moderator badge is owned + $stmt = $GLOBALS['dbcon']->prepare("SELECT id FROM badges WHERE uid = :uid AND badgeId = 3"); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + // Award badge + $query = "INSERT INTO badges (`uid`, `badgeId`) VALUES (:uid, 3);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + } + } + + if ($result['rank'] == 2) { + // Check if the moderator badge is owned + $stmt = $GLOBALS['dbcon']->prepare("SELECT id FROM badges WHERE uid = :uid AND badgeId = 3"); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + // Award badge + $query = "INSERT INTO badges (`uid`, `badgeId`) VALUES (:uid, 3);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + } + + // Remove admin badge if any + $query = "DELETE FROM badges WHERE badgeId = 2 AND uid = :uid"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + } + + if ($result['rank'] == 0) { + // Remove staff badges if any + $query = "DELETE FROM badges WHERE badgeId = 2 AND uid = :uid"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + + $query = "DELETE FROM badges WHERE badgeId = 3 AND uid = :uid"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + } + + // Check if the member badge is owned + $stmt = $GLOBALS['dbcon']->prepare("SELECT id FROM badges WHERE uid = :uid AND badgeId = 5"); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + // Award badge + $query = "INSERT INTO badges (`uid`, `badgeId`) VALUES (:uid, 5);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + } + + // Get forum post count + $postCount = $result['posts']; + $stmt = $GLOBALS['dbcon']->prepare("SELECT id FROM badges WHERE uid = :uid AND badgeId = 4"); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0 and $postCount > 999) { + // Award badge + $query = "INSERT INTO badges (`uid`, `badgeId`) VALUES (:uid, 4);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + }else{ + if ($postCount < 1000) { + $query = "DELETE FROM badges WHERE badgeId = 4 AND uid = :uid"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + } + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT id FROM badges WHERE uid = :uid AND badgeId = 7"); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0 and $result['id'] < 101) { + // Award badge + $query = "INSERT INTO badges (`uid`, `badgeId`) VALUES (:uid, 7);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + }else{ + if ($result['id'] > 100) { + $query = "DELETE FROM badges WHERE badgeId = 7 AND uid = :uid"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + } + } + + context::sendDiscordMessage("**User logged in** | ".$result['username']); + + echo 'success'; + exit; + }else{ + $query = "SELECT * FROM loginAttempts WHERE ip = :ip"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':ip', $IP, PDO::PARAM_STR); + $stmt->execute(); + + $delete = false; + if ($stmt->rowCount() == 3) { + $query = "DELETE FROM loginAttempts WHERE ip = :ip;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':ip', $IP, PDO::PARAM_STR); + $stmt->execute(); + $delete = true; + } + + if ($delete == true) { + $count = 1; + }else{ + $count = $stmt->rowCount()+1; + } + + $query = "INSERT INTO loginAttempts (`ip`, `uid`, `count`) VALUES (:ip, :uid, :count);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':ip', $IP, PDO::PARAM_STR); + $stmt->bindParam(':uid', $result['id'], PDO::PARAM_INT); + $stmt->bindParam(':count', $count, PDO::PARAM_INT); + $stmt->execute(); + echo 'incorrect-password'; + exit; + } + + }else{ + echo 'error'; + exit; + } +?> diff --git a/core/func/api/auth/ping.php b/core/func/api/auth/ping.php new file mode 100644 index 0000000..e69de29 diff --git a/core/func/api/auth/register.php b/core/func/api/auth/register.php new file mode 100644 index 0000000..26d19c2 --- /dev/null +++ b/core/func/api/auth/register.php @@ -0,0 +1,169 @@ + 20) { + echo 'username-too-long'; + exit; + } + + if(!preg_match("/^[a-zA-Z0-9][\w\.]+[a-zA-Z0-9]$/", $username) == 1) { + echo 'illegal-username'; + exit; + } + + if (strlen($email) == 0) { + echo 'no-email'; + exit; + } + + if (strlen($email) > 128) { + echo 'email-too-long'; + exit; + } + + if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + echo 'illegal-email'; + exit; + } + + $domain = substr($email, strpos($email, '@') + 1); + if (checkdnsrr($domain) == false) die("illegal-email"); + + // Email domain whitelist, to stop disposable and fake emails. Will only be checked at initial register. + $good_emails = array('@outlook', '@protonmail.com', '@xdiscuss.net', '@roblox.com', '@icloud.com', '@protonmail.ch', '@google.com', + "@yahoo.com.br", "@hotmail.com.br", "@outlook.com.br", "@uol.com.br", "@bol.com.br", "@terra.com.br", "@ig.com.br", "@itelefonica.com.br", "@r7.com", "@zipmail.com.br", "@globo.com", "@globomail.com", "@oi.com.br", + "@yahoo.com.mx", "@live.com.mx", "@hotmail.es", "@hotmail.com.mx", "@prodigy.net.mx", + "@hotmail.com.ar", "@live.com.ar", "@yahoo.com.ar", "@fibertel.com.ar", "@speedy.com.ar", "@arnet.com.ar", + "@hotmail.be", "@live.be", "@skynet.be", "@voo.be", "@tvcablenet.be", "@telenet.be", + "@mail.ru", "@rambler.ru", "@yandex.ru", "@ya.ru", "@list.ru", + "@gmx.de", "@hotmail.de", "@live.de", "@online.de", "@t-online.de", "@web.de", "@yahoo.de", + "@hotmail.fr", "@live.fr", "@laposte.net", "@yahoo.fr", "@wanadoo.fr", "@orange.fr", "@gmx.fr", "@sfr.fr", "@neuf.fr", "@free.fr", + "@sina.com", "@qq.com", "@naver.com", "@hanmail.net", "@daum.net", "@nate.com", "@yahoo.co.jp", "@yahoo.co.kr", "@yahoo.co.id", "@yahoo.co.in", "@yahoo.com.sg", "@yahoo.com.ph", + "@btinternet.com", "@virginmedia.com", "@blueyonder.co.uk", "@freeserve.co.uk", "@live.co.uk", + "@ntlworld.com", "@o2.co.uk", "@orange.net", "@sky.com", "@talktalk.co.uk", "@tiscali.co.uk", + "@virgin.net", "@wanadoo.co.uk", "@bt.com", "@bellsouth.net", "@charter.net", "@cox.net", "@earthlink.net", "@juno.com", + "@email.com", "@games.com", "@gmx.net", "@hush.com", "@hushmail.com", "@icloud.com", "@inbox.com", + "@lavabit.com", "@love.com", "@outlook.com", "@pobox.com", "@rocketmail.com", + "@safe-mail.net", "@wow.com", "@ygm.com", "@ymail.com", "@zoho.com", "@fastmail.fm", + "@yandex.com","@iname.com", "@aol.com", "@att.net", "@comcast.net", "@facebook.com", "@gmail.com", "@gmx.com", "@googlemail.com", + "@google.com", "@hotmail.com", "@hotmail.co.uk", "@mac.com", "@me.com", "@mail.com", "@msn.com", + "@live.com", "@sbcglobal.net", "@verizon.net", "@yahoo.com", "@yahoo.co.uk" + ); + + if (!context::contains(strtolower($email), $good_emails)) die("unknown-email"); + + if (strlen($password1) == 0) { + echo 'no-password'; + exit; + } + + if (strlen($password2) == 0) { + echo 'no-password'; + exit; + } + + if ($password1 != $password2) { + echo 'passwords-mismatch'; + exit; + } + + if (strlen($password1) < 6) { + echo 'password-too-short'; + exit; + } + + if (strlen($password1) > 40) { + echo 'password-too-long'; + exit; + } + + $stmt = $dbcon->prepare("SELECT * FROM users WHERE email = :email;"); + $stmt->bindParam(':email', $email, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + echo 'email-already-used'; + exit; + } + + $stmt = $dbcon->prepare("SELECT * FROM users WHERE username = :username;"); + $stmt->bindParam(':username', $username, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + echo 'username-already-used'; + exit; + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT joinDate FROM users WHERE registerIP = :ip ORDER BY id DESC LIMIT 1;"); + $stmt->bindParam(':ip', $IP, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $currentTime = context::getCurrentTime(); + $to_time = strtotime($currentTime); + $from_time = strtotime($result['joinDate']); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince < 1440) { + echo 'rate-limit'; + exit; + } + } + + // Still here? Continue. Please use password_hash... + $salt = '$2a$07$'.uniqid(mt_rand(), true).'$'; + $hash = crypt($password1, $salt); + $stmt = $dbcon->prepare("INSERT INTO users (`username`, `password_hash`, `password_salt`, `email`, `registerIP`, `passwordVersion`) VALUES (:user, :hash, :salt, :email, :ip, 2);"); + $stmt->bindParam(':ip', $IP, PDO::PARAM_STR); + $stmt->bindParam(':user', $username, PDO::PARAM_STR); + $stmt->bindParam(':hash', $hash, PDO::PARAM_STR); + $stmt->bindParam(':salt', $salt, PDO::PARAM_STR); + $stmt->bindParam(':email', $email, PDO::PARAM_STR); + $stmt->execute(); + + context::sendDiscordMessage("**New user registered!** | ".$username); + + echo 'success'; + }else{ + echo 'error'; + exit; + } +?> diff --git a/core/func/api/auth/resetPassword.php b/core/func/api/auth/resetPassword.php new file mode 100644 index 0000000..8ca76ef --- /dev/null +++ b/core/func/api/auth/resetPassword.php @@ -0,0 +1,75 @@ +prepare($query); + $stmt->bindParam(':uid', $userID, PDO::PARAM_INT); + $stmt->bindParam(':key', $key, PDO::PARAM_STR); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($stmt->rowCount() == 0 or $result['used'] == 1) { + echo 'invalid-key'; + exit; + } + + $currentTime = date('Y-m-d H:i:s'); + $to_time = strtotime($currentTime); + $from_time = strtotime($result['date']); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince > 5) { + echo 'key-expired'; + exit; + } + + if ($password1 != $password2) { + echo 'password-mismatch'; + exit; + } + + if (strlen($password1) > 42) { + echo 'password-too-long'; + exit; + } + + if (strlen($password1) < 6) { + echo 'password-too-short'; + exit; + } + + $salt = '$2a$07$'.uniqid(mt_rand(), true).'$'; + $hash = crypt($password1, $salt); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET password_salt = :salt WHERE id = :user;"); + $stmt->bindParam(':user', $userID, PDO::PARAM_INT); + $stmt->bindParam(':salt', $salt, PDO::PARAM_STR); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET password_hash = :hash WHERE id = :user;"); + $stmt->bindParam(':user', $userID, PDO::PARAM_INT); + $stmt->bindParam(':hash', $hash, PDO::PARAM_STR); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE passwordresets SET used = 1 WHERE `key` = :key AND userid = :uid;"); + $stmt->bindParam(':key', $key, PDO::PARAM_STR); + $stmt->bindParam(':uid', $userID, PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("DELETE FROM sessions WHERE userId = :uid;"); + $stmt->bindParam(':uid', $userID, PDO::PARAM_INT); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/auth/twostep.php b/core/func/api/auth/twostep.php new file mode 100644 index 0000000..eea9bfa --- /dev/null +++ b/core/func/api/auth/twostep.php @@ -0,0 +1,37 @@ +checkCode($GLOBALS['userTable']['authKey'], $factorCode)) { + echo 'wrong-code'; + exit; + }else{ + $stmt = $GLOBALS['dbcon']->prepare("UPDATE sessions SET factorFinish = 1 WHERE id = :id;"); + $stmt->bindParam(':id', $GLOBALS['sessionTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + echo 'success'; + } + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/auth/verifyEmail.php b/core/func/api/auth/verifyEmail.php new file mode 100644 index 0000000..2aa396d --- /dev/null +++ b/core/func/api/auth/verifyEmail.php @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/core/func/api/blog/addPost.php b/core/func/api/blog/addPost.php new file mode 100644 index 0000000..e37b78f --- /dev/null +++ b/core/func/api/blog/addPost.php @@ -0,0 +1,19 @@ + + + +
+

+ + \ No newline at end of file diff --git a/core/func/api/blog/getPosts.php b/core/func/api/blog/getPosts.php new file mode 100644 index 0000000..fc2f42b --- /dev/null +++ b/core/func/api/blog/getPosts.php @@ -0,0 +1,17 @@ +prepare("SELECT * FROM blogposts ORDER BY id DESC"); + $stmt->execute(); + foreach($stmt as $result) { + $userSheet = context::getUserSheetByID($result['poster_uid']); + echo '
+
+
+
+

'.context::secureString($result['title']).'

+

Posted by '.$userSheet['username'].', '.context::humanTimingSince(strtotime($result['date'])).' ago

+
+
+
'; + } +?> \ No newline at end of file diff --git a/core/func/api/blog/loadPost.php b/core/func/api/blog/loadPost.php new file mode 100644 index 0000000..c9348c0 --- /dev/null +++ b/core/func/api/blog/loadPost.php @@ -0,0 +1,25 @@ +prepare("SELECT * FROM blogposts WHERE id = :id"); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) die("Post not found"); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $userSheet = context::getUserSheetByID($result['poster_uid']); + $content = context::secureString($result['content']); + $content = preg_replace("/\s*[a-zA-Z\/\/:\.]*youtube.com\/watch\?v=([a-zA-Z0-9\-_]+)([a-zA-Z0-9\/\*\-\_\?\&\;\%\=\.]*)/i","", $content); + $content = preg_replace("/https?:\/\/[^ ]+?(?:\.jpg|\.png|\.gif)/",'', $content); + $content = context::showBBcodes($content); + echo ' +
+
+
'.context::getOnline($userSheet).''.$userSheet['username'].'
+
+

'.nl2br($content).'

+
+
+
'; +?> \ No newline at end of file diff --git a/core/func/api/catalog/getItems.php b/core/func/api/catalog/getItems.php new file mode 100644 index 0000000..b93700f --- /dev/null +++ b/core/func/api/catalog/getItems.php @@ -0,0 +1,73 @@ +type = "'.$type.'";'; + + if (isset($term) and strlen($term) > 0) { + $searchTermSQL = '%'.$term.'%'; + if ($GLOBALS['loggedIn']) $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM catalog WHERE name LIKE :term AND approved = 1 AND type = :type ORDER BY id DESC LIMIT 16 OFFSET :offset"); + if (!$GLOBALS['loggedIn']) $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM catalog WHERE name LIKE :term AND approved = 1 AND type = :type AND rbxasset = 0 ORDER BY id DESC LIMIT 16 OFFSET :offset"); + $stmt->bindParam(':term', $searchTermSQL, PDO::PARAM_STR); + }else{ + if ($GLOBALS['loggedIn']) $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM catalog WHERE type = :type AND buyable = 1 AND approved = 1 ORDER BY id DESC LIMIT 16 OFFSET :offset"); + if (!$GLOBALS['loggedIn']) $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM catalog WHERE type = :type AND buyable = 1 AND approved = 1 AND rbxasset = 0 ORDER BY id DESC LIMIT 16 OFFSET :offset"); + } + $stmt->bindParam(':type', $type, PDO::PARAM_STR); + $stmt->bindParam(':offset', $offset, PDO::PARAM_INT); + $stmt->execute(); + $count = 0; + echo '
'; + foreach($stmt as $result) { + $count++; + if ($count < 16) { + echo '
'; + echo ''; + echo '
'; + $itemName = context::secureString($result['name']); + if (strlen($itemName) >= 40) { + $itemName = substr($itemName, 0, 37). " ... "; + } + echo '
'.$itemName.'
'; + if ($result['type'] != "decals") { + if ($result['currencyType'] == 0) { + echo '
'.$result['price'].'

'; + }else{ + echo '
'.$result['price'].'

'; + } + } + echo 'Details'; + echo '
'; + } + } + if ($count == 0) { + echo '

Nothing found

'; + } + if ($count > 15) { + echo ''; + } + echo '
'; + }else{ + echo 'An error occurred'; + } +?> \ No newline at end of file diff --git a/core/func/api/catalog/post/buyItem.php b/core/func/api/catalog/post/buyItem.php new file mode 100644 index 0000000..668edd1 --- /dev/null +++ b/core/func/api/catalog/post/buyItem.php @@ -0,0 +1,99 @@ +prepare("SELECT * FROM ownedItems WHERE uid=:id AND catalogid = :catid"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':catid', $itemId, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + $owned = true; + }else{ + $owned = false; + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM catalog WHERE id=:id"); + $stmt->bindParam(':id', $itemId, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $owneruserID = $result['creator_uid']; + + if ($owned == false and $result['buyable'] == 1 and $result['type'] !== "decals" and $result['approved'] == 1) { + if ($result['id'] != $itemId) { + echo 'error'; + exit; + } + $canBuy = false; + if ($result['currencyType'] == 0) { + if ($result['price'] < $GLOBALS['userTable']['coins'] or $result['price'] == $GLOBALS['userTable']['coins']) { + $canBuy = true; + } + } + + if ($result['currencyType'] == 1) { + if ($result['price'] < $GLOBALS['userTable']['posties'] or $result['price'] == $GLOBALS['userTable']['posties']) { + $canBuy = true; + } + } + + if ($canBuy == true) { + if ($result['currencyType'] == 0) { + $newBalance = $GLOBALS['userTable']['coins']-$result['price']; + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET coins = :coins WHERE id = :user;"); + $stmt->bindParam(':coins', $newBalance, PDO::PARAM_INT); + $stmt->bindParam(':user', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + // If the buyer's account is over 1 week old, award the seller + $timeSince = round(abs(strtotime(context::getCurrentTime()) - strtotime($GLOBALS['userTable']['joinDate'])) / 60,2); + if ($timeSince > 10080) { + $awardPrice = round($result['price']/2); + + // Get seller's current coins + $stmt = $GLOBALS['dbcon']->prepare("SELECT coins FROM users WHERE id=:id"); + $stmt->bindParam(':id', $owneruserID, PDO::PARAM_INT); + $stmt->execute(); + $resultSeller = $stmt->fetch(PDO::FETCH_ASSOC); + + $currentSCoins = $resultSeller['coins']; + $newSCoins = $resultSeller['coins']+$awardPrice; + + // Award the seller right here + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET coins = :coins WHERE id = :user;"); + $stmt->bindParam(':coins', $newSCoins, PDO::PARAM_INT); + $stmt->bindParam(':user', $owneruserID, PDO::PARAM_INT); + $stmt->execute(); + } + }else{ + $newBalance = $GLOBALS['userTable']['posties']-$result['price']; + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET posties = :coins WHERE id = :user;"); + $stmt->bindParam(':coins', $newBalance, PDO::PARAM_INT); + $stmt->bindParam(':user', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + } + + $stmt = $GLOBALS['dbcon']->prepare("INSERT INTO ownedItems (`uid`, `catalogid`, `type`, `rbxasset`) VALUES (:user, :itemid, :type, :rbxasset);"); + $stmt->bindParam(':user', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':itemid', $result['id'], PDO::PARAM_INT); + $stmt->bindParam(':rbxasset', $result['rbxasset'], PDO::PARAM_INT); + $stmt->bindParam(':type', $result['type'], PDO::PARAM_STR); + $stmt->execute(); + + echo $newBalance; + }else{ + echo 'error'; + } + }else{ + echo 'error'; + } + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/catalog/post/deleteItem.php b/core/func/api/catalog/post/deleteItem.php new file mode 100644 index 0000000..8f447be --- /dev/null +++ b/core/func/api/catalog/post/deleteItem.php @@ -0,0 +1,81 @@ +prepare("SELECT * FROM catalog WHERE id=:id"); + $stmt->bindParam(':id', $itemId, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $fileHash = $result['fileHash']; + if ($result['type'] != "tshirts" and $result['type'] != "shirts" and $result['type'] != "pants" and $result['type'] != "decals") { + echo 'error'; + exit; + } + + // Make deleted true + $stmt = $GLOBALS['dbcon']->prepare("UPDATE catalog SET deleted = 1 WHERE fileHash = :id;"); + $stmt->bindParam(':id', $fileHash, PDO::PARAM_STR); + $stmt->execute(); + + // Make item unbuyable + $stmt = $GLOBALS['dbcon']->prepare("UPDATE catalog SET buyable = 0 WHERE fileHash = :id;"); + $stmt->bindParam(':id', $fileHash, PDO::PARAM_STR); + $stmt->execute(); + + // Set deleted true in owned items with the same file hash + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM catalog WHERE fileHash = :id"); + $stmt->bindParam(':id', $fileHash, PDO::PARAM_INT); + $stmt->execute(); + foreach($stmt as $result) { + $iID = $result['id']; + $stmt = $GLOBALS['dbcon']->prepare("UPDATE ownedItems SET deleted = 1 WHERE catalogid = :id;"); + $stmt->bindParam(':id', $iID, PDO::PARAM_INT); + $stmt->execute(); + } + + // Delete the actual file + if ($result['type'] == "tshirts" || $result['type'] == "shirts" || $result['type'] == "pants" || $result['type'] == "decals") { + @unlink($_SERVER['DOCUMENT_ROOT'].'/data/assets/uploads/'.$result['fileHash']); + } + + if ($result['type'] != "decals") { + // Remove from wearing + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM catalog WHERE fileHash = :id"); + $stmt->bindParam(':id', $fileHash, PDO::PARAM_INT); + $stmt->execute(); + foreach($stmt as $result) { + $iID2 = $result['id']; + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM wearing WHERE catalogId = :id"); + $stmt->bindParam(':id', $iID2, PDO::PARAM_INT); + $stmt->execute(); + foreach($stmt as $result) { + // Delete and put a request up in the imageServer + $query = "DELETE FROM `wearing` WHERE `id`=:id"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $id = $result['id']; + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + + $uid = $result['uid']; + // Add request to imageServer + $query = "INSERT INTO renders (`render_id`, `type`) VALUES (:id, 'character');"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $uid, PDO::PARAM_INT); + $stmt->execute(); + } + } + } + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/catalog/post/uploadItem.php b/core/func/api/catalog/post/uploadItem.php new file mode 100644 index 0000000..7fc0a06 --- /dev/null +++ b/core/func/api/catalog/post/uploadItem.php @@ -0,0 +1,223 @@ + 32) { + echo 'name-too-long'; + exit; + } + + if (!preg_match("/^[\w*?!\/@#$%\^&*\(\) -]+$/", $itemName) == 1) { + die("name-too-short"); + } + + if (strlen($itemName) < 5) { + echo 'name-too-short'; + exit; + } + + if (strlen($description) > 128) { + echo 'description-too-long'; + exit; + } + + if (is_numeric($itemPrice) == false) die("price-too-low"); + + if ($itemPrice < 1 && $typeString != "decals") { + echo 'price-too-low'; + exit; + } + + if ($typeString == "decals") { + $itemPrice = 0; + } + + // Check last upload date, if less than a minute return 'rate-limit' + $timeSince = round(abs(strtotime(context::getCurrentTime()) - strtotime($GLOBALS['userTable']['lastUpload'])) / 60,2); + if ($timeSince < 1) { + echo 'rate-limit'; + exit; + } + + // Get the latest assetID, if nothing, default to 1 + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM catalog WHERE type=:dbtype ORDER BY id DESC LIMIT 1;"); + $stmt->bindParam(':dbtype', $typeString, PDO::PARAM_STR); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($stmt->rowCount() == 0) { + $assetId = 1; + }else{ + $assetId = $result['assetid']+1; + } + + $uploadDirectory = $_SERVER['DOCUMENT_ROOT'].'/data/assets/uploads/'; + + // Check the file + $check = @getimagesize($_FILES["file"]["tmp_name"]); + list($width, $height) = @getimagesize($_FILES["file"]["tmp_name"]); + if ($width != 585 && $height != 559) { + if ($typeString == "shirts" or $typeString == "pants") { + echo 'incorrect-size'; + exit; + } + } + + if (!$check) { + echo 'no-image'; + exit; + } + + if ($_FILES["file"]["size"] > 1000000) { + echo 'file-too-large'; + exit; + } + + $imageFileType = pathinfo($_FILES['file']["name"], PATHINFO_EXTENSION); + $finfo = finfo_open(FILEINFO_MIME_TYPE); + $mime = finfo_file($finfo, $_FILES['file']['tmp_name']); + if ($imageFileType != "jpg" && $imageFileType != "JPG" && $imageFileType != "png" && $imageFileType != "PNG" && $imageFileType != "jpeg" && $imageFileType != "JPEG" && $mime != "image/png" && $mime != "image/jpeg") { + echo 'incorrect-extension'; + exit; + } + + if (exif_imagetype($_FILES['file']['tmp_name']) != IMAGETYPE_PNG && exif_imagetype($_FILES['file']['tmp_name']) != IMAGETYPE_JPEG) { + echo 'incorrect-extension'; + exit; + } + + + // Check user balance, should be easy + if ($GLOBALS['userTable']['coins'] < 5) { + echo 'not-enough-coins'; + exit; + } + + // Check if the file hash is not in badHashes + $fileHash = hash_file('sha512', $_FILES["file"]["tmp_name"]); + $stmt = $GLOBALS['dbcon']->prepare("SELECT id FROM badHashes WHERE hash=:fileHash"); + $stmt->bindParam(':fileHash', $fileHash, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + echo 'bad-hash'; + exit; + } + + // Move the file to the right directory. Upload complete! + // Only move if it doesn't exist already. + if (!file_exists($uploadDirectory.$fileHash)) { + if (!move_uploaded_file($_FILES["file"]["tmp_name"], $uploadDirectory.$fileHash)) { + echo 'file-upload-error'; + exit; + } + } + + $newCoins = $GLOBALS['userTable']['coins']-5; + $stmt = $dbcon->prepare("UPDATE users SET coins = :coins WHERE id = :user;"); + $stmt->bindParam(':coins', $newCoins, PDO::PARAM_INT); + $stmt->bindParam(':user', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + // Set last upload to now, for security purposes. + $stmt = $dbcon->prepare("UPDATE users SET lastUpload = NOW() WHERE id = :user;"); + $stmt->bindParam(':user', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + // Add to catalog. But keep un-approved until approved, of course, unless the hash is already approved. + // Check if any asset with the same hash is approved or not. Why approve the same file again? + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM catalog WHERE fileHash=:fileHash ORDER BY id DESC LIMIT 1;"); + $stmt->bindParam(':fileHash', $fileHash, PDO::PARAM_STR); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $approved = 0; + if ($result['approved'] == 1 && $result['fileHash'] == $fileHash && $result['deleted'] == 0) { + $approved = 1; + } + + $stmt = $dbcon->prepare("INSERT INTO catalog (`price`, `creator_uid`, `assetid`, `name`, `description`, `type`, `approved`, `fileHash`) VALUES (:price, :user, :assetid, :name, :description, :type, :approved, :fileHash);"); + $stmt->bindParam(':user', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':price', $itemPrice, PDO::PARAM_INT); + $stmt->bindParam(':type', $typeString, PDO::PARAM_STR); + $stmt->bindParam(':assetid', $assetId, PDO::PARAM_INT); + $stmt->bindParam(':name', $itemName, PDO::PARAM_STR); + $stmt->bindParam(':description', $description, PDO::PARAM_STR); + $stmt->bindParam(':approved', $approved, PDO::PARAM_INT); + $stmt->bindParam(':fileHash', $fileHash, PDO::PARAM_STR); + $stmt->execute(); + + if ($approved == 0) { + // Send the uploader a message so they can keep track of the progress of approval. + if ($typeString != "decals") { + $message = 'Your asset named '.$itemName.' is pending approval. You will receive another message after approval. Once approved, you will receive the item.'; + }else{ + $message = 'Your asset named '.$itemName.' is pending approval. You will receive another message after approval. Once approved, the decal will be visible in the catalog.'; + } + }else{ + $message = 'Your asset named '.$itemName.' has already been approved in the past. So, you can already make use of it and it is visible on the catalog.'; + } + $title = 'Asset Approval for '.$itemName; + $query = "INSERT INTO messages (`recv_uid`, `sender_uid`, `title`, `content`) VALUES (:userId2, 10370, :title, :msg);"; + $stmt = $dbcon->prepare($query); + $stmt->bindParam(':userId2', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':msg', $message, PDO::PARAM_STR); + $stmt->bindParam(':title', $title, PDO::PARAM_STR); + $stmt->execute(); + + if ($approved == 1) { + if ($typeString == "shirts" or $typeString == "pants" or $typeString == "tshirts") { + $query = "INSERT INTO renders (`render_id`, `type`) VALUES (:id, :dbtype);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $assetId, PDO::PARAM_INT); + $stmt->bindParam(':dbtype', $typeString, PDO::PARAM_STR); + $stmt->execute(); + } + + // Get latest asset by this user + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM catalog WHERE creator_uid = :uid ORDER BY id DESC LIMIT 1;"); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $catId = $result['id']; + + if ($typeString != "decals") { + $query = "INSERT INTO ownedItems (`uid`, `catalogid`, `type`) VALUES (:uid, :catid, :type);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':catid', $catId, PDO::PARAM_INT); + $stmt->bindParam(':type', $typeString, PDO::PARAM_STR); + $stmt->execute(); + } + } + + // We're done! Yahoo! + echo $newCoins; + }else{ + echo 'no-file'; + } +?> \ No newline at end of file diff --git a/core/func/api/character/getInventory.php b/core/func/api/character/getInventory.php new file mode 100644 index 0000000..b7c694c --- /dev/null +++ b/core/func/api/character/getInventory.php @@ -0,0 +1,134 @@ +prepare("SELECT catalogid FROM ownedItems WHERE type = :type AND uid = :uid AND deleted=0 ORDER BY id DESC LIMIT 7 OFFSET :offset;"); + $stmt->bindParam(':offset', $offset, PDO::PARAM_INT); + $stmt->bindParam(':type', $type, PDO::PARAM_STR); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'No items found.'; + } + $count = 0; + foreach($stmt as $resultOwned) { + $count++; + if ($count < 7) { + $wearing = false; + $disableWear = false; + $stmt = $GLOBALS['dbcon']->prepare("SELECT id FROM wearing WHERE uid = :uid AND catalogid = :id"); + $stmt->bindParam(':id', $resultOwned['catalogid'], PDO::PARAM_INT); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + $wearing = true; + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT id FROM wearing WHERE uid = :uid AND type = :type"); + $stmt->bindParam(':type', $type, PDO::PARAM_STR); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() > 4 and $type == "hats") { + $disableWear = true; + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT deleted, name, type, datafile, assetid, id, fileHash, imgTime FROM catalog WHERE id = :id"); + $stmt->bindParam(':id', $resultOwned['catalogid'], PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($result['deleted'] == 0) { + $itemName = $result['name']; + if (strlen($itemName) > 16) { + $itemName = substr($itemName, 0, 13) . '...'; + } + + echo '
'.htmlentities($itemName, ENT_QUOTES, "UTF-8").'
'; + echo ''; + if ($wearing == true) { + echo '
'; + }else{ + if ($disableWear == false) { + echo '
'; + }else{ + echo '
Wear'; + } + } + echo '
'; + } + } + } + echo '
'; + if ($page > 0) { + echo '« Previous'; + } + if ($count > 6) { + echo 'Next »'; + } + if ($count == 0 and $page > 0) { + exit; + } + echo '
'; +?> \ No newline at end of file diff --git a/core/func/api/character/getWearing.php b/core/func/api/character/getWearing.php new file mode 100644 index 0000000..d2bc7e0 --- /dev/null +++ b/core/func/api/character/getWearing.php @@ -0,0 +1,93 @@ +prepare("SELECT catalogId FROM wearing WHERE uid = :uid AND type = :type"); + $stmt->bindParam(':type', $type, PDO::PARAM_STR); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'You are not wearing any item.'; + } + foreach($stmt as $resultWearing) { + $stmt = $GLOBALS['dbcon']->prepare("SELECT id, deleted, datafile, type, assetid, name, fileHash, imgTime FROM catalog WHERE id = :id;"); + $stmt->bindParam(':id', $resultWearing['catalogId'], PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($result['deleted'] == 0) { + $itemName = $result['name']; + if (strlen($itemName) > 16) { + $itemName = substr($itemName, 0, 13) . '...'; + } + echo '
'.htmlentities($itemName, ENT_QUOTES, "UTF-8").'
'; + echo ''; + echo '
'; + echo '
'; + } + } +?> \ No newline at end of file diff --git a/core/func/api/character/post/changePose.php b/core/func/api/character/post/changePose.php new file mode 100644 index 0000000..691ad7a --- /dev/null +++ b/core/func/api/character/post/changePose.php @@ -0,0 +1,24 @@ +prepare($query); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':pose', $poseID, PDO::PARAM_INT); + $stmt->execute(); + + context::requestImage($GLOBALS['userTable']['id'], "character"); + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/character/post/regenCharacter.php b/core/func/api/character/post/regenCharacter.php new file mode 100644 index 0000000..e619a06 --- /dev/null +++ b/core/func/api/character/post/regenCharacter.php @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/core/func/api/character/post/removeItem.php b/core/func/api/character/post/removeItem.php new file mode 100644 index 0000000..2dac2f5 --- /dev/null +++ b/core/func/api/character/post/removeItem.php @@ -0,0 +1,21 @@ +prepare("DELETE FROM wearing WHERE catalogId=:id AND uid=:user"); + $stmt->bindParam(':user', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':id', $catalogId, PDO::PARAM_INT); + $stmt->execute(); + + $query = "INSERT INTO renders (`render_id`, `type`) VALUES (:uid, 'character');"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + } +?> \ No newline at end of file diff --git a/core/func/api/character/post/wearItem.php b/core/func/api/character/post/wearItem.php new file mode 100644 index 0000000..efe6982 --- /dev/null +++ b/core/func/api/character/post/wearItem.php @@ -0,0 +1,81 @@ +prepare("SELECT id FROM wearing WHERE uid = :uid AND catalogid = :id"); + $stmt->bindParam(':id', $catalogId, PDO::PARAM_INT); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + exit; + } + + + $stmt = $GLOBALS['dbcon']->prepare("SELECT id FROM ownedItems WHERE catalogId = :id AND uid = :uid"); + $stmt->bindParam(':id', $catalogId, PDO::PARAM_INT); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + exit; + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT id, deleted, assetid, datafile FROM catalog WHERE id = :id"); + $stmt->bindParam(':id', $catalogId, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($result['deleted'] == 1) { + exit; + } + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM wearing WHERE uid = :uid AND type = :type"); + $stmt->bindParam(':type', $type, PDO::PARAM_STR); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $resultcheck = $stmt->fetch(PDO::FETCH_ASSOC); + if ($type == "hats") { + if ($stmt->rowCount() == 5) { + exit; + } + }else{ + if ($stmt->rowCount() > 0) { + $stmt = $GLOBALS['dbcon']->prepare("DELETE FROM wearing WHERE catalogId=:id AND uid=:user"); + $stmt->bindParam(':user', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':id', $resultcheck['catalogId'], PDO::PARAM_INT); + $stmt->execute(); + } + } + if ($type == "hats" or $type == "gear" or $type == "faces" or $type == "heads") { + $aprString = "http://xdiscuss.net/data/assets/".$type."/models/".$result['datafile']; + } + if ($type == "shirts" or $type == "pants" or $type == "tshirts") { + $aprString = "http://xdiscuss.net/data/assets/".$type."/models/get.php?id=".$result['assetid']; + } + if ($type == "torso" or $type == "leftarm" or $type == "leftleg" or $type == "rightarm" or $type == "rightleg") { + $aprString = "http://xdiscuss.net/data/assets/package/models/".$result['datafile']; + } + $stmt = $GLOBALS['dbcon']->prepare("INSERT INTO wearing (`uid`, `catalogid`, `type`, `aprString`) VALUES (:user, :itemid, :type, :aprString);"); + $stmt->bindParam(':user', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':itemid', $catalogId, PDO::PARAM_INT); + $stmt->bindParam(':type', $type, PDO::PARAM_STR); + $stmt->bindParam(':aprString', $aprString, PDO::PARAM_STR); + $stmt->execute(); + + $query = "INSERT INTO renders (`render_id`, `type`) VALUES (:uid, 'character');"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $_COOKIE['auth_uid'], PDO::PARAM_INT); + $stmt->execute(); + + exit; + } +?> \ No newline at end of file diff --git a/core/func/api/chat/createChat.php b/core/func/api/chat/createChat.php new file mode 100644 index 0000000..b97a2a8 --- /dev/null +++ b/core/func/api/chat/createChat.php @@ -0,0 +1,49 @@ + 64) die("chat-name-too-long"); + + if (context::getTimeSince($GLOBALS['userTable']['lastUpload']) < 5) { + die("rate-limit"); + } + + $stmt = $GLOBALS['dbcon']->prepare('UPDATE users SET lastUpload = NOW() WHERE id = :uid;'); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $chatKey = context::random_str(32); + $chatJoinKey = context::random_str(8); + $stmt = $GLOBALS['dbcon']->prepare("INSERT INTO chat_sessions (`chatName`, `chatKey`, `chatJoinKey`) VALUES (:chatName, :chatKey, :chatJoinKey);"); + $stmt->bindParam(':chatName', $chatName, PDO::PARAM_STR); + $stmt->bindParam(':chatKey', $chatKey, PDO::PARAM_STR); + $stmt->bindParam(':chatJoinKey', $chatJoinKey, PDO::PARAM_STR); + $stmt->execute(); + + $query = "SELECT id, chatName, chatKey FROM chat_sessions WHERE chatKey = :chatKey"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':chatKey', $chatKey, PDO::PARAM_STR); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $chatID = $result['id']; + + $stmt = $GLOBALS['dbcon']->prepare("INSERT INTO chat_members (`chat_id`, `userId`, `rank`) VALUES (:chatId, :userId, 1);"); + $stmt->bindParam(':chatId', $chatID, PDO::PARAM_STR); + $stmt->bindParam(':userId', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $rows[] = array('chat_id' => $result['id'], + 'chatName' => context::secureString($result['chatName']), + 'chatKey' => context::secureString($result['chatKey'])); + + die(json_encode($rows)); + }else{ + die("error"); + } +?> \ No newline at end of file diff --git a/core/func/api/chat/getChatInfo.php b/core/func/api/chat/getChatInfo.php new file mode 100644 index 0000000..1f42815 --- /dev/null +++ b/core/func/api/chat/getChatInfo.php @@ -0,0 +1,27 @@ +prepare('SELECT id FROM chat_members WHERE userId = :userId AND chat_id = :id'); + $stmt->bindParam(':userId', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) die("error"); + + $stmt = $GLOBALS['dbcon']->prepare('SELECT chatName, chatJoinKey FROM chat_sessions WHERE id = :chatID'); + $stmt->bindParam(':chatID', $id, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + + $stmt = $GLOBALS['dbcon']->prepare('SELECT id FROM chat_members WHERE chat_id = :chatID'); + $stmt->bindParam(':chatID', $id, PDO::PARAM_INT); + $stmt->execute(); + $chatMemberCount = $stmt->rowCount(); + + $rows[] = array('chatMembers' => $chatMemberCount, 'chatName' => context::secureString($result['chatName']), 'joinKey' => context::secureString($result['chatJoinKey'])); + die(json_encode($rows)); + }else{ + die("error"); + } +?> \ No newline at end of file diff --git a/core/func/api/chat/getList.php b/core/func/api/chat/getList.php new file mode 100644 index 0000000..c435351 --- /dev/null +++ b/core/func/api/chat/getList.php @@ -0,0 +1,23 @@ +prepare('SELECT chat_id FROM chat_members WHERE userId = :userId'); + $stmt->bindParam(':userId', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $rows = array(); + foreach($stmt as $result) { + $chatID = $result['chat_id']; + $stmtChat = $GLOBALS['dbcon']->prepare('SELECT id, chatName, chatKey FROM chat_sessions WHERE id = :chatID'); + $stmtChat->bindParam(':chatID', $chatID, PDO::PARAM_INT); + $stmtChat->execute(); + foreach($stmtChat as $resultChat) { + $rows[] = array('chat_id' => $resultChat['id'], + 'chatName' => context::secureString($resultChat['chatName']), + 'chatKey' => context::secureString($resultChat['chatKey'])); + } + } + die(json_encode($rows)); + }else{ + die("error"); + } +?> \ No newline at end of file diff --git a/core/func/api/chat/getMessages.php b/core/func/api/chat/getMessages.php new file mode 100644 index 0000000..bdbf0c6 --- /dev/null +++ b/core/func/api/chat/getMessages.php @@ -0,0 +1,51 @@ +prepare('SELECT id FROM chat_members WHERE userId = :userId AND chat_id = :id'); + $stmt->bindParam(':userId', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) api::returnString("error"); + + $stmtChat = $GLOBALS['dbcon']->prepare('SELECT * FROM chat_messages WHERE chat_id = :chatID AND date > :timestamp'); + $stmtChat->bindParam(':chatID', $id, PDO::PARAM_INT); + $stmtChat->bindParam(':timestamp', $timestamp, PDO::PARAM_INT); + $stmtChat->execute(); + $rows = array(); + foreach($stmtChat as $resultChat) { + $stmt = $GLOBALS['dbcon']->prepare('SELECT id, username, rank FROM users WHERE id = :userId'); + $stmt->bindParam(':userId', $resultChat['userId'], PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $setRight = false; + if ($result['username'] == $GLOBALS['userTable']['username']) $setRight = true; + if ($result['rank'] > 0) { + $color = "red"; + $rank = 1; + }else{ + $color = "black"; + $rank = 0; + } + + $message = context::secureString($resultChat['message']); + $message = context::parseEmoticon($message); + + $rows[] = array('messageId' => $resultChat['id'], + 'userId' => $resultChat['userId'], + 'username' => $result['username'], + 'staff' => $rank, + 'setRight' => $setRight, + 'userColor' => $color, + 'date' => $resultChat['date'], + 'userID' => $result['id'], + 'message' => $message); + } + // Get all chat messages + die(json_encode($rows)); + }else{ + die("error"); + } +?> \ No newline at end of file diff --git a/core/func/api/chat/getTyping.php b/core/func/api/chat/getTyping.php new file mode 100644 index 0000000..8684810 --- /dev/null +++ b/core/func/api/chat/getTyping.php @@ -0,0 +1,34 @@ +prepare('SELECT lastType, userId FROM chat_members WHERE chat_id = :chatID'); + $stmt->bindParam(':chatID', $chatId, PDO::PARAM_INT); + $stmt->execute(); + $rows_typing = array(); + $usernames = array(); + $count = 0; + foreach($stmt as $result) { + if (context::getTimeSince($result['lastType']) < 0.06 && $result['userId'] != $GLOBALS['userTable']['id']) { + $count++; + $username = context::IDToUsername($result['userId']); + $usernames[] = $username; + } + } + + if ($count == 0) { + $mode = "none"; + }else if ($count < 3) { + $mode = "showTyping"; + }else { + $mode = "severalTyping"; + } + $rows_typing[] = array('usernames' => $usernames, 'mode' => $mode); + $json = context::jsonToSingle(json_encode($rows_typing)); + die($json); + }else{ + die("error"); + } +?> \ No newline at end of file diff --git a/core/func/api/chat/joinChat.php b/core/func/api/chat/joinChat.php new file mode 100644 index 0000000..3da1625 --- /dev/null +++ b/core/func/api/chat/joinChat.php @@ -0,0 +1,49 @@ + 64) die("chat-code-too-long"); + + $query = "SELECT id, chatJoinKey, chatName, chatKey FROM chat_sessions WHERE chatJoinKey = :chatKey"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':chatKey', $chatCode, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() == 0) die("invalid-code"); + + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $chatID = $result['id']; + $chatKey = $result['chatKey']; + + $query = "SELECT id FROM chat_members WHERE chat_id = :chatId AND userId = :userId"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':chatId', $chatID, PDO::PARAM_INT); + $stmt->bindParam(':userId', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() > 0) die("already-in"); + + $stmt = $GLOBALS['dbcon']->prepare("INSERT INTO chat_members (`chat_id`, `userId`, `rank`) VALUES (:chatId, :userId, 0);"); + $stmt->bindParam(':chatId', $chatID, PDO::PARAM_INT); + $stmt->bindParam(':userId', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $time = time(); + $message = $GLOBALS['userTable']['username'].' has joined'; + $stmt = $GLOBALS['dbcon']->prepare("INSERT INTO chat_messages (`chat_id`, `userId`, `message`, `bot`, `date`) VALUES (:chatId, 0, :message, 1, :time);"); + $stmt->bindParam(':chatId', $chatID, PDO::PARAM_INT); + $stmt->bindParam(':message', $message, PDO::PARAM_STR); + $stmt->bindParam(':time', $time, PDO::PARAM_INT); + $stmt->execute(); + + $rows[] = array('chat_id' => $result['id'], + 'chatName' => context::secureString($result['chatName']), + 'chatKey' => context::secureString($result['chatKey'])); + + die(json_encode($rows)); + }else{ + die("error"); + } +?> \ No newline at end of file diff --git a/core/func/api/chat/sendMessage.php b/core/func/api/chat/sendMessage.php new file mode 100644 index 0000000..cfb7e59 --- /dev/null +++ b/core/func/api/chat/sendMessage.php @@ -0,0 +1,41 @@ +prepare('SELECT id, chatKey FROM chat_sessions WHERE id = :chatId'); + $stmt->bindParam(':chatId', $_POST['chatId'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) die("error"); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + + // Check if everything matches up + if (strlen($message) > 128) die("message-too-long"); + + if (strlen($message) < 1) die("message-too-short"); + + // Also check if the current user is indeed in the chat. + $stmt = $GLOBALS['dbcon']->prepare('SELECT id FROM chat_members WHERE userId = :userId AND chat_id = :id'); + $stmt->bindParam(':userId', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':id', $chatId, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) die("error"); + + // If we're still here, we can go and add the message, encrypt message again + $time = time(); + $stmt = $GLOBALS['dbcon']->prepare("INSERT INTO chat_messages (`chat_id`, `userId`, `message`, `date`) VALUES (:chatId, :userId, :message, :timestamp);"); + $stmt->bindParam(':chatId', $chatId, PDO::PARAM_INT); + $stmt->bindParam(':userId', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':message', $message, PDO::PARAM_STR); + $stmt->bindParam(':timestamp', $time, PDO::PARAM_INT); + $stmt->execute(); + + die("success"); + }else{ + die("error"); + } +?> \ No newline at end of file diff --git a/core/func/api/chat/sendTyping.php b/core/func/api/chat/sendTyping.php new file mode 100644 index 0000000..b2b4e80 --- /dev/null +++ b/core/func/api/chat/sendTyping.php @@ -0,0 +1,17 @@ +prepare($query); + $stmt->bindParam(':userId', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':chatId', $chatId, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() == 0) die("error"); + die("success"); + }else{ + die("error"); + } +?> \ No newline at end of file diff --git a/core/func/api/chat/sounds/send.mp3 b/core/func/api/chat/sounds/send.mp3 new file mode 100644 index 0000000..22718c3 Binary files /dev/null and b/core/func/api/chat/sounds/send.mp3 differ diff --git a/core/func/api/forum/doSearch.php b/core/func/api/forum/doSearch.php new file mode 100644 index 0000000..0d98fc6 --- /dev/null +++ b/core/func/api/forum/doSearch.php @@ -0,0 +1,18 @@ +prepare('SELECT name, id FROM forums WHERE id = :id;'); + $stmt->bindParam(':id', $forumId, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($stmt->rowCount() == 0) exit; + echo ''; + echo '
'; + echo '
'; + echo '

Using this utility, you can search for posts. Just enter something and our system will search for you

'; + }else{ + echo 'An error occurred'; + } +?> \ No newline at end of file diff --git a/core/func/api/forum/getCatagories.php b/core/func/api/forum/getCatagories.php new file mode 100644 index 0000000..43ef6ef --- /dev/null +++ b/core/func/api/forum/getCatagories.php @@ -0,0 +1,15 @@ +prepare("SELECT name, id FROM catagories WHERE developer = 0"); + $stmt->execute(); + foreach($stmt as $result) { + echo '

'.context::secureString($result['name']).'

'; + } +?> \ No newline at end of file diff --git a/core/func/api/forum/getMiniProfile.php b/core/func/api/forum/getMiniProfile.php new file mode 100644 index 0000000..0310375 --- /dev/null +++ b/core/func/api/forum/getMiniProfile.php @@ -0,0 +1,34 @@ +prepare('SELECT id, imgTime, username, banned, lastSeen, rank, posts FROM users WHERE username = :username;'); + $stmt->bindParam(':username', $username, PDO::PARAM_STR); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($stmt->rowCount() == 0 or $result['banned'] == 1) { + echo 'User not found or suspended'; + echo ''; + exit; + } + echo ''; + echo ''; + if ($result['rank'] == 1) { + echo '

Administrator

'; + } + if ($result['rank'] == 2) { + echo '

Moderator

'; + } + echo '

Posts: '.$result['posts'].'

'; + echo '
Full Profile'; + if ($GLOBALS['loggedIn'] == true && $GLOBALS['userTable']['username'] != $result['username']) { + echo 'Send Message'; + } + echo '
'; + }else{ + echo 'An error occurred'; + } +?> diff --git a/core/func/api/forum/getPosts.php b/core/func/api/forum/getPosts.php new file mode 100644 index 0000000..ade067d --- /dev/null +++ b/core/func/api/forum/getPosts.php @@ -0,0 +1,195 @@ + 0) { + $keyword = $_GET['keyword']; + if (is_array($keyword)) exit; + $searchTermSQL = '%'.$keyword.'%'; + } + + $offset = $page*25; + include_once $_SERVER['DOCUMENT_ROOT'].'/core/func/includes.php'; + if ($page == 0) { + $stmt = $GLOBALS['dbcon']->prepare("SELECT id, posts, replies, name, description, locked FROM forums WHERE id = :fId AND developer = 0"); + $stmt->bindParam(':fId', $id, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'Forum not found'; + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $id = $result['id']; + echo ''; + echo '

'.context::secureString($result['name']).'

'; + echo ''; + if (!isset($keyword)) echo '

'.context::secureString($result['description']).'

'; + if (isset($keyword)) echo '

Searching by name: '.context::secureString($_GET['keyword']).'

'; + }else{ + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM forums WHERE id = :fId"); + $stmt->bindParam(':fId', $id, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'Forum not found'; + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $id = $result['id']; + } + + function showLockedStatus($locked) { + if ($locked == 1) { + return ''; + } + } + + function showPinStatus() { + return ''; + } + + + // Pinned posts + if ($page == 0 && !isset($keyword)) { + $stmt = $GLOBALS['dbcon']->prepare("SELECT id, author_uid, postTime, lastActivity, views, replies, title FROM topics WHERE forumId = :fId AND pinned = 1 ORDER BY lastActivity ASC"); + $stmt->bindParam(':fId', $id, PDO::PARAM_INT); + $stmt->execute(); + echo '
'; + $count = 0; + foreach($stmt as $result) { + $count++; + if ($count < 25) { + $userSheet = context::getUserSheetByIDForum($result['author_uid']); + if ($userSheet['rank'] == 0) { + $usern = $userSheet['username']; + }elseif ($userSheet['rank'] == 1) { + $usern = ' '.$userSheet['username'].''; + }elseif ($userSheet['rank'] == 2) { + $usern = ' '.$userSheet['username'].''; + } + echo '
'; + echo '
'; + echo '

'.showPinStatus().' '.context::secureString($result['title']).'

'; + echo ''; + echo '

Posted by '.$usern.'

'; + echo ''; + // Get last poster + $stmtr = $GLOBALS['dbcon']->prepare("SELECT author_uid FROM `replies` WHERE `postId` = :id ORDER BY id DESC LIMIT 1;"); + $stmtr->bindParam(':id', $result['id'], PDO::PARAM_INT); + $stmtr->execute(); + $resultReplyer = $stmtr->fetch(PDO::FETCH_ASSOC); + if ($stmtr->rowCount() > 0) { + $userID = $resultReplyer['author_uid']; + }else{ + $userID = $result['author_uid']; + } + $userSheetLast = context::getUserSheetByID($userID); + if ($userSheetLast['rank'] == 0) { + $usern = $userSheetLast['username']; + }elseif ($userSheetLast['rank'] == 1) { + $usern = ' '.$userSheetLast['username'].''; + }elseif ($userSheetLast['rank'] == 2) { + $usern = ' '.$userSheetLast['username'].''; + } + echo 'Last Post: '.context::humanTimingSince(strtotime($result['lastActivity'])).' ago by '.$usern.''; + echo '
'; + } + } + } + + if (!isset($keyword)) $stmt = $GLOBALS['dbcon']->prepare("SELECT id, author_uid, postTime, lastActivity, views, replies, title FROM topics WHERE forumId = :fId AND pinned = 0 ORDER BY lastActivity DESC LIMIT 26 OFFSET :offset"); + if (isset($keyword)) { + $stmt = $GLOBALS['dbcon']->prepare("SELECT id, author_uid, postTime, lastActivity, views, replies, title FROM topics WHERE forumId = :fId AND title LIKE :term ORDER BY lastActivity DESC LIMIT 26 OFFSET :offset"); + $stmt->bindParam(':term', $searchTermSQL, PDO::PARAM_STR); + } + $stmt->bindParam(':fId', $id, PDO::PARAM_INT); + $stmt->bindParam(':offset', $offset, PDO::PARAM_INT); + $stmt->execute(); + echo '
'; + $count = 0; + foreach($stmt as $result) { + $count++; + if ($count < 25) { + $userSheet = context::getUserSheetByIDForum($result['author_uid']); + if ($userSheet['rank'] == 0) { + $usern = $userSheet['username']; + }elseif ($userSheet['rank'] == 1) { + $usern = ' '.$userSheet['username'].''; + }elseif ($userSheet['rank'] == 2) { + $usern = ' '.$userSheet['username'].''; + } + echo '
'; + echo '
'; + echo '

'.showLockedStatus($result['locked']).' '.context::secureString($result['title']).'

'; + echo ''; + echo '

Posted by '.$usern.'

'; + echo ''; + // Get last poster + $stmtr = $GLOBALS['dbcon']->prepare("SELECT author_uid FROM `replies` WHERE `postId` = :id ORDER BY id DESC LIMIT 1;"); + $stmtr->bindParam(':id', $result['id'], PDO::PARAM_INT); + $stmtr->execute(); + $resultReplyer = $stmtr->fetch(PDO::FETCH_ASSOC); + if ($stmtr->rowCount() > 0) { + $userID = $resultReplyer['author_uid']; + }else{ + $userID = $result['author_uid']; + } + $userSheetLast = context::getUserSheetByID($userID); + if ($userSheetLast['rank'] == 0) { + $usern = $userSheetLast['username']; + }elseif ($userSheetLast['rank'] == 1) { + $usern = ' '.$userSheetLast['username'].''; + }elseif ($userSheetLast['rank'] == 2) { + $usern = ' '.$userSheetLast['username'].''; + } + echo 'Last Post: '.context::humanTimingSince(strtotime($result['lastActivity'])).' ago by '.$usern.''; + echo '
'; + } + } + if ($stmt->rowCount() == 0) { + echo 'There seems to be no post in this subforum. You could start the first one!'; + } + if ($count > 25) { + if (!isset($keyword)) echo ''; + if (isset($keyword)) echo ''; + } + echo '
'; + }else{ + echo 'An error occurred'; + } +?> \ No newline at end of file diff --git a/core/func/api/forum/newPost.php b/core/func/api/forum/newPost.php new file mode 100644 index 0000000..15c4db2 --- /dev/null +++ b/core/func/api/forum/newPost.php @@ -0,0 +1,23 @@ +prepare("SELECT * FROM forums WHERE id = :fId AND developer = 0"); + $stmt->bindParam(':fId', $id, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) die("Forum not found"); + + $result = $stmt->fetch(PDO::FETCH_ASSOC); + echo '

Posting in '.context::secureString($result['name']).'

'; + include_once $_SERVER['DOCUMENT_ROOT'].'/core/func/api/forum/views/newPost.php'; + }else{ + echo 'An error occurred'; + } +?> \ No newline at end of file diff --git a/core/func/api/forum/newReply.php b/core/func/api/forum/newReply.php new file mode 100644 index 0000000..6933010 --- /dev/null +++ b/core/func/api/forum/newReply.php @@ -0,0 +1,25 @@ +prepare("SELECT * FROM topics WHERE id = :fId AND developer = 0"); + $stmt->bindParam(':fId', $id, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'Post could not be found'; + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + echo '

Replying to '.context::secureString($result['title']).'

'; + include_once $_SERVER['DOCUMENT_ROOT'].'/core/func/api/forum/views/newReply.php'; + }else{ + echo 'An error occurred'; + } +?> \ No newline at end of file diff --git a/core/func/api/forum/post/deletePost.php b/core/func/api/forum/post/deletePost.php new file mode 100644 index 0000000..d1534e9 --- /dev/null +++ b/core/func/api/forum/post/deletePost.php @@ -0,0 +1,105 @@ +prepare("SELECT author_uid, forumId FROM topics WHERE id = :id AND developer = 0 ORDER BY id DESC LIMIT 1;"); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($stmt->rowCount() == 0) { + echo 'error'; + exit; + } + + $timeSince = round(abs(strtotime(context::getCurrentTime()) - strtotime($GLOBALS['userTable']['lastUpload'])) / 60,2); + if ($timeSince < 1 && $GLOBALS['userTable']['rank'] != 1) { + echo 'rate-limit'; + exit; + } + + $forumId = $result['forumId']; + $userId = $result['author_uid']; + + $stmt = $GLOBALS['dbcon']->prepare("SELECT posts FROM users WHERE id = :id ORDER BY id DESC LIMIT 1;"); + $stmt->bindParam(':id', $userId, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + + $posts = $result['posts']-1; + + $query = "UPDATE `users` SET `posts`=:posts WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $userId, PDO::PARAM_INT); + $stmt->bindParam(':posts', $posts, PDO::PARAM_INT); + $stmt->execute(); + + $query = "DELETE FROM `topics` WHERE `id`=:id"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("SELECT id, author_uid FROM replies WHERE postId = :id"); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->execute(); + foreach($stmt as $result) { + $userId = $result['author_uid']; + $stmt = $GLOBALS['dbcon']->prepare("SELECT posts FROM users WHERE id = :id ORDER BY id DESC LIMIT 1;"); + $stmt->bindParam(':id', $userId, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + + $posts = $result['posts']-1; + $query = "UPDATE `users` SET `posts`=:posts WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $userId, PDO::PARAM_INT); + $stmt->bindParam(':posts', $posts, PDO::PARAM_INT); + $stmt->execute(); + } + + $query = "DELETE FROM `replies` WHERE `postId`=:id"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->execute(); + + $query = "DELETE FROM `read` WHERE `postId`=:id"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->execute(); + + $query = "SELECT * FROM topics WHERE forumId=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $forumId, PDO::PARAM_INT); + $stmt->execute(); + $total = $stmt->rowCount(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE forums SET posts = :posts WHERE id=:id;"); + $stmt->bindParam(':id', $forumId, PDO::PARAM_INT); + $stmt->bindParam(':posts', $total, PDO::PARAM_INT); + $stmt->execute(); + + $query = "SELECT * FROM replies WHERE forumId=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $forumId, PDO::PARAM_INT); + $stmt->execute(); + $total = $stmt->rowCount(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE forums SET replies = :posts WHERE id=:id;"); + $stmt->bindParam(':id', $forumId, PDO::PARAM_INT); + $stmt->bindParam(':posts', $total, PDO::PARAM_INT); + $stmt->execute(); + + if ($GLOBALS['userTable']['rank'] != 1) { + $stmt = $dbcon->prepare("UPDATE users SET lastUpload = NOW() WHERE id = :user;"); + $stmt->bindParam(':user', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + } + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/forum/post/lockPost.php b/core/func/api/forum/post/lockPost.php new file mode 100644 index 0000000..da65539 --- /dev/null +++ b/core/func/api/forum/post/lockPost.php @@ -0,0 +1,22 @@ +prepare($query); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->execute(); + + $query = "UPDATE `topics` SET `lockedByStaff`=1 WHERE `id`=:id AND `developer` = 0;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->execute(); + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/forum/post/newPost.php b/core/func/api/forum/post/newPost.php new file mode 100644 index 0000000..807a491 --- /dev/null +++ b/core/func/api/forum/post/newPost.php @@ -0,0 +1,159 @@ +You have already posted this'); + + // Fixes things like "this i>s ex<" + $badwords2 = array("sex", "porn"); + if (context::contains($postContent, $badwords2)) { + echo 'This post contains filtered words.'; + exit; + } + + // Check without special characters removed, will catch stuff like N* + if (context::contains($contentCheck, $badwords) or context::contains($titleCheck, $badwords)) { + echo 'This post or post title contains filtered words.'; + exit; + } + + // Check again but with special characters removed, except * + $titleCheck = preg_replace("/[^A-Za-z0-9*]/", '', $titleCheck); + $contentCheck = preg_replace("/[^A-Za-z0-9*]/", '', $contentCheck); + if (context::contains($contentCheck, $badwords) or context::contains($titleCheck, $badwords)) { + echo 'This post or post title contains filtered words.'; + exit; + } + + if (!preg_match("/^[\w*?!\/@',:#$%\^&*\(\) -]+$/", $postTitle) == 1) { + die('Invalid characters in title.'); + } + + if (strlen($postTitle) < 5 or strlen($titleCheck) < 5) { + echo 'title-too-short'; + exit; + } + + if (strlen($postTitle) > 128) { + echo 'title-too-long'; + exit; + } + + if (strlen($postContent) < 5 or strlen($contentCheck) < 5) { + echo 'content-too-short'; + exit; + } + + if (strlen($postContent) > 30000) { + echo 'content-too-long'; + exit; + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT lastPost, joinDate, rank FROM users WHERE id = :id"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $timeSince = round(abs(strtotime(date('Y-m-d H:i:s')) - strtotime($result['lastPost'])) / 60,2); + if ($timeSince < 0.5 and $result['rank'] == 0) { + echo 'rate-limit'; + exit; + } + + $timeSince = round(abs(strtotime(date('Y-m-d H:i:s')) - strtotime($result['joinDate'])) / 60,2); + if ($timeSince < 1440 and $result['rank'] == 0) { + echo 'account-age'; + exit; + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM forums WHERE id = :id AND developer = 0"); + $stmt->bindParam(':id', $forum, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'no-forum'; + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($result['locked'] == 1 and $GLOBALS['userTable']['rank'] != 1) { + echo 'access-denied'; + exit; + } + + $query = "INSERT INTO topics (`forumId`, `title`, `author_uid`, `content`, `lastActivity`) VALUES (:forumid, :topicname, :poster, :content, NOW());"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':forumid', $forum, PDO::PARAM_INT); + $stmt->bindParam(':topicname', $postTitle, PDO::PARAM_STR); + $stmt->bindParam(':poster', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':content', $postContent, PDO::PARAM_STR); + $stmt->execute(); + + $query = "UPDATE `users` SET `lastPost`=NOW() WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $query = "UPDATE `users` SET `lastForumContent`=:content WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':content', $postContent, PDO::PARAM_STR); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM forums WHERE id = :id ORDER BY id DESC LIMIT 1;"); + $stmt->bindParam(':id', $forum, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $posts = $result['posts']+1; + $query = "UPDATE `forums` SET `posts`=:posts WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $forum, PDO::PARAM_INT); + $stmt->bindParam(':posts', $posts, PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("SELECT posts FROM users WHERE id = :id ORDER BY id DESC LIMIT 1;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $posts = $result['posts']+1; + $query = "UPDATE `users` SET `posts`=:posts WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':posts', $posts, PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $dbcon->prepare("SELECT id FROM topics WHERE author_uid = :id ORDER BY id DESC LIMIT 1;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + echo ''; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/forum/post/newReply.php b/core/func/api/forum/post/newReply.php new file mode 100644 index 0000000..7e977fc --- /dev/null +++ b/core/func/api/forum/post/newReply.php @@ -0,0 +1,158 @@ +You have already posted this'); + + $badwords = array("fucking", "gay", "rape", "incest", "beastiality", "cum", "maggot", "bullshit", "fuck", "penis", + "dick", "vagina", "vag", "faggot", "fag", "nigger", "asshole", "shit", "bitch", "anal", "stfu", + "cunt", "pussy", "hump", "meatspin", "redtube", "porn", "kys", "xvideos", "hentai", "gangbang", "milf", + "n*", "nobelium", "whore", "wtf", "horny", "raping", "s3x", "boob", "nigga", "nlgga", "gt2008", + "cock", "dicc", "idiot", "nibba", "nibber", "nude", "kesner", "brickopolis", "nobe", "diemauer", "nuts"); + + $badwords2 = array("sex", "porn"); + if (context::contains($replyContent, $badwords2)) { + echo 'This reply contains filtered words.'; + exit; + } + + + // Check without special characters removed + if (context::contains($contentCheck, $badwords)) { + echo 'This reply contains filtered words.'; + exit; + } + + // Check with special characters removed, except *. + $contentCheck = preg_replace("/[^A-Za-z0-9*]/", '', $contentCheck); + if (context::contains($contentCheck, $badwords)) { + echo 'This reply contains filtered words.'; + exit; + } + + if (strlen($replyContent) < 5 or strlen($contentCheck) < 5) { + echo 'content-too-short'; + exit; + } + + if (strlen($replyContent) > 30000) { + echo 'content-too-long'; + exit; + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT lastPost, joinDate, rank FROM users WHERE id = :id"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $timeSince = round(abs(strtotime(date('Y-m-d H:i:s')) - strtotime($result['lastPost'])) / 60,2); + if ($timeSince < 0.5 and $result['rank'] == 0) { + echo 'rate-limit'; + exit; + } + + $timeSince = round(abs(strtotime(date('Y-m-d H:i:s')) - strtotime($result['joinDate'])) / 60,2); + if ($timeSince < 1440 and $result['rank'] == 0) { + echo 'account-age'; + exit; + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM topics WHERE id = :id AND developer = 0"); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'no-post'; + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $postId = $result['id']; + $forumId = $result['forumId']; + if ($result['locked'] == 1 and $GLOBALS['userTable']['rank'] == 0) { + echo 'access-denied'; + exit; + } + + $query = "INSERT INTO replies (`postId`, `content`, `author_uid`, `forumId`) VALUES (:id, :content, :poster, :forumId);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->bindParam(':poster', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':content', $replyContent, PDO::PARAM_STR); + $stmt->bindParam(':forumId', $forumId, PDO::PARAM_INT); + $stmt->execute(); + + $query = "UPDATE `topics` SET `lastActivity`=NOW() WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->execute(); + + $query = "UPDATE `users` SET `lastPost`=NOW() WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $query = "UPDATE `users` SET `lastForumContent`=:content WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':content', $replyContent, PDO::PARAM_STR); + $stmt->execute(); + + $query = "DELETE FROM `read` WHERE `postId`=:id"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("SELECT replies FROM forums WHERE id = :id ORDER BY id DESC LIMIT 1;"); + $stmt->bindParam(':id', $forumId, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + + $posts = $result['replies']+1; + + $query = "UPDATE `forums` SET `replies`=:posts WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $forumId, PDO::PARAM_INT); + $stmt->bindParam(':posts', $posts, PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("SELECT replies FROM topics WHERE id = :id ORDER BY id DESC LIMIT 1;"); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + + $posts = $result['replies']+1; + + $query = "UPDATE `topics` SET `replies`=:posts WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->bindParam(':posts', $posts, PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("SELECT posts FROM users WHERE id = :id ORDER BY id DESC LIMIT 1;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + + $posts = $result['posts']+1; + $query = "UPDATE `users` SET `posts`=:posts WHERE `id`=:id;"; + $stmt = $dbcon->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':posts', $posts, PDO::PARAM_INT); + $stmt->execute(); + + echo ''; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/forum/post/pinPost.php b/core/func/api/forum/post/pinPost.php new file mode 100644 index 0000000..0180b24 --- /dev/null +++ b/core/func/api/forum/post/pinPost.php @@ -0,0 +1,18 @@ +prepare($query); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->execute(); + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/forum/post/unlockPost.php b/core/func/api/forum/post/unlockPost.php new file mode 100644 index 0000000..2ce3b3f --- /dev/null +++ b/core/func/api/forum/post/unlockPost.php @@ -0,0 +1,23 @@ +prepare($query); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->execute(); + + $query = "UPDATE `topics` SET `lockedByStaff`=0 WHERE `id`=:id AND `developer`=0;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->execute(); + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/forum/post/unpinPost.php b/core/func/api/forum/post/unpinPost.php new file mode 100644 index 0000000..50f2228 --- /dev/null +++ b/core/func/api/forum/post/unpinPost.php @@ -0,0 +1,18 @@ +prepare($query); + $stmt->bindParam(':id', $postId, PDO::PARAM_INT); + $stmt->execute(); + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/forum/showPost.php b/core/func/api/forum/showPost.php new file mode 100644 index 0000000..56ac7cb --- /dev/null +++ b/core/func/api/forum/showPost.php @@ -0,0 +1,193 @@ + +prepare("SELECT id, author_uid, postTime, lastActivity, views, replies, title, content, forumId, locked, pinned FROM topics WHERE id = :id AND developer = 0"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'Topic not found'; + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $id = $result['id']; + $stmtr = $GLOBALS['dbcon']->prepare("SELECT id FROM `read` WHERE `userId` = :id AND `postId` = :pid;"); + $stmtr->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmtr->bindParam(':pid', $id, PDO::PARAM_INT); + $stmtr->execute(); + $resultread = $stmt->fetch(PDO::FETCH_ASSOC); + if ($stmtr->rowCount() == 0) { + $read = false; + }else{ + $read = true; + } + + if ($read == false and $loggedIn == true) { + $query = "INSERT INTO `read` (`userId`, `postId`) VALUES (:userId, :postId);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':postId', $id, PDO::PARAM_INT); + $stmt->bindParam(':userId', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE topics SET views = views + 1 WHERE id = :id"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + } + + echo ''; + echo '

'.context::secureString($result['title']).'

'; + echo ''; + $userSheet = context::getUserSheetByID($result['author_uid']); + if ($userSheet['rank'] == 0) { + $usern = $userSheet['username']; + }elseif ($userSheet['rank'] == 1) { + $usern = ''.$userSheet['username'].''; + }elseif ($userSheet['rank'] == 2) { + $usern = ''.$userSheet['username'].''; + } + echo '

Started by '.$usern.'

'; + echo '
+
'.context::getOnline($userSheet).''.$usern.'
+
'; + if ($userSheet['rank'] == 1) { + echo '

Administrator

'; + } + if ($userSheet['rank'] == 2) { + echo '

Moderator

'; + } + context::checkTopPoster($userSheet['id']); + echo 'Joined: '.date('M j Y', strtotime($userSheet['joinDate'])).'
+ Posts: '.$userSheet['posts'].' +
'; + $content = strip_tags($result['content']); + $content = context::secureString($content); + $content = preg_replace("/\s*[a-zA-Z\/\/:\.]*youtube.com\/watch\?v=([a-zA-Z0-9\-_]+)([a-zA-Z0-9\/\*\-\_\?\&\;\%\=\.]*)/i","", $content); + if ($userSheet['rank'] > 0) { + $content = preg_replace("/https?:\/\/[^ ]+?(?:\.jpg|\.png|\.gif)/",'', $content); + } + $content = context::showBBcodes($content); + $content = context::parseEmoticon($content); + echo '
+ Posted on: '.date('M j Y g:i A', strtotime($result['postTime'])).'
+ '.nl2br($content).' +
'; + }else{ + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM topics WHERE id = :id"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'Topic not found!'; + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $id = $result['id']; + } + + $stmt = $dbcon->prepare("SELECT author_uid, content, post_time FROM replies WHERE postId = :id ORDER BY id DESC LIMIT 16 OFFSET :offset;"); + $stmt->bindParam(':offset', $offset, PDO::PARAM_INT); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + $count = 0; + foreach($stmt as $result) { + $count++; + if ($count < 16) { + $userSheet = context::getUserSheetByID($result['author_uid']); + if ($userSheet['rank'] == 0) { + $usern = $userSheet['username']; + }elseif ($userSheet['rank'] == 1) { + $usern = ''.$userSheet['username'].''; + }elseif ($userSheet['rank'] == 2) { + $usern = ''.$userSheet['username'].''; + } + echo '
+
'.context::getOnline($userSheet).''.$usern.'
+
'; + if ($userSheet['rank'] == 1) { + echo '

Administrator

'; + } + if ($userSheet['rank'] == 2) { + echo '

Moderator

'; + } + context::checkTopPoster($userSheet['id']); + echo 'Joined: '.date('M j Y', strtotime($userSheet['joinDate'])).'
+ Posts: '.$userSheet['posts'].' +
'; + $content = strip_tags($result['content']); + $content = context::secureString($content); + $content = preg_replace("/\s*[a-zA-Z\/\/:\.]*youtube.com\/watch\?v=([a-zA-Z0-9\-_]+)([a-zA-Z0-9\/\*\-\_\?\&\;\%\=\.]*)/i","", $content); + if ($userSheet['rank'] > 0) { + $content = preg_replace("/https?:\/\/[^ ]+?(?:\.jpg|\.png|\.gif)/",'', $content); + } + $content = context::showBBcodes($content); + $content = context::parseEmoticon($content); + echo '
+ Posted on: '.date('M j Y g:i A', strtotime($result['post_time'])).'
+ '.nl2br($content).' +
'; + } + } + if ($count > 15) { + echo ''; + } + }else{ + echo 'An error occurred'; + } +?> \ No newline at end of file diff --git a/core/func/api/forum/views/newPost.php b/core/func/api/forum/views/newPost.php new file mode 100644 index 0000000..e93a797 --- /dev/null +++ b/core/func/api/forum/views/newPost.php @@ -0,0 +1,19 @@ + + +
+

+ + \ No newline at end of file diff --git a/core/func/api/forum/views/newReply.php b/core/func/api/forum/views/newReply.php new file mode 100644 index 0000000..60dfce3 --- /dev/null +++ b/core/func/api/forum/views/newReply.php @@ -0,0 +1,19 @@ + + +
+

+ + \ No newline at end of file diff --git a/core/func/api/friends/get/getFriends.php b/core/func/api/friends/get/getFriends.php new file mode 100644 index 0000000..ea39ab1 --- /dev/null +++ b/core/func/api/friends/get/getFriends.php @@ -0,0 +1,65 @@ +prepare("SELECT * FROM `friends` WHERE `userId1` = :id ORDER BY id DESC LIMIT 10 OFFSET :offset;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':offset', $offset, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0 && $page == 0) { + echo 'You have no Graphictoria friends. Why not make some?'; + } + + echo '
'; + $count = 0; + foreach($stmt as $result) { + $count++; + if ($count < 10) { + $userId = $result['userId2']; + $stmt = $dbcon->prepare("SELECT username, imgTime, id, lastSeen FROM users WHERE id = :id;"); + $stmt->bindParam(':id', $userId, PDO::PARAM_INT); + $stmt->execute(); + $resultuser = $stmt->fetch(PDO::FETCH_ASSOC); + $username = $resultuser['username']; + if (strlen($username) > 10) { + $username = substr($username, 0, 7) . '...'; + } + echo '

'; + echo context::getOnline($resultuser); + echo ''.context::secureString($username).' +


'; + } + } + echo '
'; + echo '
'; + if ($page > 0) { + echo '« Previous'; + } + if ($count > 9) { + echo 'Next »'; + } + if ($count == 0 and $page > 0) { + exit; + } + echo '
'; +?> \ No newline at end of file diff --git a/core/func/api/friends/get/getRequests.php b/core/func/api/friends/get/getRequests.php new file mode 100644 index 0000000..4bc91af --- /dev/null +++ b/core/func/api/friends/get/getRequests.php @@ -0,0 +1,65 @@ +prepare("SELECT * FROM `friendRequests` WHERE `recvuid` = :id ORDER BY id DESC LIMIT 10 OFFSET :offset;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':offset', $offset, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0 && $page == 0) { + echo 'You do not have any friend request inbound.'; + } + + echo '
'; + $count = 0; + foreach($stmt as $result) { + $count++; + if ($count < 10) { + $userId = $result['senduid']; + $stmt = $dbcon->prepare("SELECT username, imgTime, id, lastSeen FROM users WHERE id = :id;"); + $stmt->bindParam(':id', $userId, PDO::PARAM_INT); + $stmt->execute(); + $resultuser = $stmt->fetch(PDO::FETCH_ASSOC); + $username = $resultuser['username']; + if (strlen($username) > 10) { + $username = substr($username, 0, 7) . '...'; + } + echo '

'; + echo context::getOnline($resultuser); + echo ''.context::secureString($username).' +


'; + } + } + echo '
'; + echo '
'; + if ($page > 0) { + echo '« Previous'; + } + if ($count > 9) { + echo 'Next »'; + } + if ($count == 0 and $page > 0) { + exit; + } + echo '
'; +?> \ No newline at end of file diff --git a/core/func/api/friends/get/showFriends.php b/core/func/api/friends/get/showFriends.php new file mode 100644 index 0000000..28375dd --- /dev/null +++ b/core/func/api/friends/get/showFriends.php @@ -0,0 +1,79 @@ +prepare("SELECT id FROM users WHERE id = :id;"); + $stmt->bindParam(':id', $userid, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $userid = $result['id']; + + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM `friends` WHERE `userId1` = :id ORDER BY id DESC LIMIT 10 OFFSET :offset;"); + $stmt->bindParam(':id', $userid, PDO::PARAM_INT); + $stmt->bindParam(':offset', $offset, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0 && $page == 0) { + echo 'This user has no friends.'; + } + + echo '
'; + $count = 0; + foreach($stmt as $result) { + $count++; + if ($count < 10) { + $userId = $result['userId2']; + $stmt = $dbcon->prepare("SELECT username, imgTime, id, lastSeen FROM users WHERE id = :id;"); + $stmt->bindParam(':id', $userId, PDO::PARAM_INT); + $stmt->execute(); + $resultuser = $stmt->fetch(PDO::FETCH_ASSOC); + $username = $resultuser['username']; + if (strlen($username) > 10) { + $username = substr($username, 0, 7) . '...'; + } + echo '

'; + echo context::getOnline($resultuser); + echo ''.context::secureString($username).'

'; + } + } + echo '
'; + echo '
'; + if ($page > 0) { + echo '« Previous'; + } + if ($count > 9) { + echo 'Next »'; + } + if ($count == 0 and $page > 0) { + exit; + } + echo '
'; +?> \ No newline at end of file diff --git a/core/func/api/friends/post/acceptRequest.php b/core/func/api/friends/post/acceptRequest.php new file mode 100644 index 0000000..6cb54c5 --- /dev/null +++ b/core/func/api/friends/post/acceptRequest.php @@ -0,0 +1,100 @@ +prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':sid', $userID, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($stmt->rowCount() == 0) { + echo 'error'; + exit; + } + + if ($result['senduid'] == $GLOBALS['userTable']['id'] and $stmt->rowCount() > 0) { + $query = "DELETE FROM `friendRequests` WHERE `senduid` = :sid AND `recvuid` = :id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':sid', $userID, PDO::PARAM_INT); + $stmt->execute(); + echo 'error'; + exit; + } + + $query = "SELECT * FROM `friends` WHERE `userId1` = :id AND `userId2` = :sid"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':sid', $userID, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + $query = "DELETE FROM `friendRequests` WHERE `senduid` = :sid AND `recvuid` = :id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':sid', $userID, PDO::PARAM_INT); + $stmt->execute(); + echo 'error'; + exit; + } + + $query = "SELECT * FROM `friends` WHERE `userId1` = :sid AND `userId2` = :id"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':sid', $userID, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + $query = "DELETE FROM `friendRequests` WHERE `senduid` = :id AND `recvuid` = :sid;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':sid', $userID, PDO::PARAM_INT); + $stmt->execute(); + echo 'error'; + exit; + } + + $query = "INSERT INTO friends (`userId1`, `userId2`) VALUES (:userId1, :userId2);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':userId1', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':userId2', $userID, PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':userId1', $userID, PDO::PARAM_INT); + $stmt->bindParam(':userId2', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $query = "DELETE FROM `friendRequests` WHERE `senduid` = :sid AND `recvuid` = :id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':sid', $userID, PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM users WHERE id = :id"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $resultuinfo = $stmt->fetch(PDO::FETCH_ASSOC); + $message = ''.htmlentities($resultuinfo['username'], ENT_QUOTES, "UTF-8").' has accepted your friend request. Start a conversation by replying!'; + $query = "INSERT INTO messages (`recv_uid`, `sender_uid`, `title`, `content`) VALUES (:userId1, :userId2, 'Friend Request Accepted', :msg);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':userId1', $userID, PDO::PARAM_INT); + $stmt->bindParam(':userId2', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':msg', $message, PDO::PARAM_STR); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/friends/post/ignoreRequest.php b/core/func/api/friends/post/ignoreRequest.php new file mode 100644 index 0000000..badb90e --- /dev/null +++ b/core/func/api/friends/post/ignoreRequest.php @@ -0,0 +1,21 @@ +prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':sid', $userID, PDO::PARAM_INT); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/friends/post/removeFriend.php b/core/func/api/friends/post/removeFriend.php new file mode 100644 index 0000000..d901bee --- /dev/null +++ b/core/func/api/friends/post/removeFriend.php @@ -0,0 +1,26 @@ +prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':sid', $userID, PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $dbcon->prepare($query); + $stmt->bindParam(':id', $userID, PDO::PARAM_INT); + $stmt->bindParam(':sid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/friends/post/sendRequest.php b/core/func/api/friends/post/sendRequest.php new file mode 100644 index 0000000..7a36818 --- /dev/null +++ b/core/func/api/friends/post/sendRequest.php @@ -0,0 +1,60 @@ +prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':sid', $userID, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + echo 'error'; + exit; + } + + $query = "SELECT * FROM `friendRequests` WHERE `senduid` = :id AND `recvuid` = :sid"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':sid', $userID, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + echo 'error'; + exit; + } + + $currentTime = context::getCurrentTime(); + $from_time = strtotime($GLOBALS['userTable']['lastFR']); + $to_time = strtotime($currentTime); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince < 1) { + echo 'rate-limit'; + exit; + }else{ + $query = "UPDATE users SET lastFR = NOW() WHERE id=:id"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + } + + $query = "INSERT INTO friendRequests (`senduid`, `recvuid`) VALUES (:userId1, :userId2);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':userId1', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':userId2', $userID, PDO::PARAM_INT); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/games/addKey.php b/core/func/api/games/addKey.php new file mode 100644 index 0000000..11301a5 --- /dev/null +++ b/core/func/api/games/addKey.php @@ -0,0 +1,44 @@ +Please enter a key.
'; + $err = true; + } + + if ($err == false) { + $stmt = $dbcon->prepare("SELECT * FROM games WHERE `key` = :key"); + $stmt->bindParam(':key', $key, PDO::PARAM_STR); + $stmt->execute(); + + if ($stmt->rowCount() == 0) { + echo '
Invalid key.
'; + }else{ + // Check if already submitted. + $stmt = $dbcon->prepare("SELECT * FROM gameKeys WHERE `key` = :key AND userid = :uid"); + $stmt->bindParam(':key', $key, PDO::PARAM_STR); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + if ($stmt->rowCount() == 0) { + $stmt = $dbcon->prepare("INSERT INTO `gameKeys` (`userid`, `key`) VALUES (:uid, :key);"); + $stmt->bindParam(':key', $key, PDO::PARAM_STR); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + echo '
Key added!
'; + }else{ + echo '
You have already submitted this key.
'; + } + } + } + }else{ + echo '
Something happened.
'; + } + }else{ + echo '
You need to be signed in to add a server to your list.
'; + } +?> \ No newline at end of file diff --git a/core/func/api/games/deleteServer.php b/core/func/api/games/deleteServer.php new file mode 100644 index 0000000..0fdcd9a --- /dev/null +++ b/core/func/api/games/deleteServer.php @@ -0,0 +1,30 @@ +prepare("SELECT * FROM games WHERE id = :id;"); + $stmt->bindParam(':id', $serverID, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($result['creator_uid'] != $GLOBALS['userTable']['id'] && $GLOBALS['userTable']['rank'] == 0) { + echo 'error'; + } + + if ($result['dedi'] == 1 && $GLOBALS['userTable']['rank'] != 1) die("error"); + + $stmt = $dbcon->prepare("DELETE FROM games WHERE id = :id;"); + $stmt->bindParam(':id', $serverID, PDO::PARAM_INT); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/games/getLatestServer.php b/core/func/api/games/getLatestServer.php new file mode 100644 index 0000000..daf7235 --- /dev/null +++ b/core/func/api/games/getLatestServer.php @@ -0,0 +1,69 @@ + 5){ + return 'Offline'; + }else{ + return 'Online'; + } + } + + function getOnline2($ping) { + $currentTime = date('Y-m-d H:i:s'); + $from_time = strtotime($ping); + $to_time = strtotime($currentTime); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince > 2) { + return false; + }else{ + return true; + } + } + + + function getPlayerCount($serverID, $dbcon) { + $count = 0; + $stmt = $GLOBALS['dbcon']->prepare("SELECT lastSeen, inGame FROM users WHERE inGameId = :id"); + $stmt->bindParam(':id', $serverID, PDO::PARAM_INT); + $stmt->execute(); + foreach($stmt as $result) { + if (getOnline2($result['lastSeen']) == true and $result['inGame'] == 1) { + $count++; + } + } + return $count; + } + + function getDescription($description) { + if (strlen($description) > 0) { + return htmlentities($description, ENT_QUOTES, "UTF-8"); + }else{ + return 'No description.'; + } + } + + if ($GLOBALS['loggedIn']) { + $stmt = $dbcon->prepare("SELECT * FROM games WHERE `creator_uid` = :id ORDER BY id DESC LIMIT 1;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo '

Nothing found

Looks like there is nothing here

'; + } + foreach($stmt as $result) { + $creator = $result['creator_uid']; + $stmt = $dbcon->prepare("SELECT * FROM users WHERE id = :id"); + $stmt->bindParam(':id', $creator, PDO::PARAM_INT); + $stmt->execute(); + $result2 = $stmt->fetch(PDO::FETCH_ASSOC); + echo '
'; + echo '

'.htmlentities(user::filter($result['name']), ENT_QUOTES, "UTF-8").'

Creator : '.$result2['username'].'

Status : '.getOnline($result['lastPing']).'
Online Players : '.getPlayerCount($result['id'], $dbcon).'
View
'; + echo '
'; + } + }else{ + echo '

You need to be logged in

Please login and try again.

'; + } +?> \ No newline at end of file diff --git a/core/func/api/games/getMy.php b/core/func/api/games/getMy.php new file mode 100644 index 0000000..43edd0b --- /dev/null +++ b/core/func/api/games/getMy.php @@ -0,0 +1,88 @@ + 5){ + return 'Offline'; + }else{ + return 'Online'; + } + } + + function getDescription($description) { + if (strlen($description) > 0) { + return htmlentities($description, ENT_QUOTES, "UTF-8"); + }else{ + return 'No description.'; + } + } + + function getOnline2($ping) { + $currentTime = date('Y-m-d H:i:s'); + $from_time = strtotime($ping); + $to_time = strtotime($currentTime); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince > 2) { + return false; + }else{ + return true; + } + } + + function getPlayerCount($serverID, $dbcon) { + $count = 0; + $stmt = $GLOBALS['dbcon']->prepare("SELECT lastSeen, inGame FROM users WHERE inGameId = :id"); + $stmt->bindParam(':id', $serverID, PDO::PARAM_INT); + $stmt->execute(); + foreach($stmt as $result) { + if (getOnline2($result['lastSeen']) == true and $result['inGame'] == 1) { + $count++; + } + } + return $count; + } + + if ($GLOBALS['loggedIn']) { + $stmt = $dbcon->prepare("SELECT * FROM gameKeys WHERE userid = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $count = 0; + foreach($stmt as $result) { + if (isset($_GET['version'])) { + $version = $_GET['version']; + if (is_array($version) == true) exit; + if ($version != 1 && $version != 0 && $version != 2) exit; + $gameId = $result['key']; + $stmt = $dbcon->prepare("SELECT * FROM games WHERE `key` = :key AND `version` = :version;"); + $stmt->bindParam(':version', $version, PDO::PARAM_INT); + $stmt->bindParam(':key', $gameId, PDO::PARAM_STR); + }else{ + $stmt = $dbcon->prepare("SELECT * FROM games WHERE `key` = :key;"); + $stmt->bindParam(':key', $gameId, PDO::PARAM_STR); + } + $stmt->execute(); + if ($stmt->rowCount() > 0) { + $count++; + } + + foreach($stmt as $result) { + $creator = $result['creator_uid']; + $stmt = $dbcon->prepare("SELECT * FROM users WHERE id = :id"); + $stmt->bindParam(':id', $creator, PDO::PARAM_INT); + $stmt->execute(); + $result2 = $stmt->fetch(PDO::FETCH_ASSOC); + echo '
'; + echo '

'.htmlentities(user::filter($result['name']), ENT_QUOTES, "UTF-8").'

Creator : '.$result2['username'].'

Status : '.getOnline($result['lastPing']).'
Online Players : '.getPlayerCount($result['id'], $dbcon).'
View
'; + echo '
'; + } + } + if ($count == 0) { + echo '

Nothing found

Looks like there is nothing here

'; + } + }else{ + echo '

You need to be logged in

Please login and try again.

'; + } +?> \ No newline at end of file diff --git a/core/func/api/games/getMyS.php b/core/func/api/games/getMyS.php new file mode 100644 index 0000000..ae9e6ad --- /dev/null +++ b/core/func/api/games/getMyS.php @@ -0,0 +1,78 @@ + 5){ + return 'Offline'; + }else{ + return 'Online'; + } + } + + function getOnline2($ping) { + $currentTime = date('Y-m-d H:i:s'); + $from_time = strtotime($ping); + $to_time = strtotime($currentTime); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince > 2) { + return false; + }else{ + return true; + } + } + + + function getPlayerCount($serverID, $dbcon) { + $count = 0; + $stmt = $GLOBALS['dbcon']->prepare("SELECT lastSeen, inGame FROM users WHERE inGameId = :id"); + $stmt->bindParam(':id', $serverID, PDO::PARAM_INT); + $stmt->execute(); + foreach($stmt as $result) { + if (getOnline2($result['lastSeen']) == true and $result['inGame'] == 1) { + $count++; + } + } + return $count; + } + + function getDescription($description) { + if (strlen($description) > 0) { + return htmlentities($description, ENT_QUOTES, "UTF-8"); + }else{ + return 'No description.'; + } + } + + if ($GLOBALS['loggedIn']) { + if (isset($_GET['version'])) { + $version = $_GET['version']; + if (is_array($version) == true) exit; + if ($version != 1 && $version != 0 && $version != 2) exit; + $stmt = $dbcon->prepare("SELECT * FROM games WHERE `creator_uid` = :id AND `version` = :version;"); + $stmt->bindParam(':version', $version, PDO::PARAM_INT); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + }else{ + $stmt = $dbcon->prepare("SELECT * FROM games WHERE `creator_uid` = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + } + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo '

Nothing found

Looks like there is nothing here

'; + } + foreach($stmt as $result) { + $creator = $result['creator_uid']; + $stmt = $dbcon->prepare("SELECT * FROM users WHERE id = :id"); + $stmt->bindParam(':id', $creator, PDO::PARAM_INT); + $stmt->execute(); + $result2 = $stmt->fetch(PDO::FETCH_ASSOC); + echo '
'; + echo '

'.htmlentities(user::filter($result['name']), ENT_QUOTES, "UTF-8").'

Creator : '.$result2['username'].'

Status : '.getOnline($result['lastPing']).'
Online Players : '.getPlayerCount($result['id'], $dbcon).'
View
'; + echo '
'; + } + }else{ + echo '

You need to be logged in

Please login and try again.

'; + } +?> \ No newline at end of file diff --git a/core/func/api/games/getPublic.php b/core/func/api/games/getPublic.php new file mode 100644 index 0000000..6485870 --- /dev/null +++ b/core/func/api/games/getPublic.php @@ -0,0 +1,136 @@ +prepare("SELECT * FROM games WHERE public = 1 AND version = 0 ORDER BY id DESC"); + }elseif($version == 1) { + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM games WHERE public = 1 AND version = 1 ORDER BY id DESC"); + }elseif ($version == 2) { + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM games WHERE public = 1 AND version = 2 ORDER BY id DESC"); + }else{ + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM games WHERE public = 1 ORDER BY id DESC"); + } + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo '

Looks like there are no public games for this version!

You could try adding your own server and setting it to public.

'; + exit; + } + + function getOnline($ping) { + $currentTime = date('Y-m-d H:i:s'); + $from_time = strtotime($ping); + $to_time = strtotime($currentTime); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince > 2){ + return 'Offline'; + }else{ + return 'Online'; + } + } + + function getOnline2($ping) { + $currentTime = date('Y-m-d H:i:s'); + $from_time = strtotime($ping); + $to_time = strtotime($currentTime); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince > 2) { + return false; + }else{ + return true; + } + } + + function getDedicated($dedi) { + if ($dedi == 1) return ' '; + return ''; + } + + function getPlayerCount($serverID, $dbcon, $dedicated, $pCount) { + if ($dedicated == 0) { + $count = 0; + $stmt = $GLOBALS['dbcon']->prepare("SELECT lastSeen, inGame FROM users WHERE inGameId = :id"); + $stmt->bindParam(':id', $serverID, PDO::PARAM_INT); + $stmt->execute(); + foreach($stmt as $result) { + if (getOnline2($result['lastSeen']) == true and $result['inGame'] == 1) { + $count++; + } + } + return $count; + }else{ + return $pCount; + } + } + + function getDescription($description) { + if (strlen($description) > 0) { + return htmlentities($description, ENT_QUOTES, "UTF-8"); + }else{ + return 'No description.'; + } + } + + function getImage($result2, $serverID, $imgTime) { + if (file_exists("/var/www/api/imageServer/server/".$serverID.".png") && $GLOBALS['loggedIn']) { + return "https://api.xdiscuss.net/imageServer/server/".$serverID.".png?v=".strtotime($imgTime); + }else{ + return context::getUserImage($result2); + } + } + + function getVersion($gVersion) { + if ($GLOBALS['gameVersion'] == 4) { + if ($gVersion == 0) $versionString = "2009"; + if ($gVersion == 1) $versionString = "2008"; + if ($gVersion == 2) $versionString = "2011"; + if ($gVersion == 3) $versionString = "2010"; + return 'Version : '.$versionString.'
'; + } + } + + $count = 0; + if ($stmt->rowCount() > 0) { + echo '
'; + } + foreach($stmt as $result) { + if (getOnline2($result['lastPing']) == true) { + $count++; + $creator = $result['creator_uid']; + $stmt = $GLOBALS['dbcon']->prepare("SELECT username, id, imgTime FROM users WHERE id = :id"); + $stmt->bindParam(':id', $creator, PDO::PARAM_INT); + $stmt->execute(); + $result2 = $stmt->fetch(PDO::FETCH_ASSOC); + $gameName = context::secureString($result['name']); + if (strlen($gameName) >= 20) { + $gameName = substr($gameName, 0, 17). " ... "; + } + echo '
'; + echo '

'.getDedicated($result['dedi']).$gameName.'

Creator : '.$result2['username'].'

Status : '.getOnline($result['lastPing']).'
Online Players : '.getPlayerCount($result['id'], $dbcon, $result['dedi'], $result['numPlayers']).'
'.getVersion($result['version']).'View
'; + echo '
'; + } + } + if ($stmt->rowCount() > 0) { + echo '
'; + } + + if ($count == 0) { + echo '

Looks like there are no online games for this version!

You could try adding your own server and setting it to public.

'; + } + + echo ''; +?> \ No newline at end of file diff --git a/core/func/api/games/post/addServer.php b/core/func/api/games/post/addServer.php new file mode 100644 index 0000000..f777208 --- /dev/null +++ b/core/func/api/games/post/addServer.php @@ -0,0 +1,101 @@ + 32) { + echo 'server-name-too-long'; + exit; + } + + if (strlen($serverName) < 4) { + echo 'server-name-too-short'; + exit; + } + + if (!preg_match("/^[\w*?!\/@',:#$%\^&*\(\) -]+$/", $serverName) == 1) { + die("server-name-too-short"); + } + + if (strlen($serverName) > 128) { + echo 'server-description-too-long'; + exit; + } + + if (strlen($serverIP) == 0) { + echo 'server-ip-too-short'; + exit; + } + + if (strlen($serverIP) > 64) { + echo 'server-ip-too-long'; + exit; + } + + if (strlen($serverPort) == 0) { + echo 'server-port-too-short'; + exit; + } + + if (strlen($serverPort) > 5) { + echo 'server-port-too-long'; + exit; + } + + if (is_numeric($serverPort == false) || $serverPort > 64000) die("invalid-port"); + + if (filter_var($serverIP, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) == false) { + echo 'invalid-ip'; + exit; + } + + if ($privacyType != 0 && $privacyType != 1) { + echo 'invalid-privacy'; + exit; + } + + if ($gameVersion != 0 && $gameVersion != 1 && $gameVersion != 2) { + echo 'invalid-version'; + exit; + } + + $key = md5(microtime().rand()); + $serverkey = md5(microtime().rand()); + $stmt = $dbcon->prepare("INSERT INTO games (`public`, `creator_uid`, `name`, `description`, `ip`, `port`, `key`, `privatekey`, `version`) VALUES (:public, :user, :name, :description, :ip, :port, :key, :serverkey, :version);"); + $stmt->bindParam(':public', $privacyType, PDO::PARAM_INT); + $stmt->bindParam(':version', $gameVersion, PDO::PARAM_INT); + $stmt->bindParam(':serverkey', $serverkey, PDO::PARAM_STR); + $stmt->bindParam(':user', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':name', $serverName, PDO::PARAM_STR); + $stmt->bindParam(':description', $serverDescription, PDO::PARAM_STR); + $stmt->bindParam(':ip', $serverIP, PDO::PARAM_STR); + $stmt->bindParam(':port', $serverPort, PDO::PARAM_INT); + $stmt->bindParam(':key', $key, PDO::PARAM_STR); + $stmt->execute(); + + $stmt = $dbcon->prepare("SELECT * FROM games WHERE `creator_uid`=:uid ORDER BY id DESC LIMIT 1;"); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $id = $result['id']; + echo $id; + + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/games/post/addServerDedicated.php b/core/func/api/games/post/addServerDedicated.php new file mode 100644 index 0000000..2c2ddc6 --- /dev/null +++ b/core/func/api/games/post/addServerDedicated.php @@ -0,0 +1,114 @@ + 32) { + echo 'server-name-too-long'; + exit; + } + + if (!preg_match("/^[\w*?!\/@',:#$%\^&*\(\) -]+$/", $serverName) == 1) { + die("server-name-too-short"); + } + + if (strlen($serverName) < 4) { + echo 'server-name-too-short'; + exit; + } + + if ($privacyType != 0 && $privacyType != 1) { + echo 'invalid-privacy'; + exit; + } + + if (strlen($serverDescription) > 128) { + echo 'server-description-too-long'; + exit; + } + + if (isset($_FILES['placeFile'])) { + // Upload the place file properly. + $fileContent = @file_get_contents($_FILES['placeFile']['tmp_name']); + if (strpos($fileContent, 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"') == false) { + die("invalid-placefile"); + } + + $finfo = finfo_open(FILEINFO_MIME_TYPE); + $mime = finfo_file($finfo, $_FILES['placeFile']['tmp_name']); + if ($mime != "text/plain") { + die("invalid-placefile"); + } + + $imageFileType = pathinfo($_FILES['placeFile']["name"], PATHINFO_EXTENSION); + if ($imageFileType != "rbxl" && $imageFileType != "RBXL") die("invalid-placefile"); + + // Still alive? Proceed to upload the place file. + $uploadDirectory = $_SERVER['DOCUMENT_ROOT'].'/data/assets/uploads/'; + $fileHash = hash_file('sha512', $_FILES["placeFile"]["tmp_name"]); + if (!file_exists($uploadDirectory.$fileHash)) { + if (!move_uploaded_file($_FILES["placeFile"]["tmp_name"], $uploadDirectory.$fileHash)) { + die("file-move-error"); + } + } + + $webDirectory = "http://xdiscuss.net/data/assets/uploads/".$fileHash; + }else{ + if ($genPlace == 0) die("error"); + if ($genPlace == 1) $webDirectory = "http://api.xdiscuss.net/places/baseplate.rbxl"; + } + + // If we're still here, we can continue to request the server. + $stmt = $dbcon->prepare("INSERT INTO serverRequests (`placeLocation`, `serverName`, `serverDescription`, `serverVersion`, `userID`, `serverPrivacy`) VALUES (:placeLocation, :serverName, :serverDescription, :version, :userID, :privacy);"); + $stmt->bindParam(':placeLocation', $webDirectory, PDO::PARAM_STR); + $stmt->bindParam(':serverName', $serverName, PDO::PARAM_STR); + $stmt->bindParam(':userID', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':version', $version, PDO::PARAM_INT); + $stmt->bindParam(':privacy', $privacyType, PDO::PARAM_INT); + $stmt->bindParam(':serverDescription', $serverDescription, PDO::PARAM_STR); + $stmt->execute(); + + $stmt = $dbcon->prepare("UPDATE users SET lastUpload = NOW() WHERE id = :user;"); + $stmt->bindParam(':user', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/games/post/deleteServer.php b/core/func/api/games/post/deleteServer.php new file mode 100644 index 0000000..5fff240 --- /dev/null +++ b/core/func/api/games/post/deleteServer.php @@ -0,0 +1,29 @@ +prepare("SELECT * FROM games WHERE id = :id;"); + $stmt->bindParam(':id', $serverID, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($result['creator_uid'] != $GLOBALS['userTable']['id'] && $GLOBALS['userTable']['rank'] == 0) { + echo 'error'; + exit; + } + + $stmt = $dbcon->prepare("DELETE FROM games WHERE id = :id;"); + $stmt->bindParam(':id', $serverID, PDO::PARAM_INT); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/games/viewGame.php b/core/func/api/games/viewGame.php new file mode 100644 index 0000000..15dcfd3 --- /dev/null +++ b/core/func/api/games/viewGame.php @@ -0,0 +1,78 @@ + 2) { + return false; + }else{ + return true; + } + } + + function getPlayerCount($serverID, $dbcon) { + $count = 0; + $stmt = $GLOBALS['dbcon']->prepare("SELECT lastSeen, inGame FROM users WHERE inGameId = :id"); + $stmt->bindParam(':id', $serverID, PDO::PARAM_INT); + $stmt->execute(); + foreach($stmt as $result) { + if (getOnline($result['lastSeen']) == true and $result['inGame'] == 1) { + $count++; + } + } + return $count; + } + + if (isset($_GET['id'])) { + $gameID = $_GET['id']; + if (is_array($gameID)) { + exit; + } + include_once $_SERVER['DOCUMENT_ROOT'].'/core/func/includes.php'; + $stmt = $GLOBALS['dbcon']->prepare('SELECT * FROM games WHERE id= :id'); + $stmt->bindParam(':id', $gameID, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($stmt->rowCount() == 0) { + echo 'Game not found!'; + echo ''; + exit; + } + echo ''; + $stmt = $dbcon->prepare("SELECT username, id, imgTime FROM users WHERE id = :id"); + $stmt->bindParam(':id', $result['creator_uid'], PDO::PARAM_INT); + $stmt->execute(); + $resultuser = $stmt->fetch(PDO::FETCH_ASSOC); + echo '
'; + if (file_exists("/var/www/api/imageServer/server/".$result['id'].".png") && $GLOBALS['loggedIn']) { + echo ""; + } + echo '
'; + echo '
'; + echo '
'; + echo 'Creator : '.$resultuser['username'].'
'; + echo 'Created : '.date('M j Y g:i A', strtotime($result['date'])).'
'; + if (getOnline($result['lastPing'])) { + echo 'Status : Online
'; + }else{ + echo 'Status : Offline
'; + } + if ($result['dedi'] == 0) + echo 'Online Players : '.getPlayerCount($result['id'], $GLOBALS['dbcon']).'
'; + if ($result['dedi'] == 1) { + echo 'Online Players : '.$result['numPlayers'].'
'; + } + if ($GLOBALS['loggedIn']) { + if ($result['version'] == 0) echo 'Play'; + if ($result['version'] == 1) echo 'Play'; + if ($result['version'] == 2) echo 'Play'; + }else{ + echo 'Play'; + } + echo 'Full Page'; + echo '
'; + }else{ + echo 'An error occurred'; + } +?> diff --git a/core/func/api/groups/get/getMembers.php b/core/func/api/groups/get/getMembers.php new file mode 100644 index 0000000..05815bc --- /dev/null +++ b/core/func/api/groups/get/getMembers.php @@ -0,0 +1,69 @@ +prepare("SELECT * FROM group_members WHERE gid = :id ORDER BY id DESC LIMIT 9 OFFSET :offset;"); + $stmt->bindParam(':offset', $offset, PDO::PARAM_INT); + $stmt->bindParam(':id', $groupId, PDO::PARAM_INT); + $stmt->execute(); + + $stmtc = $GLOBALS['dbcon']->prepare("SELECT id FROM group_members WHERE gid = :id"); + $stmtc->bindParam(':id', $groupId, PDO::PARAM_INT); + $stmtc->execute(); + echo ''; + + $count = 0; + if ($stmt->rowCount() == 0) { + echo 'No members found'; + } + echo '
'; + foreach($stmt as $result) { + $count++; + if ($count < 9) { + $userId = $result['uid']; + $stmt = $GLOBALS['dbcon']->prepare("SELECT username, imgTime, lastSeen, id FROM users WHERE id = :id"); + $stmt->bindParam(':id', $userId, PDO::PARAM_INT); + $stmt->execute(); + $resultuser = $stmt->fetch(PDO::FETCH_ASSOC); + $username = $resultuser['username']; + if (strlen($username) > 10) { + $username = substr($username, 0, 7) . '...'; + } + echo '

'; + echo '
'; + echo context::getOnline($resultuser); + echo ''.htmlentities($username, ENT_QUOTES, "UTF-8").'

'; + } + } + echo '
'; + if ($page > 0) { + echo '« Previous'; + } + if ($count > 6) { + echo 'Next »'; + } + if ($count == 0 and $page > 0) { + exit; + } + echo '
'; +?> \ No newline at end of file diff --git a/core/func/api/groups/post/changeDescription.php b/core/func/api/groups/post/changeDescription.php new file mode 100644 index 0000000..7f4f9b0 --- /dev/null +++ b/core/func/api/groups/post/changeDescription.php @@ -0,0 +1,36 @@ + 256 or strlen($descriptionValue) > 256) { + echo 'description-too-long'; + exit; + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM groups WHERE id = :id"); + $stmt->bindParam(':id', $groupId, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($result['cuid'] != $GLOBALS['userTable']['id'] and $GLOBALS['userTable']['rank'] == 0) { + echo 'error'; + exit; + } + + $query = "UPDATE `groups` SET `description`=:description WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $groupId, PDO::PARAM_INT); + $stmt->bindParam(':description', $descriptionValue, PDO::PARAM_STR); + $stmt->execute(); + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/groups/post/createGroup.php b/core/func/api/groups/post/createGroup.php new file mode 100644 index 0000000..5e9284c --- /dev/null +++ b/core/func/api/groups/post/createGroup.php @@ -0,0 +1,82 @@ + 32 or strlen($groupName) > 32) { + echo 'group-name-too-long'; + exit; + } + + $descriptionCheck = preg_replace("/[^ \w]+/", "", $groupDescription); + $descriptionCheck = preg_replace('/\s+/', '', $descriptionCheck); + if (strlen($descriptionCheck) > 256 or strlen($groupDescription) > 256) { + echo 'description-too-long'; + exit; + } + + if ($GLOBALS['userTable']['coins'] < 50) { + echo 'no-coins'; + exit; + } + + $count = 0; + $stmt = $GLOBALS['dbcon']->prepare("SELECT id FROM group_members WHERE uid = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $count = $count + $stmt->rowCount(); + + $stmt = $GLOBALS['dbcon']->prepare("SELECT id FROM groups WHERE cuid = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $count = $count + $stmt->rowCount(); + + if ($count > 9) { + echo 'in-too-many-groups'; + exit; + } + + $newCoins = $GLOBALS['userTable']['coins']-50; + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET coins = :coins WHERE id = :user;"); + $stmt->bindParam(':coins', $newCoins, PDO::PARAM_INT); + $stmt->bindParam(':user', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $query = "INSERT INTO groups (`cuid`, `name`, `description`) VALUES (:cuid, :name, :description);"; + $stmt = $dbcon->prepare($query); + $stmt->bindParam(':cuid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':name', $groupName, PDO::PARAM_STR); + $stmt->bindParam(':description', $groupDescription, PDO::PARAM_STR); + $stmt->execute(); + + $stmt = $dbcon->prepare("SELECT * FROM groups WHERE cuid = :id ORDER BY id DESC LIMIT 1;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + echo $result['id']; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/groups/post/joinGroup.php b/core/func/api/groups/post/joinGroup.php new file mode 100644 index 0000000..6a52bdd --- /dev/null +++ b/core/func/api/groups/post/joinGroup.php @@ -0,0 +1,58 @@ +prepare("SELECT * FROM group_members WHERE uid = :uid AND gid = :id"); + $stmt->bindParam(':id', $groupId, PDO::PARAM_INT); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + echo 'error'; + exit; + } + + // Get all group information. + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM groups WHERE id = :id"); + $stmt->bindParam(':id', $groupId, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + + // Check if owned by this user. + if ($GLOBALS['userTable']['id'] == $result['cuid']) { + echo 'error'; + exit; + } + + $count = 0; + $stmt = $GLOBALS['dbcon']->prepare("SELECT id FROM group_members WHERE uid = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $count = $count + $stmt->rowCount(); + + $stmt = $GLOBALS['dbcon']->prepare("SELECT id FROM groups WHERE cuid = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $count = $count + $stmt->rowCount(); + + if ($count > 9) { + echo 'in-too-many-groups'; + exit; + } + + // Join group + $query = "INSERT INTO group_members (`uid`, `gid`) VALUES (:uid, :gid);"; + $stmt = $dbcon->prepare($query); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':gid', $groupId, PDO::PARAM_STR); + $stmt->execute(); + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/groups/post/leaveDelete.php b/core/func/api/groups/post/leaveDelete.php new file mode 100644 index 0000000..acece87 --- /dev/null +++ b/core/func/api/groups/post/leaveDelete.php @@ -0,0 +1,48 @@ +prepare("SELECT * FROM groups WHERE id = :id"); + $stmt->bindParam(':id', $groupId, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + + // Check if not owned by this user. + if ($GLOBALS['userTable']['id'] != $result['cuid']) { + echo 'error'; + exit; + } + + // Check if not a member. + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM group_members WHERE uid = :uid AND gid = :id"); + $stmt->bindParam(':id', $groupId, PDO::PARAM_INT); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + echo 'error'; + exit; + } + + // Delete group and all its members. + $query = "DELETE FROM `group_members` WHERE `gid`=:groupId;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':groupId', $groupId, PDO::PARAM_INT); + $stmt->execute(); + + $query = "DELETE FROM `groups` WHERE `id`=:groupId;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':groupId', $groupId, PDO::PARAM_INT); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/groups/post/leaveGroup.php b/core/func/api/groups/post/leaveGroup.php new file mode 100644 index 0000000..9b67dfe --- /dev/null +++ b/core/func/api/groups/post/leaveGroup.php @@ -0,0 +1,43 @@ +prepare("SELECT * FROM groups WHERE id = :id"); + $stmt->bindParam(':id', $groupId, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + + // Check if owned by this user. + if ($GLOBALS['userTable']['id'] == $result['cuid']) { + echo 'error'; + exit; + } + + // Check if member. + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM group_members WHERE uid = :uid AND gid = :id"); + $stmt->bindParam(':id', $groupId, PDO::PARAM_INT); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'error'; + exit; + } + + // Leave group + $query = "DELETE FROM `group_members` WHERE `gid`=:groupId AND `uid`=:userId;"; + $stmt = $dbcon->prepare($query); + $stmt->bindParam(':groupId', $groupId, PDO::PARAM_INT); + $stmt->bindParam(':userId', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/groups/searchGroup.php b/core/func/api/groups/searchGroup.php new file mode 100644 index 0000000..48b9a9c --- /dev/null +++ b/core/func/api/groups/searchGroup.php @@ -0,0 +1,54 @@ +prepare("SELECT * FROM groups WHERE name LIKE :term ORDER BY id DESC LIMIT 11 OFFSET :offset;"); + }else{ + $stmt = $dbcon->prepare("SELECT * FROM groups WHERE name LIKE :term ORDER BY name ASC LIMIT 11 OFFSET :offset;"); + } + $stmt->bindParam(':term', $searchTermSQL, PDO::PARAM_STR); + $stmt->bindParam(':offset', $offset, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo '
Nothing found.
'; + } + $count = 0; + foreach($stmt as $result) { + $count++; + if ($count < 11) { + echo '
'; + echo '
'; + echo '
'; + echo ''; + echo '
'; + echo '
'; + if ($result['description'] == NULL) { + $description = "This user has not configured anything to display here"; + }else{ + $description = ''.context::secureString($result['description']).''; + } + + echo '

'.$result['name'].'

Description:

'.$description.'

'; + echo '
'; + } + } + if ($count > 10) { + echo ''; + } +?> \ No newline at end of file diff --git a/core/func/api/messages/getMessages.php b/core/func/api/messages/getMessages.php new file mode 100644 index 0000000..61e6e28 --- /dev/null +++ b/core/func/api/messages/getMessages.php @@ -0,0 +1,91 @@ +Messages'; + } + + function showReadStatus($read) { + if ($read == 0) { + return ''; + } + } + + $offset = $page*25; + include_once $_SERVER['DOCUMENT_ROOT'].'/core/func/includes.php'; + if ($GLOBALS['loggedIn'] == false) { + exit; + } + if ($filter == 0) { + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM messages WHERE recv_uid = :rId ORDER BY id DESC LIMIT 26 OFFSET :offset"); + }elseif ($filter == 1) { + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM messages WHERE recv_uid = :rId AND `read` = 0 ORDER BY id DESC LIMIT 26 OFFSET :offset"); + }elseif ($filter == 2) { + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM messages WHERE recv_uid = :rId AND `read` = 1 ORDER BY id DESC LIMIT 26 OFFSET :offset"); + }elseif ($filter == 3) { + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM messages WHERE sender_uid = :rId ORDER BY id DESC LIMIT 26 OFFSET :offset"); + }else{ + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM messages WHERE recv_uid = :rId ORDER BY id DESC LIMIT 26 OFFSET :offset"); + } + + $stmt->bindParam(':rId', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':offset', $offset, PDO::PARAM_INT); + $stmt->execute(); + echo '
'; + $count = 0; + foreach($stmt as $result) { + $count++; + if ($count < 25) { + if ($filter == 3) { + $userSheet = context::getUserSheetByID($result['recv_uid']); + }else{ + $userSheet = context::getUserSheetByID($result['sender_uid']); + } + if ($userSheet['rank'] == 0) { + $usern = $userSheet['username']; + }elseif ($userSheet['rank'] == 1) { + $usern = ''.$userSheet['username'].''; + }elseif ($userSheet['rank'] == 2) { + $usern = ''.$userSheet['username'].''; + } + echo '
'; + echo '

'.showReadStatus($result['read']).' '.context::secureString($result['title']).'

'; + echo ''; + if ($filter == 3) { + echo '

Sent to '.$usern.'

'; + }else{ + echo '

Sent by '.$usern.'

'; + } + echo '
'; + } + } + if ($stmt->rowCount() == 0) { + echo 'You do not have any message'; + } + if ($count > 25) { + echo ''; + } + echo '
'; + }else{ + echo 'An error occurred'; + } +?> \ No newline at end of file diff --git a/core/func/api/messages/newMessage.php b/core/func/api/messages/newMessage.php new file mode 100644 index 0000000..6890590 --- /dev/null +++ b/core/func/api/messages/newMessage.php @@ -0,0 +1,33 @@ +prepare("SELECT * FROM users WHERE username = :fId"); + $stmt->bindParam(':fId', $username, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'User not found'; + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($result['id'] == $GLOBALS['userTable']['id']) { + echo 'You can not send messages to yourself'; + exit; + } + if ($result['banned'] == 1) { + echo 'You can not send messages to a banned user'; + exit; + } + echo '

Sending a new message to '.context::secureString($result['username']).'

'; + include_once $_SERVER['DOCUMENT_ROOT'].'/core/func/api/messages/views/newMessage.php'; + }else{ + echo 'An error occurred'; + } +?> \ No newline at end of file diff --git a/core/func/api/messages/post/newMessage.php b/core/func/api/messages/post/newMessage.php new file mode 100644 index 0000000..3075e6e --- /dev/null +++ b/core/func/api/messages/post/newMessage.php @@ -0,0 +1,73 @@ + 128) { + echo 'title-too-long'; + exit; + } + + if (strlen($messageContent) < 5) { + echo 'content-too-short'; + exit; + } + + if (strlen($messageContent) > 30000) { + echo 'content-too-long'; + exit; + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT lastPost, joinDate, rank FROM users WHERE id = :id"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $timeSince = round(abs(strtotime(date('Y-m-d H:i:s')) - strtotime($result['lastPost'])) / 60,2); + if ($timeSince < 0.2 and $result['rank'] == 0) { + echo 'rate-limit'; + exit; + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT id, banned FROM users WHERE id = :id"); + $stmt->bindParam(':id', $userID, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'no-user'; + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($result['banned'] == 1) { + echo 'user-banned'; + exit; + } + + $query = "INSERT INTO messages (`recv_uid`, `sender_uid`, `title`, `content`) VALUES (:recv_uid, :sender_uid, :title, :content);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':sender_uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':recv_uid', $userID, PDO::PARAM_INT); + $stmt->bindParam(':title', $messageTitle, PDO::PARAM_STR); + $stmt->bindParam(':content', $messageContent, PDO::PARAM_STR); + $stmt->execute(); + + $query = "UPDATE `users` SET `lastPost`=NOW() WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/messages/showMessage.php b/core/func/api/messages/showMessage.php new file mode 100644 index 0000000..e39d363 --- /dev/null +++ b/core/func/api/messages/showMessage.php @@ -0,0 +1,84 @@ +prepare("SELECT * FROM messages WHERE id = :id"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'Message not found'; + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($result['recv_uid'] != $GLOBALS['userTable']['id'] && $result['sender_uid'] != $GLOBALS['userTable']['id']) { + echo 'Message not found!'; + exit; + } + if ($result['read'] == 0) { + $read = false; + }else{ + $read = true; + } + if ($read == false and $loggedIn == true) { + if ($result['recv_uid'] == $GLOBALS['userTable']['id']) { + $stmt = $GLOBALS['dbcon']->prepare("UPDATE messages SET `read` = 1 WHERE id = :id"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + } + } + + $id = $result['id']; + if ($result['recv_uid'] == $GLOBALS['userTable']['id']) { + $userSheet = context::getUserSheetByID($result['sender_uid']); + }else{ + $userSheet = context::getUserSheetByID($result['recv_uid']); + } + echo ''; + echo '

'.context::secureString($result['title']).'

'; + echo ''; + if ($userSheet['rank'] == 0) { + $usern = $userSheet['username']; + }elseif ($userSheet['rank'] == 1) { + $usern = ''.$userSheet['username'].''; + }elseif ($userSheet['rank'] == 2) { + $usern = ''.$userSheet['username'].''; + } + echo '
+
'.context::getOnline($userSheet).''.$usern.'
+
'; + if ($userSheet['rank'] == 1) { + echo '

Administrator

'; + } + if ($userSheet['rank'] == 2) { + echo '

Moderator

'; + } + echo 'Posts: '.$userSheet['posts'].'
+ Joined: '.date('M j Y', strtotime($userSheet['joinDate'])).' +
'; + $content = strip_tags($result['content']); + $content = context::secureString($content); + if ($userSheet['rank'] > 0) { + $content = preg_replace("/\s*[a-zA-Z\/\/:\.]*youtube.com\/watch\?v=([a-zA-Z0-9\-_]+)([a-zA-Z0-9\/\*\-\_\?\&\;\%\=\.]*)/i","", $content); + $content = preg_replace("/https?:\/\/[^ ]+?(?:\.jpg|\.png|\.gif)/",'', $content); + } + echo '
+ Sent on: '.date('M j Y g:i A', strtotime($result['date'])).'
+ '.nl2br($content).' +
'; + }else{ + echo 'An error occurred'; + } +?> \ No newline at end of file diff --git a/core/func/api/messages/views/newMessage.php b/core/func/api/messages/views/newMessage.php new file mode 100644 index 0000000..99f2397 --- /dev/null +++ b/core/func/api/messages/views/newMessage.php @@ -0,0 +1,9 @@ + +
+ + + \ No newline at end of file diff --git a/core/func/api/profile/getInventory.php b/core/func/api/profile/getInventory.php new file mode 100644 index 0000000..d27230b --- /dev/null +++ b/core/func/api/profile/getInventory.php @@ -0,0 +1,114 @@ +prepare("SELECT catalogid FROM ownedItems WHERE type = :type AND uid = :uid AND deleted=0 ORDER BY id DESC LIMIT 7 OFFSET :offset;"); + if (!$GLOBALS['loggedIn']) + $stmt = $GLOBALS['dbcon']->prepare("SELECT catalogid FROM ownedItems WHERE type = :type AND uid = :uid AND deleted=0 AND rbxasset=0 ORDER BY id DESC LIMIT 7 OFFSET :offset;"); + $stmt->bindParam(':offset', $offset, PDO::PARAM_INT); + $stmt->bindParam(':type', $type, PDO::PARAM_STR); + $stmt->bindParam(':uid', $userId, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'No items found.'; + } + $count = 0; + foreach($stmt as $resultOwned) { + $count++; + if ($count < 7) { + $stmt = $GLOBALS['dbcon']->prepare("SELECT deleted, name, type, datafile, assetid, id, fileHash, imgTime, rbxasset FROM catalog WHERE id = :id AND type = :type"); + $stmt->bindParam(':id', $resultOwned['catalogid'], PDO::PARAM_INT); + $stmt->bindParam(':type', $type, PDO::PARAM_STR); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($result['deleted'] == 0 && $result['type'] == $type) { + $itemName = $result['name']; + if (strlen($itemName) > 16) { + $itemName = substr($itemName, 0, 13) . '...'; + } + + echo '
'.htmlentities($itemName, ENT_QUOTES, "UTF-8").'
'; + echo ''; + echo '
Details'; + echo '
'; + } + } + } + echo '
'; + if ($page > 0) { + echo '« Previous'; + } + if ($count > 6) { + echo 'Next »'; + } + if ($count == 0 and $page > 0) { + exit; + } + echo '
'; +?> \ No newline at end of file diff --git a/core/func/api/settings/get/twoStep.php b/core/func/api/settings/get/twoStep.php new file mode 100644 index 0000000..c323a53 --- /dev/null +++ b/core/func/api/settings/get/twoStep.php @@ -0,0 +1,27 @@ +Click the button below to activate two step authentication. You will be asked to test your key before it will be fully enabled.

+ '; + }else{ + $gAuth = new GoogleAuthenticator(); + if ($GLOBALS['userTable']['2faEnabled'] == 0 and $GLOBALS['userTable']['2faInit'] == 1) { + echo '

Your secret key is '.$GLOBALS['userTable']['authKey'].'

'; + echo '

You can also use the QR code to add your secret key automatically.

'; + echo '

'; + echo '

Because you have not yet verified if this works, you will not be asked for a code the next time you login. Please finish the setup.

'; + echo ''; + echo ''; + }else{ + echo '

Your secret key is '.$GLOBALS['userTable']['authKey'].'

'; + echo '

You can also use the QR code to add your secret key automatically.

'; + echo '
'; + echo ''; + } + } +?> \ No newline at end of file diff --git a/core/func/api/settings/post/changeEmail.php b/core/func/api/settings/post/changeEmail.php new file mode 100644 index 0000000..9e66c60 --- /dev/null +++ b/core/func/api/settings/post/changeEmail.php @@ -0,0 +1,77 @@ +prepare("SELECT email FROM users WHERE email = :email;"); + $stmt->bindParam(':email', $newEmail, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() > 0) die("email-in-use"); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET email = :email WHERE id = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':email', $newEmail, PDO::PARAM_STR); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET lastUpload = NOW() WHERE id = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET emailverified = 0 WHERE id = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET emailcodeTime = NULL WHERE id = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'error'; + } +?> diff --git a/core/func/api/settings/post/changePassword.php b/core/func/api/settings/post/changePassword.php new file mode 100644 index 0000000..e83628f --- /dev/null +++ b/core/func/api/settings/post/changePassword.php @@ -0,0 +1,76 @@ + 40) { + echo 'password-too-long'; + exit; + } + + $auth_hash = crypt($currentPassword, $GLOBALS['userTable']['password_salt']); + if ($auth_hash != $GLOBALS['userTable']['password_hash']) { + echo 'wrong-password'; + exit; + } + + $salt = '$2a$07$'.uniqid(mt_rand(), true).'$'; + $hash = crypt($newPassword1, $salt); + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET password_salt = :salt WHERE id = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':salt', $salt, PDO::PARAM_STR); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET password_hash = :hash WHERE id = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':hash', $hash, PDO::PARAM_STR); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET passwordVersion = 2 WHERE id = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET password = NULL WHERE id = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET passwordChangeIP = :ip WHERE id = :id;"); + $IP = auth::getIP(); + $stmt->bindParam(':ip', $IP, PDO::PARAM_STR); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET passwordChangeDate = NOW() WHERE id = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("DELETE FROM sessions WHERE userId = :userId"); + $stmt->bindParam(':userId', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + echo 'success'; + }else{ + echo 'error'; + } +?> diff --git a/core/func/api/settings/post/disableTwo.php b/core/func/api/settings/post/disableTwo.php new file mode 100644 index 0000000..f022fe2 --- /dev/null +++ b/core/func/api/settings/post/disableTwo.php @@ -0,0 +1,34 @@ +prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $query = "UPDATE `users` SET `2faInit`=0 WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'staff-block'; + exit; + } + } + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/settings/post/enableTwo.php b/core/func/api/settings/post/enableTwo.php new file mode 100644 index 0000000..a02f464 --- /dev/null +++ b/core/func/api/settings/post/enableTwo.php @@ -0,0 +1,33 @@ +prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + include_once $_SERVER['DOCUMENT_ROOT'].'/core/func/libs/google/GoogleAuthenticator.php'; + $gAuth = new GoogleAuthenticator(); + $code = $gAuth->generateSecret(); + + $query = "UPDATE users SET `authKey`=:code WHERE `id`=:uid;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':code', $code, PDO::PARAM_STR); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + } + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/settings/post/enableTwoFinal.php b/core/func/api/settings/post/enableTwoFinal.php new file mode 100644 index 0000000..0616ff3 --- /dev/null +++ b/core/func/api/settings/post/enableTwoFinal.php @@ -0,0 +1,47 @@ +checkCode($GLOBALS['userTable']['authKey'], $finalCode)) { + echo 'wrong-code'; + exit; + } + + $query = "UPDATE `users` SET `2faInit`=1 WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $query = "UPDATE `users` SET `2faEnabled`=1 WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $query = "UPDATE `sessions` SET `factorFinish`=1 WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['sessionTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + echo 'success'; + } + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/settings/post/updateAbout.php b/core/func/api/settings/post/updateAbout.php new file mode 100644 index 0000000..ad16355 --- /dev/null +++ b/core/func/api/settings/post/updateAbout.php @@ -0,0 +1,40 @@ + 256) die("error"); + + // Apparently, we'll need filters here too since users can't just shut their mouths. + $badwords = array("fucking", "gay", "rape", "incest", "beastiality", "cum", "maggot", "bullshit", "fuck", "penis", + "dick", "vagina", "vag", "faggot", "fag", "nigger", "asshole", "shit", "bitch", "anal", "stfu", + "cunt", "pussy", "hump", "meatspin", "redtube", "porn", "kys", "xvideos", "hentai", "gangbang", "milf", + "n*", "nobelium", "whore", "wtf", "horny", "raping", "s3x", "boob", "nigga", "nlgga", "gt2008", + "cock", "dicc", "idiot", "nibba", "nibber", "nude", "kesner", "brickopolis", "nobe", "diemauer"); + + $badwords2 = array("sex", "porn"); + $contentCheck = preg_replace('!\s+!', ' ', $aboutContent); + $contentCheck = strip_tags($contentCheck); + $contentCheck = preg_replace("/&#?[a-z0-9]+;/i","", $contentCheck); + $contentCheck = preg_replace('!\s+!', ' ', $contentCheck); + $contentCheck = strtolower(preg_replace('|[[\/\!]*?[^\[\]]*?]|si', '', $contentCheck)); + $contentCheck = preg_replace('/\s+/', '', $contentCheck); + + if (context::contains($contentCheck, $badwords2)) die("filtered"); + + // Check without special characters removed + if (context::contains($contentCheck, $badwords)) die("filtered"); + + if(!preg_match("/^[\w*?!\/@',#$%\"'_.=\[\]\^&*\(\)\r\n -]+$/", $aboutContent) == 1 && strlen($aboutContent) != 0) die("filtered"); + + $query = "UPDATE `users` SET `about`=:about WHERE `id`=:id;"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':about', $aboutContent, PDO::PARAM_STR); + $stmt->execute(); + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/settings/post/updateTheme.php b/core/func/api/settings/post/updateTheme.php new file mode 100644 index 0000000..555a302 --- /dev/null +++ b/core/func/api/settings/post/updateTheme.php @@ -0,0 +1,19 @@ +prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':theme', $theme, PDO::PARAM_INT); + $stmt->execute(); + + echo 'success'; + }else{ + echo 'error'; + } +?> \ No newline at end of file diff --git a/core/func/api/users/getOnline.php b/core/func/api/users/getOnline.php new file mode 100644 index 0000000..ff2a9b8 --- /dev/null +++ b/core/func/api/users/getOnline.php @@ -0,0 +1,36 @@ +
+
Users currently online
+
+prepare("SELECT lastSeen, id, username, inGame, rank FROM users WHERE banned = 0 AND hideStatus = 0 ORDER BY id ASC;"); + $stmt->execute(); + $count = 0; + foreach($stmt as $result) { + $from_time = strtotime($result['lastSeen']); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince < 5){ + $count++; + if ($result['inGame'] == 1) { + if ($result['rank'] == 0) { + echo ''.$result['username'].' '; + }else{ + echo ''.$result['username'].' '; + } + }elseif ($result['rank'] > 0) { + echo ''.$result['username'].' '; + }else{ + echo ''.$result['username'].' '; + } + } + } + if ($count == 0) { + echo 'There are no users online at this moment.'; + } + echo ''; +?> +
+
\ No newline at end of file diff --git a/core/func/api/users/searchUser.php b/core/func/api/users/searchUser.php new file mode 100644 index 0000000..e13ca96 --- /dev/null +++ b/core/func/api/users/searchUser.php @@ -0,0 +1,60 @@ +prepare("SELECT * FROM users WHERE username LIKE :term AND banned = 0 ORDER BY lastSeen DESC LIMIT 11 OFFSET :offset;"); + }else{ + $stmt = $dbcon->prepare("SELECT * FROM users WHERE username LIKE :term AND banned = 0 ORDER BY username ASC LIMIT 11 OFFSET :offset;"); + } + $stmt->bindParam(':term', $searchTermSQL, PDO::PARAM_STR); + $stmt->bindParam(':offset', $offset, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo '
Nothing found.
'; + } + $count = 0; + foreach($stmt as $result) { + $count++; + if ($count < 11) { + echo '
'; + echo '
'; + echo '
'; + echo ''; + echo '
'; + echo '
'; + if ($result['lastSeen'] == NULL) { + $lastSeen = "Never"; + }else{ + $lastSeen = date('M j Y g:i A', strtotime($result['lastSeen'])); + } + + if ($result['about'] == NULL) { + $about = "This user has not configured anything to display here"; + }else{ + $about = ''.context::secureString($result['about']).''; + } + + echo '

'.context::getOnline($result).' '.$result['username'].'

Last seen: '.$lastSeen.'
About:

'.$about.'

'; + echo '
'; + } + } + if ($count > 10) { + echo ''; + } +?> \ No newline at end of file diff --git a/core/func/auth/main.php b/core/func/auth/main.php new file mode 100644 index 0000000..0617a45 --- /dev/null +++ b/core/func/auth/main.php @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/core/func/auth/sessionHandler.php b/core/func/auth/sessionHandler.php new file mode 100644 index 0000000..ef0862f --- /dev/null +++ b/core/func/auth/sessionHandler.php @@ -0,0 +1,118 @@ +prepare('SELECT lastUsed, id, csrfToken, factorFinish, location, userId, useragent FROM sessions WHERE userId = :userId AND sessionId = :sessionId LIMIT 1;'); + $stmt->bindParam(':userId', $_COOKIE['auth_uid'], PDO::PARAM_INT); + $stmt->bindParam(':sessionId', $_COOKIE['a_id'], PDO::PARAM_STR); + $stmt->execute(); + $resultSession = $stmt->fetch(PDO::FETCH_ASSOC); + $removeSession = false; + $sesexpired = false; + if ($stmt->rowCount() > 0) { + $from_time = strtotime($resultSession['lastUsed']); + $sessionId = $resultSession['id']; + $to_time = strtotime(context::getCurrentTime()); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince > 1440 || $removeSession == true) { + $sesexpired = true; + $stmt = $GLOBALS['dbcon']->prepare('DELETE FROM sessions WHERE id=:id;'); + $stmt->bindParam(':id', $sessionId, PDO::PARAM_INT); + $stmt->execute(); + } + } + + + if ($stmt->rowCount() > 0 && $sesexpired == false) { + $GLOBALS['loggedIn'] = true; + $query = "SELECT * FROM users WHERE id = :id LIMIT 1;"; + $stmt = $dbcon->prepare($query); + $stmt->bindParam(':id', $_COOKIE['auth_uid'], PDO::PARAM_STR); + $stmt->execute(); + $GLOBALS['userTable'] = $stmt->fetch(PDO::FETCH_ASSOC); + $GLOBALS['sessionTable'] = $resultSession; + $GLOBALS['csrf_token'] = $resultSession['csrfToken']; + + $IP = auth::getIP(); + if ($GLOBALS['userTable']['lastIP'] != $IP) { + $stmt = $dbcon->prepare("UPDATE users SET lastIP = :ip WHERE username = :user;"); + $stmt->bindParam(':user', $GLOBALS['userTable']['username'], PDO::PARAM_STR); + $stmt->bindParam(':ip', $IP, PDO::PARAM_STR); + $stmt->execute(); + } + + if ($GLOBALS['userTable']['banned'] == 1 && strpos($_SERVER['SCRIPT_NAME'], "banned.php") == false) { + if (!isset($GLOBALS['bypassRedirect'])) { + header("Location: /account/suspended"); + exit; + } + } + + if (security::getUserEmailVerified() == false && $GLOBALS['userTable']['banned'] == 0) { + $timeSince = round(abs(strtotime(context::getCurrentTime()) - strtotime($GLOBALS['userTable']['emailcodeTime'])) / 60,2); + if ($timeSince > 15) { + security::sendEmailVerificationMessage(); + } + if (strpos($_SERVER['SCRIPT_NAME'], "verifyEmail.php") == false) { + if (!isset($GLOBALS['bypassRedirect'])) { + header("Location: /account/verification/email"); + exit; + } + } + } + + if ($GLOBALS['sessionTable']['factorFinish'] == 0 && $GLOBALS['userTable']['banned'] == 0 && $GLOBALS['userTable']['2faEnabled'] == 1 && security::getUserEmailVerified() == true && strpos($_SERVER['SCRIPT_NAME'], "twostepauth.php") == false) { + if (!isset($GLOBALS['bypassRedirect'])) { + header("Location: /account/verification/twostepauth"); + exit; + } + } + + $from_time = strtotime($GLOBALS['userTable']['lastAward']); + $to_time = strtotime(context::getCurrentTime()); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince > 1440) { + $newCoins = $GLOBALS['userTable']['coins']+15; + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET coins = :coins WHERE id = :user;"); + $stmt->bindParam(':coins', $newCoins, PDO::PARAM_INT); + $stmt->bindParam(':user', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET lastAward = NOW() WHERE id = :user;"); + $stmt->bindParam(':user', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + } + + $from_time = strtotime($GLOBALS['sessionTable']['lastUsed']); + $to_time = strtotime(context::getCurrentTime()); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince > 3) { + $stmt = $GLOBALS['dbcon']->prepare("UPDATE sessions SET lastUsed = NOW() WHERE id = :sid;"); + $stmt->bindParam(':sid', $GLOBALS['sessionTable']['id'], PDO::PARAM_STR); + $stmt->execute(); + } + + $from_time = strtotime($GLOBALS['userTable']['lastSeen']); + $to_time = strtotime(context::getCurrentTime()); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince > 3) { + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET lastSeen = NOW() WHERE id = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + } + + if ($GLOBALS['userTable']['inGame'] == 1 and !isset($GLOBALS['ignoreGame'])) { + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET inGame = 0 WHERE id = :id;"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + } + } + + if ($GLOBALS['loggedIn'] == false) { + $GLOBALS['csrf_token'] = sha1(auth::getIP()); + if (isset($_COOKIE['auth_uid']) || isset($_COOKIE['a_id'])) { + setcookie('auth_uid', "", time() - 3600); + setcookie('a_id', "", time() - 3600); + } + } + } +?> diff --git a/core/func/character/colors.php b/core/func/character/colors.php new file mode 100644 index 0000000..f9d92c1 --- /dev/null +++ b/core/func/character/colors.php @@ -0,0 +1,556 @@ + + + +prepare("SELECT * FROM characterColors WHERE uid=:id AND type='head';"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $head = $stmt->fetch(PDO::FETCH_ASSOC); + $headColor = true; + if ($stmt->rowCount() == 0) { + $headColor = false; + } + if ($headColor == false) { + $head_hex = "#F2F3F3"; + }else{ + $h_color_int = $head['color']; + if ($h_color_int == 1) { + $head_hex = "#F2F3F3"; + }elseif ($h_color_int == 208) { + $head_hex = "#E5E4DF"; + }elseif ($h_color_int == 194) { + $head_hex = "#A3A2A5"; + }elseif ($h_color_int == 199) { + $head_hex = "#635F62"; + }elseif ($h_color_int == 26) { + $head_hex = "#1B2A35"; + }elseif ($h_color_int == 21) { + $head_hex = "#C4281C"; + }elseif ($h_color_int == 24) { + $head_hex = "#F5CD30"; + }elseif ($h_color_int == 226) { + $head_hex = "#FDEA8D"; + }elseif ($h_color_int == 23) { + $head_hex = "#0D69AC"; + }elseif ($h_color_int == 107) { + $head_hex = "#008F9C"; + }elseif ($h_color_int == 102) { + $head_hex = "#6E99CA"; + }elseif ($h_color_int == 11) { + $head_hex = "#80BBDB"; + }elseif ($h_color_int == 45) { + $head_hex = "#B4D2E4"; + }elseif ($h_color_int == 135) { + $head_hex = "#74869D"; + }elseif ($h_color_int == 105) { + $head_hex = "#E29B40"; + }elseif ($h_color_int == 141) { + $head_hex = "#27462D"; + }elseif ($h_color_int == 37) { + $head_hex = "#4B974B"; + }elseif ($h_color_int == 119) { + $head_hex = "#A4BD47"; + }elseif ($h_color_int == 29) { + $head_hex = "#A1C48C"; + }elseif ($h_color_int == 151) { + $head_hex = "#789082"; + }elseif ($h_color_int == 38) { + $head_hex = "#A05F35"; + }elseif ($h_color_int == 192) { + $head_hex = "#694028"; + }elseif ($h_color_int == 104) { + $head_hex = "#6B327C"; + }elseif ($h_color_int == 9) { + $head_hex = "#E8BAC8"; + }elseif ($h_color_int == 101) { + $head_hex = "#DA867A"; + }elseif ($h_color_int == 5) { + $head_hex = "#D7C59A"; + }elseif ($h_color_int == 153) { + $head_hex = "#957977"; + }elseif ($h_color_int == 217) { + $head_hex = "#7C5C46"; + }elseif ($h_color_int == 18) { + $head_hex = "#CC8E69"; + }elseif ($h_color_int == 125) { + $head_hex = "#EAB892"; + }else{ + $head_hex = "#F2F3F3"; + } + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM characterColors WHERE uid=:id AND type='torso';"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $torso = $stmt->fetch(PDO::FETCH_ASSOC); + $torsoColor = true; + if ($stmt->rowCount() == 0) { + $torsoColor = false; + } + if ($torsoColor == false) { + $torso_hex = "#1B2A35"; + }else{ + $t_color_int = $torso['color']; + if ($t_color_int == 1) { + $torso_hex = "#F2F3F3"; + }elseif ($t_color_int == 208) { + $torso_hex = "#E5E4DF"; + }elseif ($t_color_int == 194) { + $torso_hex = "#A3A2A5"; + }elseif ($t_color_int == 199) { + $torso_hex = "#635F62"; + }elseif ($t_color_int == 26) { + $torso_hex = "#1B2A35"; + }elseif ($t_color_int == 21) { + $torso_hex = "#C4281C"; + }elseif ($t_color_int == 24) { + $torso_hex = "#F5CD30"; + }elseif ($t_color_int == 226) { + $torso_hex = "#FDEA8D"; + }elseif ($t_color_int == 23) { + $torso_hex = "#0D69AC"; + }elseif ($t_color_int == 107) { + $torso_hex = "#008F9C"; + }elseif ($t_color_int == 102) { + $torso_hex = "#6E99CA"; + }elseif ($t_color_int == 11) { + $torso_hex = "#80BBDB"; + }elseif ($t_color_int == 45) { + $torso_hex = "#B4D2E4"; + }elseif ($t_color_int == 135) { + $torso_hex = "#74869D"; + }elseif ($t_color_int == 105) { + $torso_hex = "#E29B40"; + }elseif ($t_color_int == 141) { + $torso_hex = "#27462D"; + }elseif ($t_color_int == 37) { + $torso_hex = "#4B974B"; + }elseif ($t_color_int == 119) { + $torso_hex = "#A4BD47"; + }elseif ($t_color_int == 29) { + $torso_hex = "#A1C48C"; + }elseif ($t_color_int == 151) { + $torso_hex = "#789082"; + }elseif ($t_color_int == 38) { + $torso_hex = "#A05F35"; + }elseif ($t_color_int == 192) { + $torso_hex = "#694028"; + }elseif ($t_color_int == 104) { + $torso_hex = "#6B327C"; + }elseif ($t_color_int == 9) { + $torso_hex = "#E8BAC8"; + }elseif ($t_color_int == 101) { + $torso_hex = "#DA867A"; + }elseif ($t_color_int == 5) { + $torso_hex = "#D7C59A"; + }elseif ($t_color_int == 153) { + $torso_hex = "#957977"; + }elseif ($t_color_int == 217) { + $torso_hex = "#7C5C46"; + }elseif ($t_color_int == 18) { + $torso_hex = "#CC8E69"; + }elseif ($t_color_int == 125) { + $torso_hex = "#EAB892"; + }else{ + $torso_hex = "#1B2A35"; + } + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM characterColors WHERE uid=:id AND type='rightarm';"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $rightarm = $stmt->fetch(PDO::FETCH_ASSOC); + $rightarmColor = true; + if ($stmt->rowCount() == 0) { + $rightarmColor = false; + } + if ($rightarmColor == false) { + $rarm_hex = "#F2F3F3"; + }else{ + $rarm_color_int = $rightarm['color']; + if ($rarm_color_int == 1) { + $rarm_hex = "#F2F3F3"; + }elseif ($rarm_color_int == 208) { + $rarm_hex = "#E5E4DF"; + }elseif ($rarm_color_int == 194) { + $rarm_hex = "#A3A2A5"; + }elseif ($rarm_color_int == 199) { + $rarm_hex = "#635F62"; + }elseif ($rarm_color_int == 26) { + $rarm_hex = "#1B2A35"; + }elseif ($rarm_color_int == 21) { + $rarm_hex = "#C4281C"; + }elseif ($rarm_color_int == 24) { + $rarm_hex = "#F5CD30"; + }elseif ($rarm_color_int == 226) { + $rarm_hex = "#FDEA8D"; + }elseif ($rarm_color_int == 23) { + $rarm_hex = "#0D69AC"; + }elseif ($rarm_color_int == 107) { + $rarm_hex = "#008F9C"; + }elseif ($rarm_color_int == 102) { + $rarm_hex = "#6E99CA"; + }elseif ($rarm_color_int == 11) { + $rarm_hex = "#80BBDB"; + }elseif ($rarm_color_int == 45) { + $rarm_hex = "#B4D2E4"; + }elseif ($rarm_color_int == 135) { + $rarm_hex = "#74869D"; + }elseif ($rarm_color_int == 105) { + $rarm_hex = "#E29B40"; + }elseif ($rarm_color_int == 141) { + $rarm_hex = "#27462D"; + }elseif ($rarm_color_int == 37) { + $rarm_hex = "#4B974B"; + }elseif ($rarm_color_int == 119) { + $rarm_hex = "#A4BD47"; + }elseif ($rarm_color_int == 29) { + $rarm_hex = "#A1C48C"; + }elseif ($rarm_color_int == 151) { + $rarm_hex = "#789082"; + }elseif ($rarm_color_int == 38) { + $rarm_hex = "#A05F35"; + }elseif ($rarm_color_int == 192) { + $rarm_hex = "#694028"; + }elseif ($rarm_color_int == 104) { + $rarm_hex = "#6B327C"; + }elseif ($rarm_color_int == 9) { + $rarm_hex = "#E8BAC8"; + }elseif ($rarm_color_int == 101) { + $rarm_hex = "#DA867A"; + }elseif ($rarm_color_int == 5) { + $rarm_hex = "#D7C59A"; + }elseif ($rarm_color_int == 153) { + $rarm_hex = "#957977"; + }elseif ($rarm_color_int == 217) { + $rarm_hex = "#7C5C46"; + }elseif ($rarm_color_int == 18) { + $rarm_hex = "#CC8E69"; + }elseif ($rarm_color_int == 125) { + $rarm_hex = "#EAB892"; + }else{ + $rarm_hex = "#F2F3F3"; + } + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM characterColors WHERE uid=:id AND type='rightleg';"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $rightleg = $stmt->fetch(PDO::FETCH_ASSOC); + $rightlegColor = true; + if ($stmt->rowCount() == 0) { + $rightlegColor = false; + } + if ($rightlegColor == false) { + $rl_hex = "#C4281C"; + }else{ + $rl_color_int = $rightleg['color']; + if ($rl_color_int == 1) { + $rl_hex = "#F2F3F3"; + }elseif ($rl_color_int == 208) { + $rl_hex = "#E5E4DF"; + }elseif ($rl_color_int == 194) { + $rl_hex = "#A3A2A5"; + }elseif ($rl_color_int == 199) { + $rl_hex = "#635F62"; + }elseif ($rl_color_int == 26) { + $rl_hex = "#1B2A35"; + }elseif ($rl_color_int == 21) { + $rl_hex = "#C4281C"; + }elseif ($rl_color_int == 24) { + $rl_hex = "#F5CD30"; + }elseif ($rl_color_int == 226) { + $rl_hex = "#FDEA8D"; + }elseif ($rl_color_int == 23) { + $rl_hex = "#0D69AC"; + }elseif ($rl_color_int == 107) { + $rl_hex = "#008F9C"; + }elseif ($rl_color_int == 102) { + $rl_hex = "#6E99CA"; + }elseif ($rl_color_int == 11) { + $rl_hex = "#80BBDB"; + }elseif ($rl_color_int == 45) { + $rl_hex = "#B4D2E4"; + }elseif ($rl_color_int == 135) { + $rl_hex = "#74869D"; + }elseif ($rl_color_int == 105) { + $rl_hex = "#E29B40"; + }elseif ($rl_color_int == 141) { + $rl_hex = "#27462D"; + }elseif ($rl_color_int == 37) { + $rl_hex = "#4B974B"; + }elseif ($rl_color_int == 119) { + $rl_hex = "#A4BD47"; + }elseif ($rl_color_int == 29) { + $rl_hex = "#A1C48C"; + }elseif ($rl_color_int == 151) { + $rl_hex = "#789082"; + }elseif ($rl_color_int == 38) { + $rl_hex = "#A05F35"; + }elseif ($rl_color_int == 192) { + $rl_hex = "#694028"; + }elseif ($rl_color_int == 104) { + $rl_hex = "#6B327C"; + }elseif ($rl_color_int == 9) { + $rl_hex = "#E8BAC8"; + }elseif ($rl_color_int == 101) { + $rl_hex = "#DA867A"; + }elseif ($rl_color_int == 5) { + $rl_hex = "#D7C59A"; + }elseif ($rl_color_int == 153) { + $rl_hex = "#957977"; + }elseif ($rl_color_int == 217) { + $rl_hex = "#7C5C46"; + }elseif ($rl_color_int == 18) { + $rl_hex = "#CC8E69"; + }elseif ($rl_color_int == 125) { + $rl_hex = "#EAB892"; + }else{ + $rl_hex = "#C4281C"; + } + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM characterColors WHERE uid=:id AND type='leftarm';"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $leftarm = $stmt->fetch(PDO::FETCH_ASSOC); + $leftarmColor = true; + if ($stmt->rowCount() == 0) { + $leftarmColor = false; + } + if ($leftarmColor == false) { + $la_hex = "#F2F3F3"; + }else{ + $la_color_int = $leftarm['color']; + if ($la_color_int == 1) { + $la_hex = "#F2F3F3"; + }elseif ($la_color_int == 208) { + $la_hex = "#E5E4DF"; + }elseif ($la_color_int == 194) { + $la_hex = "#A3A2A5"; + }elseif ($la_color_int == 199) { + $la_hex = "#635F62"; + }elseif ($la_color_int == 26) { + $la_hex = "#1B2A35"; + }elseif ($la_color_int == 21) { + $la_hex = "#C4281C"; + }elseif ($la_color_int == 24) { + $la_hex = "#F5CD30"; + }elseif ($la_color_int == 226) { + $la_hex = "#FDEA8D"; + }elseif ($la_color_int == 23) { + $la_hex = "#0D69AC"; + }elseif ($la_color_int == 107) { + $la_hex = "#008F9C"; + }elseif ($la_color_int == 102) { + $la_hex = "#6E99CA"; + }elseif ($la_color_int == 11) { + $la_hex = "#80BBDB"; + }elseif ($la_color_int == 45) { + $la_hex = "#B4D2E4"; + }elseif ($la_color_int == 135) { + $la_hex = "#74869D"; + }elseif ($la_color_int == 105) { + $la_hex = "#E29B40"; + }elseif ($la_color_int == 141) { + $la_hex = "#27462D"; + }elseif ($la_color_int == 37) { + $la_hex = "#4B974B"; + }elseif ($la_color_int == 119) { + $la_hex = "#A4BD47"; + }elseif ($la_color_int == 29) { + $la_hex = "#A1C48C"; + }elseif ($la_color_int == 151) { + $la_hex = "#789082"; + }elseif ($la_color_int == 38) { + $la_hex = "#A05F35"; + }elseif ($la_color_int == 192) { + $la_hex = "#694028"; + }elseif ($la_color_int == 104) { + $la_hex = "#6B327C"; + }elseif ($la_color_int == 9) { + $la_hex = "#E8BAC8"; + }elseif ($la_color_int == 101) { + $la_hex = "#DA867A"; + }elseif ($la_color_int == 5) { + $la_hex = "#D7C59A"; + }elseif ($la_color_int == 153) { + $la_hex = "#957977"; + }elseif ($la_color_int == 217) { + $la_hex = "#7C5C46"; + }elseif ($la_color_int == 18) { + $la_hex = "#CC8E69"; + }elseif ($la_color_int == 125) { + $la_hex = "#EAB892"; + }else{ + $la_hex = "#F2F3F3"; + } + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM characterColors WHERE uid=:id AND type='leftleg';"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $leftleg = $stmt->fetch(PDO::FETCH_ASSOC); + $leftlegColor = true; + if ($stmt->rowCount() == 0) { + $leftlegColor = false; + } + if ($leftlegColor == false) { + $ll_hex = "#C4281C"; + }else{ + $ll_color_int = $leftleg['color']; + if ($ll_color_int == 1) { + $ll_hex = "#F2F3F3"; + }elseif ($ll_color_int == 208) { + $ll_hex = "#E5E4DF"; + }elseif ($ll_color_int == 194) { + $ll_hex = "#A3A2A5"; + }elseif ($ll_color_int == 199) { + $ll_hex = "#635F62"; + }elseif ($ll_color_int == 26) { + $ll_hex = "#1B2A35"; + }elseif ($ll_color_int == 21) { + $ll_hex = "#C4281C"; + }elseif ($ll_color_int == 24) { + $ll_hex = "#F5CD30"; + }elseif ($ll_color_int == 226) { + $ll_hex = "#FDEA8D"; + }elseif ($ll_color_int == 23) { + $ll_hex = "#0D69AC"; + }elseif ($ll_color_int == 107) { + $ll_hex = "#008F9C"; + }elseif ($ll_color_int == 102) { + $ll_hex = "#6E99CA"; + }elseif ($ll_color_int == 11) { + $ll_hex = "#80BBDB"; + }elseif ($ll_color_int == 45) { + $ll_hex = "#B4D2E4"; + }elseif ($ll_color_int == 135) { + $ll_hex = "#74869D"; + }elseif ($ll_color_int == 105) { + $ll_hex = "#E29B40"; + }elseif ($ll_color_int == 141) { + $ll_hex = "#27462D"; + }elseif ($ll_color_int == 37) { + $ll_hex = "#4B974B"; + }elseif ($ll_color_int == 119) { + $ll_hex = "#A4BD47"; + }elseif ($ll_color_int == 29) { + $ll_hex = "#A1C48C"; + }elseif ($ll_color_int == 151) { + $ll_hex = "#789082"; + }elseif ($ll_color_int == 38) { + $ll_hex = "#A05F35"; + }elseif ($ll_color_int == 192) { + $ll_hex = "#694028"; + }elseif ($ll_color_int == 104) { + $ll_hex = "#6B327C"; + }elseif ($ll_color_int == 9) { + $ll_hex = "#E8BAC8"; + }elseif ($ll_color_int == 101) { + $ll_hex = "#DA867A"; + }elseif ($ll_color_int == 5) { + $ll_hex = "#D7C59A"; + }elseif ($ll_color_int == 153) { + $ll_hex = "#957977"; + }elseif ($ll_color_int == 217) { + $ll_hex = "#7C5C46"; + }elseif ($ll_color_int == 18) { + $ll_hex = "#CC8E69"; + }elseif ($ll_color_int == 125) { + $ll_hex = "#EAB892"; + }else{ + $ll_hex = "#C4281C"; + } + } +?> +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/core/func/character/js/colorJs.js b/core/func/character/js/colorJs.js new file mode 100644 index 0000000..75d3aa1 --- /dev/null +++ b/core/func/character/js/colorJs.js @@ -0,0 +1,572 @@ +function updateColor(code) { + $('#colordialog').modal('toggle'); + if (bodyPart == "head") { + $.get("/core/func/character/postsColor.php?updateHead=" + code, function(data){ + if (code == 1) { + $("#head").css('background', "#F2F3F3"); + } + if (code == 208) { + $("#head").css('background', "#E5E4DF"); + } + if (code == 194) { + $("#head").css('background', "#A3A2A5"); + } + if (code == 199) { + $("#head").css('background', "#635F62"); + } + if (code == 26) { + $("#head").css('background', "#1B2A35"); + } + if (code == 21) { + $("#head").css('background', "#C4281C"); + } + if (code == 24) { + $("#head").css('background', "#F5CD30"); + } + if (code == 226) { + $("#head").css('background', "#FDEA8D"); + } + if (code == 23) { + $("#head").css('background', "#0D69AC"); + } + if (code == 107) { + $("#head").css('background', "#008F9C"); + } + if (code == 102) { + $("#head").css('background', "#6E99CA"); + } + if (code == 11) { + $("#head").css('background', "#80BBDB"); + } + if (code == 45) { + $("#head").css('background', "#B4D2E4"); + } + if (code == 135) { + $("#head").css('background', "#74869D"); + } + if (code == 105) { + $("#head").css('background', "#E29B40"); + } + if (code == 141) { + $("#head").css('background', "#27462D"); + } + if (code == 37) { + $("#head").css('background', "#4B974B"); + } + if (code == 119) { + $("#head").css('background', "#A4BD47"); + } + if (code == 29) { + $("#head").css('background', "#A1C48C"); + } + if (code == 151) { + $("#head").css('background', "#789082"); + } + if (code == 38) { + $("#head").css('background', "#A05F35"); + } + if (code == 192) { + $("#head").css('background', "#694028"); + } + if (code == 104) { + $("#head").css('background', "#6B327C"); + } + if (code == 9) { + $("#head").css('background', "#E8BAC8"); + } + if (code == 101) { + $("#head").css('background', "#DA867A"); + } + if (code == 5) { + $("#head").css('background', "#D7C59A"); + } + if (code == 153) { + $("#head").css('background', "#957977"); + } + if (code == 217) { + $("#head").css('background', "#7C5C46"); + } + if (code == 18) { + $("#head").css('background', "#CC8E69"); + } + if (code == 125) { + $("#head").css('background', "#EAB892"); + } + }); + } + + if (bodyPart == "leftarm") { + $.get("/core/func/character/postsColor.php?updateLeftArm=" + code, function(data){ + if (code == 1) { + $("#leftarm").css('background', "#F2F3F3"); + } + if (code == 208) { + $("#leftarm").css('background', "#E5E4DF"); + } + if (code == 194) { + $("#leftarm").css('background', "#A3A2A5"); + } + if (code == 199) { + $("#leftarm").css('background', "#A3A2A5"); + } + if (code == 26) { + $("#leftarm").css('background', "#1B2A35"); + } + if (code == 21) { + $("#leftarm").css('background', "#C4281C"); + } + if (code == 24) { + $("#leftarm").css('background', "#F5CD30"); + } + if (code == 226) { + $("#leftarm").css('background', "#FDEA8D"); + } + if (code == 23) { + $("#leftarm").css('background', "#0D69AC"); + } + if (code == 107) { + $("#leftarm").css('background', "#008F9C"); + } + if (code == 102) { + $("#leftarm").css('background', "#6E99CA"); + } + if (code == 11) { + $("#leftarm").css('background', "#80BBDB"); + } + if (code == 45) { + $("#leftarm").css('background', "#B4D2E4"); + } + if (code == 135) { + $("#leftarm").css('background', "#74869D"); + } + if (code == 105) { + $("#leftarm").css('background', "#E29B40"); + } + if (code == 141) { + $("#leftarm").css('background', "#27462D"); + } + if (code == 37) { + $("#leftarm").css('background', "#4B974B"); + } + if (code == 119) { + $("#leftarm").css('background', "#A4BD47"); + } + if (code == 29) { + $("#leftarm").css('background', "#A1C48C"); + } + if (code == 151) { + $("#leftarm").css('background', "#789082"); + } + if (code == 38) { + $("#leftarm").css('background', "#A05F35"); + } + if (code == 192) { + $("#leftarm").css('background', "#694028"); + } + if (code == 104) { + $("#leftarm").css('background', "#6B327C"); + } + if (code == 9) { + $("#leftarm").css('background', "#E8BAC8"); + } + if (code == 101) { + $("#leftarm").css('background', "#DA867A"); + } + if (code == 5) { + $("#leftarm").css('background', "#D7C59A"); + } + if (code == 153) { + $("#leftarm").css('background', "#957977"); + } + if (code == 217) { + $("#leftarm").css('background', "#7C5C46"); + } + if (code == 18) { + $("#leftarm").css('background', "#CC8E69"); + } + if (code == 125) { + $("#leftarm").css('background', "#EAB892"); + } + }); + } + + if (bodyPart == "torso") { + $.get("/core/func/character/postsColor.php?updateTorso=" + code, function(data){ + if (code == 1) { + $("#torso").css('background', "#F2F3F3"); + } + if (code == 208) { + $("#torso").css('background', "#E5E4DF"); + } + if (code == 194) { + $("#torso").css('background', "#A3A2A5"); + } + if (code == 199) { + $("#torso").css('background', "#A3A2A5"); + } + if (code == 26) { + $("#torso").css('background', "#1B2A35"); + } + if (code == 21) { + $("#torso").css('background', "#C4281C"); + } + if (code == 24) { + $("#torso").css('background', "#F5CD30"); + } + if (code == 226) { + $("#torso").css('background', "#FDEA8D"); + } + if (code == 23) { + $("#torso").css('background', "#0D69AC"); + } + if (code == 107) { + $("#torso").css('background', "#008F9C"); + } + if (code == 102) { + $("#torso").css('background', "#6E99CA"); + } + if (code == 11) { + $("#torso").css('background', "#80BBDB"); + } + if (code == 45) { + $("#torso").css('background', "#B4D2E4"); + } + if (code == 135) { + $("#torso").css('background', "#74869D"); + } + if (code == 105) { + $("#torso").css('background', "#E29B40"); + } + if (code == 141) { + $("#torso").css('background', "#27462D"); + } + if (code == 37) { + $("#torso").css('background', "#4B974B"); + } + if (code == 119) { + $("#torso").css('background', "#A4BD47"); + } + if (code == 29) { + $("#torso").css('background', "#A1C48C"); + } + if (code == 151) { + $("#torso").css('background', "#789082"); + } + if (code == 38) { + $("#torso").css('background', "#A05F35"); + } + if (code == 192) { + $("#torso").css('background', "#694028"); + } + if (code == 104) { + $("#torso").css('background', "#6B327C"); + } + if (code == 9) { + $("#torso").css('background', "#E8BAC8"); + } + if (code == 101) { + $("#torso").css('background', "#DA867A"); + } + if (code == 5) { + $("#torso").css('background', "#D7C59A"); + } + if (code == 153) { + $("#torso").css('background', "#957977"); + } + if (code == 217) { + $("#torso").css('background', "#7C5C46"); + } + if (code == 18) { + $("#torso").css('background', "#CC8E69"); + } + if (code == 125) { + $("#torso").css('background', "#EAB892"); + } + }); + } + + if (bodyPart == "rightarm") { + $.get("/core/func/character/postsColor.php?updateRightArm=" + code, function(data){ + if (code == 1) { + $("#rightarm").css('background', "#F2F3F3"); + } + if (code == 208) { + $("#rightarm").css('background', "#E5E4DF"); + } + if (code == 194) { + $("#rightarm").css('background', "#A3A2A5"); + } + if (code == 199) { + $("#rightarm").css('background', "#A3A2A5"); + } + if (code == 26) { + $("#rightarm").css('background', "#1B2A35"); + } + if (code == 21) { + $("#rightarm").css('background', "#C4281C"); + } + if (code == 24) { + $("#rightarm").css('background', "#F5CD30"); + } + if (code == 226) { + $("#rightarm").css('background', "#FDEA8D"); + } + if (code == 23) { + $("#rightarm").css('background', "#0D69AC"); + } + if (code == 107) { + $("#rightarm").css('background', "#008F9C"); + } + if (code == 102) { + $("#rightarm").css('background', "#6E99CA"); + } + if (code == 11) { + $("#rightarm").css('background', "#80BBDB"); + } + if (code == 45) { + $("#rightarm").css('background', "#B4D2E4"); + } + if (code == 135) { + $("#rightarm").css('background', "#74869D"); + } + if (code == 105) { + $("#rightarm").css('background', "#E29B40"); + } + if (code == 141) { + $("#rightarm").css('background', "#27462D"); + } + if (code == 37) { + $("#rightarm").css('background', "#4B974B"); + } + if (code == 119) { + $("#rightarm").css('background', "#A4BD47"); + } + if (code == 29) { + $("#rightarm").css('background', "#A1C48C"); + } + if (code == 151) { + $("#rightarm").css('background', "#789082"); + } + if (code == 38) { + $("#rightarm").css('background', "#A05F35"); + } + if (code == 192) { + $("#rightarm").css('background', "#694028"); + } + if (code == 104) { + $("#rightarm").css('background', "#6B327C"); + } + if (code == 9) { + $("#rightarm").css('background', "#E8BAC8"); + } + if (code == 101) { + $("#rightarm").css('background', "#DA867A"); + } + if (code == 5) { + $("#rightarm").css('background', "#D7C59A"); + } + if (code == 153) { + $("#rightarm").css('background', "#957977"); + } + if (code == 217) { + $("#rightarm").css('background', "#7C5C46"); + } + if (code == 18) { + $("#rightarm").css('background', "#CC8E69"); + } + if (code == 125) { + $("#rightarm").css('background', "#EAB892"); + } + }); + } + + if (bodyPart == "leftleg") { + $.get("/core/func/character/postsColor.php?updateLeftLeg=" + code, function(data){ + if (code == 1) { + $("#leftleg").css('background', "#F2F3F3"); + } + if (code == 208) { + $("#leftleg").css('background', "#E5E4DF"); + } + if (code == 194) { + $("#leftleg").css('background', "#A3A2A5"); + } + if (code == 199) { + $("#leftleg").css('background', "#A3A2A5"); + } + if (code == 26) { + $("#leftleg").css('background', "#1B2A35"); + } + if (code == 21) { + $("#leftleg").css('background', "#C4281C"); + } + if (code == 24) { + $("#leftleg").css('background', "#F5CD30"); + } + if (code == 226) { + $("#leftleg").css('background', "#FDEA8D"); + } + if (code == 23) { + $("#leftleg").css('background', "#0D69AC"); + } + if (code == 107) { + $("#leftleg").css('background', "#008F9C"); + } + if (code == 102) { + $("#leftleg").css('background', "#6E99CA"); + } + if (code == 11) { + $("#leftleg").css('background', "#80BBDB"); + } + if (code == 45) { + $("#leftleg").css('background', "#B4D2E4"); + } + if (code == 135) { + $("#leftleg").css('background', "#74869D"); + } + if (code == 105) { + $("#leftleg").css('background', "#E29B40"); + } + if (code == 141) { + $("#leftleg").css('background', "#27462D"); + } + if (code == 37) { + $("#leftleg").css('background', "#4B974B"); + } + if (code == 119) { + $("#leftleg").css('background', "#A4BD47"); + } + if (code == 29) { + $("#leftleg").css('background', "#A1C48C"); + } + if (code == 151) { + $("#leftleg").css('background', "#789082"); + } + if (code == 38) { + $("#leftleg").css('background', "#A05F35"); + } + if (code == 192) { + $("#leftleg").css('background', "#694028"); + } + if (code == 104) { + $("#leftleg").css('background', "#6B327C"); + } + if (code == 9) { + $("#leftleg").css('background', "#E8BAC8"); + } + if (code == 101) { + $("#leftleg").css('background', "#DA867A"); + } + if (code == 5) { + $("#leftleg").css('background', "#D7C59A"); + } + if (code == 153) { + $("#leftleg").css('background', "#957977"); + } + if (code == 217) { + $("#leftleg").css('background', "#7C5C46"); + } + if (code == 18) { + $("#leftleg").css('background', "#CC8E69"); + } + if (code == 125) { + $("#leftleg").css('background', "#EAB892"); + } + }); + } + + if (bodyPart == "rightleg") { + $.get("/core/func/character/postsColor.php?updateRightLeg=" + code, function(data){ + if (code == 1) { + $("#rightleg").css('background', "#F2F3F3"); + } + if (code == 208) { + $("#rightleg").css('background', "#E5E4DF"); + } + if (code == 194) { + $("#rightleg").css('background', "#A3A2A5"); + } + if (code == 199) { + $("#rightleg").css('background', "#A3A2A5"); + } + if (code == 26) { + $("#rightleg").css('background', "#1B2A35"); + } + if (code == 21) { + $("#rightleg").css('background', "#C4281C"); + } + if (code == 24) { + $("#rightleg").css('background', "#F5CD30"); + } + if (code == 226) { + $("#rightleg").css('background', "#FDEA8D"); + } + if (code == 23) { + $("#rightleg").css('background', "#0D69AC"); + } + if (code == 107) { + $("#rightleg").css('background', "#008F9C"); + } + if (code == 102) { + $("#rightleg").css('background', "#6E99CA"); + } + if (code == 11) { + $("#rightleg").css('background', "#80BBDB"); + } + if (code == 45) { + $("#rightleg").css('background', "#B4D2E4"); + } + if (code == 135) { + $("#rightleg").css('background', "#74869D"); + } + if (code == 105) { + $("#rightleg").css('background', "#E29B40"); + } + if (code == 141) { + $("#rightleg").css('background', "#27462D"); + } + if (code == 37) { + $("#rightleg").css('background', "#4B974B"); + } + if (code == 119) { + $("#rightleg").css('background', "#A4BD47"); + } + if (code == 29) { + $("#rightleg").css('background', "#A1C48C"); + } + if (code == 151) { + $("#rightleg").css('background', "#789082"); + } + if (code == 38) { + $("#rightleg").css('background', "#A05F35"); + } + if (code == 192) { + $("#rightleg").css('background', "#694028"); + } + if (code == 104) { + $("#rightleg").css('background', "#6B327C"); + } + if (code == 9) { + $("#rightleg").css('background', "#E8BAC8"); + } + if (code == 101) { + $("#rightleg").css('background', "#DA867A"); + } + if (code == 5) { + $("#rightleg").css('background', "#D7C59A"); + } + if (code == 153) { + $("#rightleg").css('background', "#957977"); + } + if (code == 217) { + $("#rightleg").css('background', "#7C5C46"); + } + if (code == 18) { + $("#rightleg").css('background', "#CC8E69"); + } + if (code == 125) { + $("#rightleg").css('background', "#EAB892"); + } + }); + } +} \ No newline at end of file diff --git a/core/func/character/postsColor.php b/core/func/character/postsColor.php new file mode 100644 index 0000000..b9d2a97 --- /dev/null +++ b/core/func/character/postsColor.php @@ -0,0 +1,106 @@ +prepare("SELECT * FROM characterColors WHERE uid = :uid AND type = :type"); + $stmt->bindParam(':uid', $_COOKIE['auth_uid'], PDO::PARAM_INT); + $stmt->bindParam(':type', $type, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + $query = "INSERT INTO characterColors (`uid`, `color`, `type`) VALUES (:uid, :color, :type);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $_COOKIE['auth_uid'], PDO::PARAM_INT); + $stmt->bindParam(':color', $color, PDO::PARAM_INT); + $stmt->bindParam(':type', $type, PDO::PARAM_STR); + $stmt->execute(); + }else{ + $query = "UPDATE `characterColors` SET `color`=:color WHERE `uid`=:uid AND `type`=:type "; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $_COOKIE['auth_uid'], PDO::PARAM_INT); + $stmt->bindParam(':color', $color, PDO::PARAM_INT); + $stmt->bindParam(':type', $type, PDO::PARAM_STR); + $stmt->execute(); + } + + $query = "INSERT INTO renders (`render_id`, `type`) VALUES (:uid, 'character');"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $_COOKIE['auth_uid'], PDO::PARAM_INT); + $stmt->execute(); + + $query = "INSERT INTO renders (`render_id`, `type`, `version`) VALUES (:uid, 'character', 2);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':uid', $_COOKIE['auth_uid'], PDO::PARAM_INT); + $stmt->execute(); + } + + if (isset($_GET['updateHead'])) { + $color = $_GET['updateHead']; + if (checkColor($color) == true) { + setColor($color, "head", $dbcon); + echo '
Updated Head Color!
'; + }else{ + echo '
This color can not be applied.
'; + } + } + + if (isset($_GET['updateTorso'])) { + $color = $_GET['updateTorso']; + if (checkColor($color) == true) { + setColor($color, "torso", $dbcon); + echo '
Updated Torso Color!
'; + }else{ + echo '
This color can not be applied.
'; + } + } + + if (isset($_GET['updateRightArm'])) { + $color = $_GET['updateRightArm']; + if (checkColor($color) == true) { + setColor($color, "rightarm", $dbcon); + echo '
Updated Right Arm Color!
'; + }else{ + echo '
This color can not be applied.
'; + } + } + + if (isset($_GET['updateRightLeg'])) { + $color = $_GET['updateRightLeg']; + if (checkColor($color) == true) { + setColor($color, "rightleg", $dbcon); + echo '
Updated Right Leg Color!
'; + }else{ + echo '
This color can not be applied.
'; + } + } + + if (isset($_GET['updateLeftArm'])) { + $color = $_GET['updateLeftArm']; + if (checkColor($color) == true) { + setColor($color, "leftarm", $dbcon); + echo '
Updated Left Arm Color!
'; + }else{ + echo '
This color can not be applied.
'; + } + } + + if (isset($_GET['updateLeftLeg'])) { + $color = $_GET['updateLeftLeg']; + if (checkColor($color) == true) { + echo '
Updated Left Leg Color!
'; + setColor($color, "leftleg", $dbcon); + }else{ + echo '
This color can not be applied.
'; + } + } +?> \ No newline at end of file diff --git a/core/func/config/config.php b/core/func/config/config.php new file mode 100644 index 0000000..db3d04b --- /dev/null +++ b/core/func/config/config.php @@ -0,0 +1,12 @@ + diff --git a/core/func/config/main.php b/core/func/config/main.php new file mode 100644 index 0000000..8669854 --- /dev/null +++ b/core/func/config/main.php @@ -0,0 +1,8 @@ + diff --git a/core/func/connectivity/main.php b/core/func/connectivity/main.php new file mode 100644 index 0000000..2123496 --- /dev/null +++ b/core/func/connectivity/main.php @@ -0,0 +1,26 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $GLOBALS['dbcon']->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + $GLOBALS['dbcon']->setAttribute(PDO::ATTR_PERSISTENT , true); + }catch (exception $e) { + echo 'We could not connect to the database. Our potatoes are working on it.'; + exit; + } + } + + public static function closeDatabaseConnection() { + if (isset($GLOBALS['dbcon'])) { + $GLOBALS['dbcon'] = null; + } + } + } +?> diff --git a/core/func/context.php b/core/func/context.php new file mode 100644 index 0000000..ae6fbee --- /dev/null +++ b/core/func/context.php @@ -0,0 +1,321 @@ +prepare($query); + $stmt->bindParam(':id', $userID, PDO::PARAM_INT); + $stmt->execute(); + return $stmt->fetch(PDO::FETCH_ASSOC); + } + + public static function getUserSheetByIDForum($userID) { + $query = "SELECT id, username, rank, imgTime FROM users WHERE id = :id"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $userID, PDO::PARAM_INT); + $stmt->execute(); + return $stmt->fetch(PDO::FETCH_ASSOC); + } + + public static function jsonToSingle($json) { + $jsonNew = substr($json, 1); + $jsonNew = substr_replace($jsonNew, "", -1); + return $jsonNew; + } + + public static function getTimeSince($timeFrom) { + $to_time = strtotime(context::getCurrentTime()); + $from_time = strtotime($timeFrom); + return round(abs($to_time - $from_time) / 60,2); + } + + public static function IDToUsername($userID) { + $stmt = $GLOBALS['dbcon']->prepare('SELECT username FROM users WHERE id = :userId'); + $stmt->bindParam(':userId', $userID, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + return $result['username']; + } + + public static function getUserImage($userSheet) { + if ($userSheet['imgTime'] == 0 || $userSheet['imgTime'] == null) { + return 'https://api.xdiscuss.net/imageServer/user/def2.png?v=2'; + }else{ + return 'https://api.xdiscuss.net/imageServer/user/'.$userSheet['id'].'.png?time='.$userSheet['imgTime']; + } + } + + public static function getGroupImage($userID) { + $query = "SELECT imgTime, id FROM users WHERE id = :id"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $userID, PDO::PARAM_INT); + $stmt->execute(); + $userSheet = $stmt->fetch(PDO::FETCH_ASSOC); + if ($userSheet['imgTime'] == 0 || $userSheet['imgTime'] == null) { + return 'https://api.xdiscuss.net/imageServer/user/def2.png'; + }else{ + return 'https://api.xdiscuss.net/imageServer/user/'.$userSheet['id'].'.png?time='.$userSheet['imgTime']; + } + } + + public static function getOnline($userSheet) { + $from_time = strtotime($userSheet['lastSeen']); + $to_time = strtotime(context::getCurrentTime()); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince > 5) { + return ''; + }else{ + return ''; + } + } + + public static function humanTiming ($time) { + $time = time()-$time; + $time = 86400-$time; + $time = ($time<1)? 1 : $time; + $tokens = array ( + 31536000 => 'year', + 2592000 => 'month', + 604800 => 'week', + 86400 => 'day', + 3600 => 'hour', + 60 => 'minute', + 1 => 'second' + ); + foreach ($tokens as $unit => $text) { + if ($time < $unit) continue; + $numberOfUnits = floor($time / $unit); + return $numberOfUnits.' '.$text.(($numberOfUnits>1)?'s':''); + } + } + + public static function humanTimingSince($time) + { + + $time = time() - $time; // to get the time since that moment + $time = ($time<1)? 1 : $time; + $tokens = array ( + 31536000 => 'year', + 2592000 => 'month', + 604800 => 'week', + 86400 => 'day', + 3600 => 'hour', + 60 => 'minute', + 1 => 'second' + ); + + foreach ($tokens as $unit => $text) { + if ($time < $unit) continue; + $numberOfUnits = floor($time / $unit); + return $numberOfUnits.' '.$text.(($numberOfUnits>1)?'s':''); + } + + } + + public static function getItemThumbnail($type, $id, $datafile, $fileHash) { + if ($type == "hats") return 'https://api.xdiscuss.net/imageServer/hats/'.$datafile.'.png'; + if ($type == "heads") return 'https://api.xdiscuss.net/imageServer/heads/'.$datafile.'.png'; + if ($type == "faces") return '/data/assets/faces/thumbnail/'.$datafile.'.png'; + if ($type == "gear") return 'https://api.xdiscuss.net/imageServer/gear/'.$datafile.'.png'; + if ($type == "decals") return "/data/assets/uploads/".$fileHash; + if ($type == "tshirts") return 'https://api.xdiscuss.net/imageServer/tshirts/'.$id.'.png'; + if ($type == "pants") return 'https://api.xdiscuss.net/imageServer/pants/'.$id.'.png'; + if ($type == "shirts") return 'https://api.xdiscuss.net/imageServer/shirts/'.$id.'.png'; + } + + public static function getItemThumbnailC($type, $id, $datafile, $fileHash, $time) { + if ($type == "hats") return 'https://api.xdiscuss.net/imageServer/hats/'.$datafile.'.png?tick='.strtotime($time).'hat'; + if ($type == "heads") return 'https://api.xdiscuss.net/imageServer/heads/'.$datafile.'.png?tick='.strtotime($time); + if ($type == "faces") return '/data/assets/faces/thumbnail/'.$datafile.'.png?tick='.strtotime($time); + if ($type == "gear") return 'https://api.xdiscuss.net/imageServer/gear/'.$datafile.'.png?tick='.strtotime($time); + if ($type == "decals") return "/data/assets/uploads/".$fileHash; + if ($type == "tshirts") return 'https://api.xdiscuss.net/imageServer/tshirts/'.$id.'.png?tick='.strtotime($time); + if ($type == "pants") return 'https://api.xdiscuss.net/imageServer/pants/'.$id.'.png?tick='.strtotime($time); + if ($type == "shirts") return 'https://api.xdiscuss.net/imageServer/shirts/'.$id.'.png?tick='.strtotime($time); + } + + public static function requestImage($ID, $type) { + $query = "INSERT INTO renders (`render_id`, `type`) VALUES (:ID, :type);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':ID', $ID, PDO::PARAM_INT); + $stmt->bindParam(':type', $type, PDO::PARAM_STR); + $stmt->execute(); + } + + public static function checkTopPoster($userID) { + $query = "SELECT id, posts FROM users ORDER BY posts DESC LIMIT 15"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->execute(); + foreach ($stmt as $result) { + if ($userID == $result['id']) { + echo '

Top 15 Poster

'; + } + } + } + + public static function buildFriendButton($userID) { + if ($GLOBALS['loggedIn'] == true) { + echo ''; + $query = "SELECT * FROM `friends` WHERE `userId1` = :id AND `userId2` = :sid"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':sid', $userID, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + $friend = true; + }else{ + $friend = false; + } + + $query = "SELECT * FROM `friendRequests` WHERE `senduid` = :id AND `recvuid` = :sid"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':sid', $userID, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + $requestSent = true; + }else{ + $requestSent = false; + } + + $query = "SELECT * FROM `friendRequests` WHERE `senduid` = :id AND `recvuid` = :sid"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $userID, PDO::PARAM_INT); + $stmt->bindParam(':sid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + $requestSenta = true; + }else{ + $requestSenta = false; + } + + if ($friend == false) { + if ($requestSent == true or $requestSenta == true) { + echo ' Pending'; + }else{ + echo ' Add'; + } + }else{ + echo ' Remove'; + } + } + } + + public static function showBBcodes($text) { + // BBcode array + $find = array( + '~\[b\](.*?)\[/b\]~s', + '~\[i\](.*?)\[/i\]~s', + '~\[u\](.*?)\[/u\]~s', + '~\[quote\](.*?)\[/quote\]~s', + '~\[red\](.*?)\[/red\]~s', + '~\[blue\](.*?)\[/blue\]~s', + '~\[s\](.*?)\[/s\]~s', + '~\[code\](.*?)\[/code\]~s' + ); + // HTML tags to replace BBcode + $replace = array( + '$1', + '$1', + '$1', + '
$1',
+				'$1',
+				'$1',
+				'$1',
+				'$1'
+			);
+			// Replacing the BBcodes with corresponding HTML tags
+			return preg_replace($find,$replace,$text);
+		}
+		
+		public static function getImageRequestCount() {
+			$query = "SELECT id FROM `renders`;";
+			$stmt = $GLOBALS['dbcon']->prepare($query);
+			$stmt->execute();
+			return $stmt->rowCount();
+		}
+		
+		public static function getUserCount() {
+			$query = "SELECT COUNT(*) FROM users;";
+			$stmt = $GLOBALS['dbcon']->prepare($query);
+			$stmt->execute();
+			$result = $stmt->fetchColumn(0);
+			return $result;
+		}
+		
+		public static function getRouterCount() {
+			$query = "SELECT id FROM `serverRequests`;";
+			$stmt = $GLOBALS['dbcon']->prepare($query);
+			$stmt->execute();
+			return $stmt->rowCount();
+		}
+		
+		public static function sendDiscordMessage($message) {
+			$url = "https://discordapp.com/api/webhooks/x/x";
+			$dataArray = array('content' => $message, 
+			'username' => "Graphictoria");
+			
+			$httpOptions = array(
+				'http' => array (
+					'header' => "Graphictoria-Server",
+					'content-type' => 'multipart/form-data',
+					'method' => "POST",
+					'content' => http_build_query($dataArray)
+				)
+			);
+			
+			$context = stream_context_create($httpOptions);
+			$result = @file_get_contents($url, false, $context);
+		}
+		
+		public static function parseEmoticon($content) {
+			$content = str_replace(":afro:",'', $content);
+			$content = str_replace(":afro-1:",'', $content);
+			$content = str_replace(":agent:",'', $content);
+			$content = str_replace(":alien:",'', $content);
+			$content = str_replace(":alien-1:",'', $content);
+			$content = str_replace(":angel:",'', $content);
+			$content = str_replace(":angry:",'', $content);
+			$content = str_replace(":angry-1:",'', $content);
+			$content = str_replace(":angry-2:",'', $content);
+			$content = str_replace(":angry-3:",'', $content);
+			$content = str_replace(":angry-4:",'', $content);
+			$content = str_replace(":angry-5:",'', $content);
+			$content = str_replace(":arguing:",'', $content);
+			$content = str_replace(":arrogant:",'', $content);
+			$content = str_replace(":asian:",'', $content);
+			$content = str_replace(":asian-1:",'', $content);
+			$content = str_replace(":avatar:",'', $content);
+			$content = str_replace(":skeleton:",'', $content);
+			$content = str_replace(":superhero:",'', $content);
+			$content = str_replace(":vampire:",'', $content);
+			$content = str_replace(":zombie:",'', $content);
+			
+			return $content;
+		}
+	}
+?>
diff --git a/core/func/html/main.php b/core/func/html/main.php
new file mode 100644
index 0000000..cbbb395
--- /dev/null
+++ b/core/func/html/main.php
@@ -0,0 +1,57 @@
+
+				
+				
+					
+				';
+			}elseif ($rand == 1) {
+				echo '
+ + + +
'; + } + } + + public static function buildMatched() { + echo '
+ +
'; + } + } +?> diff --git a/core/func/html/views/footer.php b/core/func/html/views/footer.php new file mode 100644 index 0000000..7c5e05f --- /dev/null +++ b/core/func/html/views/footer.php @@ -0,0 +1,19 @@ + +
+'; + }else{ + echo '
'; + } +?> +
Graphictoria
+

All rights belong to their respective owners

+ Privacy | Terms | DMCA | Renders: | Router Requests : +
\ No newline at end of file diff --git a/core/func/html/views/head.php b/core/func/html/views/head.php new file mode 100644 index 0000000..437dec7 --- /dev/null +++ b/core/func/html/views/head.php @@ -0,0 +1,26 @@ + + + + + + + + + + + + + +'; + if ($GLOBALS['loggedIn'] && $GLOBALS['userTable']['themeChoice'] == 0) echo ''; + + if (!$GLOBALS['loggedIn']) echo ''; +?> \ No newline at end of file diff --git a/core/func/html/views/navigation.php b/core/func/html/views/navigation.php new file mode 100644 index 0000000..ae96f04 --- /dev/null +++ b/core/func/html/views/navigation.php @@ -0,0 +1,190 @@ + + + +'; + echo '
Graphictoria is under maintenance
'; + }else{ + echo '
'; + } +?> + + + + + + + +
+
Chat
+
+
+ +
+
+
+ \ No newline at end of file diff --git a/core/func/html/views/navigation/loginPanel.php b/core/func/html/views/navigation/loginPanel.php new file mode 100644 index 0000000..3fcae72 --- /dev/null +++ b/core/func/html/views/navigation/loginPanel.php @@ -0,0 +1,10 @@ + +
  • + + +
  • +
  • + + +

    Fill in the fields to login

    +
  • \ No newline at end of file diff --git a/core/func/html/views/navigation/rightNavigation.php b/core/func/html/views/navigation/rightNavigation.php new file mode 100644 index 0000000..9820fa7 --- /dev/null +++ b/core/func/html/views/navigation/rightNavigation.php @@ -0,0 +1,47 @@ + +
  • +
  • +prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $numRequests = $stmt->rowCount(); + + if ($numRequests == 0) { + echo '
  • '; + }else{ + echo '
  • '.$numRequests.'
  • '; + } + + $query = "SELECT id FROM `messages` WHERE `recv_uid` = :id AND `read` = 0"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + $numMessages = $stmt->rowCount(); + + if ($numMessages == 0) { + echo '
  • '; + }else{ + echo '
  • '.$numMessages.'
  • '; + } +?> +
  • + \ No newline at end of file diff --git a/core/func/includes.php b/core/func/includes.php new file mode 100644 index 0000000..a7c918d --- /dev/null +++ b/core/func/includes.php @@ -0,0 +1,20 @@ + \ No newline at end of file diff --git a/core/func/js/account/suspended.js b/core/func/js/account/suspended.js new file mode 100644 index 0000000..8f33ddf --- /dev/null +++ b/core/func/js/account/suspended.js @@ -0,0 +1,24 @@ +$(document).ready(function() { + $("#liftBan").click(function() { + if ($("#liftBan").is(":disabled") == false) { + $("#liftBan").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/account/liftBan.php', { + csrf: csrf_token + }) + .done(function(response) { + $("#liftBan").prop("disabled", false); + if (response == "error") { + $("#sStatus").html("
    Network error. Try again later.
    "); + }else if (response == "ban-lift-error") { + $("#sStatus").html("
    Your ban has not been expired yet.
    "); + }else{ + window.location = "/"; + } + }) + .fail(function() { + $("#sStatus").html("
    Network error. Try again later.
    "); + }); + } + }) +}); \ No newline at end of file diff --git a/core/func/js/addServer.js b/core/func/js/addServer.js new file mode 100644 index 0000000..8ef83d0 --- /dev/null +++ b/core/func/js/addServer.js @@ -0,0 +1,167 @@ +$(document).ready(function() { + $(document).on('change', '#serverType', function() { + $("#addServer02").prop("disabled", false); + $("#serverName").prop("disabled", false); + $("#serverDescription").prop("disabled", false); + $("#placeFile").prop("disabled", false); + $("#addServer01").prop("disabled", false); + $("#serverName").prop("disabled", false); + $("#serverDescription").prop("disabled", false); + $("#serverIP").prop("disabled", false); + $("#serverPort").prop("disabled", false); + $("#privacyType").prop("disabled", false); + + if ($(this).find("option:selected").attr('value') == 0) { + $("#selfHostOptions").css("display", "block"); + $("#dedicatedOptions").css("display", "none"); + }else{ + $("#selfHostOptions").css("display", "none"); + $("#dedicatedOptions").css("display", "block"); + } + }) + $("#addServer01").click(function() { + if ($("#addServer01").is(":disabled") == false) { + $("#addServer01").prop("disabled", true); + $("#serverName").prop("disabled", true); + $("#serverDescription").prop("disabled", true); + $("#serverIP").prop("disabled", true); + $("#serverPort").prop("disabled", true); + $("#privacyType").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + var serverName = $("#serverName").val(); + var serverDescription = $("#serverDescription").val(); + var serverIP = $("#serverIP").val(); + var serverPort = $("#serverPort").val(); + var privacyType = $("#privacyType").val(); + var gameVersion = $("#versionType").val(); + $.post('/core/func/api/games/post/addServer.php', { + csrf: csrf_token, + serverName: serverName, + serverDescription: serverDescription, + serverIP: serverIP, + serverPort: serverPort, + privacyType: privacyType, + gameVersion: gameVersion + }) + .done(function(response) { + $("#addServer01").prop("disabled", false); + $("#serverName").prop("disabled", false); + $("#serverDescription").prop("disabled", false); + $("#serverIP").prop("disabled", false); + $("#serverPort").prop("disabled", false); + $("#privacyType").prop("disabled", false); + + if (response == "error") { + $("#aStatus").html("
    Could not add the server because a network error has occurred.
    "); + }else if (response == "server-name-too-long") { + $("#aStatus").html("
    Your server name is too long.
    "); + }else if (response == "server-name-too-short") { + $("#aStatus").html("
    Your server name is too short.
    "); + }else if (response == "server-description-too-long") { + $("#aStatus").html("
    Your server description is too long.
    "); + }else if (response == "server-ip-too-short") { + $("#aStatus").html("
    Your server IP is too short.
    "); + }else if (response == "server-ip-too-long") { + $("#aStatus").html("
    Your server IP is too long.
    "); + }else if (response == "server-port-too-short") { + $("#aStatus").html("
    Your server port is too short.
    "); + }else if (response == "server-port-too-long") { + $("#aStatus").html("
    Your server port is too long.
    "); + }else if (response == "invalid-port") { + $("#aStatus").html("
    Your server port is invalid.
    "); + }else if (response == "invalid-ip") { + $("#aStatus").html("
    Your server IP is invalid.
    "); + }else if (response == "invalid-privacy") { + $("#aStatus").html("
    An error has occurred.
    "); + }else if (response == "invalid-version") { + $("#aStatus").html("
    Invalid server version received.
    "); + }else{ + window.location = "/games/view/"+response; + } + }) + .fail(function() { + $("#aStatus").html("
    Could not add the server because a network error has occurred.
    "); + }); + } + }) + + $(document).on('change', '#placeFile', function() { + $(".place").css("filter", "grayscale(100%)"); + }); + + $("#placeFile").click(function() { + $(".place").css("box-shadow", "none"); + }); + + $(".place").click(function() { + if ($('#placeFile')[0].files[0] == undefined) + $(this).css("box-shadow", "0 0 0 1px #75caeb"); + }); + + $("#addServer02").click(function() { + if ($("#addServer02").is(":disabled") == false) { + $("#addServer02").prop("disabled", true); + $("#serverName").prop("disabled", true); + $("#serverDescription").prop("disabled", true); + $("#placeFile").prop("disabled", true); + $("#versionTypeDedi").prop("disabled", true); + $("#privacyTypeDedi").prop("disabled", true); + + var genPlace = 0; + if ($("#place0").css("box-shadow") != "none") genPlace = 1; + + var formData = new FormData(); + formData.append('placeFile', $('#placeFile')[0].files[0]); + formData.append('serverName', $("#serverName").val()); + formData.append('serverDescription', $("#serverDescription").val()); + formData.append('versionType', $("#versionTypeDedi").val()); + formData.append('privacyType', $("#privacyTypeDedi").val()); + formData.append('csrf_token', $('meta[name="csrf-token"]').attr('content')); + formData.append('genPlace', genPlace); + $.ajax({ + type: "POST", + url : "/core/func/api/games/post/addServerDedicated.php", + data : formData, + cache: false, + contentType: false, + processData: false, + success: function(data) { + $("#addServer02").prop("disabled", false); + $("#serverName").prop("disabled", false); + $("#serverDescription").prop("disabled", false); + $("#placeFile").prop("disabled", false); + $("#versionTypeDedi").prop("disabled", false); + $("#privacyTypeDedi").prop("disabled", false); + if (data == "server-name-too-long") { + $("#aStatus").html("
    Server name is too long
    "); + }else if (data == "server-name-too-short") { + $("#aStatus").html("
    Server name is too short
    "); + }else if (data == "server-description-too-long") { + $("#aStatus").html("
    Server description is too long
    "); + }else if (data == "invalid-placefile") { + $("#aStatus").html("
    Invalid place file.
    "); + }else if (data == "rate-limit") { + $("#aStatus").html("
    You can only add a server each 5 minutes.
    "); + }else if (data == "invalid-privacy") { + $("#aStatus").html("
    Invalid privacy type received
    "); + }else if (data == "success") { + $("#aStatus").html("
    Your dedicated server will be up and running shortly.
    "); + $(".profileCard").html("

    Loading

    Please wait as we load your server

    "); + setTimeout(function(){ + $(".profileCardContainer").load("/core/func/api/games/getLatestServer.php"); + $(".profileCardContainerHead").append("

    Your server has been created

    "); + $(".profileCard").remove(); + $(".alert").remove(); + }, 10000); + }else if (data == "error") { + $("#aStatus").html("
    Please select a place
    "); + }else{ + $("#aStatus").html("
    Could not add the server because a network error has occurred.
    "); + } + },error: function() { + $("#aStatus").html("
    Could not add the server because a network error has occurred.
    "); + } + }); + } + }) +}) \ No newline at end of file diff --git a/core/func/js/admin/assetApproval.js b/core/func/js/admin/assetApproval.js new file mode 100644 index 0000000..b65373b --- /dev/null +++ b/core/func/js/admin/assetApproval.js @@ -0,0 +1,46 @@ +$(document).ready(function() { + console.log("Asset approval ready!"); + $("#assetContainer").load("/core/func/api/admin/get/getAssets.php"); +}); + +function approveAsset(itemID) { + $(".btn-success").prop("disabled", true); + $(".btn-danger").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/admin/post/approveAsset.php', { + csrf: csrf_token, + itemID: itemID, + }) + .done(function(response) { + console.log(response); + if (response == "success") { + $("#assetContainer").load("/core/func/api/admin/get/getAssets.php"); + }else{ + alert("Could not approve this asset because an error occurred." + response); + } + }) + .fail(function() { + alert("An error occurred while reaching the Graphictoria servers. Please contact a developer."); + }); +} + +function denyAsset(itemID) { + $(".btn-success").prop("disabled", true); + $(".btn-danger").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/admin/post/denyAsset.php', { + csrf: csrf_token, + itemID: itemID, + }) + .done(function(response) { + console.log(response); + if (response == "success") { + $("#assetContainer").load("/core/func/api/admin/get/getAssets.php"); + }else{ + alert("Could not deny this asset because an error occurred." + response); + } + }) + .fail(function() { + alert("An error occurred while reaching the Graphictoria servers. Please contact a developer."); + }); +} \ No newline at end of file diff --git a/core/func/js/admin/banUser.js b/core/func/js/admin/banUser.js new file mode 100644 index 0000000..69f3e4e --- /dev/null +++ b/core/func/js/admin/banUser.js @@ -0,0 +1,48 @@ +$(document).ready(function() { + $("#banUser").click(function() { + if ($("#banUser").is(":disabled") == false) { + $("#banUser").prop("disabled", true); + $("#username").prop("disabled", true); + $("#banReason").prop("disabled", true); + $("#duration").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + var username = $("#username").val(); + var banReason = $("#banReason").val(); + var duration = $("#duration").val(); + $.post('/core/func/api/admin/post/banUser.php', { + csrf: csrf_token, + username: username, + banReason: banReason, + duration: duration + }) + .done(function(response) { + $("#banUser").prop("disabled", false); + $("#username").prop("disabled", false); + $("#banReason").prop("disabled", false); + $("#duration").prop("disabled", false); + if (response == "error") { + $("#bStatus").html("
    Could not ban this user because a network error occurred.
    "); + }else if (response == "missing-info") { + $("#bStatus").html("
    You must fill in all fields to ban this user.
    "); + }else if (response == "invalid-duration") { + $("#bStatus").html("
    Invalid duration.
    "); + }else if (response == "can-not-ban-yourself") { + $("#bStatus").html("
    You can not ban yourself.
    "); + }else if (response == "reason-too-long") { + $("#bStatus").html("
    The ban reason is too long.
    "); + }else if (response == "no-user") { + $("#bStatus").html("
    The user has not been found.
    "); + }else if (response == "can-not-ban-user") { + $("#bStatus").html("
    We could not ban this user.
    "); + }else if (response == "user-already-banned") { + $("#bStatus").html("
    This user has already been banned. If you wish to unban, use the unban utility.
    "); + }else if (response == "success") { + $("#bStatus").html("
    This user has been banned.
    "); + } + }) + .fail(function() { + $("#bStatus").html("
    Could not ban this user because a network error occurred.
    "); + }); + } + }) +}) \ No newline at end of file diff --git a/core/func/js/admin/prunePosts.js b/core/func/js/admin/prunePosts.js new file mode 100644 index 0000000..6eaea54 --- /dev/null +++ b/core/func/js/admin/prunePosts.js @@ -0,0 +1,34 @@ +$(document).ready(function() { + $("#prunePosts").click(function() { + if ($("#prunePosts").is(":disabled") == false) { + $("#prunePosts").prop("disabled", true); + $("#username").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + var username = $("#username").val(); + $.post('/core/func/api/admin/post/prunePosts.php', { + csrf: csrf_token, + username: username + }) + .done(function(response) { + $("#prunePosts").prop("disabled", false); + $("#username").prop("disabled", false); + if (response == "missing-info") { + $("#bStatus").html("
    We are missing information from you. Please check again.
    "); + }else if (response == "can-not-prune-yourself") { + $("#bStatus").html("
    You can not prune your own posts.
    "); + }else if (response == "no-user") { + $("#bStatus").html("
    The user you are trying to prune does not exist.
    "); + }else if (response == "can-not-prune-user") { + $("#bStatus").html("
    You can not prune this user.
    "); + }else if (response == "error") { + $("#bStatus").html("
    Could not prune posts from this user because a network error occurred.
    "); + }else if (response == "success") { + $("#bStatus").html("
    Posts pruned.
    "); + } + }) + .fail(function() { + $("#bStatus").html("
    Could not prune posts from this user because a network error occurred.
    "); + }); + } + }) +}) \ No newline at end of file diff --git a/core/func/js/admin/rPostie.js b/core/func/js/admin/rPostie.js new file mode 100644 index 0000000..162060e --- /dev/null +++ b/core/func/js/admin/rPostie.js @@ -0,0 +1,35 @@ +$(document).ready(function() { + $("#rewardPostie").click(function() { + if ($("#rewardPostie").is(":disabled") == false) { + $("#rewardPostie").prop("disabled", true); + $("#username").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + var username = $("#username").val(); + $.post('/core/func/api/admin/post/rewardPostie.php', { + csrf: csrf_token, + username: username + }) + .done(function(response) { + console.log(response) + $("#rewardPostie").prop("disabled", false); + $("#username").prop("disabled", false); + if (response == "error") { + $("#bStatus").html("
    Could reward this user because a network error occurred.
    "); + }else if (response == "missing-info") { + $("#bStatus").html("
    We are missing information from you. Please check and try again.
    "); + }else if (response == "can-not-reward-yourself") { + $("#bStatus").html("
    You can not reward yourself!
    "); + }else if (response == "no-user") { + $("#bStatus").html("
    This user has not been found.
    "); + }else if (response == "can-not-reward-user") { + $("#bStatus").html("
    This user has already been rewarded recently. Try again later
    "); + }else if (response == "success") { + $("#bStatus").html("
    This user has recieved 10 posties!
    "); + } + }) + .fail(function() { + $("#bStatus").html("
    Could reward this user because a network error occurred.
    "); + }); + } + }) +}) \ No newline at end of file diff --git a/core/func/js/admin/uhat.js b/core/func/js/admin/uhat.js new file mode 100644 index 0000000..9aa0556 --- /dev/null +++ b/core/func/js/admin/uhat.js @@ -0,0 +1,78 @@ +$(document).ready(function() { + $("#doUpload").click(function() { + if ($("#doUpload").is(":disabled") == false) { + $("#doUpload").prop("disabled", true); + $("#meshFile").prop("disabled", true); + $("#textureFile").prop("disabled", true); + $("#xmlContent").prop("disabled", true); + $("#isBuyable").prop("disabled", true); + $("#hatPrice").prop("disabled", true); + $("#isRBX").prop("disabled", true); + $("#hatName").prop("disabled", true); + $("#hatDescription").prop("disabled", true); + $("#datafileName").prop("disabled", true); + var formData = new FormData(); + formData.append('meshFile', $('#meshFile')[0].files[0]); + formData.append('textureFile', $('#textureFile')[0].files[0]); + formData.append('hatName', $("#hatName").val()); + formData.append('hatDescription', $("#hatDescription").val()); + formData.append('hatPrice', $("#hatPrice").val()); + formData.append('datafileName', $("#datafileName").val()); + formData.append('isBuyable', $('#isBuyable').prop('checked')); + formData.append('RBXAsset', $('#isRBX').prop('checked')); + formData.append('xmlContent', $("#xmlContent").val()); + formData.append('csrf_token', $('meta[name="csrf-token"]').attr('content')); + $.ajax({ + type: "POST", + url : "/core/func/api/admin/post/newHat.php", + data : formData, + cache: false, + contentType: false, + processData: false, + success: function(response) { + console.log(response); + $("#doUpload").prop("disabled", false); + $("#meshFile").prop("disabled", false); + $("#textureFile").prop("disabled", false); + $("#xmlContent").prop("disabled", false); + $("#isBuyable").prop("disabled", false); + $("#isRBX").prop("disabled", false); + $("#hatPrice").prop("disabled", false); + $("#hatName").prop("disabled", false); + $("#hatDescription").prop("disabled", false); + $("#datafileName").prop("disabled", false); + if (response == "success") { + $("#cStatus").html("
    Hat uploaded!
    "); + }else if (response == "error") { + $("#cStatus").html("
    Could not upload this hat because a network error occurred. Attempt again later.
    "); + }else if (response == "missing-info" || response == "no-file") { + $("#cStatus").html("
    We are missing information from you. Please check again.
    "); + }else if (response == "name-too-long") { + $("#cStatus").html("
    Your hat name is too long.
    "); + }else if (response == "datafilename-too-long") { + $("#cStatus").html("
    Your datafile name is too long.
    "); + }else if (response == "description-too-long") { + $("#cStatus").html("
    Your description is too long.
    "); + }else if (response == "illegal-buyable") { + $("#cStatus").html("
    Illegal alter detected.
    "); + }else if (response == "price-too-low") { + $("#cStatus").html("
    Price is too low. Min: 1 coin
    "); + }else if (response == "datafile-mesh-already-exists") { + $("#cStatus").html("
    This datafile name already exists. Please try another one.
    "); + }else if (response == "meshfile-illegalFileType") { + $("#cStatus").html("
    Your mesh file type is incorrect.
    "); + }else if (response == "file-upload-error") { + $("#cStatus").html("
    File upload failed. Please notify an administrator.
    "); + }else if (response == "texture-illegalFileType") { + $("#cStatus").html("
    Your texture file type is incorrect.
    "); + }else{ + $("#cStatus").html("
    Could not upload this hat because a network error occurred. Attempt again later.
    "); + } + }, + error: function() { + $("#cStatus").html("
    Could not upload this hat because a network error occurred. Attempt again later.
    "); + } + }); + } + }) +}); \ No newline at end of file diff --git a/core/func/js/admin/unbanUser.js b/core/func/js/admin/unbanUser.js new file mode 100644 index 0000000..fff356c --- /dev/null +++ b/core/func/js/admin/unbanUser.js @@ -0,0 +1,36 @@ +$(document).ready(function() { + $("#unbanUser").click(function() { + if ($("#unbanUser").is(":disabled") == false) { + $("#unbanUser").prop("disabled", true); + $("#username").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + var username = $("#username").val(); + $.post('/core/func/api/admin/post/unbanUser.php', { + csrf: csrf_token, + username: username + }) + .done(function(response) { + $("#unbanUser").prop("disabled", false); + $("#username").prop("disabled", false); + if (response == "error") { + $("#bStatus").html("
    Could not unban this user because a network error occurred.
    "); + }else if (response == "missing-info") { + $("#bStatus").html("
    We are missing information from you. Please check and try again.
    "); + }else if (response == "can-not-unban-yourself") { + $("#bStatus").html("
    You can not unban yourself!
    "); + }else if (response == "no-user") { + $("#bStatus").html("
    This user has not been found.
    "); + }else if (response == "can-not-unban-user") { + $("#bStatus").html("
    You can not unban this user.
    "); + }else if (response == "user-not-banned") { + $("#bStatus").html("
    You can not unban this user because this user is not banned.
    "); + }else if (response == "success") { + $("#bStatus").html("
    This user has been unbanned!
    "); + } + }) + .fail(function() { + $("#bStatus").html("
    Could not unban this user because a network error occurred.
    "); + }); + } + }) +}) \ No newline at end of file diff --git a/core/func/js/auth/login.js b/core/func/js/auth/login.js new file mode 100644 index 0000000..d4e3338 --- /dev/null +++ b/core/func/js/auth/login.js @@ -0,0 +1,86 @@ +$(document).ready(function() { + $("#lSubmit").click(function() { + if ($("#lSubmit").is(":disabled") == false) { + $("#lSubmit").prop("disabled", true); + $("#lForgot").prop("disabled", true); + $("#lUsername").prop("disabled", true); + $("#lPassword").prop("disabled", true); + + var user = $("#lUsername").val(); + var passwd = $("#lPassword").val(); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/auth/login.php', { + username: user, + passwd: passwd, + csrf: csrf_token + }) + .done(function(response) { + $("#lSubmit").prop("disabled", false); + $("#lForgot").prop("disabled", false); + $("#lUsername").prop("disabled", false); + $("#lPassword").prop("disabled", false); + if (response == "error") { + $("#lStatus").css("color", "red").html("Network error. Try again later."); + }else if (response == "missing-info") { + $("#lStatus").css("color", "red").html("Please fill in all fields."); + }else if (response == "no-user") { + $("#lStatus").css("color", "red").html("No user found with this name."); + }else if (response == "success") { + window.location.reload(); + }else if (response == "incorrect-password") { + $("#lStatus").css("color", "red").html("Incorrect password specified."); + }else if (response == "rate-limit") { + $("#lStatus").css("color", "red").html("Please wait a bit..."); + } + }) + .fail(function() { + $("#lStatus").css("color", "red").html("Network error. Try again later."); + }); + } + }); + + // Toggle on enter + $("#lUsername").keyup(function(event) { + if(event.keyCode == 13) { + $("#lSubmit").click(); + } + }) + + $("#lPassword").keyup(function(event) { + if(event.keyCode == 13) { + $("#lSubmit").click(); + } + }) + + $("#lForgot").click(function() { + if ($("#lForgot").is(":disabled") == false) { + $("#lSubmit").prop("disabled", true); + $("#lForgot").prop("disabled", true); + $("#lUsername").prop("disabled", true); + $("#lPassword").prop("disabled", true); + var user = $("#lUsername").val(); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/auth/forgot.php', { + username: user, + csrf: csrf_token + }) + .done(function(response) { + $("#lSubmit").prop("disabled", false); + $("#lForgot").prop("disabled", false); + $("#lUsername").prop("disabled", false); + $("#lPassword").prop("disabled", false); + console.log(response); + if (response == "no-user") { + $("#lStatus").css("color", "red").html("User not found"); + }else if (response == "rate-limit") { + $("#lStatus").css("color", "red").html("Please wait"); + }else if (response == "success") { + $("#lStatus").css("color", "green").html("E-Mail sent!"); + } + }) + .fail(function() { + $("#lStatus").css("color", "red").html("Reset password request failed."); + }); + } + }) +}); \ No newline at end of file diff --git a/core/func/js/auth/register.js b/core/func/js/auth/register.js new file mode 100644 index 0000000..9c79e56 --- /dev/null +++ b/core/func/js/auth/register.js @@ -0,0 +1,84 @@ +$(document).ready(function() { + $("#rSubmit").click(function() { + if ($("#rSubmit").is(":disabled") == false) { + $("#rUsername").prop("disabled", true); + $("#rEmail").prop("disabled", true); + $("#rPassword1").prop("disabled", true); + $("#rPassword2").prop("disabled", true); + $("#rSubmit").prop("disabled", true); + + var formData = new FormData(); + formData.append('username', $("#rUsername").val()); + formData.append('email', $("#rEmail").val()); + formData.append('passwd1', $("#rPassword1").val()); + formData.append('passwd2', $("#rPassword2").val()); + formData.append('captcha', $("#g-recaptcha-response").val()); + formData.append('csrf', $('meta[name="csrf-token"]').attr('content')); + + $.ajax({ + type: "POST", + url : "/core/func/api/auth/register.php", + data : formData, + cache: false, + contentType: false, + processData: false, + success: function(data) { + $("#rUsername").prop("disabled", false); + $("#rEmail").prop("disabled", false); + $("#rPassword1").prop("disabled", false); + $("#rPassword2").prop("disabled", false); + $("#rSubmit").prop("disabled", false); + if (data != "success") { + grecaptcha.reset(); + } + if (data == "error") { + $("#rStatus").html("
    Unexpected network error. Try again later.
    "); + }else if (data == "invalid-username") { + $("#rStatus").html("
    Your username is invalid. Please try something else.
    "); + }else if (data == "illegal-username") { + $("#rStatus").html("
    Your username contains illegal characters.
    "); + }else if (data == "username-too-long") { + $("#rStatus").html("
    Your username is too long.
    "); + }else if (data == "username-too-short") { + $("#rStatus").html("
    Your username is too short.
    "); + }else if (data == "no-username") { + $("#rStatus").html("
    Please enter a username.
    "); + }else if (data == "no-email") { + $("#rStatus").html("
    Please enter an E-Mail.
    "); + }else if (data == "no-email") { + $("#rStatus").html("
    Please enter an E-Mail.
    "); + }else if (data == "email-too-long") { + $("#rStatus").html("
    Your E-Mail is too long.
    "); + }else if (data == "illegal-email") { + $("#rStatus").html("
    Invalid E-Mail has been specified.
    "); + }else if (data == "no-password") { + $("#rStatus").html("
    Please fill in both password fields.
    "); + }else if (data == "passwords-mismatch") { + $("#rStatus").html("
    Your password and password confirmation do not match.
    "); + }else if (data == "password-too-short") { + $("#rStatus").html("
    Your password is too short.
    "); + }else if (data == "password-too-long") { + $("#rStatus").html("
    Your password is too long.
    "); + }else if (data == "email-already-used") { + $("#rStatus").html("
    The E-Mail you have entered is already being used.
    "); + }else if (data == "username-already-used") { + $("#rStatus").html("
    The username you have entered is already being used.
    "); + }else if (data == "success") { + $("#rStatus").html("
    Your account has been created!
    "); + }else if (data == "incorrect-captcha") { + $("#rStatus").html("
    Either you did not do the captcha or the captcha is incorrect.
    "); + }else if (data == "missing-info") { + $("#rStatus").html("
    Please finish the registration form.
    "); + }else if (data == "rate-limit") { + $("#rStatus").html("
    You have recently made an account. Please wait before making a new one.
    "); + }else if (data == "unknown-email") { + $("#rStatus").html("
    The email you have entered is unknown. Please use known email providers such as gmail or outlook
    "); + } + }, + error: function() { + $("#rStatus").html("
    Unexpected network error. Try again later.
    "); + } + }); + } + }) +}); \ No newline at end of file diff --git a/core/func/js/auth/resetPassword.js b/core/func/js/auth/resetPassword.js new file mode 100644 index 0000000..41fb01c --- /dev/null +++ b/core/func/js/auth/resetPassword.js @@ -0,0 +1,40 @@ +function resetPassword(key, userID) { + if ($("#changePassword").is(":disabled") == false) { + $("#changePassword").prop("changePassword", true); + $("#password1").prop("disabled", true); + $("#password2").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + var password1 = $("#password1").val(); + var password2 = $("#password2").val(); + $.post('/core/func/api/auth/resetPassword.php', { + password1: password1, + password2: password2, + key: key, + userID, userID, + csrf: csrf_token + }) + .done(function(response) { + $("#changePassword").prop("changePassword", false); + $("#password1").prop("disabled", false); + $("#password2").prop("disabled", false); + if (response == "error") { + $("#rStatus").html("
    Network error. Try again later.
    "); + }else if (response == "invalid-key") { + $("#rStatus").html("
    The key specified is invalid.
    "); + }else if (response == "key-expired") { + $("#rStatus").html("
    Your key has expired. Please request a new password reset.
    "); + }else if (response == "password-mismatch") { + $("#rStatus").html("
    The passwords you have specified do not match.
    "); + }else if (response == "password-too-long") { + $("#rStatus").html("
    Your new password is too long.
    "); + }else if (response == "password-too-short") { + $("#rStatus").html("
    Your new password is too short.
    "); + }else if (response == "success") { + window.location = "/"; + } + }) + .fail(function() { + $("#rStatus").html("
    Network error. Try again later.
    "); + }); + } +} \ No newline at end of file diff --git a/core/func/js/auth/twostep.js b/core/func/js/auth/twostep.js new file mode 100644 index 0000000..30f8b9e --- /dev/null +++ b/core/func/js/auth/twostep.js @@ -0,0 +1,37 @@ +$(document).ready(function() { + $("#finishAuth").click(function() { + if ($("#finishAuth").is(":disabled") == false) { + $("#finishAuth").prop("disabled", true); + $("#factorCode").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + var twoStepCode = $("#factorCode").val(); + $.post('/core/func/api/auth/twostep.php', { + factorCode: twoStepCode, + csrf: csrf_token + }) + .done(function(response) { + $("#finishAuth").prop("disabled", false); + $("#factorCode").prop("disabled", false); + if (response == "success") { + window.location = "/"; + }else if (response == "wrong-code") { + $("#tStatus").html("
    You have entered an incorrect code.
    "); + }else if (response == "missing-info") { + $("#tStatus").html("
    Please enter a code.
    "); + }else{ + $("#tStatus").html("
    Network error. Try again later.
    "); + } + }) + .fail(function() { + $("#tStatus").html("
    Network error. Try again later.
    "); + }); + } + }) + + // Toggle on enter + $("#factorCode").keyup(function(event) { + if(event.keyCode == 13) { + $("#finishAuth").click(); + } + }) +}); \ No newline at end of file diff --git a/core/func/js/auth/verifyEmail.js b/core/func/js/auth/verifyEmail.js new file mode 100644 index 0000000..befd0d9 --- /dev/null +++ b/core/func/js/auth/verifyEmail.js @@ -0,0 +1,70 @@ +$(document).ready(function() { + $("#verifyEmailCode").click(function() { + if ($("#verifyEmailCode").is(":disabled") == false) { + $("#verifyEmailCode").prop("disabled", true); + $("#emailCode").prop("disabled", true); + + var emailCode = $("#emailCode").val(); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/auth/verifyEmail.php', { + emailCode: emailCode, + csrf: csrf_token + }) + .done(function(response) { + $("#verifyEmailCode").prop("disabled", false); + $("#emailCode").prop("disabled", false); + if (response == "error") { + $("#vStatus").html("
    Network error. Try again later.
    "); + }else if (response == "incorrect-code") { + $("#vStatus").html("
    You have entered an incorrect verification code.
    "); + }else if (response == "success") { + window.location = "/"; + } + }) + .fail(function() { + $("#vStatus").html("
    Network error. Try again later.
    "); + }); + } + }) + + $("#confirmChange").click(function() { + if ($("#confirmChange").is(":disabled") == false) { + $("#confirmChange").prop("disabled", true); + $("#currentPassword").prop("disabled", true); + $("#newEmail").prop("disabled", true); + + var newEmail = $("#newEmail").val(); + var currentPassword = $("#currentPassword").val(); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/auth/changeEmailVerify.php', { + currentPassword: currentPassword, + newEmail: newEmail, + csrf: csrf_token + }) + .done(function(response) { + $("#confirmChange").prop("disabled", false); + $("#currentPassword").prop("disabled", false); + $("#newEmail").prop("disabled", false); + console.log(response); + if (response == "error") $(".gModalErrorContainer").html('
    Could not change your email because a network error occurred.
    '); + if (response == "missing-info") $(".gModalErrorContainer").html('
    You are missing information. Please check and try again.
    '); + if (response == "inc-password") $(".gModalErrorContainer").html('
    Your current password is incorrect.
    '); + if (response == "inc-email") $(".gModalErrorContainer").html('
    You have entered an invalid or illegal email address.
    '); + if (response == "email-in-use") $(".gModalErrorContainer").html('
    That email address is already in use by another user. Use another one.
    '); + if (response == "unknown-email") $(".gModalErrorContainer").html('
    You are using an unknown email service. Please use a more known one such as hotmail or gmail.
    '); + if (response == "rate-limit") $(".gModalErrorContainer").html('
    You have recently changed your email address. Please wait at least 60 minutes before trying again.
    '); + if (response == "success") window.location.reload(); + }) + .fail(function() { + $(".gModalErrorContainer").html('
    Could not change your email because a network error occurred.
    '); + }); + } + }) + + // Toggle on enter + $("#emailCode").keyup(function(event) { + if(event.keyCode == 13) { + $("#verifyEmailCode").click(); + } + }) +}); \ No newline at end of file diff --git a/core/func/js/blog.js b/core/func/js/blog.js new file mode 100644 index 0000000..43d2435 --- /dev/null +++ b/core/func/js/blog.js @@ -0,0 +1,28 @@ +$(document).ready(function() { + loadMain(); +}); + +function loadPost(postID) { + if (postID != undefined) { + $("#newPostBtn").css("display", "none"); + $.get("/core/func/api/blog/loadPost.php?id=" + postID, function(data) { + $("#postContainer").html(data); + }) + } +} + +function loadMain() { + $.get("/core/func/api/blog/getPosts.php", function(data) { + $("#newPostBtn").css("display", "block"); + $("#title").html("Graphictoria Blog"); + $("#postContainer").html(data); + }) +} + +function loadNew() { + $("#newPostBtn").css("display", "none"); + $.get("/core/func/api/blog/addPost.php", function(data) { + $("#title").html("New Post"); + $("#postContainer").html(data); + }) +} \ No newline at end of file diff --git a/core/func/js/catalog.js b/core/func/js/catalog.js new file mode 100644 index 0000000..d4adf33 --- /dev/null +++ b/core/func/js/catalog.js @@ -0,0 +1,52 @@ +$(document).ready(function() { + var type = "hats"; + var page = 0; + $("#itemsContainer").load("/core/func/api/catalog/getItems.php?type=hats&page=0"); + + $("#typeHats").click(function() { + switchType("hats"); + }); + + $("#typeHeads").click(function() { + switchType("heads"); + }); + + $("#typeFaces").click(function() { + switchType("faces"); + }); + + $("#typetshirts").click(function() { + switchType("tshirts"); + }); + + $("#typeshirts").click(function() { + switchType("shirts"); + }); + + $("#typepants").click(function() { + switchType("pants"); + }); + + $("#typeGear").click(function() { + switchType("gear"); + }); + + $("#typeDecals").click(function() { + switchType("decals"); + }); +}); + +function switchType(type) { + page = 0; + type = type; + $("#itemsContainer").load("/core/func/api/catalog/getItems.php?type=" + type + "&page=0"); +} + +function searchItem() { + var itemName = $("#searchCValue").val(); + if (itemName.length == 0) { + $('#errorModal').modal({ show: true}); + }else{ + $("#itemsContainer").load("/core/func/api/catalog/getItems.php?type=" + type + "&page=" +page+"&term=" + itemName); + } +} \ No newline at end of file diff --git a/core/func/js/character.js b/core/func/js/character.js new file mode 100644 index 0000000..4ce2416 --- /dev/null +++ b/core/func/js/character.js @@ -0,0 +1,128 @@ +function postPose(pose) { + if (pose == "walking") { + $("#poseStatus").html("
    Changed pose to walking
    "); + } + if (pose == "sitting") { + $("#poseStatus").html("
    Changed pose to sitting
    "); + } + if (pose == "normal") { + $("#poseStatus").html("
    Changed pose to normal
    "); + } + if (pose == "overlord") { + $("#poseStatus").html("
    Changed pose to overlord
    "); + } + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + var pose = pose; + $.post('/core/func/api/character/post/changePose.php', { + csrf: csrf_token, + pose: pose + }) +} + +$(document).ready(function() { + $("#normal").click(function() { + postPose("normal"); + }) + + $("#walking").click(function() { + postPose("walking"); + }) + + $("#sitting").click(function() { + postPose("sitting"); + }) + + $("#overlord").click(function() { + postPose("overlord"); + }) + + $("#regen").click(function() { + if ($("#regen").is(":disabled") == false) { + $("#regen").remove(); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/character/post/regenCharacter.php', { + csrf: csrf_token + }) + $("#poseStatus").html("
    Regenerating character...
    "); + } + }) + + + switchTo("hats"); + + $("#showHats").click(function() { + switchTo("hats"); + }) + + $("#showHeads").click(function() { + switchTo("heads"); + }) + + $("#showFaces").click(function() { + switchTo("faces"); + }) + + $("#showTshirts").click(function() { + switchTo("tshirts"); + }) + + $("#showShirts").click(function() { + switchTo("shirts"); + }) + + $("#showPants").click(function() { + switchTo("pants"); + }) + + $("#showGear").click(function() { + switchTo("gear"); + }) +}); + +function startGeneration(userID) { + setInterval(function() { + var characterElement = document.getElementById('character'); + characterElement.src = 'https://api.xdiscuss.net/imageServer/user/'+userID+'.png?tick=' + Math.random(); + }, 5000); +} + +function switchTo(type) { + type = type; + $("#inventoryItems").load("/core/func/api/character/getInventory.php?type=" + type); + $("#wearing").load("/core/func/api/character/getWearing.php?type=" + type); +} + +function loadPage(type, page) { + $("#inventoryItems").load("/core/func/api/character/getInventory.php?type=" + type + "&page=" + page); +} + +function wearItem(itemId, type, page) { + if ($(".wearItem").is(":disabled") == false) { + $(".wearItem").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/character/post/wearItem.php', { + csrf: csrf_token, + itemId: itemId, + type: type + }) + .done(function() { + $("#inventoryItems").load("/core/func/api/character/getInventory.php?type=" + type + "&page=" + page); + $("#wearing").load("/core/func/api/character/getWearing.php?type=" + type); + }) + } +} + +function removeItem(itemId, type, page) { + if ($(".removeItem").is(":disabled") == false) { + $(".removeItem").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/character/post/removeItem.php', { + csrf: csrf_token, + itemId: itemId + }) + .done(function() { + $("#inventoryItems").load("/core/func/api/character/getInventory.php?type=" + type + "&page=" + page); + $("#wearing").load("/core/func/api/character/getWearing.php?type=" + type); + }) + } +} diff --git a/core/func/js/chat.js b/core/func/js/chat.js new file mode 100644 index 0000000..d741606 --- /dev/null +++ b/core/func/js/chat.js @@ -0,0 +1,473 @@ +var lastMessageResponse; +var getMessages = null; +var getTypingThread = null; +var dChatOpen = false; +var lastTimestamp = 0; +var isTyping = false; +var infoOpen = false; +var chatMemberCount; +var lastMessageID = 0; +var ackIds = []; + +$(function() { + $(".loadChatList").click(function() { + loadChatList(); + removeChatInfoBar(); + }) + $(".chatOpener").click(function() { + $(".chatContainer").empty(); + $(".chatContainer").html("Loading..."); + if (dChatOpen == false) { + dChatOpen = true; + $(this).css("top", "calc(100% - 371px)"); + $(".chatOpenbackground").css("display", "block"); + $(".chatOptions").css("display", "block"); + loadChatList(); + }else{ + dChatOpen = false; + $(this).css("top", "calc(100% - 24px)"); + $(".chatOpenbackground").css("display", "none"); + $(".chatOptions").css("display", "none"); + $(".chatOpener").html("Chat"); + stopIntervals(); + } + }) + + if ($(".mobileView").css("display") == "block") { + $(".backandtext").css("top", $(".navbar").css("height")) + } +}); + +function stopIntervals() { + for (var i = 1; i < 9999; i++) { + window.clearInterval(i); + getMessages = undefined; + } +} + +function loadChatList() { + clean(); + if ($(".mobileView").css("display") == "block") { + window.history.pushState("", "", "/chat"); + var appContainer = $("#appContainer"); + appContainer.load("/core/func/views/app/user/chatlist.php", function() { + $.get("/core/func/api/chat/getList.php", function(data) { + var json = JSON.parse(data); + $(".chatContainer").empty(); + for (var i = 0; i < json.length; i++) { + var fHTML = json[i].chat_id; + $(".chatContainer").append('
  • ' + json[i].chatName + '
  • '); + } + if (data == "[]") { + $(".chatContainer").append("
    You are in no chats at the moment
    "); + } + }); + }); + }else{ + $(".chatOpener").html("Chat"); + $(".addChatBtn").css("display", "block"); + $(".chatOptions").html(""); + $.get("/core/func/api/chat/getList.php", function(data) { + var json = JSON.parse(data); + $(".chatContainer").empty(); + for (var i = 0; i < json.length; i++) { + var fHTML = json[i].chat_id; + $(".chatContainer").append('
  • ' + json[i].chatName + '
  • '); + } + if (data == "[]") { + $(".chatContainer").append("
    You are in no chats at the moment
    "); + } + }); + } +} + +function renderChatChoices() { + $("#gModalTitle").html("Add Chat"); + $("#gModalBody").html("

    Do you want to create a new chat or join one?

    "); + $(".gModalErrorContainer").html(""); + $("#gModalBody").append(""); + $("#gModalBody").append(""); + $("#globalModal2").modal('show'); +} + +function renderCreateChat() { + $("#gModalTitle").html("Create Chat"); + $("#gModalBody").html("

    Give your chat a name and press create!

    "); + $(".gModalErrorContainer").html(""); + $("#gModalBody").append(""); + $("#gModalBody").append(""); +} + +function renderJoinChat() { + $("#gModalTitle").html("Join Chat"); + $("#gModalBody").html("

    Enter a Chat Code and join a chat

    "); + $(".gModalErrorContainer").html(""); + $("#gModalBody").append(""); + $("#gModalBody").append(""); +} + +function createChat() { + $(".create_chat_name").prop("disabled", true); + $(".create_chat").prop("disabled", true); + var chatName = $(".create_chat_name").val(); + $.post('/core/func/api/chat/createChat.php', { + chatName: chatName, + csrfToken: $('meta[name="csrf-token"]').attr('content') + }) + .done(function(response) { + $(".create_chat_name").prop("disabled", false); + $(".create_chat").prop("disabled", false); + if (response == "no-name") { + $(".gModalErrorContainer").html('
    You must have a chat name
    '); + }else if (response == "chat-name-too-long") { + $(".gModalErrorContainer").html('
    Your chat name is too long
    '); + }else if (response == "rate-limit") { + $(".gModalErrorContainer").html('
    Please wait before making another chat
    '); + }else{ + if ($(".mobileView").css("display") == "none") { + loadChatList(); + } + var json = JSON.parse(response); + for (var i = 0; i < json.length; i++) { + loadChat(json[i].chatKey, json[i].chatName, json[i].chat_id); + } + $("#globalModal2").modal('hide'); + } + }) + .fail(function() { + $(".gModalErrorContainer").html('
    Could not create a chat because a network error occurred
    '); + }); +} + +function joinChat() { + $(".join_code").prop("disabled", true); + $(".join_chat").prop("disabled", true); + var chatCode = $(".join_code").val(); + $.post('/core/func/api/chat/joinChat.php', { + chatCode: chatCode, + csrfToken: $('meta[name="csrf-token"]').attr('content') + }) + .done(function(response) { + $(".join_code").prop("disabled", false); + $(".join_chat").prop("disabled", false); + if (response == "no-code") { + $(".gModalErrorContainer").html('
    Please enter a chat code
    '); + }else if (response == "chat-code-too-long") { + $(".gModalErrorContainer").html('
    The chat code you entered is too long
    '); + }else if (response == "invalid-code") { + $(".gModalErrorContainer").html('
    You have entered an invalid chat code
    '); + }else if (response == "already-in") { + $(".gModalErrorContainer").html('
    You are already in this chat
    '); + }else{ + if ($(".mobileView").css("display") == "none") { + loadChatList(); + } + var json = JSON.parse(response); + for (var i = 0; i < json.length; i++) { + loadChat(json[i].chatKey, json[i].chatName, json[i].chat_id); + } + $("#globalModal2").modal('hide'); + } + }) + .fail(function() { + $(".gModalErrorContainer").html('
    Could not join the chat because a network error occurred
    '); + }); +} + +function clean() { + infoOpen = false; + stopIntervals(); + lastMessageResponse = undefined; + lastTimestamp = 0; +} + +function sendTyping(chatId) { + if (!isTyping) { + isTyping = true; + $.post('/core/func/api/chat/sendTyping.php', { + chatId: chatId, + csrfToken: $('meta[name="csrf-token"]').attr('content') + }).fail(function() { + console.log("Error sending typing status"); + }); + setTimeout(function() { + isTyping = false; + }, 3000); + } +} + + +function executeAsync(func) { + setTimeout(func, 0); +} + +function chatInfo(chatKey, chatName, chatId) { + if (infoOpen) { + infoOpen = false; + loadChat(chatKey, chatName, chatId); + }else{ + clean(); + infoOpen = true; + console.log("Got chat info"); + $(".backandtext").html("Chat information"); + $(".chatContainer").empty(); + } +} + +function loadChat(chatKey, chatName, chatId) { + ackIds = []; + if ($(".mobileView").css("display") == "none") { + $(".list-group-item").css("background-color", "#fff"); + $("."+chatId).css("background-color", "#ddd"); + $(".chatOptions").html(''); + } + clean(); + $(".chatContainer").html('
    '); + + $("#chatMessageBox").css("width", "215px"); + $("#sendChatButton").css("margin-left", "215px").css("width", "41px") + $(".addChatBtn").css("display", "none"); + + $('#chatMessageBox').keypress(function (e) { + var key = e.which; + if(key == 13) { + $('#sendChatButton').click(); + } + }); + + $(window).resize(function() { + if ($(".mobileView").css("display") == "block") { + $(window).scrollTop($(document).height()); + } + }); + + $.get("/core/func/api/chat/getChatInfo.php?id=" + chatId, function(data) { + if (data == "error" || data == "[]") { + loadChatList(); + throw new Error("An error occurred"); + } + var json = JSON.parse(data); + for (var i = 0; i < json.length; i++) { + chatMemberCount = json[i].chatMembers; + if (chatMemberCount == 1) { + var bText = "member"; + }else{ + var bText = "members"; + } + chatJoinKey = json[i].joinKey; + $(".chatOpener").html(json[i].chatName); + } + + if ($(".mobileView").css("display") == "block") { + $(".chatBreaker").empty(); + times = 0; + while(times < $(".backandtext").height()/24) { + $(".chatBreaker").append("
    "); + times++; + } + } + + executeAsync(loadMessagesInChat(chatKey, chatId)); + executeAsync(getTyping(chatId)); + getMessages = setInterval(function() { + loadMessagesInChat(chatKey, chatId); + }, 1000); + + getTypingThread = setInterval(function() { + getTyping(chatId); + }, 3000); + $(".messageContainer").css("opacity", 0); + $(".loadContainer").append('
    ').hide(); + }).fail(function() { + loadChat(chatKey, chatName, chatId); + }); +} + +function getTyping(chatId) { + $.get("/core/func/api/chat/getTyping.php?chatId=" + chatId, function(data) { + var json = JSON.parse(data); + if (chatMemberCount == 1) { + var bText = "member"; + }else{ + var bText = "members"; + } + //if ($(".mobileView").css("display") == "block") { + if (json.mode == "none") { + $(".chatOptions").html(chatMemberCount + " " + bText + " [Invite code: " + chatJoinKey + "]"); + } + if (json.mode == "showTyping") { + var username1 = json.usernames[0]; + var username2 = json.usernames[1]; + var arrayLength = json.usernames.length; + if (arrayLength == 1) { + $(".chatOptions").html(username1 + " is typing...").css("position", "fixed"); + }else{ + $(".chatOptions").html(username1 + " and " + username2 + " are typing..."); + } + } + if (json.mode == "several") { + $(".chatOptions").html("Several people are typing"); + } + //} + }); +} + +function parseDate(date) { + var dateMessage = new Date(date*1000); + var dateCurrent = new Date(); + var dayMessageNum = dateMessage.getDate(); + var yearMessage = dateMessage.getFullYear(); + var monthMessage = dateMessage.getMonth(); + + var dateCurrentNum = dateCurrent.getDate(); + var currentYear = dateCurrent.getFullYear(); + var currentMonth = dateCurrent.getMonth(); + var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; + var dayOfWeekMessage = days[dateMessage.getDay()] + var dayOfWeekCurrent = days[dateCurrent.getDay()] + dateCurrent.setDate(dateCurrent.getDate() - 1); + var dayYesterday = days[dateCurrent.getDay()]; + if (dayOfWeekCurrent == dayOfWeekMessage && dayMessageNum == dateCurrentNum && yearMessage == currentYear && monthMessage == currentMonth) { + date = intlDate2.format(new Date(1000*date)); + }else if (dayOfWeekMessage == dayYesterday && dayMessageNum == dateCurrentNum-1 && yearMessage == currentYear && monthMessage == currentMonth) { + date = "yesterday at " + intlDate2.format(new Date(1000*date)); + }else{ + date = intlDate.format(new Date(1000*date)); + date = date.replace("M01", "Jan"); + date = date.replace("M02", "Feb"); + date = date.replace("M03", "Mar"); + date = date.replace("M04", "Apr"); + date = date.replace("M05", "May"); + date = date.replace("M06", "Jun"); + date = date.replace("M07", "Jul"); + date = date.replace("M08", "Aug"); + date = date.replace("M09", "Sep"); + date = date.replace("M10", "Oct"); + date = date.replace("M11", "Nov"); + date = date.replace("M12", "Dec"); + } + return date; +} + +function loadMessagesInChat(chatKey, chatId) { + $.get("/core/func/api/chat/getMessages.php?id=" + chatId + "×tamp=" + lastTimestamp, function(data) { + if (data == "error") { + loadChatList(); + throw new Error("An error occurred"); + } + if (lastMessageResponse != data) { + if ($(".messageContainer").css("opacity") == 0) { + $("#loadContainer").empty(); + $(".messageContainer").animate({opacity: 1}); + } + var json = JSON.parse(data); + if (data == "[]" && lastTimestamp == 0) { + createMessage("Welcome to the beginning of this chat.", "GraphictoriaBot", "red", 2, undefined, true, false); + } + for (var i = 0; i < json.length; i++) { + if (lastMessageID != json[i].messageId && ackIds.includes(json[i].messageId) == false) { + lastMessageID = json[i].messageId; + ackIds.push(json[i].messageId); + lastTimestamp = Math.round((new Date()).getTime() / 1000); + if (json[i].userId == 0) { + createMessage(json[i].message, "Graphictoria", "red", 2, json[i].date, true, false, 0); + }else{ + createMessage(json[i].message, json[i].username, json[i].userColor, json[i].staff, json[i].date, false, json[i].setRight, json[i].userID); + } + if (lastMessageResponse != undefined && data != "[]" && json[i].setRight == false) { + console.log("New message"); + var receiveSound = new Audio('/core/func/api/chat/sounds/send.mp3') + receiveSound.play(); + } + }else{ + console.log("Caught duplicate message"); + } + } + if (data != "[]") { + if ($(".mobileView").css("display") == "block") { + $(window).scrollTop($(document).height()); + }else{ + $(".chatOpenbackground").scrollTop($(".chatOpenbackground")[0].scrollHeight); + } + } + } + lastMessageResponse = data; + }); +} + +var options = { + weekday: 'long', + month: 'short', + year: 'numeric', + day: 'numeric', + hour: 'numeric', + minute: 'numeric' +},intlDate = new Intl.DateTimeFormat(undefined, options); + +var options2 = { + hour: 'numeric', + minute: 'numeric' +},intlDate2 = new Intl.DateTimeFormat(undefined, options2); + +function createMessage(message, sender, cColor, tagId, date, doCenter, setRight, userID) { + var color = cColor; + var cHTML = ""; + if (doCenter == true) { + cHTML = "center"; + } + + var sHTML = '' + sender + ''; + + if (setRight == false) { + if (tagId == 1) { + var uHTML = ' ' + sHTML + ':'; + }else if (tagId == 2) { + var uHTML = 'BOT ' + sender + ':'; + }else{ + var uHTML = sHTML + ':'; + } + }else{ + var uHTML = ""; + } + + if (setRight == true) { + var style = "style=\"float:right;max-width:100%\""; + }else{ + var style = "style=\"width:100%\""; + } + + if (date == undefined) { + date = ""; + }else{ + date = parseDate(date); + } + $(".messageContainer").append('
    ' + uHTML + ' ' + message + ' ' + date + '
    '); +} + +function sendMessageInChat(chatId, chatKey) { + $("#sendChatButton").prop("disabled", true); + $("#chatMessageBox").prop("disabled", true); + var chatMessage = $("#chatMessageBox").val(); + $("#chatMessageBox").val(""); + $.post('/core/func/api/chat/sendMessage.php', { + message: chatMessage, + chatId: chatId, + csrfToken: $('meta[name="csrf-token"]').attr('content') + }) + .done(function(response) { + $("#sendChatButton").prop("disabled", false); + $("#chatMessageBox").prop("disabled", false); + $("#chatMessageBox").focus(); + if (response == "message-too-short") { + $("#chatMessageBox").css("border", "1px solid #d9534f"); + }else if (response == "message-too-long") { + $("#chatMessageBox").css("border", "1px solid #d9534f"); + }else{ + $("#chatMessageBox").css("border", "0px solid #F44336"); + } + }) + .fail(function() { + console.log("Error while sending message"); + $("#chatMessageBox").css("border", "0px solid #F44336"); + }); +} \ No newline at end of file diff --git a/core/func/js/createGroup.js b/core/func/js/createGroup.js new file mode 100644 index 0000000..afa4be8 --- /dev/null +++ b/core/func/js/createGroup.js @@ -0,0 +1,42 @@ +$(document).ready(function() { + $("#createGroup").click(function() { + if ($("#createGroup").is(":disabled") == false) { + $("#createGroup").prop("disabled", true); + $("#groupName").prop("disabled", true); + $("#groupDescription").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + var groupName = $("#groupName").val(); + var groupDescription = $("#groupDescription").val(); + $.post('/core/func/api/groups/post/createGroup.php', { + csrf: csrf_token, + groupName: groupName, + groupDescription: groupDescription + }) + .done(function(response) { + $("#createGroup").prop("disabled", false); + $("#groupName").prop("disabled", false); + $("#groupDescription").prop("disabled", false); + if (response == "error") { + $("#gStatus").html("
    Could not create a group because a network error has occurred.
    "); + }else if (response == "no-name") { + $("#gStatus").html("
    Please specify a group name
    "); + }else if (response == "group-name-too-short") { + $("#gStatus").html("
    Your group name is too short
    "); + }else if (response == "group-name-too-long") { + $("#gStatus").html("
    Your group name is too long
    "); + }else if (response == "description-too-long") { + $("#gStatus").html("
    Your group description is too long
    "); + }else if (response == "no-coins") { + $("#gStatus").html("
    You do not have enough coins to create a group
    "); + }else if (response == "in-too-many-groups") { + $("#gStatus").html("
    You are in too many groups
    "); + }else{ + window.location = "/groups/view/"+response; + } + }) + .fail(function() { + $("#gStatus").html("
    Could not create a group because a network error has occurred.
    "); + }); + } + }) +}) \ No newline at end of file diff --git a/core/func/js/forum.js b/core/func/js/forum.js new file mode 100644 index 0000000..9412444 --- /dev/null +++ b/core/func/js/forum.js @@ -0,0 +1,343 @@ +// EnergyCell +var page = 0; +function loadForum(id) { + if ($(window).width() > 767) { + $(".adContainer").css("display", "block"); + } + $("#posts").html('


    '); + window.history.pushState("", "", '/forum-'+id); + $("html, body").animate({ scrollTop: 0 }, "fast"); + $("#posts").load("/core/func/api/forum/getPosts.php?id=" + id, function() { + if ($("#posts").height() < 1395) { + $(".adContainer").css("display", "none"); + }else{ + $(".adContainer").css("display", "block"); + } + $("#posts").hide().fadeIn('fast'); + }) + page = 0; +} + +function loadMiniProfile(userID) { + $(".modalUsername").html(""); + $(".miniProfileContent").html(''); + $(".miniProfileContent").load("/core/func/api/forum/getMiniProfile.php?id=" + userID); + $('.miniProfile').modal('show').hide().fadeIn('fast'); +} + +function search(forumID) { + $(".modalUsername").html(""); + $(".miniProfileContent").html(''); + $(".miniProfileContent").load("/core/func/api/forum/doSearch.php?id=" + forumID); + $('.miniProfile').modal('show').hide().fadeIn('fast'); +} + +function doSearch(forumID) { + var keyword = $("#searchboxValue").val(); + if (keyword.length == 0) { + $("#searchError").html('Please enter something'); + }else{ + $('.miniProfile').modal('hide'); + $("#posts").html('


    '); + $("html, body").animate({ scrollTop: 0 }, "fast"); + $("#posts").load("/core/func/api/forum/getPosts.php?id=" + forumID + "&keyword=" + encodeURIComponent(keyword), function() { + if ($("#posts").height() < 1395) { + $(".adContainer").css("display", "none"); + }else{ + $(".adContainer").css("display", "block"); + } + $("#posts").hide().fadeIn('fast'); + }) + page = 0; + } +} + +function loadPost(id) { + $(".adContainer").css("display", "none"); + $("#posts").html('


    '); + window.history.pushState("", "", '/forum+'+id); + $("html, body").animate({ scrollTop: 0 }, "fast"); + $("#posts").load("/core/func/api/forum/showPost.php?id=" + id, function() { + $("#posts").hide().fadeIn('fast'); + if ($("#posts").height() < 1395) { + $(".adContainer").css("display", "none"); + }else{ + $(".adContainer").css("display", "block"); + } + }) + page = 0; +} +function loadMore(page, postId) { + $(".loadMore").prop("disabled", true); + $.get("/core/func/api/forum/showPost.php?id=" + postId + "&page=" + page, function(data) { + $(".loadMore").remove(); + $("#posts").append(data); + }); +} + +function loadMoreForum(page, forumId) { + $(".loadMore").prop("disabled", true); + $.get("/core/func/api/forum/getPosts.php?id=" + forumId + "&page=" + page, function(data) { + $(".loadMore").remove(); + $("#posts").append(data); + }); +} + +function loadMoreForumSearch(page, forumId, keyword) { + $(".loadMore").prop("disabled", true); + $.get("/core/func/api/forum/getPosts.php?id=" + forumId + "&page=" + page + "&keyword=" + keyword, function(data) { + $(".loadMore").remove(); + $("#posts").append(data); + }); +} + +function newPost(forumId) { + $(".adContainer").css("display", "none"); + $("#posts").html('


    '); + $("#posts").load("/core/func/api/forum/newPost.php?id=" + forumId); + $("html, body").animate({ scrollTop: 0 }, "fast"); +} + +function newReply(postId) { + $(".adContainer").css("display", "none"); + $("#posts").html('


    '); + $("#posts").load("/core/func/api/forum/newReply.php?id=" + postId); + $("html, body").animate({ scrollTop: 0 }, "fast"); +} + +function postMessage(forumId) { + if ($("#postMessage").is(":disabled") == false) { + $("#postMessage").prop("disabled", true); + $("#postContent").prop("disabled", true); + $("#postTitle").prop("disabled", true); + + var postTitle = $("#postTitle").val(); + var postContent = $("#postContent").val(); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/forum/post/newPost.php', { + postTitle: postTitle, + postContent: postContent, + csrf: csrf_token, + forum: forumId + }) + .done(function(response) { + $("#postMessage").prop("disabled", false); + $("#postContent").prop("disabled", false); + $("#postTitle").prop("disabled", false); + + if (response == "error") { + $("#pStatus").css("color", "red").html("Network error. Try again later."); + }else if (response == "title-too-short") { + $("#pStatus").css("color", "red").html("Your title is too short. Try something else."); + }else if (response == "title-too-long") { + $("#pStatus").css("color", "red").html("Your title is too long. Try something else."); + }else if (response == "content-too-short") { + $("#pStatus").css("color", "red").html("Your content is too short."); + }else if (response == "content-too-long") { + $("#pStatus").css("color", "red").html("Your content is too long."); + }else if (response == "rate-limit") { + $("#pStatus").css("color", "red").html("You are posting too fast. Please wait."); + }else if (response == "account-age") { + $("#pStatus").css("color", "red").html("Your account needs to be a day old to post."); + }else if (response == "no-forum") { + $("#pStatus").css("color", "red").html("The forum you are trying to post in does not exist."); + }else if (response == "access-denied") { + $("#pStatus").css("color", "red").html("You have no permission to post in this forum."); + }else{ + $("#pStatus").html(response); + } + }) + .fail(function() { + $("#pStatus").css("color", "red").html("Network error. Try again later."); + }); + } +} + +function postReply(postId) { + if ($("#postReply").is(":disabled") == false) { + $("#postReply").prop("disabled", true); + $("#replyContent").prop("disabled", true); + + var replyContent = $("#replyContent").val(); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/forum/post/newReply.php', { + replyContent: replyContent, + csrf: csrf_token, + postId: postId + }) + .done(function(response) { + $("#postReply").prop("disabled", false); + $("#replyContent").prop("disabled", false); + + if (response == "error") { + $("#rStatus").css("color", "red").html("Network error. Try again later."); + }else if (response == "content-too-short") { + $("#rStatus").css("color", "red").html("Your reply is too short."); + }else if (response == "content-too-long") { + $("#rStatus").css("color", "red").html("Your reply is too long."); + }else if (response == "rate-limit") { + $("#rStatus").css("color", "red").html("You are posting too fast. Please wait."); + }else if (response == "account-age") { + $("#rStatus").css("color", "red").html("Your account must be at least a day old to use the forums."); + }else if (response == "no-post") { + $("#rStatus").css("color", "red").html("The post you are trying to reply to does not exist."); + }else if (response == "access-denied") { + $("#rStatus").css("color", "red").html("Access Denied."); + }else{ + $("#rStatus").html(response); + } + }) + .fail(function() { + $("#rStatus").css("color", "red").html("Network error. Try again later."); + }); + } +} + +function lockPost(postId) { + if ($("#lockPost").is(":disabled") == false) { + $("#lockPost").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/forum/post/lockPost.php', { + csrf: csrf_token, + postId: postId + }) + .done(function(response) { + if (response == "error") { + $("#pStatus").css("color", "red").html("Network error. Try again later."); + }else{ + loadPost(postId); + } + }) + .fail(function() { + $("#pStatus").css("color", "red").html("Network error. Try again later."); + }); + } +} + +function unlockPost(postId) { + if ($("#unlockPost").is(":disabled") == false) { + $("#unlockPost").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/forum/post/unlockPost.php', { + csrf: csrf_token, + postId: postId + }) + .done(function(response) { + if (response == "error") { + $("#pStatus").css("color", "red").html("Network error. Try again later."); + }else{ + loadPost(postId); + } + }) + .fail(function() { + $("#pStatus").css("color", "red").html("Network error. Try again later."); + }); + } +} + +function pinPost(postId) { + if ($("#pinPost").is(":disabled") == false) { + $("#pinPost").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/forum/post/pinPost.php', { + csrf: csrf_token, + postId: postId + }) + .done(function(response) { + if (response == "error") { + $("#pStatus").css("color", "red").html("Network error. Try again later."); + }else{ + loadPost(postId); + } + }) + .fail(function() { + $("#pStatus").css("color", "red").html("Network error. Try again later."); + }); + } +} + +function unpinPost(postId) { + if ($("#unpinPost").is(":disabled") == false) { + $("#unpinPost").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/forum/post/unpinPost.php', { + csrf: csrf_token, + postId: postId + }) + .done(function(response) { + if (response == "error") { + $("#pStatus").css("color", "red").html("Network error. Try again later."); + }else{ + loadPost(postId); + } + }) + .fail(function() { + $("#pStatus").css("color", "red").html("Network error. Try again later."); + }); + } +} + +function deletePost(postId, forumId) { + if ($("#deletePost").is(":disabled") == false) { + if ($("#deletePost").text() != "Are you sure?") { + $("#deletePost").text("Are you sure?"); + }else{ + $("#deletePost").prop("disabled", true); + $("#deletePost").text("Deleting Post..."); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/forum/post/deletePost.php', { + csrf: csrf_token, + postId: postId + }) + .done(function(response) { + if (response == "error") { + $("#pStatus").css("color", "red").html("Network error. Try again later."); + }else{ + loadForum(forumId); + } + }) + .fail(function() { + $("#pStatus").css("color", "red").html("Network error. Try again later."); + }); + } + } +} + +$(document).ready(function() { + $("#catagories").load("/core/func/api/forum/getCatagories.php"); + var load = false; + var url = window.location.href; + var n = url.indexOf("+"); + if (n > 0) {; + loadPost(url.substring(n+1)); + load = true; + } + var n = url.indexOf("-"); + if (n > 0) {; + loadForum(url.substring(n+1)); + load = true; + } + + if (load == false) { + loadForum(2); + } + + $(window).on('popstate', function() { + var load = false; + var url = window.location.href; + var n = url.indexOf("+"); + if (n > 0) {; + loadPost(url.substring(n+1)); + load = true; + } + var n = url.indexOf("-"); + if (n > 0) {; + loadForum(url.substring(n+1)); + load = true; + } + + if (load == false) { + loadForum(2); + } + }) +}); \ No newline at end of file diff --git a/core/func/js/friends/main.js b/core/func/js/friends/main.js new file mode 100644 index 0000000..fc6fcf0 --- /dev/null +++ b/core/func/js/friends/main.js @@ -0,0 +1,33 @@ +function loadFriends(page) { + $("#friendsContainer").load("/core/func/api/friends/get/getFriends.php?page=" + page); +} + +$(document).ready(function() { + loadFriends(0); +}); + +function removeFriend(userID, currentPage) { + if ($(".rmFr").is(":disabled") == false) { + if ($("[value="+userID+"]").text() != "Are you sure?") { + $("[value="+userID+"]").text("Are you sure?"); + }else{ + $(".rmFr").prop("disabled", true); + $("[value="+userID+"]").text("Deleting Friend..."); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/friends/post/removeFriend.php', { + csrf: csrf_token, + userID: userID + }) + .done(function(response) { + if (response == "error") { + $("#fStatus").html("
    Network error. Try again later.
    "); + }else{ + loadFriends(currentPage); + } + }) + .fail(function() { + $("#fStatus").html("
    Network error. Try again later.
    "); + }); + } + } +} \ No newline at end of file diff --git a/core/func/js/friends/profile.js b/core/func/js/friends/profile.js new file mode 100644 index 0000000..5a988e3 --- /dev/null +++ b/core/func/js/friends/profile.js @@ -0,0 +1,48 @@ +function deleteFriendProfile(userID) { + if ($(".friendBtn").is(":disabled") == false) { + if ($(".friendBtn").text() != "Are you sure?") { + $(".friendBtn").text("Are you sure?"); + }else{ + $(".friendBtn").prop("disabled", true); + $(".friendBtn").text("Deleting Friend..."); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/friends/post/removeFriend.php', { + csrf: csrf_token, + userID: userID + }) + .done(function(response) { + if (response == "error") { + $("#pStatus").html("
    Network error. Try again later.
    "); + }else{ + $(".friendBtn").remove(); + } + }) + .fail(function() { + $("#pStatus").html("
    Network error. Try again later.
    "); + }); + } + } +} + +function sendRequest(userID) { + $(".friendBtn").prop("disabled", true); + $(".friendBtn").text("Sending..."); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/friends/post/sendRequest.php', { + csrf: csrf_token, + userID: userID + }) + .done(function(response) { + console.log(response); + if (response == "error") { + $("#pStatus").html("
    Network error. Try again later.
    "); + }else if (response == "rate-limit") { + $("#pStatus").html("
    Please wait before sending another friend request.
    "); + }else{ + $(".friendBtn").remove(); + } + }) + .fail(function() { + $("#pStatus").html("
    Network error. Try again later.
    "); + }); +} \ No newline at end of file diff --git a/core/func/js/friends/requests.js b/core/func/js/friends/requests.js new file mode 100644 index 0000000..3838a4c --- /dev/null +++ b/core/func/js/friends/requests.js @@ -0,0 +1,55 @@ +function loadRequests(page) { + $("#friendsContainer").load("/core/func/api/friends/get/getRequests.php?page=" + page); +} + +$(document).ready(function() { + loadRequests(0); +}); + +function ignoreRequest(userID, currentPage) { + if ($(".btn-xs").is(":disabled") == false) { + if ($("[value="+userID+"ignore]").text() != "Are you sure?") { + $("[value="+userID+"ignore]").text("Are you sure?"); + }else{ + $(".btn-xs").prop("disabled", true); + $("[value="+userID+"ignore]").text("Deleting Friend Request..."); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/friends/post/ignoreRequest.php', { + csrf: csrf_token, + userID: userID + }) + .done(function(response) { + if (response == "error") { + $("#fStatus").html("
    Network error. Try again later.
    "); + }else{ + loadRequests(currentPage); + } + }) + .fail(function() { + $("#fStatus").html("
    Network error. Try again later.
    "); + }); + } + } +} + +function acceptRequest(userID, currentPage) { + if ($(".btn-xs").is(":disabled") == false) { + $(".btn-xs").prop("disabled", true); + $("[value="+userID+"]").text("Accepting friend request..."); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/friends/post/acceptRequest.php', { + csrf: csrf_token, + userID: userID + }) + .done(function(response) { + if (response == "error") { + $("#fStatus").html("
    Could not add friend.
    "); + }else{ + loadRequests(currentPage); + } + }) + .fail(function() { + $("#fStatus").html("
    Network error. Try again later.
    "); + }); + } +} \ No newline at end of file diff --git a/core/func/js/friends/show.js b/core/func/js/friends/show.js new file mode 100644 index 0000000..bf6d319 --- /dev/null +++ b/core/func/js/friends/show.js @@ -0,0 +1,3 @@ +function loadFriends(userID, page) { + $("#friendsContainer").load("/core/func/api/friends/get/showFriends.php?userid=" + userID + "&page=" + page); +} \ No newline at end of file diff --git a/core/func/js/gamesPage.js b/core/func/js/gamesPage.js new file mode 100644 index 0000000..7e6a164 --- /dev/null +++ b/core/func/js/gamesPage.js @@ -0,0 +1,153 @@ +var refreshId1; +var refreshId2; +var refreshId3; +var version = 0; + +function stopInterval(variable) { + clearInterval(variable); +} + +function doCSS(id) { + if (refreshId1) { + stopInterval(refreshId1); + } + + if (refreshId2) { + stopInterval(refreshId2); + } + + if (refreshId3) { + stopInterval(refreshId3); + } + if (id == 1) { + $("#showPublic").css("background-color", "#ddd"); + $("#showMy").css("background-color", "#f0f0f0"); + $("#showMyS").css("background-color", "#f0f0f0"); + $("#result").load("/core/func/api/games/getPublic.php?version=" + version); + refreshId1 = setInterval(function() { + $("#result").load("/core/func/api/games/getPublic.php?version=" + version); + }, 15000); + }else if (id == 2) { + $("#showPublic").css("background-color", "#f0f0f0"); + $("#ShowMyS").css("background-color", "#f0f0f0"); + $("#showMy").css("background-color", "#ddd"); + $("#result").load("/core/func/api/games/getMy.php?version=" + version); + refreshId2 = setInterval(function() { + $("#result").load("/core/func/api/games/getMy.php?version=" + version); + }, 15000); + }else if (id == 3) { + $("#showPublic").css("background-color", "#f0f0f0"); + $("#showMy").css("background-color", "#f0f0f0"); + $("#showMyS").css("background-color", "#ddd"); + $("#result").load("/core/func/api/games/getMyS.php?version=" + version); + refreshId3 = setInterval(function() { + $("#result").load("/core/func/api/games/getMyS.php?version=" + version); + }, 15000); + } +} + +$(document).ready(function() { + $("#v0").click(function() { + $("#showPublic").css("display", "table-cell"); + $("#showMy").css("display", "table-cell"); + $("#showMyS").css("display", "table-cell"); + $("#v0").addClass("active"); + $(".d09").css("display", "table-cell"); + $(".d08").css("display", "none"); + $(".d11").css("display", "none"); + $("#all").removeClass("active"); + $("#v1").removeClass("active"); + $("#v2").removeClass("active"); + version = 0; + doCSS(1); + $("#showPublic").click(); + }); + $("#v1").click(function() { + $("#showPublic").css("display", "table-cell"); + $("#showMy").css("display", "table-cell"); + $("#showMyS").css("display", "table-cell"); + $("#v1").addClass("active"); + $("#v0").removeClass("active"); + $("#v2").removeClass("active"); + $("#all").removeClass("active"); + $(".d09").css("display", "none"); + $(".d11").css("display", "none"); + $(".d08").css("display", "table-cell"); + version = 1; + doCSS(1); + $("#showPublic").click(); + }); + $("#v2").click(function() { + $("#showPublic").css("display", "table-cell"); + $("#showMy").css("display", "table-cell"); + $("#showMyS").css("display", "table-cell"); + $("#v2").addClass("active"); + $("#v0").removeClass("active"); + $("#v1").removeClass("active"); + $("#all").removeClass("active"); + $(".d09").css("display", "none"); + $(".d08").css("display", "none"); + $(".d11").css("display", "table-cell"); + version = 2; + doCSS(1); + $("#showPublic").click(); + }); + $("#all").click(function() { + $("#v2").removeClass("active"); + $("#v0").removeClass("active"); + $("#v1").removeClass("active"); + $("#all").addClass("active"); + $(".d09").css("display", "table-cell"); + $(".d08").css("display", "table-cell"); + $(".d11").css("display", "table-cell"); + version = 4; + doCSS(1); + $("#showPublic").click(); + $("#showPublic").css("display", "none"); + $("#showMy").css("display", "none"); + $("#showMyS").css("display", "none"); + }); + $("#addServer").click(function() { + $.post("/core/func/api/games/addKey.php",{key: $("#serverKey").val()}).done(function(data) { + $("#addKeyResult").html(data); + }).fail(function() { + $("#addKeyResult").css("color", "white").html("
    Could not add a server to your list because an error occurred.
    "); + }); + }); + $("#showPublic").click(function() { + $('#showPublic').attr("disabled", true); + $('#showMy').attr("disabled", false); + $('#showMyS').attr("disabled", false); + doCSS(1); + }); + $("#showMy").click(function() { + $('#showPublic').attr("disabled", false); + $('#showMy').attr("disabled", true); + $('#showMyS').attr("disabled", false); + doCSS(2); + }); + $("#showMyS").click(function() { + $('#showPublic').attr("disabled", false); + $('#showMy').attr("disabled", false); + $('#showMyS').attr("disabled", true); + doCSS(3); + }); + + // Toggle on enter + $("#serverKey").keyup(function(event) { + if(event.keyCode == 13) { + $("#addServer").click(); + } + }) + + $("#all").click(); +}) + +function viewGame(gameID) { + if (gameID != undefined) { + $(".gameTitle").html("Loading..."); + $(".gameContent").html(''); + $(".gameContent").load("/core/func/api/games/viewGame.php?id=" + gameID); + $('.viewGame').modal('show').hide().fadeIn('fast'); + } +} \ No newline at end of file diff --git a/core/func/js/groupAdmin.js b/core/func/js/groupAdmin.js new file mode 100644 index 0000000..9a8c858 --- /dev/null +++ b/core/func/js/groupAdmin.js @@ -0,0 +1,28 @@ +function changeGroupDescription(groupId) { + if ($("#changeDescription").is(":disabled") == false) { + $("#changeDescription").prop("disabled", true); + $("#descriptionValue").prop("disabled", true); + + var descriptionValue = $("#descriptionValue").val(); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/groups/post/changeDescription.php', { + descriptionValue: descriptionValue, + csrf: csrf_token, + groupId: groupId + }) + .done(function(response) { + $("#changeDescription").prop("disabled", false); + $("#descriptionValue").prop("disabled", false); + if (response == "error") { + $("#aStatus").html("
    Network error. Try again later.
    "); + }else if (response == "description-too-long") { + $("#aStatus").html("
    Your description is too long.
    "); + }else if (response == "success") { + $("#aStatus").html("
    Changed Group Description!
    "); + } + }) + .fail(function() { + $("#aStatus").html("
    Network error. Try again later.
    "); + }); + } +} \ No newline at end of file diff --git a/core/func/js/html/navigation.js b/core/func/js/html/navigation.js new file mode 100644 index 0000000..02992ed --- /dev/null +++ b/core/func/js/html/navigation.js @@ -0,0 +1,110 @@ +function doPing() { + $.get("/core/func/api/auth/ping.php", function(response) { + console.log("Ping complete"); + }) +} + +$(document).ready(function() { + $(function () { + $("[data-toggle='tooltip']").tooltip(); + }); + $('.dropdown').on('show.bs.dropdown', function() { + $(this).find('.dropdown-menu').first().stop(true, true).slideDown(); + }); + + // Add slideUp animation to Bootstrap dropdown when collapsing. + $('.dropdown').on('hide.bs.dropdown', function() { + $(this).find('.dropdown-menu').first().stop(true, true).slideUp(); + }); + + $('#navbarSideButton').click(function() { + $(".navbar-side").show(); + //$(".navbottomMargin").css("margin-bottom", "0px"); + //$("body").css("position", "relative").css("top", "0px"); + $('.navbarSide').addClass('reveal'); + $(".overlay").fadeIn(500); + $('html, body').css({ + overflow: 'hidden', + height: '100%' + }); + }); + + $(".navbottomMargin-m").css("margin-bottom", $(".navbar").css("height")); + + $('.overlay').on('click', function() { + //$(".navbottomMargin").css("margin-bottom", "53px"); + //$("#appContainer").css("position", "initial").css("top", "0px"); + $('.navbarSide').removeClass('reveal'); + $('.overlay').fadeOut(500, function () { + $(".navbar-side").hide(); + }) + $('html, body').css({ + overflow: 'auto', + height: 'auto' + }); + }); + + $(".side-link").on('click', function() { + $(".overlay").click(); + }); + + $("#searchUser").click(function() { + var searchValue = $("#searchValue").val(); + if (searchValue.length != 0) { + if ($("#searchValue").attr("placeholder") == "Username") { + window.location = "/users/" + searchValue; + }else if ($("#searchValue").attr("placeholder") == "Group name") { + window.location = "/groups/search/" + searchValue; + } + }else{ + $("#navSearch").addClass("has-error"); + } + }) + + if ($(window).width() < 1200) { + $("#searchUser").hide(); + $("#searchValue").hide(); + $("#switchSearch").hide(); + }else{ + $("#searchUser").show(); + $("#searchValue").show(); + $("#switchSearch").show(); + } + + $(window).on('resize', function() { + if ($(window).width() < 1200) { + $("#searchUser").hide(); + $("#searchValue").hide(); + $("#switchSearch").hide(); + }else{ + $("#searchUser").show(); + $("#searchValue").show(); + $("#switchSearch").show(); + } + }); + + // Toggle on enter + $("#searchValue").keyup(function(event) { + if(event.keyCode == 13) { + $("#searchUser").click(); + } + }) + + $("#switchSearch").click(function() { + if ($("#searchValue").attr("placeholder") == "Username") { + $("#searchValue").attr("placeholder", "Group name") + }else if ($("#searchValue").attr("placeholder") == "Group name") { + $("#searchValue").attr("placeholder", "Username") + } + }) + + doPing(); + setInterval(function(){ + doPing(); + }, 30000); +}); + +function showDMCA() { + $(".gModalContent").html('

    DMCA

    If you find anything that violates, please send an email. Please remember that Graphictoria is non-profit and also hosted in a country where a DMCA can be ignored.

    Note: If we notice that your message is not coming from the actual sender, we will ignore your email. Do not waste your time sending fake emails because we will find that out. If you are serious about sending legal inqueries, do it from an email we can verify is real.

    We have received a bunch of fake DMCAs up to the point we can never be sure if it is real or fake. If you are sending a real email and are actually the owner of a copyright, use your legal email and use the actual email server so we can verify headers.

    Graphictoria is not willfully wanting to destroy anyone\'s brand or property, we exist because we want to revive older versions of an amazing game and do things not possible on the real platform. We do not sell any memberships, and we will never do so. We give full rights to their respective owners.

    Because we are unable to see who sends an email through CloudFlare abuse (I could impersonate a big company and get away with it, and so can everyone else), we will be ignoring all messages sent through that.

    '); + $('.globalModal').modal({ show: true}); +} \ No newline at end of file diff --git a/core/func/js/item.js b/core/func/js/item.js new file mode 100644 index 0000000..11959b1 --- /dev/null +++ b/core/func/js/item.js @@ -0,0 +1,50 @@ +function buyItem(itemId) { + if ($("#buyItem").is(":disabled") == false) { + $("#buyItem").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/catalog/post/buyItem.php', { + csrf: csrf_token, + itemId: itemId + }) + .done(function(response) { + console.log(response); + if (response == "error") { + $("#iStatus").html("
    Could not buy this item.
    "); + }else{ + $("#iStatus").html("
    You have bought this item!
    "); + $("#buyItem").text("Already owned"); + if (cType == "coins") + $("#userCoins").html(response); + if (cType == "posties") + $("#userPosties").html(response); + } + }) + .fail(function() { + $("#iStatus").html("
    Could not buy this item because a network error occurred. Try again later.
    "); + }); + } +} + +function deleteItem(itemId) { + if ($("#deleteItem").is(":disabled") == false) { + $("#deleteItem").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/catalog/post/deleteItem.php', { + csrf: csrf_token, + itemId: itemId + }) + .done(function(response) { + console.log(response); + if (response == "error") { + $("#iStatus").html("
    Could not delete this item.
    "); + }else if (response == "success") { + window.location = "/catalog/"; + }else{ + $("#iStatus").html("
    Could not delete this item because a network error occurred. Try again later.
    "); + } + }) + .fail(function() { + $("#iStatus").html("
    Could not delete this item because a network error occurred. Try again later.
    "); + }); + } +} \ No newline at end of file diff --git a/core/func/js/messages.js b/core/func/js/messages.js new file mode 100644 index 0000000..694fa2e --- /dev/null +++ b/core/func/js/messages.js @@ -0,0 +1,106 @@ +var page = 0; +function loadMessages(filterId) { + $("#messages").html('


    '); + $("#messages").load("/core/func/api/messages/getMessages.php?filter=" + filterId); + $("html, body").animate({ scrollTop: 0 }, "slow"); + page = 0; +} + +function loadMore(page, filterId) { + $(".loadMore").remove(); + $.get("/core/func/api/messages/getMessages.php?filter=" + filterId + "&page=" + page, function(data) { + $("#messages").append(data); + }); +} + +function loadMessage(id) { + $("#messages").html('


    '); + $("#messages").load("/core/func/api/messages/showMessage.php?id=" + id); + $("html, body").animate({ scrollTop: 0 }, "slow"); + page = 0; +} + +function sendMessage(username) { + $("#messages").html('


    '); + $("#messages").load("/core/func/api/messages/newMessage.php?username=" + username); +} + +function sendMessagePost(userID) { + if ($("#sendMessage").is(":disabled") == false) { + $("#sendMessage").prop("disabled", true); + $("#messageContent").prop("disabled", true); + $("#messageTitle").prop("disabled", true); + + var messageTitle = $("#messageTitle").val(); + var messageContent = $("#messageContent").val(); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/messages/post/newMessage.php', { + messageTitle: messageTitle, + messageContent: messageContent, + csrf: csrf_token, + userID: userID + }) + .done(function(response) { + $("#sendMessage").prop("disabled", false); + $("#messageContent").prop("disabled", false); + $("#messageTitle").prop("disabled", false); + if (response == "error") { + $("#pStatus").css("color", "red").html("Network error. Try again later."); + }else if (response == "title-too-short") { + $("#pStatus").css("color", "red").html("Your title is too short."); + }else if (response == "title-too-long") { + $("#pStatus").css("color", "red").html("Your title is too long."); + }else if (response == "content-too-short") { + $("#pStatus").css("color", "red").html("Your message is too short."); + }else if (response == "content-too-long") { + $("#pStatus").css("color", "red").html("Your message is too long."); + }else if (response == "no-user") { + $("#pStatus").css("color", "red").html("The user you are sending a message to does not exist."); + }else if (response == "no-banned") { + $("#pStatus").css("color", "red").html("The user you are sending a message to has been banned."); + }else if (response == "no-banned") { + $("#pStatus").css("color", "red").html("The user you are sending a message to has been banned."); + }else if (response == "success") { + loadMessages(0); + window.history.pushState("", "", '/user/messages'); + $("#mStatus").html("
    Your message has been sent!
    "); + } + }) + .fail(function() { + $("#pStatus").css("color", "red").html("Network error. Try again later."); + }); + } +} + +$(document).ready(function() { + var load = false; + var url = window.location.href; + var n = url.indexOf("+"); + if (n > 0) {; + sendMessage(url.substring(n+1)); + load = true; + } + + if (load == false) { + loadMessages(0); + } + $("#allMessages").click(function() { + console.log("All Messages"); + loadMessages(0); + }) + + $("#unreadMessages").click(function() { + console.log("Unread Messages"); + loadMessages(1); + }) + + $("#readMessages").click(function() { + console.log("Read Messages"); + loadMessages(2); + }) + + $("#sentOnly").click(function() { + console.log("Sent Only"); + loadMessages(3); + }) +}); \ No newline at end of file diff --git a/core/func/js/profile.js b/core/func/js/profile.js new file mode 100644 index 0000000..830061a --- /dev/null +++ b/core/func/js/profile.js @@ -0,0 +1,40 @@ +$(document).ready(function() { + switchTo("hats"); + + $("#showHats").click(function() { + switchTo("hats"); + }) + + $("#showHeads").click(function() { + switchTo("heads"); + }) + + $("#showFaces").click(function() { + switchTo("faces"); + }) + + $("#showTshirts").click(function() { + switchTo("tshirts"); + }) + + $("#showShirts").click(function() { + switchTo("shirts"); + }) + + $("#showPants").click(function() { + switchTo("pants"); + }) + + $("#showGear").click(function() { + switchTo("gear"); + }) +}); + +function switchTo(type) { + type = type; + $("#inventoryItems").load("/core/func/api/profile/getInventory.php?type=" + type + "&userId=" + userId); +} + +function loadPage(type, page) { + $("#inventoryItems").load("/core/func/api/profile/getInventory.php?type=" + type + "&userId=" + userId + "&page=" + page); +} diff --git a/core/func/js/searchGroup.js b/core/func/js/searchGroup.js new file mode 100644 index 0000000..a7b5ef0 --- /dev/null +++ b/core/func/js/searchGroup.js @@ -0,0 +1,17 @@ +$(document).ready(function() { + $("#doSearch_2").click(function() { + var searchValue = $("#searchValue_2").val() + $.get("/core/func/api/groups/searchGroup.php?term=" + searchValue + "&page=0", function(data) { + $("#searchResults").html(data); + }); + }) + + $("#doSearch_2").click(); +}); + +function loadMore(page, term) { + $(".searchGroup").remove(); + $.get("/core/func/api/groups/searchGroup.php?term=" + term + "&page=" + page, function(data) { + $("#searchResults").append(data); + }); +} \ No newline at end of file diff --git a/core/func/js/settings.js b/core/func/js/settings.js new file mode 100644 index 0000000..b08c67c --- /dev/null +++ b/core/func/js/settings.js @@ -0,0 +1,235 @@ +$(document).ready(function() { + $("#updateAbout").click(function() { + if ($("#updateAbout").is(":disabled") == false) { + $("#updateAbout").prop("disabled", true); + $("#aboutValue").prop("disabled", true); + + var aboutContent = $("#aboutValue").val(); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/settings/post/updateAbout.php', { + aboutContent: aboutContent, + csrf: csrf_token + }) + .done(function(response) { + $("#updateAbout").prop("disabled", false); + $("#aboutValue").prop("disabled", false); + if (response == "filtered") { + $("#sStatus").html("
    Your about text contains bad words! Please remove them
    "); + $("#aboutValue").val(""); + }else{ + $("#sStatus").html("
    About text changed!
    "); + } + }) + .fail(function() { + $("#sStatus").html("
    Network error. Try again later.
    "); + }); + } + }) + + $("#enableRegular").click(function() { + if ($("#enableRegular").is(":disabled") == false) { + $("#enableRegular").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/settings/post/updateTheme.php', { + theme: 0, + csrf: csrf_token + }) + .done(function(response) { + $("#enableRegular").prop("disabled", false); + $("#aboutValue").prop("disabled", false); + if (response == "success") { + window.location.reload(); + }else{ + $("#sStatus").html("
    Network error. Try again later.
    "); + } + }) + .fail(function() { + $("#sStatus").html("
    Network error. Try again later.
    "); + }); + } + }) + + $("#enableDark").click(function() { + if ($("#enableRegular").is(":disabled") == false) { + $("#enableDark").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/settings/post/updateTheme.php', { + theme: 1, + csrf: csrf_token + }) + .done(function(response) { + $("#enableDark").prop("disabled", false); + $("#aboutValue").prop("disabled", false); + if (response == "success") { + window.location.reload(); + }else{ + $("#sStatus").html("
    Network error. Try again later.
    "); + } + }) + .fail(function() { + $("#sStatus").html("
    Network error. Try again later.
    "); + }); + } + }) + + $("#changePassword").click(function() { + if ($("#changePassword").is(":disabled") == false) { + $("#changePassword").prop("disabled", true); + $("#nPassword1").prop("disabled", true); + $("#nPassword2").prop("disabled", true); + $("#curPassword").prop("disabled", true); + + var npass1 = $("#nPassword1").val(); + var npass2 = $("#nPassword2").val(); + var currentPassword = $("#curPassword").val(); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/settings/post/changePassword.php', { + newPassword1: npass1, + newPassword2: npass2, + currentPassword: currentPassword, + csrf: csrf_token + }) + .done(function(response) { + $("#changePassword").prop("disabled", false); + $("#nPassword1").prop("disabled", false); + $("#nPassword2").prop("disabled", false); + $("#curPassword").prop("disabled", false); + + if (response == "error") { + $("#cPassStatus").html("
    Network error. Try again later.
    "); + }else if (response == "missing-info") { + $("#cPassStatus").html("
    Please fill in everything
    "); + }else if (response == "confirm-failed") { + $("#cPassStatus").html("
    Password confirmation has failed
    "); + }else if (response == "password-too-short") { + $("#cPassStatus").html("
    Your new password is too short
    "); + }else if (response == "password-too-long") { + $("#cPassStatus").html("
    Your new password is too long
    "); + }else if (response == "wrong-password") { + $("#cPassStatus").html("
    Your current password is incorrect
    "); + }else if (response == "success") { + window.location = "/"; + } + }) + .fail(function() { + $("#cPassStatus").html("
    Network error. Try again later.
    "); + }); + } + }) + + $("#changeEmail").click(function() { + if ($("#changeEmail").is(":disabled") == false) { + $("#changeEmail").prop("disabled", true); + $("#email").prop("disabled", true); + $("#password").prop("disabled", true); + + var newEmail = $("#email").val(); + var currentPassword = $("#password").val(); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/settings/post/changeEmail.php', { + newEmail: newEmail, + currentPassword: currentPassword, + csrf: csrf_token + }) + .done(function(response) { + $("#changeEmail").prop("disabled", false); + $("#email").prop("disabled", false); + $("#password").prop("disabled", false); + if (response == "error") { + $("#cEmailStatus").html("
    Network error. Try again later.
    "); + }else if (response == "missing-info") { + $("#cEmailStatus").html("
    Please fill in everything
    "); + }else if (response == "success") { + window.location = "/"; + }else if (response == "wrong-password") { + $("#cEmailStatus").html("
    Your current password is incorrect
    "); + }else if (response == "rate-limit") { + $("#cEmailStatus").html("
    You have recently verified your current email, please wait at least 5 minutes before doing this
    "); + }else if (response == "unknown-email") { + $("#cEmailStatus").html("
    You are using an unknown email provider. Use a more known one such as hotmail or gmail
    "); + }else if (response == "email-in-use") { + $("#cEmailStatus").html("
    That email is already in use by another user.
    "); + } + }) + .fail(function() { + $("#cEmailStatus").html("
    Network error. Try again later.
    "); + }); + } + }) + + $("#enableTwo").click(function() { + if ($("#enableTwo").is(":disabled") == false) { + $("#enableTwo").prop("disabled", true); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/settings/post/enableTwo.php', { + csrf: csrf_token + }) + .done(function(response) { + $("#updateAbout").prop("disabled", false); + $("#aboutValue").prop("disabled", false); + if (response == "success") { + $("#twocontainer").load("/core/func/api/settings/get/twoStep.php"); + }else{ + $("#sStatus").html("
    Network error. Try again later.
    "); + } + }) + .fail(function() { + $("#sStatus").html("
    Network error. Try again later.
    "); + }); + } + }) +}); + +function enableTwoFinal() { + if ($("#enableTwoFinal").is(":disabled") == false) { + $("#enableTwoFinal").prop("disabled", true); + $("#finalCode").prop("disabled", true); + var finalCode = $("#finalCode").val(); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/settings/post/enableTwoFinal.php', { + finalCode: finalCode, + csrf: csrf_token + }) + .done(function(response) { + $("#enableTwoFinal").prop("disabled", false); + $("#finalCode").prop("disabled", false); + if (response == "success") { + $("#sStatus").html("
    Two Step Authentication has been enabled! You will be asked to use it the next time you login.
    "); + $("#twocontainer").load("/core/func/api/settings/get/twoStep.php"); + }else if(response == "missing-info") { + $("#sStatus").html("
    Please enter your authentication code.
    "); + }else if(response == "wrong-code") { + $("#sStatus").html("
    Your authentication code is incorrect. Did you use the Authy or Google authentication mobile app?
    "); + }else{ + $("#sStatus").html("
    Network error. Try again later.
    "); + } + }) + .fail(function() { + $("#sStatus").html("
    Network error. Try again later.
    "); + }); + } +} + +function disableFactor() { + if ($("#disableTwo").is(":disabled") == false) { + $("#disableTwo").prop("disabled", true); + var finalCode = $("#finalCode").val(); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/settings/post/disableTwo.php', { + csrf: csrf_token + }) + .done(function(response) { + $("#disableTwo").prop("disabled", false); + if (response == "success") { + $("#twocontainer").load("/core/func/api/settings/get/twoStep.php"); + }else if (response == "staff-block") { + $("#sStatus").html("
    Staff members may not disable this feature.
    "); + }else{ + $("#sStatus").html("
    Network error. Try again later.
    ") + } + }) + .fail(function() { + $("#sStatus").html("
    Network error. Try again later.
    "); + }); + } +} \ No newline at end of file diff --git a/core/func/js/uploadItem.js b/core/func/js/uploadItem.js new file mode 100644 index 0000000..994ec1e --- /dev/null +++ b/core/func/js/uploadItem.js @@ -0,0 +1,83 @@ +$(document).ready(function() { + $(document).on('change', '#itemTypeValue', function() { + if ($(this).find("option:selected").attr('value') == 3) { + $("#itempriceContainer").css("display", "none"); + }else{ + $("#itempriceContainer").css("display", "block"); + } + }) + + $("#uploadItem").click(function() { + if ($("#uploadItem").is(":disabled") == false) { + $("#uploadItem").prop("disabled", true); + $("#itemNameValue").prop("disabled", true); + $("#itemDescriptionValue").prop("disabled", true); + $("#itemTypeValue").prop("disabled", true); + $("#itemPriceValue").prop("disabled", true); + $("#fileValue").prop("disabled", true); + + var formData = new FormData(); + formData.append('file', $('#fileValue')[0].files[0]); + formData.append('itemName', $("#itemNameValue").val()); + formData.append('itemDescription', $("#itemDescriptionValue").val()); + formData.append('itemType', $("#itemTypeValue").val()); + formData.append('itemPrice', $("#itemPriceValue").val()); + formData.append('csrf_token', $('meta[name="csrf-token"]').attr('content')); + $.ajax({ + type: "POST", + url : "/core/func/api/catalog/post/uploadItem.php", + data : formData, + cache: false, + contentType: false, + processData: false, + success: function(data) { + console.log(data); + $("#uploadItem").prop("disabled", false); + $("#itemNameValue").prop("disabled", false); + $("#itemDescriptionValue").prop("disabled", false); + $("#itemTypeValue").prop("disabled", false); + $("#itemPriceValue").prop("disabled", false); + $("#fileValue").prop("disabled", false); + + if (data == "error") { + $("#uploadStatus").html("
    Could not upload item because a network error occurred.
    "); + }else if (data == "name-too-short") { + $("#uploadStatus").html("
    Your item name is too short. Try something else.
    "); + }else if (data == "name-too-long") { + $("#uploadStatus").html("
    Your item name is too long. Try something else.
    "); + }else if (data == "description-too-long") { + $("#uploadStatus").html("
    Your description is too long. Try something else.
    "); + }else if (data == "price-too-low") { + $("#uploadStatus").html("
    Your item price is too low.
    "); + }else if (data == "rate-limit") { + $("#uploadStatus").html("
    Please wait a bit before uploading again.
    "); + }else if (data == "rate-limit") { + $("#uploadStatus").html("
    Please wait a bit before uploading again.
    "); + }else if (data == "incorrect-size") { + $("#uploadStatus").html("
    Your image has an incorrect size. Did you use the template?
    "); + }else if (data == "no-image") { + $("#uploadStatus").html("
    The file you have tried to upload is not an image.
    "); + }else if (data == "file-too-large") { + $("#uploadStatus").html("
    The file you have tried to upload is too large.
    "); + }else if (data == "incorrect-extension") { + $("#uploadStatus").html("
    The file you have tried to upload is not a valid image.
    "); + }else if (data == "not-enough-coins") { + $("#uploadStatus").html("
    You do not have enough coins to upload an item.
    "); + }else if (data == "file-upload-error") { + $("#uploadStatus").html("
    An error occured while uploading your item. Please contact an administrator.
    "); + }else if (data == "no-file") { + $("#uploadStatus").html("
    Please select a file to upload.
    "); + }else if (data == "bad-hash") { + $("#uploadStatus").html("
    This item can not be uploaded to Graphictoria.
    "); + }else{ + $("#uploadStatus").html("
    Your file has been uploaded. It will appear in the catalog when it has been approved.
    "); + $("#userCoins").html(data); + } + }, + error: function() { + $("#uploadStatus").html("
    Could not upload item because a network error occurred.
    "); + } + }); + } + }) +}); \ No newline at end of file diff --git a/core/func/js/users.js b/core/func/js/users.js new file mode 100644 index 0000000..bc4e570 --- /dev/null +++ b/core/func/js/users.js @@ -0,0 +1,17 @@ +$(document).ready(function() { + $("#doSearch_2").click(function() { + var searchValue = $("#searchValue_2").val() + $.get("/core/func/api/users/searchUser.php?term=" + searchValue + "&page=0", function(data) { + $("#searchResults").html(data); + }); + }) + + $("#doSearch_2").click(); +}); + +function loadMore(page, term) { + $(".searchUser").remove(); + $.get("/core/func/api/users/searchUser.php?term=" + term + "&page=" + page, function(data) { + $("#searchResults").append(data); + }); +} \ No newline at end of file diff --git a/core/func/js/viewGroup.js b/core/func/js/viewGroup.js new file mode 100644 index 0000000..ec88943 --- /dev/null +++ b/core/func/js/viewGroup.js @@ -0,0 +1,81 @@ +function getMembers(groupId, page) { + $("#memberField").load("/core/func/api/groups/get/getMembers.php?gid=" + groupId + "&page=" + page); +} + +function leaveDelete(groupId) { + if ($("#leaveDelete").is(":disabled") == false) { + if ($("#leaveDelete").text() != "Are you sure?") { + $("#leaveDelete").text("Are you sure?"); + }else{ + $("#leaveDelete").prop("disabled", true); + $("#leaveDelete").text("Leaving and deleting your group..."); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/groups/post/leaveDelete.php', { + csrf: csrf_token, + groupId: groupId + }) + .done(function(response) { + if (response == "error") { + $("#gStatus").html("
    Could not leave your group because a network error occurred.
    "); + }else{ + window.location = "/groups"; + } + }) + .fail(function() { + $("#gStatus").html("
    Could not leave your group because a network error occurred.
    "); + }); + } + } +} + +function leaveGroup(groupId) { + if ($("#leaveGroup").is(":disabled") == false) { + if ($("#leaveGroup").text() != "Are you sure?") { + $("#leaveGroup").text("Are you sure?"); + }else{ + $("#leaveGroup").prop("disabled", true); + $("#leaveGroup").text("Leaving group..."); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/groups/post/leaveGroup.php', { + csrf: csrf_token, + groupId: groupId + }) + .done(function(response) { + if (response == "error") { + $("#gStatus").html("
    Could not leave your group because a network error occurred.
    "); + }else{ + $("#leaveGroup").remove(); + getMembers(groupId, 0); + } + }) + .fail(function() { + $("#gStatus").html("
    Could not leave your group because a network error occurred.
    "); + }); + } + } +} + +function joinGroup(groupId) { + if ($("#joinGroup").is(":disabled") == false) { + $("#joinGroup").prop("disabled", true); + $("#joinGroup").text("Joining group..."); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/groups/post/joinGroup.php', { + csrf: csrf_token, + groupId: groupId + }) + .done(function(response) { + if (response == "error") { + $("#gStatus").html("
    Could not join this group because a network error occurred.
    "); + }else if (response == "in-too-many-groups") { + $("#gStatus").html("
    You are in too many groups.
    "); + }else{ + $("#joinGroup").remove(); + getMembers(groupId, 0); + } + }) + .fail(function() { + $("#gStatus").html("
    Could not join this group because a network error occurred.
    "); + }); + } +} \ No newline at end of file diff --git a/core/func/js/viewServer.js b/core/func/js/viewServer.js new file mode 100644 index 0000000..7d41be8 --- /dev/null +++ b/core/func/js/viewServer.js @@ -0,0 +1,25 @@ +function deleteServer(serverID) { + if ($("#deletePost").is(":disabled") == false) { + if ($("#deleteServer").text() != "Are you sure?") { + $("#deleteServer").text("Are you sure?"); + }else{ + $("#deleteServer").prop("disabled", true); + $("#deleteServer").text("Deleting Server..."); + var csrf_token = $('meta[name="csrf-token"]').attr('content'); + $.post('/core/func/api/games/post/deleteServer.php', { + csrf: csrf_token, + serverID: serverID + }) + .done(function(response) { + if (response == "error") { + $("#vStatus").html("
    Could not delete this server because a network error occurred
    ") + }else if (response == "success") { + window.location = "/games"; + } + }) + .fail(function() { + $("#vStatus").html("
    Could not delete this server because a network error occurred
    "); + }); + } + } +} \ No newline at end of file diff --git a/core/func/libs/aes/GibberishAES.php b/core/func/libs/aes/GibberishAES.php new file mode 100644 index 0000000..4e8df5c --- /dev/null +++ b/core/func/libs/aes/GibberishAES.php @@ -0,0 +1,540 @@ += 5.3.3 + * or + * Mcrypt functions installed and PHP version < 7.1.0-alpha + * + * For PHP under version 7 it is recommendable you to install within your project + * "PHP 5.x support for random_bytes() and random_int()", + * @link https://github.com/paragonie/random_compat + * + * Usage: + * + * // This is a secret pass-phrase, keep it in a safe place and don't loose it. + * $pass = 'my secret pass-phrase, it should be long'; + * + * // The string to be encrypted. + * $string = 'my secret message'; + * + * // This is the result after encryption of the given string. + * $encrypted_string = GibberishAES::enc($string, $pass); + * + * // This is the result after decryption of the previously encrypted string. + * // $decrypted_string == $string (should be). + * $decrypted_string = GibberishAES::dec($encrypted_string, $pass); + * echo $decrypted_string; + * + * // The default key-size is 256 bits. 128 and 192 bits are also allowed. + * // Example: + * $old_key_size = GibberishAES::size(); + * GibberishAES::size(192); + * // The short way: $old_key_size = GibberishAES::size(192); + * $encrypted_string = GibberishAES::enc($string, $pass); + * $decrypted_string = GibberishAES::dec($encrypted_string, $pass); + * GibberishAES::size($old_key_size); + * echo $decrypted_string; + * + * @author Ivan Tcholakov , 2012-2016. + * Code repository: @link https://github.com/ivantcholakov/gibberish-aes-php + * + * @version 1.3.1 + * + * @license The MIT License (MIT) + * @link http://opensource.org/licenses/MIT + */ + +class GibberishAES { + + // The default key size in bits. + protected static $key_size = 256; + + // The allowed key sizes in bits. + protected static $valid_key_sizes = array(128, 192, 256); + + protected static $random_bytes_exists = null; + protected static $openssl_encrypt_exists = null; + protected static $openssl_decrypt_exists = null; + protected static $mcrypt_exists = null; + protected static $mbstring_func_overload = null; + + // This is a static class, instances are disabled. + final private function __construct() {} + final private function __clone() {} + + /** + * Crypt AES (256, 192, 128) + * + * @param string $string The input message to be encrypted. + * @param string $pass The secret pass-phrase, choose a long string + * (64 characters for example) for keeping high entropy. + * The pass-phrase is converted internaly into + * a binary key that is to be used for encryption. + * @return mixed base64 encrypted string, FALSE on failure. + */ + public static function enc($string, $pass) { + + $key_size = self::$key_size; + + // Set a random salt. + $salt = self::random_bytes(8); + + $salted = ''; + $dx = ''; + + // Lengths in bytes: + $key_length = (int) ($key_size / 8); + $block_length = 16; // 128 bits, iv has the same length. + // $salted_length = $key_length (32, 24, 16) + $block_length (16) = (48, 40, 32) + $salted_length = $key_length + $block_length; + + while (self::strlen($salted) < $salted_length) { + + $dx = md5($dx.$pass.$salt, true); + $salted .= $dx; + } + + $key = self::substr($salted, 0, $key_length); + $iv = self::substr($salted, $key_length, $block_length); + + $encrypted = self::aes_cbc_encrypt($string, $key, $iv); + + return $encrypted !== false ? base64_encode('Salted__'.$salt.$encrypted) : false; + } + + /** + * Decrypt AES (256, 192, 128) + * + * @param string $string The input message to be decrypted. + * @param string $pass The secret pass-phrase that has been used for encryption. + * @return mixed base64 decrypted string, FALSE on failure. + */ + public static function dec($string, $pass) { + + $key_size = self::$key_size; + + // Lengths in bytes: + $key_length = (int) ($key_size / 8); + $block_length = 16; + + $data = base64_decode($string); + $salt = self::substr($data, 8, 8); + $encrypted = self::substr($data, 16); + + /** + * From https://github.com/mdp/gibberish-aes + * + * Number of rounds depends on the size of the AES in use + * 3 rounds for 256 + * 2 rounds for the key, 1 for the IV + * 2 rounds for 128 + * 1 round for the key, 1 round for the IV + * 3 rounds for 192 since it's not evenly divided by 128 bits + */ + $rounds = 3; + if ($key_size == 128) { + $rounds = 2; + } + + $data00 = $pass.$salt; + $md5_hash = array(); + $md5_hash[0] = md5($data00, true); + $result = $md5_hash[0]; + + for ($i = 1; $i < $rounds; $i++) { + + $md5_hash[$i] = md5($md5_hash[$i - 1].$data00, true); + $result .= $md5_hash[$i]; + } + + $key = self::substr($result, 0, $key_length); + $iv = self::substr($result, $key_length, $block_length); + + return self::aes_cbc_decrypt($encrypted, $key, $iv); + } + + /** + * Sets the key-size for encryption/decryption in number of bits + * @param mixed $newsize The new key size. The valid integer values are: 128, 192, 256 (default) + * $newsize may be NULL or may be omited - in this case + * this method is just a getter of the current key size value. + * @return integer Returns the old key size value. + */ + public static function size($newsize = null) { + + $result = self::$key_size; + + if (is_null($newsize)) { + return $result; + } + + $newsize = (string) $newsize; + + if ($newsize == '') { + return $result; + } + + $valid_integer = ctype_digit($newsize); + + $newsize = (int) $newsize; + + if (!$valid_integer || !in_array($newsize, self::$valid_key_sizes)) { + trigger_error('GibberishAES: Invalid key size value was to be set. It should be an integer value (number of bits) amongst: '.implode(', ', self::$valid_key_sizes).'.', E_USER_WARNING); + } else { + self::$key_size = $newsize; + } + + return $result; + } + + // Non-public methods ------------------------------------------------------ + + protected static function random_bytes_exists() { + + if (!isset(self::$random_bytes_exists)) { + + self::$random_bytes_exists = false; + + if (function_exists('random_bytes')) { + + try + { + $test = random_bytes(1); + self::$random_bytes_exists = true; + } + catch (Exception $e) { + // Do nothing. + } + } + } + + return self::$random_bytes_exists; + } + + protected static function openssl_encrypt_exists() { + + if (!isset(self::$openssl_encrypt_exists)) { + self::$openssl_encrypt_exists = function_exists('openssl_encrypt') + // We need the $iv parameter. + && version_compare(PHP_VERSION, '5.3.3', '>='); + } + + return self::$openssl_encrypt_exists; + } + + protected static function openssl_decrypt_exists() { + + if (!isset(self::$openssl_decrypt_exists)) { + self::$openssl_decrypt_exists = function_exists('openssl_decrypt') + // We need the $iv parameter. + && version_compare(PHP_VERSION, '5.3.3', '>='); + } + + return self::$openssl_decrypt_exists; + } + + protected static function mcrypt_exists() { + + if (!isset(self::$mcrypt_exists)) { + + if (version_compare(PHP_VERSION, '7.1.0-alpha', '>=')) { + // Avoid using mcrypt on PHP 7.1.x since deprecation notices are thrown. + self::$mcrypt_exists = false; + } else { + self::$mcrypt_exists = function_exists('mcrypt_encrypt'); + } + } + + return self::$mcrypt_exists; + } + + protected static function is_windows() { + + // Beware about 'Darwin'. + return 0 === stripos(PHP_OS, 'win'); + } + + protected static function mbstring_func_overload() { + + if (!isset(self::$mbstring_func_overload)) { + self::$mbstring_func_overload = extension_loaded('mbstring') && ini_get('mbstring.func_overload'); + } + + return self::$mbstring_func_overload; + } + + protected static function strlen($str) { + + return self::mbstring_func_overload() ? mb_strlen($str, '8bit') : strlen($str); + } + + protected static function substr($str, $start, $length = null) { + + if (self::mbstring_func_overload()) { + + // mb_substr($str, $start, null, '8bit') returns an empty string on PHP 5.3 + isset($length) OR $length = ($start >= 0 ? self::strlen($str) - $start : -$start); + + return mb_substr($str, $start, $length, '8bit'); + } + + return isset($length) ? substr($str, $start, $length) : substr($str, $start); + } + + protected static function random_bytes($length) { + + $length = (int) $length; + + if (self::random_bytes_exists()) { + + try + { + return random_bytes($length); + } + catch (Exception $e) { + // Do nothing, continue. + } + } + + // Rename the parameter on order it to fit with the code below. + $len = $length; + + /* + * The following code fragment has been taken from Secure-random-bytes-in-PHP + * project, released under the New BSD License. + * @see https://github.com/GeorgeArgyros/Secure-random-bytes-in-PHP + * + * + * + * Author: + * George Argyros + * + * Copyright (c) 2012, George Argyros + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL GEORGE ARGYROS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * + * The function is providing, at least at the systems tested :), + * $len bytes of entropy under any PHP installation or operating system. + * The execution time should be at most 10-20 ms in any system. + */ + + $SSLstr = '4'; // http://xkcd.com/221/ + + /* + * No build-in crypto randomness function found. We collect any entropy + * available in the PHP core PRNGs along with some filesystem info and memory + * stats. To make this data cryptographically strong we add data either from + * /dev/urandom or if its unavailable, we gather entropy by measuring the + * time needed to compute a number of SHA-1 hashes. + */ + $str = ''; + $bits_per_round = 2; // bits of entropy collected in each clock drift round + $msec_per_round = 400; // expected running time of each round in microseconds + $hash_len = 20; // SHA-1 Hash length + $total = $len; // total bytes of entropy to collect + $handle = @fopen('/dev/urandom', 'rb'); + if ($handle && function_exists('stream_set_read_buffer')) { + @stream_set_read_buffer($handle, 0); + } + + do { + $bytes = ($total > $hash_len) ? $hash_len : $total; + $total -= $bytes; + //collect any entropy available from the PHP system and filesystem + $entropy = rand() . uniqid(mt_rand(), true) . $SSLstr; + $entropy .= implode('', @fstat(@fopen(__FILE__, 'r'))); + $entropy .= memory_get_usage() . getmypid(); + $entropy .= serialize($_ENV) . serialize($_SERVER); + if (function_exists('posix_times')) { + $entropy .= serialize(posix_times()); + } + if (function_exists('zend_thread_id')) { + $entropy .= zend_thread_id(); + } + if ($handle) { + $entropy .= @fread($handle, $bytes); + } else { + // Measure the time that the operations will take on average + for ($i = 0; $i < 3; $i++) { + $c1 = microtime(true); + $var = sha1(mt_rand()); + for ($j = 0; $j < 50; $j++) { + $var = sha1($var); + } + $c2 = microtime(true); + $entropy .= $c1 . $c2; + } + // Based on the above measurement determine the total rounds + // in order to bound the total running time. + $rounds = (int) ($msec_per_round * 50 / (int) (($c2 - $c1) * 1000000)); + // Take the additional measurements. On average we can expect + // at least $bits_per_round bits of entropy from each measurement. + $iter = $bytes * (int) (ceil(8 / $bits_per_round)); + for ($i = 0; $i < $iter; $i++) { + $c1 = microtime(); + $var = sha1(mt_rand()); + for ($j = 0; $j < $rounds; $j++) { + $var = sha1($var); + } + $c2 = microtime(); + $entropy .= $c1 . $c2; + } + } + // We assume sha1 is a deterministic extractor for the $entropy variable. + $str .= sha1($entropy, true); + + // Modified by Ivan Tcholakov, 16-MAR-2015. + //} while ($len > strlen($str)); + } while ($len > self::strlen($str)); + // + + if ($handle) { + @fclose($handle); + } + + // Modified by Ivan Tcholakov, 16-MAR-2015. + //return substr($str, 0, $len); + return self::substr($str, 0, $len); + // + + /* + * End of code fragment from Secure-random-bytes-in-PHP project. + */ + } + + protected static function aes_cbc_encrypt($string, $key, $iv) { + + $key_size = self::$key_size; + + if (self::openssl_encrypt_exists()) { + return openssl_encrypt($string, "aes-$key_size-cbc", $key, true, $iv); + } + + if (self::mcrypt_exists()) { + + // Info: http://www.chilkatsoft.com/p/php_aes.asp + // http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation + + $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, ''); + + if (mcrypt_generic_init($cipher, $key, $iv) != -1) { + + $encrypted = mcrypt_generic($cipher, self::pkcs7_pad($string)); + mcrypt_generic_deinit($cipher); + mcrypt_module_close($cipher); + + return $encrypted; + } + + return false; + } + + trigger_error('GibberishAES: System requirements failure, please, check them.', E_USER_WARNING); + + return false; + } + + protected static function aes_cbc_decrypt($crypted, $key, $iv) { + + $key_size = self::$key_size; + + if (self::openssl_decrypt_exists()) { + return openssl_decrypt($crypted, "aes-$key_size-cbc", $key, true, $iv); + } + + if (self::mcrypt_exists()) { + + $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, ''); + + if (mcrypt_generic_init($cipher, $key, $iv) != -1) { + + $decrypted = mdecrypt_generic($cipher, $crypted); + mcrypt_generic_deinit($cipher); + mcrypt_module_close($cipher); + + return self::remove_pkcs7_pad($decrypted); + } + + return false; + } + + trigger_error('GibberishAES: System requirements failure, please, check them.', E_USER_WARNING); + + return false; + } + + // See http://www.php.net/manual/en/function.mcrypt-decrypt.php#105985 + + protected static function pkcs7_pad($string) { + + // 128 bits: $block_length = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); + $block_length = 16; + $pad = $block_length - (self::strlen($string) % $block_length); + + return $string.str_repeat(chr($pad), $pad); + } + + protected static function remove_pkcs7_pad($string) { + + // 128 bits: $block_length = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); + $block_length = 16; + $len = self::strlen($string); + $pad = ord($string[$len - 1]); + + if ($pad > 0 && $pad <= $block_length) { + + $valid_pad = true; + + for ($i = 1; $i <= $pad; $i++) { + + if (ord($string[$len - $i]) != $pad) { + $valid_pad = false; + break; + } + } + + if ($valid_pad) { + $string = self::substr($string, 0, $len - $pad); + } + } + + return $string; + } + +} diff --git a/core/func/libs/google/FixedByteNotation.php b/core/func/libs/google/FixedByteNotation.php new file mode 100644 index 0000000..97d22f7 --- /dev/null +++ b/core/func/libs/google/FixedByteNotation.php @@ -0,0 +1,276 @@ += ($radix <<= 1) && $bitsPerCharacter < 8) { + $bitsPerCharacter++; + } + + $radix >>= 1; + + } elseif ($bitsPerCharacter > 8) { + // $bitsPerCharacter must not be greater than 8 + $bitsPerCharacter = 8; + $radix = 256; + + } else { + $radix = 1 << $bitsPerCharacter; + } + + $this->_chars = $chars; + $this->_bitsPerCharacter = $bitsPerCharacter; + $this->_radix = $radix; + $this->_rightPadFinalBits = $rightPadFinalBits; + $this->_padFinalGroup = $padFinalGroup; + $this->_padCharacter = $padCharacter[0]; + } + + /** + * Encode a string + * + * @param string $rawString Binary data to encode + * @return string + */ + public function encode($rawString) + { + // Unpack string into an array of bytes + $bytes = unpack('C*', $rawString); + $byteCount = count($bytes); + + $encodedString = ''; + $byte = array_shift($bytes); + $bitsRead = 0; + + $chars = $this->_chars; + $bitsPerCharacter = $this->_bitsPerCharacter; + $rightPadFinalBits = $this->_rightPadFinalBits; + $padFinalGroup = $this->_padFinalGroup; + $padCharacter = $this->_padCharacter; + + // Generate encoded output; + // each loop produces one encoded character + for ($c = 0; $c < $byteCount * 8 / $bitsPerCharacter; $c++) { + + // Get the bits needed for this encoded character + if ($bitsRead + $bitsPerCharacter > 8) { + // Not enough bits remain in this byte for the current + // character + // Save the remaining bits before getting the next byte + $oldBitCount = 8 - $bitsRead; + $oldBits = $byte ^ ($byte >> $oldBitCount << $oldBitCount); + $newBitCount = $bitsPerCharacter - $oldBitCount; + + if (!$bytes) { + // Last bits; match final character and exit loop + if ($rightPadFinalBits) $oldBits <<= $newBitCount; + $encodedString .= $chars[$oldBits]; + + if ($padFinalGroup) { + // Array of the lowest common multiples of + // $bitsPerCharacter and 8, divided by 8 + $lcmMap = array(1 => 1, 2 => 1, 3 => 3, 4 => 1, + 5 => 5, 6 => 3, 7 => 7, 8 => 1); + $bytesPerGroup = $lcmMap[$bitsPerCharacter]; + $pads = $bytesPerGroup * 8 / $bitsPerCharacter + - ceil((strlen($rawString) % $bytesPerGroup) + * 8 / $bitsPerCharacter); + $encodedString .= str_repeat($padCharacter[0], $pads); + } + + break; + } + + // Get next byte + $byte = array_shift($bytes); + $bitsRead = 0; + + } else { + $oldBitCount = 0; + $newBitCount = $bitsPerCharacter; + } + + // Read only the needed bits from this byte + $bits = $byte >> 8 - ($bitsRead + ($newBitCount)); + $bits ^= $bits >> $newBitCount << $newBitCount; + $bitsRead += $newBitCount; + + if ($oldBitCount) { + // Bits come from seperate bytes, add $oldBits to $bits + $bits = ($oldBits << $newBitCount) | $bits; + } + + $encodedString .= $chars[$bits]; + } + + return $encodedString; + } + + /** + * Decode a string + * + * @param string $encodedString Data to decode + * @param boolean $caseSensitive + * @param boolean $strict Returns NULL if $encodedString contains + * an undecodable character + * @return string|NULL + */ + public function decode($encodedString, $caseSensitive = TRUE, + $strict = FALSE) + { + if (!$encodedString || !is_string($encodedString)) { + // Empty string, nothing to decode + return ''; + } + + $chars = $this->_chars; + $bitsPerCharacter = $this->_bitsPerCharacter; + $radix = $this->_radix; + $rightPadFinalBits = $this->_rightPadFinalBits; + $padFinalGroup = $this->_padFinalGroup; + $padCharacter = $this->_padCharacter; + + // Get index of encoded characters + if ($this->_charmap) { + $charmap = $this->_charmap; + + } else { + $charmap = array(); + + for ($i = 0; $i < $radix; $i++) { + $charmap[$chars[$i]] = $i; + } + + $this->_charmap = $charmap; + } + + // The last encoded character is $encodedString[$lastNotatedIndex] + $lastNotatedIndex = strlen($encodedString) - 1; + + // Remove trailing padding characters + while ($encodedString[$lastNotatedIndex] == $padCharacter[0]) { + $encodedString = substr($encodedString, 0, $lastNotatedIndex); + $lastNotatedIndex--; + } + + $rawString = ''; + $byte = 0; + $bitsWritten = 0; + + // Convert each encoded character to a series of unencoded bits + for ($c = 0; $c <= $lastNotatedIndex; $c++) { + + if (!isset($charmap[$encodedString[$c]]) && !$caseSensitive) { + // Encoded character was not found; try other case + if (isset($charmap[$cUpper + = strtoupper($encodedString[$c])])) { + $charmap[$encodedString[$c]] = $charmap[$cUpper]; + + } elseif (isset($charmap[$cLower + = strtolower($encodedString[$c])])) { + $charmap[$encodedString[$c]] = $charmap[$cLower]; + } + } + + if (isset($charmap[$encodedString[$c]])) { + $bitsNeeded = 8 - $bitsWritten; + $unusedBitCount = $bitsPerCharacter - $bitsNeeded; + + // Get the new bits ready + if ($bitsNeeded > $bitsPerCharacter) { + // New bits aren't enough to complete a byte; shift them + // left into position + $newBits = $charmap[$encodedString[$c]] << $bitsNeeded + - $bitsPerCharacter; + $bitsWritten += $bitsPerCharacter; + + } elseif ($c != $lastNotatedIndex || $rightPadFinalBits) { + // Zero or more too many bits to complete a byte; + // shift right + $newBits = $charmap[$encodedString[$c]] >> $unusedBitCount; + $bitsWritten = 8; //$bitsWritten += $bitsNeeded; + + } else { + // Final bits don't need to be shifted + $newBits = $charmap[$encodedString[$c]]; + $bitsWritten = 8; + } + + $byte |= $newBits; + + if ($bitsWritten == 8 || $c == $lastNotatedIndex) { + // Byte is ready to be written + $rawString .= pack('C', $byte); + + if ($c != $lastNotatedIndex) { + // Start the next byte + $bitsWritten = $unusedBitCount; + $byte = ($charmap[$encodedString[$c]] + ^ ($newBits << $unusedBitCount)) << 8 - $bitsWritten; + } + } + + } elseif ($strict) { + // Unable to decode character; abort + return NULL; + } + } + + return $rawString; + } +} diff --git a/core/func/libs/google/GoogleAuthenticator.php b/core/func/libs/google/GoogleAuthenticator.php new file mode 100644 index 0000000..c986f38 --- /dev/null +++ b/core/func/libs/google/GoogleAuthenticator.php @@ -0,0 +1,90 @@ +getCode($secret,$time + $i) == $code) { + return true; + } + } + + return false; + + } + + public function getCode($secret,$time = null) { + + if (!$time) { + $time = floor(time() / 30); + } + $base32 = new FixedBitNotation(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', TRUE, TRUE); + $secret = $base32->decode($secret); + + $time = pack("N", $time); + $time = str_pad($time,8, chr(0), STR_PAD_LEFT); + + $hash = hash_hmac('sha1',$time,$secret,true); + $offset = ord(substr($hash,-1)); + $offset = $offset & 0xF; + + $truncatedHash = self::hashToInt($hash, $offset) & 0x7FFFFFFF; + $pinValue = str_pad($truncatedHash % self::$PIN_MODULO,6,"0",STR_PAD_LEFT);; + return $pinValue; + } + + protected function hashToInt($bytes, $start) { + $input = substr($bytes, $start, strlen($bytes) - $start); + $val2 = unpack("N",substr($input,0,4)); + return $val2[1]; + } + + public function getUrl($user, $hostname, $secret) { + $url = sprintf("otpauth://totp/%s@%s&secret=%s", $user, $hostname, $secret); + $encoder = "https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl="; + $encoderURL = sprintf( "%sotpauth://totp/%s@%s&secret=%s",$encoder, $user, $hostname, $secret); + + $encoderURL = str_replace("&secret", "?secret", $encoderURL); + + return $encoderURL; + + } + + public function generateSecret() { + $secret = ""; + for($i = 1; $i<= self::$SECRET_LENGTH;$i++) { + $c = rand(0,255); + $secret .= pack("c",$c); + } + $base32 = new FixedBitNotation(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', TRUE, TRUE); + return $base32->encode($secret); + + + } + +} + diff --git a/core/func/libs/mail/PHPMailerAutoload.php b/core/func/libs/mail/PHPMailerAutoload.php new file mode 100644 index 0000000..eaa2e30 --- /dev/null +++ b/core/func/libs/mail/PHPMailerAutoload.php @@ -0,0 +1,49 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2014 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +/** + * PHPMailer SPL autoloader. + * @param string $classname The name of the class to load + */ +function PHPMailerAutoload($classname) +{ + //Can't use __DIR__ as it's only in PHP 5.3+ + $filename = dirname(__FILE__).DIRECTORY_SEPARATOR.'class.'.strtolower($classname).'.php'; + if (is_readable($filename)) { + require $filename; + } +} + +if (version_compare(PHP_VERSION, '5.1.2', '>=')) { + //SPL autoloading was introduced in PHP 5.1.2 + if (version_compare(PHP_VERSION, '5.3.0', '>=')) { + spl_autoload_register('PHPMailerAutoload', true, true); + } else { + spl_autoload_register('PHPMailerAutoload'); + } +} else { + /** + * Fall back to traditional autoload for old PHP versions + * @param string $classname The name of the class to load + */ + function __autoload($classname) + { + PHPMailerAutoload($classname); + } +} diff --git a/core/func/libs/mail/class.phpmailer.php b/core/func/libs/mail/class.phpmailer.php new file mode 100644 index 0000000..b7d7f7a --- /dev/null +++ b/core/func/libs/mail/class.phpmailer.php @@ -0,0 +1,3966 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2014 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +/** + * PHPMailer - PHP email creation and transport class. + * @package PHPMailer + * @author Marcus Bointon (Synchro/coolbru) + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + */ +class PHPMailer +{ + /** + * The PHPMailer Version number. + * @var string + */ + public $Version = '5.2.16'; + + /** + * Email priority. + * Options: null (default), 1 = High, 3 = Normal, 5 = low. + * When null, the header is not set at all. + * @var integer + */ + public $Priority = null; + + /** + * The character set of the message. + * @var string + */ + public $CharSet = 'iso-8859-1'; + + /** + * The MIME Content-type of the message. + * @var string + */ + public $ContentType = 'text/plain'; + + /** + * The message encoding. + * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable". + * @var string + */ + public $Encoding = '8bit'; + + /** + * Holds the most recent mailer error message. + * @var string + */ + public $ErrorInfo = ''; + + /** + * The From email address for the message. + * @var string + */ + public $From = 'root@localhost'; + + /** + * The From name of the message. + * @var string + */ + public $FromName = 'Root User'; + + /** + * The Sender email (Return-Path) of the message. + * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode. + * @var string + */ + public $Sender = ''; + + /** + * The Return-Path of the message. + * If empty, it will be set to either From or Sender. + * @var string + * @deprecated Email senders should never set a return-path header; + * it's the receiver's job (RFC5321 section 4.4), so this no longer does anything. + * @link https://tools.ietf.org/html/rfc5321#section-4.4 RFC5321 reference + */ + public $ReturnPath = ''; + + /** + * The Subject of the message. + * @var string + */ + public $Subject = ''; + + /** + * An HTML or plain text message body. + * If HTML then call isHTML(true). + * @var string + */ + public $Body = ''; + + /** + * The plain-text message body. + * This body can be read by mail clients that do not have HTML email + * capability such as mutt & Eudora. + * Clients that can read HTML will view the normal Body. + * @var string + */ + public $AltBody = ''; + + /** + * An iCal message part body. + * Only supported in simple alt or alt_inline message types + * To generate iCal events, use the bundled extras/EasyPeasyICS.php class or iCalcreator + * @link http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/ + * @link http://kigkonsult.se/iCalcreator/ + * @var string + */ + public $Ical = ''; + + /** + * The complete compiled MIME message body. + * @access protected + * @var string + */ + protected $MIMEBody = ''; + + /** + * The complete compiled MIME message headers. + * @var string + * @access protected + */ + protected $MIMEHeader = ''; + + /** + * Extra headers that createHeader() doesn't fold in. + * @var string + * @access protected + */ + protected $mailHeader = ''; + + /** + * Word-wrap the message body to this number of chars. + * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance. + * @var integer + */ + public $WordWrap = 0; + + /** + * Which method to use to send mail. + * Options: "mail", "sendmail", or "smtp". + * @var string + */ + public $Mailer = 'mail'; + + /** + * The path to the sendmail program. + * @var string + */ + public $Sendmail = '/usr/sbin/sendmail'; + + /** + * Whether mail() uses a fully sendmail-compatible MTA. + * One which supports sendmail's "-oi -f" options. + * @var boolean + */ + public $UseSendmailOptions = true; + + /** + * Path to PHPMailer plugins. + * Useful if the SMTP class is not in the PHP include path. + * @var string + * @deprecated Should not be needed now there is an autoloader. + */ + public $PluginDir = ''; + + /** + * The email address that a reading confirmation should be sent to, also known as read receipt. + * @var string + */ + public $ConfirmReadingTo = ''; + + /** + * The hostname to use in the Message-ID header and as default HELO string. + * If empty, PHPMailer attempts to find one with, in order, + * $_SERVER['SERVER_NAME'], gethostname(), php_uname('n'), or the value + * 'localhost.localdomain'. + * @var string + */ + public $Hostname = ''; + + /** + * An ID to be used in the Message-ID header. + * If empty, a unique id will be generated. + * You can set your own, but it must be in the format "", + * as defined in RFC5322 section 3.6.4 or it will be ignored. + * @see https://tools.ietf.org/html/rfc5322#section-3.6.4 + * @var string + */ + public $MessageID = ''; + + /** + * The message Date to be used in the Date header. + * If empty, the current date will be added. + * @var string + */ + public $MessageDate = ''; + + /** + * SMTP hosts. + * Either a single hostname or multiple semicolon-delimited hostnames. + * You can also specify a different port + * for each host by using this format: [hostname:port] + * (e.g. "smtp1.example.com:25;smtp2.example.com"). + * You can also specify encryption type, for example: + * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465"). + * Hosts will be tried in order. + * @var string + */ + public $Host = 'localhost'; + + /** + * The default SMTP server port. + * @var integer + * @TODO Why is this needed when the SMTP class takes care of it? + */ + public $Port = 25; + + /** + * The SMTP HELO of the message. + * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find + * one with the same method described above for $Hostname. + * @var string + * @see PHPMailer::$Hostname + */ + public $Helo = ''; + + /** + * What kind of encryption to use on the SMTP connection. + * Options: '', 'ssl' or 'tls' + * @var string + */ + public $SMTPSecure = ''; + + /** + * Whether to enable TLS encryption automatically if a server supports it, + * even if `SMTPSecure` is not set to 'tls'. + * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid. + * @var boolean + */ + public $SMTPAutoTLS = true; + + /** + * Whether to use SMTP authentication. + * Uses the Username and Password properties. + * @var boolean + * @see PHPMailer::$Username + * @see PHPMailer::$Password + */ + public $SMTPAuth = false; + + /** + * Options array passed to stream_context_create when connecting via SMTP. + * @var array + */ + public $SMTPOptions = array(); + + /** + * SMTP username. + * @var string + */ + public $Username = ''; + + /** + * SMTP password. + * @var string + */ + public $Password = ''; + + /** + * SMTP auth type. + * Options are CRAM-MD5, LOGIN, PLAIN, NTLM, XOAUTH2, attempted in that order if not specified + * @var string + */ + public $AuthType = ''; + + /** + * SMTP realm. + * Used for NTLM auth + * @var string + */ + public $Realm = ''; + + /** + * SMTP workstation. + * Used for NTLM auth + * @var string + */ + public $Workstation = ''; + + /** + * The SMTP server timeout in seconds. + * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2 + * @var integer + */ + public $Timeout = 300; + + /** + * SMTP class debug output mode. + * Debug output level. + * Options: + * * `0` No output + * * `1` Commands + * * `2` Data and commands + * * `3` As 2 plus connection status + * * `4` Low-level data output + * @var integer + * @see SMTP::$do_debug + */ + public $SMTPDebug = 0; + + /** + * How to handle debug output. + * Options: + * * `echo` Output plain-text as-is, appropriate for CLI + * * `html` Output escaped, line breaks converted to `
    `, appropriate for browser output + * * `error_log` Output to error log as configured in php.ini + * + * Alternatively, you can provide a callable expecting two params: a message string and the debug level: + * + * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";}; + * + * @var string|callable + * @see SMTP::$Debugoutput + */ + public $Debugoutput = 'echo'; + + /** + * Whether to keep SMTP connection open after each message. + * If this is set to true then to close the connection + * requires an explicit call to smtpClose(). + * @var boolean + */ + public $SMTPKeepAlive = false; + + /** + * Whether to split multiple to addresses into multiple messages + * or send them all in one message. + * Only supported in `mail` and `sendmail` transports, not in SMTP. + * @var boolean + */ + public $SingleTo = false; + + /** + * Storage for addresses when SingleTo is enabled. + * @var array + * @TODO This should really not be public + */ + public $SingleToArray = array(); + + /** + * Whether to generate VERP addresses on send. + * Only applicable when sending via SMTP. + * @link https://en.wikipedia.org/wiki/Variable_envelope_return_path + * @link http://www.postfix.org/VERP_README.html Postfix VERP info + * @var boolean + */ + public $do_verp = false; + + /** + * Whether to allow sending messages with an empty body. + * @var boolean + */ + public $AllowEmpty = false; + + /** + * The default line ending. + * @note The default remains "\n". We force CRLF where we know + * it must be used via self::CRLF. + * @var string + */ + public $LE = "\n"; + + /** + * DKIM selector. + * @var string + */ + public $DKIM_selector = ''; + + /** + * DKIM Identity. + * Usually the email address used as the source of the email. + * @var string + */ + public $DKIM_identity = ''; + + /** + * DKIM passphrase. + * Used if your key is encrypted. + * @var string + */ + public $DKIM_passphrase = ''; + + /** + * DKIM signing domain name. + * @example 'example.com' + * @var string + */ + public $DKIM_domain = ''; + + /** + * DKIM private key file path. + * @var string + */ + public $DKIM_private = ''; + + /** + * Callback Action function name. + * + * The function that handles the result of the send email action. + * It is called out by send() for each email sent. + * + * Value can be any php callable: http://www.php.net/is_callable + * + * Parameters: + * boolean $result result of the send action + * string $to email address of the recipient + * string $cc cc email addresses + * string $bcc bcc email addresses + * string $subject the subject + * string $body the email body + * string $from email address of sender + * @var string + */ + public $action_function = ''; + + /** + * What to put in the X-Mailer header. + * Options: An empty string for PHPMailer default, whitespace for none, or a string to use + * @var string + */ + public $XMailer = ''; + + /** + * Which validator to use by default when validating email addresses. + * May be a callable to inject your own validator, but there are several built-in validators. + * @see PHPMailer::validateAddress() + * @var string|callable + * @static + */ + public static $validator = 'auto'; + + /** + * An instance of the SMTP sender class. + * @var SMTP + * @access protected + */ + protected $smtp = null; + + /** + * The array of 'to' names and addresses. + * @var array + * @access protected + */ + protected $to = array(); + + /** + * The array of 'cc' names and addresses. + * @var array + * @access protected + */ + protected $cc = array(); + + /** + * The array of 'bcc' names and addresses. + * @var array + * @access protected + */ + protected $bcc = array(); + + /** + * The array of reply-to names and addresses. + * @var array + * @access protected + */ + protected $ReplyTo = array(); + + /** + * An array of all kinds of addresses. + * Includes all of $to, $cc, $bcc + * @var array + * @access protected + * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc + */ + protected $all_recipients = array(); + + /** + * An array of names and addresses queued for validation. + * In send(), valid and non duplicate entries are moved to $all_recipients + * and one of $to, $cc, or $bcc. + * This array is used only for addresses with IDN. + * @var array + * @access protected + * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc + * @see PHPMailer::$all_recipients + */ + protected $RecipientsQueue = array(); + + /** + * An array of reply-to names and addresses queued for validation. + * In send(), valid and non duplicate entries are moved to $ReplyTo. + * This array is used only for addresses with IDN. + * @var array + * @access protected + * @see PHPMailer::$ReplyTo + */ + protected $ReplyToQueue = array(); + + /** + * The array of attachments. + * @var array + * @access protected + */ + protected $attachment = array(); + + /** + * The array of custom headers. + * @var array + * @access protected + */ + protected $CustomHeader = array(); + + /** + * The most recent Message-ID (including angular brackets). + * @var string + * @access protected + */ + protected $lastMessageID = ''; + + /** + * The message's MIME type. + * @var string + * @access protected + */ + protected $message_type = ''; + + /** + * The array of MIME boundary strings. + * @var array + * @access protected + */ + protected $boundary = array(); + + /** + * The array of available languages. + * @var array + * @access protected + */ + protected $language = array(); + + /** + * The number of errors encountered. + * @var integer + * @access protected + */ + protected $error_count = 0; + + /** + * The S/MIME certificate file path. + * @var string + * @access protected + */ + protected $sign_cert_file = ''; + + /** + * The S/MIME key file path. + * @var string + * @access protected + */ + protected $sign_key_file = ''; + + /** + * The optional S/MIME extra certificates ("CA Chain") file path. + * @var string + * @access protected + */ + protected $sign_extracerts_file = ''; + + /** + * The S/MIME password for the key. + * Used only if the key is encrypted. + * @var string + * @access protected + */ + protected $sign_key_pass = ''; + + /** + * Whether to throw exceptions for errors. + * @var boolean + * @access protected + */ + protected $exceptions = false; + + /** + * Unique ID used for message ID and boundaries. + * @var string + * @access protected + */ + protected $uniqueid = ''; + + /** + * Error severity: message only, continue processing. + */ + const STOP_MESSAGE = 0; + + /** + * Error severity: message, likely ok to continue processing. + */ + const STOP_CONTINUE = 1; + + /** + * Error severity: message, plus full stop, critical error reached. + */ + const STOP_CRITICAL = 2; + + /** + * SMTP RFC standard line ending. + */ + const CRLF = "\r\n"; + + /** + * The maximum line length allowed by RFC 2822 section 2.1.1 + * @var integer + */ + const MAX_LINE_LENGTH = 998; + + /** + * Constructor. + * @param boolean $exceptions Should we throw external exceptions? + */ + public function __construct($exceptions = null) + { + if ($exceptions !== null) { + $this->exceptions = (boolean)$exceptions; + } + } + + /** + * Destructor. + */ + public function __destruct() + { + //Close any open SMTP connection nicely + $this->smtpClose(); + } + + /** + * Call mail() in a safe_mode-aware fashion. + * Also, unless sendmail_path points to sendmail (or something that + * claims to be sendmail), don't pass params (not a perfect fix, + * but it will do) + * @param string $to To + * @param string $subject Subject + * @param string $body Message Body + * @param string $header Additional Header(s) + * @param string $params Params + * @access private + * @return boolean + */ + private function mailPassthru($to, $subject, $body, $header, $params) + { + //Check overloading of mail function to avoid double-encoding + if (ini_get('mbstring.func_overload') & 1) { + $subject = $this->secureHeader($subject); + } else { + $subject = $this->encodeHeader($this->secureHeader($subject)); + } + + //Can't use additional_parameters in safe_mode + //@link http://php.net/manual/en/function.mail.php + if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) { + $result = @mail($to, $subject, $body, $header); + } else { + $result = @mail($to, $subject, $body, $header, $params); + } + return $result; + } + /** + * Output debugging info via user-defined method. + * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug). + * @see PHPMailer::$Debugoutput + * @see PHPMailer::$SMTPDebug + * @param string $str + */ + protected function edebug($str) + { + if ($this->SMTPDebug <= 0) { + return; + } + //Avoid clash with built-in function names + if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) { + call_user_func($this->Debugoutput, $str, $this->SMTPDebug); + return; + } + switch ($this->Debugoutput) { + case 'error_log': + //Don't output, just log + error_log($str); + break; + case 'html': + //Cleans up output a bit for a better looking, HTML-safe output + echo htmlentities( + preg_replace('/[\r\n]+/', '', $str), + ENT_QUOTES, + 'UTF-8' + ) + . "
    \n"; + break; + case 'echo': + default: + //Normalize line breaks + $str = preg_replace('/\r\n?/ms', "\n", $str); + echo gmdate('Y-m-d H:i:s') . "\t" . str_replace( + "\n", + "\n \t ", + trim($str) + ) . "\n"; + } + } + + /** + * Sets message type to HTML or plain. + * @param boolean $isHtml True for HTML mode. + * @return void + */ + public function isHTML($isHtml = true) + { + if ($isHtml) { + $this->ContentType = 'text/html'; + } else { + $this->ContentType = 'text/plain'; + } + } + + /** + * Send messages using SMTP. + * @return void + */ + public function isSMTP() + { + $this->Mailer = 'smtp'; + } + + /** + * Send messages using PHP's mail() function. + * @return void + */ + public function isMail() + { + $this->Mailer = 'mail'; + } + + /** + * Send messages using $Sendmail. + * @return void + */ + public function isSendmail() + { + $ini_sendmail_path = ini_get('sendmail_path'); + + if (!stristr($ini_sendmail_path, 'sendmail')) { + $this->Sendmail = '/usr/sbin/sendmail'; + } else { + $this->Sendmail = $ini_sendmail_path; + } + $this->Mailer = 'sendmail'; + } + + /** + * Send messages using qmail. + * @return void + */ + public function isQmail() + { + $ini_sendmail_path = ini_get('sendmail_path'); + + if (!stristr($ini_sendmail_path, 'qmail')) { + $this->Sendmail = '/var/qmail/bin/qmail-inject'; + } else { + $this->Sendmail = $ini_sendmail_path; + } + $this->Mailer = 'qmail'; + } + + /** + * Add a "To" address. + * @param string $address The email address to send to + * @param string $name + * @return boolean true on success, false if address already used or invalid in some way + */ + public function addAddress($address, $name = '') + { + return $this->addOrEnqueueAnAddress('to', $address, $name); + } + + /** + * Add a "CC" address. + * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer. + * @param string $address The email address to send to + * @param string $name + * @return boolean true on success, false if address already used or invalid in some way + */ + public function addCC($address, $name = '') + { + return $this->addOrEnqueueAnAddress('cc', $address, $name); + } + + /** + * Add a "BCC" address. + * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer. + * @param string $address The email address to send to + * @param string $name + * @return boolean true on success, false if address already used or invalid in some way + */ + public function addBCC($address, $name = '') + { + return $this->addOrEnqueueAnAddress('bcc', $address, $name); + } + + /** + * Add a "Reply-To" address. + * @param string $address The email address to reply to + * @param string $name + * @return boolean true on success, false if address already used or invalid in some way + */ + public function addReplyTo($address, $name = '') + { + return $this->addOrEnqueueAnAddress('Reply-To', $address, $name); + } + + /** + * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer + * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still + * be modified after calling this function), addition of such addresses is delayed until send(). + * Addresses that have been added already return false, but do not throw exceptions. + * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo' + * @param string $address The email address to send, resp. to reply to + * @param string $name + * @throws phpmailerException + * @return boolean true on success, false if address already used or invalid in some way + * @access protected + */ + protected function addOrEnqueueAnAddress($kind, $address, $name) + { + $address = trim($address); + $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim + if (($pos = strrpos($address, '@')) === false) { + // At-sign is misssing. + $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address"; + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new phpmailerException($error_message); + } + return false; + } + $params = array($kind, $address, $name); + // Enqueue addresses with IDN until we know the PHPMailer::$CharSet. + if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) { + if ($kind != 'Reply-To') { + if (!array_key_exists($address, $this->RecipientsQueue)) { + $this->RecipientsQueue[$address] = $params; + return true; + } + } else { + if (!array_key_exists($address, $this->ReplyToQueue)) { + $this->ReplyToQueue[$address] = $params; + return true; + } + } + return false; + } + // Immediately add standard addresses without IDN. + return call_user_func_array(array($this, 'addAnAddress'), $params); + } + + /** + * Add an address to one of the recipient arrays or to the ReplyTo array. + * Addresses that have been added already return false, but do not throw exceptions. + * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo' + * @param string $address The email address to send, resp. to reply to + * @param string $name + * @throws phpmailerException + * @return boolean true on success, false if address already used or invalid in some way + * @access protected + */ + protected function addAnAddress($kind, $address, $name = '') + { + if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) { + $error_message = $this->lang('Invalid recipient kind: ') . $kind; + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new phpmailerException($error_message); + } + return false; + } + if (!$this->validateAddress($address)) { + $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address"; + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new phpmailerException($error_message); + } + return false; + } + if ($kind != 'Reply-To') { + if (!array_key_exists(strtolower($address), $this->all_recipients)) { + array_push($this->$kind, array($address, $name)); + $this->all_recipients[strtolower($address)] = true; + return true; + } + } else { + if (!array_key_exists(strtolower($address), $this->ReplyTo)) { + $this->ReplyTo[strtolower($address)] = array($address, $name); + return true; + } + } + return false; + } + + /** + * Parse and validate a string containing one or more RFC822-style comma-separated email addresses + * of the form "display name
    " into an array of name/address pairs. + * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available. + * Note that quotes in the name part are removed. + * @param string $addrstr The address list string + * @param bool $useimap Whether to use the IMAP extension to parse the list + * @return array + * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation + */ + public function parseAddresses($addrstr, $useimap = true) + { + $addresses = array(); + if ($useimap and function_exists('imap_rfc822_parse_adrlist')) { + //Use this built-in parser if it's available + $list = imap_rfc822_parse_adrlist($addrstr, ''); + foreach ($list as $address) { + if ($address->host != '.SYNTAX-ERROR.') { + if ($this->validateAddress($address->mailbox . '@' . $address->host)) { + $addresses[] = array( + 'name' => (property_exists($address, 'personal') ? $address->personal : ''), + 'address' => $address->mailbox . '@' . $address->host + ); + } + } + } + } else { + //Use this simpler parser + $list = explode(',', $addrstr); + foreach ($list as $address) { + $address = trim($address); + //Is there a separate name part? + if (strpos($address, '<') === false) { + //No separate name, just use the whole thing + if ($this->validateAddress($address)) { + $addresses[] = array( + 'name' => '', + 'address' => $address + ); + } + } else { + list($name, $email) = explode('<', $address); + $email = trim(str_replace('>', '', $email)); + if ($this->validateAddress($email)) { + $addresses[] = array( + 'name' => trim(str_replace(array('"', "'"), '', $name)), + 'address' => $email + ); + } + } + } + } + return $addresses; + } + + /** + * Set the From and FromName properties. + * @param string $address + * @param string $name + * @param boolean $auto Whether to also set the Sender address, defaults to true + * @throws phpmailerException + * @return boolean + */ + public function setFrom($address, $name = '', $auto = true) + { + $address = trim($address); + $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim + // Don't validate now addresses with IDN. Will be done in send(). + if (($pos = strrpos($address, '@')) === false or + (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and + !$this->validateAddress($address)) { + $error_message = $this->lang('invalid_address') . " (setFrom) $address"; + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new phpmailerException($error_message); + } + return false; + } + $this->From = $address; + $this->FromName = $name; + if ($auto) { + if (empty($this->Sender)) { + $this->Sender = $address; + } + } + return true; + } + + /** + * Return the Message-ID header of the last email. + * Technically this is the value from the last time the headers were created, + * but it's also the message ID of the last sent message except in + * pathological cases. + * @return string + */ + public function getLastMessageID() + { + return $this->lastMessageID; + } + + /** + * Check that a string looks like an email address. + * @param string $address The email address to check + * @param string|callable $patternselect A selector for the validation pattern to use : + * * `auto` Pick best pattern automatically; + * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14; + * * `pcre` Use old PCRE implementation; + * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; + * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements. + * * `noregex` Don't use a regex: super fast, really dumb. + * Alternatively you may pass in a callable to inject your own validator, for example: + * PHPMailer::validateAddress('user@example.com', function($address) { + * return (strpos($address, '@') !== false); + * }); + * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator. + * @return boolean + * @static + * @access public + */ + public static function validateAddress($address, $patternselect = null) + { + if (is_null($patternselect)) { + $patternselect = self::$validator; + } + if (is_callable($patternselect)) { + return call_user_func($patternselect, $address); + } + //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321 + if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) { + return false; + } + if (!$patternselect or $patternselect == 'auto') { + //Check this constant first so it works when extension_loaded() is disabled by safe mode + //Constant was added in PHP 5.2.4 + if (defined('PCRE_VERSION')) { + //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2 + if (version_compare(PCRE_VERSION, '8.0.3') >= 0) { + $patternselect = 'pcre8'; + } else { + $patternselect = 'pcre'; + } + } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) { + //Fall back to older PCRE + $patternselect = 'pcre'; + } else { + //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension + if (version_compare(PHP_VERSION, '5.2.0') >= 0) { + $patternselect = 'php'; + } else { + $patternselect = 'noregex'; + } + } + } + switch ($patternselect) { + case 'pcre8': + /** + * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains. + * @link http://squiloople.com/2009/12/20/email-address-validation/ + * @copyright 2009-2010 Michael Rushton + * Feel free to use and redistribute this code. But please keep this copyright notice. + */ + return (boolean)preg_match( + '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' . + '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' . + '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' . + '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' . + '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' . + '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' . + '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' . + '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' . + '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD', + $address + ); + case 'pcre': + //An older regex that doesn't need a recent PCRE + return (boolean)preg_match( + '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' . + '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' . + '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' . + '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' . + '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' . + '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' . + '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' . + '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' . + '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' . + '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD', + $address + ); + case 'html5': + /** + * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements. + * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email) + */ + return (boolean)preg_match( + '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' . + '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD', + $address + ); + case 'noregex': + //No PCRE! Do something _very_ approximate! + //Check the address is 3 chars or longer and contains an @ that's not the first or last char + return (strlen($address) >= 3 + and strpos($address, '@') >= 1 + and strpos($address, '@') != strlen($address) - 1); + case 'php': + default: + return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL); + } + } + + /** + * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the + * "intl" and "mbstring" PHP extensions. + * @return bool "true" if required functions for IDN support are present + */ + public function idnSupported() + { + // @TODO: Write our own "idn_to_ascii" function for PHP <= 5.2. + return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding'); + } + + /** + * Converts IDN in given email address to its ASCII form, also known as punycode, if possible. + * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet. + * This function silently returns unmodified address if: + * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form) + * - Conversion to punycode is impossible (e.g. required PHP functions are not available) + * or fails for any reason (e.g. domain has characters not allowed in an IDN) + * @see PHPMailer::$CharSet + * @param string $address The email address to convert + * @return string The encoded address in ASCII form + */ + public function punyencodeAddress($address) + { + // Verify we have required functions, CharSet, and at-sign. + if ($this->idnSupported() and + !empty($this->CharSet) and + ($pos = strrpos($address, '@')) !== false) { + $domain = substr($address, ++$pos); + // Verify CharSet string is a valid one, and domain properly encoded in this CharSet. + if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) { + $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet); + if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ? + idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) : + idn_to_ascii($domain)) !== false) { + return substr($address, 0, $pos) . $punycode; + } + } + } + return $address; + } + + /** + * Create a message and send it. + * Uses the sending method specified by $Mailer. + * @throws phpmailerException + * @return boolean false on error - See the ErrorInfo property for details of the error. + */ + public function send() + { + try { + if (!$this->preSend()) { + return false; + } + return $this->postSend(); + } catch (phpmailerException $exc) { + $this->mailHeader = ''; + $this->setError($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + return false; + } + } + + /** + * Prepare a message for sending. + * @throws phpmailerException + * @return boolean + */ + public function preSend() + { + try { + $this->error_count = 0; // Reset errors + $this->mailHeader = ''; + + // Dequeue recipient and Reply-To addresses with IDN + foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) { + $params[1] = $this->punyencodeAddress($params[1]); + call_user_func_array(array($this, 'addAnAddress'), $params); + } + if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) { + throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL); + } + + // Validate From, Sender, and ConfirmReadingTo addresses + foreach (array('From', 'Sender', 'ConfirmReadingTo') as $address_kind) { + $this->$address_kind = trim($this->$address_kind); + if (empty($this->$address_kind)) { + continue; + } + $this->$address_kind = $this->punyencodeAddress($this->$address_kind); + if (!$this->validateAddress($this->$address_kind)) { + $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind; + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new phpmailerException($error_message); + } + return false; + } + } + + // Set whether the message is multipart/alternative + if ($this->alternativeExists()) { + $this->ContentType = 'multipart/alternative'; + } + + $this->setMessageType(); + // Refuse to send an empty message unless we are specifically allowing it + if (!$this->AllowEmpty and empty($this->Body)) { + throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL); + } + + // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding) + $this->MIMEHeader = ''; + $this->MIMEBody = $this->createBody(); + // createBody may have added some headers, so retain them + $tempheaders = $this->MIMEHeader; + $this->MIMEHeader = $this->createHeader(); + $this->MIMEHeader .= $tempheaders; + + // To capture the complete message when using mail(), create + // an extra header list which createHeader() doesn't fold in + if ($this->Mailer == 'mail') { + if (count($this->to) > 0) { + $this->mailHeader .= $this->addrAppend('To', $this->to); + } else { + $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;'); + } + $this->mailHeader .= $this->headerLine( + 'Subject', + $this->encodeHeader($this->secureHeader(trim($this->Subject))) + ); + } + + // Sign with DKIM if enabled + if (!empty($this->DKIM_domain) + && !empty($this->DKIM_private) + && !empty($this->DKIM_selector) + && file_exists($this->DKIM_private)) { + $header_dkim = $this->DKIM_Add( + $this->MIMEHeader . $this->mailHeader, + $this->encodeHeader($this->secureHeader($this->Subject)), + $this->MIMEBody + ); + $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF . + str_replace("\r\n", "\n", $header_dkim) . self::CRLF; + } + return true; + } catch (phpmailerException $exc) { + $this->setError($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + return false; + } + } + + /** + * Actually send a message. + * Send the email via the selected mechanism + * @throws phpmailerException + * @return boolean + */ + public function postSend() + { + try { + // Choose the mailer and send through it + switch ($this->Mailer) { + case 'sendmail': + case 'qmail': + return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody); + case 'smtp': + return $this->smtpSend($this->MIMEHeader, $this->MIMEBody); + case 'mail': + return $this->mailSend($this->MIMEHeader, $this->MIMEBody); + default: + $sendMethod = $this->Mailer.'Send'; + if (method_exists($this, $sendMethod)) { + return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody); + } + + return $this->mailSend($this->MIMEHeader, $this->MIMEBody); + } + } catch (phpmailerException $exc) { + $this->setError($exc->getMessage()); + $this->edebug($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + } + return false; + } + + /** + * Send mail using the $Sendmail program. + * @param string $header The message headers + * @param string $body The message body + * @see PHPMailer::$Sendmail + * @throws phpmailerException + * @access protected + * @return boolean + */ + protected function sendmailSend($header, $body) + { + if ($this->Sender != '') { + if ($this->Mailer == 'qmail') { + $sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender)); + } else { + $sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender)); + } + } else { + if ($this->Mailer == 'qmail') { + $sendmail = sprintf('%s', escapeshellcmd($this->Sendmail)); + } else { + $sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail)); + } + } + if ($this->SingleTo) { + foreach ($this->SingleToArray as $toAddr) { + if (!@$mail = popen($sendmail, 'w')) { + throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + fputs($mail, 'To: ' . $toAddr . "\n"); + fputs($mail, $header); + fputs($mail, $body); + $result = pclose($mail); + $this->doCallback( + ($result == 0), + array($toAddr), + $this->cc, + $this->bcc, + $this->Subject, + $body, + $this->From + ); + if ($result != 0) { + throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + } + } else { + if (!@$mail = popen($sendmail, 'w')) { + throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + fputs($mail, $header); + fputs($mail, $body); + $result = pclose($mail); + $this->doCallback( + ($result == 0), + $this->to, + $this->cc, + $this->bcc, + $this->Subject, + $body, + $this->From + ); + if ($result != 0) { + throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + } + return true; + } + + /** + * Send mail using the PHP mail() function. + * @param string $header The message headers + * @param string $body The message body + * @link http://www.php.net/manual/en/book.mail.php + * @throws phpmailerException + * @access protected + * @return boolean + */ + protected function mailSend($header, $body) + { + $toArr = array(); + foreach ($this->to as $toaddr) { + $toArr[] = $this->addrFormat($toaddr); + } + $to = implode(', ', $toArr); + + $params = null; + //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver + if (!empty($this->Sender)) { + $params = sprintf('-f%s', $this->Sender); + } + if ($this->Sender != '' and !ini_get('safe_mode')) { + $old_from = ini_get('sendmail_from'); + ini_set('sendmail_from', $this->Sender); + } + $result = false; + if ($this->SingleTo and count($toArr) > 1) { + foreach ($toArr as $toAddr) { + $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params); + $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From); + } + } else { + $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params); + $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From); + } + if (isset($old_from)) { + ini_set('sendmail_from', $old_from); + } + if (!$result) { + throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL); + } + return true; + } + + /** + * Get an instance to use for SMTP operations. + * Override this function to load your own SMTP implementation + * @return SMTP + */ + public function getSMTPInstance() + { + if (!is_object($this->smtp)) { + $this->smtp = new SMTP; + } + return $this->smtp; + } + + /** + * Send mail via SMTP. + * Returns false if there is a bad MAIL FROM, RCPT, or DATA input. + * Uses the PHPMailerSMTP class by default. + * @see PHPMailer::getSMTPInstance() to use a different class. + * @param string $header The message headers + * @param string $body The message body + * @throws phpmailerException + * @uses SMTP + * @access protected + * @return boolean + */ + protected function smtpSend($header, $body) + { + $bad_rcpt = array(); + if (!$this->smtpConnect($this->SMTPOptions)) { + throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL); + } + if ('' == $this->Sender) { + $smtp_from = $this->From; + } else { + $smtp_from = $this->Sender; + } + if (!$this->smtp->mail($smtp_from)) { + $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError())); + throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL); + } + + // Attempt to send to all recipients + foreach (array($this->to, $this->cc, $this->bcc) as $togroup) { + foreach ($togroup as $to) { + if (!$this->smtp->recipient($to[0])) { + $error = $this->smtp->getError(); + $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']); + $isSent = false; + } else { + $isSent = true; + } + $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From); + } + } + + // Only send the DATA command if we have viable recipients + if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) { + throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL); + } + if ($this->SMTPKeepAlive) { + $this->smtp->reset(); + } else { + $this->smtp->quit(); + $this->smtp->close(); + } + //Create error message for any bad addresses + if (count($bad_rcpt) > 0) { + $errstr = ''; + foreach ($bad_rcpt as $bad) { + $errstr .= $bad['to'] . ': ' . $bad['error']; + } + throw new phpmailerException( + $this->lang('recipients_failed') . $errstr, + self::STOP_CONTINUE + ); + } + return true; + } + + /** + * Initiate a connection to an SMTP server. + * Returns false if the operation failed. + * @param array $options An array of options compatible with stream_context_create() + * @uses SMTP + * @access public + * @throws phpmailerException + * @return boolean + */ + public function smtpConnect($options = null) + { + if (is_null($this->smtp)) { + $this->smtp = $this->getSMTPInstance(); + } + + //If no options are provided, use whatever is set in the instance + if (is_null($options)) { + $options = $this->SMTPOptions; + } + + // Already connected? + if ($this->smtp->connected()) { + return true; + } + + $this->smtp->setTimeout($this->Timeout); + $this->smtp->setDebugLevel($this->SMTPDebug); + $this->smtp->setDebugOutput($this->Debugoutput); + $this->smtp->setVerp($this->do_verp); + $hosts = explode(';', $this->Host); + $lastexception = null; + + foreach ($hosts as $hostentry) { + $hostinfo = array(); + if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) { + // Not a valid host entry + continue; + } + // $hostinfo[2]: optional ssl or tls prefix + // $hostinfo[3]: the hostname + // $hostinfo[4]: optional port number + // The host string prefix can temporarily override the current setting for SMTPSecure + // If it's not specified, the default value is used + $prefix = ''; + $secure = $this->SMTPSecure; + $tls = ($this->SMTPSecure == 'tls'); + if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) { + $prefix = 'ssl://'; + $tls = false; // Can't have SSL and TLS at the same time + $secure = 'ssl'; + } elseif ($hostinfo[2] == 'tls') { + $tls = true; + // tls doesn't use a prefix + $secure = 'tls'; + } + //Do we need the OpenSSL extension? + $sslext = defined('OPENSSL_ALGO_SHA1'); + if ('tls' === $secure or 'ssl' === $secure) { + //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled + if (!$sslext) { + throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL); + } + } + $host = $hostinfo[3]; + $port = $this->Port; + $tport = (integer)$hostinfo[4]; + if ($tport > 0 and $tport < 65536) { + $port = $tport; + } + if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) { + try { + if ($this->Helo) { + $hello = $this->Helo; + } else { + $hello = $this->serverHostname(); + } + $this->smtp->hello($hello); + //Automatically enable TLS encryption if: + // * it's not disabled + // * we have openssl extension + // * we are not already using SSL + // * the server offers STARTTLS + if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) { + $tls = true; + } + if ($tls) { + if (!$this->smtp->startTLS()) { + throw new phpmailerException($this->lang('connect_host')); + } + // We must resend EHLO after TLS negotiation + $this->smtp->hello($hello); + } + if ($this->SMTPAuth) { + if (!$this->smtp->authenticate( + $this->Username, + $this->Password, + $this->AuthType, + $this->Realm, + $this->Workstation + ) + ) { + throw new phpmailerException($this->lang('authenticate')); + } + } + return true; + } catch (phpmailerException $exc) { + $lastexception = $exc; + $this->edebug($exc->getMessage()); + // We must have connected, but then failed TLS or Auth, so close connection nicely + $this->smtp->quit(); + } + } + } + // If we get here, all connection attempts have failed, so close connection hard + $this->smtp->close(); + // As we've caught all exceptions, just report whatever the last one was + if ($this->exceptions and !is_null($lastexception)) { + throw $lastexception; + } + return false; + } + + /** + * Close the active SMTP session if one exists. + * @return void + */ + public function smtpClose() + { + if (is_a($this->smtp, 'SMTP')) { + if ($this->smtp->connected()) { + $this->smtp->quit(); + $this->smtp->close(); + } + } + } + + /** + * Set the language for error messages. + * Returns false if it cannot load the language file. + * The default language is English. + * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr") + * @param string $lang_path Path to the language file directory, with trailing separator (slash) + * @return boolean + * @access public + */ + public function setLanguage($langcode = 'en', $lang_path = '') + { + // Backwards compatibility for renamed language codes + $renamed_langcodes = array( + 'br' => 'pt_br', + 'cz' => 'cs', + 'dk' => 'da', + 'no' => 'nb', + 'se' => 'sv', + ); + + if (isset($renamed_langcodes[$langcode])) { + $langcode = $renamed_langcodes[$langcode]; + } + + // Define full set of translatable strings in English + $PHPMAILER_LANG = array( + 'authenticate' => 'SMTP Error: Could not authenticate.', + 'connect_host' => 'SMTP Error: Could not connect to SMTP host.', + 'data_not_accepted' => 'SMTP Error: data not accepted.', + 'empty_message' => 'Message body empty', + 'encoding' => 'Unknown encoding: ', + 'execute' => 'Could not execute: ', + 'file_access' => 'Could not access file: ', + 'file_open' => 'File Error: Could not open file: ', + 'from_failed' => 'The following From address failed: ', + 'instantiate' => 'Could not instantiate mail function.', + 'invalid_address' => 'Invalid address: ', + 'mailer_not_supported' => ' mailer is not supported.', + 'provide_address' => 'You must provide at least one recipient email address.', + 'recipients_failed' => 'SMTP Error: The following recipients failed: ', + 'signing' => 'Signing Error: ', + 'smtp_connect_failed' => 'SMTP connect() failed.', + 'smtp_error' => 'SMTP server error: ', + 'variable_set' => 'Cannot set or reset variable: ', + 'extension_missing' => 'Extension missing: ' + ); + if (empty($lang_path)) { + // Calculate an absolute path so it can work if CWD is not here + $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR; + } + //Validate $langcode + if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) { + $langcode = 'en'; + } + $foundlang = true; + $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php'; + // There is no English translation file + if ($langcode != 'en') { + // Make sure language file path is readable + if (!is_readable($lang_file)) { + $foundlang = false; + } else { + // Overwrite language-specific strings. + // This way we'll never have missing translation keys. + $foundlang = include $lang_file; + } + } + $this->language = $PHPMAILER_LANG; + return (boolean)$foundlang; // Returns false if language not found + } + + /** + * Get the array of strings for the current language. + * @return array + */ + public function getTranslations() + { + return $this->language; + } + + /** + * Create recipient headers. + * @access public + * @param string $type + * @param array $addr An array of recipient, + * where each recipient is a 2-element indexed array with element 0 containing an address + * and element 1 containing a name, like: + * array(array('joe@example.com', 'Joe User'), array('zoe@example.com', 'Zoe User')) + * @return string + */ + public function addrAppend($type, $addr) + { + $addresses = array(); + foreach ($addr as $address) { + $addresses[] = $this->addrFormat($address); + } + return $type . ': ' . implode(', ', $addresses) . $this->LE; + } + + /** + * Format an address for use in a message header. + * @access public + * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name + * like array('joe@example.com', 'Joe User') + * @return string + */ + public function addrFormat($addr) + { + if (empty($addr[1])) { // No name provided + return $this->secureHeader($addr[0]); + } else { + return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader( + $addr[0] + ) . '>'; + } + } + + /** + * Word-wrap message. + * For use with mailers that do not automatically perform wrapping + * and for quoted-printable encoded messages. + * Original written by philippe. + * @param string $message The message to wrap + * @param integer $length The line length to wrap to + * @param boolean $qp_mode Whether to run in Quoted-Printable mode + * @access public + * @return string + */ + public function wrapText($message, $length, $qp_mode = false) + { + if ($qp_mode) { + $soft_break = sprintf(' =%s', $this->LE); + } else { + $soft_break = $this->LE; + } + // If utf-8 encoding is used, we will need to make sure we don't + // split multibyte characters when we wrap + $is_utf8 = (strtolower($this->CharSet) == 'utf-8'); + $lelen = strlen($this->LE); + $crlflen = strlen(self::CRLF); + + $message = $this->fixEOL($message); + //Remove a trailing line break + if (substr($message, -$lelen) == $this->LE) { + $message = substr($message, 0, -$lelen); + } + + //Split message into lines + $lines = explode($this->LE, $message); + //Message will be rebuilt in here + $message = ''; + foreach ($lines as $line) { + $words = explode(' ', $line); + $buf = ''; + $firstword = true; + foreach ($words as $word) { + if ($qp_mode and (strlen($word) > $length)) { + $space_left = $length - strlen($buf) - $crlflen; + if (!$firstword) { + if ($space_left > 20) { + $len = $space_left; + if ($is_utf8) { + $len = $this->utf8CharBoundary($word, $len); + } elseif (substr($word, $len - 1, 1) == '=') { + $len--; + } elseif (substr($word, $len - 2, 1) == '=') { + $len -= 2; + } + $part = substr($word, 0, $len); + $word = substr($word, $len); + $buf .= ' ' . $part; + $message .= $buf . sprintf('=%s', self::CRLF); + } else { + $message .= $buf . $soft_break; + } + $buf = ''; + } + while (strlen($word) > 0) { + if ($length <= 0) { + break; + } + $len = $length; + if ($is_utf8) { + $len = $this->utf8CharBoundary($word, $len); + } elseif (substr($word, $len - 1, 1) == '=') { + $len--; + } elseif (substr($word, $len - 2, 1) == '=') { + $len -= 2; + } + $part = substr($word, 0, $len); + $word = substr($word, $len); + + if (strlen($word) > 0) { + $message .= $part . sprintf('=%s', self::CRLF); + } else { + $buf = $part; + } + } + } else { + $buf_o = $buf; + if (!$firstword) { + $buf .= ' '; + } + $buf .= $word; + + if (strlen($buf) > $length and $buf_o != '') { + $message .= $buf_o . $soft_break; + $buf = $word; + } + } + $firstword = false; + } + $message .= $buf . self::CRLF; + } + + return $message; + } + + /** + * Find the last character boundary prior to $maxLength in a utf-8 + * quoted-printable encoded string. + * Original written by Colin Brown. + * @access public + * @param string $encodedText utf-8 QP text + * @param integer $maxLength Find the last character boundary prior to this length + * @return integer + */ + public function utf8CharBoundary($encodedText, $maxLength) + { + $foundSplitPos = false; + $lookBack = 3; + while (!$foundSplitPos) { + $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack); + $encodedCharPos = strpos($lastChunk, '='); + if (false !== $encodedCharPos) { + // Found start of encoded character byte within $lookBack block. + // Check the encoded byte value (the 2 chars after the '=') + $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2); + $dec = hexdec($hex); + if ($dec < 128) { + // Single byte character. + // If the encoded char was found at pos 0, it will fit + // otherwise reduce maxLength to start of the encoded char + if ($encodedCharPos > 0) { + $maxLength = $maxLength - ($lookBack - $encodedCharPos); + } + $foundSplitPos = true; + } elseif ($dec >= 192) { + // First byte of a multi byte character + // Reduce maxLength to split at start of character + $maxLength = $maxLength - ($lookBack - $encodedCharPos); + $foundSplitPos = true; + } elseif ($dec < 192) { + // Middle byte of a multi byte character, look further back + $lookBack += 3; + } + } else { + // No encoded character found + $foundSplitPos = true; + } + } + return $maxLength; + } + + /** + * Apply word wrapping to the message body. + * Wraps the message body to the number of chars set in the WordWrap property. + * You should only do this to plain-text bodies as wrapping HTML tags may break them. + * This is called automatically by createBody(), so you don't need to call it yourself. + * @access public + * @return void + */ + public function setWordWrap() + { + if ($this->WordWrap < 1) { + return; + } + + switch ($this->message_type) { + case 'alt': + case 'alt_inline': + case 'alt_attach': + case 'alt_inline_attach': + $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap); + break; + default: + $this->Body = $this->wrapText($this->Body, $this->WordWrap); + break; + } + } + + /** + * Assemble message headers. + * @access public + * @return string The assembled headers + */ + public function createHeader() + { + $result = ''; + + if ($this->MessageDate == '') { + $this->MessageDate = self::rfcDate(); + } + $result .= $this->headerLine('Date', $this->MessageDate); + + // To be created automatically by mail() + if ($this->SingleTo) { + if ($this->Mailer != 'mail') { + foreach ($this->to as $toaddr) { + $this->SingleToArray[] = $this->addrFormat($toaddr); + } + } + } else { + if (count($this->to) > 0) { + if ($this->Mailer != 'mail') { + $result .= $this->addrAppend('To', $this->to); + } + } elseif (count($this->cc) == 0) { + $result .= $this->headerLine('To', 'undisclosed-recipients:;'); + } + } + + $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName))); + + // sendmail and mail() extract Cc from the header before sending + if (count($this->cc) > 0) { + $result .= $this->addrAppend('Cc', $this->cc); + } + + // sendmail and mail() extract Bcc from the header before sending + if (( + $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail' + ) + and count($this->bcc) > 0 + ) { + $result .= $this->addrAppend('Bcc', $this->bcc); + } + + if (count($this->ReplyTo) > 0) { + $result .= $this->addrAppend('Reply-To', $this->ReplyTo); + } + + // mail() sets the subject itself + if ($this->Mailer != 'mail') { + $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject))); + } + + // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4 + // https://tools.ietf.org/html/rfc5322#section-3.6.4 + if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) { + $this->lastMessageID = $this->MessageID; + } else { + $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname()); + } + $result .= $this->headerLine('Message-ID', $this->lastMessageID); + if (!is_null($this->Priority)) { + $result .= $this->headerLine('X-Priority', $this->Priority); + } + if ($this->XMailer == '') { + $result .= $this->headerLine( + 'X-Mailer', + 'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer)' + ); + } else { + $myXmailer = trim($this->XMailer); + if ($myXmailer) { + $result .= $this->headerLine('X-Mailer', $myXmailer); + } + } + + if ($this->ConfirmReadingTo != '') { + $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>'); + } + + // Add custom headers + foreach ($this->CustomHeader as $header) { + $result .= $this->headerLine( + trim($header[0]), + $this->encodeHeader(trim($header[1])) + ); + } + if (!$this->sign_key_file) { + $result .= $this->headerLine('MIME-Version', '1.0'); + $result .= $this->getMailMIME(); + } + + return $result; + } + + /** + * Get the message MIME type headers. + * @access public + * @return string + */ + public function getMailMIME() + { + $result = ''; + $ismultipart = true; + switch ($this->message_type) { + case 'inline': + $result .= $this->headerLine('Content-Type', 'multipart/related;'); + $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); + break; + case 'attach': + case 'inline_attach': + case 'alt_attach': + case 'alt_inline_attach': + $result .= $this->headerLine('Content-Type', 'multipart/mixed;'); + $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); + break; + case 'alt': + case 'alt_inline': + $result .= $this->headerLine('Content-Type', 'multipart/alternative;'); + $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); + break; + default: + // Catches case 'plain': and case '': + $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet); + $ismultipart = false; + break; + } + // RFC1341 part 5 says 7bit is assumed if not specified + if ($this->Encoding != '7bit') { + // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE + if ($ismultipart) { + if ($this->Encoding == '8bit') { + $result .= $this->headerLine('Content-Transfer-Encoding', '8bit'); + } + // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible + } else { + $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding); + } + } + + if ($this->Mailer != 'mail') { + $result .= $this->LE; + } + + return $result; + } + + /** + * Returns the whole MIME message. + * Includes complete headers and body. + * Only valid post preSend(). + * @see PHPMailer::preSend() + * @access public + * @return string + */ + public function getSentMIMEMessage() + { + return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody; + } + + /** + * Assemble the message body. + * Returns an empty string on failure. + * @access public + * @throws phpmailerException + * @return string The assembled message body + */ + public function createBody() + { + $body = ''; + //Create unique IDs and preset boundaries + $this->uniqueid = md5(uniqid(time())); + $this->boundary[1] = 'b1_' . $this->uniqueid; + $this->boundary[2] = 'b2_' . $this->uniqueid; + $this->boundary[3] = 'b3_' . $this->uniqueid; + + if ($this->sign_key_file) { + $body .= $this->getMailMIME() . $this->LE; + } + + $this->setWordWrap(); + + $bodyEncoding = $this->Encoding; + $bodyCharSet = $this->CharSet; + //Can we do a 7-bit downgrade? + if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) { + $bodyEncoding = '7bit'; + //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit + $bodyCharSet = 'us-ascii'; + } + //If lines are too long, and we're not already using an encoding that will shorten them, + //change to quoted-printable transfer encoding for the body part only + if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) { + $bodyEncoding = 'quoted-printable'; + } + + $altBodyEncoding = $this->Encoding; + $altBodyCharSet = $this->CharSet; + //Can we do a 7-bit downgrade? + if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) { + $altBodyEncoding = '7bit'; + //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit + $altBodyCharSet = 'us-ascii'; + } + //If lines are too long, and we're not already using an encoding that will shorten them, + //change to quoted-printable transfer encoding for the alt body part only + if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) { + $altBodyEncoding = 'quoted-printable'; + } + //Use this as a preamble in all multipart message types + $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE; + switch ($this->message_type) { + case 'inline': + $body .= $mimepre; + $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->attachAll('inline', $this->boundary[1]); + break; + case 'attach': + $body .= $mimepre; + $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + case 'inline_attach': + $body .= $mimepre; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', 'multipart/related;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); + $body .= $this->LE; + $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->attachAll('inline', $this->boundary[2]); + $body .= $this->LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + case 'alt': + $body .= $mimepre; + $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= $this->LE . $this->LE; + if (!empty($this->Ical)) { + $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', ''); + $body .= $this->encodeString($this->Ical, $this->Encoding); + $body .= $this->LE . $this->LE; + } + $body .= $this->endBoundary($this->boundary[1]); + break; + case 'alt_inline': + $body .= $mimepre; + $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', 'multipart/related;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); + $body .= $this->LE; + $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->attachAll('inline', $this->boundary[2]); + $body .= $this->LE; + $body .= $this->endBoundary($this->boundary[1]); + break; + case 'alt_attach': + $body .= $mimepre; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', 'multipart/alternative;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); + $body .= $this->LE; + $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->endBoundary($this->boundary[2]); + $body .= $this->LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + case 'alt_inline_attach': + $body .= $mimepre; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', 'multipart/alternative;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); + $body .= $this->LE; + $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->textLine('--' . $this->boundary[2]); + $body .= $this->headerLine('Content-Type', 'multipart/related;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"'); + $body .= $this->LE; + $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->attachAll('inline', $this->boundary[3]); + $body .= $this->LE; + $body .= $this->endBoundary($this->boundary[2]); + $body .= $this->LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + default: + // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types + //Reset the `Encoding` property in case we changed it for line length reasons + $this->Encoding = $bodyEncoding; + $body .= $this->encodeString($this->Body, $this->Encoding); + break; + } + + if ($this->isError()) { + $body = ''; + } elseif ($this->sign_key_file) { + try { + if (!defined('PKCS7_TEXT')) { + throw new phpmailerException($this->lang('extension_missing') . 'openssl'); + } + // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1 + $file = tempnam(sys_get_temp_dir(), 'mail'); + if (false === file_put_contents($file, $body)) { + throw new phpmailerException($this->lang('signing') . ' Could not write temp file'); + } + $signed = tempnam(sys_get_temp_dir(), 'signed'); + //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197 + if (empty($this->sign_extracerts_file)) { + $sign = @openssl_pkcs7_sign( + $file, + $signed, + 'file://' . realpath($this->sign_cert_file), + array('file://' . realpath($this->sign_key_file), $this->sign_key_pass), + null + ); + } else { + $sign = @openssl_pkcs7_sign( + $file, + $signed, + 'file://' . realpath($this->sign_cert_file), + array('file://' . realpath($this->sign_key_file), $this->sign_key_pass), + null, + PKCS7_DETACHED, + $this->sign_extracerts_file + ); + } + if ($sign) { + @unlink($file); + $body = file_get_contents($signed); + @unlink($signed); + //The message returned by openssl contains both headers and body, so need to split them up + $parts = explode("\n\n", $body, 2); + $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE; + $body = $parts[1]; + } else { + @unlink($file); + @unlink($signed); + throw new phpmailerException($this->lang('signing') . openssl_error_string()); + } + } catch (phpmailerException $exc) { + $body = ''; + if ($this->exceptions) { + throw $exc; + } + } + } + return $body; + } + + /** + * Return the start of a message boundary. + * @access protected + * @param string $boundary + * @param string $charSet + * @param string $contentType + * @param string $encoding + * @return string + */ + protected function getBoundary($boundary, $charSet, $contentType, $encoding) + { + $result = ''; + if ($charSet == '') { + $charSet = $this->CharSet; + } + if ($contentType == '') { + $contentType = $this->ContentType; + } + if ($encoding == '') { + $encoding = $this->Encoding; + } + $result .= $this->textLine('--' . $boundary); + $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet); + $result .= $this->LE; + // RFC1341 part 5 says 7bit is assumed if not specified + if ($encoding != '7bit') { + $result .= $this->headerLine('Content-Transfer-Encoding', $encoding); + } + $result .= $this->LE; + + return $result; + } + + /** + * Return the end of a message boundary. + * @access protected + * @param string $boundary + * @return string + */ + protected function endBoundary($boundary) + { + return $this->LE . '--' . $boundary . '--' . $this->LE; + } + + /** + * Set the message type. + * PHPMailer only supports some preset message types, not arbitrary MIME structures. + * @access protected + * @return void + */ + protected function setMessageType() + { + $type = array(); + if ($this->alternativeExists()) { + $type[] = 'alt'; + } + if ($this->inlineImageExists()) { + $type[] = 'inline'; + } + if ($this->attachmentExists()) { + $type[] = 'attach'; + } + $this->message_type = implode('_', $type); + if ($this->message_type == '') { + //The 'plain' message_type refers to the message having a single body element, not that it is plain-text + $this->message_type = 'plain'; + } + } + + /** + * Format a header line. + * @access public + * @param string $name + * @param string $value + * @return string + */ + public function headerLine($name, $value) + { + return $name . ': ' . $value . $this->LE; + } + + /** + * Return a formatted mail line. + * @access public + * @param string $value + * @return string + */ + public function textLine($value) + { + return $value . $this->LE; + } + + /** + * Add an attachment from a path on the filesystem. + * Returns false if the file could not be found or read. + * @param string $path Path to the attachment. + * @param string $name Overrides the attachment name. + * @param string $encoding File encoding (see $Encoding). + * @param string $type File extension (MIME) type. + * @param string $disposition Disposition to use + * @throws phpmailerException + * @return boolean + */ + public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment') + { + try { + if (!@is_file($path)) { + throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE); + } + + // If a MIME type is not specified, try to work it out from the file name + if ($type == '') { + $type = self::filenameToType($path); + } + + $filename = basename($path); + if ($name == '') { + $name = $filename; + } + + $this->attachment[] = array( + 0 => $path, + 1 => $filename, + 2 => $name, + 3 => $encoding, + 4 => $type, + 5 => false, // isStringAttachment + 6 => $disposition, + 7 => 0 + ); + + } catch (phpmailerException $exc) { + $this->setError($exc->getMessage()); + $this->edebug($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + return false; + } + return true; + } + + /** + * Return the array of attachments. + * @return array + */ + public function getAttachments() + { + return $this->attachment; + } + + /** + * Attach all file, string, and binary attachments to the message. + * Returns an empty string on failure. + * @access protected + * @param string $disposition_type + * @param string $boundary + * @return string + */ + protected function attachAll($disposition_type, $boundary) + { + // Return text of body + $mime = array(); + $cidUniq = array(); + $incl = array(); + + // Add all attachments + foreach ($this->attachment as $attachment) { + // Check if it is a valid disposition_filter + if ($attachment[6] == $disposition_type) { + // Check for string attachment + $string = ''; + $path = ''; + $bString = $attachment[5]; + if ($bString) { + $string = $attachment[0]; + } else { + $path = $attachment[0]; + } + + $inclhash = md5(serialize($attachment)); + if (in_array($inclhash, $incl)) { + continue; + } + $incl[] = $inclhash; + $name = $attachment[2]; + $encoding = $attachment[3]; + $type = $attachment[4]; + $disposition = $attachment[6]; + $cid = $attachment[7]; + if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) { + continue; + } + $cidUniq[$cid] = true; + + $mime[] = sprintf('--%s%s', $boundary, $this->LE); + //Only include a filename property if we have one + if (!empty($name)) { + $mime[] = sprintf( + 'Content-Type: %s; name="%s"%s', + $type, + $this->encodeHeader($this->secureHeader($name)), + $this->LE + ); + } else { + $mime[] = sprintf( + 'Content-Type: %s%s', + $type, + $this->LE + ); + } + // RFC1341 part 5 says 7bit is assumed if not specified + if ($encoding != '7bit') { + $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE); + } + + if ($disposition == 'inline') { + $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE); + } + + // If a filename contains any of these chars, it should be quoted, + // but not otherwise: RFC2183 & RFC2045 5.1 + // Fixes a warning in IETF's msglint MIME checker + // Allow for bypassing the Content-Disposition header totally + if (!(empty($disposition))) { + $encoded_name = $this->encodeHeader($this->secureHeader($name)); + if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) { + $mime[] = sprintf( + 'Content-Disposition: %s; filename="%s"%s', + $disposition, + $encoded_name, + $this->LE . $this->LE + ); + } else { + if (!empty($encoded_name)) { + $mime[] = sprintf( + 'Content-Disposition: %s; filename=%s%s', + $disposition, + $encoded_name, + $this->LE . $this->LE + ); + } else { + $mime[] = sprintf( + 'Content-Disposition: %s%s', + $disposition, + $this->LE . $this->LE + ); + } + } + } else { + $mime[] = $this->LE; + } + + // Encode as string attachment + if ($bString) { + $mime[] = $this->encodeString($string, $encoding); + if ($this->isError()) { + return ''; + } + $mime[] = $this->LE . $this->LE; + } else { + $mime[] = $this->encodeFile($path, $encoding); + if ($this->isError()) { + return ''; + } + $mime[] = $this->LE . $this->LE; + } + } + } + + $mime[] = sprintf('--%s--%s', $boundary, $this->LE); + + return implode('', $mime); + } + + /** + * Encode a file attachment in requested format. + * Returns an empty string on failure. + * @param string $path The full path to the file + * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable' + * @throws phpmailerException + * @access protected + * @return string + */ + protected function encodeFile($path, $encoding = 'base64') + { + try { + if (!is_readable($path)) { + throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE); + } + $magic_quotes = get_magic_quotes_runtime(); + if ($magic_quotes) { + if (version_compare(PHP_VERSION, '5.3.0', '<')) { + set_magic_quotes_runtime(false); + } else { + //Doesn't exist in PHP 5.4, but we don't need to check because + //get_magic_quotes_runtime always returns false in 5.4+ + //so it will never get here + ini_set('magic_quotes_runtime', false); + } + } + $file_buffer = file_get_contents($path); + $file_buffer = $this->encodeString($file_buffer, $encoding); + if ($magic_quotes) { + if (version_compare(PHP_VERSION, '5.3.0', '<')) { + set_magic_quotes_runtime($magic_quotes); + } else { + ini_set('magic_quotes_runtime', $magic_quotes); + } + } + return $file_buffer; + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + return ''; + } + } + + /** + * Encode a string in requested format. + * Returns an empty string on failure. + * @param string $str The text to encode + * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable' + * @access public + * @return string + */ + public function encodeString($str, $encoding = 'base64') + { + $encoded = ''; + switch (strtolower($encoding)) { + case 'base64': + $encoded = chunk_split(base64_encode($str), 76, $this->LE); + break; + case '7bit': + case '8bit': + $encoded = $this->fixEOL($str); + // Make sure it ends with a line break + if (substr($encoded, -(strlen($this->LE))) != $this->LE) { + $encoded .= $this->LE; + } + break; + case 'binary': + $encoded = $str; + break; + case 'quoted-printable': + $encoded = $this->encodeQP($str); + break; + default: + $this->setError($this->lang('encoding') . $encoding); + break; + } + return $encoded; + } + + /** + * Encode a header string optimally. + * Picks shortest of Q, B, quoted-printable or none. + * @access public + * @param string $str + * @param string $position + * @return string + */ + public function encodeHeader($str, $position = 'text') + { + $matchcount = 0; + switch (strtolower($position)) { + case 'phrase': + if (!preg_match('/[\200-\377]/', $str)) { + // Can't use addslashes as we don't know the value of magic_quotes_sybase + $encoded = addcslashes($str, "\0..\37\177\\\""); + if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) { + return ($encoded); + } else { + return ("\"$encoded\""); + } + } + $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches); + break; + /** @noinspection PhpMissingBreakStatementInspection */ + case 'comment': + $matchcount = preg_match_all('/[()"]/', $str, $matches); + // Intentional fall-through + case 'text': + default: + $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); + break; + } + + //There are no chars that need encoding + if ($matchcount == 0) { + return ($str); + } + + $maxlen = 75 - 7 - strlen($this->CharSet); + // Try to select the encoding which should produce the shortest output + if ($matchcount > strlen($str) / 3) { + // More than a third of the content will need encoding, so B encoding will be most efficient + $encoding = 'B'; + if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) { + // Use a custom function which correctly encodes and wraps long + // multibyte strings without breaking lines within a character + $encoded = $this->base64EncodeWrapMB($str, "\n"); + } else { + $encoded = base64_encode($str); + $maxlen -= $maxlen % 4; + $encoded = trim(chunk_split($encoded, $maxlen, "\n")); + } + } else { + $encoding = 'Q'; + $encoded = $this->encodeQ($str, $position); + $encoded = $this->wrapText($encoded, $maxlen, true); + $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded)); + } + + $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded); + $encoded = trim(str_replace("\n", $this->LE, $encoded)); + + return $encoded; + } + + /** + * Check if a string contains multi-byte characters. + * @access public + * @param string $str multi-byte text to wrap encode + * @return boolean + */ + public function hasMultiBytes($str) + { + if (function_exists('mb_strlen')) { + return (strlen($str) > mb_strlen($str, $this->CharSet)); + } else { // Assume no multibytes (we can't handle without mbstring functions anyway) + return false; + } + } + + /** + * Does a string contain any 8-bit chars (in any charset)? + * @param string $text + * @return boolean + */ + public function has8bitChars($text) + { + return (boolean)preg_match('/[\x80-\xFF]/', $text); + } + + /** + * Encode and wrap long multibyte strings for mail headers + * without breaking lines within a character. + * Adapted from a function by paravoid + * @link http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283 + * @access public + * @param string $str multi-byte text to wrap encode + * @param string $linebreak string to use as linefeed/end-of-line + * @return string + */ + public function base64EncodeWrapMB($str, $linebreak = null) + { + $start = '=?' . $this->CharSet . '?B?'; + $end = '?='; + $encoded = ''; + if ($linebreak === null) { + $linebreak = $this->LE; + } + + $mb_length = mb_strlen($str, $this->CharSet); + // Each line must have length <= 75, including $start and $end + $length = 75 - strlen($start) - strlen($end); + // Average multi-byte ratio + $ratio = $mb_length / strlen($str); + // Base64 has a 4:3 ratio + $avgLength = floor($length * $ratio * .75); + + for ($i = 0; $i < $mb_length; $i += $offset) { + $lookBack = 0; + do { + $offset = $avgLength - $lookBack; + $chunk = mb_substr($str, $i, $offset, $this->CharSet); + $chunk = base64_encode($chunk); + $lookBack++; + } while (strlen($chunk) > $length); + $encoded .= $chunk . $linebreak; + } + + // Chomp the last linefeed + $encoded = substr($encoded, 0, -strlen($linebreak)); + return $encoded; + } + + /** + * Encode a string in quoted-printable format. + * According to RFC2045 section 6.7. + * @access public + * @param string $string The text to encode + * @param integer $line_max Number of chars allowed on a line before wrapping + * @return string + * @link http://www.php.net/manual/en/function.quoted-printable-decode.php#89417 Adapted from this comment + */ + public function encodeQP($string, $line_max = 76) + { + // Use native function if it's available (>= PHP5.3) + if (function_exists('quoted_printable_encode')) { + return quoted_printable_encode($string); + } + // Fall back to a pure PHP implementation + $string = str_replace( + array('%20', '%0D%0A.', '%0D%0A', '%'), + array(' ', "\r\n=2E", "\r\n", '='), + rawurlencode($string) + ); + return preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string); + } + + /** + * Backward compatibility wrapper for an old QP encoding function that was removed. + * @see PHPMailer::encodeQP() + * @access public + * @param string $string + * @param integer $line_max + * @param boolean $space_conv + * @return string + * @deprecated Use encodeQP instead. + */ + public function encodeQPphp( + $string, + $line_max = 76, + /** @noinspection PhpUnusedParameterInspection */ $space_conv = false + ) { + return $this->encodeQP($string, $line_max); + } + + /** + * Encode a string using Q encoding. + * @link http://tools.ietf.org/html/rfc2047 + * @param string $str the text to encode + * @param string $position Where the text is going to be used, see the RFC for what that means + * @access public + * @return string + */ + public function encodeQ($str, $position = 'text') + { + // There should not be any EOL in the string + $pattern = ''; + $encoded = str_replace(array("\r", "\n"), '', $str); + switch (strtolower($position)) { + case 'phrase': + // RFC 2047 section 5.3 + $pattern = '^A-Za-z0-9!*+\/ -'; + break; + /** @noinspection PhpMissingBreakStatementInspection */ + case 'comment': + // RFC 2047 section 5.2 + $pattern = '\(\)"'; + // intentional fall-through + // for this reason we build the $pattern without including delimiters and [] + case 'text': + default: + // RFC 2047 section 5.1 + // Replace every high ascii, control, =, ? and _ characters + $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern; + break; + } + $matches = array(); + if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) { + // If the string contains an '=', make sure it's the first thing we replace + // so as to avoid double-encoding + $eqkey = array_search('=', $matches[0]); + if (false !== $eqkey) { + unset($matches[0][$eqkey]); + array_unshift($matches[0], '='); + } + foreach (array_unique($matches[0]) as $char) { + $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded); + } + } + // Replace every spaces to _ (more readable than =20) + return str_replace(' ', '_', $encoded); + } + + /** + * Add a string or binary attachment (non-filesystem). + * This method can be used to attach ascii or binary data, + * such as a BLOB record from a database. + * @param string $string String attachment data. + * @param string $filename Name of the attachment. + * @param string $encoding File encoding (see $Encoding). + * @param string $type File extension (MIME) type. + * @param string $disposition Disposition to use + * @return void + */ + public function addStringAttachment( + $string, + $filename, + $encoding = 'base64', + $type = '', + $disposition = 'attachment' + ) { + // If a MIME type is not specified, try to work it out from the file name + if ($type == '') { + $type = self::filenameToType($filename); + } + // Append to $attachment array + $this->attachment[] = array( + 0 => $string, + 1 => $filename, + 2 => basename($filename), + 3 => $encoding, + 4 => $type, + 5 => true, // isStringAttachment + 6 => $disposition, + 7 => 0 + ); + } + + /** + * Add an embedded (inline) attachment from a file. + * This can include images, sounds, and just about any other document type. + * These differ from 'regular' attachments in that they are intended to be + * displayed inline with the message, not just attached for download. + * This is used in HTML messages that embed the images + * the HTML refers to using the $cid value. + * @param string $path Path to the attachment. + * @param string $cid Content ID of the attachment; Use this to reference + * the content when using an embedded image in HTML. + * @param string $name Overrides the attachment name. + * @param string $encoding File encoding (see $Encoding). + * @param string $type File MIME type. + * @param string $disposition Disposition to use + * @return boolean True on successfully adding an attachment + */ + public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline') + { + if (!@is_file($path)) { + $this->setError($this->lang('file_access') . $path); + return false; + } + + // If a MIME type is not specified, try to work it out from the file name + if ($type == '') { + $type = self::filenameToType($path); + } + + $filename = basename($path); + if ($name == '') { + $name = $filename; + } + + // Append to $attachment array + $this->attachment[] = array( + 0 => $path, + 1 => $filename, + 2 => $name, + 3 => $encoding, + 4 => $type, + 5 => false, // isStringAttachment + 6 => $disposition, + 7 => $cid + ); + return true; + } + + /** + * Add an embedded stringified attachment. + * This can include images, sounds, and just about any other document type. + * Be sure to set the $type to an image type for images: + * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'. + * @param string $string The attachment binary data. + * @param string $cid Content ID of the attachment; Use this to reference + * the content when using an embedded image in HTML. + * @param string $name + * @param string $encoding File encoding (see $Encoding). + * @param string $type MIME type. + * @param string $disposition Disposition to use + * @return boolean True on successfully adding an attachment + */ + public function addStringEmbeddedImage( + $string, + $cid, + $name = '', + $encoding = 'base64', + $type = '', + $disposition = 'inline' + ) { + // If a MIME type is not specified, try to work it out from the name + if ($type == '' and !empty($name)) { + $type = self::filenameToType($name); + } + + // Append to $attachment array + $this->attachment[] = array( + 0 => $string, + 1 => $name, + 2 => $name, + 3 => $encoding, + 4 => $type, + 5 => true, // isStringAttachment + 6 => $disposition, + 7 => $cid + ); + return true; + } + + /** + * Check if an inline attachment is present. + * @access public + * @return boolean + */ + public function inlineImageExists() + { + foreach ($this->attachment as $attachment) { + if ($attachment[6] == 'inline') { + return true; + } + } + return false; + } + + /** + * Check if an attachment (non-inline) is present. + * @return boolean + */ + public function attachmentExists() + { + foreach ($this->attachment as $attachment) { + if ($attachment[6] == 'attachment') { + return true; + } + } + return false; + } + + /** + * Check if this message has an alternative body set. + * @return boolean + */ + public function alternativeExists() + { + return !empty($this->AltBody); + } + + /** + * Clear queued addresses of given kind. + * @access protected + * @param string $kind 'to', 'cc', or 'bcc' + * @return void + */ + public function clearQueuedAddresses($kind) + { + $RecipientsQueue = $this->RecipientsQueue; + foreach ($RecipientsQueue as $address => $params) { + if ($params[0] == $kind) { + unset($this->RecipientsQueue[$address]); + } + } + } + + /** + * Clear all To recipients. + * @return void + */ + public function clearAddresses() + { + foreach ($this->to as $to) { + unset($this->all_recipients[strtolower($to[0])]); + } + $this->to = array(); + $this->clearQueuedAddresses('to'); + } + + /** + * Clear all CC recipients. + * @return void + */ + public function clearCCs() + { + foreach ($this->cc as $cc) { + unset($this->all_recipients[strtolower($cc[0])]); + } + $this->cc = array(); + $this->clearQueuedAddresses('cc'); + } + + /** + * Clear all BCC recipients. + * @return void + */ + public function clearBCCs() + { + foreach ($this->bcc as $bcc) { + unset($this->all_recipients[strtolower($bcc[0])]); + } + $this->bcc = array(); + $this->clearQueuedAddresses('bcc'); + } + + /** + * Clear all ReplyTo recipients. + * @return void + */ + public function clearReplyTos() + { + $this->ReplyTo = array(); + $this->ReplyToQueue = array(); + } + + /** + * Clear all recipient types. + * @return void + */ + public function clearAllRecipients() + { + $this->to = array(); + $this->cc = array(); + $this->bcc = array(); + $this->all_recipients = array(); + $this->RecipientsQueue = array(); + } + + /** + * Clear all filesystem, string, and binary attachments. + * @return void + */ + public function clearAttachments() + { + $this->attachment = array(); + } + + /** + * Clear all custom headers. + * @return void + */ + public function clearCustomHeaders() + { + $this->CustomHeader = array(); + } + + /** + * Add an error message to the error container. + * @access protected + * @param string $msg + * @return void + */ + protected function setError($msg) + { + $this->error_count++; + if ($this->Mailer == 'smtp' and !is_null($this->smtp)) { + $lasterror = $this->smtp->getError(); + if (!empty($lasterror['error'])) { + $msg .= $this->lang('smtp_error') . $lasterror['error']; + if (!empty($lasterror['detail'])) { + $msg .= ' Detail: '. $lasterror['detail']; + } + if (!empty($lasterror['smtp_code'])) { + $msg .= ' SMTP code: ' . $lasterror['smtp_code']; + } + if (!empty($lasterror['smtp_code_ex'])) { + $msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex']; + } + } + } + $this->ErrorInfo = $msg; + } + + /** + * Return an RFC 822 formatted date. + * @access public + * @return string + * @static + */ + public static function rfcDate() + { + // Set the time zone to whatever the default is to avoid 500 errors + // Will default to UTC if it's not set properly in php.ini + date_default_timezone_set(@date_default_timezone_get()); + return date('D, j M Y H:i:s O'); + } + + /** + * Get the server hostname. + * Returns 'localhost.localdomain' if unknown. + * @access protected + * @return string + */ + protected function serverHostname() + { + $result = 'localhost.localdomain'; + if (!empty($this->Hostname)) { + $result = $this->Hostname; + } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) { + $result = $_SERVER['SERVER_NAME']; + } elseif (function_exists('gethostname') && gethostname() !== false) { + $result = gethostname(); + } elseif (php_uname('n') !== false) { + $result = php_uname('n'); + } + return $result; + } + + /** + * Get an error message in the current language. + * @access protected + * @param string $key + * @return string + */ + protected function lang($key) + { + if (count($this->language) < 1) { + $this->setLanguage('en'); // set the default language + } + + if (array_key_exists($key, $this->language)) { + if ($key == 'smtp_connect_failed') { + //Include a link to troubleshooting docs on SMTP connection failure + //this is by far the biggest cause of support questions + //but it's usually not PHPMailer's fault. + return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting'; + } + return $this->language[$key]; + } else { + //Return the key as a fallback + return $key; + } + } + + /** + * Check if an error occurred. + * @access public + * @return boolean True if an error did occur. + */ + public function isError() + { + return ($this->error_count > 0); + } + + /** + * Ensure consistent line endings in a string. + * Changes every end of line from CRLF, CR or LF to $this->LE. + * @access public + * @param string $str String to fixEOL + * @return string + */ + public function fixEOL($str) + { + // Normalise to \n + $nstr = str_replace(array("\r\n", "\r"), "\n", $str); + // Now convert LE as needed + if ($this->LE !== "\n") { + $nstr = str_replace("\n", $this->LE, $nstr); + } + return $nstr; + } + + /** + * Add a custom header. + * $name value can be overloaded to contain + * both header name and value (name:value) + * @access public + * @param string $name Custom header name + * @param string $value Header value + * @return void + */ + public function addCustomHeader($name, $value = null) + { + if ($value === null) { + // Value passed in as name:value + $this->CustomHeader[] = explode(':', $name, 2); + } else { + $this->CustomHeader[] = array($name, $value); + } + } + + /** + * Returns all custom headers. + * @return array + */ + public function getCustomHeaders() + { + return $this->CustomHeader; + } + + /** + * Create a message body from an HTML string. + * Automatically inlines images and creates a plain-text version by converting the HTML, + * overwriting any existing values in Body and AltBody. + * $basedir is used when handling relative image paths, e.g. + * will look for an image file in $basedir/images/a.png and convert it to inline. + * If you don't want to apply these transformations to your HTML, just set Body and AltBody yourself. + * @access public + * @param string $message HTML message string + * @param string $basedir base directory for relative paths to images + * @param boolean|callable $advanced Whether to use the internal HTML to text converter + * or your own custom converter @see PHPMailer::html2text() + * @return string $message The transformed message Body + */ + public function msgHTML($message, $basedir = '', $advanced = false) + { + preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images); + if (array_key_exists(2, $images)) { + foreach ($images[2] as $imgindex => $url) { + // Convert data URIs into embedded images + if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) { + $data = substr($url, strpos($url, ',')); + if ($match[2]) { + $data = base64_decode($data); + } else { + $data = rawurldecode($data); + } + $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2 + if ($this->addStringEmbeddedImage($data, $cid, 'embed' . $imgindex, 'base64', $match[1])) { + $message = str_replace( + $images[0][$imgindex], + $images[1][$imgindex] . '="cid:' . $cid . '"', + $message + ); + } + } elseif (substr($url, 0, 4) !== 'cid:' && !preg_match('#^[a-z][a-z0-9+.-]*://#i', $url)) { + // Do not change urls for absolute images (thanks to corvuscorax) + // Do not change urls that are already inline images + $filename = basename($url); + $directory = dirname($url); + if ($directory == '.') { + $directory = ''; + } + $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2 + if (strlen($basedir) > 1 && substr($basedir, -1) != '/') { + $basedir .= '/'; + } + if (strlen($directory) > 1 && substr($directory, -1) != '/') { + $directory .= '/'; + } + if ($this->addEmbeddedImage( + $basedir . $directory . $filename, + $cid, + $filename, + 'base64', + self::_mime_types((string)self::mb_pathinfo($filename, PATHINFO_EXTENSION)) + ) + ) { + $message = preg_replace( + '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui', + $images[1][$imgindex] . '="cid:' . $cid . '"', + $message + ); + } + } + } + } + $this->isHTML(true); + // Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better + $this->Body = $this->normalizeBreaks($message); + $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced)); + if (!$this->alternativeExists()) { + $this->AltBody = 'To view this email message, open it in a program that understands HTML!' . + self::CRLF . self::CRLF; + } + return $this->Body; + } + + /** + * Convert an HTML string into plain text. + * This is used by msgHTML(). + * Note - older versions of this function used a bundled advanced converter + * which was been removed for license reasons in #232. + * Example usage: + * + * // Use default conversion + * $plain = $mail->html2text($html); + * // Use your own custom converter + * $plain = $mail->html2text($html, function($html) { + * $converter = new MyHtml2text($html); + * return $converter->get_text(); + * }); + * + * @param string $html The HTML text to convert + * @param boolean|callable $advanced Any boolean value to use the internal converter, + * or provide your own callable for custom conversion. + * @return string + */ + public function html2text($html, $advanced = false) + { + if (is_callable($advanced)) { + return call_user_func($advanced, $html); + } + return html_entity_decode( + trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))), + ENT_QUOTES, + $this->CharSet + ); + } + + /** + * Get the MIME type for a file extension. + * @param string $ext File extension + * @access public + * @return string MIME type of file. + * @static + */ + public static function _mime_types($ext = '') + { + $mimes = array( + 'xl' => 'application/excel', + 'js' => 'application/javascript', + 'hqx' => 'application/mac-binhex40', + 'cpt' => 'application/mac-compactpro', + 'bin' => 'application/macbinary', + 'doc' => 'application/msword', + 'word' => 'application/msword', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', + 'class' => 'application/octet-stream', + 'dll' => 'application/octet-stream', + 'dms' => 'application/octet-stream', + 'exe' => 'application/octet-stream', + 'lha' => 'application/octet-stream', + 'lzh' => 'application/octet-stream', + 'psd' => 'application/octet-stream', + 'sea' => 'application/octet-stream', + 'so' => 'application/octet-stream', + 'oda' => 'application/oda', + 'pdf' => 'application/pdf', + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'mif' => 'application/vnd.mif', + 'xls' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'dcr' => 'application/x-director', + 'dir' => 'application/x-director', + 'dxr' => 'application/x-director', + 'dvi' => 'application/x-dvi', + 'gtar' => 'application/x-gtar', + 'php3' => 'application/x-httpd-php', + 'php4' => 'application/x-httpd-php', + 'php' => 'application/x-httpd-php', + 'phtml' => 'application/x-httpd-php', + 'phps' => 'application/x-httpd-php-source', + 'swf' => 'application/x-shockwave-flash', + 'sit' => 'application/x-stuffit', + 'tar' => 'application/x-tar', + 'tgz' => 'application/x-tar', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'zip' => 'application/zip', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mp2' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'mpga' => 'audio/mpeg', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'ram' => 'audio/x-pn-realaudio', + 'rm' => 'audio/x-pn-realaudio', + 'rpm' => 'audio/x-pn-realaudio-plugin', + 'ra' => 'audio/x-realaudio', + 'wav' => 'audio/x-wav', + 'bmp' => 'image/bmp', + 'gif' => 'image/gif', + 'jpeg' => 'image/jpeg', + 'jpe' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'png' => 'image/png', + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'eml' => 'message/rfc822', + 'css' => 'text/css', + 'html' => 'text/html', + 'htm' => 'text/html', + 'shtml' => 'text/html', + 'log' => 'text/plain', + 'text' => 'text/plain', + 'txt' => 'text/plain', + 'rtx' => 'text/richtext', + 'rtf' => 'text/rtf', + 'vcf' => 'text/vcard', + 'vcard' => 'text/vcard', + 'xml' => 'text/xml', + 'xsl' => 'text/xml', + 'mpeg' => 'video/mpeg', + 'mpe' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mov' => 'video/quicktime', + 'qt' => 'video/quicktime', + 'rv' => 'video/vnd.rn-realvideo', + 'avi' => 'video/x-msvideo', + 'movie' => 'video/x-sgi-movie' + ); + if (array_key_exists(strtolower($ext), $mimes)) { + return $mimes[strtolower($ext)]; + } + return 'application/octet-stream'; + } + + /** + * Map a file name to a MIME type. + * Defaults to 'application/octet-stream', i.e.. arbitrary binary data. + * @param string $filename A file name or full path, does not need to exist as a file + * @return string + * @static + */ + public static function filenameToType($filename) + { + // In case the path is a URL, strip any query string before getting extension + $qpos = strpos($filename, '?'); + if (false !== $qpos) { + $filename = substr($filename, 0, $qpos); + } + $pathinfo = self::mb_pathinfo($filename); + return self::_mime_types($pathinfo['extension']); + } + + /** + * Multi-byte-safe pathinfo replacement. + * Drop-in replacement for pathinfo(), but multibyte-safe, cross-platform-safe, old-version-safe. + * Works similarly to the one in PHP >= 5.2.0 + * @link http://www.php.net/manual/en/function.pathinfo.php#107461 + * @param string $path A filename or path, does not need to exist as a file + * @param integer|string $options Either a PATHINFO_* constant, + * or a string name to return only the specified piece, allows 'filename' to work on PHP < 5.2 + * @return string|array + * @static + */ + public static function mb_pathinfo($path, $options = null) + { + $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => ''); + $pathinfo = array(); + if (preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $pathinfo)) { + if (array_key_exists(1, $pathinfo)) { + $ret['dirname'] = $pathinfo[1]; + } + if (array_key_exists(2, $pathinfo)) { + $ret['basename'] = $pathinfo[2]; + } + if (array_key_exists(5, $pathinfo)) { + $ret['extension'] = $pathinfo[5]; + } + if (array_key_exists(3, $pathinfo)) { + $ret['filename'] = $pathinfo[3]; + } + } + switch ($options) { + case PATHINFO_DIRNAME: + case 'dirname': + return $ret['dirname']; + case PATHINFO_BASENAME: + case 'basename': + return $ret['basename']; + case PATHINFO_EXTENSION: + case 'extension': + return $ret['extension']; + case PATHINFO_FILENAME: + case 'filename': + return $ret['filename']; + default: + return $ret; + } + } + + /** + * Set or reset instance properties. + * You should avoid this function - it's more verbose, less efficient, more error-prone and + * harder to debug than setting properties directly. + * Usage Example: + * `$mail->set('SMTPSecure', 'tls');` + * is the same as: + * `$mail->SMTPSecure = 'tls';` + * @access public + * @param string $name The property name to set + * @param mixed $value The value to set the property to + * @return boolean + * @TODO Should this not be using the __set() magic function? + */ + public function set($name, $value = '') + { + if (property_exists($this, $name)) { + $this->$name = $value; + return true; + } else { + $this->setError($this->lang('variable_set') . $name); + return false; + } + } + + /** + * Strip newlines to prevent header injection. + * @access public + * @param string $str + * @return string + */ + public function secureHeader($str) + { + return trim(str_replace(array("\r", "\n"), '', $str)); + } + + /** + * Normalize line breaks in a string. + * Converts UNIX LF, Mac CR and Windows CRLF line breaks into a single line break format. + * Defaults to CRLF (for message bodies) and preserves consecutive breaks. + * @param string $text + * @param string $breaktype What kind of line break to use, defaults to CRLF + * @return string + * @access public + * @static + */ + public static function normalizeBreaks($text, $breaktype = "\r\n") + { + return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text); + } + + /** + * Set the public and private key files and password for S/MIME signing. + * @access public + * @param string $cert_filename + * @param string $key_filename + * @param string $key_pass Password for private key + * @param string $extracerts_filename Optional path to chain certificate + */ + public function sign($cert_filename, $key_filename, $key_pass, $extracerts_filename = '') + { + $this->sign_cert_file = $cert_filename; + $this->sign_key_file = $key_filename; + $this->sign_key_pass = $key_pass; + $this->sign_extracerts_file = $extracerts_filename; + } + + /** + * Quoted-Printable-encode a DKIM header. + * @access public + * @param string $txt + * @return string + */ + public function DKIM_QP($txt) + { + $line = ''; + for ($i = 0; $i < strlen($txt); $i++) { + $ord = ord($txt[$i]); + if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E))) { + $line .= $txt[$i]; + } else { + $line .= '=' . sprintf('%02X', $ord); + } + } + return $line; + } + + /** + * Generate a DKIM signature. + * @access public + * @param string $signHeader + * @throws phpmailerException + * @return string The DKIM signature value + */ + public function DKIM_Sign($signHeader) + { + if (!defined('PKCS7_TEXT')) { + if ($this->exceptions) { + throw new phpmailerException($this->lang('extension_missing') . 'openssl'); + } + return ''; + } + $privKeyStr = file_get_contents($this->DKIM_private); + if ('' != $this->DKIM_passphrase) { + $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase); + } else { + $privKey = openssl_pkey_get_private($privKeyStr); + } + //Workaround for missing digest algorithms in old PHP & OpenSSL versions + //@link http://stackoverflow.com/a/11117338/333340 + if (version_compare(PHP_VERSION, '5.3.0') >= 0 and + in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) { + if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) { + openssl_pkey_free($privKey); + return base64_encode($signature); + } + } else { + $pinfo = openssl_pkey_get_details($privKey); + $hash = hash('sha256', $signHeader); + //'Magic' constant for SHA256 from RFC3447 + //@link https://tools.ietf.org/html/rfc3447#page-43 + $t = '3031300d060960864801650304020105000420' . $hash; + $pslen = $pinfo['bits'] / 8 - (strlen($t) / 2 + 3); + $eb = pack('H*', '0001' . str_repeat('FF', $pslen) . '00' . $t); + + if (openssl_private_encrypt($eb, $signature, $privKey, OPENSSL_NO_PADDING)) { + openssl_pkey_free($privKey); + return base64_encode($signature); + } + } + openssl_pkey_free($privKey); + return ''; + } + + /** + * Generate a DKIM canonicalization header. + * @access public + * @param string $signHeader Header + * @return string + */ + public function DKIM_HeaderC($signHeader) + { + $signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader); + $lines = explode("\r\n", $signHeader); + foreach ($lines as $key => $line) { + list($heading, $value) = explode(':', $line, 2); + $heading = strtolower($heading); + $value = preg_replace('/\s{2,}/', ' ', $value); // Compress useless spaces + $lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value + } + $signHeader = implode("\r\n", $lines); + return $signHeader; + } + + /** + * Generate a DKIM canonicalization body. + * @access public + * @param string $body Message Body + * @return string + */ + public function DKIM_BodyC($body) + { + if ($body == '') { + return "\r\n"; + } + // stabilize line endings + $body = str_replace("\r\n", "\n", $body); + $body = str_replace("\n", "\r\n", $body); + // END stabilize line endings + while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") { + $body = substr($body, 0, strlen($body) - 2); + } + return $body; + } + + /** + * Create the DKIM header and body in a new message header. + * @access public + * @param string $headers_line Header lines + * @param string $subject Subject + * @param string $body Body + * @return string + */ + public function DKIM_Add($headers_line, $subject, $body) + { + $DKIMsignatureType = 'rsa-sha256'; // Signature & hash algorithms + $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body + $DKIMquery = 'dns/txt'; // Query method + $DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone) + $subject_header = "Subject: $subject"; + $headers = explode($this->LE, $headers_line); + $from_header = ''; + $to_header = ''; + $date_header = ''; + $current = ''; + foreach ($headers as $header) { + if (strpos($header, 'From:') === 0) { + $from_header = $header; + $current = 'from_header'; + } elseif (strpos($header, 'To:') === 0) { + $to_header = $header; + $current = 'to_header'; + } elseif (strpos($header, 'Date:') === 0) { + $date_header = $header; + $current = 'date_header'; + } else { + if (!empty($$current) && strpos($header, ' =?') === 0) { + $$current .= $header; + } else { + $current = ''; + } + } + } + $from = str_replace('|', '=7C', $this->DKIM_QP($from_header)); + $to = str_replace('|', '=7C', $this->DKIM_QP($to_header)); + $date = str_replace('|', '=7C', $this->DKIM_QP($date_header)); + $subject = str_replace( + '|', + '=7C', + $this->DKIM_QP($subject_header) + ); // Copied header fields (dkim-quoted-printable) + $body = $this->DKIM_BodyC($body); + $DKIMlen = strlen($body); // Length of body + $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body + if ('' == $this->DKIM_identity) { + $ident = ''; + } else { + $ident = ' i=' . $this->DKIM_identity . ';'; + } + $dkimhdrs = 'DKIM-Signature: v=1; a=' . + $DKIMsignatureType . '; q=' . + $DKIMquery . '; l=' . + $DKIMlen . '; s=' . + $this->DKIM_selector . + ";\r\n" . + "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" . + "\th=From:To:Date:Subject;\r\n" . + "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" . + "\tz=$from\r\n" . + "\t|$to\r\n" . + "\t|$date\r\n" . + "\t|$subject;\r\n" . + "\tbh=" . $DKIMb64 . ";\r\n" . + "\tb="; + $toSign = $this->DKIM_HeaderC( + $from_header . "\r\n" . + $to_header . "\r\n" . + $date_header . "\r\n" . + $subject_header . "\r\n" . + $dkimhdrs + ); + $signed = $this->DKIM_Sign($toSign); + return $dkimhdrs . $signed . "\r\n"; + } + + /** + * Detect if a string contains a line longer than the maximum line length allowed. + * @param string $str + * @return boolean + * @static + */ + public static function hasLineLongerThanMax($str) + { + //+2 to include CRLF line break for a 1000 total + return (boolean)preg_match('/^(.{'.(self::MAX_LINE_LENGTH + 2).',})/m', $str); + } + + /** + * Allows for public read access to 'to' property. + * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * @access public + * @return array + */ + public function getToAddresses() + { + return $this->to; + } + + /** + * Allows for public read access to 'cc' property. + * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * @access public + * @return array + */ + public function getCcAddresses() + { + return $this->cc; + } + + /** + * Allows for public read access to 'bcc' property. + * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * @access public + * @return array + */ + public function getBccAddresses() + { + return $this->bcc; + } + + /** + * Allows for public read access to 'ReplyTo' property. + * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * @access public + * @return array + */ + public function getReplyToAddresses() + { + return $this->ReplyTo; + } + + /** + * Allows for public read access to 'all_recipients' property. + * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * @access public + * @return array + */ + public function getAllRecipientAddresses() + { + return $this->all_recipients; + } + + /** + * Perform a callback. + * @param boolean $isSent + * @param array $to + * @param array $cc + * @param array $bcc + * @param string $subject + * @param string $body + * @param string $from + */ + protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from) + { + if (!empty($this->action_function) && is_callable($this->action_function)) { + $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from); + call_user_func_array($this->action_function, $params); + } + } +} + +/** + * PHPMailer exception handler + * @package PHPMailer + */ +class phpmailerException extends Exception +{ + /** + * Prettify error message output + * @return string + */ + public function errorMessage() + { + $errorMsg = '' . $this->getMessage() . "
    \n"; + return $errorMsg; + } +} diff --git a/core/func/libs/mail/class.phpmaileroauth.php b/core/func/libs/mail/class.phpmaileroauth.php new file mode 100644 index 0000000..b1bb09f --- /dev/null +++ b/core/func/libs/mail/class.phpmaileroauth.php @@ -0,0 +1,197 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2014 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +/** + * PHPMailerOAuth - PHPMailer subclass adding OAuth support. + * @package PHPMailer + * @author @sherryl4george + * @author Marcus Bointon (@Synchro) + */ +class PHPMailerOAuth extends PHPMailer +{ + /** + * The OAuth user's email address + * @var string + */ + public $oauthUserEmail = ''; + + /** + * The OAuth refresh token + * @var string + */ + public $oauthRefreshToken = ''; + + /** + * The OAuth client ID + * @var string + */ + public $oauthClientId = ''; + + /** + * The OAuth client secret + * @var string + */ + public $oauthClientSecret = ''; + + /** + * An instance of the PHPMailerOAuthGoogle class. + * @var PHPMailerOAuthGoogle + * @access protected + */ + protected $oauth = null; + + /** + * Get a PHPMailerOAuthGoogle instance to use. + * @return PHPMailerOAuthGoogle + */ + public function getOAUTHInstance() + { + if (!is_object($this->oauth)) { + $this->oauth = new PHPMailerOAuthGoogle( + $this->oauthUserEmail, + $this->oauthClientSecret, + $this->oauthClientId, + $this->oauthRefreshToken + ); + } + return $this->oauth; + } + + /** + * Initiate a connection to an SMTP server. + * Overrides the original smtpConnect method to add support for OAuth. + * @param array $options An array of options compatible with stream_context_create() + * @uses SMTP + * @access public + * @return bool + * @throws phpmailerException + */ + public function smtpConnect($options = array()) + { + if (is_null($this->smtp)) { + $this->smtp = $this->getSMTPInstance(); + } + + if (is_null($this->oauth)) { + $this->oauth = $this->getOAUTHInstance(); + } + + // Already connected? + if ($this->smtp->connected()) { + return true; + } + + $this->smtp->setTimeout($this->Timeout); + $this->smtp->setDebugLevel($this->SMTPDebug); + $this->smtp->setDebugOutput($this->Debugoutput); + $this->smtp->setVerp($this->do_verp); + $hosts = explode(';', $this->Host); + $lastexception = null; + + foreach ($hosts as $hostentry) { + $hostinfo = array(); + if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) { + // Not a valid host entry + continue; + } + // $hostinfo[2]: optional ssl or tls prefix + // $hostinfo[3]: the hostname + // $hostinfo[4]: optional port number + // The host string prefix can temporarily override the current setting for SMTPSecure + // If it's not specified, the default value is used + $prefix = ''; + $secure = $this->SMTPSecure; + $tls = ($this->SMTPSecure == 'tls'); + if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) { + $prefix = 'ssl://'; + $tls = false; // Can't have SSL and TLS at the same time + $secure = 'ssl'; + } elseif ($hostinfo[2] == 'tls') { + $tls = true; + // tls doesn't use a prefix + $secure = 'tls'; + } + //Do we need the OpenSSL extension? + $sslext = defined('OPENSSL_ALGO_SHA1'); + if ('tls' === $secure or 'ssl' === $secure) { + //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled + if (!$sslext) { + throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL); + } + } + $host = $hostinfo[3]; + $port = $this->Port; + $tport = (integer)$hostinfo[4]; + if ($tport > 0 and $tport < 65536) { + $port = $tport; + } + if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) { + try { + if ($this->Helo) { + $hello = $this->Helo; + } else { + $hello = $this->serverHostname(); + } + $this->smtp->hello($hello); + //Automatically enable TLS encryption if: + // * it's not disabled + // * we have openssl extension + // * we are not already using SSL + // * the server offers STARTTLS + if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) { + $tls = true; + } + if ($tls) { + if (!$this->smtp->startTLS()) { + throw new phpmailerException($this->lang('connect_host')); + } + // We must resend HELO after tls negotiation + $this->smtp->hello($hello); + } + if ($this->SMTPAuth) { + if (!$this->smtp->authenticate( + $this->Username, + $this->Password, + $this->AuthType, + $this->Realm, + $this->Workstation, + $this->oauth + ) + ) { + throw new phpmailerException($this->lang('authenticate')); + } + } + return true; + } catch (phpmailerException $exc) { + $lastexception = $exc; + $this->edebug($exc->getMessage()); + // We must have connected, but then failed TLS or Auth, so close connection nicely + $this->smtp->quit(); + } + } + } + // If we get here, all connection attempts have failed, so close connection hard + $this->smtp->close(); + // As we've caught all exceptions, just report whatever the last one was + if ($this->exceptions and !is_null($lastexception)) { + throw $lastexception; + } + return false; + } +} diff --git a/core/func/libs/mail/class.phpmaileroauthgoogle.php b/core/func/libs/mail/class.phpmaileroauthgoogle.php new file mode 100644 index 0000000..71c9bd3 --- /dev/null +++ b/core/func/libs/mail/class.phpmaileroauthgoogle.php @@ -0,0 +1,77 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2014 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +/** + * PHPMailerOAuthGoogle - Wrapper for League OAuth2 Google provider. + * @package PHPMailer + * @author @sherryl4george + * @author Marcus Bointon (@Synchro) + * @link https://github.com/thephpleague/oauth2-client + */ +class PHPMailerOAuthGoogle +{ + private $oauthUserEmail = ''; + private $oauthRefreshToken = ''; + private $oauthClientId = ''; + private $oauthClientSecret = ''; + + /** + * @param string $UserEmail + * @param string $ClientSecret + * @param string $ClientId + * @param string $RefreshToken + */ + public function __construct( + $UserEmail, + $ClientSecret, + $ClientId, + $RefreshToken + ) { + $this->oauthClientId = $ClientId; + $this->oauthClientSecret = $ClientSecret; + $this->oauthRefreshToken = $RefreshToken; + $this->oauthUserEmail = $UserEmail; + } + + private function getProvider() + { + return new League\OAuth2\Client\Provider\Google([ + 'clientId' => $this->oauthClientId, + 'clientSecret' => $this->oauthClientSecret + ]); + } + + private function getGrant() + { + return new \League\OAuth2\Client\Grant\RefreshToken(); + } + + private function getToken() + { + $provider = $this->getProvider(); + $grant = $this->getGrant(); + return $provider->getAccessToken($grant, ['refresh_token' => $this->oauthRefreshToken]); + } + + public function getOauth64() + { + $token = $this->getToken(); + return base64_encode("user=" . $this->oauthUserEmail . "\001auth=Bearer " . $token . "\001\001"); + } +} diff --git a/core/func/libs/mail/class.pop3.php b/core/func/libs/mail/class.pop3.php new file mode 100644 index 0000000..56ad1bf --- /dev/null +++ b/core/func/libs/mail/class.pop3.php @@ -0,0 +1,407 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2014 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +/** + * PHPMailer POP-Before-SMTP Authentication Class. + * Specifically for PHPMailer to use for RFC1939 POP-before-SMTP authentication. + * Does not support APOP. + * @package PHPMailer + * @author Richard Davey (original author) + * @author Marcus Bointon (Synchro/coolbru) + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + */ +class POP3 +{ + /** + * The POP3 PHPMailer Version number. + * @var string + * @access public + */ + public $Version = '5.2.16'; + + /** + * Default POP3 port number. + * @var integer + * @access public + */ + public $POP3_PORT = 110; + + /** + * Default timeout in seconds. + * @var integer + * @access public + */ + public $POP3_TIMEOUT = 30; + + /** + * POP3 Carriage Return + Line Feed. + * @var string + * @access public + * @deprecated Use the constant instead + */ + public $CRLF = "\r\n"; + + /** + * Debug display level. + * Options: 0 = no, 1+ = yes + * @var integer + * @access public + */ + public $do_debug = 0; + + /** + * POP3 mail server hostname. + * @var string + * @access public + */ + public $host; + + /** + * POP3 port number. + * @var integer + * @access public + */ + public $port; + + /** + * POP3 Timeout Value in seconds. + * @var integer + * @access public + */ + public $tval; + + /** + * POP3 username + * @var string + * @access public + */ + public $username; + + /** + * POP3 password. + * @var string + * @access public + */ + public $password; + + /** + * Resource handle for the POP3 connection socket. + * @var resource + * @access protected + */ + protected $pop_conn; + + /** + * Are we connected? + * @var boolean + * @access protected + */ + protected $connected = false; + + /** + * Error container. + * @var array + * @access protected + */ + protected $errors = array(); + + /** + * Line break constant + */ + const CRLF = "\r\n"; + + /** + * Simple static wrapper for all-in-one POP before SMTP + * @param $host + * @param integer|boolean $port The port number to connect to + * @param integer|boolean $timeout The timeout value + * @param string $username + * @param string $password + * @param integer $debug_level + * @return boolean + */ + public static function popBeforeSmtp( + $host, + $port = false, + $timeout = false, + $username = '', + $password = '', + $debug_level = 0 + ) { + $pop = new POP3; + return $pop->authorise($host, $port, $timeout, $username, $password, $debug_level); + } + + /** + * Authenticate with a POP3 server. + * A connect, login, disconnect sequence + * appropriate for POP-before SMTP authorisation. + * @access public + * @param string $host The hostname to connect to + * @param integer|boolean $port The port number to connect to + * @param integer|boolean $timeout The timeout value + * @param string $username + * @param string $password + * @param integer $debug_level + * @return boolean + */ + public function authorise($host, $port = false, $timeout = false, $username = '', $password = '', $debug_level = 0) + { + $this->host = $host; + // If no port value provided, use default + if (false === $port) { + $this->port = $this->POP3_PORT; + } else { + $this->port = (integer)$port; + } + // If no timeout value provided, use default + if (false === $timeout) { + $this->tval = $this->POP3_TIMEOUT; + } else { + $this->tval = (integer)$timeout; + } + $this->do_debug = $debug_level; + $this->username = $username; + $this->password = $password; + // Reset the error log + $this->errors = array(); + // connect + $result = $this->connect($this->host, $this->port, $this->tval); + if ($result) { + $login_result = $this->login($this->username, $this->password); + if ($login_result) { + $this->disconnect(); + return true; + } + } + // We need to disconnect regardless of whether the login succeeded + $this->disconnect(); + return false; + } + + /** + * Connect to a POP3 server. + * @access public + * @param string $host + * @param integer|boolean $port + * @param integer $tval + * @return boolean + */ + public function connect($host, $port = false, $tval = 30) + { + // Are we already connected? + if ($this->connected) { + return true; + } + + //On Windows this will raise a PHP Warning error if the hostname doesn't exist. + //Rather than suppress it with @fsockopen, capture it cleanly instead + set_error_handler(array($this, 'catchWarning')); + + if (false === $port) { + $port = $this->POP3_PORT; + } + + // connect to the POP3 server + $this->pop_conn = fsockopen( + $host, // POP3 Host + $port, // Port # + $errno, // Error Number + $errstr, // Error Message + $tval + ); // Timeout (seconds) + // Restore the error handler + restore_error_handler(); + + // Did we connect? + if (false === $this->pop_conn) { + // It would appear not... + $this->setError(array( + 'error' => "Failed to connect to server $host on port $port", + 'errno' => $errno, + 'errstr' => $errstr + )); + return false; + } + + // Increase the stream time-out + stream_set_timeout($this->pop_conn, $tval, 0); + + // Get the POP3 server response + $pop3_response = $this->getResponse(); + // Check for the +OK + if ($this->checkResponse($pop3_response)) { + // The connection is established and the POP3 server is talking + $this->connected = true; + return true; + } + return false; + } + + /** + * Log in to the POP3 server. + * Does not support APOP (RFC 2828, 4949). + * @access public + * @param string $username + * @param string $password + * @return boolean + */ + public function login($username = '', $password = '') + { + if (!$this->connected) { + $this->setError('Not connected to POP3 server'); + } + if (empty($username)) { + $username = $this->username; + } + if (empty($password)) { + $password = $this->password; + } + + // Send the Username + $this->sendString("USER $username" . self::CRLF); + $pop3_response = $this->getResponse(); + if ($this->checkResponse($pop3_response)) { + // Send the Password + $this->sendString("PASS $password" . self::CRLF); + $pop3_response = $this->getResponse(); + if ($this->checkResponse($pop3_response)) { + return true; + } + } + return false; + } + + /** + * Disconnect from the POP3 server. + * @access public + */ + public function disconnect() + { + $this->sendString('QUIT'); + //The QUIT command may cause the daemon to exit, which will kill our connection + //So ignore errors here + try { + @fclose($this->pop_conn); + } catch (Exception $e) { + //Do nothing + }; + } + + /** + * Get a response from the POP3 server. + * $size is the maximum number of bytes to retrieve + * @param integer $size + * @return string + * @access protected + */ + protected function getResponse($size = 128) + { + $response = fgets($this->pop_conn, $size); + if ($this->do_debug >= 1) { + echo "Server -> Client: $response"; + } + return $response; + } + + /** + * Send raw data to the POP3 server. + * @param string $string + * @return integer + * @access protected + */ + protected function sendString($string) + { + if ($this->pop_conn) { + if ($this->do_debug >= 2) { //Show client messages when debug >= 2 + echo "Client -> Server: $string"; + } + return fwrite($this->pop_conn, $string, strlen($string)); + } + return 0; + } + + /** + * Checks the POP3 server response. + * Looks for for +OK or -ERR. + * @param string $string + * @return boolean + * @access protected + */ + protected function checkResponse($string) + { + if (substr($string, 0, 3) !== '+OK') { + $this->setError(array( + 'error' => "Server reported an error: $string", + 'errno' => 0, + 'errstr' => '' + )); + return false; + } else { + return true; + } + } + + /** + * Add an error to the internal error store. + * Also display debug output if it's enabled. + * @param $error + * @access protected + */ + protected function setError($error) + { + $this->errors[] = $error; + if ($this->do_debug >= 1) { + echo '
    ';
    +            foreach ($this->errors as $error) {
    +                print_r($error);
    +            }
    +            echo '
    '; + } + } + + /** + * Get an array of error messages, if any. + * @return array + */ + public function getErrors() + { + return $this->errors; + } + + /** + * POP3 connection error handler. + * @param integer $errno + * @param string $errstr + * @param string $errfile + * @param integer $errline + * @access protected + */ + protected function catchWarning($errno, $errstr, $errfile, $errline) + { + $this->setError(array( + 'error' => "Connecting to the POP3 server raised a PHP warning: ", + 'errno' => $errno, + 'errstr' => $errstr, + 'errfile' => $errfile, + 'errline' => $errline + )); + } +} diff --git a/core/func/libs/mail/class.smtp.php b/core/func/libs/mail/class.smtp.php new file mode 100644 index 0000000..b5a7ccc --- /dev/null +++ b/core/func/libs/mail/class.smtp.php @@ -0,0 +1,1214 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2014 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +/** + * PHPMailer RFC821 SMTP email transport class. + * Implements RFC 821 SMTP commands and provides some utility methods for sending mail to an SMTP server. + * @package PHPMailer + * @author Chris Ryan + * @author Marcus Bointon + */ +class SMTP +{ + /** + * The PHPMailer SMTP version number. + * @var string + */ + const VERSION = '5.2.16'; + + /** + * SMTP line break constant. + * @var string + */ + const CRLF = "\r\n"; + + /** + * The SMTP port to use if one is not specified. + * @var integer + */ + const DEFAULT_SMTP_PORT = 25; + + /** + * The maximum line length allowed by RFC 2822 section 2.1.1 + * @var integer + */ + const MAX_LINE_LENGTH = 998; + + /** + * Debug level for no output + */ + const DEBUG_OFF = 0; + + /** + * Debug level to show client -> server messages + */ + const DEBUG_CLIENT = 1; + + /** + * Debug level to show client -> server and server -> client messages + */ + const DEBUG_SERVER = 2; + + /** + * Debug level to show connection status, client -> server and server -> client messages + */ + const DEBUG_CONNECTION = 3; + + /** + * Debug level to show all messages + */ + const DEBUG_LOWLEVEL = 4; + + /** + * The PHPMailer SMTP Version number. + * @var string + * @deprecated Use the `VERSION` constant instead + * @see SMTP::VERSION + */ + public $Version = '5.2.16'; + + /** + * SMTP server port number. + * @var integer + * @deprecated This is only ever used as a default value, so use the `DEFAULT_SMTP_PORT` constant instead + * @see SMTP::DEFAULT_SMTP_PORT + */ + public $SMTP_PORT = 25; + + /** + * SMTP reply line ending. + * @var string + * @deprecated Use the `CRLF` constant instead + * @see SMTP::CRLF + */ + public $CRLF = "\r\n"; + + /** + * Debug output level. + * Options: + * * self::DEBUG_OFF (`0`) No debug output, default + * * self::DEBUG_CLIENT (`1`) Client commands + * * self::DEBUG_SERVER (`2`) Client commands and server responses + * * self::DEBUG_CONNECTION (`3`) As DEBUG_SERVER plus connection status + * * self::DEBUG_LOWLEVEL (`4`) Low-level data output, all messages + * @var integer + */ + public $do_debug = self::DEBUG_OFF; + + /** + * How to handle debug output. + * Options: + * * `echo` Output plain-text as-is, appropriate for CLI + * * `html` Output escaped, line breaks converted to `
    `, appropriate for browser output + * * `error_log` Output to error log as configured in php.ini + * + * Alternatively, you can provide a callable expecting two params: a message string and the debug level: + * + * $smtp->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";}; + * + * @var string|callable + */ + public $Debugoutput = 'echo'; + + /** + * Whether to use VERP. + * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path + * @link http://www.postfix.org/VERP_README.html Info on VERP + * @var boolean + */ + public $do_verp = false; + + /** + * The timeout value for connection, in seconds. + * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2 + * This needs to be quite high to function correctly with hosts using greetdelay as an anti-spam measure. + * @link http://tools.ietf.org/html/rfc2821#section-4.5.3.2 + * @var integer + */ + public $Timeout = 300; + + /** + * How long to wait for commands to complete, in seconds. + * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2 + * @var integer + */ + public $Timelimit = 300; + + /** + * The socket for the server connection. + * @var resource + */ + protected $smtp_conn; + + /** + * Error information, if any, for the last SMTP command. + * @var array + */ + protected $error = array( + 'error' => '', + 'detail' => '', + 'smtp_code' => '', + 'smtp_code_ex' => '' + ); + + /** + * The reply the server sent to us for HELO. + * If null, no HELO string has yet been received. + * @var string|null + */ + protected $helo_rply = null; + + /** + * The set of SMTP extensions sent in reply to EHLO command. + * Indexes of the array are extension names. + * Value at index 'HELO' or 'EHLO' (according to command that was sent) + * represents the server name. In case of HELO it is the only element of the array. + * Other values can be boolean TRUE or an array containing extension options. + * If null, no HELO/EHLO string has yet been received. + * @var array|null + */ + protected $server_caps = null; + + /** + * The most recent reply received from the server. + * @var string + */ + protected $last_reply = ''; + + /** + * Output debugging info via a user-selected method. + * @see SMTP::$Debugoutput + * @see SMTP::$do_debug + * @param string $str Debug string to output + * @param integer $level The debug level of this message; see DEBUG_* constants + * @return void + */ + protected function edebug($str, $level = 0) + { + if ($level > $this->do_debug) { + return; + } + //Avoid clash with built-in function names + if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) { + call_user_func($this->Debugoutput, $str, $level); + return; + } + switch ($this->Debugoutput) { + case 'error_log': + //Don't output, just log + error_log($str); + break; + case 'html': + //Cleans up output a bit for a better looking, HTML-safe output + echo htmlentities( + preg_replace('/[\r\n]+/', '', $str), + ENT_QUOTES, + 'UTF-8' + ) + . "
    \n"; + break; + case 'echo': + default: + //Normalize line breaks + $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str); + echo gmdate('Y-m-d H:i:s') . "\t" . str_replace( + "\n", + "\n \t ", + trim($str) + )."\n"; + } + } + + /** + * Connect to an SMTP server. + * @param string $host SMTP server IP or host name + * @param integer $port The port number to connect to + * @param integer $timeout How long to wait for the connection to open + * @param array $options An array of options for stream_context_create() + * @access public + * @return boolean + */ + public function connect($host, $port = null, $timeout = 30, $options = array()) + { + static $streamok; + //This is enabled by default since 5.0.0 but some providers disable it + //Check this once and cache the result + if (is_null($streamok)) { + $streamok = function_exists('stream_socket_client'); + } + // Clear errors to avoid confusion + $this->setError(''); + // Make sure we are __not__ connected + if ($this->connected()) { + // Already connected, generate error + $this->setError('Already connected to a server'); + return false; + } + if (empty($port)) { + $port = self::DEFAULT_SMTP_PORT; + } + // Connect to the SMTP server + $this->edebug( + "Connection: opening to $host:$port, timeout=$timeout, options=".var_export($options, true), + self::DEBUG_CONNECTION + ); + $errno = 0; + $errstr = ''; + if ($streamok) { + $socket_context = stream_context_create($options); + set_error_handler(array($this, 'errorHandler')); + $this->smtp_conn = stream_socket_client( + $host . ":" . $port, + $errno, + $errstr, + $timeout, + STREAM_CLIENT_CONNECT, + $socket_context + ); + restore_error_handler(); + } else { + //Fall back to fsockopen which should work in more places, but is missing some features + $this->edebug( + "Connection: stream_socket_client not available, falling back to fsockopen", + self::DEBUG_CONNECTION + ); + set_error_handler(array($this, 'errorHandler')); + $this->smtp_conn = fsockopen( + $host, + $port, + $errno, + $errstr, + $timeout + ); + restore_error_handler(); + } + // Verify we connected properly + if (!is_resource($this->smtp_conn)) { + $this->setError( + 'Failed to connect to server', + $errno, + $errstr + ); + $this->edebug( + 'SMTP ERROR: ' . $this->error['error'] + . ": $errstr ($errno)", + self::DEBUG_CLIENT + ); + return false; + } + $this->edebug('Connection: opened', self::DEBUG_CONNECTION); + // SMTP server can take longer to respond, give longer timeout for first read + // Windows does not have support for this timeout function + if (substr(PHP_OS, 0, 3) != 'WIN') { + $max = ini_get('max_execution_time'); + // Don't bother if unlimited + if ($max != 0 && $timeout > $max) { + @set_time_limit($timeout); + } + stream_set_timeout($this->smtp_conn, $timeout, 0); + } + // Get any announcement + $announce = $this->get_lines(); + $this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER); + return true; + } + + /** + * Initiate a TLS (encrypted) session. + * @access public + * @return boolean + */ + public function startTLS() + { + if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) { + return false; + } + + //Allow the best TLS version(s) we can + $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT; + + //PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT + //so add them back in manually if we can + if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) { + $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; + $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; + } + + // Begin encrypted connection + if (!stream_socket_enable_crypto( + $this->smtp_conn, + true, + $crypto_method + )) { + return false; + } + return true; + } + + /** + * Perform SMTP authentication. + * Must be run after hello(). + * @see hello() + * @param string $username The user name + * @param string $password The password + * @param string $authtype The auth type (PLAIN, LOGIN, NTLM, CRAM-MD5, XOAUTH2) + * @param string $realm The auth realm for NTLM + * @param string $workstation The auth workstation for NTLM + * @param null|OAuth $OAuth An optional OAuth instance (@see PHPMailerOAuth) + * @return bool True if successfully authenticated.* @access public + */ + public function authenticate( + $username, + $password, + $authtype = null, + $realm = '', + $workstation = '', + $OAuth = null + ) { + if (!$this->server_caps) { + $this->setError('Authentication is not allowed before HELO/EHLO'); + return false; + } + + if (array_key_exists('EHLO', $this->server_caps)) { + // SMTP extensions are available. Let's try to find a proper authentication method + + if (!array_key_exists('AUTH', $this->server_caps)) { + $this->setError('Authentication is not allowed at this stage'); + // 'at this stage' means that auth may be allowed after the stage changes + // e.g. after STARTTLS + return false; + } + + self::edebug('Auth method requested: ' . ($authtype ? $authtype : 'UNKNOWN'), self::DEBUG_LOWLEVEL); + self::edebug( + 'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']), + self::DEBUG_LOWLEVEL + ); + + if (empty($authtype)) { + foreach (array('CRAM-MD5', 'LOGIN', 'PLAIN', 'NTLM', 'XOAUTH2') as $method) { + if (in_array($method, $this->server_caps['AUTH'])) { + $authtype = $method; + break; + } + } + if (empty($authtype)) { + $this->setError('No supported authentication methods found'); + return false; + } + self::edebug('Auth method selected: '.$authtype, self::DEBUG_LOWLEVEL); + } + + if (!in_array($authtype, $this->server_caps['AUTH'])) { + $this->setError("The requested authentication method \"$authtype\" is not supported by the server"); + return false; + } + } elseif (empty($authtype)) { + $authtype = 'LOGIN'; + } + switch ($authtype) { + case 'PLAIN': + // Start authentication + if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) { + return false; + } + // Send encoded username and password + if (!$this->sendCommand( + 'User & Password', + base64_encode("\0" . $username . "\0" . $password), + 235 + ) + ) { + return false; + } + break; + case 'LOGIN': + // Start authentication + if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) { + return false; + } + if (!$this->sendCommand("Username", base64_encode($username), 334)) { + return false; + } + if (!$this->sendCommand("Password", base64_encode($password), 235)) { + return false; + } + break; + case 'XOAUTH2': + //If the OAuth Instance is not set. Can be a case when PHPMailer is used + //instead of PHPMailerOAuth + if (is_null($OAuth)) { + return false; + } + $oauth = $OAuth->getOauth64(); + + // Start authentication + if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) { + return false; + } + break; + case 'NTLM': + /* + * ntlm_sasl_client.php + * Bundled with Permission + * + * How to telnet in windows: + * http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx + * PROTOCOL Docs http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication + */ + require_once 'extras/ntlm_sasl_client.php'; + $temp = new stdClass; + $ntlm_client = new ntlm_sasl_client_class; + //Check that functions are available + if (!$ntlm_client->initialize($temp)) { + $this->setError($temp->error); + $this->edebug( + 'You need to enable some modules in your php.ini file: ' + . $this->error['error'], + self::DEBUG_CLIENT + ); + return false; + } + //msg1 + $msg1 = $ntlm_client->typeMsg1($realm, $workstation); //msg1 + + if (!$this->sendCommand( + 'AUTH NTLM', + 'AUTH NTLM ' . base64_encode($msg1), + 334 + ) + ) { + return false; + } + //Though 0 based, there is a white space after the 3 digit number + //msg2 + $challenge = substr($this->last_reply, 3); + $challenge = base64_decode($challenge); + $ntlm_res = $ntlm_client->NTLMResponse( + substr($challenge, 24, 8), + $password + ); + //msg3 + $msg3 = $ntlm_client->typeMsg3( + $ntlm_res, + $username, + $realm, + $workstation + ); + // send encoded username + return $this->sendCommand('Username', base64_encode($msg3), 235); + case 'CRAM-MD5': + // Start authentication + if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) { + return false; + } + // Get the challenge + $challenge = base64_decode(substr($this->last_reply, 4)); + + // Build the response + $response = $username . ' ' . $this->hmac($challenge, $password); + + // send encoded credentials + return $this->sendCommand('Username', base64_encode($response), 235); + default: + $this->setError("Authentication method \"$authtype\" is not supported"); + return false; + } + return true; + } + + /** + * Calculate an MD5 HMAC hash. + * Works like hash_hmac('md5', $data, $key) + * in case that function is not available + * @param string $data The data to hash + * @param string $key The key to hash with + * @access protected + * @return string + */ + protected function hmac($data, $key) + { + if (function_exists('hash_hmac')) { + return hash_hmac('md5', $data, $key); + } + + // The following borrowed from + // http://php.net/manual/en/function.mhash.php#27225 + + // RFC 2104 HMAC implementation for php. + // Creates an md5 HMAC. + // Eliminates the need to install mhash to compute a HMAC + // by Lance Rushing + + $bytelen = 64; // byte length for md5 + if (strlen($key) > $bytelen) { + $key = pack('H*', md5($key)); + } + $key = str_pad($key, $bytelen, chr(0x00)); + $ipad = str_pad('', $bytelen, chr(0x36)); + $opad = str_pad('', $bytelen, chr(0x5c)); + $k_ipad = $key ^ $ipad; + $k_opad = $key ^ $opad; + + return md5($k_opad . pack('H*', md5($k_ipad . $data))); + } + + /** + * Check connection state. + * @access public + * @return boolean True if connected. + */ + public function connected() + { + if (is_resource($this->smtp_conn)) { + $sock_status = stream_get_meta_data($this->smtp_conn); + if ($sock_status['eof']) { + // The socket is valid but we are not connected + $this->edebug( + 'SMTP NOTICE: EOF caught while checking if connected', + self::DEBUG_CLIENT + ); + $this->close(); + return false; + } + return true; // everything looks good + } + return false; + } + + /** + * Close the socket and clean up the state of the class. + * Don't use this function without first trying to use QUIT. + * @see quit() + * @access public + * @return void + */ + public function close() + { + $this->setError(''); + $this->server_caps = null; + $this->helo_rply = null; + if (is_resource($this->smtp_conn)) { + // close the connection and cleanup + fclose($this->smtp_conn); + $this->smtp_conn = null; //Makes for cleaner serialization + $this->edebug('Connection: closed', self::DEBUG_CONNECTION); + } + } + + /** + * Send an SMTP DATA command. + * Issues a data command and sends the msg_data to the server, + * finializing the mail transaction. $msg_data is the message + * that is to be send with the headers. Each header needs to be + * on a single line followed by a with the message headers + * and the message body being separated by and additional . + * Implements rfc 821: DATA + * @param string $msg_data Message data to send + * @access public + * @return boolean + */ + public function data($msg_data) + { + //This will use the standard timelimit + if (!$this->sendCommand('DATA', 'DATA', 354)) { + return false; + } + + /* The server is ready to accept data! + * According to rfc821 we should not send more than 1000 characters on a single line (including the CRLF) + * so we will break the data up into lines by \r and/or \n then if needed we will break each of those into + * smaller lines to fit within the limit. + * We will also look for lines that start with a '.' and prepend an additional '.'. + * NOTE: this does not count towards line-length limit. + */ + + // Normalize line breaks before exploding + $lines = explode("\n", str_replace(array("\r\n", "\r"), "\n", $msg_data)); + + /* To distinguish between a complete RFC822 message and a plain message body, we check if the first field + * of the first line (':' separated) does not contain a space then it _should_ be a header and we will + * process all lines before a blank line as headers. + */ + + $field = substr($lines[0], 0, strpos($lines[0], ':')); + $in_headers = false; + if (!empty($field) && strpos($field, ' ') === false) { + $in_headers = true; + } + + foreach ($lines as $line) { + $lines_out = array(); + if ($in_headers and $line == '') { + $in_headers = false; + } + //Break this line up into several smaller lines if it's too long + //Micro-optimisation: isset($str[$len]) is faster than (strlen($str) > $len), + while (isset($line[self::MAX_LINE_LENGTH])) { + //Working backwards, try to find a space within the last MAX_LINE_LENGTH chars of the line to break on + //so as to avoid breaking in the middle of a word + $pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' '); + //Deliberately matches both false and 0 + if (!$pos) { + //No nice break found, add a hard break + $pos = self::MAX_LINE_LENGTH - 1; + $lines_out[] = substr($line, 0, $pos); + $line = substr($line, $pos); + } else { + //Break at the found point + $lines_out[] = substr($line, 0, $pos); + //Move along by the amount we dealt with + $line = substr($line, $pos + 1); + } + //If processing headers add a LWSP-char to the front of new line RFC822 section 3.1.1 + if ($in_headers) { + $line = "\t" . $line; + } + } + $lines_out[] = $line; + + //Send the lines to the server + foreach ($lines_out as $line_out) { + //RFC2821 section 4.5.2 + if (!empty($line_out) and $line_out[0] == '.') { + $line_out = '.' . $line_out; + } + $this->client_send($line_out . self::CRLF); + } + } + + //Message data has been sent, complete the command + //Increase timelimit for end of DATA command + $savetimelimit = $this->Timelimit; + $this->Timelimit = $this->Timelimit * 2; + $result = $this->sendCommand('DATA END', '.', 250); + //Restore timelimit + $this->Timelimit = $savetimelimit; + return $result; + } + + /** + * Send an SMTP HELO or EHLO command. + * Used to identify the sending server to the receiving server. + * This makes sure that client and server are in a known state. + * Implements RFC 821: HELO + * and RFC 2821 EHLO. + * @param string $host The host name or IP to connect to + * @access public + * @return boolean + */ + public function hello($host = '') + { + //Try extended hello first (RFC 2821) + return (boolean)($this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host)); + } + + /** + * Send an SMTP HELO or EHLO command. + * Low-level implementation used by hello() + * @see hello() + * @param string $hello The HELO string + * @param string $host The hostname to say we are + * @access protected + * @return boolean + */ + protected function sendHello($hello, $host) + { + $noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250); + $this->helo_rply = $this->last_reply; + if ($noerror) { + $this->parseHelloFields($hello); + } else { + $this->server_caps = null; + } + return $noerror; + } + + /** + * Parse a reply to HELO/EHLO command to discover server extensions. + * In case of HELO, the only parameter that can be discovered is a server name. + * @access protected + * @param string $type - 'HELO' or 'EHLO' + */ + protected function parseHelloFields($type) + { + $this->server_caps = array(); + $lines = explode("\n", $this->helo_rply); + + foreach ($lines as $n => $s) { + //First 4 chars contain response code followed by - or space + $s = trim(substr($s, 4)); + if (empty($s)) { + continue; + } + $fields = explode(' ', $s); + if (!empty($fields)) { + if (!$n) { + $name = $type; + $fields = $fields[0]; + } else { + $name = array_shift($fields); + switch ($name) { + case 'SIZE': + $fields = ($fields ? $fields[0] : 0); + break; + case 'AUTH': + if (!is_array($fields)) { + $fields = array(); + } + break; + default: + $fields = true; + } + } + $this->server_caps[$name] = $fields; + } + } + } + + /** + * Send an SMTP MAIL command. + * Starts a mail transaction from the email address specified in + * $from. Returns true if successful or false otherwise. If True + * the mail transaction is started and then one or more recipient + * commands may be called followed by a data command. + * Implements rfc 821: MAIL FROM: + * @param string $from Source address of this message + * @access public + * @return boolean + */ + public function mail($from) + { + $useVerp = ($this->do_verp ? ' XVERP' : ''); + return $this->sendCommand( + 'MAIL FROM', + 'MAIL FROM:<' . $from . '>' . $useVerp, + 250 + ); + } + + /** + * Send an SMTP QUIT command. + * Closes the socket if there is no error or the $close_on_error argument is true. + * Implements from rfc 821: QUIT + * @param boolean $close_on_error Should the connection close if an error occurs? + * @access public + * @return boolean + */ + public function quit($close_on_error = true) + { + $noerror = $this->sendCommand('QUIT', 'QUIT', 221); + $err = $this->error; //Save any error + if ($noerror or $close_on_error) { + $this->close(); + $this->error = $err; //Restore any error from the quit command + } + return $noerror; + } + + /** + * Send an SMTP RCPT command. + * Sets the TO argument to $toaddr. + * Returns true if the recipient was accepted false if it was rejected. + * Implements from rfc 821: RCPT TO: + * @param string $address The address the message is being sent to + * @access public + * @return boolean + */ + public function recipient($address) + { + return $this->sendCommand( + 'RCPT TO', + 'RCPT TO:<' . $address . '>', + array(250, 251) + ); + } + + /** + * Send an SMTP RSET command. + * Abort any transaction that is currently in progress. + * Implements rfc 821: RSET + * @access public + * @return boolean True on success. + */ + public function reset() + { + return $this->sendCommand('RSET', 'RSET', 250); + } + + /** + * Send a command to an SMTP server and check its return code. + * @param string $command The command name - not sent to the server + * @param string $commandstring The actual command to send + * @param integer|array $expect One or more expected integer success codes + * @access protected + * @return boolean True on success. + */ + protected function sendCommand($command, $commandstring, $expect) + { + if (!$this->connected()) { + $this->setError("Called $command without being connected"); + return false; + } + //Reject line breaks in all commands + if (strpos($commandstring, "\n") !== false or strpos($commandstring, "\r") !== false) { + $this->setError("Command '$command' contained line breaks"); + return false; + } + $this->client_send($commandstring . self::CRLF); + + $this->last_reply = $this->get_lines(); + // Fetch SMTP code and possible error code explanation + $matches = array(); + if (preg_match("/^([0-9]{3})[ -](?:([0-9]\\.[0-9]\\.[0-9]) )?/", $this->last_reply, $matches)) { + $code = $matches[1]; + $code_ex = (count($matches) > 2 ? $matches[2] : null); + // Cut off error code from each response line + $detail = preg_replace( + "/{$code}[ -]".($code_ex ? str_replace('.', '\\.', $code_ex).' ' : '')."/m", + '', + $this->last_reply + ); + } else { + // Fall back to simple parsing if regex fails + $code = substr($this->last_reply, 0, 3); + $code_ex = null; + $detail = substr($this->last_reply, 4); + } + + $this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER); + + if (!in_array($code, (array)$expect)) { + $this->setError( + "$command command failed", + $detail, + $code, + $code_ex + ); + $this->edebug( + 'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply, + self::DEBUG_CLIENT + ); + return false; + } + + $this->setError(''); + return true; + } + + /** + * Send an SMTP SAML command. + * Starts a mail transaction from the email address specified in $from. + * Returns true if successful or false otherwise. If True + * the mail transaction is started and then one or more recipient + * commands may be called followed by a data command. This command + * will send the message to the users terminal if they are logged + * in and send them an email. + * Implements rfc 821: SAML FROM: + * @param string $from The address the message is from + * @access public + * @return boolean + */ + public function sendAndMail($from) + { + return $this->sendCommand('SAML', "SAML FROM:$from", 250); + } + + /** + * Send an SMTP VRFY command. + * @param string $name The name to verify + * @access public + * @return boolean + */ + public function verify($name) + { + return $this->sendCommand('VRFY', "VRFY $name", array(250, 251)); + } + + /** + * Send an SMTP NOOP command. + * Used to keep keep-alives alive, doesn't actually do anything + * @access public + * @return boolean + */ + public function noop() + { + return $this->sendCommand('NOOP', 'NOOP', 250); + } + + /** + * Send an SMTP TURN command. + * This is an optional command for SMTP that this class does not support. + * This method is here to make the RFC821 Definition complete for this class + * and _may_ be implemented in future + * Implements from rfc 821: TURN + * @access public + * @return boolean + */ + public function turn() + { + $this->setError('The SMTP TURN command is not implemented'); + $this->edebug('SMTP NOTICE: ' . $this->error['error'], self::DEBUG_CLIENT); + return false; + } + + /** + * Send raw data to the server. + * @param string $data The data to send + * @access public + * @return integer|boolean The number of bytes sent to the server or false on error + */ + public function client_send($data) + { + $this->edebug("CLIENT -> SERVER: $data", self::DEBUG_CLIENT); + return fwrite($this->smtp_conn, $data); + } + + /** + * Get the latest error. + * @access public + * @return array + */ + public function getError() + { + return $this->error; + } + + /** + * Get SMTP extensions available on the server + * @access public + * @return array|null + */ + public function getServerExtList() + { + return $this->server_caps; + } + + /** + * A multipurpose method + * The method works in three ways, dependent on argument value and current state + * 1. HELO/EHLO was not sent - returns null and set up $this->error + * 2. HELO was sent + * $name = 'HELO': returns server name + * $name = 'EHLO': returns boolean false + * $name = any string: returns null and set up $this->error + * 3. EHLO was sent + * $name = 'HELO'|'EHLO': returns server name + * $name = any string: if extension $name exists, returns boolean True + * or its options. Otherwise returns boolean False + * In other words, one can use this method to detect 3 conditions: + * - null returned: handshake was not or we don't know about ext (refer to $this->error) + * - false returned: the requested feature exactly not exists + * - positive value returned: the requested feature exists + * @param string $name Name of SMTP extension or 'HELO'|'EHLO' + * @return mixed + */ + public function getServerExt($name) + { + if (!$this->server_caps) { + $this->setError('No HELO/EHLO was sent'); + return null; + } + + // the tight logic knot ;) + if (!array_key_exists($name, $this->server_caps)) { + if ($name == 'HELO') { + return $this->server_caps['EHLO']; + } + if ($name == 'EHLO' || array_key_exists('EHLO', $this->server_caps)) { + return false; + } + $this->setError('HELO handshake was used. Client knows nothing about server extensions'); + return null; + } + + return $this->server_caps[$name]; + } + + /** + * Get the last reply from the server. + * @access public + * @return string + */ + public function getLastReply() + { + return $this->last_reply; + } + + /** + * Read the SMTP server's response. + * Either before eof or socket timeout occurs on the operation. + * With SMTP we can tell if we have more lines to read if the + * 4th character is '-' symbol. If it is a space then we don't + * need to read anything else. + * @access protected + * @return string + */ + protected function get_lines() + { + // If the connection is bad, give up straight away + if (!is_resource($this->smtp_conn)) { + return ''; + } + $data = ''; + $endtime = 0; + stream_set_timeout($this->smtp_conn, $this->Timeout); + if ($this->Timelimit > 0) { + $endtime = time() + $this->Timelimit; + } + while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) { + $str = @fgets($this->smtp_conn, 515); + $this->edebug("SMTP -> get_lines(): \$data is \"$data\"", self::DEBUG_LOWLEVEL); + $this->edebug("SMTP -> get_lines(): \$str is \"$str\"", self::DEBUG_LOWLEVEL); + $data .= $str; + // If 4th character is a space, we are done reading, break the loop, micro-optimisation over strlen + if ((isset($str[3]) and $str[3] == ' ')) { + break; + } + // Timed-out? Log and break + $info = stream_get_meta_data($this->smtp_conn); + if ($info['timed_out']) { + $this->edebug( + 'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)', + self::DEBUG_LOWLEVEL + ); + break; + } + // Now check if reads took too long + if ($endtime and time() > $endtime) { + $this->edebug( + 'SMTP -> get_lines(): timelimit reached ('. + $this->Timelimit . ' sec)', + self::DEBUG_LOWLEVEL + ); + break; + } + } + return $data; + } + + /** + * Enable or disable VERP address generation. + * @param boolean $enabled + */ + public function setVerp($enabled = false) + { + $this->do_verp = $enabled; + } + + /** + * Get VERP address generation mode. + * @return boolean + */ + public function getVerp() + { + return $this->do_verp; + } + + /** + * Set error messages and codes. + * @param string $message The error message + * @param string $detail Further detail on the error + * @param string $smtp_code An associated SMTP error code + * @param string $smtp_code_ex Extended SMTP code + */ + protected function setError($message, $detail = '', $smtp_code = '', $smtp_code_ex = '') + { + $this->error = array( + 'error' => $message, + 'detail' => $detail, + 'smtp_code' => $smtp_code, + 'smtp_code_ex' => $smtp_code_ex + ); + } + + /** + * Set debug output method. + * @param string|callable $method The name of the mechanism to use for debugging output, or a callable to handle it. + */ + public function setDebugOutput($method = 'echo') + { + $this->Debugoutput = $method; + } + + /** + * Get debug output method. + * @return string + */ + public function getDebugOutput() + { + return $this->Debugoutput; + } + + /** + * Set debug output level. + * @param integer $level + */ + public function setDebugLevel($level = 0) + { + $this->do_debug = $level; + } + + /** + * Get debug output level. + * @return integer + */ + public function getDebugLevel() + { + return $this->do_debug; + } + + /** + * Set SMTP timeout. + * @param integer $timeout + */ + public function setTimeout($timeout = 0) + { + $this->Timeout = $timeout; + } + + /** + * Get SMTP timeout. + * @return integer + */ + public function getTimeout() + { + return $this->Timeout; + } + + /** + * Reports an error number and string. + * @param integer $errno The error number returned by PHP. + * @param string $errmsg The error message returned by PHP. + */ + protected function errorHandler($errno, $errmsg) + { + $notice = 'Connection: Failed to connect to server.'; + $this->setError( + $notice, + $errno, + $errmsg + ); + $this->edebug( + $notice . ' Error number ' . $errno . '. "Error notice: ' . $errmsg, + self::DEBUG_CONNECTION + ); + } +} diff --git a/core/func/libs/mail/composer.json b/core/func/libs/mail/composer.json new file mode 100644 index 0000000..1112fb9 --- /dev/null +++ b/core/func/libs/mail/composer.json @@ -0,0 +1,44 @@ +{ + "name": "phpmailer/phpmailer", + "type": "library", + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "authors": [ + { + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" + }, + { + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" + }, + { + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" + }, + { + "name": "Brent R. Matzelle" + } + ], + "require": { + "php": ">=5.0.0" + }, + "require-dev": { + "phpdocumentor/phpdocumentor": "*", + "phpunit/phpunit": "4.7.*" + }, + "suggest": { + "league/oauth2-google": "Needed for Google XOAUTH2 authentication" + }, + "autoload": { + "classmap": [ + "class.phpmailer.php", + "class.phpmaileroauth.php", + "class.phpmaileroauthgoogle.php", + "class.smtp.php", + "class.pop3.php", + "extras/EasyPeasyICS.php", + "extras/ntlm_sasl_client.php" + ] + }, + "license": "LGPL-2.1" +} diff --git a/core/func/libs/mail/composer.lock b/core/func/libs/mail/composer.lock new file mode 100644 index 0000000..9edbf55 --- /dev/null +++ b/core/func/libs/mail/composer.lock @@ -0,0 +1,3576 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "ca5abc72444d9608a35c39f9064c139b", + "content-hash": "8b66ed71ae9ca8cd0258c814615d624f", + "packages": [], + "packages-dev": [ + { + "name": "cilex/cilex", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/Cilex/Cilex.git", + "reference": "7acd965a609a56d0345e8b6071c261fbdb926cb5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Cilex/Cilex/zipball/7acd965a609a56d0345e8b6071c261fbdb926cb5", + "reference": "7acd965a609a56d0345e8b6071c261fbdb926cb5", + "shasum": "" + }, + "require": { + "cilex/console-service-provider": "1.*", + "php": ">=5.3.3", + "pimple/pimple": "~1.0", + "symfony/finder": "~2.1", + "symfony/process": "~2.1" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*", + "symfony/validator": "~2.1" + }, + "suggest": { + "monolog/monolog": ">=1.0.0", + "symfony/validator": ">=1.0.0", + "symfony/yaml": ">=1.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-0": { + "Cilex": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "description": "The PHP micro-framework for Command line tools based on the Symfony2 Components", + "homepage": "http://cilex.github.com", + "keywords": [ + "cli", + "microframework" + ], + "time": "2014-03-29 14:03:13" + }, + { + "name": "cilex/console-service-provider", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/Cilex/console-service-provider.git", + "reference": "25ee3d1875243d38e1a3448ff94bdf944f70d24e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Cilex/console-service-provider/zipball/25ee3d1875243d38e1a3448ff94bdf944f70d24e", + "reference": "25ee3d1875243d38e1a3448ff94bdf944f70d24e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "pimple/pimple": "1.*@dev", + "symfony/console": "~2.1" + }, + "require-dev": { + "cilex/cilex": "1.*@dev", + "silex/silex": "1.*@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-0": { + "Cilex\\Provider\\Console": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "description": "Console Service Provider", + "keywords": [ + "cilex", + "console", + "pimple", + "service-provider", + "silex" + ], + "time": "2012-12-19 10:50:58" + }, + { + "name": "container-interop/container-interop", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/container-interop/container-interop.git", + "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/container-interop/container-interop/zipball/fc08354828f8fd3245f77a66b9e23a6bca48297e", + "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Interop\\Container\\": "src/Interop/Container/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", + "time": "2014-12-30 15:22:37" + }, + { + "name": "doctrine/annotations", + "version": "v1.2.7", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/f25c8aab83e0c3e976fd7d19875f198ccf2f7535", + "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "php": ">=5.3.2" + }, + "require-dev": { + "doctrine/cache": "1.*", + "phpunit/phpunit": "4.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Annotations\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "time": "2015-08-31 12:32:49" + }, + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14 21:17:01" + }, + { + "name": "doctrine/lexer", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Lexer\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "lexer", + "parser" + ], + "time": "2014-09-09 13:34:57" + }, + { + "name": "erusev/parsedown", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/erusev/parsedown.git", + "reference": "3ebbd730b5c2cf5ce78bc1bf64071407fc6674b7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/3ebbd730b5c2cf5ce78bc1bf64071407fc6674b7", + "reference": "3ebbd730b5c2cf5ce78bc1bf64071407fc6674b7", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Parsedown": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "description": "Parser for Markdown.", + "homepage": "http://parsedown.org", + "keywords": [ + "markdown", + "parser" + ], + "time": "2015-10-04 16:44:32" + }, + { + "name": "herrera-io/json", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/kherge-abandoned/php-json.git", + "reference": "60c696c9370a1e5136816ca557c17f82a6fa83f1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kherge-abandoned/php-json/zipball/60c696c9370a1e5136816ca557c17f82a6fa83f1", + "reference": "60c696c9370a1e5136816ca557c17f82a6fa83f1", + "shasum": "" + }, + "require": { + "ext-json": "*", + "justinrainbow/json-schema": ">=1.0,<2.0-dev", + "php": ">=5.3.3", + "seld/jsonlint": ">=1.0,<2.0-dev" + }, + "require-dev": { + "herrera-io/phpunit-test-case": "1.*", + "mikey179/vfsstream": "1.1.0", + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "files": [ + "src/lib/json_version.php" + ], + "psr-0": { + "Herrera\\Json": "src/lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Herrera", + "email": "kevin@herrera.io", + "homepage": "http://kevin.herrera.io/", + "role": "Developer" + } + ], + "description": "A library for simplifying JSON linting and validation.", + "homepage": "http://herrera-io.github.com/php-json", + "keywords": [ + "json", + "lint", + "schema", + "validate" + ], + "time": "2013-10-30 16:51:34" + }, + { + "name": "herrera-io/phar-update", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/kherge-abandoned/php-phar-update.git", + "reference": "00a79e1d5b8cf3c080a2e3becf1ddf7a7fea025b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kherge-abandoned/php-phar-update/zipball/00a79e1d5b8cf3c080a2e3becf1ddf7a7fea025b", + "reference": "00a79e1d5b8cf3c080a2e3becf1ddf7a7fea025b", + "shasum": "" + }, + "require": { + "herrera-io/json": "1.*", + "kherge/version": "1.*", + "php": ">=5.3.3" + }, + "require-dev": { + "herrera-io/phpunit-test-case": "1.*", + "mikey179/vfsstream": "1.1.0", + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "files": [ + "src/lib/constants.php" + ], + "psr-0": { + "Herrera\\Phar\\Update": "src/lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Herrera", + "email": "kevin@herrera.io", + "homepage": "http://kevin.herrera.io/", + "role": "Developer" + } + ], + "description": "A library for self-updating Phars.", + "homepage": "http://herrera-io.github.com/php-phar-update", + "keywords": [ + "phar", + "update" + ], + "time": "2013-10-30 17:23:01" + }, + { + "name": "jms/metadata", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/metadata.git", + "reference": "22b72455559a25777cfd28c4ffda81ff7639f353" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/22b72455559a25777cfd28c4ffda81ff7639f353", + "reference": "22b72455559a25777cfd28c4ffda81ff7639f353", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "doctrine/cache": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5.x-dev" + } + }, + "autoload": { + "psr-0": { + "Metadata\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache" + ], + "authors": [ + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "Class/method/property metadata management in PHP", + "keywords": [ + "annotations", + "metadata", + "xml", + "yaml" + ], + "time": "2014-07-12 07:13:19" + }, + { + "name": "jms/parser-lib", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/parser-lib.git", + "reference": "c509473bc1b4866415627af0e1c6cc8ac97fa51d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/parser-lib/zipball/c509473bc1b4866415627af0e1c6cc8ac97fa51d", + "reference": "c509473bc1b4866415627af0e1c6cc8ac97fa51d", + "shasum": "" + }, + "require": { + "phpoption/phpoption": ">=0.9,<2.0-dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-0": { + "JMS\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "description": "A library for easily creating recursive-descent parsers.", + "time": "2012-11-18 18:08:43" + }, + { + "name": "jms/serializer", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/serializer.git", + "reference": "fe13a1f993ea3456e195b7820692f2eb2b6bbb48" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/serializer/zipball/fe13a1f993ea3456e195b7820692f2eb2b6bbb48", + "reference": "fe13a1f993ea3456e195b7820692f2eb2b6bbb48", + "shasum": "" + }, + "require": { + "doctrine/annotations": "1.*", + "doctrine/instantiator": "~1.0.3", + "jms/metadata": "~1.1", + "jms/parser-lib": "1.*", + "php": ">=5.4.0", + "phpcollection/phpcollection": "~0.1" + }, + "conflict": { + "twig/twig": "<1.12" + }, + "require-dev": { + "doctrine/orm": "~2.1", + "doctrine/phpcr-odm": "~1.0.1", + "jackalope/jackalope-doctrine-dbal": "1.0.*", + "phpunit/phpunit": "~4.0", + "propel/propel1": "~1.7", + "symfony/filesystem": "2.*", + "symfony/form": "~2.1", + "symfony/translation": "~2.0", + "symfony/validator": "~2.0", + "symfony/yaml": "2.*", + "twig/twig": "~1.12|~2.0" + }, + "suggest": { + "symfony/yaml": "Required if you'd like to serialize data to YAML format." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-0": { + "JMS\\Serializer": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Library for (de-)serializing data of any complexity; supports XML, JSON, and YAML.", + "homepage": "http://jmsyst.com/libs/serializer", + "keywords": [ + "deserialization", + "jaxb", + "json", + "serialization", + "xml" + ], + "time": "2015-10-27 09:24:41" + }, + { + "name": "justinrainbow/json-schema", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/justinrainbow/json-schema.git", + "reference": "cc84765fb7317f6b07bd8ac78364747f95b86341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/cc84765fb7317f6b07bd8ac78364747f95b86341", + "reference": "cc84765fb7317f6b07bd8ac78364747f95b86341", + "shasum": "" + }, + "require": { + "php": ">=5.3.29" + }, + "require-dev": { + "json-schema/json-schema-test-suite": "1.1.0", + "phpdocumentor/phpdocumentor": "~2", + "phpunit/phpunit": "~3.7" + }, + "bin": [ + "bin/validate-json" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "JsonSchema\\": "src/JsonSchema/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Bruno Prieto Reis", + "email": "bruno.p.reis@gmail.com" + }, + { + "name": "Justin Rainbow", + "email": "justin.rainbow@gmail.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Robert Schönthal", + "email": "seroscho@googlemail.com" + } + ], + "description": "A library to validate a json schema.", + "homepage": "https://github.com/justinrainbow/json-schema", + "keywords": [ + "json", + "schema" + ], + "time": "2016-01-25 15:43:01" + }, + { + "name": "kherge/version", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/kherge-abandoned/Version.git", + "reference": "f07cf83f8ce533be8f93d2893d96d674bbeb7e30" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kherge-abandoned/Version/zipball/f07cf83f8ce533be8f93d2893d96d674bbeb7e30", + "reference": "f07cf83f8ce533be8f93d2893d96d674bbeb7e30", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-0": { + "KevinGH\\Version": "src/lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Herrera", + "email": "me@kevingh.com", + "homepage": "http://www.kevingh.com/" + } + ], + "description": "A parsing and comparison library for semantic versioning.", + "homepage": "http://github.com/kherge/Version", + "time": "2012-08-16 17:13:03" + }, + { + "name": "monolog/monolog", + "version": "1.19.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "5f56ed5212dc509c8dc8caeba2715732abb32dbf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/5f56ed5212dc509c8dc8caeba2715732abb32dbf", + "reference": "5f56ed5212dc509c8dc8caeba2715732abb32dbf", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "jakub-onderka/php-parallel-lint": "0.9", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpunit/phpunit": "~4.5", + "phpunit/phpunit-mock-objects": "2.3.0", + "raven/raven": "^0.13", + "ruflin/elastica": ">=0.90 <3.0", + "swiftmailer/swiftmailer": "~5.3" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "raven/raven": "Allow sending log messages to a Sentry server", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "time": "2016-04-12 18:29:35" + }, + { + "name": "nikic/php-parser", + "version": "v1.4.1", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "f78af2c9c86107aa1a34cd1dbb5bbe9eeb0d9f51" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f78af2c9c86107aa1a34cd1dbb5bbe9eeb0d9f51", + "reference": "f78af2c9c86107aa1a34cd1dbb5bbe9eeb0d9f51", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "files": [ + "lib/bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "time": "2015-09-19 14:15:08" + }, + { + "name": "phpcollection/phpcollection", + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-collection.git", + "reference": "b8bf55a0a929ca43b01232b36719f176f86c7e83" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-collection/zipball/b8bf55a0a929ca43b01232b36719f176f86c7e83", + "reference": "b8bf55a0a929ca43b01232b36719f176f86c7e83", + "shasum": "" + }, + "require": { + "phpoption/phpoption": "1.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.3-dev" + } + }, + "autoload": { + "psr-0": { + "PhpCollection": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "http://jmsyst.com", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "General-Purpose Collection Library for PHP", + "keywords": [ + "collection", + "list", + "map", + "sequence", + "set" + ], + "time": "2014-03-11 13:46:42" + }, + { + "name": "phpdocumentor/fileset", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/Fileset.git", + "reference": "bfa78d8fa9763dfce6d0e5d3730c1d8ab25d34b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/Fileset/zipball/bfa78d8fa9763dfce6d0e5d3730c1d8ab25d34b0", + "reference": "bfa78d8fa9763dfce6d0e5d3730c1d8ab25d34b0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/finder": "~2.1" + }, + "require-dev": { + "phpunit/phpunit": "~3.7" + }, + "type": "library", + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/", + "tests/unit/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Fileset component for collecting a set of files given directories and file paths", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "files", + "fileset", + "phpdoc" + ], + "time": "2013-08-06 21:07:42" + }, + { + "name": "phpdocumentor/graphviz", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/GraphViz.git", + "reference": "a906a90a9f230535f25ea31caf81b2323956283f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/GraphViz/zipball/a906a90a9f230535f25ea31caf81b2323956283f", + "reference": "a906a90a9f230535f25ea31caf81b2323956283f", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/", + "tests/unit" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2016-02-02 13:00:08" + }, + { + "name": "phpdocumentor/phpdocumentor", + "version": "v2.9.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/phpDocumentor2.git", + "reference": "be607da0eef9b9249c43c5b4820d25d631c73667" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/phpDocumentor2/zipball/be607da0eef9b9249c43c5b4820d25d631c73667", + "reference": "be607da0eef9b9249c43c5b4820d25d631c73667", + "shasum": "" + }, + "require": { + "cilex/cilex": "~1.0", + "erusev/parsedown": "~1.0", + "herrera-io/phar-update": "1.0.3", + "jms/serializer": ">=0.12", + "monolog/monolog": "~1.6", + "php": ">=5.3.3", + "phpdocumentor/fileset": "~1.0", + "phpdocumentor/graphviz": "~1.0", + "phpdocumentor/reflection": "^3.0", + "phpdocumentor/reflection-docblock": "~2.0", + "symfony/config": "~2.3", + "symfony/console": "~2.3", + "symfony/event-dispatcher": "~2.1", + "symfony/process": "~2.0", + "symfony/stopwatch": "~2.3", + "symfony/validator": "~2.2", + "twig/twig": "~1.3", + "zendframework/zend-cache": "~2.1", + "zendframework/zend-config": "~2.1", + "zendframework/zend-filter": "~2.1", + "zendframework/zend-i18n": "~2.1", + "zendframework/zend-serializer": "~2.1", + "zendframework/zend-servicemanager": "~2.1", + "zendframework/zend-stdlib": "~2.1", + "zetacomponents/document": ">=1.3.1" + }, + "require-dev": { + "behat/behat": "~3.0", + "mikey179/vfsstream": "~1.2", + "mockery/mockery": "~0.9@dev", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.4", + "symfony/expression-language": "~2.4" + }, + "suggest": { + "ext-twig": "Enabling the twig extension improves the generation of twig based templates.", + "ext-xslcache": "Enabling the XSLCache extension improves the generation of xml based templates." + }, + "bin": [ + "bin/phpdoc.php", + "bin/phpdoc" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "2.9-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/", + "tests/unit/" + ], + "Cilex\\Provider": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Documentation Generator for PHP", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "api", + "application", + "dga", + "documentation", + "phpdoc" + ], + "time": "2016-05-22 09:50:56" + }, + { + "name": "phpdocumentor/reflection", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/Reflection.git", + "reference": "793bfd92d9a0fc96ae9608fb3e947c3f59fb3a0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/Reflection/zipball/793bfd92d9a0fc96ae9608fb3e947c3f59fb3a0d", + "reference": "793bfd92d9a0fc96ae9608fb3e947c3f59fb3a0d", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^1.0", + "php": ">=5.3.3", + "phpdocumentor/reflection-docblock": "~2.0", + "psr/log": "~1.0" + }, + "require-dev": { + "behat/behat": "~2.4", + "mockery/mockery": "~0.8", + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/", + "tests/unit/", + "tests/mocks/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Reflection library to do Static Analysis for PHP Projects", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2016-05-21 08:42:32" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2015-02-03 12:10:50" + }, + { + "name": "phpoption/phpoption", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/94e644f7d2051a5f0fcf77d81605f152eecff0ed", + "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "4.7.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-0": { + "PhpOption\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "time": "2015-07-25 16:39:46" + }, + { + "name": "phpspec/prophecy", + "version": "v1.6.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "58a8137754bc24b25740d4281399a4a3596058e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0", + "reference": "58a8137754bc24b25740d4281399a4a3596058e0", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", + "sebastian/comparator": "^1.1", + "sebastian/recursion-context": "^1.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2016-06-07 08:13:47" + }, + { + "name": "phpunit/php-code-coverage", + "version": "2.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/environment": "^1.3.2", + "sebastian/version": "~1.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2015-10-06 15:47:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2015-06-21 13:08:43" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21 13:50:34" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4|~5" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2016-05-12 18:03:57" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2015-09-15 10:49:45" + }, + { + "name": "phpunit/phpunit", + "version": "4.7.7", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "9b97f9d807b862c2de2a36e86690000801c85724" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9b97f9d807b862c2de2a36e86690000801c85724", + "reference": "9b97f9d807b862c2de2a36e86690000801c85724", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpspec/prophecy": "~1.3,>=1.3.1", + "phpunit/php-code-coverage": "~2.1", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": ">=1.0.6", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.1", + "sebastian/diff": "~1.2", + "sebastian/environment": "~1.2", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.1|~3.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.7.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2015-07-13 11:28:34" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "2.3.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2015-10-02 06:51:40" + }, + { + "name": "pimple/pimple", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/silexphp/Pimple.git", + "reference": "2019c145fe393923f3441b23f29bbdfaa5c58c4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/2019c145fe393923f3441b23f29bbdfaa5c58c4d", + "reference": "2019c145fe393923f3441b23f29bbdfaa5c58c4d", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "Pimple": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + } + ], + "description": "Pimple is a simple Dependency Injection Container for PHP 5.3", + "homepage": "http://pimple.sensiolabs.org", + "keywords": [ + "container", + "dependency injection" + ], + "time": "2013-11-22 08:30:29" + }, + { + "name": "psr/log", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Psr\\Log\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2012-12-21 11:40:51" + }, + { + "name": "sebastian/comparator", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", + "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2015-07-26 15:48:44" + }, + { + "name": "sebastian/diff", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2015-12-08 07:14:41" + }, + { + "name": "sebastian/environment", + "version": "1.3.7", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4e8f0da10ac5802913afc151413bc8c53b6c2716", + "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2016-05-17 03:18:57" + }, + { + "name": "sebastian/exporter", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2016-06-17 09:04:28" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-10-12 03:26:01" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "913401df809e99e4f47b27cdd781f4a258d58791" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", + "reference": "913401df809e99e4f47b27cdd781f4a258d58791", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2015-11-11 19:50:13" + }, + { + "name": "sebastian/version", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2015-06-21 13:59:46" + }, + { + "name": "seld/jsonlint", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/jsonlint.git", + "reference": "66834d3e3566bb5798db7294619388786ae99394" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/66834d3e3566bb5798db7294619388786ae99394", + "reference": "66834d3e3566bb5798db7294619388786ae99394", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0" + }, + "bin": [ + "bin/jsonlint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Seld\\JsonLint\\": "src/Seld/JsonLint/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "JSON Linter", + "keywords": [ + "json", + "linter", + "parser", + "validator" + ], + "time": "2015-11-21 02:21:41" + }, + { + "name": "symfony/config", + "version": "v2.8.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "a2edd59c2163c65747fc3f35d132b5a39266bd05" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/a2edd59c2163c65747fc3f35d132b5a39266bd05", + "reference": "a2edd59c2163c65747fc3f35d132b5a39266bd05", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "symfony/filesystem": "~2.3|~3.0.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Config Component", + "homepage": "https://symfony.com", + "time": "2016-06-06 11:11:27" + }, + { + "name": "symfony/console", + "version": "v2.8.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3", + "reference": "5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.1|~3.0.0", + "symfony/process": "~2.1|~3.0.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2016-06-06 15:06:25" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.8.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "2a6b8713f8bdb582058cfda463527f195b066110" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2a6b8713f8bdb582058cfda463527f195b066110", + "reference": "2a6b8713f8bdb582058cfda463527f195b066110", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.0,>=2.0.5|~3.0.0", + "symfony/dependency-injection": "~2.6|~3.0.0", + "symfony/expression-language": "~2.6|~3.0.0", + "symfony/stopwatch": "~2.3|~3.0.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2016-06-06 11:11:27" + }, + { + "name": "symfony/filesystem", + "version": "v3.0.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "74fec3511b62cb934b64bce1d96f06fffa4beafd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/74fec3511b62cb934b64bce1d96f06fffa4beafd", + "reference": "74fec3511b62cb934b64bce1d96f06fffa4beafd", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "time": "2016-04-12 18:09:53" + }, + { + "name": "symfony/finder", + "version": "v2.8.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "3ec095fab1800222732ca522a95dce8fa124007b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/3ec095fab1800222732ca522a95dce8fa124007b", + "reference": "3ec095fab1800222732ca522a95dce8fa124007b", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "time": "2016-06-06 11:11:27" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "dff51f72b0706335131b00a7f49606168c582594" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594", + "reference": "dff51f72b0706335131b00a7f49606168c582594", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2016-05-18 14:26:46" + }, + { + "name": "symfony/process", + "version": "v2.8.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "115347d00c342198cdc52a7bd8bc15b5ab43500c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/115347d00c342198cdc52a7bd8bc15b5ab43500c", + "reference": "115347d00c342198cdc52a7bd8bc15b5ab43500c", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "https://symfony.com", + "time": "2016-06-06 11:11:27" + }, + { + "name": "symfony/stopwatch", + "version": "v2.8.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "5e628055488bcc42dbace3af65be435d094e37e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5e628055488bcc42dbace3af65be435d094e37e4", + "reference": "5e628055488bcc42dbace3af65be435d094e37e4", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Stopwatch Component", + "homepage": "https://symfony.com", + "time": "2016-06-06 11:11:27" + }, + { + "name": "symfony/translation", + "version": "v3.0.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "2b0aacaa613c0ec1ad8046f972d8abdcb19c1db7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/2b0aacaa613c0ec1ad8046f972d8abdcb19c1db7", + "reference": "2b0aacaa613c0ec1ad8046f972d8abdcb19c1db7", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/config": "<2.8" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.8|~3.0", + "symfony/intl": "~2.8|~3.0", + "symfony/yaml": "~2.8|~3.0" + }, + "suggest": { + "psr/log": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Translation Component", + "homepage": "https://symfony.com", + "time": "2016-06-06 11:33:26" + }, + { + "name": "symfony/validator", + "version": "v2.8.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/validator.git", + "reference": "4c8f9fd8e2150dbc4745ef13378e690588365df0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/validator/zipball/4c8f9fd8e2150dbc4745ef13378e690588365df0", + "reference": "4c8f9fd8e2150dbc4745ef13378e690588365df0", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation": "~2.4|~3.0.0" + }, + "require-dev": { + "doctrine/annotations": "~1.0", + "doctrine/cache": "~1.0", + "egulias/email-validator": "~1.2,>=1.2.1", + "symfony/config": "~2.2|~3.0.0", + "symfony/expression-language": "~2.4|~3.0.0", + "symfony/http-foundation": "~2.1|~3.0.0", + "symfony/intl": "~2.7.4|~2.8|~3.0.0", + "symfony/property-access": "~2.3|~3.0.0", + "symfony/yaml": "~2.0,>=2.0.5|~3.0.0" + }, + "suggest": { + "doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.", + "doctrine/cache": "For using the default cached annotation reader and metadata cache.", + "egulias/email-validator": "Strict (RFC compliant) email validation", + "symfony/config": "", + "symfony/expression-language": "For using the 2.4 Expression validator", + "symfony/http-foundation": "", + "symfony/intl": "", + "symfony/property-access": "For using the 2.4 Validator API", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Validator\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Validator Component", + "homepage": "https://symfony.com", + "time": "2016-04-14 08:48:44" + }, + { + "name": "symfony/yaml", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "c5a7e7fc273c758b92b85dcb9c46149ccda89623" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/c5a7e7fc273c758b92b85dcb9c46149ccda89623", + "reference": "c5a7e7fc273c758b92b85dcb9c46149ccda89623", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2016-06-14 11:18:07" + }, + { + "name": "twig/twig", + "version": "v1.24.1", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "3566d311a92aae4deec6e48682dc5a4528c4a512" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/3566d311a92aae4deec6e48682dc5a4528c4a512", + "reference": "3566d311a92aae4deec6e48682dc5a4528c4a512", + "shasum": "" + }, + "require": { + "php": ">=5.2.7" + }, + "require-dev": { + "symfony/debug": "~2.7", + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.24-dev" + } + }, + "autoload": { + "psr-0": { + "Twig_": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + }, + { + "name": "Twig Team", + "homepage": "http://twig.sensiolabs.org/contributors", + "role": "Contributors" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "http://twig.sensiolabs.org", + "keywords": [ + "templating" + ], + "time": "2016-05-30 09:11:59" + }, + { + "name": "zendframework/zend-cache", + "version": "2.7.1", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-cache.git", + "reference": "2c68def8f96ce842d2f2a9a69e2f3508c2f5312d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-cache/zipball/2c68def8f96ce842d2f2a9a69e2f3508c2f5312d", + "reference": "2c68def8f96ce842d2f2a9a69e2f3508c2f5312d", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "zendframework/zend-eventmanager": "^2.6.2 || ^3.0", + "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3", + "zendframework/zend-stdlib": "^2.7 || ^3.0" + }, + "require-dev": { + "fabpot/php-cs-fixer": "1.7.*", + "phpbench/phpbench": "^0.10.0", + "phpunit/phpunit": "^4.5", + "zendframework/zend-serializer": "^2.6", + "zendframework/zend-session": "^2.6.2" + }, + "suggest": { + "ext-apc": "APC or compatible extension, to use the APC storage adapter", + "ext-apcu": "APCU >= 5.1.0, to use the APCu storage adapter", + "ext-dba": "DBA, to use the DBA storage adapter", + "ext-memcache": "Memcache >= 2.0.0 to use the Memcache storage adapter", + "ext-memcached": "Memcached >= 1.0.0 to use the Memcached storage adapter", + "ext-mongo": "Mongo, to use MongoDb storage adapter", + "ext-redis": "Redis, to use Redis storage adapter", + "ext-wincache": "WinCache, to use the WinCache storage adapter", + "ext-xcache": "XCache, to use the XCache storage adapter", + "mongofill/mongofill": "Alternative to ext-mongo - a pure PHP implementation designed as a drop in replacement", + "zendframework/zend-serializer": "Zend\\Serializer component", + "zendframework/zend-session": "Zend\\Session component" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev", + "dev-develop": "2.8-dev" + }, + "zf": { + "component": "Zend\\Cache", + "config-provider": "Zend\\Cache\\ConfigProvider" + } + }, + "autoload": { + "psr-4": { + "Zend\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "provides a generic way to cache any data", + "homepage": "https://github.com/zendframework/zend-cache", + "keywords": [ + "cache", + "zf2" + ], + "time": "2016-05-12 21:47:55" + }, + { + "name": "zendframework/zend-config", + "version": "2.6.0", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-config.git", + "reference": "2920e877a9f6dca9fa8f6bd3b1ffc2e19bb1e30d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-config/zipball/2920e877a9f6dca9fa8f6bd3b1ffc2e19bb1e30d", + "reference": "2920e877a9f6dca9fa8f6bd3b1ffc2e19bb1e30d", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "zendframework/zend-stdlib": "^2.7 || ^3.0" + }, + "require-dev": { + "fabpot/php-cs-fixer": "1.7.*", + "phpunit/phpunit": "~4.0", + "zendframework/zend-filter": "^2.6", + "zendframework/zend-i18n": "^2.5", + "zendframework/zend-json": "^2.6.1", + "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3" + }, + "suggest": { + "zendframework/zend-filter": "Zend\\Filter component", + "zendframework/zend-i18n": "Zend\\I18n component", + "zendframework/zend-json": "Zend\\Json to use the Json reader or writer classes", + "zendframework/zend-servicemanager": "Zend\\ServiceManager for use with the Config Factory to retrieve reader and writer instances" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev", + "dev-develop": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\Config\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "provides a nested object property based user interface for accessing this configuration data within application code", + "homepage": "https://github.com/zendframework/zend-config", + "keywords": [ + "config", + "zf2" + ], + "time": "2016-02-04 23:01:10" + }, + { + "name": "zendframework/zend-eventmanager", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-eventmanager.git", + "reference": "5c80bdee0e952be112dcec0968bad770082c3a6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/5c80bdee0e952be112dcec0968bad770082c3a6e", + "reference": "5c80bdee0e952be112dcec0968bad770082c3a6e", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0" + }, + "require-dev": { + "athletic/athletic": "^0.1", + "container-interop/container-interop": "^1.1.0", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "^2.0", + "zendframework/zend-stdlib": "^2.7.3 || ^3.0" + }, + "suggest": { + "container-interop/container-interop": "^1.1.0, to use the lazy listeners feature", + "zendframework/zend-stdlib": "^2.7.3 || ^3.0, to use the FilterChain feature" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev", + "dev-develop": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\EventManager\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Trigger and listen to events within a PHP application", + "homepage": "https://github.com/zendframework/zend-eventmanager", + "keywords": [ + "event", + "eventmanager", + "events", + "zf2" + ], + "time": "2016-02-18 20:53:00" + }, + { + "name": "zendframework/zend-filter", + "version": "2.7.1", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-filter.git", + "reference": "84c50246428efb0a1e52868e162dab3e149d5b80" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-filter/zipball/84c50246428efb0a1e52868e162dab3e149d5b80", + "reference": "84c50246428efb0a1e52868e162dab3e149d5b80", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "zendframework/zend-stdlib": "^2.7 || ^3.0" + }, + "require-dev": { + "fabpot/php-cs-fixer": "1.7.*", + "pear/archive_tar": "^1.4", + "phpunit/phpunit": "~4.0", + "zendframework/zend-crypt": "^2.6", + "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3", + "zendframework/zend-uri": "^2.5" + }, + "suggest": { + "zendframework/zend-crypt": "Zend\\Crypt component, for encryption filters", + "zendframework/zend-i18n": "Zend\\I18n component for filters depending on i18n functionality", + "zendframework/zend-servicemanager": "Zend\\ServiceManager component, for using the filter chain functionality", + "zendframework/zend-uri": "Zend\\Uri component, for the UriNormalize filter" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev", + "dev-develop": "2.8-dev" + }, + "zf": { + "component": "Zend\\Filter", + "config-provider": "Zend\\Filter\\ConfigProvider" + } + }, + "autoload": { + "psr-4": { + "Zend\\Filter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "provides a set of commonly needed data filters", + "homepage": "https://github.com/zendframework/zend-filter", + "keywords": [ + "filter", + "zf2" + ], + "time": "2016-04-18 18:32:43" + }, + { + "name": "zendframework/zend-hydrator", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-hydrator.git", + "reference": "22652e1661a5a10b3f564cf7824a2206cf5a4a65" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-hydrator/zipball/22652e1661a5a10b3f564cf7824a2206cf5a4a65", + "reference": "22652e1661a5a10b3f564cf7824a2206cf5a4a65", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "zendframework/zend-stdlib": "^2.7 || ^3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "^2.0@dev", + "zendframework/zend-eventmanager": "^2.6.2 || ^3.0", + "zendframework/zend-filter": "^2.6", + "zendframework/zend-inputfilter": "^2.6", + "zendframework/zend-serializer": "^2.6.1", + "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3" + }, + "suggest": { + "zendframework/zend-eventmanager": "^2.6.2 || ^3.0, to support aggregate hydrator usage", + "zendframework/zend-filter": "^2.6, to support naming strategy hydrator usage", + "zendframework/zend-serializer": "^2.6.1, to use the SerializableStrategy", + "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3, to support hydrator plugin manager usage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-release-1.0": "1.0-dev", + "dev-release-1.1": "1.1-dev", + "dev-master": "2.0-dev", + "dev-develop": "2.1-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\Hydrator\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "homepage": "https://github.com/zendframework/zend-hydrator", + "keywords": [ + "hydrator", + "zf2" + ], + "time": "2016-02-18 22:38:26" + }, + { + "name": "zendframework/zend-i18n", + "version": "2.7.3", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-i18n.git", + "reference": "b2db0d8246a865c659f93199f90f5fc2cd2f3cd8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-i18n/zipball/b2db0d8246a865c659f93199f90f5fc2cd2f3cd8", + "reference": "b2db0d8246a865c659f93199f90f5fc2cd2f3cd8", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "zendframework/zend-stdlib": "^2.7 || ^3.0" + }, + "require-dev": { + "fabpot/php-cs-fixer": "1.7.*", + "phpunit/phpunit": "~4.0", + "zendframework/zend-cache": "^2.6.1", + "zendframework/zend-config": "^2.6", + "zendframework/zend-eventmanager": "^2.6.2 || ^3.0", + "zendframework/zend-filter": "^2.6.1", + "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3", + "zendframework/zend-validator": "^2.6", + "zendframework/zend-view": "^2.6.3" + }, + "suggest": { + "ext-intl": "Required for most features of Zend\\I18n; included in default builds of PHP", + "zendframework/zend-cache": "Zend\\Cache component", + "zendframework/zend-config": "Zend\\Config component", + "zendframework/zend-eventmanager": "You should install this package to use the events in the translator", + "zendframework/zend-filter": "You should install this package to use the provided filters", + "zendframework/zend-i18n-resources": "Translation resources", + "zendframework/zend-servicemanager": "Zend\\ServiceManager component", + "zendframework/zend-validator": "You should install this package to use the provided validators", + "zendframework/zend-view": "You should install this package to use the provided view helpers" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev", + "dev-develop": "2.8-dev" + }, + "zf": { + "component": "Zend\\I18n", + "config-provider": "Zend\\I18n\\ConfigProvider" + } + }, + "autoload": { + "psr-4": { + "Zend\\I18n\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "homepage": "https://github.com/zendframework/zend-i18n", + "keywords": [ + "i18n", + "zf2" + ], + "time": "2016-06-07 21:08:30" + }, + { + "name": "zendframework/zend-json", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-json.git", + "reference": "f42a1588e75c2a3e338cd94c37906231e616daab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-json/zipball/f42a1588e75c2a3e338cd94c37906231e616daab", + "reference": "f42a1588e75c2a3e338cd94c37906231e616daab", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "^2.3", + "zendframework/zend-stdlib": "^2.7 || ^3.0" + }, + "suggest": { + "zendframework/zend-json-server": "For implementing JSON-RPC servers", + "zendframework/zend-xml2json": "For converting XML documents to JSON" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev", + "dev-develop": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\Json\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "provides convenience methods for serializing native PHP to JSON and decoding JSON to native PHP", + "homepage": "https://github.com/zendframework/zend-json", + "keywords": [ + "json", + "zf2" + ], + "time": "2016-04-01 02:34:00" + }, + { + "name": "zendframework/zend-serializer", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-serializer.git", + "reference": "ff74ea020f5f90866eb28365327e9bc765a61a6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-serializer/zipball/ff74ea020f5f90866eb28365327e9bc765a61a6e", + "reference": "ff74ea020f5f90866eb28365327e9bc765a61a6e", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0", + "zendframework/zend-json": "^2.5 || ^3.0", + "zendframework/zend-stdlib": "^2.7 || ^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.5", + "squizlabs/php_codesniffer": "^2.3.1", + "zendframework/zend-math": "^2.6", + "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3" + }, + "suggest": { + "zendframework/zend-math": "(^2.6 || ^3.0) To support Python Pickle serialization", + "zendframework/zend-servicemanager": "(^2.7.5 || ^3.0.3) To support plugin manager support" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev", + "dev-develop": "2.9-dev" + }, + "zf": { + "component": "Zend\\Serializer", + "config-provider": "Zend\\Serializer\\ConfigProvider" + } + }, + "autoload": { + "psr-4": { + "Zend\\Serializer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "provides an adapter based interface to simply generate storable representation of PHP types by different facilities, and recover", + "homepage": "https://github.com/zendframework/zend-serializer", + "keywords": [ + "serializer", + "zf2" + ], + "time": "2016-06-21 17:01:55" + }, + { + "name": "zendframework/zend-servicemanager", + "version": "2.7.6", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-servicemanager.git", + "reference": "a6db4d13b9141fccce5dcb553df0295d6ad7d477" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-servicemanager/zipball/a6db4d13b9141fccce5dcb553df0295d6ad7d477", + "reference": "a6db4d13b9141fccce5dcb553df0295d6ad7d477", + "shasum": "" + }, + "require": { + "container-interop/container-interop": "~1.0", + "php": "^5.5 || ^7.0" + }, + "require-dev": { + "athletic/athletic": "dev-master", + "fabpot/php-cs-fixer": "1.7.*", + "phpunit/phpunit": "~4.0", + "zendframework/zend-di": "~2.5", + "zendframework/zend-mvc": "~2.5" + }, + "suggest": { + "ocramius/proxy-manager": "ProxyManager 0.5.* to handle lazy initialization of services", + "zendframework/zend-di": "Zend\\Di component" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev", + "dev-develop": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\ServiceManager\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "homepage": "https://github.com/zendframework/zend-servicemanager", + "keywords": [ + "servicemanager", + "zf2" + ], + "time": "2016-04-27 19:07:40" + }, + { + "name": "zendframework/zend-stdlib", + "version": "2.7.7", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-stdlib.git", + "reference": "0e44eb46788f65e09e077eb7f44d2659143bcc1f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/0e44eb46788f65e09e077eb7f44d2659143bcc1f", + "reference": "0e44eb46788f65e09e077eb7f44d2659143bcc1f", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "zendframework/zend-hydrator": "~1.1" + }, + "require-dev": { + "athletic/athletic": "~0.1", + "fabpot/php-cs-fixer": "1.7.*", + "phpunit/phpunit": "~4.0", + "zendframework/zend-config": "~2.5", + "zendframework/zend-eventmanager": "~2.5", + "zendframework/zend-filter": "~2.5", + "zendframework/zend-inputfilter": "~2.5", + "zendframework/zend-serializer": "~2.5", + "zendframework/zend-servicemanager": "~2.5" + }, + "suggest": { + "zendframework/zend-eventmanager": "To support aggregate hydrator usage", + "zendframework/zend-filter": "To support naming strategy hydrator usage", + "zendframework/zend-serializer": "Zend\\Serializer component", + "zendframework/zend-servicemanager": "To support hydrator plugin manager usage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-release-2.7": "2.7-dev", + "dev-master": "3.0-dev", + "dev-develop": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\Stdlib\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "homepage": "https://github.com/zendframework/zend-stdlib", + "keywords": [ + "stdlib", + "zf2" + ], + "time": "2016-04-12 21:17:31" + }, + { + "name": "zetacomponents/base", + "version": "1.9", + "source": { + "type": "git", + "url": "https://github.com/zetacomponents/Base.git", + "reference": "f20df24e8de3e48b6b69b2503f917e457281e687" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zetacomponents/Base/zipball/f20df24e8de3e48b6b69b2503f917e457281e687", + "reference": "f20df24e8de3e48b6b69b2503f917e457281e687", + "shasum": "" + }, + "require-dev": { + "zetacomponents/unit-test": "*" + }, + "type": "library", + "autoload": { + "classmap": [ + "src" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Sergey Alexeev" + }, + { + "name": "Sebastian Bergmann" + }, + { + "name": "Jan Borsodi" + }, + { + "name": "Raymond Bosman" + }, + { + "name": "Frederik Holljen" + }, + { + "name": "Kore Nordmann" + }, + { + "name": "Derick Rethans" + }, + { + "name": "Vadym Savchuk" + }, + { + "name": "Tobias Schlitt" + }, + { + "name": "Alexandru Stanoi" + } + ], + "description": "The Base package provides the basic infrastructure that all packages rely on. Therefore every component relies on this package.", + "homepage": "https://github.com/zetacomponents", + "time": "2014-09-19 03:28:34" + }, + { + "name": "zetacomponents/document", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/zetacomponents/Document.git", + "reference": "688abfde573cf3fe0730f82538fbd7aa9fc95bc8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zetacomponents/Document/zipball/688abfde573cf3fe0730f82538fbd7aa9fc95bc8", + "reference": "688abfde573cf3fe0730f82538fbd7aa9fc95bc8", + "shasum": "" + }, + "require": { + "zetacomponents/base": "*" + }, + "require-dev": { + "zetacomponents/unit-test": "dev-master" + }, + "type": "library", + "autoload": { + "classmap": [ + "src" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Sebastian Bergmann" + }, + { + "name": "Kore Nordmann" + }, + { + "name": "Derick Rethans" + }, + { + "name": "Tobias Schlitt" + }, + { + "name": "Alexandru Stanoi" + } + ], + "description": "The Document components provides a general conversion framework for different semantic document markup languages like XHTML, Docbook, RST and similar.", + "homepage": "https://github.com/zetacomponents", + "time": "2013-12-19 11:40:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.0.0" + }, + "platform-dev": [] +} diff --git a/core/func/libs/mail/extras/EasyPeasyICS.php b/core/func/libs/mail/extras/EasyPeasyICS.php new file mode 100644 index 0000000..d8bfcfa --- /dev/null +++ b/core/func/libs/mail/extras/EasyPeasyICS.php @@ -0,0 +1,148 @@ + + * @author Manuel Reinhard + * + * Built with inspiration from + * http://stackoverflow.com/questions/1463480/how-can-i-use-php-to-dynamically-publish-an-ical-file-to-be-read-by-google-calend/1464355#1464355 + * History: + * 2010/12/17 - Manuel Reinhard - when it all started + * 2014 PHPMailer project becomes maintainer + */ + +/** + * Class EasyPeasyICS. + * Simple ICS data generator + * @package phpmailer + * @subpackage easypeasyics + */ +class EasyPeasyICS +{ + /** + * The name of the calendar + * @var string + */ + protected $calendarName; + /** + * The array of events to add to this calendar + * @var array + */ + protected $events = array(); + + /** + * Constructor + * @param string $calendarName + */ + public function __construct($calendarName = "") + { + $this->calendarName = $calendarName; + } + + /** + * Add an event to this calendar. + * @param string $start The start date and time as a unix timestamp + * @param string $end The end date and time as a unix timestamp + * @param string $summary A summary or title for the event + * @param string $description A description of the event + * @param string $url A URL for the event + * @param string $uid A unique identifier for the event - generated automatically if not provided + * @return array An array of event details, including any generated UID + */ + public function addEvent($start, $end, $summary = '', $description = '', $url = '', $uid = '') + { + if (empty($uid)) { + $uid = md5(uniqid(mt_rand(), true)) . '@EasyPeasyICS'; + } + $event = array( + 'start' => gmdate('Ymd', $start) . 'T' . gmdate('His', $start) . 'Z', + 'end' => gmdate('Ymd', $end) . 'T' . gmdate('His', $end) . 'Z', + 'summary' => $summary, + 'description' => $description, + 'url' => $url, + 'uid' => $uid + ); + $this->events[] = $event; + return $event; + } + + /** + * @return array Get the array of events. + */ + public function getEvents() + { + return $this->events; + } + + /** + * Clear all events. + */ + public function clearEvents() + { + $this->events = array(); + } + + /** + * Get the name of the calendar. + * @return string + */ + public function getName() + { + return $this->calendarName; + } + + /** + * Set the name of the calendar. + * @param $name + */ + public function setName($name) + { + $this->calendarName = $name; + } + + /** + * Render and optionally output a vcal string. + * @param bool $output Whether to output the calendar data directly (the default). + * @return string The complete rendered vlal + */ + public function render($output = true) + { + //Add header + $ics = 'BEGIN:VCALENDAR +METHOD:PUBLISH +VERSION:2.0 +X-WR-CALNAME:' . $this->calendarName . ' +PRODID:-//hacksw/handcal//NONSGML v1.0//EN'; + + //Add events + foreach ($this->events as $event) { + $ics .= ' +BEGIN:VEVENT +UID:' . $event['uid'] . ' +DTSTAMP:' . gmdate('Ymd') . 'T' . gmdate('His') . 'Z +DTSTART:' . $event['start'] . ' +DTEND:' . $event['end'] . ' +SUMMARY:' . str_replace("\n", "\\n", $event['summary']) . ' +DESCRIPTION:' . str_replace("\n", "\\n", $event['description']) . ' +URL;VALUE=URI:' . $event['url'] . ' +END:VEVENT'; + } + + //Add footer + $ics .= ' +END:VCALENDAR'; + + if ($output) { + //Output + $filename = $this->calendarName; + //Filename needs quoting if it contains spaces + if (strpos($filename, ' ') !== false) { + $filename = '"'.$filename.'"'; + } + header('Content-type: text/calendar; charset=utf-8'); + header('Content-Disposition: inline; filename=' . $filename . '.ics'); + echo $ics; + } + return $ics; + } +} diff --git a/core/func/libs/mail/extras/README.md b/core/func/libs/mail/extras/README.md new file mode 100644 index 0000000..dac79e0 --- /dev/null +++ b/core/func/libs/mail/extras/README.md @@ -0,0 +1,17 @@ +#PHPMailer Extras + +These classes provide optional additional functions to PHPMailer. + +These are not loaded by the PHPMailer autoloader, so in some cases you may need to `require` them yourself before using them. + +##EasyPeasyICS + +This class was originally written by Manuel Reinhard and provides a simple means of generating ICS/vCal files that are used in sending calendar events. PHPMailer does not use it directly, but you can use it to generate content appropriate for placing in the `Ical` property of PHPMailer. The PHPMailer project is now its official home as Manuel has given permission for that and is no longer maintaining it himself. + +##htmlfilter + +This class by Konstantin Riabitsev and Jim Jagielski implements HTML filtering to remove potentially malicious tags, such as ` +
    +

    Asset Approval

    + Things to not approve +
      +
    • Pornographic content such as naked human beings.
    • +
    • Photos of staff members or members. Only allow known people such as Bill Gates.
    • +
    • Deny all copyrighted content, such as logos, etc.
    • +
    • Punish uploaders if they break obvious rules.
    • +
    +
    +
    + +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/admin/ban.php b/core/views/admin/ban.php new file mode 100644 index 0000000..5cf6426 --- /dev/null +++ b/core/views/admin/ban.php @@ -0,0 +1,40 @@ + + + + + <?php echo config::getName();?> | Ban User + + + + +
    +
    + +
    +

    Ban User

    + + + + + +
    +
    + + + \ No newline at end of file diff --git a/core/views/admin/main.php b/core/views/admin/main.php new file mode 100644 index 0000000..ab92ecc --- /dev/null +++ b/core/views/admin/main.php @@ -0,0 +1,40 @@ + + + + + <?php echo config::getName();?> | Admin Panel + + + + +
    +

    Admin Panel

    +

    Moderators and Administrators

    +

    Ban User

    +

    Unban User

    +

    Reports

    +

    Statistics

    +

    Reward Postie

    + prepare("SELECT id FROM catalog WHERE approved = 0 AND declined = 0;"); + $stmt->execute(); + ?> +

    Asset Approval (rowCount();?>)

    +
    +

    Administrators only

    +

    Prune Posts

    +

    New Hat

    +
    + + + \ No newline at end of file diff --git a/core/views/admin/newHat.php b/core/views/admin/newHat.php new file mode 100644 index 0000000..a08e22b --- /dev/null +++ b/core/views/admin/newHat.php @@ -0,0 +1,72 @@ + + + + + <?php echo config::getName();?> | New Hat + + + + + +
    +
    +
    +

    Before you upload

    +

    Make sure that the mesh type is correctly converted

    +

    Assure that the heights of the "Handle" part is correct

    +

    Make sure that the XML file is correctly formatted

    +

    If something goes wrong, please contact an administrator to solve this

    +
    +
    +
    +

    New Hat

    +

    This tool allows you to upload a new hat to the website. Hats are structured with a texture, mesh file and a model file (which is the XML file)

    +

    Note : The XML file must be tested before upload, you can not change the XML file after upload. However, this may change in the future.

    +

    Note : Do NOT upload R15 or future XML files, they will NOT work!

    +

    Note : Abuse of this system WILL result in a revoke of all rights, and a demotion if you are staff

    + + + + + + Buyable + Roblox Asset (ALWAYS CHECK IF NOT CUSTOM MADE!!!) +
    +
    +
    +

    Mesh File

    +

    The mesh file should be a correct extension

    + +
    +
    +

    Texture File

    +

    Should be PNG, but JPG is also supported

    + +
    +
    +
    +

    If you are ready to upload, press the button below

    + +
    +
    +

    Notes

    +

    Hats require three file types, a mesh file (its extension must be converted first), a texture file (simply an image file) and a datafile (basically XML)

    +

    Once you upload the hat, it will appear in your inventory and you will get it for free

    +

    The price must be at least 1 coin, otherwise an error will be returned

    +

    The ImageServer will only correctly render your hat if the height and widths are correct, otherwise it'll appear cut in the image

    +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/admin/prune.php b/core/views/admin/prune.php new file mode 100644 index 0000000..e638e92 --- /dev/null +++ b/core/views/admin/prune.php @@ -0,0 +1,33 @@ + + + + + <?php echo config::getName();?> | Prune Posts + + + + +
    +
    + +
    +

    Prune Posts

    +

    This utility will remove all posts and replies of a certain user. Quite useful for if the user is a spammer and is not stopping.

    +

    Please know that this can not be undone and that this will only have to be done if no other option is possible.

    + + +
    +
    + + + \ No newline at end of file diff --git a/core/views/admin/reports.php b/core/views/admin/reports.php new file mode 100644 index 0000000..e939b28 --- /dev/null +++ b/core/views/admin/reports.php @@ -0,0 +1,47 @@ + + + + + <?php echo config::getName();?> | Reports + + + + +
    +
    +

    Reports

    +
    + + + + + + + + prepare("SELECT * FROM reports ORDER BY id DESC;"); + $stmt->execute(); + $count = 0; + foreach($stmt as $result) { + $count++; + echo ''; + } + ?> + +
    Reported UserReasonDate Reported
    '.$result['target'].''.htmlentities($result['reason'], ENT_QUOTES, "UTF-8").''.date('M j Y g:i A', strtotime($result['date'])).'
    +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/admin/rewardPostie.php b/core/views/admin/rewardPostie.php new file mode 100644 index 0000000..9338925 --- /dev/null +++ b/core/views/admin/rewardPostie.php @@ -0,0 +1,32 @@ + + + + + <?php echo config::getName();?> | Reward postie + + + + +
    +
    + +
    +

    Reward Postie

    +

    Have you found great content? You can now reward users with posties! With posties, you can buy exclusive items on Graphictoria

    + + +
    +
    + + + \ No newline at end of file diff --git a/core/views/admin/statistics.php b/core/views/admin/statistics.php new file mode 100644 index 0000000..2f56b0d --- /dev/null +++ b/core/views/admin/statistics.php @@ -0,0 +1,83 @@ + + + + + <?php echo config::getName();?> | Statistics + + + + +
    + prepare("SELECT id FROM users;"); + $stmt->execute(); + $amusers = $stmt->rowCount(); + + $stmt = $dbcon->prepare("SELECT id FROM users WHERE banned = 1;"); + $stmt->execute(); + $busers = $stmt->rowCount(); + + $stmt = $dbcon->prepare("SELECT id FROM users WHERE banned = 0;"); + $stmt->execute(); + $ubusers = $stmt->rowCount(); + + $stmt = $dbcon->prepare("SELECT id FROM topics"); + $stmt->execute(); + $topcount = $stmt->rowCount(); + + $stmt = $dbcon->prepare("SELECT id FROM replies"); + $stmt->execute(); + $repcount = $stmt->rowCount(); + + $totalp = ($topcount + $repcount); + + $stmt = $dbcon->prepare("SELECT id FROM users WHERE rank > 0;"); + $stmt->execute(); + $staffc = $stmt->rowCount(); + + $stmt = $dbcon->prepare("SELECT id FROM catalog"); + $stmt->execute(); + $catcount = $stmt->rowCount(); + + $stmt = $dbcon->prepare("SELECT id FROM `read`"); + $stmt->execute(); + $readc = $stmt->rowCount(); + + $stmt = $dbcon->prepare("SELECT id FROM `wearing`"); + $stmt->execute(); + $wearc = $stmt->rowCount(); + + $stmt = $dbcon->prepare("SELECT id FROM `messages`"); + $stmt->execute(); + $messagecount = $stmt->rowCount(); + + $total = ($amusers + $busers + $ubusers + $topcount + $repcount + $totalp + $staffc + $catcount + $readc + $wearc + $messagecount); + ?> +

    Statistics

    + There are currently registered accounts.
    + There are forum posts.
    + There are read forum topics.
    + There are sent private messages.
    + There are items being worn.
    + There are forum topics.
    + There are forum replies.
    + There are banned users.
    + There are unbanned users.
    + There are catalog items.
    + There are staff members.
    + + If we count this all up, we get the number . +
    + + + \ No newline at end of file diff --git a/core/views/admin/unban.php b/core/views/admin/unban.php new file mode 100644 index 0000000..b628de3 --- /dev/null +++ b/core/views/admin/unban.php @@ -0,0 +1,31 @@ + + + + + <?php echo config::getName();?> | Unban User + + + + +
    +
    + +
    +

    Unban User

    + + +
    +
    + + + \ No newline at end of file diff --git a/core/views/blog/main.php b/core/views/blog/main.php new file mode 100644 index 0000000..0395503 --- /dev/null +++ b/core/views/blog/main.php @@ -0,0 +1,37 @@ + + + + + <?php echo config::getName();?> | Blog + + + + + +
    +
    +
    +
    +
    +

    Graphictoria Blog

    + New Post'; + ?> +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/catalog/item.php b/core/views/catalog/item.php new file mode 100644 index 0000000..a8846dd --- /dev/null +++ b/core/views/catalog/item.php @@ -0,0 +1,155 @@ + + + + + <?php echo config::getName();?> | Item + + + + + '; + echo 'Incorrect itemId'; + html::buildFooter(); + exit; + } + }else{ + html::getNavigation(); + echo '
    '; + echo 'No ID specified
    '; + html::buildFooter(); + exit; + } + $stmt = $dbcon->prepare("SELECT * FROM catalog WHERE id=:id"); + $stmt->bindParam(':id', $itemId, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + html::getNavigation(); + echo '
    '; + echo 'Item not found
    '; + html::buildFooter(); + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $itemId = $result['id']; + if ($result['deleted'] == 1 or $result['declined'] == 1 or $result['approved'] == 0) { + html::getNavigation(); + echo '
    '; + echo 'Item not found
    '; + html::buildFooter(); + exit; + } + + if ($GLOBALS['loggedIn'] == false && $result['rbxasset'] == 1) { + header("Location: /catalog"); + exit; + } + + $stmt = $dbcon->prepare("SELECT * FROM users WHERE id=:id"); + $stmt->bindParam(':id', $result['creator_uid'], PDO::PARAM_INT); + $stmt->execute(); + $result_user = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($GLOBALS['loggedIn'] == true) { + $stmt = $dbcon->prepare("SELECT * FROM ownedItems WHERE uid=:id AND catalogid = :catid"); + $stmt->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->bindParam(':catid', $itemId, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() > 0) { + $owned = true; + }else{ + $owned = false; + } + } + + $stmt = $dbcon->prepare("SELECT * FROM ownedItems WHERE catalogid = :catid"); + $stmt->bindParam(':catid', $itemId, PDO::PARAM_INT); + $stmt->execute(); + $boughtTimes = $stmt->rowCount(); + html::getNavigation(); + ?> +
    +
    + var cType = "coins";'; + if ($result['currencyType'] == 1) echo ''; + ?> + +
    +
    +
    +
    +

    + +
    +
    +

    Details

    + + Creator: '.$result_user['username'].'

    '; + if ($result['type'] != "decals") { + if ($result['currencyType'] == 0) echo '

    Price: '.$result['price'].' coins

    Bought: '.$boughtTimes.' times

    '; + if ($result['currencyType'] == 1) echo '

    Price: '.$result['price'].' posties

    Bought: '.$boughtTimes.' times

    '; + } + ?> +

    Date Created:

    + Already owned'; + }else{ + if ($result['buyable'] == 1) { + if ($result['currencyType'] == 0) { + if ($GLOBALS['userTable']['coins'] > $result['price'] or $GLOBALS['userTable']['coins'] == $result['price']) { + echo ''; + }else{ + echo ''; + } + }else{ + if ($GLOBALS['userTable']['posties'] > $result['price'] or $GLOBALS['userTable']['posties'] == $result['price']) { + echo ''; + }else{ + echo ''; + } + } + }else{ + echo ''; + } + } + } + if ($loggedIn) { + if ($GLOBALS['userTable']['rank'] > 0) { + if ($result['type'] == "shirts" or $result['type'] == "tshirts" or $result['type'] == "pants" or $result['type'] == "decals") { + echo ''; + } + } + } + ?> +
    +
    + Use this link to use this decal in-game
    '; + echo 'http://xdiscuss.net/data/assets/uploads/'.$result['fileHash'].'
    '; + } + ?> + Description
    + 0) { + echo context::secureString($result['description']); + }else{ + echo '

    No Description

    '; + } + ?> +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/catalog/main.php b/core/views/catalog/main.php new file mode 100644 index 0000000..f3a3423 --- /dev/null +++ b/core/views/catalog/main.php @@ -0,0 +1,65 @@ + + + + + <?php echo config::getName();?> | Catalog + + + + + + + +
    +
    +
    + +
    +
    +
    +

    Catalog

    + + +
    +
    + + + + +
    +
    +
    +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/catalog/upload.php b/core/views/catalog/upload.php new file mode 100644 index 0000000..93d19c0 --- /dev/null +++ b/core/views/catalog/upload.php @@ -0,0 +1,62 @@ + + + + + <?php echo config::getName();?> | Upload Item + + + + + + +
    +

    Upload Item

    +

    In here you can upload an asset. This will cost you 5 coins. If your item gets deleted, you will not be granted a refund. In addition, you also need to wait for your asset to be approved.

    +
    +
    +
    +
    + + + + + + +
    + + +
    + + +
    + +
    +
    +
    + Information about assets +
      +
    • Uploading assets will cost you 5 coins. You can only upload 1 item each minute to prevent spamming.
    • +
    • Please make sure you are not breaking the terms of service. If you upload the wrong content, your account may get a punishment.
    • +
    • Shirts and Pants should have the resolution of 585x559, otherwise it will not upload.
    • +
    • Accepted formats are PNG and JPG.
    • +
    • Your item will go through approval. You will receive your item after approval, otherwise it'll be deleted.

    • + + +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/error/notfound.php b/core/views/error/notfound.php new file mode 100644 index 0000000..732c46a --- /dev/null +++ b/core/views/error/notfound.php @@ -0,0 +1,18 @@ + + + + + <?php echo config::getName();?> | Page not found + + + + +
    +

    Page not found

    +

    The page you were looking for was not found on our servers.
    If you believe this is on error, please contact us at support@xdiscuss.net describing your problem

    +
    + + + \ No newline at end of file diff --git a/core/views/forum/index.php b/core/views/forum/index.php new file mode 100644 index 0000000..a3b16f4 --- /dev/null +++ b/core/views/forum/index.php @@ -0,0 +1,47 @@ + + + + + <?php echo config::getName();?> | Forum + + + + + + + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/friends/main.php b/core/views/friends/main.php new file mode 100644 index 0000000..15aaf3e --- /dev/null +++ b/core/views/friends/main.php @@ -0,0 +1,33 @@ + + + + + <?php echo config::getName();?> | Friends + + + + + +
    +
    + +

    My Friends

    + +
    +
    +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/friends/requests.php b/core/views/friends/requests.php new file mode 100644 index 0000000..6fcb6ec --- /dev/null +++ b/core/views/friends/requests.php @@ -0,0 +1,33 @@ + + + + + <?php echo config::getName();?> | Friend Requests + + + + + +
    +
    + +

    My Friend Requests

    + +
    +
    +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/friends/show.php b/core/views/friends/show.php new file mode 100644 index 0000000..3868091 --- /dev/null +++ b/core/views/friends/show.php @@ -0,0 +1,57 @@ + + + + + <?php echo config::getName();?> | Friends + + + + +
    + '; + html::buildFooter(); + exit; + } + }else{ + echo 'No ID specified.
    '; + html::buildFooter(); + exit; + } + $stmt = $GLOBALS['dbcon']->prepare("SELECT username, id FROM users WHERE username = :username"); + $stmt->bindParam(':username', $id, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'User not found'; + html::buildFooter(); + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $id = $result['id']; + ?> + + +

    's friends

    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + + + + \ No newline at end of file diff --git a/core/views/games/download.php b/core/views/games/download.php new file mode 100644 index 0000000..a751648 --- /dev/null +++ b/core/views/games/download.php @@ -0,0 +1,33 @@ + + + + + <?php echo config::getName();?> | Download + + + + +
    +

    Browser is not supported

    +

    Use another browser such as Chrome to download. This is because this browser does not support the way of downloading.

    +
    + + + \ No newline at end of file diff --git a/core/views/games/download2008.php b/core/views/games/download2008.php new file mode 100644 index 0000000..93c26c0 --- /dev/null +++ b/core/views/games/download2008.php @@ -0,0 +1,33 @@ + + + + + <?php echo config::getName();?> | Download + + + + +
    +

    Browser is not supported

    +

    Use another browser such as Chrome to download. This is because this browser does not support the way of downloading.

    +
    + + + \ No newline at end of file diff --git a/core/views/games/download2011.php b/core/views/games/download2011.php new file mode 100644 index 0000000..fe6730e --- /dev/null +++ b/core/views/games/download2011.php @@ -0,0 +1,33 @@ + + + + + <?php echo config::getName();?> | Download + + + + +
    +

    Browser is not supported

    +

    Use another browser such as Chrome to download. This is because this browser does not support the way of downloading.

    +
    + + + \ No newline at end of file diff --git a/core/views/games/main.php b/core/views/games/main.php new file mode 100644 index 0000000..7d61815 --- /dev/null +++ b/core/views/games/main.php @@ -0,0 +1,63 @@ + + + + + <?php echo config::getName();?> | Games + + + + + +
    +
    + +
    +
    + +
    Looking to host a server? You can add a server here!
    +
    +
    + Enter key directly : + +
    +
    + All + 2008 + 2009 + 2010 + 2011 +
    +
    + View Public Servers + Private Servers + My Servers + Download 2009'; + echo ''; + echo ''; + } + ?> +
    +
    +
    +
    +
    +
    + +
    +
    + + + \ No newline at end of file diff --git a/core/views/games/new.php b/core/views/games/new.php new file mode 100644 index 0000000..f9e65b0 --- /dev/null +++ b/core/views/games/new.php @@ -0,0 +1,82 @@ + + + + + <?php echo config::getName();?> | New Server + + + + + +
    +
    +
    + +
    +
    +
    +
    +
    +
    +

    New Server

    + + + + + + +
    + + + + + + + + + +
    + +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/games/view.php b/core/views/games/view.php new file mode 100644 index 0000000..e9eb872 --- /dev/null +++ b/core/views/games/view.php @@ -0,0 +1,143 @@ + + + + + <?php echo config::getName();?> | View Server + + + + +
    + prepare("SELECT * FROM games WHERE id = :id;"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'Server not found'; + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $id = $result['id']; + if ($result['public'] == 0) { + $gameKey = $result['key']; + $stmtU = $dbcon->prepare("SELECT * FROM gameKeys WHERE userid=:id AND `key` = :key;"); + $stmtU->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmtU->bindParam(':key', $gameKey, PDO::PARAM_STR); + $stmtU->execute(); + if ($GLOBALS['loggedIn']) { + if ($stmtU->rowCount() == 0 and $result['creator_uid'] != $GLOBALS['userTable']['id'] and $GLOBALS['userTable']['rank'] == 0) { + echo 'Server not found'; + exit; + } + }else{ + echo 'Server not found'; + exit; + } + } + $stmt = $dbcon->prepare("SELECT username, id, imgTime FROM users WHERE id = :id"); + $stmt->bindParam(':id', $result['creator_uid'], PDO::PARAM_INT); + $stmt->execute(); + $resultuser = $stmt->fetch(PDO::FETCH_ASSOC); + ?> + + +
    +
    +
    +
    +
    + +
    +
    + +

    +

    Creator:

    +

    Date Created:

    + Description: None

    '; + }else{ + echo '

    Description: '.user::filter(context::secureString($result['description'])).'

    '; + } + + if ($GLOBALS['loggedIn']) { + if ($result['version'] == 0) echo 'Play'; + if ($result['version'] == 1) echo 'Play'; + if ($result['version'] == 2) echo 'Play'; + }else{ + echo 'Play'; + } + + if ($GLOBALS['loggedIn']) { + if ($GLOBALS['userTable']['rank'] > 0 or $GLOBALS['userTable']['id'] == $result['creator_uid']) { + if ($result['dedi'] == 0) echo ''; + } + if ($result['dedi'] == 1) { + if ($GLOBALS['userTable']['rank'] == 1 || $GLOBALS['userTable']['id'] == $result['creator_uid']) echo ''; + } + } + ?> +
    +
    +
    +
    +

    Online Players

    +
    + prepare("SELECT lastSeen, inGame, username, imgTime, id FROM users WHERE inGameId = :id ORDER BY id"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + $count = 0; + foreach($stmt as $resultk) { + $from_time = strtotime($resultk['lastSeen']); + $to_time = strtotime(context::getCurrentTime()); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince < 2 and $resultk['inGame'] == 1) { + $count++; + $username = $resultk['username']; + if (strlen($username) > 10) { + $username = substr($username, 0, 7) . '...'; + } + echo ''; + } + } + if ($count == 0) { + echo 'There is nobody online.'; + } + echo ''; + ?> +
    +
    +

    Command

    Use this command to start your server

    dofile("http://api.xdiscuss.net/serverscripts/server.php?key='.$result['privatekey'].'")
    '; + } + if ($result['public'] == 0) { + echo '

    Invites

    Use this key to invite people to your server

    '.$result['key'].'
    '; + } + } + ?> +
    + + + + \ No newline at end of file diff --git a/core/views/online.php b/core/views/online.php new file mode 100644 index 0000000..764267c --- /dev/null +++ b/core/views/online.php @@ -0,0 +1,36 @@ + + + + + <?php echo config::getName();?> | Online Users + + + + + +
    +
    +
    +
    +
    Users currently online
    +
    +
    +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/user/character.php b/core/views/user/character.php new file mode 100644 index 0000000..ff72746 --- /dev/null +++ b/core/views/user/character.php @@ -0,0 +1,74 @@ + + + + + <?php echo config::getName();?> | Character + + + + +
    + +
    +
    +
    +
    +
    +

    Character

    +
    + + + Regenerate + +
    +
    +
    +
    +

    Colors

    + +
    +
    +
    + +
    +

    Inventory

    + +
    +
    +
    +
    +

    Wearing

    +
    +
    +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/user/dashboard.php b/core/views/user/dashboard.php new file mode 100644 index 0000000..ec50570 --- /dev/null +++ b/core/views/user/dashboard.php @@ -0,0 +1,30 @@ + + + + + <?php echo config::getName();?> | Dashboard + + + + +
    +
    +
    +

    Hello,

    + +
    +
    +
    +

    Wall posts will appear here

    +

    We will work on this sooner or later

    +
    +
    + + + \ No newline at end of file diff --git a/core/views/user/groups/admin.php b/core/views/user/groups/admin.php new file mode 100644 index 0000000..c7536e3 --- /dev/null +++ b/core/views/user/groups/admin.php @@ -0,0 +1,59 @@ + + + + + <?php echo config::getName();?> | Group Admin + + + + + +
    + prepare("SELECT * FROM groups WHERE id = :id"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'Group has not been found'; + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $creator_uid = $result['cuid']; + $id = $result['id']; + if ($creator_uid != $GLOBALS['userTable']['id'] and $GLOBALS['userTable']['rank'] == 0) { + echo 'Access Denied'; + exit; + } + ?> + +
    +
    +
    +

    Group Admin

    + + + + Return to Group +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/user/groups/create.php b/core/views/user/groups/create.php new file mode 100644 index 0000000..bba43e7 --- /dev/null +++ b/core/views/user/groups/create.php @@ -0,0 +1,48 @@ + + + + + <?php echo config::getName();?> | Create Group + + + + + + +
    +
    +
    +
    +

    Create a Group

    +

    In here you can create a group that anyone can join and be a part of.

    +
    + + + + +
    + +
    +
    +
    +

    Things to remember

    +
      +
    • Group Names can not be longer than 32 characters
    • +
    • Group Names must be at least 5 characters
    • +
    • Descriptions can not be longer than 256 characters
    • +
    • Descriptions are optional
    • +
    • Creating a Group will cost you 50 coins
    • +
    • You can only be in 10 groups at a time
    • +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/user/groups/main.php b/core/views/user/groups/main.php new file mode 100644 index 0000000..9eb4cec --- /dev/null +++ b/core/views/user/groups/main.php @@ -0,0 +1,29 @@ + + + + + <?php echo config::getName();?> | Groups + + + + + +
    +
    +
    +

    Groups

    +

    Groups will make team-work a lot easier, interact with friends and make new ones!

    + Create new Group + Search Group +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/user/groups/search.php b/core/views/user/groups/search.php new file mode 100644 index 0000000..8385bc8 --- /dev/null +++ b/core/views/user/groups/search.php @@ -0,0 +1,39 @@ + + + + + <?php echo config::getName();?> | Groups + + + + + + +
    +
    +
    +
    +
    + + + + +
    +
    +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/user/groups/view.php b/core/views/user/groups/view.php new file mode 100644 index 0000000..302c251 --- /dev/null +++ b/core/views/user/groups/view.php @@ -0,0 +1,99 @@ + + + + + <?php echo config::getName();?> | Group + + + + +
    + prepare("SELECT * FROM groups WHERE id = :id"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'Group has not been found'; + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $creator_uid = $result['cuid']; + $id = $result['id']; + ?> + + + +
    +
    +
    +
    +

    + prepare("SELECT imgTime, id, username FROM users WHERE id = :id"); + $stmt->bindParam(':id', $creator_uid, PDO::PARAM_INT); + $stmt->execute(); + $resultuser = $stmt->fetch(PDO::FETCH_ASSOC); + ?> + +

    Creator:

    +

    Date Created:

    + Leave and delete Group'; + }else{ + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM group_members WHERE uid = :uid AND gid = :id"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->bindParam(':uid', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo ''; + }else{ + echo ''; + } + } + if ($GLOBALS['userTable']['id'] == $result['cuid'] or $GLOBALS['userTable']['rank'] > 0) { + echo 'Group Admin'; + } + }else{ + echo ''; + } + ?> +
    +
    +

    Description

    + No Description'; + }else{ + echo '

    '.nl2br(context::secureString($result['description'])).'

    '; + } + ?> +
    +
    +
    +
    +

    Members

    +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/user/logout.php b/core/views/user/logout.php new file mode 100644 index 0000000..c3cf532 --- /dev/null +++ b/core/views/user/logout.php @@ -0,0 +1,32 @@ +prepare('SELECT * FROM sessions WHERE userId = :userId AND sessionId = :sessionId;'); + $stmt->bindParam(':userId', $_COOKIE['auth_uid'], PDO::PARAM_INT); + $stmt->bindParam(':sessionId', $_COOKIE['a_id'], PDO::PARAM_STR); + $stmt->execute(); + $resultSession = $stmt->fetch(PDO::FETCH_ASSOC); + $sessionId = $resultSession['id']; + + $stmt = $dbcon->prepare('DELETE FROM sessions WHERE id=:id;'); + $stmt->bindParam(':id', $sessionId, PDO::PARAM_INT); + $stmt->execute(); + + unset($_COOKIE['auth_uid']); + unset($_COOKIE['a_id']); + setcookie('auth_uid', "", time() - 3600); + setcookie('a_id', "", time() - 3600); + + if (isset($_SERVER['HTTP_REFERER'])) { + header("Location: ".$_SERVER['HTTP_REFERER']); + exit; + }else{ + header("Location: /"); + exit; + } +?> \ No newline at end of file diff --git a/core/views/user/messages.php b/core/views/user/messages.php new file mode 100644 index 0000000..efe49ac --- /dev/null +++ b/core/views/user/messages.php @@ -0,0 +1,38 @@ + + + + + <?php echo config::getName();?> | Messages + + + + + + +
    + +
    +
    +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/user/profile.php b/core/views/user/profile.php new file mode 100644 index 0000000..e365069 --- /dev/null +++ b/core/views/user/profile.php @@ -0,0 +1,261 @@ + + + + + <?php echo config::getName();?> | Profile + + + + +
    + '; + html::buildFooter(); + exit; + } + }else{ + echo 'No username specified
    '; + html::buildFooter(); + exit; + } + + $stmt = $GLOBALS['dbcon']->prepare('SELECT * FROM users WHERE username = :username;'); + $stmt->bindParam(':username', $username, PDO::PARAM_STR); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'User not found'; + html::buildFooter(); + exit; + } + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $userID = $result['id']; + $p_username = $result['username']; + if ($result['banned'] == 1) { + echo 'This user has been suspended'; + html::buildFooter(); + exit; + } + echo ''; + + $stmtr = $GLOBALS['dbcon']->prepare("SELECT id FROM `profile_views` WHERE `viewer` = :id AND `profile` = :pid;"); + $stmtr->bindParam(':id', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmtr->bindParam(':pid', $userID, PDO::PARAM_INT); + $stmtr->execute(); + if ($stmtr->rowCount() == 0) { + $found = false; + }else{ + $found = true; + } + if ($found == false and $loggedIn == true) { + $result['profileviews'] = $result['profileviews']+1; + $query = "INSERT INTO `profile_views` (`viewer`, `profile`) VALUES (:userId, :profile);"; + $stmt = $GLOBALS['dbcon']->prepare($query); + $stmt->bindParam(':profile', $userID, PDO::PARAM_INT); + $stmt->bindParam(':userId', $GLOBALS['userTable']['id'], PDO::PARAM_INT); + $stmt->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("UPDATE users SET profileviews = profileviews + 1 WHERE id = :id"); + $stmt->bindParam(':id', $userID, PDO::PARAM_INT); + $stmt->execute(); + } + ?> +
    + +
    +
    +

    + ● ') { + if ($GLOBALS['loggedIn']) { + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM gameJoins WHERE uid = :id"); + $stmt->bindParam(':id', $result['id'], PDO::PARAM_INT); + $stmt->execute(); + $resultGame = $stmt->fetch(PDO::FETCH_ASSOC); + echo ' In Game || Follow
    '; + }else{ + echo ' In Game
    '; + } + } + ?> + + + Send Message'; + context::buildFriendButton($result['id']); + echo '
    '; + } + } + ?> +

    + '.context::secureString($result['about']).''; + } + ?> +

    +
    +
    +

    Statistics

    +

    Join Date:

    +

    Last Seen:

    + +

    +

    Forum Posts:

    +

    Profile views:

    +
    +
    +

    Groups

    + prepare("SELECT * FROM groups WHERE cuid = :id;"); + $stmt->bindParam(':id', $userID, PDO::PARAM_INT); + $stmt->execute(); + foreach($stmt as $result) { + $count++; + echo ''.context::secureString($result['name']).' '; + } + + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM group_members WHERE uid = :id;"); + $stmt->bindParam(':id', $userID, PDO::PARAM_INT); + $stmt->execute(); + foreach($stmt as $result) { + $count++; + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM groups WHERE id = :id"); + $gId = $result['gid']; + $stmt->bindParam(':id', $gId, PDO::PARAM_INT); + $stmt->execute(); + $resultGroupM = $stmt->fetch(PDO::FETCH_ASSOC); + echo ''.context::secureString($resultGroupM['name']).' '; + } + if ($count == 0) { + echo '
    This user is not in any group.
    '; + } + ?> +
    + +
    +
    +

    Friends

    + prepare("SELECT * FROM friends WHERE userId1 = :id;"); + $stmtc->bindParam(':id', $userID, PDO::PARAM_INT); + $stmtc->execute(); + + $stmt = $GLOBALS['dbcon']->prepare("SELECT * FROM friends WHERE userId1 = :id ORDER BY id DESC LIMIT 8;"); + $stmt->bindParam(':id', $userID, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'This user has no friends.'; + }else{ + echo '
    '; + } + echo ''; + foreach($stmt as $result) { + $userId = $result['userId2']; + $stmt = $GLOBALS['dbcon']->prepare("SELECT username, imgTime, lastSeen, id FROM users WHERE id = :id"); + $stmt->bindParam(':id', $userId, PDO::PARAM_INT); + $stmt->execute(); + $resultuser = $stmt->fetch(PDO::FETCH_ASSOC); + $username = $resultuser['username']; + if (strlen($username) > 10) { + $username = substr($username, 0, 7) . '...'; + } + echo '

    '; + echo '
    '; + echo context::getOnline($resultuser); + echo ''.htmlentities($username, ENT_QUOTES, "UTF-8").'

    '; + } + if ($stmt->rowCount() > 0) { + echo '
    '; + } + if ($stmtc->rowCount() > 8) { + echo 'Show all friends'; + } + ?> +
    +
    +

    Badges

    +
    + prepare("SELECT badgeId FROM badges WHERE uid = :id"); + $stmt->bindParam(':id', $userID, PDO::PARAM_INT); + $stmt->execute(); + if ($stmt->rowCount() == 0) { + echo 'This user has no badges.'; + } + $name = ""; + $description = ""; + foreach($stmt as $resultBadge) { + if ($resultBadge['badgeId'] == 1) { + $name = "Administrator"; + $description = "Owned by the administrators of Graphictoria. Owners of this badge control the whole entire website and can change everything. Users who do not have this badge are not administrators."; + } + if ($resultBadge['badgeId'] == 2) { + $name = "Administrator"; + $description = "Owned by the administrators of Graphictoria. Owners of this badge control the whole entire website and can change everything. Users who do not have this badge are not administrators."; + } + if ($resultBadge['badgeId'] == 3) { + $name = "Moderator"; + $description = "Owned by the moderators of Graphictoria. Owners of this badge moderate the website. Users who do not have this badge are not moderators."; + } + if ($resultBadge['badgeId'] == 4) { + $name = "Forumer"; + $description = "Owned by the active forumers who managed to get 1000 posts!"; + } + if ($resultBadge['badgeId'] == 5) { + $name = "Member"; + $description = "This badge is owned by every single user of Graphictoria and proves that you have played Graphictoria."; + } + if ($resultBadge['badgeId'] == 6) { + $name = "Roblox Staff"; + $description = "This badge is only awarded to verified, legitimate Roblox staff members."; + } + if ($resultBadge['badgeId'] == 7) { + $name = "Before 100"; + $description = "Owned by the very first 100 users of Graphictoria. Users with this badge know the story of how we came to be."; + } + if ($resultBadge['badgeId'] == 8) { + $name = "Gamer"; + $description = "This user has successfully joined a game at least once"; + } + echo '

    '.$name.'

    '; + } + ?> +
    +
    +
    +

    Inventory

    + +
    +
    +
    +
    +
    + +
    + + + + \ No newline at end of file diff --git a/core/views/user/security/banned.php b/core/views/user/security/banned.php new file mode 100644 index 0000000..6426323 --- /dev/null +++ b/core/views/user/security/banned.php @@ -0,0 +1,55 @@ + + + + + <?php echo config::getName();?> | Suspended + + + + + +
    +
    +
    +
    + '.$type.''; + if ($type == "Account Deleted") { + $message = "You will not be able to re-activate your account"; + }elseif ($type == "Warning") { + $message = "You will be able to activate your account now"; + }else{ + $message = "You will be able to re-activate your account once the suspension has been expired"; + } + echo '

    Suspended on : '.date('M j Y g:i A', strtotime($GLOBALS['userTable']['bantime'])).'

    '; + echo '

    '.$message.'

    '; + echo '

    Reason for suspension: '.context::secureString($GLOBALS['userTable']['banreason']).'

    '; + + if ($type != "Account Deleted") { + echo ''; + } + ?> +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/user/security/resetpassword.php b/core/views/user/security/resetpassword.php new file mode 100644 index 0000000..d54bfac --- /dev/null +++ b/core/views/user/security/resetpassword.php @@ -0,0 +1,62 @@ +prepare($query); + $stmt->bindParam(':uid', $userID, PDO::PARAM_INT); + $stmt->bindParam(':key', $key, PDO::PARAM_STR); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($stmt->rowCount() == 0 or $result['used'] == 1) { + header("Location: /"); + exit; + } + + $currentTime = date('Y-m-d H:i:s'); + $to_time = strtotime($currentTime); + $from_time = strtotime($result['date']); + $timeSince = round(abs($to_time - $from_time) / 60,2); + if ($timeSince > 5) { + header("Location: /"); + exit; + } +?> + + + + <?php echo config::getName();?> | Reset Password + + + + +
    + +
    +
    +
    +

    Reset Password

    +

    If you have lost your password, you can reset it here

    + + + +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/user/security/twostepauth.php b/core/views/user/security/twostepauth.php new file mode 100644 index 0000000..cf00f71 --- /dev/null +++ b/core/views/user/security/twostepauth.php @@ -0,0 +1,31 @@ + + + + + <?php echo config::getName();?> | Two Step Authentication + + + + + +
    +
    +
    +
    +

    Two Step Authentication

    +

    Sign in with the authentication code generated by your mobile app

    + + +
    +

    If you need help, please contact support@xdiscuss.net and we will gladly help you

    +
    +
    + + + \ No newline at end of file diff --git a/core/views/user/security/verifyEmail.php b/core/views/user/security/verifyEmail.php new file mode 100644 index 0000000..364aa81 --- /dev/null +++ b/core/views/user/security/verifyEmail.php @@ -0,0 +1,49 @@ + + + + + <?php echo config::getName();?> | Verify Email + + + + + +
    +
    +
    +
    +

    Verify your email

    +

    An email has been sent to which contains your verification code. Enter that code below.

    +

    All emails will be automatically resent after 15 minutes in case you did not receive it.

    +

    If you are unable to find your email, check your spam or junk folder.

    +

    If you made a mistake entering your email address, click here

    + + +
    +

    If you need help, please contact support@xdiscuss.net and we will gladly help you

    +
    +
    + + + + \ No newline at end of file diff --git a/core/views/user/settings.php b/core/views/user/settings.php new file mode 100644 index 0000000..2437cfd --- /dev/null +++ b/core/views/user/settings.php @@ -0,0 +1,83 @@ + + + + + <?php echo config::getName();?> | Settings + + + + + + +
    +

    Settings

    +
    + +
    +
    +
    +

    About Me

    You can set your text here which will appear on your profile.

    + + +
    +
    +
    +
    +
    +

    Change Password

    You can change your password here

    +
    +
    + +
    +
    + +
    +
    + + +
    +
    +
    +
    +
    +

    Change E-Mail

    You can change your e-mail here

    + + + +
    +
    +
    +
    +
    +
    +

    Two Step Authentication

    This feature requires you to enter a secondary code in order to login.

    +
    + +
    +
    +
    +
    +
    +

    Appearance

    How the website looks

    +
    + + +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/core/views/users.php b/core/views/users.php new file mode 100644 index 0000000..8578ae0 --- /dev/null +++ b/core/views/users.php @@ -0,0 +1,42 @@ + + + + + <?php echo config::getName();?> | Users + + + + + +
    +
    + +
    +
    +
    +
    +
    + + + + +
    +
    + Online users +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/data/.htaccess b/data/.htaccess new file mode 100644 index 0000000..290b3ce --- /dev/null +++ b/data/.htaccess @@ -0,0 +1,5 @@ +Satisfy Any +Allow from all + +RewriteEngine on +CheckSpelling on \ No newline at end of file diff --git a/data/assets/config.php b/data/assets/config.php new file mode 100644 index 0000000..6a0aac9 --- /dev/null +++ b/data/assets/config.php @@ -0,0 +1,12 @@ + diff --git a/data/assets/decals/.gitkeep b/data/assets/decals/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/faces/models/.gitkeep b/data/assets/faces/models/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/faces/texture/.gitkeep b/data/assets/faces/texture/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/faces/thumbnail/.gitkeep b/data/assets/faces/thumbnail/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/gear/animations/.gitkeep b/data/assets/gear/animations/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/gear/icons/.gitkeep b/data/assets/gear/icons/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/gear/meshes/.gitkeep b/data/assets/gear/meshes/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/gear/models/.gitkeep b/data/assets/gear/models/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/gear/sounds/.gitkeep b/data/assets/gear/sounds/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/gear/textures/.gitkeep b/data/assets/gear/textures/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/gear/thumbnail/.gitkeep b/data/assets/gear/thumbnail/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/hats/mesh/.gitkeep b/data/assets/hats/mesh/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/hats/models/.gitkeep b/data/assets/hats/models/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/hats/sound/.gitkeep b/data/assets/hats/sound/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/hats/texture/.gitkeep b/data/assets/hats/texture/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/hats/thumbnail/.gitkeep b/data/assets/hats/thumbnail/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/heads/mesh/.gitkeep b/data/assets/heads/mesh/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/heads/models/.gitkeep b/data/assets/heads/models/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/heads/texture/.gitkeep b/data/assets/heads/texture/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/heads/thumbnail/.gitkeep b/data/assets/heads/thumbnail/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/pants/.gitkeep b/data/assets/pants/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/pants/models/get.php b/data/assets/pants/models/get.php new file mode 100644 index 0000000..d548e0e --- /dev/null +++ b/data/assets/pants/models/get.php @@ -0,0 +1,45 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); + $dbcon->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + }catch (PDOExpection $e){ + echo $e->getMessage(); + } + + $stmt = $dbcon->prepare("SELECT * FROM catalog WHERE assetid=:id AND type='pants';"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($stmt->rowCount() == 0) { + $dbcon = null; + exit; + } + + header('Content-type: text/xml'); + $dbcon = null; +?> + + + + null + nil + + + + http://xdiscuss.net/data/assets/uploads/ + + Pants + true + + + \ No newline at end of file diff --git a/data/assets/pants/textures/.gitkeep b/data/assets/pants/textures/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/shirts/.gitkeep b/data/assets/shirts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/shirts/models/get.php b/data/assets/shirts/models/get.php new file mode 100644 index 0000000..ab11aa9 --- /dev/null +++ b/data/assets/shirts/models/get.php @@ -0,0 +1,45 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); + $dbcon->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + }catch (PDOExpection $e){ + echo $e->getMessage(); + } + + $stmt = $dbcon->prepare("SELECT * FROM catalog WHERE assetid=:id AND type='shirts';"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($stmt->rowCount() == 0) { + $dbcon = null; + exit; + } + + header('Content-type: text/xml'); + $dbcon = null; +?> + + + + null + nil + + + + http://xdiscuss.net/data/assets/uploads/ + + Shirt + true + + + \ No newline at end of file diff --git a/data/assets/shirts/textures/.gitkeep b/data/assets/shirts/textures/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/tshirts/.gitkeep b/data/assets/tshirts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/assets/tshirts/models/get.php b/data/assets/tshirts/models/get.php new file mode 100644 index 0000000..72efeb3 --- /dev/null +++ b/data/assets/tshirts/models/get.php @@ -0,0 +1,45 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); + $dbcon->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + }catch (PDOExpection $e){ + exit; + } + + $stmt = $dbcon->prepare("SELECT * FROM catalog WHERE assetid=:id AND type='tshirts';"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + if ($stmt->rowCount() == 0) { + $dbcon = null; + exit; + } + + header('Content-type: text/xml'); + $dbcon = null; +?> + + + + null + nil + + + + http://xdiscuss.net/data/assets/uploads/ + + Shirt Graphic + true + + + \ No newline at end of file diff --git a/data/assets/uploads/.gitkeep b/data/assets/uploads/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/data/templates/clothing4.png b/data/templates/clothing4.png new file mode 100644 index 0000000..be72b4b Binary files /dev/null and b/data/templates/clothing4.png differ diff --git a/db.sql b/db.sql new file mode 100644 index 0000000..86b2df7 --- /dev/null +++ b/db.sql @@ -0,0 +1,573 @@ +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8 */; +/*!50503 SET NAMES utf8mb4 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; + +-- Dumping database structure for xdiscuss3 +CREATE DATABASE IF NOT EXISTS `xdiscuss3` /*!40100 DEFAULT CHARACTER SET latin1 */; +USE `xdiscuss3`; + +-- Dumping structure for table xdiscuss3.badges +CREATE TABLE IF NOT EXISTS `badges` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `uid` int(11) NOT NULL DEFAULT 0, + `badgeId` int(11) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.badges: ~0 rows (approximately) +/*!40000 ALTER TABLE `badges` DISABLE KEYS */; +/*!40000 ALTER TABLE `badges` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.badHashes +CREATE TABLE IF NOT EXISTS `badHashes` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `hash` varchar(1024) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.badHashes: ~0 rows (approximately) +/*!40000 ALTER TABLE `badHashes` DISABLE KEYS */; +/*!40000 ALTER TABLE `badHashes` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.banlogs +CREATE TABLE IF NOT EXISTS `banlogs` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `banned_by_uid` int(11) NOT NULL DEFAULT 0, + `banned_by_uname` varchar(50) DEFAULT NULL, + `banned_uid` int(11) NOT NULL DEFAULT 0, + `banned_uname` varchar(50) DEFAULT NULL, + `reason` varchar(512) DEFAULT NULL, + `bantype` int(11) NOT NULL DEFAULT 0, + `date` timestamp NULL DEFAULT current_timestamp(), + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.banlogs: ~0 rows (approximately) +/*!40000 ALTER TABLE `banlogs` DISABLE KEYS */; +/*!40000 ALTER TABLE `banlogs` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.blogposts +CREATE TABLE IF NOT EXISTS `blogposts` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `poster_uid` int(11) DEFAULT 0, + `date` timestamp NULL DEFAULT current_timestamp(), + `title` varchar(64) DEFAULT NULL, + `content` varchar(30000) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.blogposts: ~0 rows (approximately) +/*!40000 ALTER TABLE `blogposts` DISABLE KEYS */; +/*!40000 ALTER TABLE `blogposts` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.catagories +CREATE TABLE IF NOT EXISTS `catagories` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `visible` int(11) unsigned NOT NULL DEFAULT 0, + `developer` int(11) unsigned NOT NULL DEFAULT 0, + `name` varchar(50) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.catagories: ~0 rows (approximately) +/*!40000 ALTER TABLE `catagories` DISABLE KEYS */; +/*!40000 ALTER TABLE `catagories` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.catalog +CREATE TABLE IF NOT EXISTS `catalog` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `price` int(11) NOT NULL DEFAULT 0, + `currencyType` int(11) NOT NULL DEFAULT 0, + `creator_uid` int(11) NOT NULL DEFAULT 0, + `buyable` int(11) NOT NULL DEFAULT 1, + `assetid` int(11) DEFAULT NULL, + `deleted` int(11) DEFAULT 0, + `approved` int(11) DEFAULT 0, + `declined` int(11) DEFAULT 0, + `rbxasset` int(11) DEFAULT 0, + `name` varchar(50) DEFAULT NULL, + `fileHash` varchar(512) DEFAULT NULL, + `type` varchar(50) DEFAULT NULL, + `description` varchar(128) DEFAULT NULL, + `datafile` varchar(50) DEFAULT NULL, + `createDate` timestamp NULL DEFAULT current_timestamp(), + `imgTime` timestamp NULL DEFAULT current_timestamp(), + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.catalog: ~0 rows (approximately) +/*!40000 ALTER TABLE `catalog` DISABLE KEYS */; +/*!40000 ALTER TABLE `catalog` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.characterColors +CREATE TABLE IF NOT EXISTS `characterColors` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `uid` int(11) DEFAULT 0, + `color` int(11) DEFAULT 0, + `type` varchar(50) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.characterColors: ~0 rows (approximately) +/*!40000 ALTER TABLE `characterColors` DISABLE KEYS */; +/*!40000 ALTER TABLE `characterColors` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.chat_members +CREATE TABLE IF NOT EXISTS `chat_members` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `chat_id` int(11) NOT NULL DEFAULT 0, + `userId` int(11) NOT NULL DEFAULT 0, + `rank` int(11) NOT NULL DEFAULT 0, + `lastActive` timestamp NOT NULL DEFAULT current_timestamp(), + `lastType` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.chat_members: ~0 rows (approximately) +/*!40000 ALTER TABLE `chat_members` DISABLE KEYS */; +/*!40000 ALTER TABLE `chat_members` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.chat_messages +CREATE TABLE IF NOT EXISTS `chat_messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `chat_id` int(11) DEFAULT 0, + `userId` int(11) DEFAULT 0, + `message` varchar(65000) DEFAULT NULL, + `date` int(11) DEFAULT 0, + `bot` int(11) DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.chat_messages: ~0 rows (approximately) +/*!40000 ALTER TABLE `chat_messages` DISABLE KEYS */; +/*!40000 ALTER TABLE `chat_messages` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.chat_sessions +CREATE TABLE IF NOT EXISTS `chat_sessions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `chatName` varchar(50) NOT NULL DEFAULT '128', + `chatImage` varchar(50) NOT NULL DEFAULT '128', + `chatKey` varchar(50) NOT NULL DEFAULT '128', + `chatJoinKey` varchar(50) NOT NULL DEFAULT '128', + `creationDate` timestamp NOT NULL DEFAULT current_timestamp(), + `lastActive` timestamp NOT NULL DEFAULT current_timestamp(), + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.chat_sessions: ~0 rows (approximately) +/*!40000 ALTER TABLE `chat_sessions` DISABLE KEYS */; +/*!40000 ALTER TABLE `chat_sessions` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.errorReports +CREATE TABLE IF NOT EXISTS `errorReports` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `string` varchar(1024) DEFAULT NULL, + `ip` varchar(128) DEFAULT NULL, + `time` timestamp NULL DEFAULT current_timestamp(), + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.errorReports: ~0 rows (approximately) +/*!40000 ALTER TABLE `errorReports` DISABLE KEYS */; +/*!40000 ALTER TABLE `errorReports` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.forums +CREATE TABLE IF NOT EXISTS `forums` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `catid` int(11) DEFAULT NULL, + `developer` int(11) DEFAULT 0, + `name` varchar(50) DEFAULT NULL, + `description` varchar(128) DEFAULT NULL, + `locked` int(11) DEFAULT 0, + `posts` int(11) DEFAULT 0, + `replies` int(11) DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.forums: ~0 rows (approximately) +/*!40000 ALTER TABLE `forums` DISABLE KEYS */; +/*!40000 ALTER TABLE `forums` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.friendRequests +CREATE TABLE IF NOT EXISTS `friendRequests` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `senduid` int(11) DEFAULT 0, + `recvuid` int(11) DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.friendRequests: ~0 rows (approximately) +/*!40000 ALTER TABLE `friendRequests` DISABLE KEYS */; +/*!40000 ALTER TABLE `friendRequests` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.friends +CREATE TABLE IF NOT EXISTS `friends` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `userId1` int(11) DEFAULT 0, + `userId2` int(11) DEFAULT 0, + `friendSince` timestamp NULL DEFAULT current_timestamp(), + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.friends: ~0 rows (approximately) +/*!40000 ALTER TABLE `friends` DISABLE KEYS */; +/*!40000 ALTER TABLE `friends` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.gameJoins +CREATE TABLE IF NOT EXISTS `gameJoins` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `uid` int(11) DEFAULT 0, + `gameId` int(11) DEFAULT NULL, + `time` timestamp NULL DEFAULT current_timestamp(), + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.gameJoins: ~0 rows (approximately) +/*!40000 ALTER TABLE `gameJoins` DISABLE KEYS */; +/*!40000 ALTER TABLE `gameJoins` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.gameKeys +CREATE TABLE IF NOT EXISTS `gameKeys` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `userid` int(11) NOT NULL DEFAULT 0, + `key` varchar(128) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.gameKeys: ~0 rows (approximately) +/*!40000 ALTER TABLE `gameKeys` DISABLE KEYS */; +/*!40000 ALTER TABLE `gameKeys` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.games +CREATE TABLE IF NOT EXISTS `games` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `version` int(11) DEFAULT 0, + `creator_uid` int(11) DEFAULT 0, + `public` int(11) DEFAULT 0, + `name` varchar(32) DEFAULT NULL, + `description` varchar(128) DEFAULT NULL, + `key` varchar(128) DEFAULT NULL, + `privatekey` varchar(128) DEFAULT NULL, + `placeURL` varchar(256) DEFAULT NULL, + `ip` varchar(64) DEFAULT NULL, + `port` int(5) DEFAULT 53640, + `numPlayers` int(5) DEFAULT 0, + `dedi` int(5) DEFAULT 0, + `date` timestamp NULL DEFAULT current_timestamp(), + `imgTime` timestamp NULL DEFAULT current_timestamp(), + `lastPing` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.games: ~0 rows (approximately) +/*!40000 ALTER TABLE `games` DISABLE KEYS */; +/*!40000 ALTER TABLE `games` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.groups +CREATE TABLE IF NOT EXISTS `groups` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `cuid` int(11) NOT NULL DEFAULT 0, + `closed` int(11) NOT NULL DEFAULT 0, + `creationDate` timestamp NOT NULL DEFAULT current_timestamp(), + `name` varchar(32) NOT NULL, + `description` varchar(256) DEFAULT NULL, + `shout` varchar(256) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.groups: ~0 rows (approximately) +/*!40000 ALTER TABLE `groups` DISABLE KEYS */; +/*!40000 ALTER TABLE `groups` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.group_members +CREATE TABLE IF NOT EXISTS `group_members` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `uid` int(11) NOT NULL DEFAULT 0, + `gid` int(11) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.group_members: ~0 rows (approximately) +/*!40000 ALTER TABLE `group_members` DISABLE KEYS */; +/*!40000 ALTER TABLE `group_members` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.loginAttempts +CREATE TABLE IF NOT EXISTS `loginAttempts` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ip` varchar(50) DEFAULT NULL, + `uid` int(11) NOT NULL DEFAULT 0, + `time` timestamp NOT NULL DEFAULT current_timestamp(), + `count` int(11) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`), + KEY `id` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.loginAttempts: ~0 rows (approximately) +/*!40000 ALTER TABLE `loginAttempts` DISABLE KEYS */; +/*!40000 ALTER TABLE `loginAttempts` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.messages +CREATE TABLE IF NOT EXISTS `messages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `recv_uid` int(11) NOT NULL DEFAULT 0, + `sender_uid` int(11) NOT NULL DEFAULT 0, + `read` int(11) NOT NULL DEFAULT 0, + `date` timestamp NOT NULL DEFAULT current_timestamp(), + `title` varchar(64) DEFAULT NULL, + `content` varchar(30000) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.messages: ~0 rows (approximately) +/*!40000 ALTER TABLE `messages` DISABLE KEYS */; +/*!40000 ALTER TABLE `messages` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.ownedItems +CREATE TABLE IF NOT EXISTS `ownedItems` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `uid` int(11) DEFAULT 0, + `catalogid` int(11) DEFAULT 0, + `type` varchar(50) DEFAULT NULL, + `deleted` int(11) DEFAULT 0, + `rbxasset` int(11) DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.ownedItems: ~0 rows (approximately) +/*!40000 ALTER TABLE `ownedItems` DISABLE KEYS */; +/*!40000 ALTER TABLE `ownedItems` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.passwordresets +CREATE TABLE IF NOT EXISTS `passwordresets` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `userId` int(11) NOT NULL DEFAULT 0, + `used` int(11) NOT NULL DEFAULT 0, + `key` varchar(256) DEFAULT NULL, + `date` timestamp NULL DEFAULT current_timestamp(), + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.passwordresets: ~0 rows (approximately) +/*!40000 ALTER TABLE `passwordresets` DISABLE KEYS */; +/*!40000 ALTER TABLE `passwordresets` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.profile_views +CREATE TABLE IF NOT EXISTS `profile_views` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `viewer` int(11) NOT NULL DEFAULT 0, + `profile` int(11) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.profile_views: ~0 rows (approximately) +/*!40000 ALTER TABLE `profile_views` DISABLE KEYS */; +/*!40000 ALTER TABLE `profile_views` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.pwdreset +CREATE TABLE IF NOT EXISTS `pwdreset` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ip` varchar(50) DEFAULT NULL, + `date` timestamp NULL DEFAULT current_timestamp(), + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.pwdreset: ~0 rows (approximately) +/*!40000 ALTER TABLE `pwdreset` DISABLE KEYS */; +/*!40000 ALTER TABLE `pwdreset` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.read +CREATE TABLE IF NOT EXISTS `read` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `userId` int(11) NOT NULL DEFAULT 0, + `postId` int(11) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.read: ~0 rows (approximately) +/*!40000 ALTER TABLE `read` DISABLE KEYS */; +/*!40000 ALTER TABLE `read` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.renders +CREATE TABLE IF NOT EXISTS `renders` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `render_id` varchar(512) NOT NULL DEFAULT '0', + `type` varchar(50) DEFAULT NULL, + `rendered` int(11) DEFAULT 0, + `version` int(11) DEFAULT 1, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.renders: ~0 rows (approximately) +/*!40000 ALTER TABLE `renders` DISABLE KEYS */; +/*!40000 ALTER TABLE `renders` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.replies +CREATE TABLE IF NOT EXISTS `replies` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `forumId` int(11) NOT NULL DEFAULT 0, + `developer` int(11) NOT NULL DEFAULT 0, + `author_uid` int(11) DEFAULT NULL, + `postId` int(11) DEFAULT NULL, + `content` varchar(30000) DEFAULT NULL, + `post_time` timestamp NULL DEFAULT current_timestamp(), + `updatedOn` timestamp NULL DEFAULT current_timestamp(), + `updatedBy` int(11) DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.replies: ~0 rows (approximately) +/*!40000 ALTER TABLE `replies` DISABLE KEYS */; +/*!40000 ALTER TABLE `replies` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.reports +CREATE TABLE IF NOT EXISTS `reports` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `reportIP` varchar(128) DEFAULT NULL, + `target` varchar(20) DEFAULT NULL, + `reason` varchar(256) DEFAULT NULL, + `date` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.reports: ~0 rows (approximately) +/*!40000 ALTER TABLE `reports` DISABLE KEYS */; +/*!40000 ALTER TABLE `reports` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.serverRequests +CREATE TABLE IF NOT EXISTS `serverRequests` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `placeLocation` varchar(512) DEFAULT NULL, + `serverName` varchar(512) DEFAULT NULL, + `serverDescription` varchar(512) DEFAULT NULL, + `serverVersion` int(11) DEFAULT 0, + `serverPrivacy` int(11) DEFAULT 0, + `userID` int(11) DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.serverRequests: ~0 rows (approximately) +/*!40000 ALTER TABLE `serverRequests` DISABLE KEYS */; +/*!40000 ALTER TABLE `serverRequests` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.sessions +CREATE TABLE IF NOT EXISTS `sessions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `userId` int(11) DEFAULT NULL, + `factorFinish` int(11) DEFAULT 0, + `sessionId` varchar(255) DEFAULT NULL, + `csrfToken` varchar(255) DEFAULT NULL, + `location` varchar(255) DEFAULT NULL, + `useragent` varchar(255) DEFAULT NULL, + `lastUsed` timestamp NULL DEFAULT current_timestamp(), + PRIMARY KEY (`id`) +) ENGINE=MEMORY DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.sessions: 0 rows +/*!40000 ALTER TABLE `sessions` DISABLE KEYS */; +/*!40000 ALTER TABLE `sessions` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.topics +CREATE TABLE IF NOT EXISTS `topics` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `forumId` int(11) NOT NULL DEFAULT 0, + `developer` int(11) NOT NULL DEFAULT 0, + `author_uid` int(11) DEFAULT 0, + `locked` int(1) DEFAULT 0, + `lockedByStaff` int(1) DEFAULT 0, + `pinned` int(1) DEFAULT 0, + `views` int(1) DEFAULT 0, + `title` varchar(1024) DEFAULT NULL, + `content` varchar(30000) DEFAULT NULL, + `postTime` timestamp NULL DEFAULT current_timestamp(), + `lastActivity` timestamp NULL DEFAULT NULL, + `updatedOn` timestamp NULL DEFAULT NULL, + `updatedBy` int(11) DEFAULT 0, + `replies` int(11) DEFAULT 0, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.topics: ~0 rows (approximately) +/*!40000 ALTER TABLE `topics` DISABLE KEYS */; +/*!40000 ALTER TABLE `topics` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.users +CREATE TABLE IF NOT EXISTS `users` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `banned` int(1) NOT NULL DEFAULT 0, + `publicBan` int(1) NOT NULL DEFAULT 0, + `bantype` int(1) NOT NULL DEFAULT 0, + `emailverified` int(1) NOT NULL DEFAULT 0, + `developer` int(1) NOT NULL DEFAULT 0, + `hatuploader` int(1) NOT NULL DEFAULT 0, + `charap` int(1) NOT NULL DEFAULT 0, + `inGameId` int(128) NOT NULL DEFAULT 0, + `emailverifyCode` varchar(256) DEFAULT NULL, + `emailcodeTime` timestamp NULL DEFAULT NULL, + `banreason` varchar(512) DEFAULT NULL, + `bantime` timestamp NULL DEFAULT NULL, + `username` varchar(21) DEFAULT NULL, + `email` varchar(128) DEFAULT NULL, + `gameKey` varchar(128) DEFAULT NULL, + `lastIP` varchar(128) DEFAULT NULL, + `registerIP` varchar(128) DEFAULT NULL, + `passwordChangeIP` varchar(128) DEFAULT NULL, + `passwordChangeDate` timestamp NULL DEFAULT NULL, + `about` varchar(256) DEFAULT NULL, + `authId` varchar(256) DEFAULT NULL, + `useragent` varchar(1024) DEFAULT NULL, + `authKey` varchar(1024) DEFAULT NULL, + `rank` int(1) NOT NULL DEFAULT 0, + `hideStatus` int(1) NOT NULL DEFAULT 0, + `coins` int(128) NOT NULL DEFAULT 0, + `posties` int(128) NOT NULL DEFAULT 0, + `imgTime` int(128) NOT NULL DEFAULT 0, + `passwordVersion` int(128) NOT NULL DEFAULT 1, + `imgp` int(1) NOT NULL DEFAULT 1, + `inGame` int(1) NOT NULL DEFAULT 0, + `themeChoice` int(1) NOT NULL DEFAULT 0, + `profileviews` int(1) NOT NULL DEFAULT 0, + `lastAward` timestamp NULL DEFAULT NULL, + `lastAward2` timestamp NULL DEFAULT NULL, + `joinDate` timestamp NULL DEFAULT current_timestamp(), + `lastSeen` timestamp NULL DEFAULT NULL, + `lastUpload` timestamp NULL DEFAULT NULL, + `password` varchar(128) DEFAULT NULL, + `password_salt` varchar(128) DEFAULT NULL, + `password_hash` varchar(128) DEFAULT NULL, + `2facode` varchar(128) DEFAULT NULL, + `2faInit` int(11) DEFAULT 0, + `2faEnabled` int(1) DEFAULT 0, + `2fagentime` timestamp NULL DEFAULT NULL, + `formcode` varchar(128) DEFAULT NULL, + `lastPost` timestamp NULL DEFAULT NULL, + `lastIDGen` timestamp NULL DEFAULT NULL, + `lastFR` timestamp NULL DEFAULT NULL, + `showAds` int(11) DEFAULT 0, + `posts` int(11) DEFAULT 0, + `lastForumContent` varchar(30000) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.users: ~0 rows (approximately) +/*!40000 ALTER TABLE `users` DISABLE KEYS */; +/*!40000 ALTER TABLE `users` ENABLE KEYS */; + +-- Dumping structure for table xdiscuss3.wearing +CREATE TABLE IF NOT EXISTS `wearing` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `catalogId` int(11) NOT NULL DEFAULT 0, + `uid` int(11) NOT NULL DEFAULT 0, + `aprString` varchar(128) DEFAULT NULL, + `type` varchar(128) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- Dumping data for table xdiscuss3.wearing: ~0 rows (approximately) +/*!40000 ALTER TABLE `wearing` DISABLE KEYS */; +/*!40000 ALTER TABLE `wearing` ENABLE KEYS */; + +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..9381b56 Binary files /dev/null and b/favicon.ico differ diff --git a/favicon.png b/favicon.png new file mode 100644 index 0000000..bdfd331 Binary files /dev/null and b/favicon.png differ diff --git a/html/img/background/background-main.png b/html/img/background/background-main.png new file mode 100644 index 0000000..2b28f76 Binary files /dev/null and b/html/img/background/background-main.png differ diff --git a/html/img/badges/2.png b/html/img/badges/2.png new file mode 100644 index 0000000..8a5e11d Binary files /dev/null and b/html/img/badges/2.png differ diff --git a/html/img/badges/3.png b/html/img/badges/3.png new file mode 100644 index 0000000..587d56e Binary files /dev/null and b/html/img/badges/3.png differ diff --git a/html/img/badges/4.png b/html/img/badges/4.png new file mode 100644 index 0000000..8a35d7d Binary files /dev/null and b/html/img/badges/4.png differ diff --git a/html/img/badges/5.png b/html/img/badges/5.png new file mode 100644 index 0000000..ab85756 Binary files /dev/null and b/html/img/badges/5.png differ diff --git a/html/img/badges/6.png b/html/img/badges/6.png new file mode 100644 index 0000000..c0c8f58 Binary files /dev/null and b/html/img/badges/6.png differ diff --git a/html/img/badges/7.png b/html/img/badges/7.png new file mode 100644 index 0000000..3962b76 Binary files /dev/null and b/html/img/badges/7.png differ diff --git a/html/img/badges/8.png b/html/img/badges/8.png new file mode 100644 index 0000000..0cd5974 Binary files /dev/null and b/html/img/badges/8.png differ diff --git a/html/img/emoticons/afro-1.png b/html/img/emoticons/afro-1.png new file mode 100644 index 0000000..0e41358 Binary files /dev/null and b/html/img/emoticons/afro-1.png differ diff --git a/html/img/emoticons/afro.png b/html/img/emoticons/afro.png new file mode 100644 index 0000000..ab281cb Binary files /dev/null and b/html/img/emoticons/afro.png differ diff --git a/html/img/emoticons/agent.png b/html/img/emoticons/agent.png new file mode 100644 index 0000000..be4e56c Binary files /dev/null and b/html/img/emoticons/agent.png differ diff --git a/html/img/emoticons/alien-1.png b/html/img/emoticons/alien-1.png new file mode 100644 index 0000000..e1b808b Binary files /dev/null and b/html/img/emoticons/alien-1.png differ diff --git a/html/img/emoticons/alien.png b/html/img/emoticons/alien.png new file mode 100644 index 0000000..13df463 Binary files /dev/null and b/html/img/emoticons/alien.png differ diff --git a/html/img/emoticons/angel.png b/html/img/emoticons/angel.png new file mode 100644 index 0000000..6ddd62f Binary files /dev/null and b/html/img/emoticons/angel.png differ diff --git a/html/img/emoticons/angry-1.png b/html/img/emoticons/angry-1.png new file mode 100644 index 0000000..1cfefee Binary files /dev/null and b/html/img/emoticons/angry-1.png differ diff --git a/html/img/emoticons/angry-2.png b/html/img/emoticons/angry-2.png new file mode 100644 index 0000000..e1b032d Binary files /dev/null and b/html/img/emoticons/angry-2.png differ diff --git a/html/img/emoticons/angry-3.png b/html/img/emoticons/angry-3.png new file mode 100644 index 0000000..1b332b2 Binary files /dev/null and b/html/img/emoticons/angry-3.png differ diff --git a/html/img/emoticons/angry-4.png b/html/img/emoticons/angry-4.png new file mode 100644 index 0000000..b2aed05 Binary files /dev/null and b/html/img/emoticons/angry-4.png differ diff --git a/html/img/emoticons/angry-5.png b/html/img/emoticons/angry-5.png new file mode 100644 index 0000000..fc5915b Binary files /dev/null and b/html/img/emoticons/angry-5.png differ diff --git a/html/img/emoticons/angry.png b/html/img/emoticons/angry.png new file mode 100644 index 0000000..9fd63f0 Binary files /dev/null and b/html/img/emoticons/angry.png differ diff --git a/html/img/emoticons/arguing.png b/html/img/emoticons/arguing.png new file mode 100644 index 0000000..b706679 Binary files /dev/null and b/html/img/emoticons/arguing.png differ diff --git a/html/img/emoticons/arrogant.png b/html/img/emoticons/arrogant.png new file mode 100644 index 0000000..3e8b303 Binary files /dev/null and b/html/img/emoticons/arrogant.png differ diff --git a/html/img/emoticons/asian-1.png b/html/img/emoticons/asian-1.png new file mode 100644 index 0000000..f278d79 Binary files /dev/null and b/html/img/emoticons/asian-1.png differ diff --git a/html/img/emoticons/asian.png b/html/img/emoticons/asian.png new file mode 100644 index 0000000..cb95d29 Binary files /dev/null and b/html/img/emoticons/asian.png differ diff --git a/html/img/emoticons/avatar.png b/html/img/emoticons/avatar.png new file mode 100644 index 0000000..8d70d8f Binary files /dev/null and b/html/img/emoticons/avatar.png differ diff --git a/html/img/emoticons/baby-1.png b/html/img/emoticons/baby-1.png new file mode 100644 index 0000000..cc3777d Binary files /dev/null and b/html/img/emoticons/baby-1.png differ diff --git a/html/img/emoticons/baby-2.png b/html/img/emoticons/baby-2.png new file mode 100644 index 0000000..fb3a021 Binary files /dev/null and b/html/img/emoticons/baby-2.png differ diff --git a/html/img/emoticons/baby.png b/html/img/emoticons/baby.png new file mode 100644 index 0000000..cbdf5e7 Binary files /dev/null and b/html/img/emoticons/baby.png differ diff --git a/html/img/emoticons/bully.png b/html/img/emoticons/bully.png new file mode 100644 index 0000000..1dadf78 Binary files /dev/null and b/html/img/emoticons/bully.png differ diff --git a/html/img/emoticons/burglar.png b/html/img/emoticons/burglar.png new file mode 100644 index 0000000..21dcbdb Binary files /dev/null and b/html/img/emoticons/burglar.png differ diff --git a/html/img/emoticons/businessman.png b/html/img/emoticons/businessman.png new file mode 100644 index 0000000..f8fa850 Binary files /dev/null and b/html/img/emoticons/businessman.png differ diff --git a/html/img/emoticons/cheeky-1.png b/html/img/emoticons/cheeky-1.png new file mode 100644 index 0000000..5d3e73b Binary files /dev/null and b/html/img/emoticons/cheeky-1.png differ diff --git a/html/img/emoticons/cheeky.png b/html/img/emoticons/cheeky.png new file mode 100644 index 0000000..b0f17ba Binary files /dev/null and b/html/img/emoticons/cheeky.png differ diff --git a/html/img/emoticons/clown.png b/html/img/emoticons/clown.png new file mode 100644 index 0000000..4a93ce1 Binary files /dev/null and b/html/img/emoticons/clown.png differ diff --git a/html/img/emoticons/confused-1.png b/html/img/emoticons/confused-1.png new file mode 100644 index 0000000..1d95c78 Binary files /dev/null and b/html/img/emoticons/confused-1.png differ diff --git a/html/img/emoticons/confused-2.png b/html/img/emoticons/confused-2.png new file mode 100644 index 0000000..7c4ae3a Binary files /dev/null and b/html/img/emoticons/confused-2.png differ diff --git a/html/img/emoticons/confused-3.png b/html/img/emoticons/confused-3.png new file mode 100644 index 0000000..d823de2 Binary files /dev/null and b/html/img/emoticons/confused-3.png differ diff --git a/html/img/emoticons/confused.png b/html/img/emoticons/confused.png new file mode 100644 index 0000000..01e3572 Binary files /dev/null and b/html/img/emoticons/confused.png differ diff --git a/html/img/emoticons/creepy.png b/html/img/emoticons/creepy.png new file mode 100644 index 0000000..477a8b5 Binary files /dev/null and b/html/img/emoticons/creepy.png differ diff --git a/html/img/emoticons/crying-1.png b/html/img/emoticons/crying-1.png new file mode 100644 index 0000000..47b63e5 Binary files /dev/null and b/html/img/emoticons/crying-1.png differ diff --git a/html/img/emoticons/crying-2.png b/html/img/emoticons/crying-2.png new file mode 100644 index 0000000..45175f0 Binary files /dev/null and b/html/img/emoticons/crying-2.png differ diff --git a/html/img/emoticons/crying-3.png b/html/img/emoticons/crying-3.png new file mode 100644 index 0000000..15cbcfc Binary files /dev/null and b/html/img/emoticons/crying-3.png differ diff --git a/html/img/emoticons/crying.png b/html/img/emoticons/crying.png new file mode 100644 index 0000000..f57e711 Binary files /dev/null and b/html/img/emoticons/crying.png differ diff --git a/html/img/emoticons/dazed-1.png b/html/img/emoticons/dazed-1.png new file mode 100644 index 0000000..4c9bf83 Binary files /dev/null and b/html/img/emoticons/dazed-1.png differ diff --git a/html/img/emoticons/dazed-2.png b/html/img/emoticons/dazed-2.png new file mode 100644 index 0000000..e6d2b92 Binary files /dev/null and b/html/img/emoticons/dazed-2.png differ diff --git a/html/img/emoticons/dazed-3.png b/html/img/emoticons/dazed-3.png new file mode 100644 index 0000000..f589595 Binary files /dev/null and b/html/img/emoticons/dazed-3.png differ diff --git a/html/img/emoticons/dazed.png b/html/img/emoticons/dazed.png new file mode 100644 index 0000000..1ac9e9c Binary files /dev/null and b/html/img/emoticons/dazed.png differ diff --git a/html/img/emoticons/dead-1.png b/html/img/emoticons/dead-1.png new file mode 100644 index 0000000..96ac819 Binary files /dev/null and b/html/img/emoticons/dead-1.png differ diff --git a/html/img/emoticons/dead-2.png b/html/img/emoticons/dead-2.png new file mode 100644 index 0000000..f1315d3 Binary files /dev/null and b/html/img/emoticons/dead-2.png differ diff --git a/html/img/emoticons/dead-3.png b/html/img/emoticons/dead-3.png new file mode 100644 index 0000000..b1c3e79 Binary files /dev/null and b/html/img/emoticons/dead-3.png differ diff --git a/html/img/emoticons/dead-4.png b/html/img/emoticons/dead-4.png new file mode 100644 index 0000000..51cdb97 Binary files /dev/null and b/html/img/emoticons/dead-4.png differ diff --git a/html/img/emoticons/dead-5.png b/html/img/emoticons/dead-5.png new file mode 100644 index 0000000..148cbe1 Binary files /dev/null and b/html/img/emoticons/dead-5.png differ diff --git a/html/img/emoticons/dead-6.png b/html/img/emoticons/dead-6.png new file mode 100644 index 0000000..187868f Binary files /dev/null and b/html/img/emoticons/dead-6.png differ diff --git a/html/img/emoticons/dead.png b/html/img/emoticons/dead.png new file mode 100644 index 0000000..550561e Binary files /dev/null and b/html/img/emoticons/dead.png differ diff --git a/html/img/emoticons/desperate-1.png b/html/img/emoticons/desperate-1.png new file mode 100644 index 0000000..5d01937 Binary files /dev/null and b/html/img/emoticons/desperate-1.png differ diff --git a/html/img/emoticons/desperate.png b/html/img/emoticons/desperate.png new file mode 100644 index 0000000..5511010 Binary files /dev/null and b/html/img/emoticons/desperate.png differ diff --git a/html/img/emoticons/detective.png b/html/img/emoticons/detective.png new file mode 100644 index 0000000..f14d543 Binary files /dev/null and b/html/img/emoticons/detective.png differ diff --git a/html/img/emoticons/dissapointment.png b/html/img/emoticons/dissapointment.png new file mode 100644 index 0000000..d76d9a3 Binary files /dev/null and b/html/img/emoticons/dissapointment.png differ diff --git a/html/img/emoticons/doctor.png b/html/img/emoticons/doctor.png new file mode 100644 index 0000000..451f0b1 Binary files /dev/null and b/html/img/emoticons/doctor.png differ diff --git a/html/img/emoticons/drunk.png b/html/img/emoticons/drunk.png new file mode 100644 index 0000000..d1a33de Binary files /dev/null and b/html/img/emoticons/drunk.png differ diff --git a/html/img/emoticons/dumb.png b/html/img/emoticons/dumb.png new file mode 100644 index 0000000..1e371bb Binary files /dev/null and b/html/img/emoticons/dumb.png differ diff --git a/html/img/emoticons/emo-1.png b/html/img/emoticons/emo-1.png new file mode 100644 index 0000000..d9ded01 Binary files /dev/null and b/html/img/emoticons/emo-1.png differ diff --git a/html/img/emoticons/emo-2.png b/html/img/emoticons/emo-2.png new file mode 100644 index 0000000..cd945fc Binary files /dev/null and b/html/img/emoticons/emo-2.png differ diff --git a/html/img/emoticons/emo.png b/html/img/emoticons/emo.png new file mode 100644 index 0000000..db19f71 Binary files /dev/null and b/html/img/emoticons/emo.png differ diff --git a/html/img/emoticons/emoticon.png b/html/img/emoticons/emoticon.png new file mode 100644 index 0000000..503a0a2 Binary files /dev/null and b/html/img/emoticons/emoticon.png differ diff --git a/html/img/emoticons/evil.png b/html/img/emoticons/evil.png new file mode 100644 index 0000000..cce71d8 Binary files /dev/null and b/html/img/emoticons/evil.png differ diff --git a/html/img/emoticons/faint-1.png b/html/img/emoticons/faint-1.png new file mode 100644 index 0000000..31bafc3 Binary files /dev/null and b/html/img/emoticons/faint-1.png differ diff --git a/html/img/emoticons/faint.png b/html/img/emoticons/faint.png new file mode 100644 index 0000000..66d34c6 Binary files /dev/null and b/html/img/emoticons/faint.png differ diff --git a/html/img/emoticons/flirt-1.png b/html/img/emoticons/flirt-1.png new file mode 100644 index 0000000..24f00db Binary files /dev/null and b/html/img/emoticons/flirt-1.png differ diff --git a/html/img/emoticons/flirt-2.png b/html/img/emoticons/flirt-2.png new file mode 100644 index 0000000..df863b1 Binary files /dev/null and b/html/img/emoticons/flirt-2.png differ diff --git a/html/img/emoticons/flirt.png b/html/img/emoticons/flirt.png new file mode 100644 index 0000000..42cdce1 Binary files /dev/null and b/html/img/emoticons/flirt.png differ diff --git a/html/img/emoticons/flirty.png b/html/img/emoticons/flirty.png new file mode 100644 index 0000000..30a796c Binary files /dev/null and b/html/img/emoticons/flirty.png differ diff --git a/html/img/emoticons/gangster.png b/html/img/emoticons/gangster.png new file mode 100644 index 0000000..953353a Binary files /dev/null and b/html/img/emoticons/gangster.png differ diff --git a/html/img/emoticons/geek-1.png b/html/img/emoticons/geek-1.png new file mode 100644 index 0000000..52bf1d3 Binary files /dev/null and b/html/img/emoticons/geek-1.png differ diff --git a/html/img/emoticons/geek.png b/html/img/emoticons/geek.png new file mode 100644 index 0000000..7124045 Binary files /dev/null and b/html/img/emoticons/geek.png differ diff --git a/html/img/emoticons/gentleman-1.png b/html/img/emoticons/gentleman-1.png new file mode 100644 index 0000000..43a068b Binary files /dev/null and b/html/img/emoticons/gentleman-1.png differ diff --git a/html/img/emoticons/gentleman-2.png b/html/img/emoticons/gentleman-2.png new file mode 100644 index 0000000..d385848 Binary files /dev/null and b/html/img/emoticons/gentleman-2.png differ diff --git a/html/img/emoticons/gentleman-3.png b/html/img/emoticons/gentleman-3.png new file mode 100644 index 0000000..da84b05 Binary files /dev/null and b/html/img/emoticons/gentleman-3.png differ diff --git a/html/img/emoticons/gentleman-4.png b/html/img/emoticons/gentleman-4.png new file mode 100644 index 0000000..4fa0ae8 Binary files /dev/null and b/html/img/emoticons/gentleman-4.png differ diff --git a/html/img/emoticons/gentleman.png b/html/img/emoticons/gentleman.png new file mode 100644 index 0000000..5e1302e Binary files /dev/null and b/html/img/emoticons/gentleman.png differ diff --git a/html/img/emoticons/ginger.png b/html/img/emoticons/ginger.png new file mode 100644 index 0000000..ce12831 Binary files /dev/null and b/html/img/emoticons/ginger.png differ diff --git a/html/img/emoticons/girl-1.png b/html/img/emoticons/girl-1.png new file mode 100644 index 0000000..eaaee43 Binary files /dev/null and b/html/img/emoticons/girl-1.png differ diff --git a/html/img/emoticons/girl.png b/html/img/emoticons/girl.png new file mode 100644 index 0000000..277c31a Binary files /dev/null and b/html/img/emoticons/girl.png differ diff --git a/html/img/emoticons/goofy-1.png b/html/img/emoticons/goofy-1.png new file mode 100644 index 0000000..a680b1a Binary files /dev/null and b/html/img/emoticons/goofy-1.png differ diff --git a/html/img/emoticons/goofy-2.png b/html/img/emoticons/goofy-2.png new file mode 100644 index 0000000..8bf730a Binary files /dev/null and b/html/img/emoticons/goofy-2.png differ diff --git a/html/img/emoticons/goofy-3.png b/html/img/emoticons/goofy-3.png new file mode 100644 index 0000000..594e59d Binary files /dev/null and b/html/img/emoticons/goofy-3.png differ diff --git a/html/img/emoticons/goofy-4.png b/html/img/emoticons/goofy-4.png new file mode 100644 index 0000000..4cccb95 Binary files /dev/null and b/html/img/emoticons/goofy-4.png differ diff --git a/html/img/emoticons/goofy.png b/html/img/emoticons/goofy.png new file mode 100644 index 0000000..4d2a639 Binary files /dev/null and b/html/img/emoticons/goofy.png differ diff --git a/html/img/emoticons/grubby-1.png b/html/img/emoticons/grubby-1.png new file mode 100644 index 0000000..7e4d568 Binary files /dev/null and b/html/img/emoticons/grubby-1.png differ diff --git a/html/img/emoticons/grubby.png b/html/img/emoticons/grubby.png new file mode 100644 index 0000000..1780dd2 Binary files /dev/null and b/html/img/emoticons/grubby.png differ diff --git a/html/img/emoticons/happy-1.png b/html/img/emoticons/happy-1.png new file mode 100644 index 0000000..aaff83c Binary files /dev/null and b/html/img/emoticons/happy-1.png differ diff --git a/html/img/emoticons/happy-10.png b/html/img/emoticons/happy-10.png new file mode 100644 index 0000000..c096885 Binary files /dev/null and b/html/img/emoticons/happy-10.png differ diff --git a/html/img/emoticons/happy-11.png b/html/img/emoticons/happy-11.png new file mode 100644 index 0000000..add80d0 Binary files /dev/null and b/html/img/emoticons/happy-11.png differ diff --git a/html/img/emoticons/happy-12.png b/html/img/emoticons/happy-12.png new file mode 100644 index 0000000..b2c386f Binary files /dev/null and b/html/img/emoticons/happy-12.png differ diff --git a/html/img/emoticons/happy-13.png b/html/img/emoticons/happy-13.png new file mode 100644 index 0000000..3f6699c Binary files /dev/null and b/html/img/emoticons/happy-13.png differ diff --git a/html/img/emoticons/happy-14.png b/html/img/emoticons/happy-14.png new file mode 100644 index 0000000..33dd951 Binary files /dev/null and b/html/img/emoticons/happy-14.png differ diff --git a/html/img/emoticons/happy-15.png b/html/img/emoticons/happy-15.png new file mode 100644 index 0000000..2798e4a Binary files /dev/null and b/html/img/emoticons/happy-15.png differ diff --git a/html/img/emoticons/happy-16.png b/html/img/emoticons/happy-16.png new file mode 100644 index 0000000..54f651e Binary files /dev/null and b/html/img/emoticons/happy-16.png differ diff --git a/html/img/emoticons/happy-2.png b/html/img/emoticons/happy-2.png new file mode 100644 index 0000000..f5ca485 Binary files /dev/null and b/html/img/emoticons/happy-2.png differ diff --git a/html/img/emoticons/happy-3.png b/html/img/emoticons/happy-3.png new file mode 100644 index 0000000..70d1b1e Binary files /dev/null and b/html/img/emoticons/happy-3.png differ diff --git a/html/img/emoticons/happy-4.png b/html/img/emoticons/happy-4.png new file mode 100644 index 0000000..c17b45a Binary files /dev/null and b/html/img/emoticons/happy-4.png differ diff --git a/html/img/emoticons/happy-5.png b/html/img/emoticons/happy-5.png new file mode 100644 index 0000000..2925d57 Binary files /dev/null and b/html/img/emoticons/happy-5.png differ diff --git a/html/img/emoticons/happy-6.png b/html/img/emoticons/happy-6.png new file mode 100644 index 0000000..0ccb86d Binary files /dev/null and b/html/img/emoticons/happy-6.png differ diff --git a/html/img/emoticons/happy-7.png b/html/img/emoticons/happy-7.png new file mode 100644 index 0000000..390106b Binary files /dev/null and b/html/img/emoticons/happy-7.png differ diff --git a/html/img/emoticons/happy-8.png b/html/img/emoticons/happy-8.png new file mode 100644 index 0000000..33ebd27 Binary files /dev/null and b/html/img/emoticons/happy-8.png differ diff --git a/html/img/emoticons/happy-9.png b/html/img/emoticons/happy-9.png new file mode 100644 index 0000000..8158ec5 Binary files /dev/null and b/html/img/emoticons/happy-9.png differ diff --git a/html/img/emoticons/happy.png b/html/img/emoticons/happy.png new file mode 100644 index 0000000..4d93947 Binary files /dev/null and b/html/img/emoticons/happy.png differ diff --git a/html/img/emoticons/harry-potter.png b/html/img/emoticons/harry-potter.png new file mode 100644 index 0000000..6e1eb8d Binary files /dev/null and b/html/img/emoticons/harry-potter.png differ diff --git a/html/img/emoticons/heisenberg.png b/html/img/emoticons/heisenberg.png new file mode 100644 index 0000000..d7fc8a4 Binary files /dev/null and b/html/img/emoticons/heisenberg.png differ diff --git a/html/img/emoticons/hipster-1.png b/html/img/emoticons/hipster-1.png new file mode 100644 index 0000000..5e18b02 Binary files /dev/null and b/html/img/emoticons/hipster-1.png differ diff --git a/html/img/emoticons/hipster-2.png b/html/img/emoticons/hipster-2.png new file mode 100644 index 0000000..1fd4ebe Binary files /dev/null and b/html/img/emoticons/hipster-2.png differ diff --git a/html/img/emoticons/hipster.png b/html/img/emoticons/hipster.png new file mode 100644 index 0000000..8478a92 Binary files /dev/null and b/html/img/emoticons/hipster.png differ diff --git a/html/img/emoticons/in-love-1.png b/html/img/emoticons/in-love-1.png new file mode 100644 index 0000000..5874a15 Binary files /dev/null and b/html/img/emoticons/in-love-1.png differ diff --git a/html/img/emoticons/in-love-2.png b/html/img/emoticons/in-love-2.png new file mode 100644 index 0000000..0982215 Binary files /dev/null and b/html/img/emoticons/in-love-2.png differ diff --git a/html/img/emoticons/in-love-3.png b/html/img/emoticons/in-love-3.png new file mode 100644 index 0000000..cdec924 Binary files /dev/null and b/html/img/emoticons/in-love-3.png differ diff --git a/html/img/emoticons/in-love-4.png b/html/img/emoticons/in-love-4.png new file mode 100644 index 0000000..2fec6af Binary files /dev/null and b/html/img/emoticons/in-love-4.png differ diff --git a/html/img/emoticons/in-love-5.png b/html/img/emoticons/in-love-5.png new file mode 100644 index 0000000..19a53e7 Binary files /dev/null and b/html/img/emoticons/in-love-5.png differ diff --git a/html/img/emoticons/in-love-6.png b/html/img/emoticons/in-love-6.png new file mode 100644 index 0000000..771e1a1 Binary files /dev/null and b/html/img/emoticons/in-love-6.png differ diff --git a/html/img/emoticons/in-love.png b/html/img/emoticons/in-love.png new file mode 100644 index 0000000..7b7b0b3 Binary files /dev/null and b/html/img/emoticons/in-love.png differ diff --git a/html/img/emoticons/japan.png b/html/img/emoticons/japan.png new file mode 100644 index 0000000..f8c8b30 Binary files /dev/null and b/html/img/emoticons/japan.png differ diff --git a/html/img/emoticons/jew.png b/html/img/emoticons/jew.png new file mode 100644 index 0000000..79963a3 Binary files /dev/null and b/html/img/emoticons/jew.png differ diff --git a/html/img/emoticons/joyful-1.png b/html/img/emoticons/joyful-1.png new file mode 100644 index 0000000..c86ff3b Binary files /dev/null and b/html/img/emoticons/joyful-1.png differ diff --git a/html/img/emoticons/joyful-2.png b/html/img/emoticons/joyful-2.png new file mode 100644 index 0000000..ae72f02 Binary files /dev/null and b/html/img/emoticons/joyful-2.png differ diff --git a/html/img/emoticons/joyful.png b/html/img/emoticons/joyful.png new file mode 100644 index 0000000..e543251 Binary files /dev/null and b/html/img/emoticons/joyful.png differ diff --git a/html/img/emoticons/kiss-1.png b/html/img/emoticons/kiss-1.png new file mode 100644 index 0000000..5007b92 Binary files /dev/null and b/html/img/emoticons/kiss-1.png differ diff --git a/html/img/emoticons/kiss-2.png b/html/img/emoticons/kiss-2.png new file mode 100644 index 0000000..d024bd1 Binary files /dev/null and b/html/img/emoticons/kiss-2.png differ diff --git a/html/img/emoticons/kiss-3.png b/html/img/emoticons/kiss-3.png new file mode 100644 index 0000000..95ef8c1 Binary files /dev/null and b/html/img/emoticons/kiss-3.png differ diff --git a/html/img/emoticons/kiss-4.png b/html/img/emoticons/kiss-4.png new file mode 100644 index 0000000..82e65c9 Binary files /dev/null and b/html/img/emoticons/kiss-4.png differ diff --git a/html/img/emoticons/kiss.png b/html/img/emoticons/kiss.png new file mode 100644 index 0000000..02b7455 Binary files /dev/null and b/html/img/emoticons/kiss.png differ diff --git a/html/img/emoticons/laughing-1.png b/html/img/emoticons/laughing-1.png new file mode 100644 index 0000000..65fb9ac Binary files /dev/null and b/html/img/emoticons/laughing-1.png differ diff --git a/html/img/emoticons/laughing-2.png b/html/img/emoticons/laughing-2.png new file mode 100644 index 0000000..d9babcf Binary files /dev/null and b/html/img/emoticons/laughing-2.png differ diff --git a/html/img/emoticons/laughing-3.png b/html/img/emoticons/laughing-3.png new file mode 100644 index 0000000..441c478 Binary files /dev/null and b/html/img/emoticons/laughing-3.png differ diff --git a/html/img/emoticons/laughing.png b/html/img/emoticons/laughing.png new file mode 100644 index 0000000..5dec7c1 Binary files /dev/null and b/html/img/emoticons/laughing.png differ diff --git a/html/img/emoticons/listening.png b/html/img/emoticons/listening.png new file mode 100644 index 0000000..12b8b48 Binary files /dev/null and b/html/img/emoticons/listening.png differ diff --git a/html/img/emoticons/love.png b/html/img/emoticons/love.png new file mode 100644 index 0000000..e2078eb Binary files /dev/null and b/html/img/emoticons/love.png differ diff --git a/html/img/emoticons/manly.png b/html/img/emoticons/manly.png new file mode 100644 index 0000000..15102dc Binary files /dev/null and b/html/img/emoticons/manly.png differ diff --git a/html/img/emoticons/miserly-1.png b/html/img/emoticons/miserly-1.png new file mode 100644 index 0000000..78783cb Binary files /dev/null and b/html/img/emoticons/miserly-1.png differ diff --git a/html/img/emoticons/miserly.png b/html/img/emoticons/miserly.png new file mode 100644 index 0000000..41c6871 Binary files /dev/null and b/html/img/emoticons/miserly.png differ diff --git a/html/img/emoticons/nerd-1.png b/html/img/emoticons/nerd-1.png new file mode 100644 index 0000000..eb850eb Binary files /dev/null and b/html/img/emoticons/nerd-1.png differ diff --git a/html/img/emoticons/nerd-2.png b/html/img/emoticons/nerd-2.png new file mode 100644 index 0000000..1ed02aa Binary files /dev/null and b/html/img/emoticons/nerd-2.png differ diff --git a/html/img/emoticons/nerd-3.png b/html/img/emoticons/nerd-3.png new file mode 100644 index 0000000..ebf9f12 Binary files /dev/null and b/html/img/emoticons/nerd-3.png differ diff --git a/html/img/emoticons/nerd-4.png b/html/img/emoticons/nerd-4.png new file mode 100644 index 0000000..fc18093 Binary files /dev/null and b/html/img/emoticons/nerd-4.png differ diff --git a/html/img/emoticons/nerd.png b/html/img/emoticons/nerd.png new file mode 100644 index 0000000..bee5b1f Binary files /dev/null and b/html/img/emoticons/nerd.png differ diff --git a/html/img/emoticons/ninja.png b/html/img/emoticons/ninja.png new file mode 100644 index 0000000..1380f53 Binary files /dev/null and b/html/img/emoticons/ninja.png differ diff --git a/html/img/emoticons/pirate-1.png b/html/img/emoticons/pirate-1.png new file mode 100644 index 0000000..db0f469 Binary files /dev/null and b/html/img/emoticons/pirate-1.png differ diff --git a/html/img/emoticons/pirate-2.png b/html/img/emoticons/pirate-2.png new file mode 100644 index 0000000..2f5d5cf Binary files /dev/null and b/html/img/emoticons/pirate-2.png differ diff --git a/html/img/emoticons/pirate.png b/html/img/emoticons/pirate.png new file mode 100644 index 0000000..9b5cc2c Binary files /dev/null and b/html/img/emoticons/pirate.png differ diff --git a/html/img/emoticons/punk-1.png b/html/img/emoticons/punk-1.png new file mode 100644 index 0000000..5e590db Binary files /dev/null and b/html/img/emoticons/punk-1.png differ diff --git a/html/img/emoticons/punk-2.png b/html/img/emoticons/punk-2.png new file mode 100644 index 0000000..81dcbd9 Binary files /dev/null and b/html/img/emoticons/punk-2.png differ diff --git a/html/img/emoticons/punk.png b/html/img/emoticons/punk.png new file mode 100644 index 0000000..0df310b Binary files /dev/null and b/html/img/emoticons/punk.png differ diff --git a/html/img/emoticons/rapper.png b/html/img/emoticons/rapper.png new file mode 100644 index 0000000..5f3af8b Binary files /dev/null and b/html/img/emoticons/rapper.png differ diff --git a/html/img/emoticons/relieved.png b/html/img/emoticons/relieved.png new file mode 100644 index 0000000..ff9359d Binary files /dev/null and b/html/img/emoticons/relieved.png differ diff --git a/html/img/emoticons/rich-1.png b/html/img/emoticons/rich-1.png new file mode 100644 index 0000000..1aa872c Binary files /dev/null and b/html/img/emoticons/rich-1.png differ diff --git a/html/img/emoticons/rich-2.png b/html/img/emoticons/rich-2.png new file mode 100644 index 0000000..fad3462 Binary files /dev/null and b/html/img/emoticons/rich-2.png differ diff --git a/html/img/emoticons/rich.png b/html/img/emoticons/rich.png new file mode 100644 index 0000000..48e78df Binary files /dev/null and b/html/img/emoticons/rich.png differ diff --git a/html/img/emoticons/rockstar.png b/html/img/emoticons/rockstar.png new file mode 100644 index 0000000..1976989 Binary files /dev/null and b/html/img/emoticons/rockstar.png differ diff --git a/html/img/emoticons/sad-1.png b/html/img/emoticons/sad-1.png new file mode 100644 index 0000000..4c45781 Binary files /dev/null and b/html/img/emoticons/sad-1.png differ diff --git a/html/img/emoticons/sad-2.png b/html/img/emoticons/sad-2.png new file mode 100644 index 0000000..997c19b Binary files /dev/null and b/html/img/emoticons/sad-2.png differ diff --git a/html/img/emoticons/sad-3.png b/html/img/emoticons/sad-3.png new file mode 100644 index 0000000..55bb651 Binary files /dev/null and b/html/img/emoticons/sad-3.png differ diff --git a/html/img/emoticons/sad-4.png b/html/img/emoticons/sad-4.png new file mode 100644 index 0000000..5e455a4 Binary files /dev/null and b/html/img/emoticons/sad-4.png differ diff --git a/html/img/emoticons/sad-5.png b/html/img/emoticons/sad-5.png new file mode 100644 index 0000000..7fcfd6e Binary files /dev/null and b/html/img/emoticons/sad-5.png differ diff --git a/html/img/emoticons/sad-6.png b/html/img/emoticons/sad-6.png new file mode 100644 index 0000000..bc4a357 Binary files /dev/null and b/html/img/emoticons/sad-6.png differ diff --git a/html/img/emoticons/sad.png b/html/img/emoticons/sad.png new file mode 100644 index 0000000..07450ea Binary files /dev/null and b/html/img/emoticons/sad.png differ diff --git a/html/img/emoticons/scared-1.png b/html/img/emoticons/scared-1.png new file mode 100644 index 0000000..b763075 Binary files /dev/null and b/html/img/emoticons/scared-1.png differ diff --git a/html/img/emoticons/scared-2.png b/html/img/emoticons/scared-2.png new file mode 100644 index 0000000..a02c0c1 Binary files /dev/null and b/html/img/emoticons/scared-2.png differ diff --git a/html/img/emoticons/scared-3.png b/html/img/emoticons/scared-3.png new file mode 100644 index 0000000..e0794b7 Binary files /dev/null and b/html/img/emoticons/scared-3.png differ diff --git a/html/img/emoticons/scared.png b/html/img/emoticons/scared.png new file mode 100644 index 0000000..07f9abb Binary files /dev/null and b/html/img/emoticons/scared.png differ diff --git a/html/img/emoticons/sceptic-1.png b/html/img/emoticons/sceptic-1.png new file mode 100644 index 0000000..2c1712b Binary files /dev/null and b/html/img/emoticons/sceptic-1.png differ diff --git a/html/img/emoticons/sceptic-2.png b/html/img/emoticons/sceptic-2.png new file mode 100644 index 0000000..900af62 Binary files /dev/null and b/html/img/emoticons/sceptic-2.png differ diff --git a/html/img/emoticons/sceptic-3.png b/html/img/emoticons/sceptic-3.png new file mode 100644 index 0000000..4c63234 Binary files /dev/null and b/html/img/emoticons/sceptic-3.png differ diff --git a/html/img/emoticons/sceptic-4.png b/html/img/emoticons/sceptic-4.png new file mode 100644 index 0000000..c2b0290 Binary files /dev/null and b/html/img/emoticons/sceptic-4.png differ diff --git a/html/img/emoticons/sceptic-5.png b/html/img/emoticons/sceptic-5.png new file mode 100644 index 0000000..a834932 Binary files /dev/null and b/html/img/emoticons/sceptic-5.png differ diff --git a/html/img/emoticons/sceptic-6.png b/html/img/emoticons/sceptic-6.png new file mode 100644 index 0000000..f721502 Binary files /dev/null and b/html/img/emoticons/sceptic-6.png differ diff --git a/html/img/emoticons/sceptic-7.png b/html/img/emoticons/sceptic-7.png new file mode 100644 index 0000000..eb16766 Binary files /dev/null and b/html/img/emoticons/sceptic-7.png differ diff --git a/html/img/emoticons/sceptic.png b/html/img/emoticons/sceptic.png new file mode 100644 index 0000000..29dbf39 Binary files /dev/null and b/html/img/emoticons/sceptic.png differ diff --git a/html/img/emoticons/secret.png b/html/img/emoticons/secret.png new file mode 100644 index 0000000..4d8af27 Binary files /dev/null and b/html/img/emoticons/secret.png differ diff --git a/html/img/emoticons/shocked-1.png b/html/img/emoticons/shocked-1.png new file mode 100644 index 0000000..bcef6b3 Binary files /dev/null and b/html/img/emoticons/shocked-1.png differ diff --git a/html/img/emoticons/shocked-2.png b/html/img/emoticons/shocked-2.png new file mode 100644 index 0000000..92da83f Binary files /dev/null and b/html/img/emoticons/shocked-2.png differ diff --git a/html/img/emoticons/shocked-3.png b/html/img/emoticons/shocked-3.png new file mode 100644 index 0000000..76d157e Binary files /dev/null and b/html/img/emoticons/shocked-3.png differ diff --git a/html/img/emoticons/shocked.png b/html/img/emoticons/shocked.png new file mode 100644 index 0000000..3a5b38a Binary files /dev/null and b/html/img/emoticons/shocked.png differ diff --git a/html/img/emoticons/sick-1.png b/html/img/emoticons/sick-1.png new file mode 100644 index 0000000..0546c96 Binary files /dev/null and b/html/img/emoticons/sick-1.png differ diff --git a/html/img/emoticons/sick-2.png b/html/img/emoticons/sick-2.png new file mode 100644 index 0000000..e7cbfeb Binary files /dev/null and b/html/img/emoticons/sick-2.png differ diff --git a/html/img/emoticons/sick-3.png b/html/img/emoticons/sick-3.png new file mode 100644 index 0000000..888f0aa Binary files /dev/null and b/html/img/emoticons/sick-3.png differ diff --git a/html/img/emoticons/sick-4.png b/html/img/emoticons/sick-4.png new file mode 100644 index 0000000..bf11b6c Binary files /dev/null and b/html/img/emoticons/sick-4.png differ diff --git a/html/img/emoticons/sick.png b/html/img/emoticons/sick.png new file mode 100644 index 0000000..77c9b7f Binary files /dev/null and b/html/img/emoticons/sick.png differ diff --git a/html/img/emoticons/silent.png b/html/img/emoticons/silent.png new file mode 100644 index 0000000..0355f2f Binary files /dev/null and b/html/img/emoticons/silent.png differ diff --git a/html/img/emoticons/skeleton.png b/html/img/emoticons/skeleton.png new file mode 100644 index 0000000..3b69b24 Binary files /dev/null and b/html/img/emoticons/skeleton.png differ diff --git a/html/img/emoticons/smile.png b/html/img/emoticons/smile.png new file mode 100644 index 0000000..9316c35 Binary files /dev/null and b/html/img/emoticons/smile.png differ diff --git a/html/img/emoticons/smiling-1.png b/html/img/emoticons/smiling-1.png new file mode 100644 index 0000000..ee20b43 Binary files /dev/null and b/html/img/emoticons/smiling-1.png differ diff --git a/html/img/emoticons/smiling.png b/html/img/emoticons/smiling.png new file mode 100644 index 0000000..3e4b545 Binary files /dev/null and b/html/img/emoticons/smiling.png differ diff --git a/html/img/emoticons/smoked.png b/html/img/emoticons/smoked.png new file mode 100644 index 0000000..ffc2b7c Binary files /dev/null and b/html/img/emoticons/smoked.png differ diff --git a/html/img/emoticons/smug-1.png b/html/img/emoticons/smug-1.png new file mode 100644 index 0000000..06b2726 Binary files /dev/null and b/html/img/emoticons/smug-1.png differ diff --git a/html/img/emoticons/smug-2.png b/html/img/emoticons/smug-2.png new file mode 100644 index 0000000..f31cd92 Binary files /dev/null and b/html/img/emoticons/smug-2.png differ diff --git a/html/img/emoticons/smug-3.png b/html/img/emoticons/smug-3.png new file mode 100644 index 0000000..8029499 Binary files /dev/null and b/html/img/emoticons/smug-3.png differ diff --git a/html/img/emoticons/smug-4.png b/html/img/emoticons/smug-4.png new file mode 100644 index 0000000..12230da Binary files /dev/null and b/html/img/emoticons/smug-4.png differ diff --git a/html/img/emoticons/smug-5.png b/html/img/emoticons/smug-5.png new file mode 100644 index 0000000..ac9451b Binary files /dev/null and b/html/img/emoticons/smug-5.png differ diff --git a/html/img/emoticons/smug-6.png b/html/img/emoticons/smug-6.png new file mode 100644 index 0000000..0622196 Binary files /dev/null and b/html/img/emoticons/smug-6.png differ diff --git a/html/img/emoticons/smug.png b/html/img/emoticons/smug.png new file mode 100644 index 0000000..9781ba4 Binary files /dev/null and b/html/img/emoticons/smug.png differ diff --git a/html/img/emoticons/sporty.png b/html/img/emoticons/sporty.png new file mode 100644 index 0000000..8d8eff5 Binary files /dev/null and b/html/img/emoticons/sporty.png differ diff --git a/html/img/emoticons/stunned.png b/html/img/emoticons/stunned.png new file mode 100644 index 0000000..d8c17dc Binary files /dev/null and b/html/img/emoticons/stunned.png differ diff --git a/html/img/emoticons/superhero-1.png b/html/img/emoticons/superhero-1.png new file mode 100644 index 0000000..63d0250 Binary files /dev/null and b/html/img/emoticons/superhero-1.png differ diff --git a/html/img/emoticons/superhero-2.png b/html/img/emoticons/superhero-2.png new file mode 100644 index 0000000..756e7dc Binary files /dev/null and b/html/img/emoticons/superhero-2.png differ diff --git a/html/img/emoticons/superhero-3.png b/html/img/emoticons/superhero-3.png new file mode 100644 index 0000000..1efcf64 Binary files /dev/null and b/html/img/emoticons/superhero-3.png differ diff --git a/html/img/emoticons/superhero-4.png b/html/img/emoticons/superhero-4.png new file mode 100644 index 0000000..4f8975b Binary files /dev/null and b/html/img/emoticons/superhero-4.png differ diff --git a/html/img/emoticons/superhero.png b/html/img/emoticons/superhero.png new file mode 100644 index 0000000..0fc1bc2 Binary files /dev/null and b/html/img/emoticons/superhero.png differ diff --git a/html/img/emoticons/surprised-1.png b/html/img/emoticons/surprised-1.png new file mode 100644 index 0000000..5b7cf8f Binary files /dev/null and b/html/img/emoticons/surprised-1.png differ diff --git a/html/img/emoticons/surprised.png b/html/img/emoticons/surprised.png new file mode 100644 index 0000000..e55a30f Binary files /dev/null and b/html/img/emoticons/surprised.png differ diff --git a/html/img/emoticons/thinking.png b/html/img/emoticons/thinking.png new file mode 100644 index 0000000..8dbedc1 Binary files /dev/null and b/html/img/emoticons/thinking.png differ diff --git a/html/img/emoticons/tired-1.png b/html/img/emoticons/tired-1.png new file mode 100644 index 0000000..cd74791 Binary files /dev/null and b/html/img/emoticons/tired-1.png differ diff --git a/html/img/emoticons/tired-2.png b/html/img/emoticons/tired-2.png new file mode 100644 index 0000000..cf10865 Binary files /dev/null and b/html/img/emoticons/tired-2.png differ diff --git a/html/img/emoticons/tired-3.png b/html/img/emoticons/tired-3.png new file mode 100644 index 0000000..975e802 Binary files /dev/null and b/html/img/emoticons/tired-3.png differ diff --git a/html/img/emoticons/tired.png b/html/img/emoticons/tired.png new file mode 100644 index 0000000..6073a88 Binary files /dev/null and b/html/img/emoticons/tired.png differ diff --git a/html/img/emoticons/tough-1.png b/html/img/emoticons/tough-1.png new file mode 100644 index 0000000..c049b5e Binary files /dev/null and b/html/img/emoticons/tough-1.png differ diff --git a/html/img/emoticons/tough.png b/html/img/emoticons/tough.png new file mode 100644 index 0000000..0a2a574 Binary files /dev/null and b/html/img/emoticons/tough.png differ diff --git a/html/img/emoticons/trendy.png b/html/img/emoticons/trendy.png new file mode 100644 index 0000000..93b1173 Binary files /dev/null and b/html/img/emoticons/trendy.png differ diff --git a/html/img/emoticons/vampire-1.png b/html/img/emoticons/vampire-1.png new file mode 100644 index 0000000..279b12b Binary files /dev/null and b/html/img/emoticons/vampire-1.png differ diff --git a/html/img/emoticons/vampire.png b/html/img/emoticons/vampire.png new file mode 100644 index 0000000..c3c8b8a Binary files /dev/null and b/html/img/emoticons/vampire.png differ diff --git a/html/img/emoticons/wink-1.png b/html/img/emoticons/wink-1.png new file mode 100644 index 0000000..a8932c8 Binary files /dev/null and b/html/img/emoticons/wink-1.png differ diff --git a/html/img/emoticons/wink-2.png b/html/img/emoticons/wink-2.png new file mode 100644 index 0000000..5009f83 Binary files /dev/null and b/html/img/emoticons/wink-2.png differ diff --git a/html/img/emoticons/wink.png b/html/img/emoticons/wink.png new file mode 100644 index 0000000..538b75d Binary files /dev/null and b/html/img/emoticons/wink.png differ diff --git a/html/img/emoticons/winking-1.png b/html/img/emoticons/winking-1.png new file mode 100644 index 0000000..dabdaa0 Binary files /dev/null and b/html/img/emoticons/winking-1.png differ diff --git a/html/img/emoticons/winking.png b/html/img/emoticons/winking.png new file mode 100644 index 0000000..d1c0f6d Binary files /dev/null and b/html/img/emoticons/winking.png differ diff --git a/html/img/emoticons/yawning-1.png b/html/img/emoticons/yawning-1.png new file mode 100644 index 0000000..a3e729f Binary files /dev/null and b/html/img/emoticons/yawning-1.png differ diff --git a/html/img/emoticons/yawning-2.png b/html/img/emoticons/yawning-2.png new file mode 100644 index 0000000..acb73ea Binary files /dev/null and b/html/img/emoticons/yawning-2.png differ diff --git a/html/img/emoticons/yawning-3.png b/html/img/emoticons/yawning-3.png new file mode 100644 index 0000000..2d391d8 Binary files /dev/null and b/html/img/emoticons/yawning-3.png differ diff --git a/html/img/emoticons/yawning.png b/html/img/emoticons/yawning.png new file mode 100644 index 0000000..bbd7e71 Binary files /dev/null and b/html/img/emoticons/yawning.png differ diff --git a/html/img/emoticons/yelling.png b/html/img/emoticons/yelling.png new file mode 100644 index 0000000..25096f7 Binary files /dev/null and b/html/img/emoticons/yelling.png differ diff --git a/html/img/emoticons/zombie.png b/html/img/emoticons/zombie.png new file mode 100644 index 0000000..262d336 Binary files /dev/null and b/html/img/emoticons/zombie.png differ diff --git a/html/img/places/baseplate.png b/html/img/places/baseplate.png new file mode 100644 index 0000000..1f6c7b9 Binary files /dev/null and b/html/img/places/baseplate.png differ diff --git a/index.php b/index.php new file mode 100644 index 0000000..629162d --- /dev/null +++ b/index.php @@ -0,0 +1,62 @@ + + + + + <?php echo config::getName();?> + + + + + + + + +
    +
    +
    +

    Welcome to !

    +

    Forum, chat and play games with other players and make friends

    +

    Customize your character with items found in our catalog

    +
    +
    + +

    Create an account

    +

    If you are new to , you can sign up by filling in the form below

    +
    + + + + +
    + +
    +
    +
    + + +