1
0
mirror of https://github.com/Daichimarukana/uwuzu.git synced 2026-06-05 03:24:41 +00:00

uwuzu v1.4.6 Funium

This commit is contained in:
Daichimarukana
2024-11-06 22:21:58 +09:00
parent 88c38b99d9
commit 84984e7043
28 changed files with 226 additions and 255 deletions
+1 -1
View File
@@ -124,7 +124,7 @@ if( !empty($_POST['btn_submit']) ) {
if ($checkResult) { if ($checkResult) {
if( empty($error_message) ) { if( empty($error_message) ) {
$backupcode = random(); $backupcode = random();
$hashbackupcode = password_hash($backupcode, PASSWORD_DEFAULT); $hashbackupcode = uwuzu_password_hash($backupcode);
$secret = $_SESSION['secretcode']; $secret = $_SESSION['secretcode'];
if(!(empty($userData["encryption_ivkey"]))){ if(!(empty($userData["encryption_ivkey"]))){
+3 -1
View File
@@ -318,7 +318,9 @@ if( !empty($_POST['btn_submit']) ) {
$role = "official"; $role = "official";
$admin = "yes"; $admin = "yes";
$hashpassword = password_hash($password, PASSWORD_DEFAULT);
$hashpassword = uwuzu_password_hash($password);
$LoginIdBytes = random_bytes(64); $LoginIdBytes = random_bytes(64);
$loginid = hash('sha3-512', $LoginIdBytes); $loginid = hash('sha3-512', $LoginIdBytes);
+1 -1
View File
@@ -135,7 +135,7 @@ if( !empty($_POST['btn_submit']) ) {
$backuplogin = false; $backuplogin = false;
} }
if($backuplogin === true || password_verify($userbackupcode,$row["backupcode"])){ if($backuplogin === true || uwuzu_password_verify($userbackupcode,$row["backupcode"])){
$pdo->beginTransaction(); $pdo->beginTransaction();
try { try {
+2 -2
View File
@@ -4533,7 +4533,7 @@ hr{
.hny .textmain{ .hny .textmain{
background-color: #F5F5F5; background-color: #F5F5F5;
padding-top: 8px; padding-top: 8px;
padding-bottom: 8px; padding-bottom: 24px;
padding-left: 24px; padding-left: 24px;
padding-right: 24px; padding-right: 24px;
} }
@@ -6929,7 +6929,7 @@ noscript .noscript_modal .inner .center_text p{
.hny .textmain{ .hny .textmain{
background-color: #f5f4f0; background-color: #f5f4f0;
padding-top: 8px; padding-top: 8px;
padding-bottom: 8px; padding-bottom: 24px;
padding-left: 24px; padding-left: 24px;
padding-right: 24px; padding-right: 24px;
} }
+103 -52
View File
@@ -281,63 +281,70 @@ function replaceProfileEmojiImages($postText) {
return $postTextWithImages; return $postTextWithImages;
} }
// ユーズ内の絵文字やhashtagを画像に置き換える // ユーズ内の絵文字やhashtagを画像に置き換える
function replaceEmojisWithImages($postText) { function replaceEmojisWithImages($postText) {
$postText = str_replace(''', '\'', $postText); $postText = str_replace(''', '\'', $postText);
// ユーズ内で絵文字名(:emoji:)を検出して画像に置き換える
$emojiPattern = '/:(\w+):/';
$postTextWithImages = preg_replace_callback($emojiPattern, function($matches) {
$emojiName = $matches[1];
//絵文字path取得
$dbh = new PDO('mysql:charset=utf8mb4;dbname='.DB_NAME.';host='.DB_HOST, DB_USER, DB_PASS, array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
));
$emoji_Query = $dbh->prepare("SELECT emojifile, emojiname FROM emoji WHERE emojiname = :emojiname");
$emoji_Query->bindValue(':emojiname', $emojiName);
$emoji_Query->execute();
$emoji_row = $emoji_Query->fetch();
if(empty($emoji_row["emojifile"])){
$emoji_path = "img/sysimage/errorimage/emoji_404.png";
return ":".$emojiName.":";
}else{
$emoji_path = $emoji_row["emojifile"];
return "<img src='../".$emoji_path."' alt=':$emojiName:' title=':$emojiName:'>";
}
}, $postText);
// @username を検出してリンクに置き換える
$usernamePattern = '/@(\w+)/';
$postTextWithImagesAndUsernames = preg_replace_callback($usernamePattern, function($matches) {
$username = $matches[1];
$dbh = new PDO('mysql:charset=utf8mb4;dbname='.DB_NAME.';host='.DB_HOST, DB_USER, DB_PASS, array( $emojiPattern = '/:(\w+):/';
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, $postTextWithImages = preg_replace_callback($emojiPattern, function($matches) {
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, $emojiName = $matches[1];
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, $dbh = new PDO('mysql:charset=utf8mb4;dbname='.DB_NAME.';host='.DB_HOST, DB_USER, DB_PASS, array(
)); PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
$mentionsuserQuery = $dbh->prepare("SELECT username, userid FROM account WHERE userid = :userid"); PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
$mentionsuserQuery->bindValue(':userid', $username); ));
$mentionsuserQuery->execute(); $emoji_Query = $dbh->prepare("SELECT emojifile, emojiname FROM emoji WHERE emojiname = :emojiname");
$mentionsuserData = $mentionsuserQuery->fetch(); $emoji_Query->bindValue(':emojiname', $emojiName);
$emoji_Query->execute();
if(empty($mentionsuserData)){ $emoji_row = $emoji_Query->fetch();
return "@$username"; if(empty($emoji_row["emojifile"])){
}else{ $emoji_path = "img/sysimage/errorimage/emoji_404.png";
return "<a class = 'mta' href='/@".htmlentities($mentionsuserData["userid"], ENT_QUOTES, 'UTF-8', false)."'>@".replaceProfileEmojiImages(htmlentities($mentionsuserData["username"], ENT_QUOTES, 'UTF-8', false))."</a>"; return ":".$emojiName.":";
} }else{
$emoji_path = $emoji_row["emojifile"];
return "<img src='../".$emoji_path."' alt=':$emojiName:' title=':$emojiName:'>";
}
}, $postText);
$urlPattern = '/https?:\/\/[^\s]+/';
$urlPlaceholders = [];
$postTextWithPlaceholders = preg_replace_callback($urlPattern, function($matches) use (&$urlPlaceholders) {
$placeholder = 'URL_PLACEHOLDER_' . count($urlPlaceholders);
$urlPlaceholders[$placeholder] = $matches[0];
return $placeholder;
}, $postTextWithImages); }, $postTextWithImages);
$hashtagsPattern = '/#([\p{Han}\p{Hiragana}\p{Katakana}A-Za-z0-9ー_!]+)/u'; $usernamePattern = '/@(\w+)/';
$postTextWithHashtags = preg_replace_callback($hashtagsPattern, function($matches) { $postTextWithUsernames = preg_replace_callback($usernamePattern, function($matches) {
$hashtags = $matches[1]; $username = $matches[1];
return "<a class='hashtags' href='/search?q=" . urlencode('#' . $hashtags) . "'>" . '#' . $hashtags . "</a>";
}, $postTextWithImagesAndUsernames); $dbh = new PDO('mysql:charset=utf8mb4;dbname='.DB_NAME.';host='.DB_HOST, DB_USER, DB_PASS, array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
));
$mentionsuserQuery = $dbh->prepare("SELECT username, userid FROM account WHERE userid = :userid");
$mentionsuserQuery->bindValue(':userid', $username);
$mentionsuserQuery->execute();
$mentionsuserData = $mentionsuserQuery->fetch();
if(empty($mentionsuserData)){
return "@".$username."";
}else{
return "<a class='mta' href='/@".htmlentities($mentionsuserData["userid"], ENT_QUOTES, 'UTF-8', false)."'>@".replaceProfileEmojiImages(htmlentities($mentionsuserData["username"], ENT_QUOTES, 'UTF-8', false))."</a>";
}
}, $postTextWithPlaceholders);
$postTextWithUrlsRestored = str_replace(array_keys($urlPlaceholders), array_values($urlPlaceholders), $postTextWithUsernames);
$hashtagsPattern = '/#([\p{Han}\p{Hiragana}\p{Katakana}A-Za-z0-9ー_!]+)/u';
$postTextWithHashtags = preg_replace_callback($hashtagsPattern, function($matches) {
$hashtags = $matches[1];
return "<a class='hashtags' href='/search?q=" . urlencode('#' . $hashtags) . "'>" . '#' . $hashtags . "</a>";
}, $postTextWithUrlsRestored);
return $postTextWithHashtags; return $postTextWithHashtags;
} }
function replaceURLsWithLinks($postText, $maxLength = 48) { function replaceURLsWithLinks($postText, $maxLength = 48) {
$pattern = '/(https:\/\/[\w!?\/+\-_~;.,*&@#$%()+|https:\/\/[ぁ-んァ-ヶ一-龠々\w\-\/?=&%.]+)/'; $pattern = '/(https:\/\/[\w!?\/+\-_~;.,*&@#$%()+|https:\/\/[ぁ-んァ-ヶ一-龠々\w\-\/?=&%.]+)/';
$convertedText = preg_replace_callback($pattern, function($matches) use ($maxLength) { $convertedText = preg_replace_callback($pattern, function($matches) use ($maxLength) {
@@ -1283,7 +1290,7 @@ function deleteDirectory($dir) {
return rmdir($dir); return rmdir($dir);
} }
// ユーザーデータの暗号化関連
function GenUserEnckey($datetime){ function GenUserEnckey($datetime){
$dateBaseKey = hash('sha3-512', $datetime); $dateBaseKey = hash('sha3-512', $datetime);
$complexEncKey = hash('sha3-512', ENC_KEY . $dateBaseKey); $complexEncKey = hash('sha3-512', ENC_KEY . $dateBaseKey);
@@ -1295,4 +1302,48 @@ function EncryptionUseEncrKey($data,$key,$iv){
function DecryptionUseEncrKey($data,$key,$iv){ function DecryptionUseEncrKey($data,$key,$iv){
return openssl_decrypt($data, "aes-256-cbc", $key, 0, $iv); return openssl_decrypt($data, "aes-256-cbc", $key, 0, $iv);
} }
// パスワードのArgon2&bcrypt対応認証
function uwuzu_password_hash($password){
if (in_array("argon2id", password_algos())) {
$hashpassword = password_hash($password, PASSWORD_ARGON2ID);
}else{
if(strlen($password) > 72){
$onehash = hash('sha3-256', $password);
$hashpassword = password_hash($onehash, PASSWORD_BCRYPT);
}else{
$hashpassword = password_hash($password, PASSWORD_BCRYPT);
}
}
return $hashpassword;
}
function uwuzu_password_verify($password, $hash){
if (in_array("argon2id", password_algos())) {
if(password_verify($password, $hash)){
return true;
}else{
return false;
}
}else{
if(strlen($password) > 72){
$shapass = hash('sha3-256', $password);
if(password_verify($shapass, $hash)){
return true;
}else{
$pass72 = substr($password, 0, 72);
if(password_verify($pass72, $hash)){
return true;
}else{
return false;
}
}
}else{
if(password_verify($password, $hash)){
return true;
}else{
return false;
}
}
}
}
?> ?>
+7 -5
View File
@@ -1,7 +1,9 @@
/*-----Console Notice-----*/ /*-----Console Notice-----*/
const sesstoken_reset_url = location.protocol+"//"+location.hostname+"/others/";
console.log( console.log(
"%c警告!!!%c\nもし誰かにここに%cコピペ%cしろと言われたりCookieというものをコピーしろなどと言われているのであればその行為は%c今すぐやめて%cください。", "%c警告!!!%c\n\nもし誰かにここに%cコピペ%cしろと言われたりCookieというものをコピーしろなどと言われているのであればその行為は%c今すぐやめて%cください。",
"color:white; background-color:#FF4848; padding:4px; border-radius:4px; font-weight: bold; font-size: 16pt", "color:white; background-color:#FF4848; padding:4px; border-radius:4px; font-weight: bold; font-size: 24pt",
"", "",
"color:#FF4848; font-size: 16pt; font-weight: bold;", "color:#FF4848; font-size: 16pt; font-weight: bold;",
"", "",
@@ -16,12 +18,12 @@ console.log(
"", "",
); );
console.log( console.log(
"自分で意図して行っていないのであれば%c今直ぐにこのツールを閉じて%cログアウトもしくはCookieとセッションの削除をするべきです。", "自分で意図して行っていないのであれば%c今直ぐにこのツールを閉じて作業を中断してください。%c\n中断後、安全性の観点からセッショントークンの再生成をすることを強く推奨します。\nセッショントークンの再生性は以下のリンクより行えます。"+sesstoken_reset_url,
"color:#FF4848; font-weight: bold;", "color:#FF4848; font-weight: bold;",
"", "",
); );
console.log( console.log(
"%cMessage by uwuzu%c\nこのメッセージはuwuzu開発者であるだいちまるによって書き込まれたものです。\nuwuzuサーバー運営者及びuwuzu開発者がCookie情報等を要求することはありません。", "%cMessage by uwuzu%c\n\nこのメッセージはuwuzu開発者であるだいちまるによって書き込まれたものです。\nuwuzuサーバー運営者及びuwuzu開発者がCookie情報等を要求することはありません。",
"color:white; background-color:#FFC832; padding:4px; border-radius:4px; font-size: 12pt", "color:white; background-color:#FFC832; padding:4px; border-radius:4px; font-weight: bold; font-size: 10pt",
"", "",
); );
+1 -1
View File
@@ -38,4 +38,4 @@ function view_notify(notify){
setTimeout(function(){ setTimeout(function(){
$("#notify").hide(); $("#notify").hide();
}, 10000); }, 10000);
} }
+1 -1
View File
@@ -199,7 +199,7 @@ if( !empty($_POST['btn_submit']) ) {
$row = $result->fetch(); // ここでデータベースから取得した値を $row に代入する $row = $result->fetch(); // ここでデータベースから取得した値を $row に代入する
if($row["userid"] == $userid){ if($row["userid"] == $userid){
if(password_verify($password,$row["password"])){ if(uwuzu_password_verify($password,$row["password"])){
if(empty($row["authcode"])){ if(empty($row["authcode"])){
$_SESSION['admin_login'] = true; $_SESSION['admin_login'] = true;
+1 -1
View File
@@ -424,7 +424,7 @@ if( !empty($_POST['btn_submit']) ) {
$role = "user"; $role = "user";
$admin = "none"; $admin = "none";
$hashpassword = password_hash($password, PASSWORD_DEFAULT); $hashpassword = uwuzu_password_hash($password);
$LoginIdBytes = random_bytes(64); $LoginIdBytes = random_bytes(64);
$loginid = hash('sha3-512', $LoginIdBytes); $loginid = hash('sha3-512', $LoginIdBytes);
+3 -1
View File
@@ -408,7 +408,9 @@ if( !empty($_POST['btn_submit']) ) {
$role = "user"; $role = "user";
$admin = "none"; $admin = "none";
$hashpassword = password_hash($password, PASSWORD_DEFAULT);
$hashpassword = uwuzu_password_hash($password);
$LoginIdBytes = random_bytes(64); $LoginIdBytes = random_bytes(64);
$loginid = hash('sha3-512', $LoginIdBytes); $loginid = hash('sha3-512', $LoginIdBytes);
+1 -1
View File
@@ -162,7 +162,7 @@ if (isset($_GET['userid']) && isset($_GET['account_id'])) {
} }
} }
if($message['ads'] === "true"){ if($message['ads'] === "true"){
echo '<div class="ads"><a href = "' . safetext($message['ads_url']) . '"><img src="' . safetext($message['ads_img_url']) . '" title="' . safetext($message['ads_memo']) . '"></a></div>'; echo '<div class="ads"><a href = "' . safetext($message['ads_url']) . '" target="_blank"><img src="' . safetext($message['ads_img_url']) . '" title="' . safetext($message['ads_memo']) . '"></a></div>';
} }
}else{ }else{
echo '<div class="tokonone" id="noueuse"><p>ユーズがありません</p></div>'; echo '<div class="tokonone" id="noueuse"><p>ユーズがありません</p></div>';
+1 -1
View File
@@ -165,7 +165,7 @@ if (isset($_GET['userid']) && isset($_GET['account_id'])) {
} }
} }
if($message['ads'] === "true"){ if($message['ads'] === "true"){
echo '<div class="ads"><a href = "' . safetext($message['ads_url']) . '"><img src="' . safetext($message['ads_img_url']) . '" title="' . safetext($message['ads_memo']) . '"></a></div>'; echo '<div class="ads"><a href = "' . safetext($message['ads_url']) . '" target="_blank"><img src="' . safetext($message['ads_img_url']) . '" title="' . safetext($message['ads_memo']) . '"></a></div>';
} }
}else{ }else{
echo '<div class="tokonone" id="noueuse"><p>ユーズがありません</p></div>'; echo '<div class="tokonone" id="noueuse"><p>ユーズがありません</p></div>';
+1 -1
View File
@@ -142,7 +142,7 @@ if (isset($_GET['userid']) && isset($_GET['account_id'])) {
} }
} }
if($message['ads'] === "true"){ if($message['ads'] === "true"){
echo '<div class="ads"><a href = "' . safetext($message['ads_url']) . '"><img src="' . safetext($message['ads_img_url']) . '" title="' . safetext($message['ads_memo']) . '"></a></div>'; echo '<div class="ads"><a href = "' . safetext($message['ads_url']) . '" target="_blank"><img src="' . safetext($message['ads_img_url']) . '" title="' . safetext($message['ads_memo']) . '"></a></div>';
} }
}else{ }else{
echo '<div class="tokonone" id="noueuse"><p>ユーズがありません</p></div>'; echo '<div class="tokonone" id="noueuse"><p>ユーズがありません</p></div>';
+7 -2
View File
@@ -82,8 +82,13 @@ if (isset($_GET['userid']) && isset($_GET['account_id'])) {
$userQuery->bindValue(':userid', $value['fromuserid']); $userQuery->bindValue(':userid', $value['fromuserid']);
$userQuery->execute(); $userQuery->execute();
$user_array = $userQuery->fetch(); $user_array = $userQuery->fetch();
$value['fromusericon'] = "../".$user_array["iconname"]; if(!(empty($user_array))){
$value['fromusername'] = $user_array["username"]; $value['fromusericon'] = "../".$user_array["iconname"];
$value['fromusername'] = $user_array["username"];
}else{
$value['fromusericon'] = "../img/deficon/icon.png";
$value['fromusername'] = "でふぉると";
}
} }
} }
$messageDisplay = new MessageDisplay($value); // userid を渡さない $messageDisplay = new MessageDisplay($value); // userid を渡さない
+1 -1
View File
@@ -167,7 +167,7 @@ if (isset($_GET['userid']) && isset($_GET['account_id'])) {
} }
} }
if($message['ads'] === "true"){ if($message['ads'] === "true"){
echo '<div class="ads"><a href = "' . safetext($message['ads_url']) . '"><img src="' . safetext($message['ads_img_url']) . '" title="' . safetext($message['ads_memo']) . '"></a></div>'; echo '<div class="ads"><a href = "' . safetext($message['ads_url']) . '" target="_blank"><img src="' . safetext($message['ads_img_url']) . '" title="' . safetext($message['ads_memo']) . '"></a></div>';
} }
}else{ }else{
echo '<div class="tokonone" id="noueuse"><p>投稿がありません</p></div>'; echo '<div class="tokonone" id="noueuse"><p>投稿がありません</p></div>';
+1 -1
View File
@@ -153,7 +153,7 @@ if (isset($_GET['userid']) && isset($_GET['account_id'])) {
} }
} }
if($message['ads'] === "true"){ if($message['ads'] === "true"){
echo '<div class="ads"><a href = "' . safetext($message['ads_url']) . '"><img src="' . safetext($message['ads_img_url']) . '" title="' . safetext($message['ads_memo']) . '"></a></div>'; echo '<div class="ads"><a href = "' . safetext($message['ads_url']) . '" target="_blank"><img src="' . safetext($message['ads_img_url']) . '" title="' . safetext($message['ads_memo']) . '"></a></div>';
} }
}else{ }else{
echo '<div class="tokonone" id="noueuse"><p>ユーズがありません</p></div>'; echo '<div class="tokonone" id="noueuse"><p>ユーズがありません</p></div>';
+1 -1
View File
@@ -153,7 +153,7 @@ if (isset($_GET['userid']) && isset($_GET['account_id'])) {
} }
} }
if($message['ads'] === "true"){ if($message['ads'] === "true"){
echo '<div class="ads"><a href = "' . safetext($message['ads_url']) . '"><img src="' . safetext($message['ads_img_url']) . '" title="' . safetext($message['ads_memo']) . '"></a></div>'; echo '<div class="ads"><a href = "' . safetext($message['ads_url']) . '" target="_blank"><img src="' . safetext($message['ads_img_url']) . '" title="' . safetext($message['ads_memo']) . '"></a></div>';
} }
}else{ }else{
echo '<div class="tokonone" id="noueuse"><p>ユーズがありません</p></div>'; echo '<div class="tokonone" id="noueuse"><p>ユーズがありません</p></div>';
+1 -1
View File
@@ -147,7 +147,7 @@ if (isset($_GET['userid']) && isset($_GET['account_id'])) {
} }
} }
if($message['ads'] === "true"){ if($message['ads'] === "true"){
echo '<div class="ads"><a href = "' . safetext($message['ads_url']) . '"><img src="' . safetext($message['ads_img_url']) . '" title="' . safetext($message['ads_memo']) . '"></a></div>'; echo '<div class="ads"><a href = "' . safetext($message['ads_url']) . '" target="_blank"><img src="' . safetext($message['ads_img_url']) . '" title="' . safetext($message['ads_memo']) . '"></a></div>';
} }
}else{ }else{
echo '<div class="tokonone" id="noueuse"><p>ユーズがありません</p></div>'; echo '<div class="tokonone" id="noueuse"><p>ユーズがありません</p></div>';
+6 -1
View File
@@ -268,10 +268,15 @@ if( !empty($_POST['btn_submit']) ) {
$deleteQuery->bindValue(':userid', $userid, PDO::PARAM_STR); $deleteQuery->bindValue(':userid', $userid, PDO::PARAM_STR);
$res = $deleteQuery->execute(); $res = $deleteQuery->execute();
// 通知削除クエリを実行 // 通知削除クエリを実行(自分宛ての通知)
$deleteQuery = $pdo->prepare("DELETE FROM notification WHERE touserid = :touserid"); $deleteQuery = $pdo->prepare("DELETE FROM notification WHERE touserid = :touserid");
$deleteQuery->bindValue(':touserid', $userid, PDO::PARAM_STR); $deleteQuery->bindValue(':touserid', $userid, PDO::PARAM_STR);
$res = $deleteQuery->execute(); $res = $deleteQuery->execute();
// 通知削除クエリを実行(自分からの通知)
$deleteQuery = $pdo->prepare("DELETE FROM notification WHERE fromuserid = :fromuserid");
$deleteQuery->bindValue(':fromuserid', $userid, PDO::PARAM_STR);
$res = $deleteQuery->execute();
// ユーザーIDを削除したい全てのアカウントを取得 // ユーザーIDを削除したい全てのアカウントを取得
$query = $pdo->prepare("SELECT * FROM account WHERE follow LIKE :pattern1 OR follow LIKE :pattern2 OR follow LIKE :pattern3 OR follower LIKE :pattern1 OR follower LIKE :pattern2 OR follower LIKE :pattern3"); $query = $pdo->prepare("SELECT * FROM account WHERE follow LIKE :pattern1 OR follow LIKE :pattern2 OR follow LIKE :pattern3 OR follower LIKE :pattern1 OR follower LIKE :pattern2 OR follower LIKE :pattern3");
+6 -3
View File
@@ -114,7 +114,8 @@ if(!($userid == null)){
if( empty($error_message) ) { if( empty($error_message) ) {
// トランザクション開始 // トランザクション開始
$pdo->beginTransaction(); $pdo->beginTransaction();
$hashpassword = password_hash($password, PASSWORD_DEFAULT);
$hashpassword = uwuzu_password_hash($password);
try { try {
// SQL作成 // SQL作成
@@ -209,8 +210,10 @@ if(!($userid == null)){
if( empty($error_message) ) { if( empty($error_message) ) {
// トランザクション開始 // トランザクション開始
$pdo->beginTransaction(); $pdo->beginTransaction();
$hashpassword = password_hash($password, PASSWORD_DEFAULT);
$hashpassword = uwuzu_password_hash($password);
try { try {
// SQL作成 // SQL作成
+30 -159
View File
@@ -2,9 +2,8 @@
使っている方ならわかると思いますが普通のSNSです! 使っている方ならわかると思いますが普通のSNSです!
これと言った大きな特徴もなく、平凡で、なんとも言えないSNSです… これと言った大きな特徴もなく、平凡で、なんとも言えないSNSです…
あっ!特徴かもしれないのが誰でもサーバーを建てられることです!!! あっ!特徴かもしれないのが誰でもサーバーを建てられることです!!!
詳細は5. サーバーの立て方をご覧ください! 詳細はdocs.uwuzu.xyzを確認してください!
### 1.1 作られた理由は? ### 1.1 uwuzuのよみは?
uwuzuは某X社のSNSを再構築しようと考えたdaichimarukanaにより作成されたSNSです()
uwuzuの読みはゆずです。 uwuzuの読みはゆずです。
## 2. 誰でもサーバーを建てれるってことは、分散型? ## 2. 誰でもサーバーを建てれるってことは、分散型?
@@ -12,7 +11,7 @@ uwuzuの読みはゆずです。
uwuzuにはActivityPubやその他の連合用機能がないため基本的に導入されたサーバー中心の中央集権型SNSです! uwuzuにはActivityPubやその他の連合用機能がないため基本的に導入されたサーバー中心の中央集権型SNSです!
いやでも中央集権型でも誰でもサーバーを立てれるから分散型...? いやでも中央集権型でも誰でもサーバーを立てれるから分散型...?
分散中央型SNSな気がしてきました!(?) 分散中央型SNSな気がしてきました!(?)
今後いつかはActivityPubも導入しようかと思っています... 今後いつかはActivityPubも本格導入しようかと思っています...
## 3. 名前の由来って何? ## 3. 名前の由来って何?
おっ!いい着眼点ですねぇ~~~ おっ!いい着眼点ですねぇ~~~
@@ -29,165 +28,16 @@ uwuzuはPHPとJS、HTML(プログラミング言語じゃないか)、CSSで作
使用している画像は友人またはGoogle Icons様より使わせて頂いております! 使用している画像は友人またはGoogle Icons様より使わせて頂いております!
## 5. サーバーの建て方 ## 5. サーバーの建て方
まず、Apache2とPHP 8とmysql Ver 15が導入されているサーバーを準備します docs.uwuzu.xyzをご確認いただくかgithubのreadme.mdをよんでください
PHP 8では事前にGDを有効化しておいてください!(QRコードの生成に必要です。)
次にSQLを設定します。(InnoDB)
まず、お好きな名前でDBを作成し、その中に、account,emoji,notice,role,ueuse,notification,ads,reportとテーブルを作成します。
テーブルの中身は以下のとおりです。
照合順序は全て標準でutf8mb4_general_ciです。
【追記】v1.2.28からSSLが必須項目になりました。localhostでアクセスする分には大丈夫ですが、他の端末からのアクセス時にはSSLの設定をしてください。
## 簡単に構築できるようSQLの構造ファイルがリリースに添付されています!そちらをインポートしていただけますと大幅に簡単に導入できます!
(userロールとofficialロールとiceロールの設定は別途必要です。お手数ですがそこの設定だけよろしくお願いいたします。)
### account
- sysid(INT)(AUTO_INCREMENT ) アカウントが追加されるとカウントされるシステム用ID
- username(varchar(500)) ユーザーネーム保存用
- userid(varchar(500)) ユーザーID保存用
- password(varchar(1024)) パスワード保存用(ハッシュ化されます)
- loginid(varchar(256)) 自動ログイン時に本人アカウントか確認
- mailadds(varchar(500)) メールアドレス保存用
- profile(mediumtext) プロフィールテキスト保存用
- iconname(varchar(256)) アイコン画像リンク保存用
- headname(varchar(256)) ヘッダー画像リンク保存用
- role(varchar(1024)) 「user」のようなロール保存用
- datetime(datetime) アカウント作成日時保存用
- follow(mediumtext) アカウントがフォローしている人保存用
- follower(mediumtext) アカウントがフォローされている人保存用
- bookmark(mediumtext) ブックマーク保存用
- blocklist(mediumtext) ブロックしている人保存用
- admin(varchar(25)) 管理者アカウントなら「yes」、それ以外なら「none」と入力。
- authcode(varchar(256)) 二段階認証用キー保存用
- backupcode(varchar(256)) 二段階認証のバックアップコード保存用
- sacinfo(varchar(256)) 特殊アカウント識別用
- notification_settings(varchar(256)) 受け取る通知設定用
- mail_settings(mediumtext) メールの送信設定保存用
- encryption_ivkey(varchar(256)) ユーザーデータ暗号化時の暗号化ベクトル保存用
### ads
- sysid(INT)(AUTO_INCREMENT) 追加されるとカウントされるシステム用ID
- uniqid(varchar(512)) 広告ID保存用
- url(varchar(512)) 広告のクリック先URL保存用
- image_url(varchar(512)) 広告に表示する画像URL保存用
- memo(mediumtext) 広告にマウスオーバーしたときに表示されるメッセージ保存用
- start_date(datetime) 広告配信開始日時保存用
- limit_date(datetime) 広告配信終了日時保存用
- datetime(datetime) 広告追加日時保存用
### emoji
- sysid(INT)(AUTO_INCREMENT) アカウントが追加されるとカウントされるシステム用ID
- emojifile(varchar(512)) 絵文字ファイルパス保存用
- emojiname(varchar(512)) 「:emoji:」のような絵文字名保存用
- emojiinfo(mediumtext) 絵文字についての説明保存用
- emojidate(datetime) 絵文字登録日時保存用
### invitation
- sysid(INT)(AUTO_INCREMENT) 追加されるとカウントされるシステム用ID
- code(varchar(512)) 招待コード
- used(varchar(25)) 使用済みかそうでないか
- datetime(datetime) 招待コード仕様日時更新用
### migration
- sysid(INT)(AUTO_INCREMENT) 追加されるとカウントされるシステム用ID
- account(varchar(512)) ユーザーID保存用
- domain(varchar(1024)) 移行先サーバーのドメイン保存用
- migration_code(varchar(256)) 識別コード
- encryption_ivkey(varchar(256)) 暗号化用
- encryption_key(varchar(256)) 暗号化用
- datetime(datetime) 招待コード仕様日時更新用
### notice
- sysid(INT)(AUTO_INCREMENT) うんえいからのおしらせが追加されるとカウントされるシステム用ID
- uniqid(varchar(256)) ID保存用
- title(varchar(1024)) お知らせのタイトル保存用
- note(mediumtext) お知らせの内容保存用
- account(varchar(500)) 編集者ID保存用
- emojidate(datetime) お知らせ登録日時保存用
### notification
- sysid(INT)(AUTO_INCREMENT) 通知されるとカウントされるシステム用ID
- fromuserid(varchar(512)) 通知元ID保存用
- touserid(varchar(512)) 通知先ID保存用
- title(varchar(1024)) 通知のタイトル
- url(通知のクリック先URL保存用)
- msg(mediumtext) 通知の内容
- datetime(datetime) 通知日時
- userchk(varchar(25)) 通知の既読確認
- category(varchar(256)) 通知のカテゴリ識別用
### report
- sysid(INT)(AUTO_INCREMENT) 追加されるとカウントされるシステム用ID
- uniqid(varchar(256)) 通報ID保存用
- userid(varchar(500)) 通報先ユーザーID保存用
- report_userid(varchar(500)) 通報元ユーザーID保存用
- msg(mediumtext) サービス管理者宛メッセージ保存用
- datetime(datetime) 通報日時保存用
- admin_chk(varchar(25)) 解決済みかどうか確認用
### role
- sysid(INT)(AUTO_INCREMENT) ロールが追加されるとカウントされるシステム用ID
- rolename(varchar(512)) ロール表示名保存用
- roleauth(varchar(256)) ロールの権限保存用
- rolecolor(varchar(25)) ロールの色保存用
- roleidname(varchar(512)) 「user」のようなロール指定用
- roleeffect(varchar(256)) アニメーションロール機能のエフェクト指定用
### ueuse
- sysid(INT)(AUTO_INCREMENT) 投稿されるとカウントされるシステム用ID
- username(varchar(512)) 投稿時点での投稿者名保存用
- account(varchar(512)) 投稿者ID保存用
- uniqid(varchar(256)) 投稿ID保存用
- rpuniqid(varchar(256)) リプライ先ID保存用
- ruuniqid(varchar(256)) リユーズ先ID保存用
- ueuse(mediumtext) 投稿内容保存用
- photo1(varchar(512)) 投稿に添付されたファイルの保存ディレクトリ保存用
- photo2(varchar(512)) 投稿に添付されたファイルの保存ディレクトリ保存用
- photo3(varchar(512)) 投稿に添付されたファイルの保存ディレクトリ保存用
- photo4(varchar(512)) 投稿に添付されたファイルの保存ディレクトリ保存用
- video1(varchar(512)) 投稿に添付されたファイルの保存ディレクトリ保存用
- datetime(datetime) 投稿日時保存用
- favorite(mediumtext) いいね保存用
- abi(mediumtext) 投稿者の追記保存用
- abidate(datetime) 追記日時保存用
- nsfw(varchar(25)) NSFW指定有無保存用
すべて作成完了したらGithubよりuwuzuのファイルをDLし、解凍し、それをサーバーの動作ディレクトリに置き、Apacheのhttpd.confからその動作ディレクトリを指定し、動作ディレクトリ内のdb.phpにDBのログイン情報を書き込んであとはApacheとphpとMy SQLを起動するだけ!
起動したらまずDBのroleにphpmyadminから「user」ロールと「official」ロールと「ice」ロールを追加、権限は「user」と「official」と「ice」でOK。ロール名はとりあえず「一般ユーザー」とか適当でOK、ロールの色はHEXコード(#を除く)で000000のように指定。(この3つのロールがないとエラーが発生します。)
そしたら普通にuwuzuにアクセスして自分のアカウントを登録。
## 管理者アカウント登録機能が追加されました。【[domain]/admin/】より設定できるのでそちらをご利用ください。
なお、管理者アカウントを導入後に登録した場合サーバーを止めてuwuzu動作ディレクトリ内のserverフォルダ内のファイルを設定する必要はございません。
それが終わったら一度サーバーを止め、uwuzuの動作ディレクトリ内のserverフォルダ内のファイルを各自設定
ファイルの機能は以下の通り!
## 管理者アカウント作成後にログインし、サーバー設定より以下の項目が簡単に設定できます。
- 404imagepath.txt : 404ページに表示する画像パス保存用
- 503imagepath.txt : 503ページに表示する画像パス保存用
- banurldomain.txt : 投稿禁止URLドメイン
- banuserid.txt : 登録禁止ユーザーid
- badpass.txt : 登録禁止パスワードリスト
- info.txt : サーバー登録時に表示されるメッセージ(好きな内容)
- privacypolicy.txt : プライバシーポリシー(サーバーのプライバシーポリシーを記載)
- serverstop.txt : サーバー停止ページで表示するメッセージ
- terms.txt : 利用規約(サーバーの利用規約を記載)
- textsize.txt : 最大文字数
- serversettings.ini : サーバー情報保存ファイル
- uwuzuabout.txt : このファイル
- uwuzuinfo.txt : uwuzuのバージョン等記載
- uwuzurelease.txt : uwuzuのバージョン等記載
### これでサーバーは完成!!!
もう一度サーバーを起動してみんなに公開しよう!!!(まだ脆弱性は残っていると思われます。公開する際は気をつけてください。私だいちまる及びPutonfpsは一切責任を負いません。)
## 6. Android、iOS、その他OS向けのアプリについて ## 6. Android、iOS、その他OS向けのアプリについて
残念ですが今現在は公式アプリ等はなく、Webブラウザからお楽しみいただけます。 残念ですが今現在は公式アプリ等はなく、Webブラウザからお楽しみいただけます。
誰かが作ってくれたらありがたいな~() 誰かが作ってくれたらありがたいな~
PWA機能によってアプリっぽくすることはできます!
## 7. 開発したいです!!! ## 7. 開発したいです!!!
uwuzuを自分の思うように改造して使いたい場合はUPULライセンスのもと改造後ソースコードを公開するということで改造してください! uwuzuを自分の思うように改造して使いたい場合はUPULライセンスのもと改造後ソースコードを公開するということで改造してください!
場合によってはdaichimarukanaの作る本家(?)uwuzuにも改造で追加された機能が実装されるかも...() 場合によってはdaichimarukanaの作る本家(?)uwuzuにも改造で追加された機能が実装されるかも...
daichimarukanaと一緒に開発したいよ~って人は私のHPからメールとか某Xとかから連絡してくださいな~ daichimarukanaと一緒に開発したいよ~って人は私のHPからメールとか某Xとかから連絡してくださいな~
(uwuzuはv1.3.0よりAGPLからUPULに変更されました。) (uwuzuはv1.3.0よりAGPLからUPULに変更されました。)
@@ -202,7 +52,7 @@ daichimarukanaと一緒に開発したいよ~って人は私のHPからメー
## 9. ライセンス ## 9. ライセンス
UPULライセンスです! UPULライセンスです!
UPULライセンスに関しては同梱されているUPUL_License.txtを確認するか、uwuzu.comより詳細をご確認ください。 UPULライセンスに関しては同梱されているUPUL_License.txtを確認するか、uwuzu.xyzより詳細をご確認ください。
## 10. 利用させていただいているライブラリなどのライセンス ## 10. 利用させていただいているライブラリなどのライセンス
@@ -244,7 +94,28 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
### WebPush
Copyright (c) 2015 Louis Lagrange
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
## 更新情報 ## 更新情報
編集者 : daichimarukana 編集者 : daichimarukana
最終更新日 : 2024/08/19 16:58 最終更新日 : 2024/11/06 21:54
+2 -2
View File
@@ -1,4 +1,4 @@
uwuzu uwuzu
1.4.5 1.4.6
2024/10/13 2024/11/06
daichimarukana,putonfps daichimarukana,putonfps
+13
View File
@@ -1,6 +1,19 @@
## リリースノートだぜぇぇぇぇぇぇい!!!!!!! ## リリースノートだぜぇぇぇぇぇぇい!!!!!!!
ここにはuwuzuの更新情報を載せてくぜぇ~!(いやまてテンションおかしいだろ...) ここにはuwuzuの更新情報を載せてくぜぇ~!(いやまてテンションおかしいだろ...)
## Version 1.4.6 (Funium)
リリース日:2024/11/06
fix: ActivityPubに関する一部問題を修正しました。
fix: パスワードが72文字以上の場合に、72文字目以降のパスワードが入力されていなくても認証されてしまう問題を修正しました。
この修正がユーザーに適用されるにはパスワードの更新が必要です。(引き続き同じパスワードを使用することも可能です)
fix: 一部URLに関する不具合に応急処置をしました!
fix: アカウント削除時に自分が起こしたアクションにより送信された通知が削除されない問題を修正しました。
fix: 通知ページで削除されたアカウントにより通知の表示がうまく行われない問題を修正しました。
chg: 広告をクリックした際に新しいタブで開くように変更しました!
chg: 一部UIを変更しました!
chg: ユーザーに脆弱性に対しての注意喚起をする機能のメッセージを一部編集しました。
## Version 1.4.5 (Funium) ## Version 1.4.5 (Funium)
リリース日:2024/10/13 リリース日:2024/10/13
fix: URLに関する処理の問題を修正しました fix: URLに関する処理の問題を修正しました
+3 -1
View File
@@ -216,7 +216,9 @@ if( !empty($_POST['btn_submit']) ) {
if ($checkResult) { if ($checkResult) {
if( empty($error_message) ) { if( empty($error_message) ) {
$backupcode = random(); $backupcode = random();
$hashbackupcode = password_hash($backupcode, PASSWORD_DEFAULT);
$hashbackupcode = uwuzu_password_hash($backupcode);
$secret = $_SESSION['secretcode']; $secret = $_SESSION['secretcode'];
if(!(empty($userData["encryption_ivkey"]))){ if(!(empty($userData["encryption_ivkey"]))){
+2 -4
View File
@@ -303,7 +303,6 @@ if( !empty($_POST['btn_submit']) ) {
if( empty($error_message) ) { if( empty($error_message) ) {
// トランザクション開始 // トランザクション開始
$pdo->beginTransaction(); $pdo->beginTransaction();
$hashpassword = password_hash($password, PASSWORD_DEFAULT);
try { try {
// SQL作成 // SQL作成
@@ -352,8 +351,6 @@ if( !empty($_POST['pass_submit']) ) {
$pass_chk = safetext($_POST['passchk_userid']); $pass_chk = safetext($_POST['passchk_userid']);
$password = $_POST['password']; $password = $_POST['password'];
$hashpassword = password_hash($password, PASSWORD_DEFAULT);
if(empty($pass_chk)){ if(empty($pass_chk)){
$error_message[] = 'ユーザーidを入力してください。(USERID_INPUT_PLEASE)'; $error_message[] = 'ユーザーidを入力してください。(USERID_INPUT_PLEASE)';
}else{ }else{
@@ -389,7 +386,8 @@ if( !empty($_POST['pass_submit']) ) {
if( empty($error_message) ) { if( empty($error_message) ) {
// トランザクション開始 // トランザクション開始
$pdo->beginTransaction(); $pdo->beginTransaction();
$hashpassword = password_hash($password, PASSWORD_DEFAULT);
$hashpassword = uwuzu_password_hash($password);
try { try {
// SQL作成 // SQL作成
+5
View File
@@ -487,6 +487,11 @@ if( !empty($_POST['send_ban_submit']) ) {
$deleteQuery->bindValue(':touserid', $userId2, PDO::PARAM_STR); $deleteQuery->bindValue(':touserid', $userId2, PDO::PARAM_STR);
$res = $deleteQuery->execute(); $res = $deleteQuery->execute();
// 通知削除クエリを実行(自分からの通知)
$deleteQuery = $pdo->prepare("DELETE FROM notification WHERE fromuserid = :fromuserid");
$deleteQuery->bindValue(':fromuserid', $userId2, PDO::PARAM_STR);
$res = $deleteQuery->execute();
// ユーザーIDを削除したい全てのアカウントを取得 // ユーザーIDを削除したい全てのアカウントを取得
$query = $pdo->prepare("SELECT * FROM account WHERE follow LIKE :pattern1 OR follow LIKE :pattern2 OR follow LIKE :pattern3 OR follower LIKE :pattern1 OR follower LIKE :pattern2 OR follower LIKE :pattern3"); $query = $pdo->prepare("SELECT * FROM account WHERE follow LIKE :pattern1 OR follow LIKE :pattern2 OR follow LIKE :pattern3 OR follower LIKE :pattern1 OR follower LIKE :pattern2 OR follower LIKE :pattern3");
$query->bindValue(':pattern1', "%,$userid,%", PDO::PARAM_STR); $query->bindValue(':pattern1', "%,$userid,%", PDO::PARAM_STR);
+21 -7
View File
@@ -1,19 +1,33 @@
{ {
"software": "uwuzu", "software": "uwuzu",
"version": "1.4.5", "version": "1.4.6",
"release_date": "2024-10-13", "release_date": "2024-11-06",
"release_notes": "このアップデートではログイン時にパスワードが32文字以上入力できない問題や、他数件の問題が修正されています。", "release_notes": "このアップデートではパスワードが完全に入力されていなくても認証されてしまう問題を含め、他数件の問題が修正されています!!!\n早急なアップデートを強く推奨します!!!!!",
"notices": "アップデートの前に、データのバックアップを行うことをおすすめします!", "notices": "アップデートの前に、データのバックアップを行うことをおすすめします!",
"files": { "files": {
"overwrite": [ "overwrite": [
"/admin/addadmin.php", "/admin/addadmin.php",
"/api/ueuse/get.php", "/css/home.css",
"/bookmark/index.php",
"/emoji/index.php",
"/function/function.php", "/function/function.php",
"/home/index.php", "/home/index.php",
"/js/console_notice.js",
"/migration/index.php",
"/nextpage/bookmark.php",
"/nextpage/ftlpage.php",
"/nextpage/nextpage.php",
"/nextpage/notification.php",
"/nextpage/ueusepage.php",
"/nextpage/userlikepage.php",
"/nextpage/usermediapage.php",
"/nextpage/userpage.php",
"/others/index.php",
"/passrecovery/startrecovery.php",
"/settings/addauthcode.php",
"/settings/index.php",
"/settings_admin/userinfo.php",
"/user/outbox/index.php", "/user/outbox/index.php",
"/settings_admin/ad_admin.php", "/addauthcode.php",
"/authlogin.php",
"/login.php", "/login.php",
"/new.php", "/new.php",
"/server/uwuzuabout.txt", "/server/uwuzuabout.txt",
+1 -3
View File
@@ -62,7 +62,6 @@ if(safetext($serversettings["serverinfo"]["server_activitypub"]) === "true"){
"url" => "https://" . $domain . "/ueuse/activity/?ueuse=" . $value["uniqid"], "url" => "https://" . $domain . "/ueuse/activity/?ueuse=" . $value["uniqid"],
"published" => date(DATE_ATOM, strtotime($value["datetime"])), "published" => date(DATE_ATOM, strtotime($value["datetime"])),
"to" => [ "to" => [
"https://" . $domain . "/followers",
"https://www.w3.org/ns/activitystreams#Public", "https://www.w3.org/ns/activitystreams#Public",
], ],
"actor" => "https://" . $domain . "/actor/?actor=@" . $userid, "actor" => "https://" . $domain . "/actor/?actor=@" . $userid,
@@ -73,7 +72,6 @@ if(safetext($serversettings["serverinfo"]["server_activitypub"]) === "true"){
"url" => "https://" . $domain . "/!" . $value["uniqid"], "url" => "https://" . $domain . "/!" . $value["uniqid"],
"published" => date(DATE_ATOM, strtotime($value["datetime"])), "published" => date(DATE_ATOM, strtotime($value["datetime"])),
"to" => [ "to" => [
"https://" . $domain . "/followers",
"https://www.w3.org/ns/activitystreams#Public", "https://www.w3.org/ns/activitystreams#Public",
], ],
"attributedTo" => "https://" . $domain . "/@" . $value["account"], "attributedTo" => "https://" . $domain . "/@" . $value["account"],
@@ -87,7 +85,7 @@ if(safetext($serversettings["serverinfo"]["server_activitypub"]) === "true"){
$item = array( $item = array(
"type" => "OrderedCollection", "type" => "OrderedCollection",
"@context" => "https://www.w3.org/ns/activitystreams", "@context" => "https://www.w3.org/ns/activitystreams",
"id" => "https://" . $domain . "/user/outbox/?actor=@" . $userid . "?page=true", "id" => "https://" . $domain . "/user/outbox/?actor=@" . $userid . "&page=true",
"partOf" => "https://" . $domain . "/user/outbox/?actor=@" . $userid, "partOf" => "https://" . $domain . "/user/outbox/?actor=@" . $userid,
"summary" => "outbox of " . $userid, "summary" => "outbox of " . $userid,
"totalItems" => count($messages), "totalItems" => count($messages),