xref: /plugin/mizarverifiabledocs/action.php (revision 4754b0a76a6bc23f6462b21189b836e85a2d37b9)
16b7e227cSYamadaMiz<?php
247595f9cSYamadaMiz
347595f9cSYamadaMizuse dokuwiki\Extension\ActionPlugin;
447595f9cSYamadaMizuse dokuwiki\Extension\EventHandler;
547595f9cSYamadaMizuse dokuwiki\Extension\Event;
647595f9cSYamadaMiz
747595f9cSYamadaMizclass action_plugin_mizarproofchecker extends ActionPlugin
847595f9cSYamadaMiz{
947595f9cSYamadaMiz    /**
10*4754b0a7SYamadaMiz     * Registers a callback function for a given event
1147595f9cSYamadaMiz     *
1247595f9cSYamadaMiz     * @param EventHandler $controller DokuWiki's event controller object
1347595f9cSYamadaMiz     * @return void
1447595f9cSYamadaMiz     */
1547595f9cSYamadaMiz    public function register(EventHandler $controller)
1647595f9cSYamadaMiz    {
176b7e227cSYamadaMiz        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handle_ajax_call');
186b7e227cSYamadaMiz    }
196b7e227cSYamadaMiz
2047595f9cSYamadaMiz    /**
2147595f9cSYamadaMiz     * Handles AJAX requests
2247595f9cSYamadaMiz     *
2347595f9cSYamadaMiz     * @param Event $event
2447595f9cSYamadaMiz     * @param $param
2547595f9cSYamadaMiz     */
2647595f9cSYamadaMiz    public function handle_ajax_call(Event $event, $param)
2747595f9cSYamadaMiz    {
286b7e227cSYamadaMiz        unset($param); // 未使用のパラメータを無効化
2947595f9cSYamadaMiz
3047595f9cSYamadaMiz        switch ($event->data) {
3147595f9cSYamadaMiz            case 'clear_temp_files':
3247595f9cSYamadaMiz                $event->preventDefault();
3347595f9cSYamadaMiz                $event->stopPropagation();
3447595f9cSYamadaMiz                $this->clearTempFiles();  // 追加: 一時ファイル削除の呼び出し
3547595f9cSYamadaMiz                break;
3647595f9cSYamadaMiz            case 'source_sse':
376b7e227cSYamadaMiz                $event->preventDefault();
386b7e227cSYamadaMiz                $event->stopPropagation();
396b7e227cSYamadaMiz                $this->handleSourceSSERequest();
4047595f9cSYamadaMiz                break;
4147595f9cSYamadaMiz            case 'source_compile':
426b7e227cSYamadaMiz                $event->preventDefault();
436b7e227cSYamadaMiz                $event->stopPropagation();
446b7e227cSYamadaMiz                $this->handleSourceCompileRequest();
4547595f9cSYamadaMiz                break;
4647595f9cSYamadaMiz            case 'view_compile':
476b7e227cSYamadaMiz                $event->preventDefault();
486b7e227cSYamadaMiz                $event->stopPropagation();
496b7e227cSYamadaMiz                $this->handleViewCompileRequest();
5047595f9cSYamadaMiz                break;
5147595f9cSYamadaMiz            case 'view_sse':
526b7e227cSYamadaMiz                $event->preventDefault();
536b7e227cSYamadaMiz                $event->stopPropagation();
546b7e227cSYamadaMiz                $this->handleViewSSERequest();
5547595f9cSYamadaMiz                break;
569fc5dc4bSYamadaMiz            case 'create_combined_file':
579fc5dc4bSYamadaMiz                $event->preventDefault();
589fc5dc4bSYamadaMiz                $event->stopPropagation();
599fc5dc4bSYamadaMiz                $this->handle_create_combined_file();
609fc5dc4bSYamadaMiz                break;
616b7e227cSYamadaMiz        }
626b7e227cSYamadaMiz    }
636b7e227cSYamadaMiz
646b7e227cSYamadaMiz    // source用のコンパイルリクエスト処理
6547595f9cSYamadaMiz    private function handleSourceCompileRequest()
6647595f9cSYamadaMiz    {
676b7e227cSYamadaMiz        global $INPUT;
686b7e227cSYamadaMiz        $pageContent = $INPUT->post->str('content');
696b7e227cSYamadaMiz        $mizarData = $this->extractMizarContent($pageContent);
706b7e227cSYamadaMiz
716b7e227cSYamadaMiz        if ($mizarData === null) {
726b7e227cSYamadaMiz            $this->sendAjaxResponse(false, 'Mizar content not found');
736b7e227cSYamadaMiz            return;
746b7e227cSYamadaMiz        }
756b7e227cSYamadaMiz
766b7e227cSYamadaMiz        $filePath = $this->saveMizarContent($mizarData);
776b7e227cSYamadaMiz
786b7e227cSYamadaMiz        session_start();
796b7e227cSYamadaMiz        $_SESSION['source_filepath'] = $filePath;
806b7e227cSYamadaMiz
816b7e227cSYamadaMiz        $this->sendAjaxResponse(true, 'Mizar content processed successfully');
826b7e227cSYamadaMiz    }
836b7e227cSYamadaMiz
846b7e227cSYamadaMiz    // source用のSSEリクエスト処理
8547595f9cSYamadaMiz    private function handleSourceSSERequest()
8647595f9cSYamadaMiz    {
876b7e227cSYamadaMiz        header('Content-Type: text/event-stream');
886b7e227cSYamadaMiz        header('Cache-Control: no-cache');
896b7e227cSYamadaMiz
906b7e227cSYamadaMiz        session_start();
916b7e227cSYamadaMiz        if (!isset($_SESSION['source_filepath'])) {
926b7e227cSYamadaMiz            echo "data: Mizar file path not found in session\n\n";
936b7e227cSYamadaMiz            ob_flush();
946b7e227cSYamadaMiz            flush();
956b7e227cSYamadaMiz            return;
966b7e227cSYamadaMiz        }
976b7e227cSYamadaMiz
986b7e227cSYamadaMiz        $filePath = $_SESSION['source_filepath'];
996b7e227cSYamadaMiz        $this->streamSourceOutput($filePath);
1006b7e227cSYamadaMiz
1016b7e227cSYamadaMiz        echo "event: end\n";
1026b7e227cSYamadaMiz        echo "data: Compilation complete\n\n";
1036b7e227cSYamadaMiz        ob_flush();
1046b7e227cSYamadaMiz        flush();
1056b7e227cSYamadaMiz    }
1066b7e227cSYamadaMiz
10747595f9cSYamadaMiz    // view用のコンパイルリクエスト処理
10847595f9cSYamadaMiz    private function handleViewCompileRequest()
10947595f9cSYamadaMiz    {
11047595f9cSYamadaMiz        global $INPUT;
11147595f9cSYamadaMiz        $content = $INPUT->post->str('content');
11247595f9cSYamadaMiz
11347595f9cSYamadaMiz        $filePath = $this->createTempFile($content);
11447595f9cSYamadaMiz
11547595f9cSYamadaMiz        session_start();
11647595f9cSYamadaMiz        $_SESSION['view_filepath'] = $filePath;
11747595f9cSYamadaMiz
11847595f9cSYamadaMiz        $this->sendAjaxResponse(true, 'Mizar content processed successfully');
11947595f9cSYamadaMiz    }
12047595f9cSYamadaMiz
12147595f9cSYamadaMiz    // view用のSSEリクエスト処理
12247595f9cSYamadaMiz    private function handleViewSSERequest()
12347595f9cSYamadaMiz    {
12447595f9cSYamadaMiz        header('Content-Type: text/event-stream');
12547595f9cSYamadaMiz        header('Cache-Control: no-cache');
12647595f9cSYamadaMiz
12747595f9cSYamadaMiz        session_start();
12847595f9cSYamadaMiz        if (!isset($_SESSION['view_filepath'])) {
12947595f9cSYamadaMiz            echo "data: Mizar file path not found in session\n\n";
13047595f9cSYamadaMiz            ob_flush();
13147595f9cSYamadaMiz            flush();
13247595f9cSYamadaMiz            return;
13347595f9cSYamadaMiz        }
13447595f9cSYamadaMiz
13547595f9cSYamadaMiz        $filePath = $_SESSION['view_filepath'];
1369fc5dc4bSYamadaMiz        $this->streamViewCompileOutput($filePath);
13747595f9cSYamadaMiz
13847595f9cSYamadaMiz        echo "event: end\n";
13947595f9cSYamadaMiz        echo "data: Compilation complete\n\n";
14047595f9cSYamadaMiz        ob_flush();
14147595f9cSYamadaMiz        flush();
14247595f9cSYamadaMiz    }
14347595f9cSYamadaMiz
14447595f9cSYamadaMiz    // Mizarコンテンツの抽出
14547595f9cSYamadaMiz    private function extractMizarContent($pageContent)
14647595f9cSYamadaMiz    {
1476b7e227cSYamadaMiz        $pattern = '/<mizar\s+([^>]+)>(.*?)<\/mizar>/s';
1486b7e227cSYamadaMiz        preg_match_all($pattern, $pageContent, $matches, PREG_SET_ORDER);
1496b7e227cSYamadaMiz
1506b7e227cSYamadaMiz        if (empty($matches)) {
15147595f9cSYamadaMiz            return null;
1526b7e227cSYamadaMiz        }
1536b7e227cSYamadaMiz
15447595f9cSYamadaMiz        $fileName = trim($matches[0][1]);
1556b7e227cSYamadaMiz        $combinedContent = '';
1566b7e227cSYamadaMiz
1576b7e227cSYamadaMiz        foreach ($matches as $match) {
1586b7e227cSYamadaMiz            if (trim($match[1]) !== $fileName) {
1596b7e227cSYamadaMiz                return ['error' => 'File name mismatch in <mizar> tags'];
1606b7e227cSYamadaMiz            }
1616b7e227cSYamadaMiz            $combinedContent .= trim($match[2]) . "\n";
1626b7e227cSYamadaMiz        }
1636b7e227cSYamadaMiz
1646b7e227cSYamadaMiz        return ['fileName' => $fileName, 'content' => $combinedContent];
1656b7e227cSYamadaMiz    }
1666b7e227cSYamadaMiz
16747595f9cSYamadaMiz    // Mizarコンテンツの保存
16847595f9cSYamadaMiz    private function saveMizarContent($mizarData)
16947595f9cSYamadaMiz    {
1706b7e227cSYamadaMiz        $workPath = rtrim($this->getConf('mizar_work_dir'), '/\\');
1716b7e227cSYamadaMiz        $filePath = $workPath . "/TEXT/" . $mizarData['fileName'];
1726b7e227cSYamadaMiz        file_put_contents($filePath, $mizarData['content']);
1736b7e227cSYamadaMiz        return $filePath;
1746b7e227cSYamadaMiz    }
1756b7e227cSYamadaMiz
17647595f9cSYamadaMiz    // source用の出力をストリーム
17747595f9cSYamadaMiz    private function streamSourceOutput($filePath)
17847595f9cSYamadaMiz    {
1796b7e227cSYamadaMiz        $workPath = rtrim($this->getConf('mizar_work_dir'), '/\\');
1806b7e227cSYamadaMiz        chdir($workPath);
1816b7e227cSYamadaMiz
1826b7e227cSYamadaMiz        $command = "miz2prel " . escapeshellarg($filePath);
1836b7e227cSYamadaMiz        $process = proc_open($command, array(1 => array("pipe", "w")), $pipes);
1846b7e227cSYamadaMiz
1856b7e227cSYamadaMiz        if (is_resource($process)) {
1866b7e227cSYamadaMiz            while ($line = fgets($pipes[1])) {
1876b7e227cSYamadaMiz                echo "data: " . $line . "\n\n";
1886b7e227cSYamadaMiz                ob_flush();
1896b7e227cSYamadaMiz                flush();
1906b7e227cSYamadaMiz            }
1916b7e227cSYamadaMiz            fclose($pipes[1]);
1929fc5dc4bSYamadaMiz
1939fc5dc4bSYamadaMiz            // エラー処理の追加
1949fc5dc4bSYamadaMiz            $errFilename = str_replace('.miz', '.err', $filePath);
1959fc5dc4bSYamadaMiz            if ($this->handleCompilationErrors($errFilename, rtrim($this->getConf('mizar_share_dir'), '/\\') . '/mizar.msg')) {
1969fc5dc4bSYamadaMiz                // エラーがあった場合は処理を終了
1979fc5dc4bSYamadaMiz                proc_close($process);
1989fc5dc4bSYamadaMiz                return;
1999fc5dc4bSYamadaMiz            }
2009fc5dc4bSYamadaMiz
2016b7e227cSYamadaMiz            proc_close($process);
2026b7e227cSYamadaMiz        }
2036b7e227cSYamadaMiz    }
2046b7e227cSYamadaMiz
20547595f9cSYamadaMiz    // view用の一時ファイル作成
20647595f9cSYamadaMiz    private function createTempFile($content)
20747595f9cSYamadaMiz    {
2086b7e227cSYamadaMiz        $workPath = rtrim($this->getConf('mizar_work_dir'), '/\\') . '/TEXT/';
20947595f9cSYamadaMiz        $uniqueName = str_replace('.', '_', uniqid('tmp', true));
2106b7e227cSYamadaMiz        $tempFilename = $workPath . $uniqueName . ".miz";
2116b7e227cSYamadaMiz        file_put_contents($tempFilename, $content);
2126b7e227cSYamadaMiz        return $tempFilename;
2136b7e227cSYamadaMiz    }
2146b7e227cSYamadaMiz
21547595f9cSYamadaMiz    //  Clear all temporary files in the TEXT folder
21647595f9cSYamadaMiz    private function clearTempFiles()
21747595f9cSYamadaMiz    {
21847595f9cSYamadaMiz        $workPath = rtrim($this->getConf('mizar_work_dir'), '/\\') . '/TEXT/';
21947595f9cSYamadaMiz        $files = glob($workPath . '*');  // TEXTフォルダ内のすべてのファイルを取得
22047595f9cSYamadaMiz
22147595f9cSYamadaMiz        $errors = [];
22247595f9cSYamadaMiz        foreach ($files as $file) {
22347595f9cSYamadaMiz            if (is_file($file)) {
22447595f9cSYamadaMiz                // ファイルが使用中かどうか確認
22547595f9cSYamadaMiz                if (!$this->is_file_locked($file)) {
22647595f9cSYamadaMiz                    $retries = 3; // 最大3回リトライ
22747595f9cSYamadaMiz                    while ($retries > 0) {
22847595f9cSYamadaMiz                        if (unlink($file)) {
22947595f9cSYamadaMiz                            break; // 削除成功
23047595f9cSYamadaMiz                        }
2315cbf3a53SYamadaMiz                        $errors[] = "Error deleting $file: " . error_get_last()['message'];
23247595f9cSYamadaMiz                        $retries--;
23347595f9cSYamadaMiz                        sleep(1); // 1秒待ってリトライ
23447595f9cSYamadaMiz                    }
23547595f9cSYamadaMiz                    if ($retries === 0) {
23647595f9cSYamadaMiz                        $errors[] = "Failed to delete: $file";  // 削除失敗
23747595f9cSYamadaMiz                    }
23847595f9cSYamadaMiz                } else {
23947595f9cSYamadaMiz                    $errors[] = "File is locked: $file";  // ファイルがロックされている
24047595f9cSYamadaMiz                }
24147595f9cSYamadaMiz            }
24247595f9cSYamadaMiz        }
24347595f9cSYamadaMiz
24447595f9cSYamadaMiz        if (empty($errors)) {
24547595f9cSYamadaMiz            $this->sendAjaxResponse(true, 'Temporary files cleared successfully');
24647595f9cSYamadaMiz        } else {
24747595f9cSYamadaMiz            $this->sendAjaxResponse(false, 'Some files could not be deleted', $errors);
24847595f9cSYamadaMiz        }
24947595f9cSYamadaMiz    }
25047595f9cSYamadaMiz
25147595f9cSYamadaMiz    // ファイルがロックされているかをチェックする関数
25247595f9cSYamadaMiz    private function is_file_locked($file)
25347595f9cSYamadaMiz    {
25447595f9cSYamadaMiz        $fileHandle = @fopen($file, "r+");
25547595f9cSYamadaMiz
25647595f9cSYamadaMiz        if ($fileHandle === false) {
25747595f9cSYamadaMiz            return true; // ファイルが開けない、つまりロックされているかアクセス権がない
25847595f9cSYamadaMiz        }
25947595f9cSYamadaMiz
26047595f9cSYamadaMiz        $locked = !flock($fileHandle, LOCK_EX | LOCK_NB); // ロックの取得を試みる(非ブロッキングモード)
26147595f9cSYamadaMiz
26247595f9cSYamadaMiz        fclose($fileHandle);
26347595f9cSYamadaMiz        return $locked; // ロックが取得できなければファイルはロックされている
26447595f9cSYamadaMiz    }
26547595f9cSYamadaMiz
2669fc5dc4bSYamadaMiz    // View用コンパイル出力のストリーム
2679fc5dc4bSYamadaMiz    private function streamViewCompileOutput($filePath)
26847595f9cSYamadaMiz    {
2696b7e227cSYamadaMiz        $workPath = $this->getConf('mizar_work_dir');
2706b7e227cSYamadaMiz        $sharePath = rtrim($this->getConf('mizar_share_dir'), '/\\') . '/';
2716b7e227cSYamadaMiz
2726b7e227cSYamadaMiz        chdir($workPath);
2736b7e227cSYamadaMiz
2749fc5dc4bSYamadaMiz        $errFilename = str_replace('.miz', '.err', $filePath);
2756b7e227cSYamadaMiz        $command = "makeenv " . escapeshellarg($filePath);
2766b7e227cSYamadaMiz        $process = proc_open($command, array(1 => array("pipe", "w"), 2 => array("pipe", "w")), $pipes);
2776b7e227cSYamadaMiz
2786b7e227cSYamadaMiz        if (is_resource($process)) {
2796b7e227cSYamadaMiz            while ($line = fgets($pipes[1])) {
2806b7e227cSYamadaMiz                echo "data: " . mb_convert_encoding($line, 'UTF-8', 'SJIS') . "\n\n";
2816b7e227cSYamadaMiz                ob_flush();
2826b7e227cSYamadaMiz                flush();
2836b7e227cSYamadaMiz            }
2846b7e227cSYamadaMiz            fclose($pipes[1]);
2856b7e227cSYamadaMiz
2866b7e227cSYamadaMiz            while ($line = fgets($pipes[2])) {
2876b7e227cSYamadaMiz                echo "data: ERROR: " . mb_convert_encoding($line, 'UTF-8', 'SJIS') . "\n\n";
2886b7e227cSYamadaMiz                ob_flush();
2896b7e227cSYamadaMiz                flush();
2906b7e227cSYamadaMiz            }
2916b7e227cSYamadaMiz            fclose($pipes[2]);
2926b7e227cSYamadaMiz            proc_close($process);
2936b7e227cSYamadaMiz
2949fc5dc4bSYamadaMiz            // エラー処理を別の関数に移動
2959fc5dc4bSYamadaMiz            if ($this->handleCompilationErrors($errFilename, $sharePath . '/mizar.msg')) {
2966b7e227cSYamadaMiz                return;
2976b7e227cSYamadaMiz            }
2986b7e227cSYamadaMiz
2996b7e227cSYamadaMiz            // verifierの実行
3006b7e227cSYamadaMiz            $exePath = rtrim($this->getConf('mizar_exe_dir'), '/\\') . '/';
3016b7e227cSYamadaMiz            $verifierPath = escapeshellarg($exePath . "verifier");
3026b7e227cSYamadaMiz            if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
3036b7e227cSYamadaMiz                $verifierPath .= ".exe";
3046b7e227cSYamadaMiz            }
3056b7e227cSYamadaMiz            $verifierCommand = $verifierPath . " -q -l " . escapeshellarg("TEXT/" . basename($filePath));
3066b7e227cSYamadaMiz
3076b7e227cSYamadaMiz            $verifierProcess = proc_open($verifierCommand, array(1 => array("pipe", "w"), 2 => array("pipe", "w")), $verifierPipes);
3086b7e227cSYamadaMiz
3096b7e227cSYamadaMiz            if (is_resource($verifierProcess)) {
3106b7e227cSYamadaMiz                while ($line = fgets($verifierPipes[1])) {
3116b7e227cSYamadaMiz                    echo "data: " . mb_convert_encoding($line, 'UTF-8', 'SJIS') . "\n\n";
3126b7e227cSYamadaMiz                    ob_flush();
3136b7e227cSYamadaMiz                    flush();
3146b7e227cSYamadaMiz                }
3156b7e227cSYamadaMiz                fclose($verifierPipes[1]);
3166b7e227cSYamadaMiz
3176b7e227cSYamadaMiz                while ($line = fgets($verifierPipes[2])) {
3186b7e227cSYamadaMiz                    echo "data: ERROR: " . mb_convert_encoding($line, 'UTF-8', 'SJIS') . "\n\n";
3196b7e227cSYamadaMiz                    ob_flush();
3206b7e227cSYamadaMiz                    flush();
3216b7e227cSYamadaMiz                }
3226b7e227cSYamadaMiz                fclose($verifierPipes[2]);
3236b7e227cSYamadaMiz                proc_close($verifierProcess);
3246b7e227cSYamadaMiz            } else {
3256b7e227cSYamadaMiz                echo "data: ERROR: Failed to execute verifier command.\n\n";
3266b7e227cSYamadaMiz                ob_flush();
3276b7e227cSYamadaMiz                flush();
3286b7e227cSYamadaMiz            }
3296b7e227cSYamadaMiz        } else {
3306b7e227cSYamadaMiz            echo "data: ERROR: Failed to execute makeenv command.\n\n";
3316b7e227cSYamadaMiz            ob_flush();
3326b7e227cSYamadaMiz            flush();
3336b7e227cSYamadaMiz        }
3346b7e227cSYamadaMiz    }
3356b7e227cSYamadaMiz
33647595f9cSYamadaMiz    private function getMizarErrorMessages($mizarMsgFile)
33747595f9cSYamadaMiz    {
3386b7e227cSYamadaMiz        $errorMessages = [];
3396b7e227cSYamadaMiz        $lines = file($mizarMsgFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
3406b7e227cSYamadaMiz
3416b7e227cSYamadaMiz        $isReadingErrorMsg = false;
3426b7e227cSYamadaMiz        $key = 0;
3436b7e227cSYamadaMiz
3446b7e227cSYamadaMiz        foreach ($lines as $line) {
3456b7e227cSYamadaMiz            if (preg_match('/# (\d+)/', $line, $matches)) {
3466b7e227cSYamadaMiz                $isReadingErrorMsg = true;
3476b7e227cSYamadaMiz                $key = intval($matches[1]);
3486b7e227cSYamadaMiz            } elseif ($isReadingErrorMsg) {
3496b7e227cSYamadaMiz                $errorMessages[$key] = $line;
3506b7e227cSYamadaMiz                $isReadingErrorMsg = false;
3516b7e227cSYamadaMiz            }
3526b7e227cSYamadaMiz        }
3536b7e227cSYamadaMiz
3546b7e227cSYamadaMiz        return $errorMessages;
3556b7e227cSYamadaMiz    }
3566b7e227cSYamadaMiz
35747595f9cSYamadaMiz    private function sendAjaxResponse($success, $message, $data = '')
35847595f9cSYamadaMiz    {
3596b7e227cSYamadaMiz        header('Content-Type: application/json');
3606b7e227cSYamadaMiz        echo json_encode(['success' => $success, 'message' => $message, 'data' => $data]);
3616b7e227cSYamadaMiz        exit;
3626b7e227cSYamadaMiz    }
3639fc5dc4bSYamadaMiz
3649fc5dc4bSYamadaMiz    private function handleCompilationErrors($errFilename, $mizarMsgFilePath)
3659fc5dc4bSYamadaMiz    {
3669fc5dc4bSYamadaMiz        if (file_exists($errFilename)) {
3679fc5dc4bSYamadaMiz            $errors = [];
3689fc5dc4bSYamadaMiz            $errorLines = file($errFilename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
3699fc5dc4bSYamadaMiz            if (empty($errorLines)) {
3709fc5dc4bSYamadaMiz            }
3719fc5dc4bSYamadaMiz            foreach ($errorLines as $errorLine) {
3729fc5dc4bSYamadaMiz                if (preg_match('/(\d+)\s+(\d+)\s+(\d+)/', $errorLine, $matches)) {
3739fc5dc4bSYamadaMiz                    $errorCode = intval($matches[3]);
3749fc5dc4bSYamadaMiz                    $errors[] = [
3759fc5dc4bSYamadaMiz                        'code' => $errorCode,
3769fc5dc4bSYamadaMiz                        'line' => intval($matches[1]),
3779fc5dc4bSYamadaMiz                        'column' => intval($matches[2]),
3789fc5dc4bSYamadaMiz                        'message' => $this->getMizarErrorMessages($mizarMsgFilePath)[$errorCode] ?? 'Unknown error'
3799fc5dc4bSYamadaMiz                    ];
3809fc5dc4bSYamadaMiz                }
3819fc5dc4bSYamadaMiz            }
3829fc5dc4bSYamadaMiz            if (!empty($errors)) {
3839fc5dc4bSYamadaMiz                echo "event: compileErrors\n";
3849fc5dc4bSYamadaMiz                echo "data: " . json_encode($errors) . "\n\n";
3859fc5dc4bSYamadaMiz                ob_flush();
3869fc5dc4bSYamadaMiz                flush();
3879fc5dc4bSYamadaMiz                return true;
3889fc5dc4bSYamadaMiz            }
3899fc5dc4bSYamadaMiz        }
3909fc5dc4bSYamadaMiz        return false;
3919fc5dc4bSYamadaMiz    }
3929fc5dc4bSYamadaMiz
3939fc5dc4bSYamadaMiz    private function handle_create_combined_file()
3949fc5dc4bSYamadaMiz    {
3959fc5dc4bSYamadaMiz        global $INPUT;
3969fc5dc4bSYamadaMiz
3979fc5dc4bSYamadaMiz        // 投稿されたコンテンツを取得
3989fc5dc4bSYamadaMiz        $combinedContent = $INPUT->post->str('content');
3999fc5dc4bSYamadaMiz        $filename = $INPUT->post->str('filename', 'combined_file.miz'); // ファイル名を取得、デフォルト名も設定
4009fc5dc4bSYamadaMiz
4019fc5dc4bSYamadaMiz        // ファイルパスを指定
4029fc5dc4bSYamadaMiz        $workPath = rtrim($this->getConf('mizar_work_dir'), '/\\') . '/TEXT/';
4039fc5dc4bSYamadaMiz        $filePath = $workPath . $filename;
4049fc5dc4bSYamadaMiz
4059fc5dc4bSYamadaMiz        // ファイルを書き込み
4069fc5dc4bSYamadaMiz        if (file_put_contents($filePath, $combinedContent) !== false) {
4079fc5dc4bSYamadaMiz            // コピー先ディレクトリのパスを指定
4089fc5dc4bSYamadaMiz            $copyDir = DOKU_INC . 'lib/plugins/mizarproofchecker/TEXT/';
4099fc5dc4bSYamadaMiz
4109fc5dc4bSYamadaMiz            // コピー先ディレクトリが存在しない場合は作成する
4119fc5dc4bSYamadaMiz            if (!is_dir($copyDir)) {
4129fc5dc4bSYamadaMiz                mkdir($copyDir, 0777, true);
4139fc5dc4bSYamadaMiz            }
4149fc5dc4bSYamadaMiz
4159fc5dc4bSYamadaMiz            // ファイルをコピー
4169fc5dc4bSYamadaMiz            if (copy($filePath, $copyDir . basename($filePath))) {
4179fc5dc4bSYamadaMiz                $fileUrl = DOKU_BASE . 'lib/plugins/mizarproofchecker/TEXT/' . urlencode($filename);
4189fc5dc4bSYamadaMiz                $this->sendAjaxResponse(true, 'File created successfully', ['fileUrl' => $fileUrl]);
4199fc5dc4bSYamadaMiz                error_log("Generated file URL: " . $fileUrl);
4209fc5dc4bSYamadaMiz            } else {
4219fc5dc4bSYamadaMiz                $this->sendAjaxResponse(false, 'Failed to copy file');
4229fc5dc4bSYamadaMiz            }
4239fc5dc4bSYamadaMiz        } else {
4249fc5dc4bSYamadaMiz            $this->sendAjaxResponse(false, 'Failed to create file');
4259fc5dc4bSYamadaMiz        }
4269fc5dc4bSYamadaMiz    }
4276b7e227cSYamadaMiz}