Files
http2pic/web/index.php
Chris 7360d0b08a
All checks were successful
Build Container / docker (push) Successful in 4m13s
feat: add fullpage and maxheight parameters for enhanced screenshot options
2026-04-24 15:43:08 +02:00

149 lines
5.7 KiB
PHP
Executable File

<?php
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
define('DS', DIRECTORY_SEPARATOR);
define('ROOT', dirname(__FILE__) . DS . '..');
// increase PHP timeout - rendering can take 60s+
set_time_limit(120);
ignore_user_abort(true);
require_once(ROOT . DS . 'src' . DS . 'config.inc.php');
require_once(ROOT . DS . 'src' . DS . 'helpers.php');
require_once(ROOT . DS . 'src' . DS . 'http2pic.class.php');
require_once(ROOT . DS . 'src' . DS . 'vendor' . DS . 'autoload.php');
$url = array_filter(explode('/', ltrim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/')));
//check for integrated server
if (php_sapi_name() == 'cli-server' && file_exists(ROOT . DS . 'web' . DS . implode('/', $url)) && !is_dir(ROOT . DS . 'web' . DS . implode('/', $url)))
return false;
switch ($url[0]) {
case 'api':
if (defined('API_KEY') && API_KEY !== '') {
$provided = $_SERVER['HTTP_X_API_KEY'] ?? $_REQUEST['key'] ?? '';
if (!hash_equals(API_KEY, $provided)) {
header('HTTP/1.0 401 Unauthorized');
echo 'Invalid or missing API key';
exit;
}
}
$target = substr($_SERVER['REQUEST_URI'], 5);
if (!$target || !filter_var($target, FILTER_VALIDATE_URL))
$target = $_REQUEST['url'];
if (!filter_var($target, FILTER_VALIDATE_URL)) {
header('HTTP/1.0 400 Bad Request');
echo 'Invalid URL';
exit;
}
$scheme = strtolower(parse_url($target, PHP_URL_SCHEME) ?? '');
if (!in_array($scheme, ['http', 'https'], true)) {
header('HTTP/1.0 400 Bad Request');
echo 'Invalid URL';
exit;
}
$ip = getUserIP();
$viewport = $_REQUEST['viewport'] ?: '1024x768';
if (!preg_match('/^\d+x\d+$/', $viewport)) {
header('HTTP/1.0 400 Bad Request');
echo 'Invalid viewport format. Use WIDTHxHEIGHT (e.g., 1024x768)';
exit;
}
$vpParts = array_map('intval', explode('x', $viewport));
if ($vpParts[0] < 1 || $vpParts[1] < 1 || $vpParts[0] > 3840 || $vpParts[1] > 2160) {
header('HTTP/1.0 400 Bad Request');
echo 'Viewport dimensions must be between 1x1 and 3840x2160';
exit;
}
$js = $_REQUEST['js'] == 'false' ? false : true;
$fullpage = isset($_REQUEST['fullpage']) && $_REQUEST['fullpage'] === 'true';
$maxheight = 15000;
if (isset($_REQUEST['maxheight'])) {
$mh = intval($_REQUEST['maxheight']);
if ($mh < 1 || $mh > 30000) {
header('HTTP/1.0 400 Bad Request');
echo 'maxheight must be between 1 and 30000';
exit;
}
$maxheight = $mh;
}
if (defined('BLOCK_PRIVATE_IPS') && BLOCK_PRIVATE_IPS) {
$host = parse_url($target, PHP_URL_HOST);
if (filter_var($host, FILTER_VALIDATE_IP)) {
$resolvedIp = $host;
} else {
$resolvedIp = gethostbyname($host);
if ($resolvedIp === $host) {
header('HTTP/1.0 403 Forbidden');
echo 'URL not allowed';
exit;
}
}
if (isPrivateIP($resolvedIp)) {
header('HTTP/1.0 403 Forbidden');
echo 'URL not allowed';
exit;
}
}
$serverUrl = 'http://localhost:4444';
$options = new \Facebook\WebDriver\Chrome\ChromeOptions();
$options->addArguments(['--headless', '--disable-gpu', '--no-sandbox', '--disable-dev-shm-usage']);
$capabilities = DesiredCapabilities::chrome();
$capabilities->setCapability(\Facebook\WebDriver\Chrome\ChromeOptions::CAPABILITY, $options);
if (!$js)
$capabilities->setCapability('javascriptEnabled', false);
$driver = null;
$error = null;
try {
$driver = RemoteWebDriver::create($serverUrl, $capabilities, 30000, 60000);
$driver->manage()->window()->setSize(new \Facebook\WebDriver\WebDriverDimension($vpParts[0], $vpParts[1]));
$driver->get($target);
if ($fullpage) {
$fullH = (int)$driver->executeScript('return Math.max(document.body.scrollHeight, document.documentElement.scrollHeight)');
$cappedH = min($fullH, $maxheight);
if ($cappedH < $fullH) {
addToLog($ip . ' Full-page height capped at ' . $maxheight . 'px (actual: ' . $fullH . 'px) for ' . $target);
}
$driver->manage()->window()->setSize(new \Facebook\WebDriver\WebDriverDimension($vpParts[0], $cappedH));
} else {
$driver->executeScript('document.body.style.overflow = "hidden";');
}
addToLog($ip . ' Requested ' . $target . ' viewport=' . $viewport . ' js=' . ($js ? 'enabled' : 'disabled') . ($fullpage ? ' fullpage=true' : ''));
$screenshot = $driver->takeScreenshot();
header('Content-Type: image/png');
header('Content-Length: ' . strlen($screenshot));
echo $screenshot;
} catch (Exception $e) {
$error = $e->getMessage();
addToLog($ip . ' Error requesting ' . $target . ': ' . $error);
} finally {
if ($driver instanceof RemoteWebDriver) {
try { $driver->quit(); } catch (Exception $q) {}
}
}
if ($error !== null) {
header('HTTP/1.0 500 Internal Server Error');
echo 'Screenshot failed';
}
break;
default:
echo renderTemplate('index.html.php');
break;
}