| Server IP : 188.114.96.3 / Your IP : 216.73.216.143 Web Server : Apache System : Linux sv058.home.net.pl 6.8.2 husak_dirty_pages_fix #1 SMP PREEMPT_DYNAMIC Tue Apr 2 22:06:51 CEST 2024 x86_64 User : ( 3194769) PHP Version : 8.5.12 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /test2.famaresto/szukaj/ |
Upload File : |
<?php
header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store');
/** -------- UTF-8 hardening (żeby json_encode nie wywalał) -------- */
function _is_valid_utf8($s) {
return is_string($s) && preg_match('//u', $s);
}
function _fix_to_utf8($s) {
if (!is_string($s)) return $s;
if ($s === '') return $s;
// już OK
if (_is_valid_utf8($s)) return $s;
// spróbuj typowe PL kodowania nazw plików
if (function_exists('iconv')) {
foreach (['Windows-1250', 'CP1250', 'ISO-8859-2'] as $enc) {
$t = @iconv($enc, 'UTF-8//IGNORE', $s);
if (is_string($t) && $t !== '' && _is_valid_utf8($t)) return $t;
}
// ostatnia deska ratunku: wytnij bajty psujące UTF-8
$t = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
if (is_string($t) && $t !== '') return $t;
}
// hard fallback: tylko ASCII
return preg_replace('/[^\x20-\x7E]/', '', $s);
}
function _normalize_for_json($v) {
if (is_array($v)) {
$out = [];
foreach ($v as $k => $val) {
$nk = _fix_to_utf8((string)$k);
$out[$nk] = _normalize_for_json($val);
}
return $out;
}
if (is_string($v)) return _fix_to_utf8($v);
return $v;
}
function json_out($payload, $status = 200) {
http_response_code($status);
$payload = _normalize_for_json($payload);
$opts = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
if (defined('JSON_INVALID_UTF8_SUBSTITUTE')) $opts |= JSON_INVALID_UTF8_SUBSTITUTE;
$json = json_encode($payload, $opts);
if ($json === false) {
$msg = function_exists('json_last_error_msg') ? json_last_error_msg() : 'json_encode_failed';
echo '{"docs":[],"error":"json_encode_failed","msg":"' . addslashes($msg) . '"}';
exit;
}
echo $json;
exit;
}
/** -------- config + helpers -------- */
function load_config() {
$file = __DIR__ . '/config.php';
if (is_file($file)) {
$cfg = include $file;
if (is_array($cfg)) return $cfg;
}
return [];
}
function detect_base_url($configured) {
// pozwól jawnie ustawić '' (root)
if ($configured !== null) {
$configured = (string)$configured;
$b = '/' . trim($configured, '/');
return ($b === '/') ? '' : $b;
}
$scriptDir = str_replace('\\', '/', dirname(isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : '/szukaj/api.php'));
$base = preg_replace('~/szukaj$~', '', $scriptDir);
$base = rtrim((string)$base, '/');
if ($base === '/' || $base === '') return '';
return $base;
}
function url_path_from_rel($rel, $baseUrl) {
// UWAGA: rawurlencode działa na bajtach – to jest OK nawet gdy nazwy plików są "dziwne"
$parts = explode('/', $rel);
$enc = [];
foreach ($parts as $p) $enc[] = rawurlencode($p);
$path = '/' . implode('/', $enc);
return ($baseUrl === '') ? $path : ($baseUrl . $path);
}
function human_title_from_filename($filename) {
$filename = _fix_to_utf8($filename);
$base = preg_replace('/\.[^.]+$/', '', $filename);
$base = str_replace(['_','-','.'], ' ', $base);
$base = preg_replace('/\s+/', ' ', (string)$base);
$base = trim((string)$base);
if ($base === '') return $filename;
$first = strtoupper(substr($base, 0, 1));
return $first . substr($base, 1);
}
function scan_dir($dir, $root, $baseUrl, $allowedExt, $excludeDirs, $excludeFiles, $overrides, &$docs, &$errors, &$countFiles, $maxFiles) {
if ($countFiles >= $maxFiles) return;
$items = @scandir($dir);
if ($items === false) {
$errors[] = "Brak dostępu do katalogu: " . $dir;
return;
}
foreach ($items as $name) {
if ($name === '.' || $name === '..') continue;
$path = $dir . DIRECTORY_SEPARATOR . $name;
// omijaj symlinki (często pętle/permission)
if (@is_link($path)) continue;
if (@is_dir($path)) {
if (in_array($name, $excludeDirs, true)) continue;
if (strlen($name) > 0 && $name[0] === '.') continue; // ukryte
if (!@is_readable($path)) {
$errors[] = "Nieczytelny katalog: " . $path;
continue;
}
scan_dir($path, $root, $baseUrl, $allowedExt, $excludeDirs, $excludeFiles, $overrides, $docs, $errors, $countFiles, $maxFiles);
if ($countFiles >= $maxFiles) return;
continue;
}
if (!@is_file($path)) continue;
if (in_array($name, $excludeFiles, true)) continue;
$ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));
if (!in_array($ext, $allowedExt, true)) continue;
$countFiles++;
// rel path (bajty zostają, bo URL i tak percent-enc)
$rootNorm = rtrim(str_replace('\\','/',$root), '/') . '/';
$absNorm = str_replace('\\','/',$path);
$rel = (strpos($absNorm, $rootNorm) === 0) ? substr($absNorm, strlen($rootNorm)) : $absNorm;
$section = 'Główne';
$parts = explode('/', $rel);
if (count($parts) >= 2 && $parts[0] !== '') $section = _fix_to_utf8($parts[0]);
$title = (isset($overrides[$rel]) && is_string($overrides[$rel]) && $overrides[$rel] !== '')
? _fix_to_utf8($overrides[$rel])
: human_title_from_filename($name);
$docs[] = [
'title' => $title,
'rel' => _fix_to_utf8($rel),
'url' => url_path_from_rel($rel, $baseUrl),
'section' => $section,
'ext' => $ext,
];
if ($countFiles >= $maxFiles) return;
}
}
/** -------- main -------- */
$cfg = load_config();
$debug = isset($_GET['debug']) && $_GET['debug'] == '1';
// Domyślnie: katalog strony = parent katalogu "szukaj"
$ROOT = isset($cfg['scan_root']) ? $cfg['scan_root'] : dirname(__DIR__);
$ROOT_REAL = @realpath($ROOT);
if ($ROOT_REAL !== false) $ROOT = $ROOT_REAL;
if (!is_dir($ROOT)) {
json_out([
'docs' => [],
'error' => 'scan_root_not_found',
'debug' => [
'scan_root' => $ROOT,
'realpath' => $ROOT_REAL,
'open_basedir' => ini_get('open_basedir'),
],
], 200);
}
$BASE_URL = detect_base_url($cfg['base_url'] ?? null);
$allowedExt = (isset($cfg['allowed_ext']) && is_array($cfg['allowed_ext']))
? $cfg['allowed_ext']
: ['pdf','doc','docx','xls','xlsx','ppt','pptx','zip','rtf','txt'];
$allowedExt = array_values(array_unique(array_map(fn($e) => strtolower((string)$e), $allowedExt)));
$excludeDirs = (isset($cfg['exclude_dirs']) && is_array($cfg['exclude_dirs']))
? $cfg['exclude_dirs']
: ['_bak','default_files','szukaj','images','media'];
$excludeDirs = array_values(array_unique($excludeDirs));
$excludeFiles = ['.htaccess','.htpasswd','.htpasswd.bak','.htpasswd_bak'];
$maxFiles = isset($cfg['max_files']) ? (int)$cfg['max_files'] : 20000;
if ($maxFiles <= 0) $maxFiles = 20000;
// overrides
$overrides = [];
$overridesFile = __DIR__ . '/data/overrides.json';
if (is_file($overridesFile)) {
$raw = @file_get_contents($overridesFile);
if ($raw !== false && $raw !== '') {
$j = json_decode($raw, true);
if (is_array($j)) $overrides = $j;
}
}
// cache
$cacheTtl = isset($cfg['cache_ttl']) ? (int)$cfg['cache_ttl'] : 0;
$cacheFile = __DIR__ . '/cache/docs.json';
if ($cacheTtl > 0 && is_file($cacheFile)) {
$age = time() - (int)@filemtime($cacheFile);
if ($age >= 0 && $age <= $cacheTtl) {
$raw = @file_get_contents($cacheFile);
if ($raw !== false && $raw !== '') {
// cache powinien być już UTF-8; jakby coś, poleci przez normalny output
echo $raw;
exit;
}
}
}
// buduj indeks
$docs = [];
$errors = [];
$countFiles = 0;
scan_dir($ROOT, $ROOT, $BASE_URL, $allowedExt, $excludeDirs, $excludeFiles, $overrides, $docs, $errors, $countFiles, $maxFiles);
// sort
usort($docs, function($a, $b) {
$sa = $a['section'] ?? '';
$sb = $b['section'] ?? '';
if ($sa === $sb) {
return strcasecmp($a['title'] ?? '', $b['title'] ?? '');
}
return strcasecmp($sa, $sb);
});
$out = [
'docs' => $docs,
'meta' => [
'count' => count($docs),
'scan_root' => _fix_to_utf8($ROOT),
'base_url' => _fix_to_utf8($BASE_URL),
],
];
if ($debug) {
$out['debug'] = [
'php' => PHP_VERSION,
'open_basedir' => ini_get('open_basedir'),
'errors' => array_slice(array_map('_fix_to_utf8', $errors), 0, 50),
'scanned_files' => $countFiles,
'max_files' => $maxFiles,
];
}
// zapisz cache jeśli się da
if ($cacheTtl > 0) {
$payload = _normalize_for_json($out);
$opts = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
if (defined('JSON_INVALID_UTF8_SUBSTITUTE')) $opts |= JSON_INVALID_UTF8_SUBSTITUTE;
$json = json_encode($payload, $opts);
if ($json !== false) {
@file_put_contents($cacheFile, $json);
}
}
json_out($out, 200);