<?php
function isIpInCIDR($ip, $cidr){
    if (!strpos($cidr, '/')) {
        return $ip === $cidr;
    }

    [$network, $prefixLength] = explode('/', $cidr);
    if((filter_var($network, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) || filter_var($network, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) && (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) || filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4))){
        $prefixLength = (int)$prefixLength;

        $ipBinary = inet_pton($ip);
        $networkBinary = inet_pton($network);

        if ($ipBinary === false || $networkBinary === false) {
            actionLog(null, "error", "isIpInCIDR", null, "invalid_ip_or_network_".$ipBinary."/".$networkBinary, 4);
            return false;
        }

        $totalBits = strlen($networkBinary) * 8;

        if ($prefixLength < 0 || $prefixLength > $totalBits) {
            actionLog(null, "error", "isIpInCIDR", null, "bad_prefix_length_".$prefixLength, 4);
            return false;
        }

        $mask = str_repeat("\xFF", (int)($prefixLength / 8));
        $remainingBits = $prefixLength % 8;

        if ($remainingBits > 0) {
            $mask .= chr((0xFF << (8 - $remainingBits)) & 0xFF);
        }
        $mask = str_pad($mask, strlen($networkBinary), "\x00");

        return ($ipBinary & $mask) === ($networkBinary & $mask);
    }else{
        actionLog(null, "error", "isIpInCIDR", null, "bad_ip", 4);
        return false;
    }
}
function blockedIP($ip_addr) {
    // データベースに接続
    try {
        $pdo = new PDO(
            'mysql:charset=utf8mb4;dbname=' . DB_NAME . ';host=' . DB_HOST,
            DB_USER,
            DB_PASS,
            [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::MYSQL_ATTR_MULTI_STATEMENTS => false,
            ]
        );
    } catch (PDOException $e) {
        error_log("Database connection failed: " . $e->getMessage());
        return false;
    }

    // IPブロックリストの取得
    $search_query = $pdo->prepare('SELECT ipaddr FROM ipblock');
    $search_query->execute();
    $blocked_ips = $search_query->fetchAll(PDO::FETCH_COLUMN);

    foreach ($blocked_ips as $blocked_ip) {
        if (isIpInCIDR($ip_addr, $blocked_ip)) {
            $fron_uwuzu_errcode = "IP_BANNED";
            $url = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'] . "/unsupported.php?errcode=" . $fron_uwuzu_errcode;
            header("Location: " . $url);

            require(__DIR__ . '/../unsupported.php');
            exit;
        }
    }
}
function stopLoadAvg(){
    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
		$loadAve = 0;
	} else {
		if (function_exists("sys_getloadavg")) {
            $load = sys_getloadavg();
            $loadAve = is_array($load) && isset($load[0]) ? $load[0] : 0;
        } else {
            $loadAve = 0;
        }
	}

    if (defined('STOP_LA') && (int)STOP_LA !== -1) {
        if ($loadAve > (int)STOP_LA) {
            include_once __DIR__ . '/../errorpage/overcapacity.php';
            exit;
        }
    }
}
//通常のログイン処理
function uwuzuUserLogin($session, $cookie, $ip_addr, $operation_permission = "user") {
    //セッション,クッキー,IPアドレス,閲覧権限(userかadminかの二種類)を受け取る
    $serversettings_file = $_SERVER['DOCUMENT_ROOT']."/server/serversettings.ini";
    $serversettings = parse_ini_file($serversettings_file, true);
    // データベースに接続
    try {
        $option = array(
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::MYSQL_ATTR_MULTI_STATEMENTS => false
        );
        $pdo = new PDO('mysql:charset=utf8mb4;dbname='.DB_NAME.';host='.DB_HOST , DB_USER, DB_PASS, $option);
    } catch(PDOException $e) {
        actionLog(null, "error", "uwuzuUserLogin", null, $e, 4);
        return false;
    }

    if(isset($session['loginid'])){
        $loginid = safetext($session['loginid']);
    }else if(isset($cookie['loginid'])){
        $loginid = safetext($cookie['loginid']);
    } else {
        return false;
    }

    if(isset($session['loginkey'])) {
        $loginkey = safetext($session['loginkey']);
    }else if(isset($cookie['loginkey'])){
        $loginkey = safetext($cookie['loginkey']);
    } else {
        $loginkey = null;
    }

    $loginQuery = $pdo->prepare("SELECT * FROM account WHERE loginid = :loginid");
    $loginQuery->bindValue(':loginid', $loginid);
    $loginQuery->execute();
    $loginResponse = $loginQuery->fetch();
    if(empty($loginResponse["userid"])){
        return false;
    }elseif($loginid === $loginResponse["loginid"]){
        $userEncKey = GenUserEnckey($loginResponse["datetime"]);
        $userLoginKey = hash_hmac('sha256', $loginResponse["loginid"], $userEncKey);

        if(!(empty($loginkey))){
            if(hash_equals($loginkey, $userLoginKey)){
                if($operation_permission == "admin"){
                    if($loginResponse["admin"] == "yes"){
                        $is_login = true;
                    }else{
                        $is_login = false;
                        stopLoadAvg();
                    }
                }else{
                    $is_login = true;
                    stopLoadAvg();
                }
            }else{
                $is_login = false;
                stopLoadAvg();
            }
        }else{
            if(isset($session['userid']) && isset($session['username'])){
                if($session['userid'] === $loginResponse["userid"] && $session['username'] === $loginResponse["username"]){
                    if($operation_permission === "admin"){
                        if($loginResponse["admin"] == "yes"){
                            $is_login = true;
                        }else{
                            $is_login = false;
                            stopLoadAvg();
                        }
                    }else{
                        $is_login = true;
                        stopLoadAvg();
                    }
                }else{
                    $is_login = false;
                    stopLoadAvg();
                }
            }else if(isset($cookie['userid']) && isset($cookie['username'])){
                if($cookie['userid'] === $loginResponse["userid"] && $cookie['username'] === $loginResponse["username"]){
                    if($operation_permission === "admin"){
                        if($loginResponse["admin"] == "yes"){
                            $is_login = true;
                        }else{
                            $is_login = false;
                            stopLoadAvg();
                        }
                    }else{
                        $is_login = true;
                        stopLoadAvg();
                    }
                }else{
                    $is_login = false;
                    stopLoadAvg();
                }
            }else{
                $is_login = false;
                stopLoadAvg();
            }
        }

        if($is_login === true){
            $userid = safetext($loginResponse['userid']); // セッションに格納されている値をそのままセット
            $username = safetext($loginResponse['username']); // セッションに格納されている値をそのままセット
            $loginid = safetext($loginResponse["loginid"]);

            $_SESSION['userid'] = $userid;
            $_SESSION['username'] = $username;
            $_SESSION['loginid'] = $loginid;

            setcookie('loginid', $loginid,[
                'expires' => time() + 60 * 60 * 24 * 28,
                'path' => '/',
                'samesite' => 'lax',
                'secure' => true,
                'httponly' => true,
            ]);

            setcookie('loginkey', $userLoginKey,[
                'expires' => time() + 60 * 60 * 24 * 28,
                'path' => '/',
                'samesite' => 'lax',
                'secure' => true,
                'httponly' => true,
            ]);

            //IP保存が有効であれば保存する---------------------------------------------------
            if(safetext($serversettings["serverinfo"]["server_get_ip"]) === "true"){
                if(filter_var($ip_addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) || filter_var($ip_addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)){
                    $enc_ip_addr = EncryptionUseEncrKey($ip_addr, $userEncKey, $loginResponse["encryption_ivkey"]);
                    $pdo->beginTransaction();
                    try {
                        $updateQuery = $pdo->prepare("UPDATE account SET last_ip = :last_ip WHERE userid = :userid");
                        $updateQuery->bindValue(':last_ip', $enc_ip_addr, PDO::PARAM_STR);
                        $updateQuery->bindValue(':userid', $userid, PDO::PARAM_STR);
                        $res = $updateQuery->execute();

                        if($res){
                            $pdo->commit();
                        }else{
                            // ロールバック
                            $pdo->rollBack();
                            actionLog($userid, "error", "uwuzuUserLogin", null, "IPアドレスを記録できませんでした！", 3);
                        }
                    } catch (Exception $e) {
                        // ロールバック
                        $pdo->rollBack();
                        actionLog($userid, "error", "uwuzuUserLogin", null, $e, 4);
                    }
                }else{
                    actionLog($userid, "notice", "uwuzuUserLogin", null, "ユーザーのIPアドレスが不正な値でした！", 2);
                }
            }

            //JobがあればJobを実行する---------------------------------------------------
            $job = getJob($pdo, $userid);
            if(!(empty($job))){
                if($job["job"] == "deleteUser"){
                    deleteUser($pdo, $job["userid"], $job["step"], $job["uniqid"]);
                }
            }

            return $loginResponse;
        }else{
            return false;
        }
    }else{
        return false;
    }
}
//APIなどのログイン処理(loginidとloginkeyが有効かを確かめる)
function uwuzuUserLoginCheck($loginid, $loginkey, $operation_permission = "user") {
    //セッション,クッキー,IPアドレス,閲覧権限(userかadminかの二種類)を受け取る
    // データベースに接続
    try {
        $option = array(
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::MYSQL_ATTR_MULTI_STATEMENTS => false
        );
        $pdo = new PDO('mysql:charset=utf8mb4;dbname='.DB_NAME.';host='.DB_HOST , DB_USER, DB_PASS, $option);
    } catch(PDOException $e) {
        actionLog(null, "error", "uwuzuUserLogin", null, $e, 4);
        return false;
    }

    if(!(isset($loginid))){
        return false;
        exit;
    }

    if(!(isset($loginkey))){
        return false;
        exit;
    }

    $loginQuery = $pdo->prepare("SELECT * FROM account WHERE loginid = :loginid");
    $loginQuery->bindValue(':loginid', $loginid);
    $loginQuery->execute();
    $loginResponse = $loginQuery->fetch();
    if(empty($loginResponse["userid"])){
        return false;
    }elseif($loginid === $loginResponse["loginid"]){
        $userEncKey = GenUserEnckey($loginResponse["datetime"]);
        $userLoginKey = hash_hmac('sha256', $loginResponse["loginid"], $userEncKey);

        if(!(empty($loginkey))){
            if(hash_equals($loginkey, $userLoginKey)){
                if($operation_permission == "admin"){
                    if($loginResponse["admin"] == "yes"){
                        $is_login = true;
                    }else{
                        $is_login = false;
                    }
                }else{
                    $is_login = true;
                }
            }else{
                $is_login = false;
            }
        }else{
            $is_login = false;
        }

        return $is_login;
    }else{
        return false;
    }
}
//---------UNIQID-MAKER---------
function Legacy_createUniqId(){
    list($msec, $sec) = explode(" ", microtime());
    $hashCreateTime = $sec.floor($msec*1000000);

    $hashCreateTime = strrev($hashCreateTime);

    return base_convert($hashCreateTime,10,36);
}
function createUniqId($randDigits = 6) {
    $msec_time = (int)(microtime(true) * 1000);
    $randMax = pow(10, $randDigits) - 1;
    $rand_num = str_pad(random_int(0, $randMax), $randDigits, '0', STR_PAD_LEFT);
    $combined = $msec_time . $rand_num;
    return base_convert(strrev($combined), 10, 36);
}
function parseUniqId($id, $randDigits = 6) {
    $reversed_num_str = base_convert($id, 36, 10);
    $combined_num_str = strrev($reversed_num_str);
    $msec_time_str = substr($combined_num_str, 0, -$randDigits);
    return date("Y-m-d H:i:s.v", (int)($msec_time_str / 1000));
}
//----------EXIF_Delete----------
//EXIFを削除するやつです。
function rotate($image, $exif){
    $orientation = $exif['Orientation'] ?? 1;

    switch ($orientation) {
        case 1: //no rotate
            break;
        case 2: //FLIP_HORIZONTAL
            imageflip($image, IMG_FLIP_HORIZONTAL);
            break;
        case 3: //ROTATE 180
            $image = imagerotate($image, 180, 0);
            break;
        case 4: //FLIP_VERTICAL
            imageflip($image, IMG_FLIP_VERTICAL);
            break;
        case 5: //ROTATE 270 FLIP_HORIZONTAL
            $image = imagerotate($image, 270, 0);
            imageflip($image, IMG_FLIP_HORIZONTAL);
            break;
        case 6: //ROTATE 90
            $image = imagerotate($image, 270, 0);
            break;
        case 7: //ROTATE 90 FLIP_HORIZONTAL
            $image = imagerotate($image, 90, 0);
            imageflip($image, IMG_FLIP_HORIZONTAL);
            break;
        case 8: //ROTATE 270
            $image = imagerotate($image, 90, 0);
            break;
    }
    return $image;
}
function delete_exif($extension, $path){
    $exifimgext = array(
		"jpg",
		"jpeg",
		"jfif",
		"pjpeg",
		"pjp",
		"hdp",
		"wdp",
		"jxr",
		"tiff",
		"tif"
	);
	if(in_array($extension,$exifimgext)){
        if(check_mime($path) == "image/jpeg"){
            $gd = imagecreatefromjpeg($path);
            $w = imagesx($gd);
            $h = imagesy($gd);
            $gd_out = imagecreatetruecolor($w,$h);
            imagecopyresampled($gd_out, $gd, 0,0,0,0, $w,$h,$w,$h);
            $exif = exif_read_data($path);
            $gd_out = rotate($gd_out, $exif);
            imagejpeg($gd_out, $path);
            imagedestroy($gd_out);
        }
	}
}
//----------EXIF_Delete----------
//----------Check_Extension------
//ファイル形式チェック(画像かどうか)
function check_mime($tmp_name){
    $finfo = new finfo();
    $tmp_ext = $finfo->file($tmp_name, FILEINFO_MIME_TYPE);
    $safe_img_mime = array(
		"image/gif",
		"image/jpeg",
		"image/png",
		"image/webp",
        "image/bmp",
	);
	if(in_array($tmp_ext,$safe_img_mime)){
        return $tmp_ext;
    }else{
        return false;
    }
}
//ファイル形式チェック(画像かどうか)
function check_mime_video($tmp_name){
    $finfo = new finfo();
    $tmp_ext = $finfo->file($tmp_name, FILEINFO_MIME_TYPE);
    $safe_vid_mime = array(
		"video/mpeg",
		"video/mp4",
		"video/webm",
		"video/x-msvideo",
	);
	if(in_array($tmp_ext,$safe_vid_mime)){
        return $tmp_ext;
    }else{
        return false;
    }
}
function convert_mime($mime_type){
    $safe_img_mime = array(
        "image/gif" => 'gif',
        "image/jpeg" => 'jpg',
        "image/png" => 'png',
        "image/webp" => 'webp',
        "image/bmp" => 'bmp',
        "video/mpeg" => 'mpeg',
        "video/mp4" => 'mp4',
        "video/webm" => 'webm',
        "video/x-msvideo" => 'avi',
    );
    if(isset($safe_img_mime[$mime_type])){
        return $safe_img_mime[$mime_type];
    }else{
        return false;
    }
}
//ファイル形式チェック(Base64の場合)
function base64_mime($Base64,$userid){
    $Base64 = base64_decode($Base64);
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mime_type = finfo_buffer($finfo, $Base64);

    $safe_img_mime = [
		"image/gif" => 'gif',
		"image/jpeg" => 'jpg',
		"image/png" => 'png',
		"image/webp" => 'webp',
        "image/bmp" => 'bmp',
	];

    if(isset($safe_img_mime[$mime_type])){
        $extension = $safe_img_mime[$mime_type];
        $temp_file = tempnam(sys_get_temp_dir(), 'img');
        file_put_contents($temp_file, $Base64);

        delete_exif($extension, $temp_file);
        resizeImage($temp_file, 8192, 8192);

        if(check_mime($temp_file) == "image/webp"){
            $extension = 'webp';
        }

        $newFilename = createUniqId() . '-' . $userid . '.' . $extension;
        $uploadedPath = '../ueuseimages/' . $newFilename;

        $result = copy($temp_file, "../".$uploadedPath);
        if($result){
            return $uploadedPath;
        } else {
            return false;
        }
    } else {
        return false;
    }
}
//APIユーズと通常ユーズ統合時に使うのでけさない
function base64_to_files($Base64, $userid) {
    // Base64デコード
    $decodedData = base64_decode($Base64);
    if ($decodedData === false) {
        return false;
    }

    // MIMEタイプの検出
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mime_type = finfo_buffer($finfo, $decodedData);
    finfo_close($finfo);

    // 許可されているMIMEタイプと拡張子の対応
    $safe_img_mime = [
        "image/gif" => 'gif',
        "image/jpeg" => 'jpg',
        "image/png" => 'png',
        "image/webp" => 'webp',
        "image/bmp" => 'bmp',
    ];

    if (!(isset($safe_img_mime[$mime_type]))) {
        return false;
    }

    $extension = $safe_img_mime[$mime_type];

    // 一時ファイルを作成
    $temp_file = tempnam(sys_get_temp_dir(), 'img');
    file_put_contents($temp_file, $decodedData);

    // 必要に応じてEXIFデータを削除
    delete_exif($extension, $temp_file);
    resizeImage($temp_file, 8192, 8192);

    if(check_mime($temp_file) == "image/webp"){
        $extension = 'webp';
    }

    // ファイル名とアップロードパスを生成
    $newFilename = createUniqId() . '-' . $userid . '.' . $extension;

    // $_FILES形式の配列を作成して返す
    return [
        'name' => $newFilename,
        'type' => $mime_type,
        'tmp_name' => $temp_file,
        'error' => 0,
        'size' => filesize($temp_file),
    ];
}

function resizeImage($filePath, $maxWidth, $maxHeight) {
    if (file_exists($filePath)) {
        // 元の画像タイプを取得
        $imageType = check_mime($filePath);
        // 画像タイプに応じてリソースを作成
        if($imageType == "image/jpeg"){
            $originalImage = imagecreatefromjpeg($filePath);
        } elseif($imageType == "image/png") {
            $originalImage = imagecreatefrompng($filePath);
        } elseif($imageType == "image/webp") {
            $originalImage = imagecreatefromwebp($filePath);
        } elseif($imageType == "image/bmp") {
            $originalImage = imagecreatefrombmp($filePath);
        } else {
            return true;
        }

        // 元の画像のサイズを取得
        list($originalWidth, $originalHeight) = getimagesize($filePath);

        if ($originalWidth <= $maxWidth && $originalHeight <= $maxHeight) {
            imagewebp($originalImage, $filePath, 90);
            imagedestroy($originalImage);
            return true;
        }

        // 縦横比を計算
        $aspectRatio = $originalWidth / $originalHeight;

        // 新しいサイズを計算
        if ($maxWidth / $maxHeight > $aspectRatio) {
            $newWidth = $maxHeight * $aspectRatio;
            $newHeight = $maxHeight;
        } else {
            $newWidth = $maxWidth;
            $newHeight = $maxWidth / $aspectRatio;
        }

        // 新しい画像リソースを作成
        $resizedImage = imagecreatetruecolor($newWidth, $newHeight);
        // 画像をリサイズ
        imagecopyresampled($resizedImage, $originalImage, 0, 0, 0, 0, $newWidth, $newHeight, $originalWidth, $originalHeight);
        // リサイズされた画像を表示
        imagewebp($resizedImage, $filePath);
        // メモリの解放
        imagedestroy($originalImage);
        imagedestroy($resizedImage);

        return true;
    }
}

function uploadAmazonS3($tmp_name){
    if(check_mime_video($tmp_name) == false){
        $is_video = false;
    }else{
        $is_video = true;
    }
    $credentials = [
        'key'    => AMS3_ACCESSKEY,
        'secret' => AMS3_SECRETKEY,
    ];

    $bucket        = AMS3_BUCKET_NM;
    $srcFilePath   = $tmp_name;
    if($is_video == true){
        $mime = check_mime_video($srcFilePath);
        $extension = convert_mime($mime);
    }else{
        $mime = check_mime($srcFilePath);
        $extension = convert_mime($mime);
    }
    $key           = AMS3_PREFIX_NM.'/'.createUniqId().'' . '.' . $extension;

    if(AMS3_IS_S3FPS_ == 'true'){
        $S3FPS = true;
    }else{
        $S3FPS = false;
    }

    try {
        $s3Client = new Aws\S3\S3Client([
            'endpoint'    => AMS3_ENDPOINTS,
            'region'      => AMS3_REGION_NM,
            'version'     => 'latest',
            'credentials' => $credentials,
            'use_path_style_endpoint' => $S3FPS,
        ]);
        $result = $s3Client->putObject([
            'Bucket'     => $bucket,
            'Key'        => $key,
            'SourceFile' => $srcFilePath,
            'ContentType'	=> $mime,
        ]);
        if($result){
            $url = AMS3_BASE_URLS . '/' . $key;
            return $url;
        }else{
            actionLog(null, "error", "uploadAmazonS3", null, "アップロードに失敗しました", 4);
            return false;
        }
    } catch (Aws\S3\Exception\S3Exception $e) {
        actionLog(null, "error", "uploadAmazonS3", null, $e->getMessage(), 4);
        return false;
    }
}

function deleteAmazonS3($url){
    $key = explode("/", mb_substr(parse_url($url, PHP_URL_PATH), 1));
    if ($key[0] == AMS3_BUCKET_NM) {
        array_shift($key);
    }
    $key = implode("/", $key);

    $credentials = [
        'key'    => AMS3_ACCESSKEY,
        'secret' => AMS3_SECRETKEY,
    ];

    $bucket        = AMS3_BUCKET_NM;
    if(AMS3_IS_S3FPS_ == 'true'){
        $S3FPS = true;
    }else{
        $S3FPS = false;
    }

    try {
        $s3Client = new Aws\S3\S3Client([
            'endpoint'    => AMS3_ENDPOINTS,
            'region'      => AMS3_REGION_NM,
            'version'     => 'latest',
            'credentials' => $credentials,
            'use_path_style_endpoint' => $S3FPS,
        ]);
        $is_hasfile = $s3Client->doesObjectExistV2($bucket, $key, false, []);
        if($is_hasfile == true){
            $result = $s3Client->deleteObject([
                'Bucket'     => $bucket,
                'Key'        => $key
            ]);
            if($result){
                return true;
            }else{
                actionLog(null, "error", "deleteAmazonS3", null, "削除に失敗しました", 4);
                return false;
            }
        }else{
            actionLog(null, "error", "deleteAmazonS3", null, $key."が既に削除されていました", 1);
            return true;
        }
    } catch (Aws\S3\Exception\S3Exception $e) {
        actionLog(null, "error", "deleteAmazonS3", null, $e->getMessage(), 4);
        return false;
    }
}

//文字装飾・URL変換など
function processMarkdownAndWrapEmptyLines($markdownText) {
    $placeholders = [];

    // インラインコードをプレースホルダーに置き換える
    $markdownText = preg_replace_callback('/`([^`\n]+)`/', function($matches) use (&$placeholders) {
        $placeholder = 'PLACEHOLDER_' . count($placeholders);
        $placeholders[$placeholder] = '<span class="inline">' . $matches[1] . '</span>';
        return $placeholder;
    }, $markdownText);

    // ここから先の処理はインラインコードとコードブロックに影響しない

    $markdownText = preg_replace('/\[\[buruburu (.+)\]\]/m', '<span class="buruburu">$1</span>', $markdownText);//ぶるぶる

    $markdownText = preg_replace_callback('/\[\[time (\d+)\]\]/m', function($matches) {
        $timestamp = $matches[1];
        return '<span class="unixtime" title="'.date("Y/m/d H:i.s", htmlentities($timestamp, ENT_QUOTES, 'UTF-8', false)).'">' . date("Y/m/d H:i", htmlentities($timestamp, ENT_QUOTES, 'UTF-8', false)) . '</span>';
    }, $markdownText);

    //太字&斜体------------------------------------------------------------------------
    $markdownText = preg_replace('/\*\*\*(.+)\*\*\*(?=\s)/', '<b><i>$1</i></b>', $markdownText);//太字&斜体の全部のせセット
    $markdownText = preg_replace('/\*\*\*(.+)\*\*\*/', '<b><i>$1</i></b>', $markdownText);//太字&斜体の全部のせセット

    $markdownText = preg_replace('/\_\_\_(.+)\_\_\_(?=\s)/', '<b><i>$1</i></b>', $markdownText);//太字&斜体の全部のせセット
    $markdownText = preg_replace('/\b\_\_\_(.+)\_\_\_\b/', '<b><i>$1</i></b>', $markdownText);//太字&斜体の全部のせセット

    //太字-----------------------------------------------------------------------------
    $markdownText = preg_replace('/\*\*(.+)\*\*/', '<b>$1</b>', $markdownText);//太字
    $markdownText = preg_replace('/\b\*\*(.+)\*\*\b/', '<b>$1</b>', $markdownText);//太字

    $markdownText = preg_replace('/\_\_(.+)\_\_(?=\s)/', '<b>$1</b>', $markdownText);//太字
    $markdownText = preg_replace('/\b\_\_(.+)\_\_\b/', '<b>$1</b>', $markdownText);//太字

    //斜体-----------------------------------------------------------------------------
    $markdownText = preg_replace('/\*(.+)\*/', '<i>$1</i>', $markdownText);//斜体
    $markdownText = preg_replace('/\b\*(.+)\*\b/', '<i>$1</i>', $markdownText);//斜体

    $markdownText = preg_replace('/\_(.+)\_(?=\s)/', '<i>$1</i>', $markdownText);//斜体
    $markdownText = preg_replace('/\b\_(.+)\_\b/', '<i>$1</i>', $markdownText);//斜体

    $markdownText = preg_replace('/\~\~(.+)\~\~/m', '<s>$1</s>', $markdownText);//打ち消し線

    $markdownText = preg_replace('/&gt;&gt;&gt; (.+)/m', '<span class="quote">$1</span>', $markdownText);//>>> 引用

    $markdownText = preg_replace('/\|\|(.+)\|\|/m', '<span class="blur">$1</span>', $markdownText);//黒塗り

    // タイトル（#、##、###）をHTMLのhタグに変換
    $markdownText = preg_replace('/^# (.+)/m', '<h1>$1</h1>', $markdownText);
    $markdownText = preg_replace('/^## (.+)/m', '<h2>$1</h2>', $markdownText);
    $markdownText = preg_replace('/^### (.+)/m', '<h3>$1</h3>', $markdownText);

    // 箇条書き（-）をHTMLのul/liタグに変換
    $markdownText = preg_replace('/^- (.+)/m', '<p>・ $1</p>', $markdownText);

    // 空行の前に何もない行をHTMLのpタグに変換
    $markdownText = preg_replace('/(^\s*)(?!\s)(.*)/m', '$1<p>$2</p>', $markdownText);

    // プレースホルダーを元のコードに戻す
    foreach ($placeholders as $placeholder => $original) {
        $markdownText = str_replace($placeholder, $original, $markdownText);
    }

    return $markdownText;
}

//Profile
function replaceProfileEmojiImages($postText) {
    $postText = str_replace('&#039;', '\'', $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";
        }else{
            $emoji_path = $emoji_row["emojifile"];
        }
        return "<img src='../".$emoji_path."' alt=':$emojiName:' title=':$emojiName:'>";
    }, $postText);
    return $postTextWithImages;
}
// ユーズ内の絵文字やhashtagを画像に置き換える
function replaceEmojisWithImages($postText) {
    $postText = str_replace('&#039;', '\'', $postText);

    $emojiPattern = '/:(\w+):/';
    $postTextWithImages = preg_replace_callback($emojiPattern, function($matches) {
        $emojiName = $matches[1];
        $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);

    $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);

    $usernamePattern = '/@(\w+)/';
    $postTextWithUsernames = 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(
            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;
}
function replaceURLsWithLinks($postText, $maxLength = 48) {
    $pattern = '/(https:\/\/[\w!?\/+\-_~;.,*&@#$%()+|https:\/\/[ぁ-んァ-ヶ一-龠々\w\-\/?=&%.]+)/';
    $convertedText = preg_replace_callback($pattern, function($matches) use ($maxLength) {
        $link = $matches[0];
        if(!(preg_match('/:(\w+):/',$link))){
            $no_https_link = preg_replace('/https:\/\//', '', $link, 1);
            if (mb_strlen($link) > $maxLength) {
                $truncatedLink = mb_substr($no_https_link, 0, $maxLength).'...';
                return '<a href="'.$link.'" target="_blank">'.$truncatedLink.'</a>';
            } else {
                return '<a href="'.$link.'" target="_blank">'.$no_https_link.'</a>';
            }
        }else{
            return $link;
        }
    }, $postText);

    return $convertedText;
}
function YouTube_and_nicovideo_Links($postText) {
    // URLを正規表現を使って検出
    $pattern = '/(https:\/\/[^\s<>\[\]\'"]+)/';  // 改良された正規表現
    preg_match_all($pattern, $postText, $matches);

    if(empty($url)){
        $postText = "";
    }

    // 検出したURLごとに処理を行う
    foreach ($matches[0] as $url) {
        // ドメイン部分を抽出
        $parsedUrl = parse_url($url);
        if(!(empty($parsedUrl['host']))){
            $video_time = "0";
            $video_id = "";

            if($parsedUrl['host'] == "youtube.com" || $parsedUrl['host'] == "youtu.be" || $parsedUrl['host'] == "www.youtube.com" || $parsedUrl['host'] == "m.youtube.com"){
                if (isset($parsedUrl['query'])) {
                    // クエリ部分を連想配列に変換する
                    parse_str($parsedUrl['query'], $queryParams);

                    // video_idの取得
                    if (isset($queryParams['v'])) {
                        $video_id = safetext($queryParams['v']);
                        $iframe = true;
                    } else {
                        $video_id = str_replace('/', '', safetext($parsedUrl['path']));
                        $iframe = true;
                    }
                    // video_timeの取得
                    if (isset($queryParams['amp;t'])) {
                        $video_time = safetext($queryParams['amp;t']);
                        if(!(is_numeric($video_time))){
                            $video_time = "0";
                        }
                    } else {
                        $video_time = "0";
                    }
                    $video_id = str_replace('&amp;', '?', $video_id);
                } elseif (isset($parsedUrl['path'])) {
                    if (preg_match('/^\/watch\/|^\/embed\/|^\/shorts\/|^\/v\/|\//', $parsedUrl['path'])) {
                        $video_id = str_replace('/', '', htmlentities($parsedUrl['path'], ENT_QUOTES, 'UTF-8', false));
                        $video_time = 0;
                        $iframe = true;
                    } else {
                        // チャンネルや他のパスの場合は動画IDを取得しない
                        $video_id = "";
                        $video_time = 0;
                        $iframe = false;
                    }
                } else {
                    $video_id = "";
                    $video_time = "0";
                    $iframe = false;
                }

                // 不要な文字を削除してaタグを生成
                if ($iframe) {
                    $link = '<iframe src="https://www.youtube-nocookie.com/embed/'.$video_id.'?start='.$video_time.'" rel="0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>';
                } else {
                    $link = "";
                }

                // URLをドメインのみを表示するaタグで置き換え
                $postText = $link;
            }elseif($parsedUrl['host'] == "nicovideo.jp" || $parsedUrl['host'] == "www.nicovideo.jp" || $parsedUrl['host'] == "nico.ms"){
                if(isset($parsedUrl['path'])){
                    $video_id = str_replace('/','',str_replace('/watch/', '', safetext($parsedUrl['path'])));
                    $iframe = true;
                }else{
                    $video_id = "";
                    $iframe = false;
                }
                if (isset($parsedUrl['query'])) {
                    // クエリ部分を連想配列に変換する
                    parse_str($parsedUrl['query'], $queryParams);

                    // video_timeの取得
                    if (isset($queryParams['from'])) {
                        $video_time = safetext($queryParams['from']);
                        if(!(is_numeric($video_time))){
                            $video_time = "0";
                        }
                    } else {
                        $video_time = "0";
                    }
                }
                // 不要な文字を削除してaタグを生成
                if($iframe == true){
                    $link = '<iframe src="https://embed.nicovideo.jp/watch/'.$video_id.'?from='.$video_time.'"</iframe>';
                }else{
                    $link = "";
                }
                // URLをドメインのみを表示するaタグで置き換え
                $postText = $link;
            }else{
                $postText = "";
            }
        }
    }

    return $postText;
}

function to_null($value) {
    $null_conditions = [
        "ueuse"  => "",
        "photo1" => "none",
        "photo2" => "none",
        "photo3" => "none",
        "photo4" => "none",
        "video1" => "none",
        "rpuniqid" => "",
        "ruuniqid" => "",
        "abi" => "none",
    ];

    foreach ($null_conditions as $key => $invalid_value) {
        if (isset($value[$key]) && $value[$key] === $invalid_value) {
            $value[$key] = null;
        }
    }

    return $value;
}

function UserAgent_to_Device($useragent) {
    if(preg_match('/Windows\sNT\s10.0/', $useragent)) {
        $device = "Windows 10/11";
    }elseif(preg_match('/Windows\sNT\s6.3/', $useragent)) {
        $device = "Windows 8.1";
    }elseif(preg_match('/Windows\sNT\s6.2/', $useragent)) {
        $device = "Windows 8";
    }elseif(preg_match('/Windows\sNT\s6.1/', $useragent)) {
        $device = "Windows 7";
    }elseif(preg_match('/Windows\sNT\s6.0/', $useragent)) {
        $device = "Windows Vista";
    }elseif(preg_match('/Windows\sNT\s5.2/', $useragent)) {
        $device = "Windows XP";
    }elseif(preg_match('/Windows\sNT\s5.1/', $useragent)) {
        $device = "Windows XP";
    }elseif(preg_match('/Windows\sPhone/', $useragent)) {
        $device = "Windows Phone";
    }elseif(preg_match('/iPhone/', $useragent)) {
        $device = "iPhone";
    }elseif(preg_match('/iPad/', $useragent)) {
        $device = "iPad";
    }elseif(preg_match('/iPod\stouch/', $useragent)) {
        $device = "iPod touch";
    }elseif(preg_match('/Mac\sOS\sX/', $useragent)) {
        $device = "macOS";
    }elseif(preg_match('/Android/', $useragent)) {
        $device = "Android";
    }elseif(preg_match('/BlackBerry/', $useragent)) {
        $device = "BlackBerry";
    }elseif(preg_match('/Linux/', $useragent)) {
        $device = "Linux";
    }elseif(preg_match('/Nintendo\sWiiU/', $useragent)) {
        $device = "Nintendo WiiU";
    }elseif(preg_match('/PlayStation\s4/', $useragent)) {
        $device = "PlayStation 4";
    }elseif(preg_match('/PlayStation\s5/', $useragent)) {
        $device = "PlayStation 5";
    }elseif(preg_match('/Nintendo\sSwitch/', $useragent)) {
        $device = "Nintendo Switch";
    }elseif(preg_match('/Nintendo\s3DS/', $useragent)) {
        $device = "Nintendo 3DS";
    }else{
        $device = "Others";
    }
    return $device;
}
function File_MaxUploadSize(){
    $memory_max = ini_get('memory_limit');
    $post_max = ini_get('post_max_size');
    $upload_max = ini_get('upload_max_filesize');
    if(!($memory_max == "-1")){
        $memory_max_s = return_bytes($memory_max);
    }else{
        $memory_max_s = PHP_INT_MAX;
    }
    if(!($post_max == "-1")){
        $post_max_s = return_bytes($post_max);
    }else{
        $post_max_s = PHP_INT_MAX;
    }
    if(!($upload_max == "-1")){
        $upload_max_s = return_bytes($upload_max);
    }else{
        $upload_max_s = PHP_INT_MAX;
    }

    if($memory_max_s >= $post_max_s){
        $maxsize = $post_max_s;
    }else{
        $maxsize = $memory_max_s;
    }

    if($maxsize >= $upload_max_s){
        $file_maxsize = $upload_max_s;
    }else{
        $file_maxsize = $maxsize;
    }
    return $file_maxsize;
}
function return_bytes($val) {
    $val = trim($val);
    $last = strtolower($val[strlen($val)-1]);
    $num = (int)str_replace($last, '', strtolower($val));
    if($last == "g"){
        $num *= 1024 * 1024 * 1024;
    }else if($last == "m"){
        $num *= 1024 * 1024;
    }else if($last == "k"){
        $num *= 1024;
    }else if($last == ""){
        $num = $num;
    }
    return $num;
}
function x1024($byte){
	$n_mb = $byte / 1024;
    return round($n_mb, 1);
}
function uwuzu_ver($select,$path){
    $softwaredata = file_get_contents($path);

    $softwaredata = explode( "\n", $softwaredata );
    $cnt = count( $softwaredata );
    for( $i=0;$i<$cnt;$i++ ){
        $software_info[$i] = ($softwaredata[$i]);
    }
    if($select == "name"){
        $ret = $software_info[0];
    }elseif($select == "ver_"){
        $ret = $software_info[1];
    }elseif($select == "date"){
        $ret = $software_info[2];
    }elseif($select == "dev_"){
        $ret = $software_info[3];
    }else{
        $ret = "no_data";
    }
    return htmlentities($ret, ENT_QUOTES, 'UTF-8', false);
}
function get_mentions_userid($postText) {
    // @useridを検出する
    $usernamePattern = '/@(\w+)/';
    $mentionedUsers = [];

    preg_replace_callback($usernamePattern, function($matches) use (&$mentionedUsers) {
        $mention_username = $matches[1];

        $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,
        ));

        $mention_userQuery = $dbh->prepare("SELECT username, userid FROM account WHERE userid = :userid");
        $mention_userQuery->bindValue(':userid', $mention_username);
        $mention_userQuery->execute();
        $mention_userData = $mention_userQuery->fetch();

        if (!empty($mention_userData)) {
            $mentionedUsers[] = strtolower($mention_username);
        }
    }, $postText);

    return $mentionedUsers;
}
function GenNotificationId($to, $from, $title, $message, $url, $category) {
    $data = "" . $to . ":" . $from . ":" . $title . ":" . $message . ":" . $url . ":" . $category;
    return hash('sha3-512', $data);
}

function send_notification($to,$from,$title,$message,$url,$category,$valueid = null){
    // データベースに接続
    try {
        $option = array(
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::MYSQL_ATTR_MULTI_STATEMENTS => false
        );
        $pdo = new PDO('mysql:charset=utf8mb4;dbname='.DB_NAME.';host='.DB_HOST , DB_USER, DB_PASS, $option);
    } catch(PDOException $e) {
        actionLog($from, "error", "send_notification", $to, $e, 4);
        return false;
    }

    if(!(strtolower($to) == strtolower($from)) || $category === "system" || $category === "other"){
        $to_result = getUserData($pdo, $to);

        $category_list = ["system","favorite","reply","reuse","ueuse","follow","mention","other", "login"];
        if(in_array($category, $category_list)){
            if(in_array($category, explode(',', $to_result["notification_settings"])) || empty($to_result["notification_settings"]) || $category === "system" || $category === "other"){
                //ブロックされてたら送らない
                if(!(in_array($from, explode(',', $to_result["blocklist"])))){
                    if(!(empty($valueid))){
                        if(mb_strlen($valueid) > 256){
                            $save_valueid = "";
                        }else{
                            $save_valueid = $valueid;
                        }
                    }else{
                        $save_valueid = "";
                    }
                    if(!(empty($pdo))){
                        $pdo->beginTransaction();
                        try {
                            $fromuserid = safetext($from);
                            $touserid = safetext($to);
                            $datetime = date("Y-m-d H:i:s");
                            $msg = safetext($message);
                            $title = safetext($title);
                            $url = safetext($url);
                            $userchk = 'none';
                            $notification_category = safetext($category);
                            $notification_id = GenNotificationId($touserid, $fromuserid, $title, $msg, $url, $notification_category);

                            // 通知用SQL作成
                            $stmt = $pdo->prepare("INSERT INTO notification (fromuserid, touserid, msg, url, datetime, userchk, title, category, notificationid, valueid) VALUES (:fromuserid, :touserid, :msg, :url, :datetime, :userchk, :title, :category, :notificationid, :valueid)");

                            $stmt->bindParam(':fromuserid', $fromuserid, PDO::PARAM_STR);
                            $stmt->bindParam(':touserid', $touserid, PDO::PARAM_STR);
                            $stmt->bindParam(':msg', $msg, PDO::PARAM_STR);
                            $stmt->bindParam(':url', $url, PDO::PARAM_STR);
                            $stmt->bindParam(':userchk', $userchk, PDO::PARAM_STR);
                            $stmt->bindParam(':title', $title, PDO::PARAM_STR);
                            $stmt->bindParam(':category', $notification_category, PDO::PARAM_STR);
                            $stmt->bindParam(':notificationid', $notification_id, PDO::PARAM_STR);

                            $stmt->bindParam(':valueid', $save_valueid, PDO::PARAM_STR);

                            $stmt->bindParam(':datetime', $datetime, PDO::PARAM_STR);

                            $res = $stmt->execute();

                            $res = $pdo->commit();

                            if($res){
                                return true;
                            }else{
                                $pdo->rollBack();
                                actionLog($from, "error", "send_notification", $to, "通知の送信に失敗しました(rollBack)", 3);
                                return false;
                            }

                        } catch(Exception $e) {
                            $pdo->rollBack();
                            actionLog($from, "error", "send_notification", $to, $e, 4);
                            return false;
                        }
                    }else{
                        return false;
                    }
                }else{
                    return true;
                }
            }else{
                // 受信しない設定なのでtrue
                return true;
            }
        }else{
            return false;
        }
    }else{
        // 送信元と送信先が同じなら送信しない
        return true;
    }
}

function delete_notification($to,$from,$title,$message,$url,$category){
    // データベースに接続
    try {
        $option = array(
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::MYSQL_ATTR_MULTI_STATEMENTS => false
        );
        $pdo = new PDO('mysql:charset=utf8mb4;dbname='.DB_NAME.';host='.DB_HOST , DB_USER, DB_PASS, $option);
    } catch(PDOException $e) {
        actionLog($from, "error", "send_notification", $to, $e, 4);
        return false;
    }

    if(!(strtolower($to) == strtolower($from)) || $category === "system" || $category === "other"){
        $to_result = getUserData($pdo, $to);

        $category_list = ["system","favorite","reply","reuse","ueuse","follow","mention","other", "login"];
        if(in_array($category, $category_list)){
            if(in_array($category, explode(',', $to_result["notification_settings"])) || empty($to_result["notification_settings"]) || $category === "system" || $category === "other"){
                if(!(empty($pdo))){
                    $fromuserid = safetext($from);
                    $touserid = safetext($to);
                    $msg = safetext($message);
                    $title = safetext($title);
                    $url = safetext($url);
                    $notification_category = safetext($category);
                    $notification_id = GenNotificationId($touserid, $fromuserid, $title, $msg, $url, $notification_category);
                    $pdo->beginTransaction();
                    try {
                        // 削除クエリを実行
                        $deleteQuery = $pdo->prepare("DELETE FROM notification WHERE notificationid = :notificationid");
                        $deleteQuery->bindValue(':notificationid', $notification_id, PDO::PARAM_STR);
                        $res = $deleteQuery->execute();

                        if ($res) {
                            $res = $pdo->commit();
                            return true;
                        } else {
                            $pdo->rollBack();
                            actionLog($from, "error", "delete_notification", $to, "通知の削除に失敗しました(rollBack)", 3);
                            return false;
                        }
                    } catch(PDOException $e) {
                        $pdo->rollBack();
                        actionLog($from, "error", "delete_notification", $to, $e, 4);
                        return false;
                    }
                }else{
                    return false;
                }
            }else{
                // 受信しない設定なのでtrue
                return true;
            }
        }else{
            return false;
        }
    }else{
        // 送信元と送信先が同じなら送信しない
        return true;
    }
}
// ユーズするとき全部この関数
function send_ueuse($userid,$rpUniqid,$ruUniqid,$ueuse,$photo1,$photo2,$photo3,$photo4,$video1,$nsfw,$aibwm){
    // AIBlockWaterMark--------------------------------------------
    require_once(__DIR__ . '/../settings_admin/plugin_settings/aiblockwatermark_settings.php');
    //------------------------------------------------------
    if ($aibwm === true && !empty(AIBWM_CHK) && AIBWM_CHK == "true") {
        if (file_exists(__DIR__ . '/../plugin/AIBlockWaterMark/aiblockwatermark.php')) {
            require(__DIR__ . '/../plugin/AIBlockWaterMark/aiblockwatermark.php');
        }
    }
    //------------------------------------------------------
    if (file_exists(__DIR__ . '/../settings_admin/plugin_settings/amazons3_settings.php')) {
        require_once(__DIR__ . '/../settings_admin/plugin_settings/amazons3_settings.php');
        if (defined('AMS3_CHKS') && AMS3_CHKS == "true") {
            if (file_exists(__DIR__ . '/../plugin/aws/aws-autoloader.php')) {
                require_once(__DIR__ . '/../plugin/aws/aws-autoloader.php');
            } else {
                actionLog(null, "error", "uploadAmazonS3", null, "AWS SDK for PHPが見つかりませんでした！", 4);
            }
        }
    } else {
        actionLog(null, "error", "uploadAmazonS3", null, "amazons3_settings.phpが見つかりませんでした！", 3);
    }

    $rpUniqid = safetext($rpUniqid);
    $ruUniqid = safetext($ruUniqid);
    $userid = safetext($userid);
    $ueuse = safetext($ueuse);
    $nsfw = safetext($nsfw);

    $error_message = array();
    $mojisizefile = __DIR__ . "/../server/textsize.txt";

    //投稿及び返信レート制限↓(分):デフォで60件/分まで
    if(!((int)RATE_LM === -1)){
        $max_ueuse_rate_limit = (int)RATE_LM;
    }else{
        $max_ueuse_rate_limit = PHP_INT_MAX;
    }

    $banurldomainfile = __DIR__ . "/../server/banurldomain.txt";
    $banurl_info = file_get_contents($banurldomainfile);
    $banurl = array_filter(preg_split("/\r\n|\n|\r/", $banurl_info));


    // データベースに接続
    try {
        $option = array(
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::MYSQL_ATTR_MULTI_STATEMENTS => false
        );
        $pdo = new PDO('mysql:charset=utf8mb4;dbname='.DB_NAME.';host='.DB_HOST , DB_USER, DB_PASS, $option);
    } catch(PDOException $e) {
        actionLog($userid, "error", "send_ueuse", null, $e, 4);
        return [false, "DB_ERROR"];
    }

    if(!(empty($pdo))){
        $uniqid = createUniqId();//最初に決めちゃう
        if(empty(getUeuseData($pdo, $uniqid))){

            $userData = getUserData($pdo, $userid);
            $username = safetext($userData["username"]);
            $userRoleList = explode(',', safetext($userData["role"]));
            if(in_array("ice", $userRoleList)){
                $error_message[] = 'アカウントが凍結されています。(ACCOUNT_HAS_BEEN_FROZEN)';
            }
            $ueuse = safetext($ueuse);
            if(safetext($nsfw) === "true"){
                $save_nsfw = "true";
            }else{
                $save_nsfw = "false";
            }

            if (($ueuse === '' || $ueuse === null) && empty($ruUniqid)) {
                $error_message[] = '内容を入力してください。(INPUT_PLEASE)';
            } else {
                // 文字数を確認
                if((int)safetext(file_get_contents($mojisizefile)) < mb_strlen($ueuse, 'UTF-8')) {
                    $error_message[] = '内容は'.safetext(file_get_contents($mojisizefile)).'文字以内で入力してください。(INPUT_OVER_MAX_COUNT)';
                }

                // 禁止url確認
                if(!(empty($banurl))){
                    for($i = 0; $i < count($banurl); $i++) {
                        if(!($banurl[$i] == "")){
                            if (false !== strpos($ueuse, 'https://'.$banurl[$i])) {
                                $error_message[] = '投稿が禁止されているURLが含まれています。(INPUT_CONTAINS_PROHIBITED_URL)';
                            }
                        }
                    }
                }

                // 改行ユーズ確認
                if(preg_match('/^\s+$/u', $ueuse) === 1){
                    $error_message[] = '内容を入力してください。(INPUT_PLEASE)';
                }
            }

            $old_datetime = date("Y-m-d H:i:00");
            $now_datetime = date("Y-m-d H:i:00",strtotime("+1 minute"));
            $rate_Query = $pdo->prepare("SELECT * FROM ueuse WHERE account = :userid AND TIME(datetime) BETWEEN :old_datetime AND :now_datetime");
            $rate_Query->bindValue(':userid', $userid);
            $rate_Query->bindValue(':old_datetime', $old_datetime);
            $rate_Query->bindValue(':now_datetime', $now_datetime);
            $rate_Query->execute();
            $rate_count = $rate_Query->rowCount();
            if(!($rate_count > $max_ueuse_rate_limit-1)){
                if(empty($error_message)) {
                    if (empty($photo1['name'])) {
                        $save_photo1 = "none";
                    } else {
                        // アップロードされたファイル情報
                        $uploadedFile = $photo1;

                        if(!(empty($uploadedFile['tmp_name']))){
                            if(check_mime($uploadedFile['tmp_name'])){
                                // アップロードされたファイルの拡張子を取得
                                $extension = convert_mime(check_mime($uploadedFile['tmp_name']));
                                delete_exif($extension, $uploadedFile['tmp_name']);
                                resizeImage($uploadedFile['tmp_name'], 8192, 8192);

                                if($aibwm === true){
                                    AIBlockWaterMark($uploadedFile['tmp_name'], $userid);
                                }
                                if(AMS3_CHKS == "true"){
                                    $s3result = uploadAmazonS3($uploadedFile['tmp_name']);
                                }else{
                                    if(check_mime($uploadedFile['tmp_name']) == "image/webp"){
                                        $extension = 'webp';
                                    }
                                    // 新しいファイル名を生成（uniqid + 拡張子）
                                    $newFilename = createUniqId() . '-'.$userid.'.' . $extension;
                                    // 保存先のパスを生成
                                    $uploadedPath = '../ueuseimages/' . $newFilename;
                                    // ファイルを移動
                                    $result = move_uploaded_file($uploadedFile['tmp_name'], __DIR__."/".$uploadedPath);

                                    if ($result) {
                                        $save_photo1 = $uploadedPath; // 保存されたファイルのパスを使用
                                    } else {
                                        $errnum = $uploadedFile['error'];
                                        if($errnum === 1){$errcode = "FILE_DEKASUGUI_PHP_INI_KAKUNIN";}
                                        if($errnum === 2){$errcode = "FILE_DEKASUGUI_HTML_KAKUNIN";}
                                        if($errnum === 3){$errcode = "FILE_SUKOSHIDAKE_UPLOAD";}
                                        if($errnum === 4){$errcode = "FILE_UPLOAD_DEKINAKATTA";}
                                        if($errnum === 6){$errcode = "TMP_FOLDER_NAI";}
                                        if($errnum === 7){$errcode = "FILE_KAKIKOMI_SIPPAI";}
                                        if($errnum === 8){$errcode = "PHPINFO()_KAKUNIN";}
                                        $error_message[] = 'アップロード失敗！(1)エラーコード：' .$errcode.'';
                                    }
                                }
                                if(isset($s3result)){
                                    if($s3result == false){
                                        $error_message[] = 'アップロード失敗！(1)エラーコード： S3ERROR';
                                    }else{
                                        $save_photo1 = $s3result; // S3に保存されたファイルのパスを使用
                                    }
                                }
                            }else{
                                $error_message[] = "使用できない画像形式です。(SORRY_FILE_HITAIOU)";
                            }
                        }else{
                            $error_message[] = "ファイルがアップロードできませんでした。(FILE_UPLOAD_DEKINAKATTA)";
                        }
                    }

                    if (empty($photo2['name'])) {
                        $save_photo2 = "none";
                    } else {
                        if (empty($photo1['name'])){
                            $error_message[] = '画像1から画像を選択してください！！！(PHOTO_SELECT_PLEASE)';
                        }
                        // アップロードされたファイル情報
                        $uploadedFile2 = $photo2;

                        if(!(empty($uploadedFile2['tmp_name']))){
                            if(check_mime($uploadedFile2['tmp_name'])){
                                // アップロードされたファイルの拡張子を取得
                                $extension2 = convert_mime(check_mime($uploadedFile2['tmp_name']));
                                delete_exif($extension2, $uploadedFile2['tmp_name']);
                                resizeImage($uploadedFile2['tmp_name'], 8192, 8192);
                                if($aibwm === true){
                                    AIBlockWaterMark($uploadedFile2['tmp_name'], $userid);
                                }
                                if(AMS3_CHKS == "true"){
                                    $s3result = uploadAmazonS3($uploadedFile2['tmp_name']);
                                }else{
                                    if(check_mime($uploadedFile2['tmp_name']) == "image/webp"){
                                        $extension2 = 'webp';
                                    }
                                    // 新しいファイル名を生成（uniqid + 拡張子）
                                    $newFilename2 = createUniqId() . '-'.$userid.'.' . $extension2;
                                    // 保存先のパスを生成
                                    $uploadedPath2 = '../ueuseimages/' . $newFilename2;
                                    // ファイルを移動
                                    $result2 = move_uploaded_file($uploadedFile2['tmp_name'], __DIR__."/".$uploadedPath2);
                                    if ($result2) {
                                        $save_photo2 = $uploadedPath2; // 保存されたファイルのパスを使用
                                    } else {
                                        $errnum = $uploadedFile2['error'];
                                        if($errnum === 1){$errcode = "FILE_DEKASUGUI_PHP_INI_KAKUNIN";}
                                        if($errnum === 2){$errcode = "FILE_DEKASUGUI_HTML_KAKUNIN";}
                                        if($errnum === 3){$errcode = "FILE_SUKOSHIDAKE_UPLOAD";}
                                        if($errnum === 4){$errcode = "FILE_UPLOAD_DEKINAKATTA";}
                                        if($errnum === 6){$errcode = "TMP_FOLDER_NAI";}
                                        if($errnum === 7){$errcode = "FILE_KAKIKOMI_SIPPAI";}
                                        if($errnum === 8){$errcode = "PHPINFO()_KAKUNIN";}
                                        $error_message[] = 'アップロード失敗！(2)エラーコード：' .$errcode.'';
                                    }
                                }
                                if(isset($s3result)){
                                    if($s3result == false){
                                        $error_message[] = 'アップロード失敗！(2)エラーコード： S3ERROR';
                                    }else{
                                        $save_photo2 = $s3result; // S3に保存されたファイルのパスを使用
                                    }
                                }
                            }else{
                                $error_message[] = "使用できない画像形式です。(SORRY_FILE_HITAIOU)";
                            }
                        }else{
                            $error_message[] = "ファイルがアップロードできませんでした。(FILE_UPLOAD_DEKINAKATTA)";
                        }
                    }

                    if (empty($photo3['name'])) {
                        $save_photo3 = "none";
                    } else {
                        if (empty($photo2['name'])){
                            $error_message[] = '画像2から画像を選択してください！！！(PHOTO_SELECT_PLEASE)';
                        }
                        // アップロードされたファイル情報
                        $uploadedFile3 = $photo3;

                        if(!(empty($uploadedFile3['tmp_name']))){
                            if(check_mime($uploadedFile3['tmp_name'])){
                                // アップロードされたファイルの拡張子を取得
                                $extension3 = convert_mime(check_mime($uploadedFile3['tmp_name']));
                                delete_exif($extension3, $uploadedFile3['tmp_name']);
                                resizeImage($uploadedFile3['tmp_name'], 8192, 8192);
                                if($aibwm === true){
                                    AIBlockWaterMark($uploadedFile3['tmp_name'], $userid);
                                }
                                if(AMS3_CHKS == "true"){
                                    $s3result = uploadAmazonS3($uploadedFile3['tmp_name']);
                                }else{
                                    if(check_mime($uploadedFile3['tmp_name']) == "image/webp"){
                                        $extension3 = 'webp';
                                    }
                                    // 新しいファイル名を生成（uniqid + 拡張子）
                                    $newFilename3 = createUniqId() . '-'.$userid.'.' . $extension3;
                                    // 保存先のパスを生成
                                    $uploadedPath3 = '../ueuseimages/' . $newFilename3;
                                    // ファイルを移動
                                    $result3 = move_uploaded_file($uploadedFile3['tmp_name'], __DIR__."/".$uploadedPath3);
                                    if ($result3) {
                                        $save_photo3 = $uploadedPath3; // 保存されたファイルのパスを使用
                                    } else {
                                        $errnum = $uploadedFile3['error'];
                                        if($errnum === 1){$errcode = "FILE_DEKASUGUI_PHP_INI_KAKUNIN";}
                                        if($errnum === 2){$errcode = "FILE_DEKASUGUI_HTML_KAKUNIN";}
                                        if($errnum === 3){$errcode = "FILE_SUKOSHIDAKE_UPLOAD";}
                                        if($errnum === 4){$errcode = "FILE_UPLOAD_DEKINAKATTA";}
                                        if($errnum === 6){$errcode = "TMP_FOLDER_NAI";}
                                        if($errnum === 7){$errcode = "FILE_KAKIKOMI_SIPPAI";}
                                        if($errnum === 8){$errcode = "PHPINFO()_KAKUNIN";}
                                        $error_message[] = 'アップロード失敗！(3)エラーコード：' .$errcode.'';
                                    }
                                }
                                if(isset($s3result)){
                                    if($s3result == false){
                                        $error_message[] = 'アップロード失敗！(3)エラーコード： S3ERROR';
                                    }else{
                                        $save_photo3 = $s3result; // S3に保存されたファイルのパスを使用
                                    }
                                }
                            }else{
                                $error_message[] = "使用できない画像形式です。(SORRY_FILE_HITAIOU)";
                            }
                        }else{
                            $error_message[] = "ファイルがアップロードできませんでした。(FILE_UPLOAD_DEKINAKATTA)";
                        }
                    }

                    if (empty($photo4['name'])) {
                        $save_photo4 = "none";
                    } else {
                        if (empty($photo3['name'])){
                            $error_message[] = '画像3から画像を選択してください！！！(PHOTO_SELECT_PLEASE)';
                        }
                        // アップロードされたファイル情報
                        $uploadedFile4 = $photo4;
                        if(!(empty($uploadedFile4['tmp_name']))){
                            if(check_mime($uploadedFile4['tmp_name'])){
                                // アップロードされたファイルの拡張子を取得
                                $extension4 = convert_mime(check_mime($uploadedFile4['tmp_name']));
                                delete_exif($extension4, $uploadedFile4['tmp_name']);
                                resizeImage($uploadedFile4['tmp_name'], 8192, 8192);
                                if($aibwm === true){
                                    AIBlockWaterMark($uploadedFile4['tmp_name'], $userid);
                                }
                                if(AMS3_CHKS == "true"){
                                    $s3result = uploadAmazonS3($uploadedFile4['tmp_name']);
                                }else{
                                    if(check_mime($uploadedFile4['tmp_name']) == "image/webp"){
                                        $extension4 = 'webp';
                                    }
                                    // 新しいファイル名を生成（uniqid + 拡張子）
                                    $newFilename4 = createUniqId() . '-'.$userid.'.' . $extension4;
                                    // 保存先のパスを生成
                                    $uploadedPath4 = '../ueuseimages/' . $newFilename4;
                                    // ファイルを移動
                                    $result4 = move_uploaded_file($uploadedFile4['tmp_name'], __DIR__."/".$uploadedPath4);
                                    if ($result4) {
                                        $save_photo4 = $uploadedPath4; // 保存されたファイルのパスを使用
                                    } else {
                                        $errnum = $uploadedFile4['error'];
                                        if($errnum === 1){$errcode = "FILE_DEKASUGUI_PHP_INI_KAKUNIN";}
                                        if($errnum === 2){$errcode = "FILE_DEKASUGUI_HTML_KAKUNIN";}
                                        if($errnum === 3){$errcode = "FILE_SUKOSHIDAKE_UPLOAD";}
                                        if($errnum === 4){$errcode = "FILE_UPLOAD_DEKINAKATTA";}
                                        if($errnum === 6){$errcode = "TMP_FOLDER_NAI";}
                                        if($errnum === 7){$errcode = "FILE_KAKIKOMI_SIPPAI";}
                                        if($errnum === 8){$errcode = "PHPINFO()_KAKUNIN";}
                                        $error_message[] = 'アップロード失敗！(4)エラーコード：' .$errcode.'';
                                    }
                                }
                                if(isset($s3result)){
                                    if($s3result == false){
                                        $error_message[] = 'アップロード失敗！(1)エラーコード： S3ERROR';
                                    }else{
                                        $save_photo4 = $s3result; // S3に保存されたファイルのパスを使用
                                    }
                                }
                            }else{
                                $error_message[] = "使用できない画像形式です。(SORRY_FILE_HITAIOU)";
                            }
                        }else{
                            $error_message[] = "ファイルがアップロードできませんでした。(FILE_UPLOAD_DEKINAKATTA)";
                        }
                    }

                    if (empty($video1['name'])) {
                        $save_video1 = "none";
                    } else {
                        // アップロードされたファイル情報
                        $uploadedVideo = $video1;

                        if(!(empty($uploadedVideo['tmp_name']))){
                            if(check_mime_video($uploadedVideo['tmp_name'])){
                                if(AMS3_CHKS == "true"){
                                    $s3result = uploadAmazonS3($uploadedVideo['tmp_name']);
                                }else{
                                    // アップロードされたファイルの拡張子を取得
                                    $extensionVideo = convert_mime(check_mime_video($uploadedVideo['tmp_name']));
                                    // 正しい拡張子の場合、新しいファイル名を生成
                                    $newFilenameVideo = createUniqId() . '-'.$userid.'.' . $extensionVideo;
                                    // 保存先のパスを生成
                                    $uploadedPathVideo = '../ueusevideos/' . $newFilenameVideo;
                                    // ファイルを移動
                                    $resultVideo = move_uploaded_file($uploadedVideo['tmp_name'], __DIR__."/".$uploadedPathVideo);
                                    if ($resultVideo) {
                                        $save_video1 = $uploadedPathVideo; // 保存されたファイルのパスを使用
                                    } else {
                                        $errnum = $uploadedVideo['error'];
                                        if($errnum === 1){$errcode = "FILE_DEKASUGUI_PHP_INI_KAKUNIN";}
                                        if($errnum === 2){$errcode = "FILE_DEKASUGUI_HTML_KAKUNIN";}
                                        if($errnum === 3){$errcode = "FILE_SUKOSHIDAKE_UPLOAD";}
                                        if($errnum === 4){$errcode = "FILE_UPLOAD_DEKINAKATTA";}
                                        if($errnum === 6){$errcode = "TMP_FOLDER_NAI";}
                                        if($errnum === 7){$errcode = "FILE_KAKIKOMI_SIPPAI";}
                                        if($errnum === 8){$errcode = "PHPINFO()_KAKUNIN";}
                                        $error_message[] = 'アップロード失敗！(5)エラーコード：' .$errcode.'';
                                    }
                                }
                                if(isset($s3result)){
                                    if($s3result == false){
                                        $error_message[] = 'アップロード失敗！(5)エラーコード： S3ERROR';
                                    }else{
                                        $save_video1 = $s3result; // S3に保存されたファイルのパスを使用
                                    }
                                }
                            } else {
                                $error_message[] = '対応していないファイル形式です！(SORRY_FILE_HITAIOU)';
                            }
                        }else{
                            $error_message[] = "ファイルがアップロードできませんでした。(FILE_UPLOAD_DEKINAKATTA)";
                        }
                    }

                    if(empty($error_message)) {
                        // 書き込み日時を取得
                        $datetime = date("Y-m-d H:i:s");
                        $abi = "none";
                        $popularity = 0;
                        $mentionedUsers = array_unique(get_mentions_userid($ueuse));
                        $mentions = implode(",", $mentionedUsers);

                        if(empty($rpUniqid) && empty($ruUniqid)){
                            //-----------通常ユーズ-----------
                            // トランザクション開始
                            $pdo->beginTransaction();

                            try {

                                // SQL作成
                                $stmt = $pdo->prepare("INSERT INTO ueuse (username, account, uniqid, ueuse, photo1, photo2, photo3, photo4, video1, datetime, abi, nsfw, popularity, mentions) VALUES (:username, :account, :uniqid, :ueuse, :photo1, :photo2, :photo3, :photo4, :video1, :datetime, :abi, :nsfw, :popularity, :mentions)");

                                $stmt->bindParam(':username', $username, PDO::PARAM_STR);
                                $stmt->bindParam(':account', $userid, PDO::PARAM_STR);
                                $stmt->bindParam(':uniqid', $uniqid, PDO::PARAM_STR);
                                $stmt->bindParam(':ueuse', $ueuse, PDO::PARAM_STR);

                                $stmt->bindParam(':photo1', $save_photo1, PDO::PARAM_STR);
                                $stmt->bindParam(':photo2', $save_photo2, PDO::PARAM_STR);
                                $stmt->bindParam(':photo3', $save_photo3, PDO::PARAM_STR);
                                $stmt->bindParam(':photo4', $save_photo4, PDO::PARAM_STR);
                                $stmt->bindParam(':video1', $save_video1, PDO::PARAM_STR);
                                $stmt->bindParam(':datetime', $datetime, PDO::PARAM_STR);

                                $stmt->bindParam(':nsfw', $save_nsfw, PDO::PARAM_STR);
                                $stmt->bindParam(':popularity', $popularity, PDO::PARAM_INT);

                                $stmt->bindParam(':mentions', $mentions, PDO::PARAM_STR);

                                $stmt->bindParam(':abi', $abi, PDO::PARAM_STR);

                                // SQLクエリの実行
                                $res = $stmt->execute();

                                // コミット
                                $res = $pdo->commit();

                                foreach ($mentionedUsers as $mentionedUser) {
                                    send_notification($mentionedUser,$userid,"".$userid."さんにメンションされました！",$ueuse,"/!".$uniqid."", "mention", $uniqid);
                                }

                            } catch(Exception $e) {
                                // エラーが発生した時はロールバック
                                $pdo->rollBack();
                                actionLog($userid, "error", "send_ueuse", null, $e, 4);
                            }
                        }elseif((!empty($rpUniqid)) && empty($ruUniqid)){
                            //-----------リプライ-----------
                            $toUserIdQuery = $pdo->prepare("SELECT account FROM ueuse WHERE uniqid = :ueuseid ORDER BY datetime ASC LIMIT 1");
                            $toUserIdQuery->bindValue(':ueuseid', $rpUniqid, PDO::PARAM_STR);
                            $toUserIdQuery->execute();
                            $toUserId_res = $toUserIdQuery->fetch();

                            if(!(empty($toUserId_res))){
                                $touserid = $toUserId_res["account"];
                            }else{
                                $touserid = null;
                            }

                            changePopularity($pdo, $rpUniqid, $userid, 3);
                            // トランザクション開始
                            $pdo->beginTransaction();

                            try {
                                // SQL作成
                                $stmt = $pdo->prepare("INSERT INTO ueuse (username, account, uniqid, rpuniqid, ueuse, photo1, photo2, photo3, photo4, video1, datetime, abi, nsfw, popularity, mentions) VALUES (:username, :account, :uniqid, :rpuniqid, :ueuse, :photo1, :photo2, :photo3, :photo4, :video1, :datetime, :abi, :nsfw, :popularity, :mentions)");

                                $stmt->bindParam(':username', $username, PDO::PARAM_STR);
                                $stmt->bindParam(':account', $userid, PDO::PARAM_STR);
                                $stmt->bindParam(':uniqid', $uniqid, PDO::PARAM_STR);
                                $stmt->bindParam(':rpuniqid', $rpUniqid, PDO::PARAM_STR);
                                $stmt->bindParam(':ueuse', $ueuse, PDO::PARAM_STR);

                                $stmt->bindParam(':photo1', $save_photo1, PDO::PARAM_STR);
                                $stmt->bindParam(':photo2', $save_photo2, PDO::PARAM_STR);
                                $stmt->bindParam(':photo3', $save_photo3, PDO::PARAM_STR);
                                $stmt->bindParam(':photo4', $save_photo4, PDO::PARAM_STR);
                                $stmt->bindParam(':video1', $save_video1, PDO::PARAM_STR);
                                $stmt->bindParam(':datetime', $datetime, PDO::PARAM_STR);

                                $stmt->bindParam(':nsfw', $save_nsfw, PDO::PARAM_STR);

                                $stmt->bindParam(':abi', $abi, PDO::PARAM_STR);
                                $stmt->bindParam(':popularity', $popularity, PDO::PARAM_INT);
                                $stmt->bindParam(':mentions', $mentions, PDO::PARAM_STR);

                                // SQLクエリの実行
                                $res = $stmt->execute();

                                // コミット
                                $res = $pdo->commit();

                                foreach ($mentionedUsers as $mentionedUser) {
                                    send_notification($mentionedUser,$userid,"".$userid."さんにメンションされました！",$ueuse,"/!".$uniqid."", "mention", $uniqid);
                                }

                                send_notification($touserid,$userid,"".$userid."さんが返信しました！",$ueuse,"/!".$uniqid."", "reply", $uniqid);
                            } catch(Exception $e) {
                                // エラーが発生した時はロールバック
                                $pdo->rollBack();
                                actionLog($userid, "error", "send_ueuse", null, $e, 4);
                            }
                        }elseif(empty($rpUniqid) && (!empty($ruUniqid))){
                            //-----------リユーズ-----------
                            $toUserIdQuery = $pdo->prepare("SELECT account FROM ueuse WHERE uniqid = :ueuseid ORDER BY datetime ASC LIMIT 1");
                            $toUserIdQuery->bindValue(':ueuseid', $ruUniqid, PDO::PARAM_STR);
                            $toUserIdQuery->execute();
                            $toUserId_res = $toUserIdQuery->fetch();

                            if(!(empty($toUserId_res))){
                                $touserid = $toUserId_res["account"];
                            }else{
                                $touserid = null;
                            }

                            changePopularity($pdo, $ruUniqid, $userid, 2);

                            // トランザクション開始
                            $pdo->beginTransaction();

                            try {
                                // SQL作成
                                $stmt = $pdo->prepare("INSERT INTO ueuse (username, account, uniqid, ruuniqid, ueuse, photo1, photo2, photo3, photo4, video1, datetime, abi, nsfw, popularity, mentions) VALUES (:username, :account, :uniqid, :ruuniqid, :ueuse, :photo1, :photo2, :photo3, :photo4, :video1, :datetime, :abi, :nsfw, :popularity, :mentions)");

                                $stmt->bindParam(':username', $username, PDO::PARAM_STR);
                                $stmt->bindParam(':account', $userid, PDO::PARAM_STR);
                                $stmt->bindParam(':uniqid', $uniqid, PDO::PARAM_STR);
                                $stmt->bindParam(':ruuniqid', $ruUniqid, PDO::PARAM_STR);
                                $stmt->bindParam(':ueuse', $ueuse, PDO::PARAM_STR);

                                $stmt->bindParam(':photo1', $save_photo1, PDO::PARAM_STR);
                                $stmt->bindParam(':photo2', $save_photo2, PDO::PARAM_STR);
                                $stmt->bindParam(':photo3', $save_photo3, PDO::PARAM_STR);
                                $stmt->bindParam(':photo4', $save_photo4, PDO::PARAM_STR);
                                $stmt->bindParam(':video1', $save_video1, PDO::PARAM_STR);
                                $stmt->bindParam(':datetime', $datetime, PDO::PARAM_STR);

                                $stmt->bindParam(':nsfw', $save_nsfw, PDO::PARAM_STR);

                                $stmt->bindParam(':abi', $abi, PDO::PARAM_STR);
                                $stmt->bindParam(':popularity', $popularity, PDO::PARAM_INT);
                                $stmt->bindParam(':mentions', $mentions, PDO::PARAM_STR);


                                // SQLクエリの実行
                                $res = $stmt->execute();

                                // コミット
                                $res = $pdo->commit();

                                foreach ($mentionedUsers as $mentionedUser) {
                                    send_notification($mentionedUser,$userid,"".$userid."さんにメンションされました！",$ueuse,"/!".$uniqid."", "mention", $uniqid);
                                }

                                send_notification($touserid,$userid,"".$userid."さんがリユーズしました！",$ueuse,"/!".$uniqid."", "reuse", $uniqid);

                            } catch(Exception $e) {
                                // エラーが発生した時はロールバック
                                $pdo->rollBack();
                                actionLog($userid, "error", "send_ueuse", null, $e, 4);
                            }
                        }else{
                            $error_message[] = '返信とリユーズを同時に行うことはできません。(ERROR)';
                            return [false, $error_message];
                        }

                        if( $res ) {
                            return [true, $uniqid];
                        } else {
                            $error_message[] = "ユーズに失敗しました。(REGISTERED_DAME)";
                            return [false, $error_message];
                        }

                        // プリペアドステートメントを削除
                        $stmt = null;
                    }else{
                        actionLog($userid, "error", "send_ueuse", null, $error_message, 0);
                        return [false, $error_message];
                    }
                }else{
                    actionLog($userid, "error", "send_ueuse", null, $error_message, 0);
                    return [false, $error_message];
                }
            }else{
                $error_message[] = "投稿回数のレート制限を超過しています。(OVER_RATE_LIMIT)";
                actionLog($userid, "error", "send_ueuse", null, $error_message, 0);
                return [false, $error_message];
            }
        }else{
            $error_message[] = "ユーズのIDに問題が発生しました。(ERROR)";
            actionLog($userid, "error", "send_ueuse", null, $error_message, 4);
            return [false, $error_message];
        }
    }
}

function delete_ueuse($uniqid, $userid, $account_id){
    if(file_exists(__DIR__ . "/../settings_admin/plugin_settings/amazons3_settings.php")){
        require_once __DIR__ . '/../settings_admin/plugin_settings/amazons3_settings.php';
        if(AMS3_CHKS == "true"){
            if(file_exists(__DIR__ . "/../plugin/aws/aws-autoloader.php")){
                require_once __DIR__ . '/../plugin/aws/aws-autoloader.php';
            }else{
                actionLog(null, "error", "delete_ueuse", null, "AWS SDK for PHPが見つかりませんでした！", 4);
            }
        }
    }else{
        actionLog(null, "error", "delete_ueuse", null, "amazons3_settings.phpが見つかりませんでした！", 3);
    }

    if (safetext(isset($uniqid)) && safetext(isset($userid)) && safetext(isset($account_id))){
        $postUserid = safetext($userid);
        $postUniqid = safetext($uniqid);
        $loginid = safetext($account_id);

        try {
            $option = array(
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::MYSQL_ATTR_MULTI_STATEMENTS => false
            );
            $pdo = new PDO('mysql:charset=utf8mb4;dbname=' . DB_NAME . ';host=' . DB_HOST, DB_USER, DB_PASS, $option);
        } catch (PDOException $e) {
            // 接続エラーのときエラー内容を取得する
            $error_message[] = $e->getMessage();
            actionLog($userid, "error", "delete_ueuse", null, $e, 4);
        }

        $query = $pdo->prepare('SELECT * FROM ueuse WHERE uniqid = :uniqid limit 1');
        $query->execute(array(':uniqid' => $postUniqid));
        $result = $query->fetch();

        if($result > 0){
            if($result["account"] === $postUserid){
                $query = $pdo->prepare('SELECT * FROM account WHERE userid = :userid limit 1');
                $query->execute(array(':userid' => $postUserid));
                $result2 = $query->fetch();

                if($result2["loginid"] === $loginid){
                    $photo_query = $pdo->prepare("SELECT * FROM ueuse WHERE account = :userid AND uniqid = :uniqid");
                    $photo_query->bindValue(':userid', $postUserid);
                    $photo_query->bindValue(':uniqid', $postUniqid);
                    $photo_query->execute();
                    $photo_and_video = $photo_query->fetch();

                    if(!($photo_and_video["photo1"] == "none")){
                        if(filter_var($photo_and_video["photo1"], FILTER_VALIDATE_URL)){
                            if(AMS3_CHKS == "true"){
                                deleteAmazonS3($photo_and_video["photo1"]);
                            }
                        }else{
                            $photoDelete1 = glob($photo_and_video["photo1"]); // 「-ユーザーID.拡張子」というパターンを検索
                            foreach ($photoDelete1 as $photo1) {
                                if (is_file($photo1)) {
                                    unlink($photo1);
                                }
                            }
                        }
                    }
                    if(!($photo_and_video["photo2"] == "none")){
                        if(filter_var($photo_and_video["photo2"], FILTER_VALIDATE_URL)){
                            if(AMS3_CHKS == "true"){
                                deleteAmazonS3($photo_and_video["photo2"]);
                            }
                        }else{
                            $photoDelete2 = glob($photo_and_video["photo2"]); // 「-ユーザーID.拡張子」というパターンを検索
                            foreach ($photoDelete2 as $photo2) {
                                if (is_file($photo2)) {
                                    unlink($photo2);
                                }
                            }
                        }
                    }
                    if(!($photo_and_video["photo3"] == "none")){
                        if(filter_var($photo_and_video["photo3"], FILTER_VALIDATE_URL)){
                            if(AMS3_CHKS == "true"){
                                deleteAmazonS3($photo_and_video["photo3"]);
                            }
                        }else{
                            $photoDelete3 = glob($photo_and_video["photo3"]); // 「-ユーザーID.拡張子」というパターンを検索
                            foreach ($photoDelete3 as $photo3) {
                                if (is_file($photo3)) {
                                    unlink($photo3);
                                }
                            }
                        }
                    }
                    if(!($photo_and_video["photo4"] == "none")){
                        if(filter_var($photo_and_video["photo4"], FILTER_VALIDATE_URL)){
                            if(AMS3_CHKS == "true"){
                                deleteAmazonS3($photo_and_video["photo4"]);
                            }
                        }else{
                            $photoDelete4 = glob($photo_and_video["photo4"]); // 「-ユーザーID.拡張子」というパターンを検索
                            foreach ($photoDelete4 as $photo4) {
                                if (is_file($photo4)) {
                                    unlink($photo4);
                                }
                            }
                        }
                    }
                    if(!($photo_and_video["video1"] == "none")){
                        if(filter_var($photo_and_video["video1"], FILTER_VALIDATE_URL)){
                            if(AMS3_CHKS == "true"){
                                deleteAmazonS3($photo_and_video["video1"]);
                            }
                        }else{
                            $videoDelete1 = glob($photo_and_video["video1"]); // 「-ユーザーID.拡張子」というパターンを検索
                            foreach ($videoDelete1 as $video1) {
                                if (is_file($video1)) {
                                    unlink($video1);
                                }
                            }
                        }
                    }

                    $ruChkquery = $pdo->prepare('SELECT * FROM ueuse WHERE ruuniqid = :uniqid AND ueuse = "" limit 1');
                    $ruChkquery->execute(array(':uniqid' => $postUniqid));
                    $result3 = $ruChkquery->fetch();

                    if($result3 > 0){
                        // トランザクション開始
                        $pdo->beginTransaction();
                        try {
                            // 削除クエリを実行
                            $rudeleteQuery = $pdo->prepare("DELETE FROM ueuse WHERE ruuniqid = :uniqid AND ueuse = ''");
                            $rudeleteQuery->bindValue(':uniqid', $postUniqid, PDO::PARAM_STR);
                            $res = $rudeleteQuery->execute();

                            if (!($res)){
                                $pdo->rollBack();
                                $error_message[] = "リユーズの削除ができませんでした。";
                                actionLog($userid, "error", "delete_ueuse", null, $error_message, 3);
                            }else{
                                $pdo->commit();
                            }
                        } catch(PDOException $e) {
                            $pdo->rollBack();
                            $error_message[] = 'データベースエラー：' . $e->getMessage();
                            actionLog($userid, "error", "delete_ueuse", null, $e, 4);
                        }
                    }

                    $ru_tree_Chkquery = $pdo->prepare('SELECT * FROM ueuse WHERE uniqid = :ruuniqid limit 1');
                    $ru_tree_Chkquery->execute(array(':ruuniqid' => $result["ruuniqid"]));
                    $result4 = $ru_tree_Chkquery->fetch();
                    if($result4 > 0){
                        changePopularity($pdo, $result["ruuniqid"], $userid, -2);
                    }

                    $rp_tree_Chkquery = $pdo->prepare('SELECT * FROM ueuse WHERE uniqid = :rpuniqid limit 1');
                    $rp_tree_Chkquery->execute(array(':rpuniqid' => $result["rpuniqid"]));
                    $result5 = $rp_tree_Chkquery->fetch();
                    if($result5 > 0){
                        changePopularity($pdo, $result["rpuniqid"], $userid, -3);
                    }

                    // トランザクション開始
                    $pdo->beginTransaction();
                    try {
                        // 削除クエリを実行
                        $deleteQuery = $pdo->prepare("DELETE FROM ueuse WHERE uniqid = :uniqid AND account = :userid");
                        $deleteQuery->bindValue(':uniqid', $postUniqid, PDO::PARAM_STR);
                        $deleteQuery->bindValue(':userid', $postUserid, PDO::PARAM_STR);
                        $res = $deleteQuery->execute();

                        if ($res) {
                            $pdo->commit();
                            return [true, "削除に成功しました！"];
                        } else {
                            $pdo->rollBack();
                            return [false, "削除に失敗しました"];
                        }
                    } catch(PDOException $e) {
                        $pdo->rollBack();
                        actionLog($userid, "error", "delete_ueuse", null, $e, 4);
                        return [false, "削除に失敗しました！"];
                    }
                }
            }else{
                return [false, "削除に失敗しました！"];
            }
        }else{
            return [true, "すでに削除しています"];
        }
    }else{
        return [true, "削除に成功しました！"];
    }
}
// SQL操作関数pdo引っ張ってくるように変更(あとでほかもする)
function follow_user($pdo, $to_userid, $userid){
    if (!(empty($pdo)) && !(empty($to_userid)) && !(empty($userid))){
        $myData = getUserData($pdo, $userid);
        $userData = getUserData($pdo, $to_userid);

        if (empty($myData) || empty($userData)) {
            return false;
        }

        if ($myData["userid"] == $userData["userid"]) {
            return false;
        }

        if($myData["role"] == "ice" || $userData["role"] == "ice"){
            actionLog($userid, "error", "follow_user", $to_userid, "凍結されているユーザーはフォローできません。", 3);
            return false;
        }

        $other_settings_me = is_OtherSettings($pdo, $userid);
        $other_settings_user = is_OtherSettings($pdo, $to_userid);
        if($other_settings_me === true && $other_settings_user === true){
            // トランザクションを開始
            $pdo->beginTransaction();
            try {
                // フォローボタンが押された場合の処理
                $followerList = explode(',', $userData['follower'] ?? '');
                if (!(in_array($userid, $followerList))) {
                    // 自分が相手をフォローしていない場合、相手のfollowerカラムと自分のfollowカラムを更新
                    $followerList[] = $userid;
                    $followerList = array_values(array_unique(array_filter($followerList)));
                    $newFollowerList = implode(',', $followerList);

                    // UPDATE文を実行してフォロー情報を更新
                    $updateQuery = $pdo->prepare("UPDATE account SET follower = :follower WHERE userid = :userid");
                    $updateQuery->bindValue(':follower', $newFollowerList, PDO::PARAM_STR);
                    $updateQuery->bindValue(':userid', $userData['userid'], PDO::PARAM_STR);
                    $res = $updateQuery->execute();

                    // 自分のfollowカラムを更新
                    $myflwlist = explode(',', $myData["follow"]);
                    $myflwlist[] = $userData['userid'];
                    $myflwlist = array_values(array_unique(array_filter($myflwlist)));
                    $newFollowList = implode(',', $myflwlist);

                    $updateQuery = $pdo->prepare("UPDATE account SET follow = :follow WHERE userid = :userid");
                    $updateQuery->bindValue(':follow', $newFollowList, PDO::PARAM_STR);
                    $updateQuery->bindValue(':userid', $userid, PDO::PARAM_STR);
                    $res_follow = $updateQuery->execute();

                    send_notification($userData["userid"], $userid, "🎉" . $userid . "さんにフォローされました！🎉", "" . $userid . "さんにフォローされました。", "/@" . $userid . "", "follow", $userid);

                    if ($res && $res_follow) {
                        $pdo->commit();
                        return true;
                    } else {
                        $pdo->rollBack();
                        actionLog($userid, "error", "follow_user", $to_userid, "フォローに失敗", 3);
                        return false;
                    }
                }else{
                    $pdo->commit();
                    return true;
                }
            } catch (Exception $e) {
                $pdo->rollBack();
                actionLog($userid, "error", "follow_user", $to_userid, $e, 4);
                return false;
            }
        }else{
            return false;
        }
    }else{
        return false;
    }
}
function unfollow_user($pdo, $to_userid, $userid){
    if (!(empty($pdo)) && !(empty($to_userid)) && !(empty($userid))){
        $myData = getUserData($pdo, $userid);
        $userData = getUserData($pdo, $to_userid);

        $other_settings_me = is_OtherSettings($pdo, $userid);
        $other_settings_user = is_OtherSettings($pdo, $to_userid);
        if($other_settings_me === true && $other_settings_user === true){
            // トランザクションを開始
            $pdo->beginTransaction();
            try {
                // フォロー解除ボタンが押された場合の処理
                $followerList = explode(',', $userData['follower']);
                if (in_array($userid, $followerList)) {
                    // 自分が相手をフォローしている場合、相手のfollowerカラムと自分のfollowカラムを更新
                    $followerList = array_diff($followerList, array($userid));
                    $followerList = array_values(array_unique(array_filter($followerList)));
                    $newFollowerList = implode(',', $followerList);

                    // UPDATE文を実行してフォロー情報を更新
                    $updateQuery = $pdo->prepare("UPDATE account SET follower = :follower WHERE userid = :userid");
                    $updateQuery->bindValue(':follower', $newFollowerList, PDO::PARAM_STR);
                    $updateQuery->bindValue(':userid', $userData['userid'], PDO::PARAM_STR);
                    $res = $updateQuery->execute();

                    $myflwlist = explode(',', $myData["follow"]);
                    $delfollowList = array_diff($myflwlist, array($userData['userid']));
                    $delfollowList = array_values(array_unique(array_filter($delfollowList)));
                    $deluserid = implode(',', $delfollowList);

                    // 自分のfollowカラムから相手のユーザーIDを削除
                    $updateQuery = $pdo->prepare("UPDATE account SET follow = :follow WHERE userid = :userid");
                    $updateQuery->bindValue(':follow', $deluserid, PDO::PARAM_STR);
                    $updateQuery->bindValue(':userid', $userid, PDO::PARAM_STR);
                    $res_follow = $updateQuery->execute();

                    if ($res && $res_follow) {
                        // コミット
                        $pdo->commit();
                        return true;
                    } else {
                        // ロールバック
                        $pdo->rollBack();
                        actionLog($userid, "error", "unfollow_user", $to_userid, "フォロー解除に失敗", 3);
                        return false;
                    }
                }else{
                    $pdo->commit();
                    return true;
                }
            } catch (Exception $e) {
                // ロールバック
                $pdo->rollBack();
                actionLog($userid, "error", "unfollow_user", $to_userid, $e, 4);
                return false;
            }
        }else{
            return false;
        }
    }else{
        return false;
    }
}
function block_user($pdo, $to_userid, $userid){
    if (!(empty($pdo)) && !(empty($to_userid)) && !(empty($userid))){
        $myData = getUserData($pdo, $userid);
        $userData = getUserData($pdo, $to_userid);

        if (empty($myData) || empty($userData)) {
            return false;
        }

        if ($myData["userid"] == $userData["userid"]) {
            return false;
        }

        $other_settings_me = is_OtherSettings($pdo, $userid);
        $other_settings_user = is_OtherSettings($pdo, $to_userid);
        if($other_settings_me === true && $other_settings_user === true){
            // トランザクションを開始
            $pdo->beginTransaction();
            try {
                // フォロー解除ボタンが押された場合の処理
                $blockList = explode(',', $myData['blocklist']);
                if (!(in_array($userData['userid'], $blockList))) {
                    $blockList[] = $userData['userid'];
                    $newBlockList = implode(',', array_unique($blockList));

                    // UPDATE文を実行してフォロー情報を更新
                    $updateQuery = $pdo->prepare("UPDATE account SET blocklist = :blocklist WHERE userid = :userid");
                    $updateQuery->bindValue(':blocklist', $newBlockList, PDO::PARAM_STR);
                    $updateQuery->bindValue(':userid', $myData['userid'], PDO::PARAM_STR);
                    $res = $updateQuery->execute();

                    if ($res) {
                        // コミット
                        $pdo->commit();

                        $unfollow = unfollow_user($pdo, $to_userid, $userid);
                        if($unfollow === true){
                            return true;
                        }else{
                            return false;
                        }
                    } else {
                        // ロールバック
                        $pdo->rollBack();
                        actionLog($userid, "error", "block_user", $to_userid, "ブロックに失敗", 3);
                        return false;
                    }
                }else{
                    $pdo->rollBack();
                    return true;
                }
            } catch (Exception $e) {
                // ロールバック
                $pdo->rollBack();
                actionLog($userid, "error", "block_user", $to_userid, $e, 4);
                return false;
            }
        }else{
            return false;
        }
    }else{
        return false;
    }
}
function unblock_user($pdo, $to_userid, $userid){
    if (!(empty($pdo)) && !(empty($to_userid)) && !(empty($userid))){
        $myData = getUserData($pdo, $userid);
        $userData = getUserData($pdo, $to_userid);

        if (empty($myData) || empty($userData)) {
            return false;
        }

        $other_settings_me = is_OtherSettings($pdo, $userid);
        $other_settings_user = is_OtherSettings($pdo, $to_userid);
        if($other_settings_me === true && $other_settings_user === true){
            // トランザクションを開始
            $pdo->beginTransaction();
            try {
                // フォロー解除ボタンが押された場合の処理
                $blockList = explode(',', $myData['blocklist']);
                if (in_array($userData['userid'], $blockList)) {
                    $blockList = array_diff($blockList, array($userData['userid']));
                    $newBlockList = implode(',', $blockList);

                    // UPDATE文を実行してフォロー情報を更新
                    $updateQuery = $pdo->prepare("UPDATE account SET blocklist = :blocklist WHERE userid = :userid");
                    $updateQuery->bindValue(':blocklist', $newBlockList, PDO::PARAM_STR);
                    $updateQuery->bindValue(':userid', $myData['userid'], PDO::PARAM_STR);
                    $res = $updateQuery->execute();

                    if ($res) {
                        // コミット
                        $pdo->commit();
                        return true;
                    } else {
                        // ロールバック
                        $pdo->rollBack();
                        actionLog($userid, "error", "unblock_user", $to_userid, "ブロック解除に失敗", 3);
                        return false;
                    }
                }else{
                    $pdo->rollBack();
                    return true;
                }
            } catch (Exception $e) {
                // ロールバック
                $pdo->rollBack();
                actionLog($userid, "error", "unblock_user", $to_userid, $e, 4);
                return false;
            }
        }else{
            return false;
        }
    }else{
        return false;
    }
}
//--------------------アカウント削除--------------------
function deleteUser($pdo, $userid, $step, $job_uniqid){
    $userdata = getUserData($pdo, $userid);
    if(empty($userdata)){
        changeJob($pdo, $userid, $job_uniqid, "delete_account", "finished");
        return false;
    }else{
        $userid = $userdata["userid"];
        if($step == "stop_account"){
            if(changeJob($pdo, $userid, $job_uniqid, "stop_account", "running")){
                $newrole = "ice";
                $newtoken = "ice";
                $newadmin = "none";
                // トランザクション開始
                $pdo->beginTransaction();

                try {
                    $stmt = $pdo->prepare("UPDATE account SET role = :role,token = :newtoken,admin = :newadmin WHERE userid = :userid");

                    $stmt->bindValue(':role', $newrole, PDO::PARAM_STR);
                    $stmt->bindValue(':newtoken', $newtoken, PDO::PARAM_STR);
                    $stmt->bindValue(':newadmin', $newadmin, PDO::PARAM_STR);

                    $stmt->bindValue(':userid', $userid, PDO::PARAM_STR);

                    $res = $stmt->execute();

                    if ($res) {
                        $pdo->commit();

                        send_notification($userid, "uwuzu-fromsys", "🗑️アカウントの削除が開始されました🗑️", "アカウントの削除が開始されました！\n今後、アカウントのデータは順次削除されます。\n削除には時間がかかります。\n\nログアウトしてお待ち下さい。\n\nアカウントの復旧はできません。", "/others", "system", $userid);
                        if(changeJob($pdo, $userid, $job_uniqid, "delete_ueuse", "waiting")){
                            return true;
                        }else{
                            actionLog($userid, "error", "deleteAccount", null, "Job("+$job_uniqid+")のステータスをdelete_image-waitingに変更失敗", 3);
                            return false;
                        }
                    } else {
                        $pdo->rollBack();
                        actionLog($userid, "error", "deleteUser", $userid, "アカウントの削除前凍結に失敗しました", 4);
                        if(changeJob($pdo, $userid, $job_uniqid, "stop_account", "waiting")){
                            return true;
                        }else{
                            actionLog($userid, "error", "deleteAccount", null, "Job("+$job_uniqid+")のステータスをstop_account-waitingに変更失敗", 3);
                            return false;
                        }
                    }
                } catch (Exception $e) {
                    $pdo->rollBack();
                    actionLog($userid, "error", "deleteUser", $userid, "iceError: ".$e, 4);
                    if(changeJob($pdo, $userid, $job_uniqid, "stop_account", "error")){
                        return true;
                    }else{
                        actionLog($userid, "error", "deleteAccount", null, "Job("+$job_uniqid+")のステータスをstop_account-errorに変更失敗", 3);
                        return false;
                    }
                }
            }

        }

        if($step == "delete_ueuse"){
            if(changeJob($pdo, $userid, $job_uniqid, "delete_ueuse", "running")){
                // ユーズを直近100件取得
                $getUeuse_query = $pdo->prepare("SELECT * FROM ueuse WHERE account = :userid ORDER BY datetime DESC LIMIT 50");
                $getUeuse_query->bindValue(':userid', $userid, PDO::PARAM_STR);
                $getUeuse_query->execute();
                $getUeuse = $getUeuse_query->fetchAll();

                foreach ($getUeuse as $ueuse) {
                    delete_ueuse($ueuse["uniqid"], $userid, $userdata["loginid"]);
                }

                if(count($getUeuse) >= 50){
                    if(changeJob($pdo, $userid, $job_uniqid, "delete_ueuse", "waiting")){
                        return true;
                    }else{
                        actionLog($userid, "error", "deleteAccount", null, "Job("+$job_uniqid+")のステータスをdelete_ueuse-waitingに変更失敗", 3);
                        return false;
                    }
                }else{
                    if(changeJob($pdo, $userid, $job_uniqid, "delete_image", "waiting")){
                        return true;
                    }else{
                        actionLog($userid, "error", "deleteAccount", null, "Job("+$job_uniqid+")のステータスをdelete_image-waitingに変更失敗", 3);
                        return false;
                    }
                }
            }
        }

        if($step == "delete_image"){
            if(changeJob($pdo, $userid, $job_uniqid, "delete_image", "running")){
                // ユーザーの画像を削除
                $folderPath = "../ueuseimages/";
                $filesToDelete = glob($folderPath . "*-$userid.*");
                foreach ($filesToDelete as $file) {
                    if (is_file($file)) {
                        unlink($file);
                    }
                }
                // ユーザーの動画を削除
                $folderPath2 = "../ueusevideos/";
                $filesToDelete2 = glob($folderPath2 . "*-$userid.*");
                foreach ($filesToDelete2 as $file2) {
                    if (is_file($file2)) {
                        unlink($file2);
                    }
                }

                if(changeJob($pdo, $userid, $job_uniqid, "delete_follow", "waiting")){
                    return true;
                }else{
                    actionLog($userid, "error", "deleteAccount", null, "Job("+$job_uniqid+")のステータスをdelete_follow-waitingに変更失敗", 3);
                    return false;
                }
            }
        }

        if($step == "delete_follow"){
            if(changeJob($pdo, $userid, $job_uniqid, "delete_follow", "running")){
                // フォロー・フォロワー情報を削除したい全てのアカウントを取得
                    $flw_query = $pdo->prepare("SELECT *
                    FROM account
                    WHERE FIND_IN_SET(:userid, follow) > 0
                    OR FIND_IN_SET(:userid, follower) > 0;
                ");
                $flw_query->bindValue(':userid', $userid, PDO::PARAM_STR);
                $flw_query->execute();
                $flw_accounts = $flw_query->fetchAll();

                foreach ($flw_accounts as $account) {
                    unfollow_user($pdo, $account['userid'], $userid);
                    unfollow_user($pdo, $userid, $account['userid']);
                }

                // ユーザーIDを削除したい全てのアカウントを取得
                $blk_query = $pdo->prepare("SELECT *
                    FROM account
                    WHERE FIND_IN_SET(:userid, blocklist) > 0;
                ");
                $blk_query->bindValue(':userid', $userid, PDO::PARAM_STR);
                $blk_query->execute();
                $blk_accounts = $blk_query->fetchAll();

                foreach ($blk_accounts as $account) {
                    unblock_user($pdo, $userid, $account['userid']);
                }

                //いいねを外したいすべてのユーズを取得
                $fav_ueuse_query = $pdo->prepare("SELECT *
                    FROM ueuse
                    WHERE FIND_IN_SET(:userid, favorite) > 0;
                ");
                $fav_ueuse_query->bindValue(':userid', $userid, PDO::PARAM_STR);
                $fav_ueuse_query->execute();
                $fav_ueuse_ueuses = $fav_ueuse_query->fetchAll();
                foreach ($fav_ueuse_ueuses as $ueuse) {
                    addFavorite($pdo, $ueuse['uniqid'], $userid);
                }

                if(changeJob($pdo, $userid, $job_uniqid, "delete_account", "waiting")){
                    return true;
                }else{
                    actionLog($userid, "error", "deleteAccount", null, "Job("+$job_uniqid+")のステータスをdelete_account-waitingに変更失敗", 3);
                    return false;
                }
            }
        }

        if($step == "delete_account"){
            if(file_exists(__DIR__ . "/../settings_admin/plugin_settings/amazons3_settings.php")){
                require_once __DIR__ . '/../settings_admin/plugin_settings/amazons3_settings.php';
                if(AMS3_CHKS == "true"){
                    if(file_exists(__DIR__ . "/../plugin/aws/aws-autoloader.php")){
                        require_once __DIR__ . '/../plugin/aws/aws-autoloader.php';
                    }else{
                        actionLog(null, "error", "uploadAmazonS3", null, "AWS SDK for PHPが見つかりませんでした！", 4);
                    }
                }
            }else{
                actionLog(null, "error", "uploadAmazonS3", null, "amazons3_settings.phpが見つかりませんでした！", 3);
            }

            if(changeJob($pdo, $userid, $job_uniqid, "delete_account", "running")){
                $usericonurl = $userdata["iconname"];
                if(filter_var($usericonurl, FILTER_VALIDATE_URL)){
                    if(AMS3_CHKS == "true"){
                        deleteAmazonS3($usericonurl);
                    }
                }else{
                    $folderPath3 = "../usericons/";
                    $filesToDelete3 = glob($folderPath3 . "*-$userid.*"); // 「-ユーザーID.拡張子」というパターンを検索
                    // ファイルを順に削除
                    foreach ($filesToDelete3 as $file3) {
                        if (is_file($file3)) {
                            unlink($file3); // ファイルを削除
                        }
                    }
                }

                $userheadurl = $userdata["headname"];
                if(filter_var($userheadurl, FILTER_VALIDATE_URL)){
                    if(AMS3_CHKS == "true"){
                        deleteAmazonS3($userheadurl);
                    }
                }else{
                    $folderPath4 = "../userheads/";
                    $filesToDelete4 = glob($folderPath4 . "*-$userid.*"); // 「-ユーザーID.拡張子」というパターンを検索
                    // ファイルを順に削除
                    foreach ($filesToDelete4 as $file4) {
                        if (is_file($file4)) {
                            unlink($file4);
                        }
                    }
                }

                $pdo->beginTransaction();
                try {
                    // 投稿削除クエリを実行
                    $deleteQuery = $pdo->prepare("DELETE FROM ueuse WHERE account = :userid");
                    $deleteQuery->bindValue(':userid', $userid, PDO::PARAM_STR);
                    $res = $deleteQuery->execute();

                    // 通知削除クエリを実行(自分宛ての通知)
                    $deleteQuery = $pdo->prepare("DELETE FROM notification WHERE touserid = :touserid");
                    $deleteQuery->bindValue(':touserid', $userid, PDO::PARAM_STR);
                    $res = $deleteQuery->execute();

                    // 通知削除クエリを実行(自分からの通知)
                    $deleteQuery = $pdo->prepare("DELETE FROM notification WHERE fromuserid = :fromuserid");
                    $deleteQuery->bindValue(':fromuserid', $userid, PDO::PARAM_STR);
                    $res = $deleteQuery->execute();

                    // APIキー削除クエリを実行
                    $deleteQuery = $pdo->prepare("DELETE FROM api WHERE userid = :userid");
                    $deleteQuery->bindValue(':userid', $userid, PDO::PARAM_STR);
                    $res = $deleteQuery->execute();

                    // アカウント削除クエリを実行
                    $deleteQuery = $pdo->prepare("DELETE FROM account WHERE userid = :userid");
                    $deleteQuery->bindValue(':userid', $userid, PDO::PARAM_STR);
                    $res = $deleteQuery->execute();

                    if($res) {
                        // コミット
                        $pdo->commit();
                        changeJob($pdo, $userid, $job_uniqid, "delete_account", "finished");
                        actionLog($userid, "success", "deleteAccount", null, "アカウント削除に成功", 1);

                        return true;
                    } else {
                        // ロールバック
                        $pdo->rollBack();
                        actionLog($userid, "error", "deleteAccount", null, "アカウント削除に失敗", 3);
                        changeJob($pdo, $userid, $job_uniqid, "delete_account", "error");

                        return false;
                    }
                } catch (Exception $e) {
                    // エラーが発生した時はロールバック
                    $pdo->rollBack();
                    actionLog($userid, "error", "deleteAccount", null, $e, 4);
                    changeJob($pdo, $userid, $job_uniqid, "delete_account", "error");

                    return false;
                }
            }
        }
    }
}
function changePopularity($pdo, $uniqid, $userid, $change_range){
    if (!(empty($pdo)) && !(empty($uniqid))){
        if(is_numeric($change_range)){
            $pdo->beginTransaction();
            try {
                // 投稿のいいね情報を取得
                $stmt = $pdo->prepare("SELECT popularity FROM ueuse WHERE uniqid = :uniqid");
                $stmt->bindValue(':uniqid', $uniqid, PDO::PARAM_STR);
                $stmt->execute();
                $post = $stmt->fetch(PDO::FETCH_ASSOC);

                if (!(empty($post))) {
                    $new_popularity = (int)$post['popularity'] + (int)$change_range;
                    if($new_popularity >= 2147483647){
                        $new_popularity = 2147483647;
                    }

                    $updateQuery = $pdo->prepare("UPDATE ueuse SET popularity = :popularity WHERE uniqid = :uniqid");
                    $updateQuery->bindValue(':popularity', $new_popularity, PDO::PARAM_INT);
                    $updateQuery->bindValue(':uniqid', $uniqid, PDO::PARAM_STR);
                    $res = $updateQuery->execute();

                    if ($res) {
                        $pdo->commit();
                        return true;
                    } else {
                        $pdo->rollBack();
                        actionLog($userid, "error", "changePopularity", $uniqid, "いいねに失敗しました", 3);
                        return false;
                    }
                } else {
                    $pdo->rollBack();
                    return false;
                }
            } catch(PDOException $e) {
                actionLog($userid, "error", "changePopularity", $uniqid, $e, 4);
                return false;
            }
        }else{
            actionLog($userid, "error", "changePopularity", $uniqid, "不正な変更値です", 4);
            return false;
        }
    }
}
function addFavorite($pdo, $uniqid, $userid){
    if (!(empty($pdo)) && !(empty($uniqid)) && !(empty($userid))){
        // 投稿のいいね情報を取得
        $stmt = $pdo->prepare("SELECT account,ueuse,favorite FROM ueuse WHERE uniqid = :uniqid");
        $stmt->bindValue(':uniqid', $uniqid, PDO::PARAM_STR);
        $stmt->execute();
        $post = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!(empty($post))) {
            $favoriteList = explode(',', $post['favorite']);
            $index = array_search($userid, $favoriteList);

            if ($index === false) {
                // ユーザーIDを追加
                $favoriteList[] = $userid;

                send_notification(safetext($post['account']),$userid,"".$userid."さんがいいねしました！",safetext($post['ueuse']),"/!".$uniqid."","favorite", $uniqid);

                //1いいねでスコアが1増加
                changePopularity($pdo, $uniqid, $userid, 1);
            } else {
                // ユーザーIDを削除
                array_splice($favoriteList, $index, 1);

                //1いいね解除でスコアが1減る
                changePopularity($pdo, $uniqid, $userid, -1);

                delete_notification(safetext($post['account']),$userid,"".$userid."さんがいいねしました！",safetext($post['ueuse']),"/!".$uniqid."","favorite");
            }

            $pdo->beginTransaction();
            try {
                // 新しいいいね情報を更新
                $newFavorite = implode(',', $favoriteList);
                $updateQuery = $pdo->prepare("UPDATE ueuse SET favorite = :favorite WHERE uniqid = :uniqid");
                $updateQuery->bindValue(':favorite', $newFavorite, PDO::PARAM_STR);
                $updateQuery->bindValue(':uniqid', $uniqid, PDO::PARAM_STR);
                $res = $updateQuery->execute();

                if ($res) {
                    $pdo->commit();
                    return [true, "いいねに成功しました", $newFavorite];
                } else {
                    $pdo->rollBack();
                    actionLog($userid, "error", "addFavorite", $uniqid, "いいねに失敗しました", 3);
                    return [false, "いいねに失敗しました", $post['favorite']];
                }
            } catch(PDOException $e) {
                actionLog($userid, "error", "addFavorite", $uniqid, $e, 4);
                return [false, "データベースエラー", null];
            }
        } else {
            return [false, "投稿が見つかりませんでした", null];
        }
    }
}
function getFavorite($pdo, $uniqid){
    if (!(empty($pdo)) && !(empty($uniqid))){

        try {
            // 投稿のいいね情報を取得
            $stmt = $pdo->prepare("SELECT account,ueuse,favorite FROM ueuse WHERE uniqid = :uniqid");
            $stmt->bindValue(':uniqid', $uniqid, PDO::PARAM_STR);
            $stmt->execute();
            $post = $stmt->fetch(PDO::FETCH_ASSOC);

            if (!(empty($post))) {
                return [true, "いいねを取得しました", $post['favorite']];
            } else {
                return [false, "投稿が見つかりませんでした", null];
            }
        } catch(PDOException $e) {
            actionLog(null, "error", "getFavorite", $uniqid, $e, 4);
            return [false, "データベースエラー", null];
        }
    }
}
function getUserData($pdo, $userid) {
    $query = $pdo->prepare("SELECT * FROM account WHERE userid = :userid");
    $query->bindValue(':userid', $userid, PDO::PARAM_STR);
    $query->execute();
    return $query->fetch();
}
function getUserDataForUpdate($pdo, $userid) {
    $query = $pdo->prepare("SELECT * FROM account WHERE userid = :userid FOR UPDATE");
    $query->bindValue(':userid', $userid, PDO::PARAM_STR);
    $query->execute();
    return $query->fetch();
}

function getUeuseData($pdo, $uniqid) {
    $query = $pdo->prepare("SELECT * FROM ueuse WHERE uniqid = :uniqid");
    $query->bindValue(':uniqid', $uniqid, PDO::PARAM_STR);
    $query->execute();
    $ueuseDatas = $query->fetch();

    if (empty($ueuseDatas)) {
        return false;
    }

    //リプライ数取得
    $rpQuery = $pdo->prepare("SELECT COUNT(*) as reply_count FROM ueuse WHERE rpuniqid = :rpuniqid");
    $rpQuery->bindValue(':rpuniqid', $ueuseDatas['uniqid']);
    $rpQuery->execute();
    $rpData = $rpQuery->fetch(PDO::FETCH_ASSOC);

    if ($rpData){
        $ueuseDatas['reply_count'] = $rpData['reply_count'];
    }

    //リユーズ数取得
    $ruQuery = $pdo->prepare("SELECT COUNT(*) as reuse_count FROM ueuse WHERE ruuniqid = :ruuniqid");
    $ruQuery->bindValue(':ruuniqid', $ueuseDatas['uniqid']);
    $ruQuery->execute();
    $ruData = $ruQuery->fetch(PDO::FETCH_ASSOC);

    if ($ruData){
        $ueuseDatas['reuse_count'] = $ruData['reuse_count'];
    }

    $fav = $ueuseDatas['favorite'];
    $favIds = explode(',', $fav);
    $ueuseDatas["favorite_count"] = count($favIds)-1;

    return $ueuseDatas;
}
function actionLog($userid, $type, $place, $target, $content, $importance){

    if(empty($userid)){
        $userid = "uwuzu-fromsys";
    }

    switch ($importance) {
        case 0:
            $importance_level = 0;
            break;
        case 1:
            $importance_level = 1;
            break;
        case 2:
            $importance_level = 2;
            break;
        case 3:
            $importance_level = 3;
            break;
        case 4:
            $importance_level = 4;
            break;
        case "none":
            $importance_level = 0;
            break;
        case "low":
            $importance_level = 1;
            break;
        case "middle":
            $importance_level = 2;
            break;
        case "high":
            $importance_level = 3;
            break;
        case "critical":
            $importance_level = 4;
            break;
        default:
            $importance_level = 0;
            break;
    }

    if(empty($type)){
        $type = "none";
    }

    if(empty($target)){
        $target = "none";
    }

    if(empty($content)){
        $content = "none";
    }
    if(is_array($content)){
        $content = implode(', ', $content);
    }

    if(empty($place)){
        $place = "none";
    }

    // データベースに接続
    try {
        $option = array(
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::MYSQL_ATTR_MULTI_STATEMENTS => false
        );
        $pdo = new PDO('mysql:charset=utf8mb4;dbname='.DB_NAME.';host='.DB_HOST , DB_USER, DB_PASS, $option);
    } catch(PDOException $e) {
        return false;
    }

    if(!(empty($pdo))){
        $uniqid = createUniqId();
        $datetime = date('Y-m-d H:i:s');

        // トランザクション開始
        $pdo->beginTransaction();

        try {
            // SQL作成
            $stmt = $pdo->prepare("INSERT INTO actionlog (uniqid, userid, type, place, target, content, importance, datetime) VALUES (:uniqid, :userid, :type, :place, :target, :content, :importance, :datetime)");

            $stmt->bindParam(':uniqid', $uniqid, PDO::PARAM_STR);
            $stmt->bindParam(':userid', $userid, PDO::PARAM_STR);
            $stmt->bindParam(':type', $type, PDO::PARAM_STR);
            $stmt->bindParam(':place', $place, PDO::PARAM_STR);

            $stmt->bindParam(':target', $target, PDO::PARAM_STR);
            $stmt->bindParam(':content', $content, PDO::PARAM_STR);
            $stmt->bindParam(':importance', $importance_level, PDO::PARAM_INT);
            $stmt->bindParam(':datetime', $datetime, PDO::PARAM_STR);
            $res = $stmt->execute();
            if($res){
                $pdo->commit();
                return true;
            }else{
                $pdo->rollBack();
                return false;
            }
        } catch(Exception $e) {
            // エラーが発生した時はロールバック
            // ここでログを残そうとすると無限ループ入るのでなし
            $pdo->rollBack();
            return false;
        }
    }
}

function addJob($pdo, $userid, $job, $step){
    $userid = getUserData($pdo, $userid)["userid"];
    if(empty($userid)){
        return false;
    }
    if(empty($job)){
        return false;
    }
    if(empty($step)){
        $step = "start";
    }

    if(!(empty($pdo))){
        $uniqid = createUniqId();
        $datetime = date('Y-m-d H:i:s');
        $status = "waiting";

        // トランザクション開始
        $pdo->beginTransaction();

        try {
            // SQL作成
            $stmt = $pdo->prepare("INSERT INTO jobs (uniqid, userid, job, step, status, datetime) VALUES (:uniqid, :userid, :job, :step, :status, :datetime)");

            $stmt->bindParam(':uniqid', $uniqid, PDO::PARAM_STR);
            $stmt->bindParam(':userid', $userid, PDO::PARAM_STR);
            $stmt->bindParam(':job', $job, PDO::PARAM_STR);
            $stmt->bindParam(':step', $step, PDO::PARAM_STR);
            $stmt->bindParam(':status', $status, PDO::PARAM_STR);
            $stmt->bindParam(':datetime', $datetime, PDO::PARAM_STR);
            $res = $stmt->execute();
            if($res){
                $pdo->commit();
                return true;
            }else{
                actionLog($userid, "error", "addJob", null, "Jobを追加できませんでした！", 3);
                $pdo->rollBack();
                return false;
            }
        } catch(Exception $e) {
            actionLog($userid, "error", "addJob", null, $e, 4);
            $pdo->rollBack();
            return false;
        }
    }
}

function changeJob($pdo, $userid, $uniqid, $step, $status){
    if(empty($uniqid)){
        return false;
    }
    if(empty($step)){
        $step = "start";
    }
    if(empty($status)){
        $status = "waiting";
    }
    $status_list = ["waiting","running","finished","error"];
    if(in_array($status, $status_list)){
        if(!(empty($pdo))){
            $pdo->beginTransaction();

            try {
                $updateQuery = $pdo->prepare("UPDATE jobs SET step = :step, status = :status WHERE uniqid = :uniqid");
                $updateQuery->bindValue(':step', $step, PDO::PARAM_STR);
                $updateQuery->bindValue(':status', $status, PDO::PARAM_STR);
                $updateQuery->bindValue(':uniqid', $uniqid, PDO::PARAM_STR);
                $res = $updateQuery->execute();

                if($res){
                    $pdo->commit();
                    return true;
                }else{
                    $pdo->rollBack();
                    actionLog($userid, "error", "is_OtherSettings", null, "ジョブを編集できませんでした", 3);
                    return false;
                }
            } catch(Exception $e) {
                actionLog($userid, "error", "changeJob", null, $e, 4);
                $pdo->rollBack();
                return false;
            }
        }
    }else{
        actionLog($userid, "error", "changeJob", null, "不正なステータスです！", 3);
        return false;
    }
}

function getJob($pdo, $userid){
    if(empty($userid)){
        return false;
    }

    if(!(empty($pdo))){
        $query = $pdo->prepare("SELECT * FROM jobs WHERE status = 'waiting' ORDER BY datetime ASC LIMIT 1");
        $query->execute();
        $job = $query->fetch(PDO::FETCH_ASSOC);

        if($job){
            return $job;
        }else{
            return false;
        }
    }
}

function localcloudURL($url){
    if(!($url == null || $url == "" || $url == "none")){
        if(filter_var($url, FILTER_VALIDATE_URL)){
            return $url;
        }else{
            return "../" . $url;
        }
    }else{
        return null;
    }
}

function localcloudURLtoAPI($text){
    if(!($text == null || $text == "" || $text == "none")){
        $domain = $_SERVER['HTTP_HOST'];
        $address = localcloudURL($text);
        if(strpos($address, '../') !== false){
            $address = "https://".$domain."/".str_replace('../', '', $address);
        }
        return $address;
    }else{
        return null;
    }
}

function safetext($text){
    // テキストの安全化
    return htmlspecialchars(preg_replace('/[\x00-\x08\x0b\x0c\x0e-\x1f]/', '', $text), ENT_QUOTES, 'UTF-8', false);
}

function to_array_safetext($value) {
    foreach ($value as $key => $val) {
        if (is_array($val)) {
            $value[$key] = to_array_safetext($val);
        } else {
            $value[$key] = safetext($val);
        }
    }
    return $value;
}

function decode_yajirushi($postText){
    $postText = str_replace('&larr;', '←', $postText);
    $postText = str_replace('&darr;', '↓', $postText);
    $postText = str_replace('&uarr;', '↑', $postText);
    $postText = str_replace('&rarr;', '→', $postText);
    return $postText;
}
function deleteDirectory($dir) {
    //ディレクトリを一括で消すやつ
    if (!is_dir($dir)) {
        return false;
    }

    $items = scandir($dir);
    foreach ($items as $item) {
        if ($item == '.' || $item == '..') {
            continue;
        }

        $path = $dir . DIRECTORY_SEPARATOR . $item;

        if (is_dir($path)) {
            // サブディレクトリの場合、再帰的に削除
            deleteDirectory($path);
        } else {
            unlink($path);
        }
    }

    return rmdir($dir);
}
// ユーザーデータの暗号化関連
function GenUserEnckey($datetime){
    $dateBaseKey = hash('sha3-512', $datetime);
    $complexEncKey = hash('sha3-512', ENC_KEY . $dateBaseKey);
    return $complexEncKey;
}
function EncryptionUseEncrKey($data,$key,$iv){
    return openssl_encrypt($data, "aes-256-cbc", $key, 0, $iv);
}
function DecryptionUseEncrKey($data,$key,$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;
            }
        }
    }
}

//ユーザーのOther_Settings読み取り関数
function val_OtherSettings($dataname, $jsontext){
    $other_settings = json_decode($jsontext, true);
    if(!(empty($other_settings[$dataname]))) {
        if(is_bool($other_settings[$dataname]) === true){
            if($other_settings[$dataname] == true){
                $ret = true;
            }else{
                $ret = false;
            }
        }elseif(is_int($other_settings[$dataname]) === true){
            $ret = (int)$other_settings[$dataname];
        }elseif(is_string($other_settings[$dataname])){
            $ret = $other_settings[$dataname];
        }
    }else{
        $ret = false;
    }
    return $ret;
}
//ユーザーのOther_Settings追加関数
function val_AddOtherSettings($dataname, $data, $jsontext){
    $other_settings = json_decode($jsontext, true);
    if(empty($other_settings)){
        $new_data = [$dataname=>$data];
        $ret = json_encode($new_data);
    }else{
        if(isset($dataname) && isset($data) && isset($jsontext)) {
            if(is_bool($data) === true){
                $new_data = [$dataname=>$data];
                $ret = json_encode(array_merge($other_settings,$new_data));
            }elseif(is_int($data) === true){
                $new_data = [$dataname=>(int)$data];
                $ret = json_encode(array_merge($other_settings,$new_data));
            }elseif(is_string($data)){
                $new_data = [$dataname=>$data];
                $ret = json_encode(array_merge($other_settings,$new_data));
            }
        }else{
            $ret = false;
        }
    }

    return $ret;
}
//ユーザーのOther_Settingsが既にあるかないか(なければ空のJSONを追加)
function is_OtherSettings($pdo, $userid, $add = true){
    $other_settings = getUserData($pdo, $userid)["other_settings"];
    if(empty($other_settings)){
        if($add === true){
            $new_data = [];
            $new_json = json_encode($new_data);

            $pdo->beginTransaction();
            try {
                // UPDATE文を実行してフォロー情報を更新
                $updateQuery = $pdo->prepare("UPDATE account SET other_settings = :other_settings WHERE userid = :userid");
                $updateQuery->bindValue(':other_settings', $new_json, PDO::PARAM_STR);
                $updateQuery->bindValue(':userid', $userid, PDO::PARAM_STR);
                $res = $updateQuery->execute();

                if($res){
                    $pdo->commit();
                    return true;
                }else{
                    // ロールバック
                    $pdo->rollBack();
                    actionLog($userid, "error", "is_OtherSettings", null, "空のOtherSettingsを追加できませんでした", 3);
                    return false;
                }
            } catch (Exception $e) {
                // ロールバック
                $pdo->rollBack();
                actionLog($userid, "error", "is_OtherSettings", null, $e, 4);
                return false;
            }
        }else{
            return false;
        }
    }else{
        return true;
    }
}

function GetActivityPubJson($url) {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,         // リダイレクトを追跡
        CURLOPT_MAXREDIRS => 10,                // 最大リダイレクト回数
        CURLOPT_CONNECTTIMEOUT => 5,
        CURLOPT_TIMEOUT => 10,
        CURLOPT_USERAGENT => 'uwuzu-ActivityPubClient/1.0',
        CURLOPT_HTTPHEADER => [
            'Accept: application/activity+json, application/ld+json, application/json'
        ]
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
    $err = curl_error($ch);
    curl_close($ch);

    if ($response === false || $httpCode >= 400) {
        return null;
    }

    $json = json_decode($response, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        return null;
    }

    return $json;
}

function GetActivityPubUser($userid, $domain) {
    $webfingerUrl = "https://$domain/.well-known/webfinger?resource=acct:$userid@$domain";

    $webfingerJson = GetActivityPubJson($webfingerUrl);

    if (!$webfingerJson || empty($webfingerJson['links'])) {
        return ['error' => 'Failed to fetch WebFinger'];
    }

    $actorUrl = null;
    foreach ($webfingerJson['links'] as $link) {
        if ($link['rel'] === 'self' && $link['type'] === 'application/activity+json') {
            $actorUrl = $link['href'];
            break;
        }
    }

    if (!$actorUrl) {
        return ['error' => 'Actor URL not found'];
    }

    $actorJson = GetActivityPubJson($actorUrl);
    if (!$actorJson) {
        return ['error' => 'Failed to fetch actor'];
    }

    $summaryHtml = $actorJson['summary'] ?? '';
    $withNewlines = preg_replace('/<br\s*\/?>/i', "\n", $summaryHtml);
    $plainText = strip_tags($withNewlines);


    return [
        'userid' => $actorJson['preferredUsername'] ?? null,
        'username' => $actorJson['name'] ?? null,
        'profile' => $plainText ?? null,
        'id' => $actorJson['id'] ?? null,
        'inbox' => $actorJson['inbox'] ?? null,
        'outbox' => $actorJson['outbox'] ?? null,
        'followers' => $actorJson['followers'] ?? null,
        'iconname' => $actorJson['icon']['url'] ?? "../img/deficon/icon.png",
        'headname' => $actorJson['image']['url'] ?? "../img/defhead/head.png",
        'datetime' => $actorJson['published'] ?? null,
        'role' => 'user',
        'other_settings' => '{}',
        'follow' => '',
        'follower' => '',
        'raw' => $actorJson
    ];
}

function FormatUeuseItem(array $value, string $myblocklist, string $mybookmark, $pdo, string $userId): ?array {
    if (in_array(safetext($value['account']), explode(",", $myblocklist))) return null;
    if ($value["role"] === "ice") return null;

    $value['iconname'] = filter_var($value['iconname'], FILTER_VALIDATE_URL)
        ? $value['iconname']
        : "../" . $value['iconname'];

    $value = to_null($value);
    $value = to_array_safetext($value);
    $value["role"] = explode(',', $value["role"]);

    if(isset($value["activitypub"]) && $value["activitypub"] == true) {
        $value["activitypub"] = true;
    } else {
        $value["activitypub"] = false;
    }

    if(isset($value["sacinfo"]) && $value["sacinfo"] == "bot") {
        $value["is_bot"] = true;
    } else {
        $value["is_bot"] = false;
    }

    if (!empty($value['rpuniqid'])) {
        $value["type"] = "Reply";
    } elseif (!empty($value['ruuniqid'])) {
        $value["type"] = "Reuse";

        $reused = getUeuseData($pdo, $value['ruuniqid']);
        if ($reused) {
            $reusedUserData = getUserData($pdo, $reused['account']);
            $reusedUserData["role"] = explode(',', $reusedUserData["role"]);

            $reused = to_null($reused);
            $reused = to_array_safetext($reused);

            if(isset($reusedUserData["sacinfo"]) && $reusedUserData["sacinfo"] == "bot") {
                $reusedUserData["is_bot"] = true;
            } else {
                $reusedUserData["is_bot"] = false;
            }

            $value["reuse"] = [
                "type" => "Reuse",
                "uniqid" => $reused["uniqid"],
                "datetime" => $reused["datetime"],
                "userid" => $reused["account"],
                "userdata" => [
                    "userid" => $reusedUserData["userid"],
                    "username" => $reusedUserData["username"],
                    "iconurl" => filter_var($reusedUserData['iconname'], FILTER_VALIDATE_URL)
                        ? $reusedUserData['iconname']
                        : "../" . $reusedUserData['iconname'],
                    "role" => $reusedUserData["role"],
                    "is_bot" => $reusedUserData["is_bot"],
                ],
                "ueuse" => $reused["ueuse"],
                "photo1" => $reused["photo1"],
                "photo2" => $reused["photo2"],
                "photo3" => $reused["photo3"],
                "photo4" => $reused["photo4"],
                "video1" => $reused["video1"],
                "rpuniqid" => $reused["rpuniqid"],
                "ruuniqid" => $reused["ruuniqid"],
                "nsfw" => filter_var($reused["nsfw"], FILTER_VALIDATE_BOOLEAN),
                "favoritecount" => $reused["favorite_count"],
                "replycount" => $reused["reply_count"],
                "reusecount" => $reused["reuse_count"],
                "is_favorite" => in_array($userId, explode(',', $reused['favorite'])),
                "is_bookmark" => in_array($reused["uniqid"], explode(',', $mybookmark)),
                "abi" => [
                    "abi_text" => $reused["abi"],
                    "abi_date" => $reused["abidate"],
                ],
                "is_activitypub" => $value["activitypub"],
            ];
        } else {
            $value["reuse"] = null;
        }
    } else {
        $value["type"] = "Ueuse";
    }

    $ueuse = [
        "type" => $value["type"],
        "uniqid" => $value["uniqid"],
        "datetime" => $value["datetime"],
        "userid" => $value["account"],
        "userdata" => [
            "userid" => $value["account"],
            "username" => $value["username"],
            "iconurl" => $value['iconname'],
            "role" => $value["role"],
            "is_bot" => $value["is_bot"],
        ],
        "ueuse" => $value["ueuse"],
        "photo1" => $value["photo1"],
        "photo2" => $value["photo2"],
        "photo3" => $value["photo3"],
        "photo4" => $value["photo4"],
        "video1" => $value["video1"],
        "rpuniqid" => $value["rpuniqid"],
        "ruuniqid" => $value["ruuniqid"],
        "nsfw" => filter_var($value["nsfw"], FILTER_VALIDATE_BOOLEAN),
        "favoritecount" => $value["favorite_count"],
        "replycount" => $value["reply_count"],
        "reusecount" => $value["reuse_count"],
        "is_favorite" => in_array($userId, explode(',', $value['favorite'])),
        "is_bookmark" => in_array($value["uniqid"], explode(',', $mybookmark)),
        "abi" => [
            "abi_text" => $value["abi"],
            "abi_date" => $value["abidate"],
        ],
        "is_activitypub" => $value["activitypub"],
    ];

    if ($value["type"] === "Reuse") {
        $ueuse["reuse"] = $value["reuse"];
    }

    return $ueuse;
}

function GetAPIScopes($scope){
    $scopelist = [
        "read:me" => "重要な情報以外の自分のアカウントの情報を見る",
        "write:me" => "重要な情報以外の自分のアカウントの情報を変更する",
        "read:users" => "他のユーザーのアカウント情報を見る",
        "read:ueuse" => "ユーズを見る",
        "write:ueuse" => "ユーズの作成・削除をする",
        "write:follow" => "フォロー・フォロー解除をする",
        "write:favorite" => "いいねをする・解除をする",
        "read:notifications" => "通知を見る",
        "write:notifications" => "通知を既読にする",
        "write:bookmark" => "ブックマークにユーズを追加・削除する",
        "read:bookmark" => "ブックマークを見る"
    ];
    if(empty($scope)){
        return $scopelist;
    }else{
        if(array_key_exists($scope, $scopelist)){
            return $scopelist[$scope];
        }else{
            return false;
        }
    }
}

function MinimumHash($text) {
    $hash = hash('sha3-512', $text);

    for ($i = 0; $i < 5; $i++) {
        $parts = str_split($hash, 2);
        $new = [];
        foreach ($parts as $index => $part) {
            $new[] = ($index % 2 === 0) ? substr($part, 0, -1) : substr($part, 1);
        }
        $hash = implode('', $new);
    }

    $baseChars = preg_replace('/[^a-zA-Z0-9]/', '', $text);
    if ($baseChars === '') {
        $baseChars = 'fallback';
    }
    $baseChars = str_split($baseChars);

    $alphabet = array_merge(range('a', 'z'), range('0', '9'));
    $map = [];
    foreach ($alphabet as $i => $char) {
        $map[$char] = $baseChars[$i % count($baseChars)];
    }

    $encoded = '';
    foreach (str_split($hash) as $char) {
        if ($char === '.') continue; // ドット除外
        if (isset($map[$char])) {
            $encoded .= $map[$char];
            if (strlen($encoded) === 4) break;
        }
    }

    return (strlen($encoded) === 4) ? $encoded : null;
}

function GenAPIToken(int $totalLength = 64){
    $prefix = strtoupper(MinimumHash($_SERVER['HTTP_HOST']));
    $length = $totalLength - strlen($prefix);

    $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    $charLen = strlen($chars);

    $token = '';
    while (strlen($token) < $length) {
        $byte = random_bytes(1);
        $val = ord($byte);
        if ($val < 62 * floor(256 / 62)) {
            $token .= $chars[$val % $charLen];
        }
    }

    return $prefix . $token;
}
function DelAPIToken($pdo, $uniqid){
    if(!(empty($uniqid))){
        $tokenQuery = $pdo->prepare("SELECT token FROM api WHERE uniqid = :uniqid");
        $tokenQuery->bindValue(':uniqid', $uniqid);
        $tokenQuery->execute();
        $tokenData = $tokenQuery->fetch();
        if(!(empty($tokenData["token"]))){
            $pdo->beginTransaction();
            try {
                // 削除クエリを実行
                $deleteQuery = $pdo->prepare("DELETE FROM api WHERE uniqid = :uniqid");
                $deleteQuery->bindValue(':uniqid', $uniqid, PDO::PARAM_STR);
                $res = $deleteQuery->execute();

                if ($res) {
                    $res = $pdo->commit();
                    return true;
                } else {
                    $pdo->rollBack();
                    actionLog($uniqid, "error", "delete_api_token", null, "APIトークンの削除に失敗しました(rollBack)", 3);
                    return false;
                }
            } catch(PDOException $e) {
                $pdo->rollBack();
                actionLog($uniqid, "error", "delete_api_token", null, $e, 4);
                return false;
            }
        }else{
            actionLog($uniqid, "error", "delete_api_token", null, "カラムは存在しますがAPIトークンが存在しません", 3);
            return false;
        }
    }else{
        return false;
    }
}
function DelSessionidAPIToken($pdo, $session){
    $tokenQuery = $pdo->prepare("SELECT uniqid, userid, token FROM api WHERE sessionid = :sessionid");
    $tokenQuery->bindValue(':sessionid', $session);
    $tokenQuery->execute();
    $tokenData = $tokenQuery->fetch();

    $none = "";
    if(!(empty($tokenData["userid"]))){
        $pdo->beginTransaction();
        try {
            $updateQuery = $pdo->prepare("UPDATE api SET sessionid = :sessionid WHERE uniqid = :uniqid");
            $updateQuery->bindValue(':sessionid', $none, PDO::PARAM_STR);
            $updateQuery->bindValue(':uniqid', $tokenData["uniqid"], PDO::PARAM_STR);
            $res = $updateQuery->execute();

            if($res){
                $pdo->commit();
                return true;
            }else{
                // ロールバック
                $pdo->rollBack();
                actionLog($tokenData["userid"], "error", "DelSessionidAPIToken", $tokenData["uniqid"], "セッションIDの無効化に失敗しました！", 3);
                return false;
            }
        } catch (Exception $e) {
            // ロールバック
            $pdo->rollBack();
            actionLog($tokenData["userid"], "error", "DelSessionidAPIToken", $tokenData["uniqid"], $e, 4);
            return false;
        }
    }else{
        actionLog($tokenData["userid"], "error", "DelSessionidAPIToken", $tokenData["uniqid"], "セッションIDが存在しません。", 3);
        return false;
    }
}
function APIAuth($pdo, $token, $scope){
    $tokenQuery = $pdo->prepare("SELECT userid, scope FROM api WHERE token = :token");
    $tokenQuery->bindValue(':token', $token);
    $tokenQuery->execute();
    $tokenData = $tokenQuery->fetch();

    if(!(empty($tokenData["userid"]))){
        $allow_scope = array_unique(array_map('trim', explode(",", $tokenData["scope"])));
        if(in_array($scope, $allow_scope)){
            $userdata = getUserData($pdo, $tokenData["userid"]);
            if(!(empty($userdata))){
                if($userdata["role"] === "ice"){
                    return [false, "this_account_has_been_frozen", null];
                }else{
                    return [true, "success", $userdata];
                }
            }else{
                return [false, "token_invalid", null];
            }
        }else{
            return [false, "not_allow_scope", null];
        }
    }else{
        $userQuery = $pdo->prepare("SELECT * FROM account WHERE token = :token");
        $userQuery->bindValue(':token', $token);
        $userQuery->execute();
        $userData = $userQuery->fetch();

        if(empty($userData["userid"])){
            return [false, "token_invalid", null];
        }elseif($userData["role"] === "ice"){
            return [false, "this_account_has_been_frozen", null];
        }else{
            return [true, "success", $userData];
        }
    }
}

function getDatasUeuse(PDO $pdo, array $messages): array {
    if (empty($messages)) return [];

    // --- userId / uniqid を安全に抽出 ---
    $userIds = array_values(array_unique(array_filter(array_column($messages, 'account'), fn($v) => $v !== null && $v !== '')));
    $uniqids = array_values(array_unique(array_filter(array_column($messages, 'uniqid'), fn($v) => $v !== null && $v !== '')));

    $users = [];
    if (!empty($userIds)) {
        $placeholders = implode(',', array_fill(0, count($userIds), '?'));
        $stmt = $pdo->prepare("SELECT userid, username, profile, role, iconname, headname, sacinfo FROM account WHERE userid IN ($placeholders)");
        $stmt->execute($userIds);
        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $users[$row['userid']] = $row;
        }
    }

    $replyCounts = [];
    $reuseCounts = [];
    if (!empty($uniqids)) {
        $placeholders = implode(',', array_fill(0, count($uniqids), '?'));

        $stmt = $pdo->prepare("SELECT rpuniqid, COUNT(*) AS reply_count FROM ueuse WHERE rpuniqid IN ($placeholders) GROUP BY rpuniqid");
        $stmt->execute($uniqids);
        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $replyCounts[$row['rpuniqid']] = (int)$row['reply_count'];
        }

        $stmt = $pdo->prepare("SELECT ruuniqid, COUNT(*) AS reuse_count FROM ueuse WHERE ruuniqid IN ($placeholders) GROUP BY ruuniqid");
        $stmt->execute($uniqids);
        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $reuseCounts[$row['ruuniqid']] = (int)$row['reuse_count'];
        }
    }

    // --- messages に反映（ループ内でDBを叩かない）---
    foreach ($messages as &$message) {
        // account のユーザー情報をマージ（存在すれば上書き）
        $acc = $message['account'] ?? null;
        if ($acc !== null && isset($users[$acc])) {
            $userRow = $users[$acc];
            $message['username'] = $userRow['username'] ?? ($message['username'] ?? null);
            $message['profile']  = $userRow['profile']  ?? ($message['profile']  ?? null);
            $message['role']     = $userRow['role']     ?? ($message['role']     ?? null);
            $message['iconname'] = $userRow['iconname'] ?? ($message['iconname'] ?? null);
            $message['headname'] = $userRow['headname'] ?? ($message['headname'] ?? null);
            $message['sacinfo']  = $userRow['sacinfo']  ?? ($message['sacinfo']  ?? null);
        }

        // reply / reuse
        $uniq = $message['uniqid'] ?? '';
        $message['reply_count'] = $replyCounts[$uniq] ?? 0;
        $message['reuse_count'] = $reuseCounts[$uniq] ?? 0;

        // --- favorite_count を安全に計算 ---
        // 1) 値を文字列として扱い、2) explode して trim、3) 空文字を除去、4) count
        $favStr = isset($message['favorite']) ? (string)$message['favorite'] : '';
        if ($favStr === '') {
            $favCount = 0;
        } else {
            $parts = array_map('trim', explode(',', $favStr));
            $parts = array_filter($parts, fn($v) => $v !== '');
            $favCount = count($parts);
        }

        $message['favorite_count'] = $favCount;
    }
    unset($message);

    return $messages;
}

function getAPIToken() {
    // 従来の方法(body/URLパラメータ)
    $Get_Post_Json = file_get_contents("php://input");
    if(isset($_GET["token"]) || !empty($Get_Post_Json)) {
        if(empty($_GET["token"])){
            $post_json = json_decode($Get_Post_Json, true);
            if(isset($post_json["token"])){
                return safetext($post_json["token"]);
            }else{
                return "_ERR:INPUT_NOT_FOUND";
            }
        }else{
            return safetext($_GET["token"]);
        }
    }elseif(empty($_GET["token"])){
        return "_ERR:INPUT_NOT_FOUND";
    }elseif(empty($_SERVER["HTTP_AUTHORIZATION"])){
        return "_ERR:INPUT_NOT_FOUND";
    }else{
        $token = strstr($_SERVER["HTTP_AUTHORIZATION"],"Bearer ");
        if($token == false){
            return "_ERR:FORMAT_FIFFERENT";
        }else{
            $token = str_replace(" ","",$token);
            if ($token == "") {
                return "_ERR:FORMAT_FIFFERENT";
            } else {
                return $token;
            }
        }
    }
}

?>
