Replacing file content in PHP

I need a function just like preg_replace but instead of strings I need it to work with files / file content.

19
задан codaddict 26 August 2010 в 13:02
поделиться

2 ответа

Вы можете сделать:

$file = 'filename';
file_put_contents($file,str_replace('find','replace',file_get_contents($file)));
49
ответ дан 30 November 2019 в 02:02
поделиться

@codaddict's ответ вполне достаточен для небольших файлов (и как бы я его реализовал, если бы размер файла был меньше МиБ). Однако это съест тонну памяти, и поэтому вы должны быть осторожны при чтении больших файлов.

Если вам нужна более удобная для памяти версия, вы можете использовать потоковые фильтры...

class ReplaceText_filter extends php_user_filter {
    protected $search = '';
    protected $replace = '';

    public function filter($in, $out, &$consumed, $closing) {
        while ($bucket = stream_bucket_make_writable($in)) {
            $bucket->data = str_replace(
                $this->search, 
                $this->replace, 
                $bucket->data
            );
            $consumed += $bucket->datalen;
            stream_bucket_append($out, $bucket);
        }
        return PSFS_PASS_ON;
    }

    public function onCreate() {
        if (strpos($this->filtername, '.') === false) return false;
        list ($name, $arguments) = explode('.', $this->filtername, 2);
        $replace = '';
        $search = $arguments;
        if (strpos($arguments, '|') !== false) {
            list ($search, $replace) = explode('|', $arguments, 2);
        }
        if (strpos($search, ',') !== false) {
            $search = explode(',', $search);
        }
        if (strpos($replace, ',') !== false) {
            $search = explode(',', $replace);
        }
        $this->search = $search;
        $this->replace = $replace;
    }
}
stream_filter_register('replacetext.*', 'ReplaceText_Filter');

Тогда вы можете добавить произвольный потоковый фильтр. Имя фильтра определяет аргументы:

$search = 'foo';
$replace = 'bar';
$name = 'replacetext.'.$search.'|'.$replace;
stream_filter_append($stream, $name);

или для массивов,

$search = array('foo', 'bar');
$replace = array('bar', 'baz');
$name = 'replacetext.'.implode(',', $search).'|'.implode(',', $replace);
stream_filter_append($stream, $name);

Очевидно, что это действительно простой пример (и не выполняет много проверок ошибок), но он позволяет вам сделать что-то вроде этого:

$f1 = fopen('mysourcefile', 'r');
$f2 = fopen('mytmpfile', 'w');
$search = array('foo', 'bar');
$replace = array('bar', 'baz');
$name = 'replacetext.'.implode(',', $search).'|'.implode(',', $replace);
stream_filter_append($f1, $name);
stream_copy_to_stream($f1, $f2);
fclose($f1);
fclose($f2);
rename('mytmpfile', 'mysourcefile');

И это будет поддерживать очень низкое использование памяти при обработке потенциально огромных (ГиБ или ТиБ) файлов...

О, и еще одна интересная вещь, это то, что он может встроенно редактировать различные типы потоков. Под этим я подразумеваю, что вы можете читать из HTTP-потока, редактировать встроенные файлы и записывать в файловый поток. Это довольно мощно (поскольку вы можете связать эти фильтры в цепочку)...

21
ответ дан 30 November 2019 в 02:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: