403Webshell
Server IP : 202.61.199.114  /  Your IP : 216.73.217.139
Web Server : nginx/1.22.1
System : Linux de.arni-solutions.de 6.1.0-49-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.174-1 (2026-05-26) x86_64
User : web20 ( 1018)
PHP Version : 8.4.23
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /var/www/arni-solutions.de/web/terminal/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/arni-solutions.de/web/terminal/pinnwand-media.php
<?php
/**
 * Pinnwand – Medien-Auslieferung mit Terminal-Auth + HTTP-Range (Video-Streaming).
 *
 *   GET pinnwand-media.php?v=<view_token>&term=<hash>&f=<base>&s=t|m|o|p|v|l|a|h|s|ls
 *     s=t Thumbnail  s=m Feed-Größe  s=o Original(JPEG)  s=p Video-Poster
 *     s=v Videodatei (mp4/webm, mit Range)  s=l Link-Vorschaubild
 *     s=a Profilfoto (klein)  s=h Profil-Header
 *     s=s Mini (160px, Kachel-/Kommentar-Thumbs; Bild oder Video-Poster)
 *     s=ls Mini des Link-Vorschaubilds
 *     Mini-Größen werden für Bestandsdateien bei der ersten Anfrage
 *     aus _t/_p bzw. dem Link-Bild erzeugt und gecacht (Lazy-Konvertierung).
 *
 * Auth identisch zu view.php: gültiger Unlock-Cookie + Ansicht zugewiesen/global.
 * Dateien liegen unter data/pinnwand/<view_id>/ – Dateiname ist ein 32-Hex-Token,
 * es wird NIE ein Nutzer-Pfad verwendet (kein Traversal möglich).
 */
require __DIR__ . '/config.inc.php';

$viewToken = (string)($_GET['v'] ?? '');
$termHash  = (string)($_GET['term'] ?? '');
$base      = (string)($_GET['f'] ?? '');
$size      = (string)($_GET['s'] ?? 'm');

if (!preg_match('/^[a-f0-9]{32}$/', $base) || !in_array($size, ['t', 'm', 'o', 'p', 'v', 'l', 'a', 'h', 's', 'ls'], true)) {
    http_response_code(404); exit;
}

/** Mini-Variante (max. 160px) aus einer JPEG-/PNG-Quelle erzeugen (PNG behält den Alphakanal). */
function term_media_mini(string $src, string $dst, int $max = 160): bool
{
    if (!is_file($src) || !function_exists('imagecreatefromstring')) return false;
    $img = @imagecreatefromstring((string)@file_get_contents($src));
    if (!$img) return false;
    $iw = imagesx($img); $ih = imagesy($img);
    $sc = min(1, $max / max($iw, $ih));
    $nw = max(1, (int)round($iw * $sc)); $nh = max(1, (int)round($ih * $sc));
    $out = imagecreatetruecolor($nw, $nh);
    $png = substr($dst, -4) === '.png';
    if ($png) { imagealphablending($out, false); imagesavealpha($out, true); }
    imagecopyresampled($out, $img, 0, 0, 0, 0, $nw, $nh, $iw, $ih);
    $ok = $png ? @imagepng($out, $dst, 6) : @imagejpeg($out, $dst, 75);
    imagedestroy($out);
    imagedestroy($img);
    return (bool)$ok;
}

$db = term_db();
$terminal = term_terminal_grants_for($db, $viewToken, $termHash);
if (!$terminal) { http_response_code(403); exit; }

$st = $db->prepare('SELECT id FROM ' . term_tbl('views') . ' WHERE view_token = ? AND view_active = 1');
$st->execute([$viewToken]);
$wid = (int)$st->fetchColumn();
if (!$wid) { http_response_code(404); exit; }

$dir = dirname(__FILE__) . '/data/pinnwand/' . $wid;

if ($size === 'l') {
    // Link-Vorschaubild (Cache-Verzeichnis „links", Feed-Größe)
    $path = "$dir/links/{$base}_m.jpg";
    if (!is_file($path)) $path = "$dir/links/$base.jpg";
    $mime = 'image/jpeg';
} elseif ($size === 's' || $size === 'ls') {
    // Mini (160px): für Bestandsdateien bei der ersten Anfrage erzeugen.
    // Quelle: Bild-Thumbnail _t (JPEG oder PNG), sonst Video-Poster _p bzw. das Link-Bild.
    $path = $size === 'ls' ? "$dir/links/{$base}_s.jpg" : "$dir/{$base}_s.jpg";
    if (!is_file($path) && is_file(substr($path, 0, -4) . '.png')) $path = substr($path, 0, -4) . '.png';
    if (!is_file($path)) {
        if ($size === 'ls') {
            $srcPath = is_file("$dir/links/{$base}_m.jpg") ? "$dir/links/{$base}_m.jpg" : "$dir/links/$base.jpg";
        } else {
            $srcPath = is_file("$dir/{$base}_t.jpg") ? "$dir/{$base}_t.jpg"
                : (is_file("$dir/{$base}_t.png") ? "$dir/{$base}_t.png" : "$dir/{$base}_p.jpg");
        }
        // Ziel-Endung folgt der Quelle (PNG behält den Alphakanal, z. B. Sticker)
        $path = substr($path, 0, -4) . (substr($srcPath, -4) === '.png' ? '.png' : '.jpg');
        if (!term_media_mini($srcPath, $path)) $path = $srcPath; // Fallback: Quelle ausliefern
    }
    $mime = substr($path, -4) === '.png' ? 'image/png' : 'image/jpeg';
} elseif ($size === 'a' || $size === 'h') {
    // Profilfotos (Verzeichnis „profiles"): a = klein (Avatar), h = groß (Header)
    $path = "$dir/profiles/{$base}" . ($size === 'a' ? '_t' : '_m') . '.jpg';
    if (!is_file($path)) $path = "$dir/profiles/$base.jpg";
    $mime = 'image/jpeg';
} elseif ($size === 'v') {
    // Video: Medienzeile liefert die Endung (mp4/webm)
    $st = $db->prepare('SELECT ext, mime FROM ' . term_tbl('post_media') . " WHERE file_base = ? AND view_id = ? AND media_type = 'video'");
    $st->execute([$base, $wid]);
    $m = $st->fetch();
    if (!$m || !preg_match('/^(mp4|webm)$/', (string)$m['ext'])) { http_response_code(404); exit; }
    $path = "$dir/$base.{$m['ext']}";
    $mime = (string)$m['mime'];
} else {
    $suffix = ['t' => '_t', 'm' => '_m', 'o' => '', 'p' => '_p'][$size];
    $path = "$dir/$base$suffix.jpg";
    $mime = 'image/jpeg';
    // Transparente Bilder (Handy-Sticker) liegen als PNG mit Alphakanal vor
    if (!is_file($path) && is_file("$dir/$base$suffix.png")) {
        $path = "$dir/$base$suffix.png";
        $mime = 'image/png';
    }
}

if (!is_file($path)) { http_response_code(404); exit; }

$fsize = filesize($path);
header('Content-Type: ' . $mime);
header('X-Content-Type-Options: nosniff');
header('Content-Security-Policy: default-src \'none\'');
header('Cache-Control: private, max-age=31536000, immutable'); // Token-Dateinamen sind unveränderlich
header('Accept-Ranges: bytes');

// HTTP-Range (nur ein Bereich; für Video-Scrubbing auf iOS zwingend)
$start = 0; $end = $fsize - 1;
if (isset($_SERVER['HTTP_RANGE']) && preg_match('/bytes=(\d*)-(\d*)/', (string)$_SERVER['HTTP_RANGE'], $m)) {
    if ($m[1] !== '') $start = (int)$m[1];
    if ($m[2] !== '') $end = min((int)$m[2], $fsize - 1);
    if ($m[1] === '' && $m[2] !== '') { $start = max(0, $fsize - (int)$m[2]); $end = $fsize - 1; }
    if ($start > $end || $start >= $fsize) {
        http_response_code(416);
        header("Content-Range: bytes */$fsize");
        exit;
    }
    http_response_code(206);
    header("Content-Range: bytes $start-$end/$fsize");
}
header('Content-Length: ' . ($end - $start + 1));

if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'HEAD') exit;

$fh = fopen($path, 'rb');
if (!$fh) { http_response_code(500); exit; }
fseek($fh, $start);
$left = $end - $start + 1;
while ($left > 0 && !feof($fh)) {
    $chunk = fread($fh, min(262144, $left));
    if ($chunk === false) break;
    echo $chunk;
    $left -= strlen($chunk);
    flush();
}
fclose($fh);

Youez - 2016 - github.com/yon3zu
LinuXploit