Создать или написать / добавить в текстовом файле

170

У меня есть веб-сайт, который каждый раз, когда пользователь входит или выходит из системы, сохраняет его в текстовом файле.

Мой код не работает при добавлении данных или создании текстового файла, если он не существует .. Вот пример кода

$myfile = fopen("logs.txt", "wr") or die("Unable to open file!");
$txt = "user id date";
fwrite($myfile, $txt);
fclose($myfile);

Кажется, он не добавляется к следующей строке после повторного открытия.

Кроме того, я думаю, что это также приведет к ошибке в ситуации, когда два пользователя будут входить в систему одновременно, повлияет ли это на открытие текстового файла и сохранение его впоследствии?

Джерахмил Асебуш
источник

Ответы:

337

Попробуйте что-то вроде этого:

 $txt = "user id date";
 $myfile = file_put_contents('logs.txt', $txt.PHP_EOL , FILE_APPEND | LOCK_EX);
SpencerX
источник
5
это создает текстовый файл, если он не существует?
Джерахмил Асебуш
5
Да, это создать текстовый файл logs.txtи добавить содержимое в нем
SpencerX
5
у меня есть вопрос. используя LOCK_EX. я знаю, что это предотвратит одновременную запись в файл. но что будет с другим?
Джерахмил Асебуш
13
php.net/manual/en/function.file-put-contents.php Эта функция возвращает количество байтов, записанных в файл, или FALSE при ошибке. Просто если кому-то интересно.
Мастер Джеймс
7
@JerahmeelAcebuche Второй процесс, пытающийся получить блокировку, будет «блокировать до получения запрошенной блокировки» ( источник ). Другими словами, второй процесс будет ожидать, пока первый не закроет файл и не снимет блокировку.
Риного
102

Используйте aрежим. Это означает append.

$myfile = fopen("logs.txt", "a") or die("Unable to open file!");
$txt = "user id date";
fwrite($myfile, "\n". $txt);
fclose($myfile);
Валентин Мерсье
источник
у меня также есть эта проблема \ n. это не работает. это работает для вас?
Джерахмил Асебуш
1
это работает, если ситуация произойдет, как я уже сказал?
Джерахмил Асебуш
1
aфлаг будет создать файл , если он не не существует и не имеет значения , что убедитесь , что вы действительно appendновый текст. Для этого \nэто работает, но только если внутри двойных кавычек "не одиночные кавычки'
Валентин Мерсье
Я имею в виду ситуацию, когда два пользователя входят в разные браузеры. Затем php откроет файл в двух браузерах одновременно и обновит его одновременно. будет ли проблема? \
Jerahmeel Acebuche
1
О, да, в этом случае будет использоваться база данных SQL, она имеет встроенный движок, чтобы избежать гоночных условий. Но это совершенно новый вопрос.
Валентин Мерсье
10

Вы можете сделать это OO способом, просто альтернативой и гибкостью:

class Logger {

    private
        $file,
        $timestamp;

    public function __construct($filename) {
        $this->file = $filename;
    }

    public function setTimestamp($format) {
        $this->timestamp = date($format)." » ";
    }

    public function putLog($insert) {
        if (isset($this->timestamp)) {
            file_put_contents($this->file, $this->timestamp.$insert."<br>", FILE_APPEND);
        } else {
            trigger_error("Timestamp not set", E_USER_ERROR);
        }
    }

    public function getLog() {
        $content = @file_get_contents($this->file);
        return $content;
    }

}

Затем используйте его следующим образом ... допустим, вы user_nameсохранили в сеансе (полупсевдокод):

$log = new Logger("log.txt");
$log->setTimestamp("D M d 'y h.i A");

if (user logs in) {
    $log->putLog("Successful Login: ".$_SESSION["user_name"]);
}
if (user logs out) {
    $log->putLog("Logout: ".$_SESSION["user_name"]);
}

Проверьте ваш журнал с этим:

$log->getLog();

Результат похож на:

Sun Jul 02 '17 05.45 PM » Successful Login: JohnDoe
Sun Jul 02 '17 05.46 PM » Logout: JohnDoe


github.com/thielicious/Logger

Thielicious
источник
1
Большое спасибо за этот класс Logger! Я не ожидал найти это, когда нашел эту страницу ... но на самом деле это основа гораздо лучшего решения, чем то, что я изначально планировал реализовать.
Майк Картер
4

Это работает для меня, написание (создание также) и / или добавление контента в том же режиме.

$fp = fopen("MyFile.txt", "a+") 
Михир Бхатт
источник
3

Попробуйте этот код:

function logErr($data){
  $logPath = __DIR__. "/../logs/logs.txt";
  $mode = (!file_exists($logPath)) ? 'w':'a';
  $logfile = fopen($logPath, $mode);
  fwrite($logfile, "\r\n". $data);
  fclose($logfile);
}

Я всегда так использую, и это работает ...

Rwakos
источник
1
Нет причин делать это (!file_exists($logPath)) ? 'w':'a'- aопция уже имеет правильное поведение, когда файл не существует. Таким образом, можно упростить этот ответ, удалив строку $mode = ...;и изменив следующую строку на $logfile = fopen($logPath, 'a');.
ToolmakerSteve
2

В вашем коде нет такого режима открытия файлов, как "wr":

fopen("logs.txt", "wr") 

Режимы открытия файлов в PHP http://php.net/manual/en/function.fopen.php такие же, как в C: http://www.cplusplus.com/reference/cstdio/fopen/

Существуют следующие основные открытые режимы «r» для чтения, «w» для записи и «a» для добавления, и вы не можете объединить их. Вы можете добавить другие модификаторы, такие как «+» для обновления, «b» для двоичного файла. Новый стандарт C добавляет новый стандартный подспецификатор («x»), поддерживаемый PHP, который может быть добавлен к любому спецификатору «w» (для формирования «wx», «wbx», «w + x» или «w + bx»). "/" WB + х "). Этот подспецификатор заставляет функцию завершиться ошибкой, если файл существует, вместо того, чтобы перезаписывать его.

Кроме того, в PHP 5.2.6 был добавлен основной открытый режим 'c'. Вы не можете комбинировать «c» с «a», «r», «w». «С» открывает файл только для записи. Если файл не существует, он создается. Если он существует, он не усекается (в отличие от 'w'), и вызов этой функции не выполняется (как в случае с 'x'). 'c +' Открыть файл для чтения и записи; в противном случае он ведет себя так же, как «с».

Кроме того, в PHP 7.1.2 была добавлена ​​опция 'e', ​​которую можно комбинировать с другими режимами. Он установил флаг close-on-exec для открытого дескриптора файла. Доступно только в PHP, скомпилированном в соответствии с POSIX.1-2008.

Таким образом, для задачи, как вы ее описали, лучшим режимом открытия файла будет «a». Он открывает файл только для записи. Он помещает указатель файла в конец файла. Если файл не существует, он пытается его создать. В этом режиме fseek () не действует, записи всегда добавляются.

Вот что вам нужно, как уже было указано выше:

fopen("logs.txt", "a") 
Максим Масютин
источник
0

Хотя есть много способов сделать это. Но если вы хотите сделать это простым способом и хотите отформатировать текст перед записью в файл журнала. Вы можете создать вспомогательную функцию для этого.

if (!function_exists('logIt')) {
    function logIt($logMe)
    {
        $logFilePath = storage_path('logs/cron.log.'.date('Y-m-d').'.log');
        $cronLogFile = fopen($logFilePath, "a");
        fwrite($cronLogFile, date('Y-m-d H:i:s'). ' : ' .$logMe. PHP_EOL);
        fclose($cronLogFile);
    }
}
PHP Worm ...
источник