feat: initial project setup with Laravel 12 and Filament v4
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
@echo off
|
||||
setlocal
|
||||
set "SCRIPTS_DIR=%~dp0"
|
||||
set "SCRIPTS_DIR=%SCRIPTS_DIR:~0,-1%"
|
||||
for %%F in ("%SCRIPTS_DIR%\..") do set "PROJECT_DIR=%%~fF"
|
||||
set "PHP=%SCRIPTS_DIR%\php\php.exe"
|
||||
|
||||
echo ===================================
|
||||
echo Storage Fix - Matab Panel
|
||||
echo ===================================
|
||||
echo.
|
||||
|
||||
echo [1/2] Fixing storage link (no admin needed)...
|
||||
echo [2/2] Scanning for orphan files...
|
||||
echo.
|
||||
|
||||
"%PHP%" "%SCRIPTS_DIR%\fix_storage.php" --delete
|
||||
|
||||
echo.
|
||||
pause
|
||||
@@ -0,0 +1,36 @@
|
||||
$vbsPath = 'D:\git\matab-panel\scripts\start-server.vbs'
|
||||
$taskName = 'MatabPanel'
|
||||
|
||||
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
|
||||
|
||||
$action = New-ScheduledTaskAction -Execute 'wscript.exe' -Argument "`"$vbsPath`""
|
||||
|
||||
$trigger = New-ScheduledTaskTrigger -AtLogOn -User $env:USERNAME
|
||||
$trigger.Delay = 'PT20S'
|
||||
|
||||
$settings = New-ScheduledTaskSettingsSet `
|
||||
-ExecutionTimeLimit (New-TimeSpan -Hours 0) `
|
||||
-MultipleInstances IgnoreNew `
|
||||
-StartWhenAvailable
|
||||
|
||||
$principal = New-ScheduledTaskPrincipal `
|
||||
-UserId $env:USERNAME `
|
||||
-LogonType Interactive `
|
||||
-RunLevel Limited
|
||||
|
||||
Register-ScheduledTask `
|
||||
-TaskName $taskName `
|
||||
-Action $action `
|
||||
-Trigger $trigger `
|
||||
-Settings $settings `
|
||||
-Principal $principal `
|
||||
-Force
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Task created. Verifying..."
|
||||
$info = Get-ScheduledTaskInfo -TaskName $taskName
|
||||
Write-Host " State : $((Get-ScheduledTask -TaskName $taskName).State)"
|
||||
Write-Host " Last Run : $($info.LastRunTime)"
|
||||
Write-Host " Next Run : $($info.NextRunTime)"
|
||||
Write-Host ""
|
||||
Write-Host "DONE. Task will run 20s after next login."
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
define('LARAVEL_START', microtime(true));
|
||||
|
||||
$projectRoot = dirname(__DIR__);
|
||||
|
||||
require $projectRoot . '/vendor/autoload.php';
|
||||
|
||||
$app = require_once $projectRoot . '/bootstrap/app.php';
|
||||
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
|
||||
$kernel->bootstrap();
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
$dryRun = !in_array('--delete', $argv ?? []);
|
||||
echo "\n=== ۱. Storage Link Fix ===\n\n";
|
||||
|
||||
$link = $projectRoot . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'storage';
|
||||
$target = $projectRoot . DIRECTORY_SEPARATOR . 'storage' . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . 'public';
|
||||
|
||||
echo "Link : {$link}\n";
|
||||
echo "Target : {$target}\n\n";
|
||||
|
||||
if (!is_dir($target)) {
|
||||
echo "ERROR: Target directory not found!\n";
|
||||
} else {
|
||||
if (is_link($link) || (PHP_OS_FAMILY === 'Windows' && is_dir($link))) {
|
||||
if (PHP_OS_FAMILY === 'Windows') {
|
||||
exec('rmdir "' . $link . '"', $out, $code);
|
||||
} else {
|
||||
unlink($link);
|
||||
}
|
||||
echo "Old link removed.\n";
|
||||
}
|
||||
|
||||
if (!file_exists($link) && !is_dir($link)) {
|
||||
if (PHP_OS_FAMILY === 'Windows') {
|
||||
exec('mklink /J "' . $link . '" "' . $target . '"', $out, $code);
|
||||
if ($code === 0) {
|
||||
echo "Junction created successfully! (no admin needed)\n";
|
||||
} else {
|
||||
echo "ERROR: " . implode("\n", $out) . "\n";
|
||||
}
|
||||
} else {
|
||||
if (symlink($target, $link)) {
|
||||
echo "Symlink created successfully!\n";
|
||||
} else {
|
||||
echo "ERROR: Could not create symlink.\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo "OK: Link already exists and points to correct target.\n";
|
||||
}
|
||||
}
|
||||
echo "\n=== ۲. Orphan Files Cleanup ===\n";
|
||||
echo $dryRun ? "Mode: DRY RUN (add --delete to actually delete)\n\n" : "Mode: DELETE\n\n";
|
||||
|
||||
$referencedFiles = [];
|
||||
|
||||
$patients = DB::table('patients')->select('photos_before', 'photos_after', 'videos', 'audio_files')->get();
|
||||
foreach ($patients as $p) {
|
||||
foreach (['photos_before', 'photos_after', 'videos', 'audio_files'] as $field) {
|
||||
foreach (json_decode($p->$field ?? '[]', true) ?? [] as $file) {
|
||||
$referencedFiles[] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$initials = DB::table('osurg_initials')->select('attachment')->whereNotNull('attachment')->get();
|
||||
foreach ($initials as $i) {
|
||||
if ($i->attachment) {
|
||||
$referencedFiles[] = $i->attachment;
|
||||
}
|
||||
}
|
||||
|
||||
$referencedFiles = array_filter($referencedFiles);
|
||||
echo "Files referenced in DB: " . count($referencedFiles) . "\n\n";
|
||||
|
||||
$dirs = ['patients/photos-before', 'patients/photos-after', 'patients/videos', 'patients/audio', 'initials'];
|
||||
$totalOrphans = 0;
|
||||
$totalSize = 0;
|
||||
|
||||
foreach ($dirs as $dir) {
|
||||
$diskFiles = Storage::disk('public')->files($dir);
|
||||
|
||||
if (empty($diskFiles)) {
|
||||
echo "[{$dir}] No files.\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
$orphans = array_values(array_filter($diskFiles, fn($f) => !in_array($f, $referencedFiles)));
|
||||
|
||||
echo "[{$dir}] total=" . count($diskFiles) . " orphans=" . count($orphans) . "\n";
|
||||
|
||||
foreach ($orphans as $orphan) {
|
||||
$size = Storage::disk('public')->size($orphan);
|
||||
$totalSize += $size;
|
||||
$totalOrphans++;
|
||||
echo " - {$orphan} (" . number_format($size / 1024, 1) . " KB)";
|
||||
|
||||
if (!$dryRun) {
|
||||
Storage::disk('public')->delete($orphan);
|
||||
echo " [DELETED]";
|
||||
}
|
||||
echo "\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "\n─────────────────────────────────\n";
|
||||
echo "Orphan files : {$totalOrphans}\n";
|
||||
echo "Wasted space : " . number_format($totalSize / 1024 / 1024, 2) . " MB\n";
|
||||
|
||||
if ($dryRun && $totalOrphans > 0) {
|
||||
echo "\nبرای حذف اجرا کن:\n php scripts/fix_storage.php --delete\n";
|
||||
}
|
||||
|
||||
echo "\nDone!\n";
|
||||
@@ -0,0 +1,278 @@
|
||||
<?php
|
||||
|
||||
|
||||
set_time_limit(0);
|
||||
error_reporting(E_ERROR);
|
||||
|
||||
$FTP_HOST = '0.0.0.0';
|
||||
$FTP_PORT = 2121;
|
||||
$FTP_USER = 'root';
|
||||
$FTP_PASS = 'Mjoshanitcm7717';
|
||||
$FTP_ROOT = realpath(__DIR__ . '/../storage/app/public');
|
||||
|
||||
$envFile = __DIR__ . '/../.env';
|
||||
if (file_exists($envFile)) {
|
||||
foreach (file($envFile) as $line) {
|
||||
$line = trim($line);
|
||||
if (strpos($line, '=') === false || strpos($line, '#') === 0) continue;
|
||||
[$key, $val] = explode('=', $line, 2);
|
||||
$key = trim($key); $val = trim($val, "\" \t\n\r");
|
||||
if ($key === 'FTP_PORT') $FTP_PORT = (int)$val;
|
||||
if ($key === 'FTP_USER') $FTP_USER = $val;
|
||||
if ($key === 'FTP_PASS') $FTP_PASS = $val;
|
||||
if ($key === 'FTP_ROOT') $FTP_ROOT = $val;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$FTP_ROOT || !is_dir($FTP_ROOT)) {
|
||||
die("ERROR: Root dir not found: {$FTP_ROOT}\n");
|
||||
}
|
||||
|
||||
$server = @stream_socket_server("tcp://{$FTP_HOST}:{$FTP_PORT}", $errno, $errstr);
|
||||
if (!$server) {
|
||||
die("ERROR: Cannot start FTP server on port {$FTP_PORT}: {$errstr}\n"
|
||||
. "Hint: Run as Administrator or change FTP_PORT in .env\n");
|
||||
}
|
||||
|
||||
echo "=========================================\n";
|
||||
echo " matab-panel FTP Server\n";
|
||||
echo "=========================================\n";
|
||||
echo "Port : {$FTP_PORT}\n";
|
||||
echo "User : {$FTP_USER}\n";
|
||||
echo "Root : {$FTP_ROOT}\n";
|
||||
echo "Press Ctrl+C to stop\n\n";
|
||||
|
||||
while ($ctrl = stream_socket_accept($server, -1)) {
|
||||
$peer = stream_socket_get_name($ctrl, true);
|
||||
echo "[" . date('H:i:s') . "] Connected: {$peer}\n";
|
||||
try {
|
||||
ftpSession($ctrl, $FTP_USER, $FTP_PASS, $FTP_ROOT);
|
||||
} catch (\Throwable $e) {
|
||||
echo "Error: " . $e->getMessage() . "\n";
|
||||
}
|
||||
fclose($ctrl);
|
||||
echo "[" . date('H:i:s') . "] Disconnected: {$peer}\n";
|
||||
}
|
||||
fclose($server);
|
||||
|
||||
|
||||
function ftpSend($ctrl, string $msg): void
|
||||
{
|
||||
fwrite($ctrl, $msg . "\r\n");
|
||||
}
|
||||
|
||||
function ftpRead($ctrl): string
|
||||
{
|
||||
$line = fgets($ctrl, 8192);
|
||||
return $line ? rtrim($line, "\r\n") : '';
|
||||
}
|
||||
|
||||
function ftpOpenData(&$pasvSock): mixed
|
||||
{
|
||||
if (!$pasvSock) return null;
|
||||
stream_set_timeout($pasvSock, 15);
|
||||
$data = stream_socket_accept($pasvSock, 15);
|
||||
fclose($pasvSock);
|
||||
$pasvSock = null;
|
||||
return $data ?: null;
|
||||
}
|
||||
|
||||
function ftpResolvePath(string $cwd, string $arg, string $root): ?string
|
||||
{
|
||||
if ($arg === '') {
|
||||
$path = $cwd;
|
||||
} elseif ($arg[0] === '/') {
|
||||
$path = $arg;
|
||||
} else {
|
||||
$path = rtrim($cwd, '/') . '/' . $arg;
|
||||
}
|
||||
// Normalize
|
||||
$parts = explode('/', $path);
|
||||
$out = [];
|
||||
foreach ($parts as $p) {
|
||||
if ($p === '' || $p === '.') continue;
|
||||
if ($p === '..') { array_pop($out); } else { $out[] = $p; }
|
||||
}
|
||||
$path = '/' . implode('/', $out);
|
||||
$real = realpath($root . $path);
|
||||
if ($real !== false && strpos($real, realpath($root)) !== 0) return null;
|
||||
return $path;
|
||||
}
|
||||
|
||||
function ftpSession($ctrl, string $user, string $pass, string $root): void
|
||||
{
|
||||
$cwd = '/';
|
||||
$authed = false;
|
||||
$pendUser = '';
|
||||
$pasvSock = null;
|
||||
|
||||
ftpSend($ctrl, '220 matab-panel FTP Server');
|
||||
|
||||
while (!feof($ctrl)) {
|
||||
$line = ftpRead($ctrl);
|
||||
if ($line === '') continue;
|
||||
|
||||
$parts = explode(' ', $line, 2);
|
||||
$cmd = strtoupper($parts[0]);
|
||||
$arg = isset($parts[1]) ? trim($parts[1]) : '';
|
||||
|
||||
switch ($cmd) {
|
||||
|
||||
case 'USER':
|
||||
$pendUser = $arg;
|
||||
ftpSend($ctrl, '331 Password required');
|
||||
break;
|
||||
|
||||
case 'PASS':
|
||||
if ($pendUser === $user && $arg === $pass) {
|
||||
$authed = true;
|
||||
ftpSend($ctrl, '230 Login successful');
|
||||
echo " Auth OK\n";
|
||||
} else {
|
||||
ftpSend($ctrl, '530 Login incorrect');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'SYST':
|
||||
ftpSend($ctrl, '215 UNIX Type: L8');
|
||||
break;
|
||||
|
||||
case 'FEAT':
|
||||
ftpSend($ctrl, "211-Features:\r\n PASV\r\n211 End");
|
||||
break;
|
||||
|
||||
case 'TYPE':
|
||||
ftpSend($ctrl, '200 Type set to ' . ($arg ?: 'I'));
|
||||
break;
|
||||
|
||||
case 'PWD': case 'XPWD':
|
||||
if (!$authed) { ftpSend($ctrl, '530 Not logged in'); break; }
|
||||
ftpSend($ctrl, '257 "' . $cwd . '"');
|
||||
break;
|
||||
|
||||
case 'CWD': case 'XCWD':
|
||||
if (!$authed) { ftpSend($ctrl, '530 Not logged in'); break; }
|
||||
$p = ftpResolvePath($cwd, $arg, $root);
|
||||
if ($p !== null && is_dir($root . $p)) {
|
||||
$cwd = $p;
|
||||
ftpSend($ctrl, '250 OK');
|
||||
} else {
|
||||
ftpSend($ctrl, '550 No such directory');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'CDUP':
|
||||
if (!$authed) { ftpSend($ctrl, '530 Not logged in'); break; }
|
||||
$cwd = dirname($cwd) ?: '/';
|
||||
ftpSend($ctrl, '200 OK');
|
||||
break;
|
||||
|
||||
case 'MKD': case 'XMKD':
|
||||
if (!$authed) { ftpSend($ctrl, '530 Not logged in'); break; }
|
||||
$p = ftpResolvePath($cwd, $arg, $root);
|
||||
if ($p !== null) {
|
||||
$full = $root . $p;
|
||||
if (!is_dir($full)) mkdir($full, 0755, true);
|
||||
ftpSend($ctrl, '257 "' . $p . '" created');
|
||||
} else {
|
||||
ftpSend($ctrl, '550 Failed');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PASV':
|
||||
if (!$authed) { ftpSend($ctrl, '530 Not logged in'); break; }
|
||||
if ($pasvSock) fclose($pasvSock);
|
||||
$pasvPort = rand(49152, 65534);
|
||||
$pasvSock = @stream_socket_server("tcp://0.0.0.0:{$pasvPort}", $e1, $e2);
|
||||
if (!$pasvSock) { ftpSend($ctrl, '425 Cannot open passive connection'); break; }
|
||||
$localAddr = stream_socket_get_name($ctrl, false);
|
||||
$localIp = explode(':', $localAddr)[0];
|
||||
$p1 = intdiv($pasvPort, 256);
|
||||
$p2 = $pasvPort % 256;
|
||||
ftpSend($ctrl, '227 Entering Passive Mode (' . str_replace('.', ',', $localIp) . ",{$p1},{$p2})");
|
||||
break;
|
||||
|
||||
case 'LIST': case 'NLST':
|
||||
if (!$authed) { ftpSend($ctrl, '530 Not logged in'); break; }
|
||||
$data = ftpOpenData($pasvSock);
|
||||
if (!$data) { ftpSend($ctrl, '425 No data connection'); break; }
|
||||
ftpSend($ctrl, '150 Opening data connection');
|
||||
$dirPath = $root . $cwd;
|
||||
$list = '';
|
||||
if (is_dir($dirPath)) {
|
||||
foreach (scandir($dirPath) as $f) {
|
||||
if ($f === '.' || $f === '..') continue;
|
||||
$fp = $dirPath . '/' . $f;
|
||||
$size = is_file($fp) ? filesize($fp) : 0;
|
||||
$type = is_dir($fp) ? 'd' : '-';
|
||||
$list .= "{$type}rw-r--r-- 1 root root {$size} Jan 1 00:00 {$f}\r\n";
|
||||
}
|
||||
}
|
||||
fwrite($data, $list);
|
||||
fclose($data);
|
||||
ftpSend($ctrl, '226 Transfer complete');
|
||||
break;
|
||||
|
||||
case 'STOR':
|
||||
if (!$authed) { ftpSend($ctrl, '530 Not logged in'); break; }
|
||||
$p = ftpResolvePath($cwd, $arg, $root);
|
||||
if ($p === null) { ftpSend($ctrl, '550 Invalid path'); break; }
|
||||
$full = $root . $p;
|
||||
$dir = dirname($full);
|
||||
if (!is_dir($dir)) mkdir($dir, 0755, true);
|
||||
$data = ftpOpenData($pasvSock);
|
||||
if (!$data) { ftpSend($ctrl, '425 No data connection'); break; }
|
||||
ftpSend($ctrl, '150 Ready to receive');
|
||||
$fp = fopen($full, 'wb');
|
||||
if (!$fp) { fclose($data); ftpSend($ctrl, '550 Cannot write file'); break; }
|
||||
while (!feof($data)) {
|
||||
$buf = fread($data, 65536);
|
||||
if ($buf !== false && $buf !== '') fwrite($fp, $buf);
|
||||
}
|
||||
fclose($fp);
|
||||
fclose($data);
|
||||
echo " STOR: {$p} (" . number_format(filesize($full)) . " bytes)\n";
|
||||
ftpSend($ctrl, '226 Transfer complete');
|
||||
break;
|
||||
|
||||
case 'RETR':
|
||||
if (!$authed) { ftpSend($ctrl, '530 Not logged in'); break; }
|
||||
$p = ftpResolvePath($cwd, $arg, $root);
|
||||
if ($p === null || !file_exists($root . $p)) { ftpSend($ctrl, '550 File not found'); break; }
|
||||
$data = ftpOpenData($pasvSock);
|
||||
if (!$data) { ftpSend($ctrl, '425 No data connection'); break; }
|
||||
ftpSend($ctrl, '150 Opening data connection');
|
||||
$fp = fopen($root . $p, 'rb');
|
||||
while (!feof($fp)) {
|
||||
$buf = fread($fp, 65536);
|
||||
if ($buf !== false && $buf !== '') fwrite($data, $buf);
|
||||
}
|
||||
fclose($fp);
|
||||
fclose($data);
|
||||
echo " RETR: {$p}\n";
|
||||
ftpSend($ctrl, '226 Transfer complete');
|
||||
break;
|
||||
|
||||
case 'SIZE':
|
||||
if (!$authed) { ftpSend($ctrl, '530 Not logged in'); break; }
|
||||
$p = ftpResolvePath($cwd, $arg, $root);
|
||||
if ($p !== null && file_exists($root . $p)) {
|
||||
ftpSend($ctrl, '213 ' . filesize($root . $p));
|
||||
} else {
|
||||
ftpSend($ctrl, '550 File not found');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NOOP':
|
||||
ftpSend($ctrl, '200 OK');
|
||||
break;
|
||||
|
||||
case 'QUIT':
|
||||
ftpSend($ctrl, '221 Goodbye');
|
||||
return;
|
||||
|
||||
default:
|
||||
ftpSend($ctrl, '502 Not implemented: ' . $cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
@echo off
|
||||
setlocal
|
||||
set "SCRIPTS_DIR=%~dp0"
|
||||
set "SCRIPTS_DIR=%SCRIPTS_DIR:~0,-1%"
|
||||
for %%F in ("%SCRIPTS_DIR%\..") do set "PROJECT_DIR=%%~fF"
|
||||
|
||||
echo =============================================
|
||||
echo MatabPanel - First Time Install
|
||||
echo =============================================
|
||||
echo.
|
||||
echo Project folder: %PROJECT_DIR%
|
||||
echo.
|
||||
|
||||
REM --- Find PHP (bundled first, then system fallbacks) ---
|
||||
set "PHP_EXE="
|
||||
|
||||
if exist "%SCRIPTS_DIR%\php\php.exe" (
|
||||
set "PHP_EXE=%SCRIPTS_DIR%\php\php.exe"
|
||||
)
|
||||
|
||||
if not defined PHP_EXE (
|
||||
for %%P in (
|
||||
"C:\xampp\php\php.exe"
|
||||
"C:\php\php.exe"
|
||||
) do (
|
||||
if exist %%P set "PHP_EXE=%%~P"
|
||||
)
|
||||
)
|
||||
|
||||
if not defined PHP_EXE (
|
||||
powershell -NoProfile -Command ^
|
||||
"if(Test-Path 'C:\wamp64\bin\php'){$v=Get-ChildItem 'C:\wamp64\bin\php' -Directory | Sort-Object Name | Select-Object -Last 1; if($v){Write-Host ($v.FullName+'\php.exe')}}" > "%TEMP%\phppath.txt" 2>nul
|
||||
set /p PHP_EXE=<"%TEMP%\phppath.txt"
|
||||
del "%TEMP%\phppath.txt" >nul 2>&1
|
||||
)
|
||||
|
||||
if not exist "%PHP_EXE%" (
|
||||
echo [ERROR] PHP not found!
|
||||
echo Bundled PHP not found in scripts\php\, and no system PHP detected.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [OK] PHP found: %PHP_EXE%
|
||||
echo.
|
||||
|
||||
REM --- [1/3] storage:link ---
|
||||
echo [1/3] Creating storage link...
|
||||
cd /d "%PROJECT_DIR%"
|
||||
"%PHP_EXE%" artisan storage:link >nul 2>&1
|
||||
if exist "%PROJECT_DIR%\public\storage" (
|
||||
echo [OK] Storage link ready.
|
||||
) else (
|
||||
echo [WARN] Storage link may need admin rights. Run as Administrator if images don't show.
|
||||
)
|
||||
echo.
|
||||
|
||||
REM --- [2/3] Optimize Laravel ---
|
||||
echo [2/3] Optimizing Laravel cache...
|
||||
"%PHP_EXE%" artisan optimize >nul 2>&1
|
||||
echo [OK] Done.
|
||||
echo.
|
||||
|
||||
REM --- [3/3] Firewall rules for FTP ---
|
||||
echo [3/3] Adding firewall rules for FTP...
|
||||
netsh advfirewall firewall delete rule name="MatabPanel FTP" >nul 2>&1
|
||||
netsh advfirewall firewall add rule name="MatabPanel FTP" protocol=TCP dir=in localport=2121 action=allow >nul 2>&1
|
||||
netsh advfirewall firewall delete rule name="MatabPanel FTP Data" >nul 2>&1
|
||||
netsh advfirewall firewall add rule name="MatabPanel FTP Data" protocol=TCP dir=in localport=49152-65534 action=allow >nul 2>&1
|
||||
echo [OK] Firewall rules added.
|
||||
echo.
|
||||
|
||||
REM --- [4/4] Autostart + Start server ---
|
||||
echo [4/4] Setting up autostart and starting server...
|
||||
call "%SCRIPTS_DIR%\setup-autostart.bat"
|
||||
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
class TrayApp : ApplicationContext
|
||||
{
|
||||
private NotifyIcon tray;
|
||||
private int port = 8000;
|
||||
private string phpExe = @"C:\wamp64\bin\php\php8.3.28\php.exe";
|
||||
private string projectDir;
|
||||
|
||||
public TrayApp(string dir)
|
||||
{
|
||||
projectDir = dir;
|
||||
StartServer();
|
||||
BuildTray();
|
||||
}
|
||||
|
||||
void StartServer()
|
||||
{
|
||||
bool inUse = false;
|
||||
try {
|
||||
TcpClient tcp = new TcpClient();
|
||||
tcp.Connect("127.0.0.1", port);
|
||||
tcp.Close();
|
||||
inUse = true;
|
||||
} catch {}
|
||||
|
||||
if (!inUse) {
|
||||
ProcessStartInfo psi = new ProcessStartInfo();
|
||||
psi.FileName = phpExe;
|
||||
psi.Arguments = "artisan serve --host=0.0.0.0 --port=" + port;
|
||||
psi.WorkingDirectory = projectDir;
|
||||
psi.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
psi.CreateNoWindow = true;
|
||||
psi.UseShellExecute = false;
|
||||
Process.Start(psi);
|
||||
}
|
||||
}
|
||||
|
||||
void BuildTray()
|
||||
{
|
||||
Icon icon = SystemIcons.Application;
|
||||
string ico = Path.Combine(projectDir, "public", "favicon.ico");
|
||||
if (File.Exists(ico)) { try { icon = new Icon(ico); } catch {} }
|
||||
|
||||
tray = new NotifyIcon();
|
||||
tray.Icon = icon;
|
||||
tray.Text = "Matab Panel";
|
||||
tray.Visible = true;
|
||||
|
||||
ContextMenuStrip menu = new ContextMenuStrip();
|
||||
|
||||
ToolStripMenuItem openItem = new ToolStripMenuItem("Open Matab Panel");
|
||||
openItem.Font = new Font(openItem.Font, FontStyle.Bold);
|
||||
openItem.Click += delegate { OpenBrowser(); };
|
||||
menu.Items.Add(openItem);
|
||||
|
||||
menu.Items.Add(new ToolStripSeparator());
|
||||
|
||||
ToolStripMenuItem stopItem = new ToolStripMenuItem("Stop Server");
|
||||
stopItem.Click += delegate {
|
||||
foreach (Process p in Process.GetProcessesByName("php"))
|
||||
try { p.Kill(); } catch {}
|
||||
tray.Visible = false;
|
||||
ExitThread();
|
||||
};
|
||||
menu.Items.Add(stopItem);
|
||||
|
||||
tray.ContextMenuStrip = menu;
|
||||
tray.DoubleClick += delegate { OpenBrowser(); };
|
||||
|
||||
tray.BalloonTipTitle = "Matab Panel";
|
||||
tray.BalloonTipText = "Server running - http://localhost:" + port;
|
||||
tray.BalloonTipIcon = ToolTipIcon.Info;
|
||||
tray.ShowBalloonTip(4000);
|
||||
}
|
||||
|
||||
void OpenBrowser()
|
||||
{
|
||||
ProcessStartInfo psi = new ProcessStartInfo("http://localhost:" + port);
|
||||
psi.UseShellExecute = true;
|
||||
Process.Start(psi);
|
||||
}
|
||||
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
string exeDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
string projectDir = Path.GetFullPath(Path.Combine(exeDir, ".."));
|
||||
Application.Run(new TrayApp(projectDir));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
@echo off
|
||||
setlocal
|
||||
set "SCRIPTS_DIR=%~dp0"
|
||||
set "SCRIPTS_DIR=%SCRIPTS_DIR:~0,-1%"
|
||||
for %%F in ("%SCRIPTS_DIR%\..") do set "PROJECT_DIR=%%~fF"
|
||||
|
||||
echo === MatabPanel Autostart Setup ===
|
||||
echo.
|
||||
|
||||
echo [1/3] Registering web server autostart...
|
||||
set "VBS_PATH=%SCRIPTS_DIR%\start-server.vbs"
|
||||
powershell -NoProfile -Command "$vbs='%VBS_PATH%'; $startup=[Environment]::GetFolderPath('Startup'); $s=(New-Object -COM WScript.Shell).CreateShortcut($startup+'\MatabPanel.lnk'); $s.TargetPath='wscript.exe'; $s.Arguments=[char]34+$vbs+[char]34; $s.WindowStyle=7; $s.Save(); Write-Host ('Registered: '+$startup+'\MatabPanel.lnk')"
|
||||
echo.
|
||||
|
||||
echo [2/3] Registering FTP server autostart...
|
||||
set "FTP_VBS=%SCRIPTS_DIR%\start-ftp-server.vbs"
|
||||
powershell -NoProfile -Command "$vbs='%FTP_VBS%'; $startup=[Environment]::GetFolderPath('Startup'); $s=(New-Object -COM WScript.Shell).CreateShortcut($startup+'\MatabPanelFTP.lnk'); $s.TargetPath='wscript.exe'; $s.Arguments=[char]34+$vbs+[char]34; $s.WindowStyle=7; $s.Save(); Write-Host ('Registered: '+$startup+'\MatabPanelFTP.lnk')"
|
||||
echo.
|
||||
|
||||
echo [3/3] Starting servers now...
|
||||
wscript.exe "%SCRIPTS_DIR%\start-ftp-server.vbs"
|
||||
wscript.exe "%SCRIPTS_DIR%\start-server.vbs"
|
||||
echo Waiting for server to be ready...
|
||||
powershell -NoProfile -Command "$max=30; $i=0; while($i -lt $max){ try{ $t=New-Object Net.Sockets.TcpClient; $t.Connect('127.0.0.1',8000); $t.Close(); Write-Host '[OK] Server is ready.'; $i=$max+1 }catch{ $i++; Start-Sleep -Milliseconds 500 } }; if($i -eq $max){ Write-Host '[WARN] Server did not respond in 15s. Check scripts\server.log' }"
|
||||
if not errorlevel 1 start "" "http://localhost:8000"
|
||||
echo.
|
||||
echo Done! Servers will auto-start on every login.
|
||||
echo Web : http://localhost:8000
|
||||
echo FTP : port 2121
|
||||
pause
|
||||
@@ -0,0 +1,65 @@
|
||||
Dim shell, fso, scriptsDir, phpExe, logFile
|
||||
Set shell = CreateObject("WScript.Shell")
|
||||
Set fso = CreateObject("Scripting.FileSystemObject")
|
||||
scriptsDir = fso.GetParentFolderName(WScript.ScriptFullName)
|
||||
logFile = scriptsDir & "\ftp-server.log"
|
||||
|
||||
' --- Find PHP ---
|
||||
phpExe = ""
|
||||
Dim candidates(4)
|
||||
candidates(0) = scriptsDir & "\php\php.exe"
|
||||
candidates(1) = "C:\xampp\php\php.exe"
|
||||
candidates(2) = "C:\php\php.exe"
|
||||
candidates(3) = "C:\wamp64\bin\php\php.exe"
|
||||
candidates(4) = "C:\wamp\bin\php\php.exe"
|
||||
|
||||
Dim i
|
||||
For i = 0 To 4
|
||||
If fso.FileExists(candidates(i)) Then
|
||||
phpExe = candidates(i)
|
||||
Exit For
|
||||
End If
|
||||
Next
|
||||
|
||||
' --- Try WAMP versioned folders ---
|
||||
If phpExe = "" Then
|
||||
Dim wampBase(1)
|
||||
wampBase(0) = "C:\wamp64\bin\php"
|
||||
wampBase(1) = "C:\wamp\bin\php"
|
||||
Dim w
|
||||
For w = 0 To 1
|
||||
If fso.FolderExists(wampBase(w)) Then
|
||||
Dim subF
|
||||
For Each subF In fso.GetFolder(wampBase(w)).SubFolders
|
||||
phpExe = subF.Path & "\php.exe"
|
||||
Next
|
||||
If fso.FileExists(phpExe) Then Exit For
|
||||
phpExe = ""
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
|
||||
If phpExe = "" Then
|
||||
On Error Resume Next
|
||||
Dim ts
|
||||
Set ts = fso.OpenTextFile(logFile, 8, True)
|
||||
ts.WriteLine Now & " - ERROR: php.exe not found in any known location"
|
||||
ts.Close
|
||||
WScript.Quit 1
|
||||
End If
|
||||
|
||||
' --- Skip if already running on port 2121 ---
|
||||
Dim portInUse
|
||||
portInUse = shell.Run("cmd /c netstat -ano | find "":2121 "" >nul 2>&1", 0, True)
|
||||
If portInUse = 0 Then WScript.Quit 0
|
||||
|
||||
' --- Log start ---
|
||||
On Error Resume Next
|
||||
Dim ts2
|
||||
Set ts2 = fso.OpenTextFile(logFile, 8, True)
|
||||
ts2.WriteLine Now & " - Starting FTP server with: " & phpExe
|
||||
ts2.Close
|
||||
On Error GoTo 0
|
||||
|
||||
' --- Start FTP server silently in background ---
|
||||
shell.Run "cmd /c """ & phpExe & """ -d display_errors=0 """ & scriptsDir & "\ftp-server.php"" >> """ & logFile & """ 2>&1", 0, False
|
||||
@@ -0,0 +1,33 @@
|
||||
@echo off
|
||||
setlocal
|
||||
set "SCRIPTS_DIR=%~dp0"
|
||||
set "SCRIPTS_DIR=%SCRIPTS_DIR:~0,-1%"
|
||||
|
||||
REM --- Find PHP ---
|
||||
set "PHP_EXE="
|
||||
if exist "%SCRIPTS_DIR%\php\php.exe" set "PHP_EXE=%SCRIPTS_DIR%\php\php.exe"
|
||||
|
||||
if not defined PHP_EXE (
|
||||
for %%P in ("C:\xampp\php\php.exe" "C:\php\php.exe") do (
|
||||
if exist %%P set "PHP_EXE=%%~P"
|
||||
)
|
||||
)
|
||||
|
||||
if not defined PHP_EXE (
|
||||
powershell -NoProfile -Command ^
|
||||
"if(Test-Path 'C:\wamp64\bin\php'){$v=Get-ChildItem 'C:\wamp64\bin\php' -Directory|Sort-Object Name|Select-Object -Last 1;if($v){Write-Host ($v.FullName+'\php.exe')}}" > "%TEMP%\phppath.txt" 2>nul
|
||||
set /p PHP_EXE=<"%TEMP%\phppath.txt"
|
||||
del "%TEMP%\phppath.txt" >nul 2>&1
|
||||
)
|
||||
|
||||
if not exist "%PHP_EXE%" (
|
||||
echo [ERROR] PHP not found!
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [FTP] Starting FTP server with: %PHP_EXE%
|
||||
echo [FTP] Port 21 - Run as Administrator if access denied
|
||||
echo.
|
||||
"%PHP_EXE%" -d display_errors=0 "%SCRIPTS_DIR%\ftp-server.php"
|
||||
pause
|
||||
@@ -0,0 +1,18 @@
|
||||
@echo off
|
||||
setlocal
|
||||
set "SCRIPTS_DIR=%~dp0"
|
||||
set "SCRIPTS_DIR=%SCRIPTS_DIR:~0,-1%"
|
||||
for %%F in ("%SCRIPTS_DIR%\..") do set "PROJECT_DIR=%%~fF"
|
||||
|
||||
echo Checking port 8000...
|
||||
powershell -NoProfile -Command ^
|
||||
"if((Test-NetConnection -ComputerName localhost -Port 8000 -WarningAction SilentlyContinue).TcpTestSucceeded){Write-Host 'Already running on http://localhost:8000';exit 0}else{Write-Host 'Not running. Starting...';exit 1}"
|
||||
if %errorLevel% equ 0 (
|
||||
start "" "http://localhost:8000"
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
wscript.exe "%SCRIPTS_DIR%\start-server.vbs"
|
||||
echo Waiting for server to be ready...
|
||||
powershell -NoProfile -Command "$max=30; $i=0; $ok=$false; while($i -lt $max){ try{ $t=New-Object Net.Sockets.TcpClient; $t.Connect('127.0.0.1',8000); $t.Close(); Write-Host '[OK] Server ready: http://localhost:8000'; Start-Process 'http://localhost:8000'; $ok=$true; break }catch{ $i++; Start-Sleep -Milliseconds 500 } }; if(-not $ok){ Write-Host '[FAIL] Server did not start. Check: %SCRIPTS_DIR%\server.log' }"
|
||||
pause
|
||||
@@ -0,0 +1,89 @@
|
||||
Dim shell, fso, scriptsDir, projectDir, phpExe, logFile
|
||||
Set shell = CreateObject("WScript.Shell")
|
||||
Set fso = CreateObject("Scripting.FileSystemObject")
|
||||
scriptsDir = fso.GetParentFolderName(WScript.ScriptFullName)
|
||||
projectDir = fso.GetParentFolderName(scriptsDir)
|
||||
logFile = scriptsDir & "\server.log"
|
||||
phpExe = ""
|
||||
|
||||
' --- Method 0: Bundled PHP inside scripts\php\ ---
|
||||
If fso.FileExists(scriptsDir & "\php\php.exe") Then
|
||||
phpExe = scriptsDir & "\php\php.exe"
|
||||
End If
|
||||
|
||||
' --- Method 1: Scan WAMP's php folder for any version ---
|
||||
If phpExe = "" Then
|
||||
On Error Resume Next
|
||||
If fso.FolderExists("C:\wamp64\bin\php") Then
|
||||
Dim phpFolder, subFolder, latestPhp
|
||||
latestPhp = ""
|
||||
Set phpFolder = fso.GetFolder("C:\wamp64\bin\php")
|
||||
For Each subFolder In phpFolder.SubFolders
|
||||
If fso.FileExists(subFolder.Path & "\php.exe") Then
|
||||
latestPhp = subFolder.Path & "\php.exe"
|
||||
End If
|
||||
Next
|
||||
If latestPhp <> "" Then phpExe = latestPhp
|
||||
End If
|
||||
On Error GoTo 0
|
||||
End If
|
||||
|
||||
' --- Method 2: where php (reads stdout directly, no temp file) ---
|
||||
If phpExe = "" Then
|
||||
On Error Resume Next
|
||||
Dim oExec, firstLine
|
||||
Set oExec = shell.Exec("cmd /c where php")
|
||||
If Err.Number = 0 Then
|
||||
Do While Not oExec.StdOut.AtEndOfStream
|
||||
firstLine = Trim(oExec.StdOut.ReadLine())
|
||||
If firstLine <> "" Then
|
||||
If fso.FileExists(firstLine) Then
|
||||
phpExe = firstLine
|
||||
Exit Do
|
||||
End If
|
||||
End If
|
||||
Loop
|
||||
End If
|
||||
On Error GoTo 0
|
||||
End If
|
||||
|
||||
' --- Method 3: known fixed paths ---
|
||||
If phpExe = "" Then
|
||||
Dim candidates(2)
|
||||
candidates(0) = "C:\xampp\php\php.exe"
|
||||
candidates(1) = "C:\php\php.exe"
|
||||
candidates(2) = shell.ExpandEnvironmentStrings("%PHPRC%\php.exe")
|
||||
Dim i
|
||||
For i = 0 To UBound(candidates)
|
||||
On Error Resume Next
|
||||
If fso.FileExists(candidates(i)) Then phpExe = candidates(i)
|
||||
On Error GoTo 0
|
||||
If phpExe <> "" Then Exit For
|
||||
Next
|
||||
End If
|
||||
|
||||
' --- PHP not found ---
|
||||
If phpExe = "" Then
|
||||
On Error Resume Next
|
||||
Dim tsErr
|
||||
Set tsErr = fso.OpenTextFile(logFile, 8, True)
|
||||
tsErr.WriteLine Now & " - ERROR: php.exe not found. Install WAMP or add PHP to PATH."
|
||||
tsErr.Close
|
||||
On Error GoTo 0
|
||||
WScript.Quit 1
|
||||
End If
|
||||
|
||||
' --- Port check: exit only if actively LISTENING on 8000 ---
|
||||
Dim portInUse
|
||||
portInUse = shell.Run("cmd /c netstat -ano | find ""0.0.0.0:8000"" >nul 2>&1", 0, True)
|
||||
If portInUse = 0 Then WScript.Quit 0
|
||||
|
||||
' --- Log and start server ---
|
||||
On Error Resume Next
|
||||
Dim ts
|
||||
Set ts = fso.OpenTextFile(logFile, 8, True)
|
||||
ts.WriteLine Now & " - Starting MatabPanel server with: " & phpExe
|
||||
ts.Close
|
||||
On Error GoTo 0
|
||||
|
||||
shell.Run "cmd /c cd /d """ & projectDir & """ && """ & phpExe & """ artisan serve --host=0.0.0.0 --port=8000 >> """ & logFile & """ 2>&1", 0, False
|
||||
@@ -0,0 +1,5 @@
|
||||
@echo off
|
||||
echo Stopping Matab Panel server...
|
||||
taskkill /f /im php.exe >nul 2>&1
|
||||
echo Done.
|
||||
pause
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
$ip = $argv[1] ?? null;
|
||||
$port = (int)($argv[2] ?? 2121);
|
||||
$user = $argv[3] ?? 'root';
|
||||
$pass = $argv[4] ?? 'Mjoshanitcm7717';
|
||||
|
||||
if (!$ip) {
|
||||
$envFile = __DIR__ . '/../.env';
|
||||
if (file_exists($envFile)) {
|
||||
foreach (file($envFile) as $line) {
|
||||
$line = trim($line);
|
||||
if (strpos($line, 'SYNC_PEER_IP=') === 0) {
|
||||
$ip = trim(substr($line, 13), '"\'');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$ip) {
|
||||
$pdo = null;
|
||||
$dbEnv = [];
|
||||
foreach (file(__DIR__ . '/../.env') as $line) {
|
||||
$line = trim($line);
|
||||
if (strpos($line, '=') === false || $line[0] === '#') continue;
|
||||
[$k, $v] = explode('=', $line, 2);
|
||||
$dbEnv[trim($k)] = trim($v, '"\'');
|
||||
}
|
||||
try {
|
||||
$dsn = "mysql:host=" . ($dbEnv['DB_HOST'] ?? '127.0.0.1')
|
||||
. ";port=" . ($dbEnv['DB_PORT'] ?? '3306')
|
||||
. ";dbname=" . ($dbEnv['DB_DATABASE'] ?? '');
|
||||
$pdo = new PDO($dsn, $dbEnv['DB_USERNAME'] ?? 'root', $dbEnv['DB_PASSWORD'] ?? '');
|
||||
$ip = $pdo->query("SELECT init_value FROM osurg_initials WHERE init_parameter='sync_peer_ip'")->fetchColumn() ?: $ip;
|
||||
$port = (int)($pdo->query("SELECT init_value FROM osurg_initials WHERE init_parameter='ftp_port'")->fetchColumn() ?: $port);
|
||||
$user = $pdo->query("SELECT init_value FROM osurg_initials WHERE init_parameter='ftp_user'")->fetchColumn() ?: $user;
|
||||
$pass = $pdo->query("SELECT init_value FROM osurg_initials WHERE init_parameter='ftp_pass'")->fetchColumn() ?: $pass;
|
||||
} catch (\Throwable $e) {}
|
||||
}
|
||||
|
||||
if (!$ip) {
|
||||
echo "ERROR: IP سیستم مطب مشخص نیست.\n";
|
||||
echo "Usage: php test-ftp.php 192.168.1.X\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
echo "==========================================\n";
|
||||
echo " تست FTP سیستم مطب\n";
|
||||
echo "==========================================\n";
|
||||
echo "IP : {$ip}\n";
|
||||
echo "Port : {$port}\n";
|
||||
echo "User : {$user}\n\n";
|
||||
|
||||
echo "[1] بررسی پورت {$port}... ";
|
||||
$sock = @fsockopen($ip, $port, $errno, $errstr, 5);
|
||||
if ($sock) {
|
||||
fclose($sock);
|
||||
echo "باز است ✓\n";
|
||||
} else {
|
||||
echo "بسته است ✗ ({$errstr})\n";
|
||||
echo "\n=> FTP server روی سیستم مطب اجرا نیست.\n";
|
||||
echo " scripts\\start-ftp-server.vbs یا install.bat را اجرا کن.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
echo "[2] اتصال FTP... ";
|
||||
$ftp = @ftp_connect($ip, $port, 10);
|
||||
if (!$ftp) {
|
||||
echo "ناموفق ✗\n";
|
||||
exit(1);
|
||||
}
|
||||
echo "موفق ✓\n";
|
||||
|
||||
// ---- تست 3: لاگین ----
|
||||
echo "[3] ورود با {$user}... ";
|
||||
if (!@ftp_login($ftp, $user, $pass)) {
|
||||
echo "ناموفق ✗ (کاربر یا رمز اشتباه)\n";
|
||||
ftp_close($ftp);
|
||||
exit(1);
|
||||
}
|
||||
echo "موفق ✓\n";
|
||||
|
||||
echo "[4] Passive mode... ";
|
||||
ftp_pasv($ftp, true);
|
||||
echo "OK ✓\n";
|
||||
|
||||
echo "[5] لیست پوشه اصلی... ";
|
||||
$list = @ftp_nlist($ftp, '/');
|
||||
if ($list !== false) {
|
||||
echo "موفق ✓ (" . count($list) . " آیتم)\n";
|
||||
} else {
|
||||
echo "خالی یا خطا\n";
|
||||
}
|
||||
|
||||
echo "[6] ارسال فایل تست... ";
|
||||
$tmpLocal = tempnam(sys_get_temp_dir(), 'ftp_test_');
|
||||
file_put_contents($tmpLocal, 'FTP test from ' . gethostname() . ' at ' . date('Y-m-d H:i:s'));
|
||||
if (@ftp_put($ftp, '/ftp_test.txt', $tmpLocal, FTP_BINARY)) {
|
||||
echo "موفق ✓\n";
|
||||
@ftp_delete($ftp, '/ftp_test.txt');
|
||||
echo "[6] پاکسازی فایل تست... OK ✓\n";
|
||||
} else {
|
||||
echo "ناموفق ✗ (مشکل دسترسی به پوشه)\n";
|
||||
}
|
||||
unlink($tmpLocal);
|
||||
|
||||
ftp_close($ftp);
|
||||
|
||||
echo "\n==========================================\n";
|
||||
echo " همه تستها موفق بودن! FTP آماده است.\n";
|
||||
echo "==========================================\n";
|
||||
Reference in New Issue
Block a user