<details><summary>Connections</summary><a target="_blank" href="http://127.0.0.1:8080/2025-06-28-FileServerUpload/2025-06-28-MultiUpload(SFTP-FTP)/upload.php?server=192.168.0.1&protocol=ftp&path=%2F&upload_type=url&anonymous=yes&file" style=color:blue>TPLink</a></details>
<?php
// URL reachability check function
function checkUrlReachability($url) {
    if (empty($url)) {
        return ['reachable' => false, 'status' => 'No URL provided'];
    }
    if (!filter_var($url, FILTER_VALIDATE_URL)) {
        return ['reachable' => false, 'status' => 'Invalid URL format'];
    }
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_NOBODY, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    if ($httpCode >= 200 && $httpCode < 400) {
        return ['reachable' => true, 'status' => "URL is accessible (HTTP $httpCode)"];
    } else {
        return ['reachable' => false, 'status' => "URL is not accessible: " . ($error ? $error : "HTTP $httpCode")];
    }
}
$urlReachability = [];
if (!empty($_GET['url'])) {
    $urlReachability = checkUrlReachability($_GET['url']);
}
?>
<?php
if (!empty($urlReachability)) {
    $statusClass = $urlReachability['reachable'] ? 'url-accessible' : 'url-inaccessible';
    echo "<div class='url-status $statusClass'>" . htmlspecialchars($urlReachability['status']) . "</div>";
}
?>
<script>
// URL reachability check functionality
function checkUrlReachability(url) {
    if (!url) {
        return Promise.resolve({ reachable: false, status: 'No URL provided' });
    }
    try {
        new URL(url);
    } catch (e) {
        return Promise.resolve({ reachable: false, status: 'Invalid URL format' });
    }
    return fetch(url, { 
        method: 'HEAD',
        mode: 'no-cors',
        cache: 'no-cache'
    })
    .then(response => {
        return { reachable: true, status: 'URL is accessible' };
    })
    .catch(error => {
        return { reachable: false, status: 'URL is not accessible: ' + error.message };
    });
}
function updateUrlStatusIndicator(statusElement, result) {
    statusElement.textContent = result.status;
    statusElement.className = result.reachable ? 'url-status url-accessible' : 'url-status url-inaccessible';
}
document.addEventListener('DOMContentLoaded', function() {
    const urlInput = document.querySelector('input[name="upload_url"]');
    const urlUploadDiv = document.getElementById('urlUploadDiv');
    if (!urlInput || !urlUploadDiv) return;
    const statusElement = document.createElement('div');
    statusElement.className = 'url-status';
    urlUploadDiv.appendChild(statusElement);
    if (urlInput.value) {
        statusElement.textContent = 'Checking URL...';
        checkUrlReachability(urlInput.value)
            .then(result => updateUrlStatusIndicator(statusElement, result));
    }
    let timeoutId;
    urlInput.addEventListener('input', function() {
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => {
            if (urlInput.value) {
                statusElement.textContent = 'Checking URL...';
                checkUrlReachability(urlInput.value)
                    .then(result => updateUrlStatusIndicator(statusElement, result));
            } else {
                statusElement.textContent = '';
                statusElement.className = 'url-status';
            }
        }, 800);
    });
});
</script>
<style>
.url-status {
    margin-top: 5px;
    padding: 5px;
    border-radius: 3px;
    font-size: 12px;
}
.url-accessible {
    background-color: #d4edda;
    color: #155724;
    border: 1px solid #c3e6cb;
}
.url-inaccessible {
    background-color: #f8d7da;
    color: #721c24;
    border: 1px solid #f5c6cb;
}
</style>


<script>
function getQueryParam(name) {
    const params = new URLSearchParams(window.location.search);
    return params.get(name) || '';
}

window.addEventListener('DOMContentLoaded', () => {
    const uploadUrlInput = document.querySelector('input[name="upload_url"]');
    const urlParam = getQueryParam('url');
    if (uploadUrlInput && urlParam) {
        uploadUrlInput.value = urlParam;
    }
});
</script>

<script>
function getQueryParam(name) {
    const params = new URLSearchParams(window.location.search);
    return params.get(name) || '';
}

function saveCredentialsToLocalStorage(username, password) {
    if (username) localStorage.setItem('username', username);
    if (password) localStorage.setItem('password', password);
}

function loadCredentialsFromLocalStorage() {
    return {
        username: localStorage.getItem('username') || '',
        password: localStorage.getItem('password') || ''
    };
}

window.addEventListener('DOMContentLoaded', () => {
    const usernameInput = document.querySelector('input[name="username"]');
    const passwordInput = document.querySelector('input[name="password"]');

    let username = getQueryParam('username');
    let password = getQueryParam('password');

    if (!username || !password) {
        const stored = loadCredentialsFromLocalStorage();
        if (!username) username = stored.username;
        if (!password) password = stored.password;
    }

    if (usernameInput && username) usernameInput.value = username;
    if (passwordInput && password) passwordInput.value = password;

    const form = usernameInput.closest('form');
    if (form) {
        form.addEventListener('submit', () => {
            saveCredentialsToLocalStorage(usernameInput.value, passwordInput.value);
        });
    }
});
</script>

<?php
ini_set('memory_limit', '1024M');
set_time_limit(0);
set_error_handler(function($errno, $errstr, $errfile, $errline) { return true; });

function getQuery($key, $default = '') {
    return isset($_REQUEST[$key]) ? $_REQUEST[$key] : $default;
}

// ---------------- FTP/SFTP/WebDAV FUNCTIONS ----------------
function ftpUpload($server, $username, $password, $remoteDir, $localFile, $remoteFile, &$debug) {
    $conn = @ftp_connect($server);
    if (!$conn) { $debug[]="FTP connect failed."; return false; }

    if (!@ftp_login($conn, $username, $password)) { 
        $debug[]="FTP login failed. Check username/password."; 
        ftp_close($conn); return false; 
    }

    ftp_pasv($conn, true);

    if (!@ftp_chdir($conn, $remoteDir)) { 
        $debug[]="FTP cannot change to directory '$remoteDir'. Check path."; 
        ftp_close($conn); return false; 
    }

    $list = @ftp_nlist($conn, ".");
    if ($list !== false && in_array($remoteFile, $list)) { 
        $debug[]="FTP upload canceled: '$remoteFile' already exists."; 
        ftp_close($conn); return false; 
    }

    if (@ftp_put($conn, $remoteFile, $localFile, FTP_BINARY)) {
        $debug[]="FTP upload successful: $remoteFile";
        ftp_close($conn);
        return true;
    } else {
        $debug[]="FTP upload failed: Unknown error.";
        ftp_close($conn);
        return false;
    }
}

function sftpUpload($server, $username, $password, $remoteDir, $localFile, $remoteFile, &$debug) {
    $url = "sftp://$username:$password@$server/" . trim($remoteDir,'/') . '/' . $remoteFile;

    // Check if file exists
    $chCheck = curl_init();
    curl_setopt($chCheck, CURLOPT_URL, $url);
    curl_setopt($chCheck, CURLOPT_NOBODY, true);
    curl_setopt($chCheck, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($chCheck, CURLOPT_PROTOCOLS, CURLPROTO_SFTP);
    $resCheck = curl_exec($chCheck);
    $codeCheck = curl_getinfo($chCheck, CURLINFO_HTTP_CODE);
    curl_close($chCheck);
    if($resCheck !== false && $codeCheck === 0) {
        $debug[]="SFTP upload canceled: '$remoteFile' already exists.";
        return false;
    }

    $fp = fopen($localFile,'rb'); 
    if(!$fp){ $debug[]="Local file open failed."; return false; }

    $ch = curl_init();
    curl_setopt($ch,CURLOPT_URL,$url);
    curl_setopt($ch,CURLOPT_UPLOAD,true);
    curl_setopt($ch,CURLOPT_INFILE,$fp);
    curl_setopt($ch,CURLOPT_INFILESIZE,filesize($localFile));
    curl_setopt($ch,CURLOPT_PROTOCOLS,CURLPROTO_SFTP);
    curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
    $res = curl_exec($ch);
    if($res === false) {
        $debug[] = "SFTP upload failed: " . curl_error($ch);
        curl_close($ch);
        fclose($fp);
        return false;
    } else {
        $debug[] = "SFTP upload successful: $remoteFile";
        curl_close($ch);
        fclose($fp);
        return true;
    }
}

function webdavUpload($server, $username, $password, $remoteDir, $localFile, $remoteFile, &$debug) {
    $url = rtrim("https://$server/" . trim($remoteDir,'/'), '/') . '/' . $remoteFile;

    // 1. Check if file exists via HEAD
    $optsCheck = ["http"=>[
        "method"=>"HEAD",
        "header"=>"Authorization: Basic ".base64_encode("$username:$password"),
        "ignore_errors"=>true
    ]];
    $ctxCheck = stream_context_create($optsCheck);
    @file_get_contents($url,false,$ctxCheck);
    if (isset($http_response_header)) {
        foreach($http_response_header as $line){
            if (preg_match('#HTTP/\d+\.\d+\s+(\d+)#', $line, $m)){
                $code = intval($m[1]);
                if($code >= 200 && $code < 300){
                    $debug[] = "WebDAV upload canceled: '$remoteFile' already exists.";
                    return false;
                }
                break;
            }
        }
    }

    // 2. Upload
    $data = file_get_contents($localFile);
    $opts = ["http"=>[
        "method"=>"PUT",
        "header"=>"Authorization: Basic ".base64_encode("$username:$password")."\r\nContent-Length: ".strlen($data),
        "content"=>$data,
        "ignore_errors"=>true
    ]];
    $ctx = stream_context_create($opts);
    $res = @file_get_contents($url,false,$ctx);

    if ($res === false) {
        $debug[] = "WebDAV upload failed: Cannot reach server or unauthorized.";
        return false;
    }

    if (isset($http_response_header) && is_array($http_response_header)) {
        $statusLine = $http_response_header[0];
        preg_match('#HTTP/\d+\.\d+\s+(\d+)#', $statusLine, $matches);
        $code = isset($matches[1]) ? intval($matches[1]) : 0;
        if ($code >= 200 && $code < 300) {
            $debug[] = "WebDAV upload successful: $remoteFile (HTTP $code)";
            return true;
        } else {
            $debug[] = "WebDAV upload failed: HTTP $code - " . $statusLine;
            return false;
        }
    }

    $debug[] = "WebDAV upload unknown result.";
    return false;
}

function buildUrl($protocol,$server,$path) {
    $scheme=($protocol==='webdav')?'https':$protocol;
    return "$scheme://$server$path";
}

function listDirectory($protocol, $server, $username, $password, $path, &$debug) {
    $files=[];
    if ($protocol==='ftp') {
        $conn=@ftp_connect($server);
        if($conn&&@ftp_login($conn,$username,$password)){
            ftp_pasv($conn,true);
            if(@ftp_chdir($conn,$path)){
                $raw=ftp_rawlist($conn,".");
                foreach($raw as $line){
                    $parts=preg_split("/\s+/",$line,9);
                    if(count($parts)===9){
                        $files[]=['name'=>$parts[8],'type'=>$parts[0][0]==='d'?'dir':'file'];
                    }
                }
            }
            ftp_close($conn);
        }
    } elseif($protocol==='sftp') {
        $conn=@ssh2_connect($server);
        if($conn&&@ssh2_auth_password($conn,$username,$password)){
            $sftp=ssh2_sftp($conn);
            $dh=@opendir("ssh2.sftp://$sftp$path");
            if($dh){while(($f=readdir($dh))!==false){if($f==='.'||$f==='..')continue;$fp="ssh2.sftp://$sftp$path$f";$files[]=['name'=>$f,'type'=>is_dir($fp)?'dir':'file'];}closedir($dh);}
        }
    } elseif($protocol==='webdav') {
        $url=buildUrl($protocol,$server,$path);
        $opts=["http"=>["method"=>"PROPFIND","header"=>"Authorization: Basic ".base64_encode("$username:$password")."\r\nDepth: 1","content"=>""]];
        $ctx=stream_context_create($opts);
        $res=@file_get_contents($url,false,$ctx);
        if($res!==false){preg_match_all('/<d:href>(.*?)<\/d:href>/i',$res,$m);foreach($m[1] as $href){$nm=basename(parse_url($href,PHP_URL_PATH));if($nm&&$nm!==basename($path)){$files[]=['name'=>$nm,'type'=>(substr($href,-1)==='/')?'dir':'file'];}}}
    }
    return $files;
}

// ---------------- FORM VALUES -----------------
$username   = getQuery('username');
$password   = getQuery('password');
$server     = getQuery('server');
$path       = getQuery('path', '/');
$protocol   = getQuery('protocol', 'ftp');
$uploadType = getQuery('upload_type', 'url');
$anonymous  = getQuery('anonymous', '') ? true : false;

if ($anonymous) {
    $username = 'anonymous';
    $password = 'anonymous@domain.com';
}

$isDir = substr($path, -1) === '/';
$files = [];
$debug = [];

// ---------------- HANDLE UPLOAD -----------------
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if ($uploadType==='file' && !empty($_FILES['upload_file']['tmp_name'])) {
        $file = $_FILES['upload_file'];
        $remoteFile = basename($file['name']);
        $tmpFile = $file['tmp_name'];
        if($protocol==='ftp') ftpUpload($server,$username,$password,$path,$tmpFile,$remoteFile,$debug);
        elseif($protocol==='sftp') sftpUpload($server,$username,$password,$path,$tmpFile,$remoteFile,$debug);
        elseif($protocol==='webdav') webdavUpload($server,$username,$password,$path,$tmpFile,$remoteFile,$debug);
    } elseif($uploadType==='url' && !empty($_POST['upload_url'])) {
        $urlFile = $_POST['upload_url'];
        $remoteFile = basename(parse_url($urlFile, PHP_URL_PATH));
        $tmpFile = tempnam(sys_get_temp_dir(), 'up');
        if(file_put_contents($tmpFile, file_get_contents($urlFile))===false){
            $debug[] = "Download from URL failed: $urlFile";
        } else {
            if($protocol==='ftp') ftpUpload($server,$username,$password,$path,$tmpFile,$remoteFile,$debug);
            elseif($protocol==='sftp') sftpUpload($server,$username,$password,$path,$tmpFile,$remoteFile,$debug);
            elseif($protocol==='webdav') webdavUpload($server,$username,$password,$path,$tmpFile,$remoteFile,$debug);
        }
        unlink($tmpFile);
    }

    if(!empty($debug)){
        echo "<div style='border:1px solid #888;padding:10px;margin:10px 0;background:#f0f0f0;'>";
        foreach($debug as $d) echo htmlspecialchars($d) . "<br>";
        echo "</div>";
    }
}

// ----------------- HTML FORM ------------------
echo '<form method="post" enctype="multipart/form-data" style="margin-bottom:20px;">
    Upload type:<br>
    <label><input type="radio" name="upload_type" value="file" '.($uploadType==='file'?'checked':'').' onclick="toggleUploadType()"> File</label><br>
    <label><input type="radio" name="upload_type" value="url" '.($uploadType==='url'?'checked':'').' onclick="toggleUploadType()"> URL</label><br><br>
    
    <label><input type="checkbox" name="anonymous" value="1" '.($anonymous?'checked':'').' onclick="toggleAnonymous()"> Anonymous Login</label><br><br>

    Username: <input type="text" name="username" value="'.htmlspecialchars($username).'"><br>
    Password: <input type="password" name="password" value="'.htmlspecialchars($password).'"><br>
    Server: <input type="text" name="server" value="'.htmlspecialchars($server).'"><br>
    Path: <input type="text" name="path" value="'.htmlspecialchars($path).'"><br>
    
    Protocol:<br>
    <label><input type="radio" name="protocol" value="ftp" '.($protocol=='ftp'?'checked':'').'> FTP</label>
    <label><input type="radio" name="protocol" value="sftp" '.($protocol=='sftp'?'checked':'').'> SFTP</label>
    <label><input type="radio" name="protocol" value="webdav" '.($protocol=='webdav'?'checked':'').'> WebDAV</label>
    <br><br>
    
    <div id="fileUploadDiv" style="display: '.($uploadType==='file'?'block':'none').';">
        Select file to upload:<br>
        <input type="file" name="upload_file"><br>
    </div>
    
    <div id="urlUploadDiv" style="display: '.($uploadType==='url'?'block':'none').';">
        Enter URL to upload:<br>
        <input type="url" name="upload_url" style="width:300px;" value="'.htmlspecialchars(getQuery('upload_url')).'"><br>
    </div>
    
    <input type="submit" value="Connect / Upload">
</form>

<script>
function toggleUploadType() {
    const fileDiv = document.getElementById("fileUploadDiv");
    const urlDiv = document.getElementById("urlUploadDiv");
    const fileRadio = document.querySelector(\'input[name="upload_type"][value="file"]\');
    if(fileRadio.checked){fileDiv.style.display="block";urlDiv.style.display="none";}else{fileDiv.style.display="none";urlDiv.style.display="block";}
}
</script>
<script>
function toggleAnonymous() {
    const anon = document.querySelector(\'input[name="anonymous"]\');
    const userField = document.querySelector(\'input[name="username"]\');
    const passField = document.querySelector(\'input[name="password"]\');
    if(anon.checked){userField.disabled=true;passField.disabled=true;}else{userField.disabled=false;passField.disabled=false;}
}
</script>
';

// ---------------- Directory listing -------------------
if ($server && $isDir) {
    $files = listDirectory($protocol, $server, $username, $password, $path, $debug);

    if ($path !== '/') {
        $parent = rtrim($path, '/');
        $parent = substr($parent, 0, strrpos($parent, '/') + 1);
        echo '<a href="?username='.urlencode($username).'&password='.urlencode($password).'&server='.urlencode($server).'&protocol='.urlencode($protocol).'&path='.urlencode($parent).'&upload_type='.htmlspecialchars($uploadType).'&anonymous='.($anonymous?1:0).'">.. (Parent directory)</a><br>';
    }

    echo "<ul>";
    foreach ($files as $file) {
        $name = $file['name'];
        $type = $file['type'];
        $urlPath = $path . $name . ($type === 'dir' ? '/' : '');

        echo '<li>';
        if ($type === 'dir') {
            echo "📁 <a href='?username=".urlencode($username)."&password=".urlencode($password)."&server=".urlencode($server)."&protocol=".urlencode($protocol)."&path=".urlencode($urlPath)."&upload_type=".htmlspecialchars($uploadType)."&anonymous=".($anonymous?1:0)."'>" . htmlspecialchars($name) . "</a>";
        } else {
            $downloadUrl = "download.php?protocol=" . urlencode($protocol) .
                           "&server=" . urlencode($server) .
                           "&path=" . urlencode($urlPath) .
                           "&username=" . urlencode($username) .
                           "&password=" . urlencode($password) .
                           "&anonymous=" . ($anonymous?1:0);

            $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));
            if (in_array($ext, ['mp3','mp4','png','jpg','jpeg','gif'])) {
                echo "📄 <a href='" . htmlspecialchars($downloadUrl) . "' target='_blank'>" . htmlspecialchars($name) . "</a>";
            } else {
                echo "📄 <a href='" . htmlspecialchars($downloadUrl) . "' download>" . htmlspecialchars($name) . "</a>";
            }
        }
        echo "</li>";
    }
    echo "</ul>";
}
?>
