Operowanie na katalogach i plikach – kilka przydatnych funkcji w PHP

File-management

Są w PHP takie rzeczy, które jeśli raz już ktoś gdzieś napisał, to później już nikt tego nie dotyka. Wierzcie mi lub nie, ale sam napisałem kilka takich klas / funkcji, do których nie chciałbym wracać. Oczywiście nie dlatego, że zostały źle napisane, a z prostego powodu – pisze się to raz, testuje oraz wykorzystuje i nie pamięta jakich funkcji konkretnie trzeba było użyć.

Przykładem takich funkcji, które wpisują się w pierwsze zdanie dzisiejszego artykułu są operacje na pojedynczych plikach oraz całym systemie plików. Postaram się Wam dzisiaj pokazać kilka ciekawych (tak myślę!) operacji, które pozwolą stworzyć sobie małą bibliotekę do zarządzania plikami lub katalogami.

Usuniecie pojedynczego pliku / rekursywne usuniecie całego katalogu

/**
 * Usuniecie pliku / rekursywne usuniecie calego katalogu
 *
 * @param string $path sciezka do pliku / katalogu do usuniecia
 * @return void
 */
function deleteRecursive($path) {
    if (is_dir($path)) {
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::CHILD_FIRST
        );

        foreach ($iterator as $file) {
            if ($file->isDir()) {
                rmdir($file->getPathname());
            } else {
                unlink($file->getPathname());
            }
        }

        rmdir($path);
    } else {
        unlink($path);
    }
}

Kopiowanie pojedynczego pliku / rekursywne kopiowanie katalogu

/**
 * Kopiowanie pojedynczego pliku / rekursywne kopiowanie katalogu
 *
 * @param string $source    sciezka do zrodla
 * @param string $dest      sciezka przeznaczenia
 * @return void
 */
function copyRecursive($source, $dest) {
    if (is_dir($source)) {
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS), 
            RecursiveIteratorIterator::SELF_FIRST
        );

        foreach ($iterator as $file) {
            if ($file->isDir()) {
                mkdir($dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName());
            } else {
                copy($file, $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName());
            }
        }
    } else {
        copy($source, $dest);
    }
}

Rozmiar pliku lub katalogu

/**
 * Rozmiar pliku lub katalogu
 *
 * UWAGA: Na systemach 32bitowych mozemy otrzymac niespodziewane wyniki dla plikow majacych rozmiar ponad 2GB
 *
 * @param string $path sciezka do pliku lub katalogu
 * @return int rozmiaru (w bajtach)
 */
function sizeRecursive($path) {
    $size = 0;
    if (is_dir($path)) {
        $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path));

        foreach ($iterator as $file) {
            $size += $file->getSize();
        }
    } else {
        $size = filesize($path);
    }

    return $size;
}

Funkcja tail (*unix) – odczytanie kilku (ostatnich) linii z pliku

/**
 * Funkcja tail (*unix) - odczytanie kilku (ostatnich) linii z pliku
 *
 * UWAGA: Ponizsza funkcja dziala dla plikow majacych zakonczenie linii rowne CRLF, LF lub CR
 *
 * @param string $file  sciezka do pliku
 * @param int $lines    ilosc linii do zwrocenia przez funkcje
 * @return string
 */
function tail($file, $lines) {
    if ($lines < 1) {
        return '';
    }

    $line = '';
    $line_count = 0;
    $prev_char = '';
    $fp = fopen($file, 'r');
    $cursor = -1;

    fseek($fp, $cursor, SEEK_END);
    $char = fgetc($fp);

    while ($char !== false) {
        if ($char === "\\n" || $char === "\\r") {
            fseek($fp, --$cursor, SEEK_END);
            $next_char = fgetc($fp);

            if ($char === "\\n" && $next_char === "\\r") {
                $line_count++;
            } elseif ($char === "\\r" && $prev_char !== "\\n") {
                $line_count++;
            } elseif ($char === "\\n") {
                $line_count++;
            }

            fseek($fp, ++$cursor, SEEK_END);
        }

        if ($line_count == $lines) {
            break;
        }

        $line = $char . $line;
        $prev_char = $char;
        fseek($fp, --$cursor, SEEK_END);
        $char = fgetc($fp);
    }

    fclose($fp);

    return $line;
}