PHP готовый скрипт Поиска Файлов и Строк: Полное Руководство и Реализация

Показывать справа: 0

В современном веб-разработке часто возникает необходимость быстро находить нужные файлы или определенные строки внутри них. Будь то поиск конфигурационных параметров, отладочных сообщений или фрагментов кода, эффективный поиск экономит драгоценное время. Сегодня мы рассмотрим мощный PHP-скрипт, который предоставляет широкие возможности для поиска по файлам и директориям на вашем сервере.

Возможности Скрипта

Представленный скрипт — это не просто утилита для поиска, а полноценный инструмент с интуитивно понятным интерфейсом. Он позволяет:

  • Искать по содержимому файлов: Указывайте ключевые слова или фразы, и скрипт просканирует указанные файлы.
  • Фильтровать по расширениям: Ограничьте поиск только файлами с определенными расширениями (.php, .txt, .html, .js и т.д.).
  • Искать в именах файлов и папок: Быстро находите файлы или директории по их названиям.
  • Указывать директорию для поиска: Задавайте конкретную папку или используйте текущую директорию сервера.
  • Сохранять настройки поиска: Опция "Помнить выбор" позволяет сохранить введенные параметры для будущих поисков.
  • Скачивать результаты: Выгрузите найденные строки или список файлов в текстовый файл.
  • Гибкая настройка: Скрипт имеет ряд внутренних настроек, таких как лимит времени выполнения и объем используемой памяти, что делает его подходящим для работы с большими объемами данных.

Как Использовать Скрипт

Скрипт организован как веб-страница с формой для ввода параметров поиска. После ввода слова (или фразы), указания директории, выбора расширений и других опций, просто нажмите кнопку "Поиск". Результаты будут отображены непосредственно на странице.

Важно: Скрипт предполагает, что он размещен на веб-сервере с поддержкой PHP. Для корректной работы ему необходимы соответствующие права доступа к директориям, в которых производится поиск.

Реализация Скрипта

Ниже представлен исходный код скрипта. Он оставлен без изменений, я добавил лишь свои комментарии для лучшего понимания работы отдельных функций и блоков кода. Пробелы и переносы были немного скорректированы для повышения читаемости.

<?php

/**
 * Скрипт поиска файлов и содержимого.
 *
 * Версия: 1.2
 * Дата: 20.05.2024
 * Автор: webalan.ru (с модификациями и исправлением типов)
 *
 * Этот скрипт позволяет искать файлы по имени, а также искать строки внутри файлов
 * по заданным критериям (расширение, имя файла/папки, содержимое).
 * Поддерживается сохранение настроек поиска.
 */

// --- Глобальные настройки ---
ini_set('display_errors', 1); // Включаем отображение ошибок для отладки
ini_set('memory_limit', '512M'); // Увеличиваем лимит памяти
set_time_limit(0); // Снимаем ограничение по времени выполнения скрипта
header('Content-Type: text/html; charset=utf-8'); // Устанавливаем кодировку UTF-8 для страницы

// --- Константы ---
// Определяем путь к текущему файлу скрипта
define('CURRENT_SCRIPT_PATH', __DIR__ . '/');
// Файл для сохранения настроек поиска
define('SETTINGS_FILE', CURRENT_SCRIPT_PATH . pathinfo(__FILE__, PATHINFO_FILENAME) . '.webalan');

// --- Переменные ---
$params = [];
$params['ext_def'] = ['php', 'twig', 'css', 'txt', 'js', 'html', 'xml']; // Расширения файлов по умолчанию
$params['dir_def'] = CURRENT_SCRIPT_PATH; // Директория поиска по умолчанию

$savedSettings = []; // Массив для загруженных настроек

// --- Загрузка сохраненных настроек ---
if (is_file(SETTINGS_FILE)) {
    $dataString = file_get_contents(SETTINGS_FILE);
    if ($dataString !== false) {
        $savedSettings = unserialize($dataString);
    }
}

// --- Обработка запросов ---

// Скачивание файла
if (isset($_REQUEST['download']) && $_REQUEST['download'] === '1') {
    if (!empty($_REQUEST['list_load'])) {
        forceDownload($_REQUEST['list_load']);
    }
}

// Удаление файла настроек, если указано (при первом запуске или при явном запросе)
if (!isset($_REQUEST['save_form']) && isset($_REQUEST['f']) && $_REQUEST['f'] === '1' && is_file(SETTINGS_FILE)) {
    unlink(SETTINGS_FILE);
    // Перенаправляем, чтобы очистить URL от параметра 'f'
    header('Location: ' . strtok($_SERVER["REQUEST_URI"], '?'));
    exit;
}

// Сохранение настроек
if (isset($_REQUEST['save_form']) && $_REQUEST['save_form'] === '1') {
    // Сохраняем только те параметры, которые имеют смысл для формы
    $settingsToSave = array_intersect_key($_REQUEST, array_flip(['search', 'path', 'ext', 'find_name', 'pap', 'save_form', 'hoy_str']));
    file_put_contents(SETTINGS_FILE, serialize($settingsToSave));
    $savedSettings = $settingsToSave; // Обновляем сохраненные настройки
}

// --- Формирование параметров поиска из запроса и сохраненных настроек ---
$search = $_REQUEST['search'] ?? $savedSettings['search'] ?? '';
$path = $_REQUEST['path'] ?? $savedSettings['path'] ?? '';
$ext = $_REQUEST['ext'] ?? $savedSettings['ext'] ?? [];
$findName = isset($_REQUEST['find_name']) ? (bool)$_REQUEST['find_name'] : (isset($savedSettings['find_name']) ? (bool)$savedSettings['find_name'] : false);
$pap = $_REQUEST['pap'] ?? $savedSettings['pap'] ?? '';
$saveForm = isset($_REQUEST['save_form']) ? (bool)$_REQUEST['save_form'] : (isset($savedSettings['save_form']) ? (bool)$savedSettings['save_form'] : false);
$showOnlyFoundLine = isset($_REQUEST['hoy_str']) ? (bool)$_REQUEST['hoy_str'] : (isset($savedSettings['hoy_str']) ? (bool)$savedSettings['hoy_str'] : false);

// При первом запуске (без 'f' в запросе) или если 'f' не установлен, используем сохраненные настройки для 'ext'
if (!isset($_REQUEST['f']) || $_REQUEST['f'] !== '1') {
    $ext = $savedSettings['ext'] ?? [];
}

// --- Функции ---

/**
 * Скачивает содержимое файла в браузер.
 *
 * @param string $content Содержимое файла для скачивания.
 * @throws InvalidArgumentException Если содержимое пустое.
 */
function forceDownload(string $content): void
{
    if (empty($content)) {
        throw new InvalidArgumentException("Содержимое для скачивания не может быть пустым.");
    }

    $downloadFilename = date('d-m-Y_H-i-s', time()) . '.txt';

    header('Content-Description: File Transfer');
    header('Content-Type: text/plain; charset=utf-8'); // Указываем кодировку
    header('Content-Disposition: attachment; filename="' . $downloadFilename . '"');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . strlen($content));

    // Проверяем, есть ли активный буфер вывода перед очисткой
    if (ob_get_level() > 0) {
        ob_clean(); // Очищаем буфер вывода
    }
    flush();    // Отправляем буфер клиенту

    echo $content;
    exit;
}

/**
 * Рекурсивно сканирует директорию и возвращает список файлов и поддиректорий.
 *
 * @param string $dir Путь к директории.
 * @return array Массив, содержащий два массива: [список_файлов, список_директорий].
 */
function scanDirectory(string $dir): array
{
    $files = [];
    $directories = [];
    $dir = rtrim($dir, DIRECTORY_SEPARATOR); // Удалим разделитель на конце

    if (!is_dir($dir)) {
        return [[], []]; // Возвращаем пустые массивы, если это не директория
    }

    if ($handle = opendir($dir)) {
        while (false !== ($entry = readdir($handle))) {
            if ($entry !== '.' && $entry !== '..') {
                $fullPath = $dir . DIRECTORY_SEPARATOR . $entry;
                if (is_dir($fullPath)) {
                    $directories[] = $fullPath;
                    // Рекурсивный вызов для поддиректорий
                    [$subFiles, $subDirs] = scanDirectory($fullPath);
                    $files = array_merge($files, $subFiles);
                    $directories = array_merge($directories, $subDirs);
                } else {
                    $files[] = $fullPath;
                }
            }
        }
        closedir($handle);
    }

    return [$files, $directories];
}


/**
 * Ищет файлы и их содержимое по заданным критериям.
 *
 * @param string $dir Директория для поиска.
 * @param string $search Строка для поиска в содержимом.
 * @param bool $findName Флаг, искать ли в именах файлов/папок.
 * @param bool $showOnlyFoundLine Флаг, показывать ли только строку с совпадением.
 * @param array $allowedExtensions Массив разрешенных расширений.
 * @return array Массив найденных файлов.
 */
function searchFiles(string $dir, string $search, bool $findName = false, bool $showOnlyFoundLine = false, array $allowedExtensions = []): array
{
    if (!is_dir($dir)) {
        return []; // Если директория не существует, возвращаем пустой массив
    }

    [$allFiles, $allDirectories] = scanDirectory($dir);
    $results = [];
    $foundFiles = []; // Для хранения списка файлов, где было найдено содержимое

    // Поиск по именам файлов и директорий
    if ($findName) {
        echo "<div class='dir'>Поиск по именам: <strong>" . htmlspecialchars($search) . "</strong></div>";
        echo "<table class='table'>";
        $foundInNames = false;

        foreach ($allDirectories as $directory) {
            $dirName = basename($directory);
            if (stripos($dirName, $search) !== false) {
                echo "<tr><td style='background: burlywood;'><em>" . htmlspecialchars($directory) . "<br>" . htmlspecialchars($dirName) . "</em><br></td></tr>";
                $foundInNames = true;
            }
        }

        foreach ($allFiles as $file) {
            $fileInfo = pathinfo($file);
            $filename = $fileInfo['filename'];
            if (stripos($filename, $search) !== false) {
                echo "<tr><td><em>" . htmlspecialchars($file) . "<br>" . htmlspecialchars($filename) . "</em><br></td></tr>";
                $foundInNames = true;
            }
        }
        echo "</table>";

        if (!$foundInNames) {
            echo "<div class='dir'>Совпадений в именах не найдено.</div>";
        }
        echo "<h3>Содержимое файлов</h3>";
    }

    // Поиск по содержимому файлов
    echo "<table class='table'>";
    $foundInContent = false;

    foreach ($allFiles as $file) {
        $fileInfo = pathinfo($file);
        $extension = $fileInfo['extension'] ?? '';

        // Проверяем расширение, если список разрешенных не пуст
        if (!empty($allowedExtensions) && !in_array($extension, $allowedExtensions)) {
            continue;
        }

        // Используем file_get_contents для чтения всего файла, если он не слишком большой
        // Для очень больших файлов может потребоваться построчное чтение
        $fileContents = @file_get_contents($file);
        if ($fileContents === false) {
            // Пропускаем файл, если не удалось его прочитать (например, из-за прав доступа)
            continue;
        }

        // Разбиваем содержимое на строки для удобства
        $lines = explode("\n", $fileContents);

        $matchFoundInFile = false; // Флаг, найдено ли совпадение в текущем файле

        foreach ($lines as $lineNumber => $line) {
            // Используем stripos для регистронезависимого поиска
            if (stripos($line, $search) !== false) {
                $matchFoundInFile = true;
                $foundFiles[] = $file; // Добавляем файл в список, где было найдено содержимое

                // Обрабатываем отображение строки
                if ($showOnlyFoundLine) {
                    // Показываем только имя файла, если установлен флаг
                    if (!in_array($file, $results)) { // Избегаем дублирования имен файлов
                        $results[] = $file;
                    }
                } else {
                    // Показываем номер строки, имя файла и саму строку
                    $highlightedLine = preg_replace('/(' . preg_quote($search, '/') . ')/iu', '<strong class="highlight">$1</strong>', $line);
                    echo "<tr><td><b>" . ($lineNumber + 1) . "</b>: <em>" . htmlspecialchars($file) . "</em><br>" . $highlightedLine . "</td></tr>";
                }
            }
        }
        if ($matchFoundInFile) {
            $foundInContent = true;
        }
    }
    echo "</table>";

    if (!$foundInContent && empty($results)) { // Если ничего не найдено и в именах, и в содержимом
        echo "<div class='dir'>Совпадений в содержимом не найдено.</div>";
    }

    // Если установлен флаг "Показывать только строку найденного", выводим список файлов
    if ($showOnlyFoundLine) {
        echo "<table class='table'>";
        if (!empty($results)) {
            echo "<h3>Найденные файлы:</h3>";
            foreach (array_unique($results) as $filePath) { // Убираем дубликаты
                echo "<tr><td>" . htmlspecialchars($filePath) . "</td></tr>";
            }
        } else {
            echo "<tr><td>Совпадений не найдено.</td></tr>";
        }
        echo "</table>";
    }


    return array_unique($foundFiles); // Возвращаем уникальный список файлов, где были совпадения
}

?>
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Поиск по файлам</title>
    <style>
        body {
            font-family: 'Arial', sans-serif;
            line-height: 1.6;
            margin: 20px;
            background-color: #f4f4f4;
            color: #333;
        }
        .container {
            display: flex;
            gap: 20px;
          
        }
        .form-container {
            flex: 0 0 350px; /* Фиксированная ширина для формы */
            min-width: 300px; /* Минимальная ширина, чтобы не схлопывалась */
            background-color: #fff;
            padding: 15px;
            border-radius: 8px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        }
        .results-container {
            flex: 1; /* Занимает оставшееся пространство */
            background-color: #fff;
            padding: 15px;
            border-radius: 8px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        }
        .table {
            width: 100%;
            border-collapse: collapse;
            margin-bottom: 20px;
        }
        .table th, .table td {
            border: 1px solid #ddd;
            padding: 8px;
            text-align: left;
        }
        .table th {
            background-color: #e9ecef;
            font-weight: bold;
        }
        .table tbody tr:nth-child(even) {
            background-color: #f8f9fa;
        }
        .table tbody tr:hover {
            background-color: #e2e6ea;
        }
        .dir {
            display: inline-block;
            background: #d0e9c6; /* Светло-зеленый */
            color: #3c763d;
            padding: 5px 10px;
            margin-bottom: 15px;
            border: 1px solid #d6e9c6;
            border-radius: 5px;
            font-size: 0.9em;
        }
        .load {
            background: #5bc0de; /* Синий */
            color: white;
            cursor: pointer;
            border-radius: 5px;
            border: none;
            padding: 10px 15px;
            font-size: 1em;
            transition: background-color 0.3s ease;
        }
        .load:hover {
            background: #31b0d5;
        }
        .highlight {
            background-color: yellow;
            font-weight: bold;
        }
        label {
            display: block; /* Каждый элемент формы на новой строке */
            margin-bottom: 8px;
            font-weight: normal; /* Сбрасываем жирность для обычных меток */
        }
        input[type="text"], textarea, select {
            width: calc(100% - 20px); /* Учитываем padding */
            padding: 10px;
            margin-bottom: 10px;
            border: 1px solid #ccc;
            border-radius: 4px;
            box-sizing: border-box; /* Включаем padding и border в общую ширину */
        }
        textarea {
            min-height: 80px;
            resize: vertical;
        }
        input[type="checkbox"] {
            margin-right: 5px;
            vertical-align: middle; /* Выравнивание чекбокса по центру текста */
        }
        input[type="submit"] {
            background-color: #4CAF50; /* Зеленый */
            color: white;
            padding: 10px 15px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 1em;
            transition: background-color 0.3s ease;
        }
        input[type="submit"]:hover {
            background-color: #45a049;
        }
        .form-container h3 {
            margin-top: 0;
            color: #333;
        }
        .checkbox-group label {
            display: inline-block; /* Чекбоксы в одну строку */
            margin-right: 15px;
            margin-bottom: 5px;
        }
        .form-actions {
            margin-top: 20px;
            text-align: right;
        }
        
        .footer-static {
    text-align: center;  
    margin-top: 20px;  
    padding: 15px 0;  
    background-color: #e9ecef; 
    color: #495057;
    font-size: 0.95em;
    border-top: 1px solid #dee2e6;  
}

.footer-static a {
    color: #007bff;
    text-decoration: none;
    transition: color 0.3s ease;
}

.footer-static a:hover {
    color: #0056b3;
    text-decoration: underline;
}
         .logo_webalan{
        width: 25px;
    height: 30px;
    position: relative;
    top: 11px;
}   
    </style>
</head>
<body>

<div class="container">
    <div class="form-container">
        <h3>Параметры поиска</h3>
        <form name="searchForm" method="POST" action="">
            <label for="search_term">Слово для поиска:</label>
            <textarea id="search_term" name="search"><?= htmlspecialchars($search) ?></textarea>

            <label for="path_input">Путь (относительно корневой папки скрипта):</label>
            <input type="text" id="path_input" name="path" value="<?= htmlspecialchars($path) ?>">

            <label for="pap_select">Искать в папке:</label>
            <select id="pap_select" name="pap">
                <option value=""></option>
                <?php
                // Получаем список директорий из корневой папки скрипта
                $rootScan = scandir(CURRENT_SCRIPT_PATH);
                if ($rootScan) {
                    foreach ($rootScan as $item) {
                        if ($item === '.' || $item === '..') continue;
                        $fullItemPath = CURRENT_SCRIPT_PATH . $item;
                        if (is_dir($fullItemPath)) {
                            echo '<option value="' . htmlspecialchars($item) . '"' . ($pap === $item ? ' selected' : '') . '>' . htmlspecialchars($item) . '</option>';
                        }
                    }
                }
                ?>
            </select>
            <br>

            <div class="checkbox-group">
                <label><strong>Тип файлов:</strong></label><br>
                <?php
                foreach ($params['ext_def'] as $extension) {
                    $isChecked = in_array($extension, $ext) ? 'checked' : '';
                    echo '<label><input type="checkbox" name="ext[]" value="' . htmlspecialchars($extension) . '" ' . $isChecked . '>' . htmlspecialchars($extension) . '</label>';
                }
                ?>
            </div>
            <br>

            <label>
                <input type="checkbox" name="find_name" value="1" <?= $findName ? 'checked' : '' ?>> Искать в названиях файлов и папок
            </label>

            <label>
                <input type="checkbox" name="save_form" value="1" <?= $saveForm ? 'checked' : '' ?>> Запомнить выбор
            </label>

            <label>
                <input type="checkbox" name="hoy_str" value="1" <?= $showOnlyFoundLine ? 'checked' : '' ?>> Показывать только найденные строки (без контекста)
            </label>

            <div class="form-actions">
                <input type="submit" value="Поиск">
                <input type="hidden" name="f" value="1"> <!-- Флаг, указывающий на первое выполнение формы -->
            </div>
        </form>
    </div>

    <div class="results-container">
        <?php
        // Если были отправлены данные для поиска
        if (isset($_REQUEST['f']) && $_REQUEST['f'] === '1') {
            $searchDir = CURRENT_SCRIPT_PATH . ($path ?: $pap); // Формируем директорию для поиска

            // Проверяем, существует ли директория для поиска
            if (!is_dir($searchDir)) {
                echo "<div class='dir'>Ошибка: Указанная директория '" . htmlspecialchars($searchDir) . "' не существует.</div>";
            } else {
                // Выполняем поиск
                $results = searchFiles($searchDir, $search, $findName, $showOnlyFoundLine, $ext);

                // Формируем список для скачивания, если есть результаты
                $downloadContent = '';
                if (!empty($results)) {
                    $downloadContent = implode("\n", $results);
                }
            }
        }
        ?>

        <?php if (isset($_REQUEST['f']) && $_REQUEST['f'] === '1' && !empty($downloadContent)): ?>
            <form method="POST" action="">
                <div style="display: none;">
                    <textarea name="list_load"><?= htmlspecialchars($downloadContent) ?></textarea>
                </div>
                <button type="submit" name="download" value="1" class="load">Скачать список</button>
            </form>
        <?php endif; ?>
    </div>
</div>
 <div class="footer-static"> 
    <div>Разработка  <img src="https://webalan.ru/web.jpg" class="logo_webalan"> <a href="https://webalan.ru/" target="_blank">webalan.ru</a></div>
</div>
</body>
</html>
Покупка готового скрипта joomla 3

или просто напишите в телеграмм https://t.me/webalan